diff options
author | Johannes Stezenbach <js@linuxtv.org> | 2005-06-24 01:02:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:05:30 -0400 |
commit | 776338e121b9db3156bfb4e21622a0219bbab9d4 (patch) | |
tree | 5102272b708a9e8ff81165714870d3d38363cc23 /drivers/media/dvb/dvb-usb/dvb-usb-urb.c | |
parent | b6a235b1186dda0800c8bedc2526830a4a36b44e (diff) |
[PATCH] dvb: Add generalized dvb-usb driver
Add generalized dvb-usb driver which supports a wide variety of devices.
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Johannes Stezenbach <js@linuxtv.org>
Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/dvb/dvb-usb/dvb-usb-urb.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c new file mode 100644 index 000000000000..83d476fb410a --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c | |||
@@ -0,0 +1,211 @@ | |||
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 | } | ||