aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2005-04-21 15:28:02 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:45 -0400
commit884b600f63dc7c646f415a5d8f356df1f66ff6f2 (patch)
tree64f843dc70a12a6d9f7bd3181b3f5c99daab12b0 /drivers/usb/class
parentd5926ae7a827bdd06b588ffbc56fd4525cd9214a (diff)
[PATCH] USB: fix acm trouble with terminals
This patch fixes lost LF when ACM device is used with getty/login/bash, in case of a modem which takes calls. Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Oliver Neukum <oliver@neukum.name> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r--drivers/usb/class/cdc-acm.c209
-rw-r--r--drivers/usb/class/cdc-acm.h25
2 files changed, 197 insertions, 37 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 6d1f9b6aecff..69e859e0f51d 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -106,6 +106,111 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
106 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) 106 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
107 107
108/* 108/*
109 * Write buffer management.
110 * All of these assume proper locks taken by the caller.
111 */
112
113static int acm_wb_alloc(struct acm *acm)
114{
115 int i, wbn;
116 struct acm_wb *wb;
117
118 wbn = acm->write_current;
119 i = 0;
120 for (;;) {
121 wb = &acm->wb[wbn];
122 if (!wb->use) {
123 wb->use = 1;
124 return wbn;
125 }
126 wbn = (wbn + 1) % ACM_NWB;
127 if (++i >= ACM_NWB)
128 return -1;
129 }
130}
131
132static void acm_wb_free(struct acm *acm, int wbn)
133{
134 acm->wb[wbn].use = 0;
135}
136
137static int acm_wb_is_avail(struct acm *acm)
138{
139 int i, n;
140
141 n = 0;
142 for (i = 0; i < ACM_NWB; i++) {
143 if (!acm->wb[i].use)
144 n++;
145 }
146 return n;
147}
148
149static inline int acm_wb_is_used(struct acm *acm, int wbn)
150{
151 return acm->wb[wbn].use;
152}
153
154/*
155 * Finish write.
156 */
157static void acm_write_done(struct acm *acm)
158{
159 unsigned long flags;
160 int wbn;
161
162 spin_lock_irqsave(&acm->write_lock, flags);
163 acm->write_ready = 1;
164 wbn = acm->write_current;
165 acm_wb_free(acm, wbn);
166 acm->write_current = (wbn + 1) % ACM_NWB;
167 spin_unlock_irqrestore(&acm->write_lock, flags);
168}
169
170/*
171 * Poke write.
172 */
173static int acm_write_start(struct acm *acm)
174{
175 unsigned long flags;
176 int wbn;
177 struct acm_wb *wb;
178 int rc;
179
180 spin_lock_irqsave(&acm->write_lock, flags);
181 if (!acm->dev) {
182 spin_unlock_irqrestore(&acm->write_lock, flags);
183 return -ENODEV;
184 }
185
186 if (!acm->write_ready) {
187 spin_unlock_irqrestore(&acm->write_lock, flags);
188 return 0; /* A white lie */
189 }
190
191 wbn = acm->write_current;
192 if (!acm_wb_is_used(acm, wbn)) {
193 spin_unlock_irqrestore(&acm->write_lock, flags);
194 return 0;
195 }
196 wb = &acm->wb[wbn];
197
198 acm->write_ready = 0;
199 spin_unlock_irqrestore(&acm->write_lock, flags);
200
201 acm->writeurb->transfer_buffer = wb->buf;
202 acm->writeurb->transfer_dma = wb->dmah;
203 acm->writeurb->transfer_buffer_length = wb->len;
204 acm->writeurb->dev = acm->dev;
205
206 if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
207 dbg("usb_submit_urb(write bulk) failed: %d", rc);
208 acm_write_done(acm);
209 }
210 return rc;
211}
212
213/*
109 * Interrupt handlers for various ACM device responses 214 * Interrupt handlers for various ACM device responses
110 */ 215 */
111 216
@@ -237,17 +342,13 @@ static void acm_rx_tasklet(unsigned long _acm)
237static void acm_write_bulk(struct urb *urb, struct pt_regs *regs) 342static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
238{ 343{
239 struct acm *acm = (struct acm *)urb->context; 344 struct acm *acm = (struct acm *)urb->context;
240 dbg("Entering acm_write_bulk with status %d\n", urb->status);
241
242 if (!ACM_READY(acm))
243 goto out;
244 345
245 if (urb->status) 346 dbg("Entering acm_write_bulk with status %d\n", urb->status);
246 dbg("nonzero write bulk status received: %d", urb->status);
247 347
248 schedule_work(&acm->work); 348 acm_write_done(acm);
249out: 349 acm_write_start(acm);
250 acm->ready_for_write = 1; 350 if (ACM_READY(acm))
351 schedule_work(&acm->work);
251} 352}
252 353
253static void acm_softint(void *private) 354static void acm_softint(void *private)
@@ -351,32 +452,33 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
351{ 452{
352 struct acm *acm = tty->driver_data; 453 struct acm *acm = tty->driver_data;
353 int stat; 454 int stat;
455 unsigned long flags;
456 int wbn;
457 struct acm_wb *wb;
458
354 dbg("Entering acm_tty_write to write %d bytes,\n", count); 459 dbg("Entering acm_tty_write to write %d bytes,\n", count);
355 460
356 if (!ACM_READY(acm)) 461 if (!ACM_READY(acm))
357 return -EINVAL; 462 return -EINVAL;
358 if (!acm->ready_for_write)
359 return 0;
360 if (!count) 463 if (!count)
361 return 0; 464 return 0;
362 465
363 count = (count > acm->writesize) ? acm->writesize : count; 466 spin_lock_irqsave(&acm->write_lock, flags);
467 if ((wbn = acm_wb_alloc(acm)) < 0) {
468 spin_unlock_irqrestore(&acm->write_lock, flags);
469 acm_write_start(acm);
470 return 0;
471 }
472 wb = &acm->wb[wbn];
364 473
474 count = (count > acm->writesize) ? acm->writesize : count;
365 dbg("Get %d bytes...", count); 475 dbg("Get %d bytes...", count);
366 memcpy(acm->write_buffer, buf, count); 476 memcpy(wb->buf, buf, count);
367 dbg(" Successfully copied.\n"); 477 wb->len = count;
478 spin_unlock_irqrestore(&acm->write_lock, flags);
368 479
369 acm->writeurb->transfer_buffer_length = count; 480 if ((stat = acm_write_start(acm)) < 0)
370 acm->writeurb->dev = acm->dev;
371
372 acm->ready_for_write = 0;
373 stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
374 if (stat < 0) {
375 dbg("usb_submit_urb(write bulk) failed");
376 acm->ready_for_write = 1;
377 return stat; 481 return stat;
378 }
379
380 return count; 482 return count;
381} 483}
382 484
@@ -385,7 +487,11 @@ static int acm_tty_write_room(struct tty_struct *tty)
385 struct acm *acm = tty->driver_data; 487 struct acm *acm = tty->driver_data;
386 if (!ACM_READY(acm)) 488 if (!ACM_READY(acm))
387 return -EINVAL; 489 return -EINVAL;
388 return !acm->ready_for_write ? 0 : acm->writesize; 490 /*
491 * Do not let the line discipline to know that we have a reserve,
492 * or it might get too enthusiastic.
493 */
494 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
389} 495}
390 496
391static int acm_tty_chars_in_buffer(struct tty_struct *tty) 497static int acm_tty_chars_in_buffer(struct tty_struct *tty)
@@ -393,7 +499,10 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
393 struct acm *acm = tty->driver_data; 499 struct acm *acm = tty->driver_data;
394 if (!ACM_READY(acm)) 500 if (!ACM_READY(acm))
395 return -EINVAL; 501 return -EINVAL;
396 return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0; 502 /*
503 * This is inaccurate (overcounts), but it works.
504 */
505 return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
397} 506}
398 507
399static void acm_tty_throttle(struct tty_struct *tty) 508static void acm_tty_throttle(struct tty_struct *tty)
@@ -526,6 +635,39 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
526 * USB probe and disconnect routines. 635 * USB probe and disconnect routines.
527 */ 636 */
528 637
638/* Little helper: write buffers free */
639static void acm_write_buffers_free(struct acm *acm)
640{
641 int i;
642 struct acm_wb *wb;
643
644 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
645 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
646 }
647}
648
649/* Little helper: write buffers allocate */
650static int acm_write_buffers_alloc(struct acm *acm)
651{
652 int i;
653 struct acm_wb *wb;
654
655 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
656 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
657 &wb->dmah);
658 if (!wb->buf) {
659 while (i != 0) {
660 --i;
661 --wb;
662 usb_buffer_free(acm->dev, acm->writesize,
663 wb->buf, wb->dmah);
664 }
665 return -ENOMEM;
666 }
667 }
668 return 0;
669}
670
529static int acm_probe (struct usb_interface *intf, 671static int acm_probe (struct usb_interface *intf,
530 const struct usb_device_id *id) 672 const struct usb_device_id *id)
531{ 673{
@@ -700,7 +842,8 @@ skip_normal_probe:
700 acm->bh.data = (unsigned long) acm; 842 acm->bh.data = (unsigned long) acm;
701 INIT_WORK(&acm->work, acm_softint, acm); 843 INIT_WORK(&acm->work, acm_softint, acm);
702 spin_lock_init(&acm->throttle_lock); 844 spin_lock_init(&acm->throttle_lock);
703 acm->ready_for_write = 1; 845 spin_lock_init(&acm->write_lock);
846 acm->write_ready = 1;
704 847
705 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); 848 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
706 if (!buf) { 849 if (!buf) {
@@ -716,12 +859,10 @@ skip_normal_probe:
716 } 859 }
717 acm->read_buffer = buf; 860 acm->read_buffer = buf;
718 861
719 buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma); 862 if (acm_write_buffers_alloc(acm) < 0) {
720 if (!buf) {
721 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); 863 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
722 goto alloc_fail4; 864 goto alloc_fail4;
723 } 865 }
724 acm->write_buffer = buf;
725 866
726 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); 867 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
727 if (!acm->ctrlurb) { 868 if (!acm->ctrlurb) {
@@ -750,9 +891,9 @@ skip_normal_probe:
750 acm->readurb->transfer_dma = acm->read_dma; 891 acm->readurb->transfer_dma = acm->read_dma;
751 892
752 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), 893 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
753 acm->write_buffer, acm->writesize, acm_write_bulk, acm); 894 NULL, acm->writesize, acm_write_bulk, acm);
754 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; 895 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
755 acm->writeurb->transfer_dma = acm->write_dma; 896 /* acm->writeurb->transfer_dma = 0; */
756 897
757 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); 898 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
758 899
@@ -775,7 +916,7 @@ alloc_fail7:
775alloc_fail6: 916alloc_fail6:
776 usb_free_urb(acm->ctrlurb); 917 usb_free_urb(acm->ctrlurb);
777alloc_fail5: 918alloc_fail5:
778 usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma); 919 acm_write_buffers_free(acm);
779alloc_fail4: 920alloc_fail4:
780 usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma); 921 usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma);
781alloc_fail3: 922alloc_fail3:
@@ -806,7 +947,7 @@ static void acm_disconnect(struct usb_interface *intf)
806 947
807 flush_scheduled_work(); /* wait for acm_softint */ 948 flush_scheduled_work(); /* wait for acm_softint */
808 949
809 usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma); 950 acm_write_buffers_free(acm);
810 usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma); 951 usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma);
811 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); 952 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
812 953
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 9009114e311b..963a5dfd2096 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -51,14 +51,34 @@
51 * Internal driver structures. 51 * Internal driver structures.
52 */ 52 */
53 53
54/*
55 * The only reason to have several buffers is to accomodate assumptions
56 * in line disciplines. They ask for empty space amount, receive our URB size,
57 * and proceed to issue several 1-character writes, assuming they will fit.
58 * The very first write takes a complete URB. Fortunately, this only happens
59 * when processing onlcr, so we only need 2 buffers.
60 */
61#define ACM_NWB 2
62struct acm_wb {
63 unsigned char *buf;
64 dma_addr_t dmah;
65 int len;
66 int use;
67};
68
54struct acm { 69struct acm {
55 struct usb_device *dev; /* the corresponding usb device */ 70 struct usb_device *dev; /* the corresponding usb device */
56 struct usb_interface *control; /* control interface */ 71 struct usb_interface *control; /* control interface */
57 struct usb_interface *data; /* data interface */ 72 struct usb_interface *data; /* data interface */
58 struct tty_struct *tty; /* the corresponding tty */ 73 struct tty_struct *tty; /* the corresponding tty */
59 struct urb *ctrlurb, *readurb, *writeurb; /* urbs */ 74 struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
60 u8 *ctrl_buffer, *read_buffer, *write_buffer; /* buffers of urbs */ 75 u8 *ctrl_buffer, *read_buffer; /* buffers of urbs */
61 dma_addr_t ctrl_dma, read_dma, write_dma; /* dma handles of buffers */ 76 dma_addr_t ctrl_dma, read_dma; /* dma handles of buffers */
77 struct acm_wb wb[ACM_NWB];
78 int write_current; /* current write buffer */
79 int write_used; /* number of non-empty write buffers */
80 int write_ready; /* write urb is not running */
81 spinlock_t write_lock;
62 struct usb_cdc_line_coding line; /* bits, stop, parity */ 82 struct usb_cdc_line_coding line; /* bits, stop, parity */
63 struct work_struct work; /* work queue entry for line discipline waking up */ 83 struct work_struct work; /* work queue entry for line discipline waking up */
64 struct tasklet_struct bh; /* rx processing */ 84 struct tasklet_struct bh; /* rx processing */
@@ -71,7 +91,6 @@ struct acm {
71 unsigned int minor; /* acm minor number */ 91 unsigned int minor; /* acm minor number */
72 unsigned char throttle; /* throttled by tty layer */ 92 unsigned char throttle; /* throttled by tty layer */
73 unsigned char clocal; /* termios CLOCAL */ 93 unsigned char clocal; /* termios CLOCAL */
74 unsigned char ready_for_write; /* write urb can be used */
75 unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */ 94 unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */
76 unsigned int ctrl_caps; /* control capabilities from the class specific header */ 95 unsigned int ctrl_caps; /* control capabilities from the class specific header */
77}; 96};