ti-ocf-crypto-module: add crypto module for hw accel
[openembedded.git] / recipes / linux / linux-mtx-1-2.4.27 / 45-acm-tty-and-sb2.patch
blob4561facb731465f0014ff0bc310e5d915e0dfd39
1 --- linux/drivers/usb/acm.c-orig 2007-04-13 18:32:16.352672105 +0200
2 +++ linux/drivers/usb/acm.c 2007-04-13 18:33:21.063526545 +0200
3 @@ -124,6 +124,9 @@
4 #define ACM_CTRL_PARITY 0x20
5 #define ACM_CTRL_OVERRUN 0x40
7 +// some devices don't have one comm and one data interface, but only one interface with endpoints for comm and data
8 +#define SINGLE_IF_ACM 0x01
11 * Line speed and caracter encoding.
13 @@ -139,6 +142,8 @@
14 * Internal driver structures.
17 +#define TD_SIZE 16384
19 struct acm {
20 struct usb_device *dev; /* the coresponding usb device */
21 struct usb_interface *iface; /* the interfaces - +0 control +1 data */
22 @@ -153,12 +158,23 @@
23 unsigned int minor; /* acm minor number */
24 unsigned char throttle; /* throttled by tty layer */
25 unsigned char clocal; /* termios CLOCAL */
26 + unsigned long throttle_start;
27 + unsigned char resubmit_to_unthrottle; /* Leftover data from last operation */
28 + unsigned char *throttle_data;
29 + int td_len;
30 + int td_busy;
31 + unsigned char used_interfaces;
32 + struct semaphore mutex;
35 +#define mutex_lock(x) down(x)
36 +#define mutex_unlock(x) up(x)
38 /* global params controlling max sizes for read, write, control */
39 static int maxszr = 0;
40 static int maxszw = 0;
41 static int maxszc = 0;
42 +static int nonlegacy = 0;
44 static struct usb_driver acm_driver;
45 static struct tty_driver acm_tty_driver;
46 @@ -167,6 +183,95 @@
47 #define ACM_READY(acm) (acm && acm->dev && acm->used)
50 + * Helper functions to optimize throttleing
51 + */
52 +static int
53 +acm_fill_tty(struct urb *urb, struct tty_struct *tty, unsigned char *data, int length)
55 + struct acm *acm = urb->context;
56 + int n = 0;
57 + /*printk("acm_fill_tty: %d bytes\n", length);*/
58 + if (!urb->status && !acm->throttle) {
59 + for (n = 0; n < length && !acm->throttle; n++) {
60 + /* if we insert more than TTY_FLIPBUF_SIZE characters,
61 + * we drop them. */
62 + if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
63 + tty_flip_buffer_push(tty);
64 + }
65 + tty_insert_flip_char(tty, data[n], 0);
66 + }
67 + tty_flip_buffer_push(tty);
68 + }
69 + /*printk("copied %d bytes.\n", n);*/
70 + return n;
73 +static int
74 +acm_shift_if_throttle(unsigned char *data, int *length, int shift_by)
76 + if (shift_by < *length) {
77 + dbg("need to shift uncopied %d bytes to front.", *length - shift_by);
78 + memmove(data, data + shift_by, *length - shift_by);
79 + *length -= shift_by;
80 + return 1;
81 + }
82 + return 0;
85 +static int
86 +acm_buffer_if_thottle(struct acm *acm, unsigned char *data, int start, int *length)
88 + int copied = *length;
89 + if (start < *length) {
90 + int space = TD_SIZE - acm->td_len;
91 + int needed = *length - start;
92 + copied = (space < needed)? space: needed;
93 + dbg("need to push %d to throttle buffer, can copy %d.",
94 + needed, copied);
95 + memcpy(acm->throttle_data + acm->td_len, data, copied);
96 + acm->td_len += copied;
97 + *length -= copied;
98 + }
99 + return copied;
102 +static int
103 +acm_empty_throttle(struct urb *urb, struct tty_struct *tty)
105 + unsigned long flags;
106 + struct acm *acm = urb->context;
108 + save_flags(flags);
109 + cli();
111 + if (acm->td_busy) {
112 + restore_flags(flags);
113 + return 0;
115 + acm->td_busy = 1;
116 + restore_flags(flags);
118 + if (acm->td_len > 0) {
120 + dbg("acm_empty_throttle: trying to empty throttle buffer: %d bytes.",
121 + acm->td_len);
123 + /* if there has been something left from previous operations
124 + * we try to complete this before looking at the urb */
125 + int copied = acm_fill_tty(urb, tty, acm->throttle_data, acm->td_len);
126 + if (acm_shift_if_throttle(acm->throttle_data, &acm->td_len, copied)) {
127 + /* we were unable to empty the throttle data, so we can't
128 + * copy anything more now */
129 + acm->td_busy = 0;
130 + return 0;
132 + acm->td_len = 0;
134 + acm->td_busy = 0;
135 + return 1;
139 * Functions for ACM control messages.
142 @@ -174,7 +279,10 @@
144 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
145 request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);
146 - dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
147 + if (retval < 0)
148 + err("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
149 + else
150 + dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
151 return retval < 0 ? retval : 0;
154 @@ -191,10 +299,12 @@
155 struct acm *acm = urb->context;
156 struct usb_ctrlrequest *dr = urb->transfer_buffer;
157 unsigned char *data = (unsigned char *)(dr + 1);
158 - int newctrl;
159 + int newctrl, s1, s2;
161 if (!ACM_READY(acm)) return;
163 + //err("acm_ctrl_irq %p %i", urb, dr->bRequestType);
165 if (urb->status < 0) {
166 dbg("nonzero ctrl irq status received: %d", urb->status);
167 return;
168 @@ -226,8 +336,15 @@
170 return;
172 + case 0x2a:
173 + s1 = le32_to_cpup((__u32 *) data);
174 + s2 = le32_to_cpup((__u32 *) (data+4));
176 + dbg("acm.c: ctrl 0x2a: idx %i len %i speed %i %i", dr->wIndex, dr->wLength, s1, s2);
177 + return;
179 default:
180 - dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
181 + err("unknown control event received: request %d index %d len %d data0 %d data1 %d",
182 dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);
183 return;
185 @@ -238,36 +355,39 @@
186 struct acm *acm = urb->context;
187 struct tty_struct *tty = acm->tty;
188 unsigned char *data = urb->transfer_buffer;
189 - int i = 0;
190 + int copied = 0;
191 + int buffered = 0;
193 if (!ACM_READY(acm)) return;
195 - if (urb->status)
196 - dbg("nonzero read bulk status received: %d", urb->status);
197 + if (urb->status) {
198 + err("nonzero read bulk status received: %d", urb->status);
201 - if (!urb->status && !acm->throttle) {
202 - for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
203 - /* if we insert more than TTY_FLIPBUF_SIZE characters,
204 - * we drop them. */
205 - if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
206 - tty_flip_buffer_push(tty);
208 - tty_insert_flip_char(tty, data[i], 0);
210 - tty_flip_buffer_push(tty);
211 + if (!acm_empty_throttle(urb, tty)) {
212 + dbg("could not empty throttle buffer, entering throttle state, acm->td_busy: %d.", acm->td_busy);
215 + /* got here, either there was nothing in the throttle data or it could
216 + * all be copied without throttleing again */
217 + copied = acm_fill_tty(urb, tty, data, urb->actual_length);
218 if (acm->throttle) {
219 - memmove(data, data + i, urb->actual_length - i);
220 - urb->actual_length -= i;
221 - return;
222 + int length = urb->actual_length;
223 + buffered = acm_buffer_if_thottle(acm, data, copied, &urb->actual_length);
224 + if (buffered < length - copied
225 + && acm_shift_if_throttle(data, &urb->actual_length, copied + buffered)) {
226 + dbg("need to resubmit to unthrottle\n");
227 + acm->resubmit_to_unthrottle = 1;
228 + return;
232 urb->actual_length = 0;
233 urb->dev = acm->dev;
235 - if (usb_submit_urb(urb))
236 + if (usb_submit_urb(urb)) {
237 dbg("failed resubmitting read urb");
241 static void acm_write_bulk(struct urb *urb)
242 @@ -283,6 +403,9 @@
243 mark_bh(IMMEDIATE_BH);
246 +static int unlinking_in_progress=0;
247 +static int closing=0;
249 static void acm_softint(void *private)
251 struct acm *acm = private;
252 @@ -306,34 +429,57 @@
254 if (!acm || !acm->dev) return -EINVAL;
256 + mutex_lock (&acm->mutex);
258 tty->driver_data = acm;
259 acm->tty = tty;
261 MOD_INC_USE_COUNT;
263 - lock_kernel();
264 + if ( closing )
265 + err("acm_tty_open: potential possibility of race condition detected");
267 + if ( unlinking_in_progress ) {
268 + err("acm_tty_open: cannot open because unlinking_in_progress %i", acm->used);
269 + mutex_unlock (&acm->mutex);
270 + return -1;
273 - if (acm->used++) {
274 - unlock_kernel();
275 - return 0;
277 + if (acm->used) {
278 + acm->used++;
279 + mutex_unlock (&acm->mutex);
280 + return 0;
283 - unlock_kernel();
284 + unlinking_in_progress=1;
285 + err("acm_tty_open: %i %p !!", acm->used, tty);
287 + acm->resubmit_to_unthrottle = 0;
288 + acm->td_len = 0;
289 + acm->td_busy = 0;
291 acm->ctrlurb.dev = acm->dev;
292 if (usb_submit_urb(&acm->ctrlurb))
293 - dbg("usb_submit_urb(ctrl irq) failed");
294 + dbg("acm open: usb_submit_urb(ctrl irq) failed");
295 + else
296 + dbg("acm open: ctrlurb %p submitted", &acm->ctrlurb);
298 + acm->used++;
299 + acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
301 acm->readurb.dev = acm->dev;
302 if (usb_submit_urb(&acm->readurb))
303 - dbg("usb_submit_urb(read bulk) failed");
305 - acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
306 + dbg("acm open: usb_submit_urb(read bulk) failed");
307 + else
308 + dbg("acm open: readurb %p submitted", &acm->readurb);
310 - /* force low_latency on so that our tty_push actually forces the data through,
311 + /* force low_latency on so that our tty_push actually forces the data through,
312 otherwise it is scheduled, and with high data rates data can get lost. */
313 tty->low_latency = 1;
315 + unlinking_in_progress=0;
316 + mutex_unlock (&acm->mutex);
318 return 0;
321 @@ -343,19 +489,35 @@
323 if (!acm || !acm->used) return;
325 - if (!--acm->used) {
326 - if (acm->dev) {
327 - acm_set_control(acm, acm->ctrlout = 0);
328 - usb_unlink_urb(&acm->ctrlurb);
329 - usb_unlink_urb(&acm->writeurb);
330 - usb_unlink_urb(&acm->readurb);
331 - } else {
332 - tty_unregister_devfs(&acm_tty_driver, acm->minor);
333 - acm_table[acm->minor] = NULL;
334 - kfree(acm);
336 + mutex_lock (&acm->mutex);
338 + closing = 1;
339 + if (--acm->used) {
340 + closing=0;
341 + MOD_DEC_USE_COUNT;
342 + mutex_unlock (&acm->mutex);
343 + return;
345 + unlinking_in_progress = 1;
347 + err("acm_tty_close: %i %p", acm->used, tty);
349 + if (acm->dev) {
350 + acm_set_control(acm, acm->ctrlout = 0);
351 + usb_unlink_urb(&acm->ctrlurb);
352 + usb_unlink_urb(&acm->writeurb);
353 + usb_unlink_urb(&acm->readurb);
354 + } else {
355 + tty_unregister_devfs(&acm_tty_driver, acm->minor);
356 + acm_table[acm->minor] = NULL;
357 + kfree(acm->throttle_data);
358 + kfree(acm);
361 + closing=0;
362 + unlinking_in_progress = 0;
363 MOD_DEC_USE_COUNT;
364 + mutex_unlock (&acm->mutex);
367 static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
368 @@ -363,8 +525,16 @@
369 struct acm *acm = tty->driver_data;
371 if (!ACM_READY(acm)) return -EINVAL;
372 - if (acm->writeurb.status == -EINPROGRESS) return 0;
373 - if (!count) return 0;
375 + if (acm->writeurb.status == -EINPROGRESS) {
376 + dbg("tty_write in progress");
377 + return 0;
380 + if (!count) {
381 + dbg("tty_write: nothing to write");
382 + return 0;
385 count = (count > acm->writesize) ? acm->writesize : count;
387 @@ -401,22 +571,44 @@
389 struct acm *acm = tty->driver_data;
390 if (!ACM_READY(acm)) return;
391 + dbg("acm_tty_throttle ON %ld ---> %ld", jiffies-acm->throttle_start, jiffies);
392 acm->throttle = 1;
393 + acm->throttle_start = jiffies;
396 static void acm_tty_unthrottle(struct tty_struct *tty)
398 struct acm *acm = tty->driver_data;
399 if (!ACM_READY(acm)) return;
400 + dbg("acm_tty_throttle OFF %ld ---> %ld", jiffies, jiffies-acm->throttle_start);
401 acm->throttle = 0;
402 - if (acm->readurb.status != -EINPROGRESS)
404 + if (!acm_empty_throttle(&acm->readurb, tty)) {
405 + if (acm->td_busy) {
406 + printk("***** pending acm_empty_throttle!\n");
407 + } else {
408 + dbg("throttle not emptied.\n");
412 + if (acm->resubmit_to_unthrottle != 0) {
413 + dbg("resubmit_to_unthrottle: acm_read_bulk");
414 + acm->resubmit_to_unthrottle = 0;
415 acm_read_bulk(&acm->readurb);
419 static void acm_tty_break_ctl(struct tty_struct *tty, int state)
421 struct acm *acm = tty->driver_data;
423 if (!ACM_READY(acm)) return;
425 + if (nonlegacy) {
426 + err("non-legacy port, skipping acm_tty_break_ctl");
427 + return;
430 if (acm_send_break(acm, state ? 0xffff : 0))
431 dbg("send break failed");
433 @@ -455,7 +647,19 @@
434 case TIOCMBIC: newctrl &= ~mask; break;
437 - if (acm->ctrlout == newctrl) return 0;
438 + if (acm->ctrlout == newctrl) {
439 + dbg("acm_tty_ioctl: set old state %x", newctrl);
440 + return 0;
443 + err("acm_tty_ioctl: %s%s%s -> dtr%s rts%s (%lx)",
444 + cmd==TIOCMBIC?"Clear":(cmd==TIOCMBIS?"Set":"SET"),
445 + mask & ACM_CTRL_DTR ? " DTR":"",
446 + mask & ACM_CTRL_RTS ? " RTS":"",
447 + newctrl & ACM_CTRL_DTR ? "+":"-",
448 + newctrl & ACM_CTRL_RTS ? "+":"-",
449 + arg);
451 return acm_set_control(acm, acm->ctrlout = newctrl);
454 @@ -483,6 +687,12 @@
456 if (!ACM_READY(acm)) return;
458 + if (nonlegacy) {
459 + acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
460 + dbg("non-legacy port, skipping acm_tty_set_termios");
461 + return;
464 newline.speed = cpu_to_le32p(acm_tty_speed +
465 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
466 newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
467 @@ -518,34 +727,64 @@
468 struct usb_config_descriptor *cfacm;
469 struct usb_interface_descriptor *ifcom, *ifdata;
470 struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
471 - int readsize, ctrlsize, minor, i, j;
472 + int readsize, ctrlsize, minor, i;
473 unsigned char *buf;
474 + unsigned char used_interfaces=2;
476 for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
478 cfacm = dev->config + i;
480 - dbg("probing config %d", cfacm->bConfigurationValue);
481 + ifcom = cfacm->interface[ifnum].altsetting + 0;
483 + if (id->driver_info == SINGLE_IF_ACM) {
484 + printk("using single_if_acm\n");
485 + struct usb_endpoint_descriptor *ep=ifcom->endpoint;
486 + int k;
488 + if (ifcom->bNumEndpoints != 3) {
489 + continue;
492 + epctrl = epread = epwrite = NULL;
493 + for (k=0; k<3; ++k, ++ep) {
494 + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT &&
495 + (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
496 + epctrl = ep;
497 + } else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK &&
498 + (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
499 + epread = ep;
500 + } else if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
501 + epwrite = ep;
505 - for (j = 0; j < cfacm->bNumInterfaces - 1; j++) {
506 + if ( !epctrl || !epread || !epwrite ) {
507 + dbg("SINGLE_IF_ACM acm_probe inv eps epctrl %s epread %s epwrite %s", epctrl?"ok":"missing",
508 + epread?"ok":"missing", epwrite?"ok":"missing");
509 + dbg("SINGLE_IF_ACM Invalid enpoint configuration");
510 + continue;
513 - if (usb_interface_claimed(cfacm->interface + j) ||
514 - usb_interface_claimed(cfacm->interface + j + 1))
515 + used_interfaces = 1;
516 + } else {
517 + if ((ifnum+1)>=cfacm->bNumInterfaces || usb_interface_claimed(cfacm->interface + ifnum + 1)) {
518 + // no data interface available
519 continue;
522 - ifcom = cfacm->interface[j].altsetting + 0;
523 - ifdata = cfacm->interface[j + 1].altsetting + 0;
524 + ifdata = cfacm->interface[ifnum + 1].altsetting + 0;
526 if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
527 - ifcom = cfacm->interface[j + 1].altsetting + 0;
528 - ifdata = cfacm->interface[j].altsetting + 0;
529 + ifcom = cfacm->interface[ifnum + 1].altsetting + 0;
530 + ifdata = cfacm->interface[ifnum].altsetting + 0;
531 if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
532 continue;
535 if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
536 - ifcom->bInterfaceProtocol < 1 || ifcom->bInterfaceProtocol > 6 ||
537 - ifcom->bNumEndpoints < 1)
538 + ifcom->bInterfaceProtocol < 1 || ifcom->bInterfaceProtocol > 6 ||
539 + ifcom->bNumEndpoints < 1)
540 continue;
542 epctrl = ifcom->endpoint + 0;
543 @@ -553,76 +792,86 @@
544 epwrite = ifdata->endpoint + 1;
546 if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
547 - (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
548 - ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
549 + (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
550 + ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
551 continue;
553 - dbg("using interface %d\n", j);
555 if ((epread->bEndpointAddress & 0x80) != 0x80) {
556 epread = ifdata->endpoint + 1;
557 epwrite = ifdata->endpoint + 0;
561 - usb_set_configuration(dev, cfacm->bConfigurationValue);
562 + usb_set_configuration(dev, cfacm->bConfigurationValue);
564 - for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
565 - if (acm_table[minor]) {
566 - err("no more free acm devices");
567 - return NULL;
569 + for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
570 + if (acm_table[minor]) {
571 + err("no more free acm devices");
572 + return NULL;
575 - if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
576 - err("out of memory");
577 - return NULL;
579 - memset(acm, 0, sizeof(struct acm));
580 + if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
581 + err("out of memory");
582 + return NULL;
584 + memset(acm, 0, sizeof(struct acm));
586 - ctrlsize = (epctrl->wMaxPacketSize > maxszc)?
587 - epctrl->wMaxPacketSize: maxszc;
588 - readsize = (epread->wMaxPacketSize > maxszr)?
589 - epread->wMaxPacketSize: maxszr;
590 - acm->writesize = (epwrite->wMaxPacketSize > maxszw)?
591 - epwrite->wMaxPacketSize: maxszw;
593 - acm->iface = cfacm->interface + j;
594 - acm->minor = minor;
595 - acm->dev = dev;
597 - acm->tqueue.routine = acm_softint;
598 - acm->tqueue.data = acm;
600 - if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
601 - err("out of memory");
602 - kfree(acm);
603 - return NULL;
605 + ctrlsize = (epctrl->wMaxPacketSize > maxszc)?
606 + epctrl->wMaxPacketSize: maxszc;
607 + readsize = (epread->wMaxPacketSize > maxszr)?
608 + epread->wMaxPacketSize: maxszr;
609 + acm->writesize = (epwrite->wMaxPacketSize > maxszw)?
610 + epwrite->wMaxPacketSize: maxszw;
612 + init_MUTEX (&acm->mutex);
613 + if (!(acm->throttle_data = kmalloc(TD_SIZE * sizeof (*acm->throttle_data), GFP_KERNEL))) {
614 + err("out of memory (throttle_data)");
615 + kfree(acm);
616 + return NULL;
618 + acm->iface = cfacm->interface + ifnum;
619 + acm->minor = minor;
620 + acm->dev = dev;
622 - FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
623 - buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
624 + acm->used_interfaces = used_interfaces;
626 - FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
627 - buf += ctrlsize, readsize, acm_read_bulk, acm);
628 - acm->readurb.transfer_flags |= USB_NO_FSBR;
629 + acm->tqueue.routine = acm_softint;
630 + acm->tqueue.data = acm;
632 - FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
633 - buf += readsize, acm->writesize, acm_write_bulk, acm);
634 - acm->writeurb.transfer_flags |= USB_NO_FSBR;
635 + if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
636 + err("out of memory (urb buf)");
637 + kfree(acm);
638 + return NULL;
641 - printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
642 + FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
643 + buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
645 - acm_set_control(acm, acm->ctrlout);
646 + FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
647 + buf += ctrlsize, readsize, acm_read_bulk, acm);
648 + acm->readurb.transfer_flags |= USB_NO_FSBR;
650 - acm->line.speed = cpu_to_le32(9600);
651 - acm->line.databits = 8;
652 - acm_set_line(acm, &acm->line);
653 + FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
654 + buf += readsize, acm->writesize, acm_write_bulk, acm);
655 + acm->writeurb.transfer_flags |= USB_NO_FSBR;
657 - usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
658 - usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
659 + printk(KERN_INFO "ttyACM%d: USB ACM device C %p W %p R %p %x\n", minor, &acm->ctrlurb,
660 + &acm->writeurb, &acm->readurb, acm->ctrlout);
662 + acm_set_control(acm, acm->ctrlout);
664 - tty_register_devfs(&acm_tty_driver, 0, minor);
665 - return acm_table[minor] = acm;
666 + acm->line.speed = cpu_to_le32(9600);
667 + acm->line.databits = 8;
668 + acm_set_line(acm, &acm->line);
670 + if ( acm->used_interfaces == 2 ) {
671 + // only just checked interface is claimed automatically, so claim data interface too
672 + usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
675 + tty_register_devfs(&acm_tty_driver, 0, minor);
677 + return acm_table[minor] = acm;
680 return NULL;
681 @@ -646,7 +895,9 @@
682 kfree(acm->ctrlurb.transfer_buffer);
684 usb_driver_release_interface(&acm_driver, acm->iface + 0);
685 - usb_driver_release_interface(&acm_driver, acm->iface + 1);
686 + if ( acm->used_interfaces == 2 ) {
687 + usb_driver_release_interface(&acm_driver, acm->iface + 1);
690 if (!acm->used) {
691 tty_unregister_devfs(&acm_tty_driver, acm->minor);
692 @@ -665,6 +916,9 @@
694 static struct usb_device_id acm_ids[] = {
695 { USB_DEVICE(0x22B8, 0x1005) }, /* Motorola TimePort 280 */
696 + { USB_DEVICE(0x05C6, 0x7001), driver_info: SINGLE_IF_ACM }, /* Siemens HC15/HC25 */
697 + { USB_DEVICE(0x0681, 0x003e), driver_info: SINGLE_IF_ACM }, /* Siemens HC15/HC25 */
698 + { USB_DEVICE(0x22B8, 0x1006) },
699 { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
700 { USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
702 @@ -735,7 +989,7 @@
703 return -1;
706 - info(DRIVER_VERSION ":" DRIVER_DESC);
707 + info(DRIVER_VERSION ":" DRIVER_DESC "(non-legacy %d)", nonlegacy);
709 return 0;
711 @@ -759,7 +1013,9 @@
712 MODULE_PARM(maxszc, "i");
713 MODULE_PARM_DESC(maxszc, "User specified USB endpoint control size");
715 +MODULE_PARM(nonlegacy, "i");
716 +MODULE_PARM_DESC(nonlegacy, "Set this to 1 to for use with non-legacy device");
718 MODULE_AUTHOR( DRIVER_AUTHOR );
719 MODULE_DESCRIPTION( DRIVER_DESC );
720 MODULE_LICENSE("GPL");