diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 98 |
1 files changed, 52 insertions, 46 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0147ea39340e..7b572e75e73c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -31,6 +31,7 @@ | |||
31 | * v0.23 - use softirq for rx processing, as needed by tty layer | 31 | * v0.23 - use softirq for rx processing, as needed by tty layer |
32 | * v0.24 - change probe method to evaluate CDC union descriptor | 32 | * v0.24 - change probe method to evaluate CDC union descriptor |
33 | * v0.25 - downstream tasks paralelized to maximize throughput | 33 | * v0.25 - downstream tasks paralelized to maximize throughput |
34 | * v0.26 - multiple write urbs, writesize increased | ||
34 | */ | 35 | */ |
35 | 36 | ||
36 | /* | 37 | /* |
@@ -72,7 +73,7 @@ | |||
72 | /* | 73 | /* |
73 | * Version Information | 74 | * Version Information |
74 | */ | 75 | */ |
75 | #define DRIVER_VERSION "v0.25" | 76 | #define DRIVER_VERSION "v0.26" |
76 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" | 77 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" |
77 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" | 78 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" |
78 | 79 | ||
@@ -118,7 +119,7 @@ static int acm_wb_alloc(struct acm *acm) | |||
118 | int i, wbn; | 119 | int i, wbn; |
119 | struct acm_wb *wb; | 120 | struct acm_wb *wb; |
120 | 121 | ||
121 | wbn = acm->write_current; | 122 | wbn = 0; |
122 | i = 0; | 123 | i = 0; |
123 | for (;;) { | 124 | for (;;) { |
124 | wb = &acm->wb[wbn]; | 125 | wb = &acm->wb[wbn]; |
@@ -132,11 +133,6 @@ static int acm_wb_alloc(struct acm *acm) | |||
132 | } | 133 | } |
133 | } | 134 | } |
134 | 135 | ||
135 | static void acm_wb_free(struct acm *acm, int wbn) | ||
136 | { | ||
137 | acm->wb[wbn].use = 0; | ||
138 | } | ||
139 | |||
140 | static int acm_wb_is_avail(struct acm *acm) | 136 | static int acm_wb_is_avail(struct acm *acm) |
141 | { | 137 | { |
142 | int i, n; | 138 | int i, n; |
@@ -156,26 +152,22 @@ static inline int acm_wb_is_used(struct acm *acm, int wbn) | |||
156 | /* | 152 | /* |
157 | * Finish write. | 153 | * Finish write. |
158 | */ | 154 | */ |
159 | static void acm_write_done(struct acm *acm) | 155 | static void acm_write_done(struct acm *acm, struct acm_wb *wb) |
160 | { | 156 | { |
161 | unsigned long flags; | 157 | unsigned long flags; |
162 | int wbn; | ||
163 | 158 | ||
164 | spin_lock_irqsave(&acm->write_lock, flags); | 159 | spin_lock_irqsave(&acm->write_lock, flags); |
165 | acm->write_ready = 1; | 160 | acm->write_ready = 1; |
166 | wbn = acm->write_current; | 161 | wb->use = 0; |
167 | acm_wb_free(acm, wbn); | ||
168 | acm->write_current = (wbn + 1) % ACM_NW; | ||
169 | spin_unlock_irqrestore(&acm->write_lock, flags); | 162 | spin_unlock_irqrestore(&acm->write_lock, flags); |
170 | } | 163 | } |
171 | 164 | ||
172 | /* | 165 | /* |
173 | * Poke write. | 166 | * Poke write. |
174 | */ | 167 | */ |
175 | static int acm_write_start(struct acm *acm) | 168 | static int acm_write_start(struct acm *acm, int wbn) |
176 | { | 169 | { |
177 | unsigned long flags; | 170 | unsigned long flags; |
178 | int wbn; | ||
179 | struct acm_wb *wb; | 171 | struct acm_wb *wb; |
180 | int rc; | 172 | int rc; |
181 | 173 | ||
@@ -190,24 +182,24 @@ static int acm_write_start(struct acm *acm) | |||
190 | return 0; /* A white lie */ | 182 | return 0; /* A white lie */ |
191 | } | 183 | } |
192 | 184 | ||
193 | wbn = acm->write_current; | ||
194 | if (!acm_wb_is_used(acm, wbn)) { | 185 | if (!acm_wb_is_used(acm, wbn)) { |
195 | spin_unlock_irqrestore(&acm->write_lock, flags); | 186 | spin_unlock_irqrestore(&acm->write_lock, flags); |
196 | return 0; | 187 | return 0; |
197 | } | 188 | } |
198 | wb = &acm->wb[wbn]; | 189 | wb = &acm->wb[wbn]; |
199 | 190 | ||
200 | acm->write_ready = 0; | 191 | if(acm_wb_is_avail(acm) <= 1) |
192 | acm->write_ready = 0; | ||
201 | spin_unlock_irqrestore(&acm->write_lock, flags); | 193 | spin_unlock_irqrestore(&acm->write_lock, flags); |
202 | 194 | ||
203 | acm->writeurb->transfer_buffer = wb->buf; | 195 | wb->urb->transfer_buffer = wb->buf; |
204 | acm->writeurb->transfer_dma = wb->dmah; | 196 | wb->urb->transfer_dma = wb->dmah; |
205 | acm->writeurb->transfer_buffer_length = wb->len; | 197 | wb->urb->transfer_buffer_length = wb->len; |
206 | acm->writeurb->dev = acm->dev; | 198 | wb->urb->dev = acm->dev; |
207 | 199 | ||
208 | if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) { | 200 | if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { |
209 | dbg("usb_submit_urb(write bulk) failed: %d", rc); | 201 | dbg("usb_submit_urb(write bulk) failed: %d", rc); |
210 | acm_write_done(acm); | 202 | acm_write_done(acm, wb); |
211 | } | 203 | } |
212 | return rc; | 204 | return rc; |
213 | } | 205 | } |
@@ -268,10 +260,10 @@ static void acm_ctrl_irq(struct urb *urb) | |||
268 | case -ENOENT: | 260 | case -ENOENT: |
269 | case -ESHUTDOWN: | 261 | case -ESHUTDOWN: |
270 | /* this urb is terminated, clean up */ | 262 | /* this urb is terminated, clean up */ |
271 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, status); | 263 | dbg("%s - urb shutting down with status: %d", __func__, status); |
272 | return; | 264 | return; |
273 | default: | 265 | default: |
274 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, status); | 266 | dbg("%s - nonzero urb status received: %d", __func__, status); |
275 | goto exit; | 267 | goto exit; |
276 | } | 268 | } |
277 | 269 | ||
@@ -315,7 +307,7 @@ exit: | |||
315 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 307 | retval = usb_submit_urb (urb, GFP_ATOMIC); |
316 | if (retval) | 308 | if (retval) |
317 | err ("%s - usb_submit_urb failed with result %d", | 309 | err ("%s - usb_submit_urb failed with result %d", |
318 | __FUNCTION__, retval); | 310 | __func__, retval); |
319 | } | 311 | } |
320 | 312 | ||
321 | /* data interface returns incoming bytes, or we got unthrottled */ | 313 | /* data interface returns incoming bytes, or we got unthrottled */ |
@@ -450,12 +442,13 @@ urbs: | |||
450 | /* data interface wrote those outgoing bytes */ | 442 | /* data interface wrote those outgoing bytes */ |
451 | static void acm_write_bulk(struct urb *urb) | 443 | static void acm_write_bulk(struct urb *urb) |
452 | { | 444 | { |
453 | struct acm *acm = (struct acm *)urb->context; | 445 | struct acm *acm; |
446 | struct acm_wb *wb = urb->context; | ||
454 | 447 | ||
455 | dbg("Entering acm_write_bulk with status %d", urb->status); | 448 | dbg("Entering acm_write_bulk with status %d", urb->status); |
456 | 449 | ||
457 | acm_write_done(acm); | 450 | acm = wb->instance; |
458 | acm_write_start(acm); | 451 | acm_write_done(acm, wb); |
459 | if (ACM_READY(acm)) | 452 | if (ACM_READY(acm)) |
460 | schedule_work(&acm->work); | 453 | schedule_work(&acm->work); |
461 | } | 454 | } |
@@ -489,6 +482,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
489 | else | 482 | else |
490 | rv = 0; | 483 | rv = 0; |
491 | 484 | ||
485 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); | ||
492 | tty->driver_data = acm; | 486 | tty->driver_data = acm; |
493 | acm->tty = tty; | 487 | acm->tty = tty; |
494 | 488 | ||
@@ -556,7 +550,8 @@ static void acm_tty_unregister(struct acm *acm) | |||
556 | usb_put_intf(acm->control); | 550 | usb_put_intf(acm->control); |
557 | acm_table[acm->minor] = NULL; | 551 | acm_table[acm->minor] = NULL; |
558 | usb_free_urb(acm->ctrlurb); | 552 | usb_free_urb(acm->ctrlurb); |
559 | usb_free_urb(acm->writeurb); | 553 | for (i = 0; i < ACM_NW; i++) |
554 | usb_free_urb(acm->wb[i].urb); | ||
560 | for (i = 0; i < nr; i++) | 555 | for (i = 0; i < nr; i++) |
561 | usb_free_urb(acm->ru[i].urb); | 556 | usb_free_urb(acm->ru[i].urb); |
562 | kfree(acm->country_codes); | 557 | kfree(acm->country_codes); |
@@ -577,7 +572,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
577 | if (acm->dev) { | 572 | if (acm->dev) { |
578 | acm_set_control(acm, acm->ctrlout = 0); | 573 | acm_set_control(acm, acm->ctrlout = 0); |
579 | usb_kill_urb(acm->ctrlurb); | 574 | usb_kill_urb(acm->ctrlurb); |
580 | usb_kill_urb(acm->writeurb); | 575 | for (i = 0; i < ACM_NW; i++) |
576 | usb_kill_urb(acm->wb[i].urb); | ||
581 | for (i = 0; i < nr; i++) | 577 | for (i = 0; i < nr; i++) |
582 | usb_kill_urb(acm->ru[i].urb); | 578 | usb_kill_urb(acm->ru[i].urb); |
583 | usb_autopm_put_interface(acm->control); | 579 | usb_autopm_put_interface(acm->control); |
@@ -605,7 +601,6 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c | |||
605 | spin_lock_irqsave(&acm->write_lock, flags); | 601 | spin_lock_irqsave(&acm->write_lock, flags); |
606 | if ((wbn = acm_wb_alloc(acm)) < 0) { | 602 | if ((wbn = acm_wb_alloc(acm)) < 0) { |
607 | spin_unlock_irqrestore(&acm->write_lock, flags); | 603 | spin_unlock_irqrestore(&acm->write_lock, flags); |
608 | acm_write_start(acm); | ||
609 | return 0; | 604 | return 0; |
610 | } | 605 | } |
611 | wb = &acm->wb[wbn]; | 606 | wb = &acm->wb[wbn]; |
@@ -616,7 +611,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c | |||
616 | wb->len = count; | 611 | wb->len = count; |
617 | spin_unlock_irqrestore(&acm->write_lock, flags); | 612 | spin_unlock_irqrestore(&acm->write_lock, flags); |
618 | 613 | ||
619 | if ((stat = acm_write_start(acm)) < 0) | 614 | if ((stat = acm_write_start(acm, wbn)) < 0) |
620 | return stat; | 615 | return stat; |
621 | return count; | 616 | return count; |
622 | } | 617 | } |
@@ -809,7 +804,7 @@ static int acm_probe (struct usb_interface *intf, | |||
809 | { | 804 | { |
810 | struct usb_cdc_union_desc *union_header = NULL; | 805 | struct usb_cdc_union_desc *union_header = NULL; |
811 | struct usb_cdc_country_functional_desc *cfd = NULL; | 806 | struct usb_cdc_country_functional_desc *cfd = NULL; |
812 | char *buffer = intf->altsetting->extra; | 807 | unsigned char *buffer = intf->altsetting->extra; |
813 | int buflen = intf->altsetting->extralen; | 808 | int buflen = intf->altsetting->extralen; |
814 | struct usb_interface *control_interface; | 809 | struct usb_interface *control_interface; |
815 | struct usb_interface *data_interface; | 810 | struct usb_interface *data_interface; |
@@ -886,9 +881,13 @@ static int acm_probe (struct usb_interface *intf, | |||
886 | if ((call_management_function & 3) != 3) | 881 | if ((call_management_function & 3) != 3) |
887 | err("This device cannot do calls on its own. It is no modem."); | 882 | err("This device cannot do calls on its own. It is no modem."); |
888 | break; | 883 | break; |
889 | |||
890 | default: | 884 | default: |
891 | err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]); | 885 | /* there are LOTS more CDC descriptors that |
886 | * could legitimately be found here. | ||
887 | */ | ||
888 | dev_dbg(&intf->dev, "Ignoring descriptor: " | ||
889 | "type %02x, length %d\n", | ||
890 | buffer[2], buffer[0]); | ||
892 | break; | 891 | break; |
893 | } | 892 | } |
894 | next_desc: | 893 | next_desc: |
@@ -976,7 +975,7 @@ skip_normal_probe: | |||
976 | 975 | ||
977 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); | 976 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); |
978 | readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); | 977 | readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); |
979 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); | 978 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; |
980 | acm->control = control_interface; | 979 | acm->control = control_interface; |
981 | acm->data = data_interface; | 980 | acm->data = data_interface; |
982 | acm->minor = minor; | 981 | acm->minor = minor; |
@@ -1031,10 +1030,19 @@ skip_normal_probe: | |||
1031 | goto alloc_fail7; | 1030 | goto alloc_fail7; |
1032 | } | 1031 | } |
1033 | } | 1032 | } |
1034 | acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); | 1033 | for(i = 0; i < ACM_NW; i++) |
1035 | if (!acm->writeurb) { | 1034 | { |
1036 | dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n"); | 1035 | struct acm_wb *snd = &(acm->wb[i]); |
1037 | goto alloc_fail7; | 1036 | |
1037 | if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) { | ||
1038 | dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); | ||
1039 | goto alloc_fail7; | ||
1040 | } | ||
1041 | |||
1042 | usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), | ||
1043 | NULL, acm->writesize, acm_write_bulk, snd); | ||
1044 | snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
1045 | snd->instance = acm; | ||
1038 | } | 1046 | } |
1039 | 1047 | ||
1040 | usb_set_intfdata (intf, acm); | 1048 | usb_set_intfdata (intf, acm); |
@@ -1070,10 +1078,6 @@ skip_countries: | |||
1070 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 1078 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
1071 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; | 1079 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; |
1072 | 1080 | ||
1073 | usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), | ||
1074 | NULL, acm->writesize, acm_write_bulk, acm); | ||
1075 | acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; | ||
1076 | |||
1077 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); | 1081 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); |
1078 | 1082 | ||
1079 | acm_set_control(acm, acm->ctrlout); | 1083 | acm_set_control(acm, acm->ctrlout); |
@@ -1091,7 +1095,8 @@ skip_countries: | |||
1091 | 1095 | ||
1092 | return 0; | 1096 | return 0; |
1093 | alloc_fail8: | 1097 | alloc_fail8: |
1094 | usb_free_urb(acm->writeurb); | 1098 | for (i = 0; i < ACM_NW; i++) |
1099 | usb_free_urb(acm->wb[i].urb); | ||
1095 | alloc_fail7: | 1100 | alloc_fail7: |
1096 | for (i = 0; i < num_rx_buf; i++) | 1101 | for (i = 0; i < num_rx_buf; i++) |
1097 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | 1102 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
@@ -1115,7 +1120,8 @@ static void stop_data_traffic(struct acm *acm) | |||
1115 | tasklet_disable(&acm->urb_task); | 1120 | tasklet_disable(&acm->urb_task); |
1116 | 1121 | ||
1117 | usb_kill_urb(acm->ctrlurb); | 1122 | usb_kill_urb(acm->ctrlurb); |
1118 | usb_kill_urb(acm->writeurb); | 1123 | for(i = 0; i < ACM_NW; i++) |
1124 | usb_kill_urb(acm->wb[i].urb); | ||
1119 | for (i = 0; i < acm->rx_buflimit; i++) | 1125 | for (i = 0; i < acm->rx_buflimit; i++) |
1120 | usb_kill_urb(acm->ru[i].urb); | 1126 | usb_kill_urb(acm->ru[i].urb); |
1121 | 1127 | ||