mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 18:53:52 +08:00
USB: cdc-acm: export parsed capabilities through sysfs
this patch exports the attributes cdc-acm knows about a device through sysfs. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
bb74782e62
commit
c4cabd28c7
@ -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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@ skip_normal_probe:
|
|||||||
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 @@ skip_normal_probe:
|
|||||||
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 @@ alloc_fail:
|
|||||||
|
|
||||||
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)
|
|||||||
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 {
|
|||||||
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];
|
||||||
|
Loading…
Reference in New Issue
Block a user