[PATCH 09/78] USB: cdc-acm: export parsed capabilities through sysfs

Greg Kroah-Hartman <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
From: Oliver Neukum <[email protected]>

this patch exports the attributes cdc-acm knows about a device through sysfs.

Signed-off-by: Oliver Neukum <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 drivers/usb/class/cdc-acm.c |   81 ++++++++++++++++++++++++++++++++++++++++---
 drivers/usb/class/cdc-acm.h |    3 ++
 2 files changed, 79 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 31ae661..14de3b1 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)
 	}
 	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
  */
@@ -514,6 +548,7 @@ static void acm_tty_unregister(struct acm *acm)
 	usb_free_urb(acm->writeurb);
 	for (i = 0; i < nr; i++)
 		usb_free_urb(acm->ru[i].urb);
+	kfree(acm->country_codes);
 	kfree(acm);
 }
 
@@ -761,6 +796,7 @@ static int acm_probe (struct usb_interface *intf,
 		      const struct usb_device_id *id)
 {
 	struct usb_cdc_union_desc *union_header = NULL;
+	struct usb_cdc_country_functional_desc *cfd = NULL;
 	char *buffer = intf->altsetting->extra;
 	int buflen = intf->altsetting->extralen;
 	struct usb_interface *control_interface;
@@ -824,8 +860,9 @@ static int acm_probe (struct usb_interface *intf,
 				union_header = (struct usb_cdc_union_desc *)
 							buffer;
 				break;
-			case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
-				break; /* for now we ignore it */
+			case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
+				cfd = (struct usb_cdc_country_functional_desc *)buffer;
+				break;
 			case USB_CDC_HEADER_TYPE: /* maybe check version */ 
 				break; /* for now we ignore it */ 
 			case USB_CDC_ACM_TYPE:
@@ -983,6 +1020,34 @@ skip_normal_probe:
 		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),
 			 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
 	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);
 
 	acm_table[minor] = acm;
-	usb_set_intfdata (intf, acm);
-	return 0;
 
+	return 0;
+alloc_fail8:
+	usb_free_urb(acm->writeurb);
 alloc_fail7:
 	for (i = 0; i < num_rx_buf; i++)
 		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)
 {
-	struct acm *acm = usb_get_intfdata (intf);
+	struct acm *acm = usb_get_intfdata(intf);
 	struct usb_device *usb_dev = interface_to_usbdev(intf);
 	int i;
 
@@ -1041,6 +1107,11 @@ static void acm_disconnect(struct usb_interface *intf)
 		mutex_unlock(&open_mutex);
 		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;
 	usb_set_intfdata(acm->control, NULL);
 	usb_set_intfdata(acm->data, NULL);
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 1bcaea3..09f7765 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -91,6 +91,9 @@ struct acm {
 	struct urb *ctrlurb, *writeurb;			/* urbs */
 	u8 *ctrl_buffer;				/* buffers of urbs */
 	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_ru ru[ACM_NR];
 	struct acm_rb rb[ACM_NR];
-- 
1.5.1.2


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.