aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class/cdc-acm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r--drivers/usb/class/cdc-acm.c81
1 files changed, 76 insertions, 5 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 31ae661e586a..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 */
218static 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}
226static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
227
228static 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}
237
238static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
239
240static 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}
215 248
249static 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 */
@@ -514,6 +548,7 @@ static void acm_tty_unregister(struct acm *acm)
514 usb_free_urb(acm->writeurb); 548 usb_free_urb(acm->writeurb);
515 for (i = 0; i < nr; i++) 549 for (i = 0; i < nr; i++)
516 usb_free_urb(acm->ru[i].urb); 550 usb_free_urb(acm->ru[i].urb);
551 kfree(acm->country_codes);
517 kfree(acm); 552 kfree(acm);
518} 553}
519 554
@@ -761,6 +796,7 @@ static int acm_probe (struct usb_interface *intf,
761 const struct usb_device_id *id) 796 const struct usb_device_id *id)
762{ 797{
763 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;
764 char *buffer = intf->altsetting->extra; 800 char *buffer = intf->altsetting->extra;
765 int buflen = intf->altsetting->extralen; 801 int buflen = intf->altsetting->extralen;
766 struct usb_interface *control_interface; 802 struct usb_interface *control_interface;
@@ -824,8 +860,9 @@ static int acm_probe (struct usb_interface *intf,
824 union_header = (struct usb_cdc_union_desc *) 860 union_header = (struct usb_cdc_union_desc *)
825 buffer; 861 buffer;
826 break; 862 break;
827 case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */ 863 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
828 break; /* for now we ignore it */ 864 cfd = (struct usb_cdc_country_functional_desc *)buffer;
865 break;
829 case USB_CDC_HEADER_TYPE: /* maybe check version */ 866 case USB_CDC_HEADER_TYPE: /* maybe check version */
830 break; /* for now we ignore it */ 867 break; /* for now we ignore it */
831 case USB_CDC_ACM_TYPE: 868 case USB_CDC_ACM_TYPE:
@@ -983,6 +1020,34 @@ skip_normal_probe:
983 goto alloc_fail7; 1020 goto alloc_fail7;
984 } 1021 }
985 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
1050skip_countries:
986 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),
987 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); 1052 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
988 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1053 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -1006,9 +1071,10 @@ skip_normal_probe:
1006 tty_register_device(acm_tty_driver, minor, &control_interface->dev); 1071 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
1007 1072
1008 acm_table[minor] = acm; 1073 acm_table[minor] = acm;
1009 usb_set_intfdata (intf, acm);
1010 return 0;
1011 1074
1075 return 0;
1076alloc_fail8:
1077 usb_free_urb(acm->writeurb);
1012alloc_fail7: 1078alloc_fail7:
1013 for (i = 0; i < num_rx_buf; i++) 1079 for (i = 0; i < num_rx_buf; i++)
1014 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);
@@ -1027,7 +1093,7 @@ alloc_fail:
1027 1093
1028static void acm_disconnect(struct usb_interface *intf) 1094static void acm_disconnect(struct usb_interface *intf)
1029{ 1095{
1030 struct acm *acm = usb_get_intfdata (intf); 1096 struct acm *acm = usb_get_intfdata(intf);
1031 struct usb_device *usb_dev = interface_to_usbdev(intf); 1097 struct usb_device *usb_dev = interface_to_usbdev(intf);
1032 int i; 1098 int i;
1033 1099
@@ -1041,6 +1107,11 @@ static void acm_disconnect(struct usb_interface *intf)
1041 mutex_unlock(&open_mutex); 1107 mutex_unlock(&open_mutex);
1042 return; 1108 return;
1043 } 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);
1044 acm->dev = NULL; 1115 acm->dev = NULL;
1045 usb_set_intfdata(acm->control, NULL); 1116 usb_set_intfdata(acm->control, NULL);
1046 usb_set_intfdata(acm->data, NULL); 1117 usb_set_intfdata(acm->data, NULL);