diff options
author | Dmitry Torokhov <dtor@insightbb.com> | 2007-05-01 00:24:54 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-05-01 00:24:54 -0400 |
commit | bc95f3669f5e6f63cf0b84fe4922c3c6dd4aa775 (patch) | |
tree | 427fcf2a7287c16d4b5aa6cbf494d59579a6a8b1 /drivers/usb/class | |
parent | 3d29cdff999c37b3876082278a8134a0642a02cd (diff) | |
parent | dc87c3985e9b442c60994308a96f887579addc39 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/usb/input/Makefile
drivers/usb/input/gtco.c
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 114 | ||||
-rw-r--r-- | drivers/usb/class/cdc-acm.h | 3 | ||||
-rw-r--r-- | drivers/usb/class/usblp.c | 6 |
3 files changed, 106 insertions, 17 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 98199628e394..14de3b1b6a20 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -212,7 +212,41 @@ static int acm_write_start(struct acm *acm) | |||
212 | } | 212 | } |
213 | return rc; | 213 | return rc; |
214 | } | 214 | } |
215 | /* | ||
216 | * attributes exported through sysfs | ||
217 | */ | ||
218 | static ssize_t show_caps | ||
219 | (struct device *dev, struct device_attribute *attr, char *buf) | ||
220 | { | ||
221 | struct usb_interface *intf = to_usb_interface(dev); | ||
222 | struct acm *acm = usb_get_intfdata(intf); | ||
223 | |||
224 | return sprintf(buf, "%d", acm->ctrl_caps); | ||
225 | } | ||
226 | static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); | ||
227 | |||
228 | static ssize_t show_country_codes | ||
229 | (struct device *dev, struct device_attribute *attr, char *buf) | ||
230 | { | ||
231 | struct usb_interface *intf = to_usb_interface(dev); | ||
232 | struct acm *acm = usb_get_intfdata(intf); | ||
233 | |||
234 | memcpy(buf, acm->country_codes, acm->country_code_size); | ||
235 | return acm->country_code_size; | ||
236 | } | ||
215 | 237 | ||
238 | static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); | ||
239 | |||
240 | static ssize_t show_country_rel_date | ||
241 | (struct device *dev, struct device_attribute *attr, char *buf) | ||
242 | { | ||
243 | struct usb_interface *intf = to_usb_interface(dev); | ||
244 | struct acm *acm = usb_get_intfdata(intf); | ||
245 | |||
246 | return sprintf(buf, "%d", acm->country_rel_date); | ||
247 | } | ||
248 | |||
249 | static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); | ||
216 | /* | 250 | /* |
217 | * Interrupt handlers for various ACM device responses | 251 | * Interrupt handlers for various ACM device responses |
218 | */ | 252 | */ |
@@ -326,10 +360,16 @@ static void acm_rx_tasklet(unsigned long _acm) | |||
326 | struct tty_struct *tty = acm->tty; | 360 | struct tty_struct *tty = acm->tty; |
327 | struct acm_ru *rcv; | 361 | struct acm_ru *rcv; |
328 | unsigned long flags; | 362 | unsigned long flags; |
329 | int i = 0; | 363 | unsigned char throttled; |
330 | dbg("Entering acm_rx_tasklet"); | 364 | dbg("Entering acm_rx_tasklet"); |
331 | 365 | ||
332 | if (!ACM_READY(acm) || acm->throttle) | 366 | if (!ACM_READY(acm)) |
367 | return; | ||
368 | |||
369 | spin_lock_irqsave(&acm->throttle_lock, flags); | ||
370 | throttled = acm->throttle; | ||
371 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | ||
372 | if (throttled) | ||
333 | return; | 373 | return; |
334 | 374 | ||
335 | next_buffer: | 375 | next_buffer: |
@@ -346,22 +386,20 @@ next_buffer: | |||
346 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); | 386 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); |
347 | 387 | ||
348 | tty_buffer_request_room(tty, buf->size); | 388 | tty_buffer_request_room(tty, buf->size); |
349 | if (!acm->throttle) | 389 | spin_lock_irqsave(&acm->throttle_lock, flags); |
390 | throttled = acm->throttle; | ||
391 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | ||
392 | if (!throttled) | ||
350 | tty_insert_flip_string(tty, buf->base, buf->size); | 393 | tty_insert_flip_string(tty, buf->base, buf->size); |
351 | tty_flip_buffer_push(tty); | 394 | tty_flip_buffer_push(tty); |
352 | 395 | ||
353 | spin_lock(&acm->throttle_lock); | 396 | if (throttled) { |
354 | if (acm->throttle) { | 397 | dbg("Throttling noticed"); |
355 | dbg("Throtteling noticed"); | ||
356 | memmove(buf->base, buf->base + i, buf->size - i); | ||
357 | buf->size -= i; | ||
358 | spin_unlock(&acm->throttle_lock); | ||
359 | spin_lock_irqsave(&acm->read_lock, flags); | 398 | spin_lock_irqsave(&acm->read_lock, flags); |
360 | list_add(&buf->list, &acm->filled_read_bufs); | 399 | list_add(&buf->list, &acm->filled_read_bufs); |
361 | spin_unlock_irqrestore(&acm->read_lock, flags); | 400 | spin_unlock_irqrestore(&acm->read_lock, flags); |
362 | return; | 401 | return; |
363 | } | 402 | } |
364 | spin_unlock(&acm->throttle_lock); | ||
365 | 403 | ||
366 | spin_lock_irqsave(&acm->read_lock, flags); | 404 | spin_lock_irqsave(&acm->read_lock, flags); |
367 | list_add(&buf->list, &acm->spare_read_bufs); | 405 | list_add(&buf->list, &acm->spare_read_bufs); |
@@ -467,7 +505,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
467 | goto bail_out; | 505 | goto bail_out; |
468 | } | 506 | } |
469 | 507 | ||
470 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) | 508 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && |
509 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) | ||
471 | goto full_bailout; | 510 | goto full_bailout; |
472 | 511 | ||
473 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 512 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
@@ -480,6 +519,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
480 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | 519 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); |
481 | } | 520 | } |
482 | 521 | ||
522 | acm->throttle = 0; | ||
523 | |||
483 | tasklet_schedule(&acm->urb_task); | 524 | tasklet_schedule(&acm->urb_task); |
484 | 525 | ||
485 | done: | 526 | done: |
@@ -507,6 +548,7 @@ static void acm_tty_unregister(struct acm *acm) | |||
507 | usb_free_urb(acm->writeurb); | 548 | usb_free_urb(acm->writeurb); |
508 | for (i = 0; i < nr; i++) | 549 | for (i = 0; i < nr; i++) |
509 | usb_free_urb(acm->ru[i].urb); | 550 | usb_free_urb(acm->ru[i].urb); |
551 | kfree(acm->country_codes); | ||
510 | kfree(acm); | 552 | kfree(acm); |
511 | } | 553 | } |
512 | 554 | ||
@@ -754,6 +796,7 @@ static int acm_probe (struct usb_interface *intf, | |||
754 | const struct usb_device_id *id) | 796 | const struct usb_device_id *id) |
755 | { | 797 | { |
756 | struct usb_cdc_union_desc *union_header = NULL; | 798 | struct usb_cdc_union_desc *union_header = NULL; |
799 | struct usb_cdc_country_functional_desc *cfd = NULL; | ||
757 | char *buffer = intf->altsetting->extra; | 800 | char *buffer = intf->altsetting->extra; |
758 | int buflen = intf->altsetting->extralen; | 801 | int buflen = intf->altsetting->extralen; |
759 | struct usb_interface *control_interface; | 802 | struct usb_interface *control_interface; |
@@ -817,8 +860,9 @@ static int acm_probe (struct usb_interface *intf, | |||
817 | union_header = (struct usb_cdc_union_desc *) | 860 | union_header = (struct usb_cdc_union_desc *) |
818 | buffer; | 861 | buffer; |
819 | break; | 862 | break; |
820 | case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */ | 863 | case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ |
821 | break; /* for now we ignore it */ | 864 | cfd = (struct usb_cdc_country_functional_desc *)buffer; |
865 | break; | ||
822 | case USB_CDC_HEADER_TYPE: /* maybe check version */ | 866 | case USB_CDC_HEADER_TYPE: /* maybe check version */ |
823 | break; /* for now we ignore it */ | 867 | break; /* for now we ignore it */ |
824 | case USB_CDC_ACM_TYPE: | 868 | case USB_CDC_ACM_TYPE: |
@@ -976,6 +1020,34 @@ skip_normal_probe: | |||
976 | goto alloc_fail7; | 1020 | goto alloc_fail7; |
977 | } | 1021 | } |
978 | 1022 | ||
1023 | usb_set_intfdata (intf, acm); | ||
1024 | |||
1025 | i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); | ||
1026 | if (i < 0) | ||
1027 | goto alloc_fail8; | ||
1028 | |||
1029 | if (cfd) { /* export the country data */ | ||
1030 | acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); | ||
1031 | if (!acm->country_codes) | ||
1032 | goto skip_countries; | ||
1033 | acm->country_code_size = cfd->bLength - 4; | ||
1034 | memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); | ||
1035 | acm->country_rel_date = cfd->iCountryCodeRelDate; | ||
1036 | |||
1037 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); | ||
1038 | if (i < 0) { | ||
1039 | kfree(acm->country_codes); | ||
1040 | goto skip_countries; | ||
1041 | } | ||
1042 | |||
1043 | i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); | ||
1044 | if (i < 0) { | ||
1045 | kfree(acm->country_codes); | ||
1046 | goto skip_countries; | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | skip_countries: | ||
979 | usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), | 1051 | usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), |
980 | acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); | 1052 | acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); |
981 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 1053 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
@@ -999,9 +1071,10 @@ skip_normal_probe: | |||
999 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); | 1071 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); |
1000 | 1072 | ||
1001 | acm_table[minor] = acm; | 1073 | acm_table[minor] = acm; |
1002 | usb_set_intfdata (intf, acm); | ||
1003 | return 0; | ||
1004 | 1074 | ||
1075 | return 0; | ||
1076 | alloc_fail8: | ||
1077 | usb_free_urb(acm->writeurb); | ||
1005 | alloc_fail7: | 1078 | alloc_fail7: |
1006 | for (i = 0; i < num_rx_buf; i++) | 1079 | for (i = 0; i < num_rx_buf; i++) |
1007 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | 1080 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
@@ -1020,7 +1093,7 @@ alloc_fail: | |||
1020 | 1093 | ||
1021 | static void acm_disconnect(struct usb_interface *intf) | 1094 | static void acm_disconnect(struct usb_interface *intf) |
1022 | { | 1095 | { |
1023 | struct acm *acm = usb_get_intfdata (intf); | 1096 | struct acm *acm = usb_get_intfdata(intf); |
1024 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1097 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1025 | int i; | 1098 | int i; |
1026 | 1099 | ||
@@ -1034,6 +1107,11 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1034 | mutex_unlock(&open_mutex); | 1107 | mutex_unlock(&open_mutex); |
1035 | return; | 1108 | return; |
1036 | } | 1109 | } |
1110 | if (acm->country_codes){ | ||
1111 | device_remove_file(&intf->dev, &dev_attr_wCountryCodes); | ||
1112 | device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate); | ||
1113 | } | ||
1114 | device_remove_file(&intf->dev, &dev_attr_bmCapabilities); | ||
1037 | acm->dev = NULL; | 1115 | acm->dev = NULL; |
1038 | usb_set_intfdata(acm->control, NULL); | 1116 | usb_set_intfdata(acm->control, NULL); |
1039 | usb_set_intfdata(acm->data, NULL); | 1117 | usb_set_intfdata(acm->data, NULL); |
@@ -1092,6 +1170,10 @@ static struct usb_device_id acm_ids[] = { | |||
1092 | { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ | 1170 | { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ |
1093 | .driver_info = SINGLE_RX_URB, /* firmware bug */ | 1171 | .driver_info = SINGLE_RX_URB, /* firmware bug */ |
1094 | }, | 1172 | }, |
1173 | { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ | ||
1174 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | ||
1175 | }, | ||
1176 | |||
1095 | /* control interfaces with various AT-command sets */ | 1177 | /* control interfaces with various AT-command sets */ |
1096 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1178 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1097 | USB_CDC_ACM_PROTO_AT_V25TER) }, | 1179 | USB_CDC_ACM_PROTO_AT_V25TER) }, |
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 1bcaea32cfc1..09f7765dbf8d 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h | |||
@@ -91,6 +91,9 @@ struct acm { | |||
91 | struct urb *ctrlurb, *writeurb; /* urbs */ | 91 | struct urb *ctrlurb, *writeurb; /* urbs */ |
92 | u8 *ctrl_buffer; /* buffers of urbs */ | 92 | u8 *ctrl_buffer; /* buffers of urbs */ |
93 | dma_addr_t ctrl_dma; /* dma handles of buffers */ | 93 | dma_addr_t ctrl_dma; /* dma handles of buffers */ |
94 | u8 *country_codes; /* country codes from device */ | ||
95 | unsigned int country_code_size; /* size of this buffer */ | ||
96 | unsigned int country_rel_date; /* release date of version */ | ||
94 | struct acm_wb wb[ACM_NW]; | 97 | struct acm_wb wb[ACM_NW]; |
95 | struct acm_ru ru[ACM_NR]; | 98 | struct acm_ru ru[ACM_NR]; |
96 | struct acm_rb rb[ACM_NR]; | 99 | struct acm_rb rb[ACM_NR]; |
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 63e50a1f1396..6584cf00f7f3 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c | |||
@@ -202,6 +202,7 @@ struct quirk_printer_struct { | |||
202 | 202 | ||
203 | #define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ | 203 | #define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ |
204 | #define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ | 204 | #define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ |
205 | #define USBLP_QUIRK_BAD_CLASS 0x4 /* descriptor uses vendor-specific Class or SubClass */ | ||
205 | 206 | ||
206 | static const struct quirk_printer_struct quirk_printers[] = { | 207 | static const struct quirk_printer_struct quirk_printers[] = { |
207 | { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ | 208 | { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ |
@@ -218,6 +219,7 @@ static const struct quirk_printer_struct quirk_printers[] = { | |||
218 | { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ | 219 | { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ |
219 | { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ | 220 | { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ |
220 | { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut <kernel@zut.de> */ | 221 | { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut <kernel@zut.de> */ |
222 | { 0x04b8, 0x0202, USBLP_QUIRK_BAD_CLASS }, /* Seiko Epson Receipt Printer M129C */ | ||
221 | { 0, 0 } | 223 | { 0, 0 } |
222 | }; | 224 | }; |
223 | 225 | ||
@@ -1048,7 +1050,8 @@ static int usblp_select_alts(struct usblp *usblp) | |||
1048 | ifd = &if_alt->altsetting[i]; | 1050 | ifd = &if_alt->altsetting[i]; |
1049 | 1051 | ||
1050 | if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) | 1052 | if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) |
1051 | continue; | 1053 | if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS)) |
1054 | continue; | ||
1052 | 1055 | ||
1053 | if (ifd->desc.bInterfaceProtocol < USBLP_FIRST_PROTOCOL || | 1056 | if (ifd->desc.bInterfaceProtocol < USBLP_FIRST_PROTOCOL || |
1054 | ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL) | 1057 | ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL) |
@@ -1232,6 +1235,7 @@ static struct usb_device_id usblp_ids [] = { | |||
1232 | { USB_INTERFACE_INFO(7, 1, 1) }, | 1235 | { USB_INTERFACE_INFO(7, 1, 1) }, |
1233 | { USB_INTERFACE_INFO(7, 1, 2) }, | 1236 | { USB_INTERFACE_INFO(7, 1, 2) }, |
1234 | { USB_INTERFACE_INFO(7, 1, 3) }, | 1237 | { USB_INTERFACE_INFO(7, 1, 3) }, |
1238 | { USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */ | ||
1235 | { } /* Terminating entry */ | 1239 | { } /* Terminating entry */ |
1236 | }; | 1240 | }; |
1237 | 1241 | ||