Commit c4cabd28 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB: cdc-acm: export parsed capabilities through sysfs

this patch exports the attributes cdc-acm knows about a device through sysfs.
Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent bb74782e
...@@ -212,7 +212,41 @@ static int acm_write_start(struct acm *acm) ...@@ -212,7 +212,41 @@ static int acm_write_start(struct acm *acm)
} }
return rc; return rc;
} }
/*
* attributes exported through sysfs
*/
static ssize_t show_caps
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct acm *acm = usb_get_intfdata(intf);
return sprintf(buf, "%d", acm->ctrl_caps);
}
static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
static ssize_t show_country_codes
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct acm *acm = usb_get_intfdata(intf);
memcpy(buf, acm->country_codes, acm->country_code_size);
return acm->country_code_size;
}
static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
static ssize_t show_country_rel_date
(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct acm *acm = usb_get_intfdata(intf);
return sprintf(buf, "%d", acm->country_rel_date);
}
static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
/* /*
* Interrupt handlers for various ACM device responses * Interrupt handlers for various ACM device responses
*/ */
...@@ -514,6 +548,7 @@ static void acm_tty_unregister(struct acm *acm) ...@@ -514,6 +548,7 @@ static void acm_tty_unregister(struct acm *acm)
usb_free_urb(acm->writeurb); usb_free_urb(acm->writeurb);
for (i = 0; i < nr; i++) for (i = 0; i < nr; i++)
usb_free_urb(acm->ru[i].urb); usb_free_urb(acm->ru[i].urb);
kfree(acm->country_codes);
kfree(acm); kfree(acm);
} }
...@@ -761,6 +796,7 @@ static int acm_probe (struct usb_interface *intf, ...@@ -761,6 +796,7 @@ static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_union_desc *union_header = NULL;
struct usb_cdc_country_functional_desc *cfd = NULL;
char *buffer = intf->altsetting->extra; char *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen; int buflen = intf->altsetting->extralen;
struct usb_interface *control_interface; struct usb_interface *control_interface;
...@@ -824,8 +860,9 @@ static int acm_probe (struct usb_interface *intf, ...@@ -824,8 +860,9 @@ static int acm_probe (struct usb_interface *intf,
union_header = (struct usb_cdc_union_desc *) union_header = (struct usb_cdc_union_desc *)
buffer; buffer;
break; break;
case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */ case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
break; /* for now we ignore it */ cfd = (struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE: /* maybe check version */ case USB_CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */ break; /* for now we ignore it */
case USB_CDC_ACM_TYPE: case USB_CDC_ACM_TYPE:
...@@ -983,6 +1020,34 @@ static int acm_probe (struct usb_interface *intf, ...@@ -983,6 +1020,34 @@ static int acm_probe (struct usb_interface *intf,
goto alloc_fail7; goto alloc_fail7;
} }
usb_set_intfdata (intf, acm);
i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
if (i < 0)
goto alloc_fail8;
if (cfd) { /* export the country data */
acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
if (!acm->country_codes)
goto skip_countries;
acm->country_code_size = cfd->bLength - 4;
memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
acm->country_rel_date = cfd->iCountryCodeRelDate;
i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
if (i < 0) {
kfree(acm->country_codes);
goto skip_countries;
}
i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
if (i < 0) {
kfree(acm->country_codes);
goto skip_countries;
}
}
skip_countries:
usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
...@@ -1006,9 +1071,10 @@ static int acm_probe (struct usb_interface *intf, ...@@ -1006,9 +1071,10 @@ static int acm_probe (struct usb_interface *intf,
tty_register_device(acm_tty_driver, minor, &control_interface->dev); tty_register_device(acm_tty_driver, minor, &control_interface->dev);
acm_table[minor] = acm; acm_table[minor] = acm;
usb_set_intfdata (intf, acm);
return 0;
return 0;
alloc_fail8:
usb_free_urb(acm->writeurb);
alloc_fail7: alloc_fail7:
for (i = 0; i < num_rx_buf; i++) for (i = 0; i < num_rx_buf; i++)
usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
...@@ -1027,7 +1093,7 @@ static int acm_probe (struct usb_interface *intf, ...@@ -1027,7 +1093,7 @@ static int acm_probe (struct usb_interface *intf,
static void acm_disconnect(struct usb_interface *intf) static void acm_disconnect(struct usb_interface *intf)
{ {
struct acm *acm = usb_get_intfdata (intf); struct acm *acm = usb_get_intfdata(intf);
struct usb_device *usb_dev = interface_to_usbdev(intf); struct usb_device *usb_dev = interface_to_usbdev(intf);
int i; int i;
...@@ -1041,6 +1107,11 @@ static void acm_disconnect(struct usb_interface *intf) ...@@ -1041,6 +1107,11 @@ static void acm_disconnect(struct usb_interface *intf)
mutex_unlock(&open_mutex); mutex_unlock(&open_mutex);
return; return;
} }
if (acm->country_codes){
device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
}
device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
acm->dev = NULL; acm->dev = NULL;
usb_set_intfdata(acm->control, NULL); usb_set_intfdata(acm->control, NULL);
usb_set_intfdata(acm->data, NULL); usb_set_intfdata(acm->data, NULL);
......
...@@ -91,6 +91,9 @@ struct acm { ...@@ -91,6 +91,9 @@ struct acm {
struct urb *ctrlurb, *writeurb; /* urbs */ struct urb *ctrlurb, *writeurb; /* urbs */
u8 *ctrl_buffer; /* buffers of urbs */ u8 *ctrl_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma; /* dma handles of buffers */ dma_addr_t ctrl_dma; /* dma handles of buffers */
u8 *country_codes; /* country codes from device */
unsigned int country_code_size; /* size of this buffer */
unsigned int country_rel_date; /* release date of version */
struct acm_wb wb[ACM_NW]; struct acm_wb wb[ACM_NW];
struct acm_ru ru[ACM_NR]; struct acm_ru ru[ACM_NR];
struct acm_rb rb[ACM_NR]; struct acm_rb rb[ACM_NR];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment