Johannes Stezenbach | 776338e | 2005-06-23 22:02:35 -0700 | [diff] [blame^] | 1 | /* dvb-usb-urb.c is part of the DVB USB library. |
| 2 | * |
| 3 | * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) |
| 4 | * see dvb-usb-init.c for copyright information. |
| 5 | * |
| 6 | * This file contains functions for initializing and handling the |
| 7 | * USB and URB stuff. |
| 8 | */ |
| 9 | #include "dvb-usb-common.h" |
| 10 | |
| 11 | int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, |
| 12 | u16 rlen, int delay_ms) |
| 13 | { |
| 14 | int actlen,ret = -ENOMEM; |
| 15 | |
| 16 | if (d->props.generic_bulk_ctrl_endpoint == 0) { |
| 17 | err("endpoint for generic control not specified."); |
| 18 | return -EINVAL; |
| 19 | } |
| 20 | |
| 21 | if (wbuf == NULL || wlen == 0) |
| 22 | return -EINVAL; |
| 23 | |
| 24 | if ((ret = down_interruptible(&d->usb_sem))) |
| 25 | return ret; |
| 26 | |
| 27 | debug_dump(wbuf,wlen,deb_xfer); |
| 28 | |
| 29 | ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, |
| 30 | d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, |
| 31 | 2*HZ); |
| 32 | |
| 33 | if (ret) |
| 34 | err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); |
| 35 | else |
| 36 | ret = actlen != wlen ? -1 : 0; |
| 37 | |
| 38 | /* an answer is expected, and no error before */ |
| 39 | if (!ret && rbuf && rlen) { |
| 40 | if (delay_ms) |
| 41 | msleep(delay_ms); |
| 42 | |
| 43 | ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, |
| 44 | d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, |
| 45 | 2*HZ); |
| 46 | |
| 47 | if (ret) |
| 48 | err("recv bulk message failed: %d",ret); |
| 49 | else |
| 50 | debug_dump(rbuf,actlen,deb_xfer); |
| 51 | } |
| 52 | |
| 53 | up(&d->usb_sem); |
| 54 | return ret; |
| 55 | } |
| 56 | EXPORT_SYMBOL(dvb_usb_generic_rw); |
| 57 | |
| 58 | int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) |
| 59 | { |
| 60 | return dvb_usb_generic_rw(d,buf,len,NULL,0,0); |
| 61 | } |
| 62 | EXPORT_SYMBOL(dvb_usb_generic_write); |
| 63 | |
| 64 | static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs) |
| 65 | { |
| 66 | struct dvb_usb_device *d = urb->context; |
| 67 | |
| 68 | deb_ts("bulk urb completed. feedcount: %d, status: %d, length: %d\n",d->feedcount,urb->status, |
| 69 | urb->actual_length); |
| 70 | |
| 71 | switch (urb->status) { |
| 72 | case 0: /* success */ |
| 73 | case -ETIMEDOUT: /* NAK */ |
| 74 | break; |
| 75 | case -ECONNRESET: /* kill */ |
| 76 | case -ENOENT: |
| 77 | case -ESHUTDOWN: |
| 78 | return; |
| 79 | default: /* error */ |
| 80 | deb_ts("urb completition error %d.", urb->status); |
| 81 | break; |
| 82 | } |
| 83 | |
| 84 | if (d->feedcount > 0 && urb->actual_length > 0) { |
| 85 | if (d->state & DVB_USB_STATE_DVB) |
| 86 | dvb_dmx_swfilter(&d->demux, (u8*) urb->transfer_buffer,urb->actual_length); |
| 87 | } else |
| 88 | deb_ts("URB dropped because of feedcount.\n"); |
| 89 | |
| 90 | usb_submit_urb(urb,GFP_ATOMIC); |
| 91 | } |
| 92 | |
| 93 | int dvb_usb_urb_kill(struct dvb_usb_device *d) |
| 94 | { |
| 95 | int i; |
| 96 | for (i = 0; i < d->urbs_submitted; i++) { |
| 97 | deb_info("killing URB no. %d.\n",i); |
| 98 | |
| 99 | /* stop the URB */ |
| 100 | usb_kill_urb(d->urb_list[i]); |
| 101 | } |
| 102 | d->urbs_submitted = 0; |
| 103 | return 0; |
| 104 | } |
| 105 | |
| 106 | int dvb_usb_urb_submit(struct dvb_usb_device *d) |
| 107 | { |
| 108 | int i,ret; |
| 109 | for (i = 0; i < d->urbs_initialized; i++) { |
| 110 | deb_info("submitting URB no. %d\n",i); |
| 111 | if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) { |
| 112 | err("could not submit URB no. %d - get them all back\n",i); |
| 113 | dvb_usb_urb_kill(d); |
| 114 | return ret; |
| 115 | } |
| 116 | d->urbs_submitted++; |
| 117 | } |
| 118 | return 0; |
| 119 | } |
| 120 | |
| 121 | static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) |
| 122 | { |
| 123 | int i,bufsize = d->props.urb.count * d->props.urb.u.bulk.buffersize; |
| 124 | |
| 125 | deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize); |
| 126 | /* allocate the actual buffer for the URBs */ |
| 127 | if ((d->buffer = usb_buffer_alloc(d->udev, bufsize, SLAB_ATOMIC, &d->dma_handle)) == NULL) { |
| 128 | deb_info("not enough memory for urb-buffer allocation.\n"); |
| 129 | return -ENOMEM; |
| 130 | } |
| 131 | deb_info("allocation successful\n"); |
| 132 | memset(d->buffer,0,bufsize); |
| 133 | |
| 134 | d->state |= DVB_USB_STATE_URB_BUF; |
| 135 | |
| 136 | /* allocate the URBs */ |
| 137 | for (i = 0; i < d->props.urb.count; i++) { |
| 138 | if (!(d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) { |
| 139 | return -ENOMEM; |
| 140 | } |
| 141 | |
| 142 | usb_fill_bulk_urb( d->urb_list[i], d->udev, |
| 143 | usb_rcvbulkpipe(d->udev,d->props.urb.endpoint), |
| 144 | &d->buffer[i*d->props.urb.u.bulk.buffersize], |
| 145 | d->props.urb.u.bulk.buffersize, |
| 146 | dvb_usb_bulk_urb_complete, d); |
| 147 | |
| 148 | d->urb_list[i]->transfer_flags = 0; |
| 149 | d->urbs_initialized++; |
| 150 | } |
| 151 | return 0; |
| 152 | } |
| 153 | |
| 154 | int dvb_usb_urb_init(struct dvb_usb_device *d) |
| 155 | { |
| 156 | /* |
| 157 | * when reloading the driver w/o replugging the device |
| 158 | * sometimes a timeout occures, this helps |
| 159 | */ |
| 160 | if (d->props.generic_bulk_ctrl_endpoint != 0) { |
| 161 | usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint)); |
| 162 | usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint)); |
| 163 | } |
| 164 | usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.urb.endpoint)); |
| 165 | |
| 166 | /* allocate the array for the data transfer URBs */ |
| 167 | d->urb_list = kmalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL); |
| 168 | if (d->urb_list == NULL) |
| 169 | return -ENOMEM; |
| 170 | memset(d->urb_list,0,d->props.urb.count * sizeof(struct urb *)); |
| 171 | d->state |= DVB_USB_STATE_URB_LIST; |
| 172 | |
| 173 | switch (d->props.urb.type) { |
| 174 | case DVB_USB_BULK: |
| 175 | return dvb_usb_bulk_urb_init(d); |
| 176 | case DVB_USB_ISOC: |
| 177 | err("isochronous transfer not yet implemented in dvb-usb."); |
| 178 | return -EINVAL; |
| 179 | default: |
| 180 | err("unkown URB-type for data transfer."); |
| 181 | return -EINVAL; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | int dvb_usb_urb_exit(struct dvb_usb_device *d) |
| 186 | { |
| 187 | int i; |
| 188 | |
| 189 | dvb_usb_urb_kill(d); |
| 190 | |
| 191 | if (d->state & DVB_USB_STATE_URB_LIST) { |
| 192 | for (i = 0; i < d->urbs_initialized; i++) { |
| 193 | if (d->urb_list[i] != NULL) { |
| 194 | deb_info("freeing URB no. %d.\n",i); |
| 195 | /* free the URBs */ |
| 196 | usb_free_urb(d->urb_list[i]); |
| 197 | } |
| 198 | } |
| 199 | d->urbs_initialized = 0; |
| 200 | /* free the urb array */ |
| 201 | kfree(d->urb_list); |
| 202 | d->state &= ~DVB_USB_STATE_URB_LIST; |
| 203 | } |
| 204 | |
| 205 | if (d->state & DVB_USB_STATE_URB_BUF) |
| 206 | usb_buffer_free(d->udev, d->props.urb.u.bulk.buffersize * d->props.urb.count, |
| 207 | d->buffer, d->dma_handle); |
| 208 | |
| 209 | d->state &= ~DVB_USB_STATE_URB_BUF; |
| 210 | return 0; |
| 211 | } |