diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hisax/st5481_usb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hisax/st5481_usb.c')
-rw-r--r-- | drivers/isdn/hisax/st5481_usb.c | 650 |
1 files changed, 650 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c new file mode 100644 index 000000000000..2369180b1cb1 --- /dev/null +++ b/drivers/isdn/hisax/st5481_usb.c | |||
@@ -0,0 +1,650 @@ | |||
1 | /* | ||
2 | * Driver for ST5481 USB ISDN modem | ||
3 | * | ||
4 | * Author Frode Isaksen | ||
5 | * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> | ||
6 | * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/usb.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include "st5481.h" | ||
17 | |||
18 | /* ====================================================================== | ||
19 | * control pipe | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * Send the next endpoint 0 request stored in the FIFO. | ||
24 | * Called either by the completion or by usb_ctrl_msg. | ||
25 | */ | ||
26 | static void usb_next_ctrl_msg(struct urb *urb, | ||
27 | struct st5481_adapter *adapter) | ||
28 | { | ||
29 | struct st5481_ctrl *ctrl = &adapter->ctrl; | ||
30 | int r_index; | ||
31 | |||
32 | if (test_and_set_bit(0, &ctrl->busy)) { | ||
33 | return; | ||
34 | } | ||
35 | |||
36 | if ((r_index = fifo_remove(&ctrl->msg_fifo.f)) < 0) { | ||
37 | test_and_clear_bit(0,&ctrl->busy); | ||
38 | return; | ||
39 | } | ||
40 | urb->setup_packet = | ||
41 | (unsigned char *)&ctrl->msg_fifo.data[r_index]; | ||
42 | |||
43 | DBG(1,"request=0x%02x,value=0x%04x,index=%x", | ||
44 | ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest, | ||
45 | ((struct ctrl_msg *)urb->setup_packet)->dr.wValue, | ||
46 | ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex); | ||
47 | |||
48 | // Prepare the URB | ||
49 | urb->dev = adapter->usb_dev; | ||
50 | |||
51 | SUBMIT_URB(urb, GFP_ATOMIC); | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * Asynchronous endpoint 0 request (async version of usb_control_msg). | ||
56 | * The request will be queued up in a FIFO if the endpoint is busy. | ||
57 | */ | ||
58 | void usb_ctrl_msg(struct st5481_adapter *adapter, | ||
59 | u8 request, u8 requesttype, u16 value, u16 index, | ||
60 | ctrl_complete_t complete, void *context) | ||
61 | { | ||
62 | struct st5481_ctrl *ctrl = &adapter->ctrl; | ||
63 | int w_index; | ||
64 | struct ctrl_msg *ctrl_msg; | ||
65 | |||
66 | if ((w_index = fifo_add(&ctrl->msg_fifo.f)) < 0) { | ||
67 | WARN("control msg FIFO full"); | ||
68 | return; | ||
69 | } | ||
70 | ctrl_msg = &ctrl->msg_fifo.data[w_index]; | ||
71 | |||
72 | ctrl_msg->dr.bRequestType = requesttype; | ||
73 | ctrl_msg->dr.bRequest = request; | ||
74 | ctrl_msg->dr.wValue = cpu_to_le16p(&value); | ||
75 | ctrl_msg->dr.wIndex = cpu_to_le16p(&index); | ||
76 | ctrl_msg->dr.wLength = 0; | ||
77 | ctrl_msg->complete = complete; | ||
78 | ctrl_msg->context = context; | ||
79 | |||
80 | usb_next_ctrl_msg(ctrl->urb, adapter); | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Asynchronous endpoint 0 device request. | ||
85 | */ | ||
86 | void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter, | ||
87 | u8 request, u16 value, | ||
88 | ctrl_complete_t complete, void *context) | ||
89 | { | ||
90 | usb_ctrl_msg(adapter, request, | ||
91 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
92 | value, 0, complete, context); | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Asynchronous pipe reset (async version of usb_clear_halt). | ||
97 | */ | ||
98 | void st5481_usb_pipe_reset(struct st5481_adapter *adapter, | ||
99 | u_char pipe, | ||
100 | ctrl_complete_t complete, void *context) | ||
101 | { | ||
102 | DBG(1,"pipe=%02x",pipe); | ||
103 | |||
104 | usb_ctrl_msg(adapter, | ||
105 | USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RECIP_ENDPOINT, | ||
106 | 0, pipe, complete, context); | ||
107 | } | ||
108 | |||
109 | |||
110 | /* | ||
111 | Physical level functions | ||
112 | */ | ||
113 | |||
114 | void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command) | ||
115 | { | ||
116 | DBG(8,"command=%s", ST5481_CMD_string(command)); | ||
117 | |||
118 | st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL); | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * The request on endpoint 0 has completed. | ||
123 | * Call the user provided completion routine and try | ||
124 | * to send the next request. | ||
125 | */ | ||
126 | static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs) | ||
127 | { | ||
128 | struct st5481_adapter *adapter = urb->context; | ||
129 | struct st5481_ctrl *ctrl = &adapter->ctrl; | ||
130 | struct ctrl_msg *ctrl_msg; | ||
131 | |||
132 | if (unlikely(urb->status < 0)) { | ||
133 | if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { | ||
134 | WARN("urb status %d",urb->status); | ||
135 | } else { | ||
136 | DBG(1,"urb killed"); | ||
137 | return; // Give up | ||
138 | } | ||
139 | } | ||
140 | |||
141 | ctrl_msg = (struct ctrl_msg *)urb->setup_packet; | ||
142 | |||
143 | if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { | ||
144 | /* Special case handling for pipe reset */ | ||
145 | le16_to_cpus(&ctrl_msg->dr.wIndex); | ||
146 | |||
147 | /* toggle is reset on clear */ | ||
148 | usb_settoggle(adapter->usb_dev, | ||
149 | ctrl_msg->dr.wIndex & ~USB_DIR_IN, | ||
150 | (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0, | ||
151 | 0); | ||
152 | |||
153 | |||
154 | } | ||
155 | |||
156 | if (ctrl_msg->complete) | ||
157 | ctrl_msg->complete(ctrl_msg->context); | ||
158 | |||
159 | clear_bit(0, &ctrl->busy); | ||
160 | |||
161 | // Try to send next control message | ||
162 | usb_next_ctrl_msg(urb, adapter); | ||
163 | return; | ||
164 | } | ||
165 | |||
166 | /* ====================================================================== | ||
167 | * interrupt pipe | ||
168 | */ | ||
169 | |||
170 | /* | ||
171 | * The interrupt endpoint will be called when any | ||
172 | * of the 6 registers changes state (depending on masks). | ||
173 | * Decode the register values and schedule a private event. | ||
174 | * Called at interrupt. | ||
175 | */ | ||
176 | static void usb_int_complete(struct urb *urb, struct pt_regs *regs) | ||
177 | { | ||
178 | u8 *data = urb->transfer_buffer; | ||
179 | u8 irqbyte; | ||
180 | struct st5481_adapter *adapter = urb->context; | ||
181 | int j; | ||
182 | int status; | ||
183 | |||
184 | switch (urb->status) { | ||
185 | case 0: | ||
186 | /* success */ | ||
187 | break; | ||
188 | case -ECONNRESET: | ||
189 | case -ENOENT: | ||
190 | case -ESHUTDOWN: | ||
191 | /* this urb is terminated, clean up */ | ||
192 | DBG(1, "urb shutting down with status: %d", urb->status); | ||
193 | return; | ||
194 | default: | ||
195 | WARN("nonzero urb status received: %d", urb->status); | ||
196 | goto exit; | ||
197 | } | ||
198 | |||
199 | |||
200 | DBG_PACKET(1, data, INT_PKT_SIZE); | ||
201 | |||
202 | if (urb->actual_length == 0) { | ||
203 | goto exit; | ||
204 | } | ||
205 | |||
206 | irqbyte = data[MPINT]; | ||
207 | if (irqbyte & DEN_INT) | ||
208 | FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL); | ||
209 | |||
210 | if (irqbyte & DCOLL_INT) | ||
211 | FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL); | ||
212 | |||
213 | irqbyte = data[FFINT_D]; | ||
214 | if (irqbyte & OUT_UNDERRUN) | ||
215 | FsmEvent(&adapter->d_out.fsm, EV_DOUT_UNDERRUN, NULL); | ||
216 | |||
217 | if (irqbyte & OUT_DOWN) | ||
218 | ;// printk("OUT_DOWN\n"); | ||
219 | |||
220 | irqbyte = data[MPINT]; | ||
221 | if (irqbyte & RXCI_INT) | ||
222 | FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL); | ||
223 | |||
224 | for (j = 0; j < 2; j++) | ||
225 | adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j]; | ||
226 | |||
227 | urb->actual_length = 0; | ||
228 | |||
229 | exit: | ||
230 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
231 | if (status) | ||
232 | WARN("usb_submit_urb failed with result %d", status); | ||
233 | } | ||
234 | |||
235 | /* ====================================================================== | ||
236 | * initialization | ||
237 | */ | ||
238 | |||
239 | int st5481_setup_usb(struct st5481_adapter *adapter) | ||
240 | { | ||
241 | struct usb_device *dev = adapter->usb_dev; | ||
242 | struct st5481_ctrl *ctrl = &adapter->ctrl; | ||
243 | struct st5481_intr *intr = &adapter->intr; | ||
244 | struct usb_interface *intf; | ||
245 | struct usb_host_interface *altsetting = NULL; | ||
246 | struct usb_host_endpoint *endpoint; | ||
247 | int status; | ||
248 | struct urb *urb; | ||
249 | u8 *buf; | ||
250 | |||
251 | DBG(1,""); | ||
252 | |||
253 | if ((status = usb_reset_configuration (dev)) < 0) { | ||
254 | WARN("reset_configuration failed,status=%d",status); | ||
255 | return status; | ||
256 | } | ||
257 | |||
258 | intf = usb_ifnum_to_if(dev, 0); | ||
259 | if (intf) | ||
260 | altsetting = usb_altnum_to_altsetting(intf, 3); | ||
261 | if (!altsetting) | ||
262 | return -ENXIO; | ||
263 | |||
264 | // Check if the config is sane | ||
265 | if ( altsetting->desc.bNumEndpoints != 7 ) { | ||
266 | WARN("expecting 7 got %d endpoints!", altsetting->desc.bNumEndpoints); | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | |||
270 | // The descriptor is wrong for some early samples of the ST5481 chip | ||
271 | altsetting->endpoint[3].desc.wMaxPacketSize = __constant_cpu_to_le16(32); | ||
272 | altsetting->endpoint[4].desc.wMaxPacketSize = __constant_cpu_to_le16(32); | ||
273 | |||
274 | // Use alternative setting 3 on interface 0 to have 2B+D | ||
275 | if ((status = usb_set_interface (dev, 0, 3)) < 0) { | ||
276 | WARN("usb_set_interface failed,status=%d",status); | ||
277 | return status; | ||
278 | } | ||
279 | |||
280 | // Allocate URB for control endpoint | ||
281 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
282 | if (!urb) { | ||
283 | return -ENOMEM; | ||
284 | } | ||
285 | ctrl->urb = urb; | ||
286 | |||
287 | // Fill the control URB | ||
288 | usb_fill_control_urb (urb, dev, | ||
289 | usb_sndctrlpipe(dev, 0), | ||
290 | NULL, NULL, 0, usb_ctrl_complete, adapter); | ||
291 | |||
292 | |||
293 | fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data)); | ||
294 | |||
295 | // Allocate URBs and buffers for interrupt endpoint | ||
296 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
297 | if (!urb) { | ||
298 | return -ENOMEM; | ||
299 | } | ||
300 | intr->urb = urb; | ||
301 | |||
302 | buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL); | ||
303 | if (!buf) { | ||
304 | return -ENOMEM; | ||
305 | } | ||
306 | |||
307 | endpoint = &altsetting->endpoint[EP_INT-1]; | ||
308 | |||
309 | // Fill the interrupt URB | ||
310 | usb_fill_int_urb(urb, dev, | ||
311 | usb_rcvintpipe(dev, endpoint->desc.bEndpointAddress), | ||
312 | buf, INT_PKT_SIZE, | ||
313 | usb_int_complete, adapter, | ||
314 | endpoint->desc.bInterval); | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * Release buffers and URBs for the interrupt and control | ||
321 | * endpoint. | ||
322 | */ | ||
323 | void st5481_release_usb(struct st5481_adapter *adapter) | ||
324 | { | ||
325 | struct st5481_intr *intr = &adapter->intr; | ||
326 | struct st5481_ctrl *ctrl = &adapter->ctrl; | ||
327 | |||
328 | DBG(1,""); | ||
329 | |||
330 | // Stop and free Control and Interrupt URBs | ||
331 | usb_unlink_urb(ctrl->urb); | ||
332 | if (ctrl->urb->transfer_buffer) | ||
333 | kfree(ctrl->urb->transfer_buffer); | ||
334 | usb_free_urb(ctrl->urb); | ||
335 | |||
336 | usb_unlink_urb(intr->urb); | ||
337 | if (intr->urb->transfer_buffer) | ||
338 | kfree(intr->urb->transfer_buffer); | ||
339 | usb_free_urb(intr->urb); | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * Initialize the adapter. | ||
344 | */ | ||
345 | void st5481_start(struct st5481_adapter *adapter) | ||
346 | { | ||
347 | static const u8 init_cmd_table[]={ | ||
348 | SET_DEFAULT,0, | ||
349 | STT,0, | ||
350 | SDA_MIN,0x0d, | ||
351 | SDA_MAX,0x29, | ||
352 | SDELAY_VALUE,0x14, | ||
353 | GPIO_DIR,0x01, | ||
354 | GPIO_OUT,RED_LED, | ||
355 | // FFCTRL_OUT_D,4, | ||
356 | // FFCTRH_OUT_D,12, | ||
357 | FFCTRL_OUT_B1,6, | ||
358 | FFCTRH_OUT_B1,20, | ||
359 | FFCTRL_OUT_B2,6, | ||
360 | FFCTRH_OUT_B2,20, | ||
361 | MPMSK,RXCI_INT+DEN_INT+DCOLL_INT, | ||
362 | 0 | ||
363 | }; | ||
364 | struct st5481_intr *intr = &adapter->intr; | ||
365 | int i = 0; | ||
366 | u8 request,value; | ||
367 | |||
368 | DBG(8,""); | ||
369 | |||
370 | adapter->leds = RED_LED; | ||
371 | |||
372 | // Start receiving on the interrupt endpoint | ||
373 | SUBMIT_URB(intr->urb, GFP_KERNEL); | ||
374 | |||
375 | while ((request = init_cmd_table[i++])) { | ||
376 | value = init_cmd_table[i++]; | ||
377 | st5481_usb_device_ctrl_msg(adapter, request, value, NULL, NULL); | ||
378 | } | ||
379 | st5481_ph_command(adapter, ST5481_CMD_PUP); | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * Reset the adapter to default values. | ||
384 | */ | ||
385 | void st5481_stop(struct st5481_adapter *adapter) | ||
386 | { | ||
387 | DBG(8,""); | ||
388 | |||
389 | st5481_usb_device_ctrl_msg(adapter, SET_DEFAULT, 0, NULL, NULL); | ||
390 | } | ||
391 | |||
392 | /* ====================================================================== | ||
393 | * isochronous USB helpers | ||
394 | */ | ||
395 | |||
396 | static void | ||
397 | fill_isoc_urb(struct urb *urb, struct usb_device *dev, | ||
398 | unsigned int pipe, void *buf, int num_packets, | ||
399 | int packet_size, usb_complete_t complete, | ||
400 | void *context) | ||
401 | { | ||
402 | int k; | ||
403 | |||
404 | spin_lock_init(&urb->lock); | ||
405 | urb->dev=dev; | ||
406 | urb->pipe=pipe; | ||
407 | urb->transfer_buffer=buf; | ||
408 | urb->number_of_packets = num_packets; | ||
409 | urb->transfer_buffer_length=num_packets*packet_size; | ||
410 | urb->actual_length = 0; | ||
411 | urb->complete=complete; | ||
412 | urb->context=context; | ||
413 | urb->transfer_flags=URB_ISO_ASAP; | ||
414 | for (k = 0; k < num_packets; k++) { | ||
415 | urb->iso_frame_desc[k].offset = packet_size * k; | ||
416 | urb->iso_frame_desc[k].length = packet_size; | ||
417 | urb->iso_frame_desc[k].actual_length = 0; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | int | ||
422 | st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, | ||
423 | unsigned int pipe, int num_packets, | ||
424 | int packet_size, int buf_size, | ||
425 | usb_complete_t complete, void *context) | ||
426 | { | ||
427 | int j, retval; | ||
428 | unsigned char *buf; | ||
429 | |||
430 | for (j = 0; j < 2; j++) { | ||
431 | retval = -ENOMEM; | ||
432 | urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL); | ||
433 | if (!urb[j]) | ||
434 | goto err; | ||
435 | |||
436 | // Allocate memory for 2000bytes/sec (16Kb/s) | ||
437 | buf = kmalloc(buf_size, GFP_KERNEL); | ||
438 | if (!buf) | ||
439 | goto err; | ||
440 | |||
441 | // Fill the isochronous URB | ||
442 | fill_isoc_urb(urb[j], dev, pipe, buf, | ||
443 | num_packets, packet_size, complete, | ||
444 | context); | ||
445 | } | ||
446 | return 0; | ||
447 | |||
448 | err: | ||
449 | for (j = 0; j < 2; j++) { | ||
450 | if (urb[j]) { | ||
451 | if (urb[j]->transfer_buffer) | ||
452 | kfree(urb[j]->transfer_buffer); | ||
453 | usb_free_urb(urb[j]); | ||
454 | } | ||
455 | } | ||
456 | return retval; | ||
457 | } | ||
458 | |||
459 | void st5481_release_isocpipes(struct urb* urb[2]) | ||
460 | { | ||
461 | int j; | ||
462 | |||
463 | for (j = 0; j < 2; j++) { | ||
464 | usb_unlink_urb(urb[j]); | ||
465 | if (urb[j]->transfer_buffer) | ||
466 | kfree(urb[j]->transfer_buffer); | ||
467 | usb_free_urb(urb[j]); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * Decode frames received on the B/D channel. | ||
473 | * Note that this function will be called continously | ||
474 | * with 64Kbit/s / 16Kbit/s of data and hence it will be | ||
475 | * called 50 times per second with 20 ISOC descriptors. | ||
476 | * Called at interrupt. | ||
477 | */ | ||
478 | static void usb_in_complete(struct urb *urb, struct pt_regs *regs) | ||
479 | { | ||
480 | struct st5481_in *in = urb->context; | ||
481 | unsigned char *ptr; | ||
482 | struct sk_buff *skb; | ||
483 | int len, count, status; | ||
484 | |||
485 | if (unlikely(urb->status < 0)) { | ||
486 | if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { | ||
487 | WARN("urb status %d",urb->status); | ||
488 | } else { | ||
489 | DBG(1,"urb killed"); | ||
490 | return; // Give up | ||
491 | } | ||
492 | } | ||
493 | |||
494 | DBG_ISO_PACKET(0x80,urb); | ||
495 | |||
496 | len = st5481_isoc_flatten(urb); | ||
497 | ptr = urb->transfer_buffer; | ||
498 | while (len > 0) { | ||
499 | if (in->mode == L1_MODE_TRANS) { | ||
500 | memcpy(in->rcvbuf, ptr, len); | ||
501 | status = len; | ||
502 | len = 0; | ||
503 | } else { | ||
504 | status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count, | ||
505 | in->rcvbuf, in->bufsize); | ||
506 | ptr += count; | ||
507 | len -= count; | ||
508 | } | ||
509 | |||
510 | if (status > 0) { | ||
511 | // Good frame received | ||
512 | DBG(4,"count=%d",status); | ||
513 | DBG_PACKET(0x400, in->rcvbuf, status); | ||
514 | if (!(skb = dev_alloc_skb(status))) { | ||
515 | WARN("receive out of memory\n"); | ||
516 | break; | ||
517 | } | ||
518 | memcpy(skb_put(skb, status), in->rcvbuf, status); | ||
519 | in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb); | ||
520 | } else if (status == -HDLC_CRC_ERROR) { | ||
521 | INFO("CRC error"); | ||
522 | } else if (status == -HDLC_FRAMING_ERROR) { | ||
523 | INFO("framing error"); | ||
524 | } else if (status == -HDLC_LENGTH_ERROR) { | ||
525 | INFO("length error"); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | // Prepare URB for next transfer | ||
530 | urb->dev = in->adapter->usb_dev; | ||
531 | urb->actual_length = 0; | ||
532 | |||
533 | SUBMIT_URB(urb, GFP_ATOMIC); | ||
534 | } | ||
535 | |||
536 | int st5481_setup_in(struct st5481_in *in) | ||
537 | { | ||
538 | struct usb_device *dev = in->adapter->usb_dev; | ||
539 | int retval; | ||
540 | |||
541 | DBG(4,""); | ||
542 | |||
543 | in->rcvbuf = kmalloc(in->bufsize, GFP_KERNEL); | ||
544 | retval = -ENOMEM; | ||
545 | if (!in->rcvbuf) | ||
546 | goto err; | ||
547 | |||
548 | retval = st5481_setup_isocpipes(in->urb, dev, | ||
549 | usb_rcvisocpipe(dev, in->ep), | ||
550 | in->num_packets, in->packet_size, | ||
551 | in->num_packets * in->packet_size, | ||
552 | usb_in_complete, in); | ||
553 | if (retval) | ||
554 | goto err_free; | ||
555 | return 0; | ||
556 | |||
557 | err_free: | ||
558 | kfree(in->rcvbuf); | ||
559 | err: | ||
560 | return retval; | ||
561 | } | ||
562 | |||
563 | void st5481_release_in(struct st5481_in *in) | ||
564 | { | ||
565 | DBG(2,""); | ||
566 | |||
567 | st5481_release_isocpipes(in->urb); | ||
568 | } | ||
569 | |||
570 | /* | ||
571 | * Make the transfer_buffer contiguous by | ||
572 | * copying from the iso descriptors if necessary. | ||
573 | */ | ||
574 | int st5481_isoc_flatten(struct urb *urb) | ||
575 | { | ||
576 | struct usb_iso_packet_descriptor *pipd,*pend; | ||
577 | unsigned char *src,*dst; | ||
578 | unsigned int len; | ||
579 | |||
580 | if (urb->status < 0) { | ||
581 | return urb->status; | ||
582 | } | ||
583 | for (pipd = &urb->iso_frame_desc[0], | ||
584 | pend = &urb->iso_frame_desc[urb->number_of_packets], | ||
585 | dst = urb->transfer_buffer; | ||
586 | pipd < pend; | ||
587 | pipd++) { | ||
588 | |||
589 | if (pipd->status < 0) { | ||
590 | return (pipd->status); | ||
591 | } | ||
592 | |||
593 | len = pipd->actual_length; | ||
594 | pipd->actual_length = 0; | ||
595 | src = urb->transfer_buffer+pipd->offset; | ||
596 | |||
597 | if (src != dst) { | ||
598 | // Need to copy since isoc buffers not full | ||
599 | while (len--) { | ||
600 | *dst++ = *src++; | ||
601 | } | ||
602 | } else { | ||
603 | // No need to copy, just update destination buffer | ||
604 | dst += len; | ||
605 | } | ||
606 | } | ||
607 | // Return size of flattened buffer | ||
608 | return (dst - (unsigned char *)urb->transfer_buffer); | ||
609 | } | ||
610 | |||
611 | static void st5481_start_rcv(void *context) | ||
612 | { | ||
613 | struct st5481_in *in = context; | ||
614 | struct st5481_adapter *adapter = in->adapter; | ||
615 | |||
616 | DBG(4,""); | ||
617 | |||
618 | in->urb[0]->dev = adapter->usb_dev; | ||
619 | SUBMIT_URB(in->urb[0], GFP_KERNEL); | ||
620 | |||
621 | in->urb[1]->dev = adapter->usb_dev; | ||
622 | SUBMIT_URB(in->urb[1], GFP_KERNEL); | ||
623 | } | ||
624 | |||
625 | void st5481_in_mode(struct st5481_in *in, int mode) | ||
626 | { | ||
627 | if (in->mode == mode) | ||
628 | return; | ||
629 | |||
630 | in->mode = mode; | ||
631 | |||
632 | usb_unlink_urb(in->urb[0]); | ||
633 | usb_unlink_urb(in->urb[1]); | ||
634 | |||
635 | if (in->mode != L1_MODE_NULL) { | ||
636 | if (in->mode != L1_MODE_TRANS) | ||
637 | isdnhdlc_rcv_init(&in->hdlc_state, | ||
638 | in->mode == L1_MODE_HDLC_56K); | ||
639 | |||
640 | st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); | ||
641 | st5481_usb_device_ctrl_msg(in->adapter, in->counter, | ||
642 | in->packet_size, | ||
643 | NULL, NULL); | ||
644 | st5481_start_rcv(in); | ||
645 | } else { | ||
646 | st5481_usb_device_ctrl_msg(in->adapter, in->counter, | ||
647 | 0, NULL, NULL); | ||
648 | } | ||
649 | } | ||
650 | |||