aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2009-05-16 15:13:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:45 -0400
commita2bfb4a346d2c2e25f84b35c6044ff53296be1ee (patch)
tree494cea0b367252d248a73bd8fe2490d0539ac5f1
parent0b10395ab86c11bef10e882a4323367e6735c9b2 (diff)
USB: support for cdc-acm of single interface devices
This implement support in cdc-acm for acm devices another popular OS can handle - adds support for autodetection of devices that use one interface - autodetection of endpoints - add a quirk for surpressing a setting that OS doesn't use - autoassume that quirk for single interface devices Signed-off-by: Oliver Neukum <oliver@neukum.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/class/cdc-acm.c68
-rw-r--r--drivers/usb/class/cdc-acm.h2
2 files changed, 58 insertions, 12 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ddeb69192537..778e023d1467 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -937,9 +937,9 @@ static int acm_probe(struct usb_interface *intf,
937 int buflen = intf->altsetting->extralen; 937 int buflen = intf->altsetting->extralen;
938 struct usb_interface *control_interface; 938 struct usb_interface *control_interface;
939 struct usb_interface *data_interface; 939 struct usb_interface *data_interface;
940 struct usb_endpoint_descriptor *epctrl; 940 struct usb_endpoint_descriptor *epctrl = NULL;
941 struct usb_endpoint_descriptor *epread; 941 struct usb_endpoint_descriptor *epread = NULL;
942 struct usb_endpoint_descriptor *epwrite; 942 struct usb_endpoint_descriptor *epwrite = NULL;
943 struct usb_device *usb_dev = interface_to_usbdev(intf); 943 struct usb_device *usb_dev = interface_to_usbdev(intf);
944 struct acm *acm; 944 struct acm *acm;
945 int minor; 945 int minor;
@@ -952,6 +952,7 @@ static int acm_probe(struct usb_interface *intf,
952 unsigned long quirks; 952 unsigned long quirks;
953 int num_rx_buf; 953 int num_rx_buf;
954 int i; 954 int i;
955 int combined_interfaces = 0;
955 956
956 /* normal quirks */ 957 /* normal quirks */
957 quirks = (unsigned long)id->driver_info; 958 quirks = (unsigned long)id->driver_info;
@@ -1033,9 +1034,15 @@ next_desc:
1033 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); 1034 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
1034 control_interface = intf; 1035 control_interface = intf;
1035 } else { 1036 } else {
1036 dev_dbg(&intf->dev, 1037 if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
1037 "No union descriptor, giving up\n"); 1038 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
1038 return -ENODEV; 1039 return -ENODEV;
1040 } else {
1041 dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
1042 combined_interfaces = 1;
1043 control_interface = data_interface = intf;
1044 goto look_for_collapsed_interface;
1045 }
1039 } 1046 }
1040 } else { 1047 } else {
1041 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); 1048 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
@@ -1049,6 +1056,36 @@ next_desc:
1049 if (data_interface_num != call_interface_num) 1056 if (data_interface_num != call_interface_num)
1050 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); 1057 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
1051 1058
1059 if (control_interface == data_interface) {
1060 /* some broken devices designed for windows work this way */
1061 dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
1062 combined_interfaces = 1;
1063 /* a popular other OS doesn't use it */
1064 quirks |= NO_CAP_LINE;
1065 if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
1066 dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
1067 return -EINVAL;
1068 }
1069look_for_collapsed_interface:
1070 for (i = 0; i < 3; i++) {
1071 struct usb_endpoint_descriptor *ep;
1072 ep = &data_interface->cur_altsetting->endpoint[i].desc;
1073
1074 if (usb_endpoint_is_int_in(ep))
1075 epctrl = ep;
1076 else if (usb_endpoint_is_bulk_out(ep))
1077 epwrite = ep;
1078 else if (usb_endpoint_is_bulk_in(ep))
1079 epread = ep;
1080 else
1081 return -EINVAL;
1082 }
1083 if (!epctrl || !epread || !epwrite)
1084 return -ENODEV;
1085 else
1086 goto made_compressed_probe;
1087 }
1088
1052skip_normal_probe: 1089skip_normal_probe:
1053 1090
1054 /*workaround for switched interfaces */ 1091 /*workaround for switched interfaces */
@@ -1068,10 +1105,11 @@ skip_normal_probe:
1068 } 1105 }
1069 1106
1070 /* Accept probe requests only for the control interface */ 1107 /* Accept probe requests only for the control interface */
1071 if (intf != control_interface) 1108 if (!combined_interfaces && intf != control_interface)
1072 return -ENODEV; 1109 return -ENODEV;
1073 1110
1074 if (usb_interface_claimed(data_interface)) { /* valid in this context */ 1111 if (!combined_interfaces && usb_interface_claimed(data_interface)) {
1112 /* valid in this context */
1075 dev_dbg(&intf->dev, "The data interface isn't available\n"); 1113 dev_dbg(&intf->dev, "The data interface isn't available\n");
1076 return -EBUSY; 1114 return -EBUSY;
1077 } 1115 }
@@ -1095,6 +1133,7 @@ skip_normal_probe:
1095 epread = epwrite; 1133 epread = epwrite;
1096 epwrite = t; 1134 epwrite = t;
1097 } 1135 }
1136made_compressed_probe:
1098 dbg("interfaces are valid"); 1137 dbg("interfaces are valid");
1099 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); 1138 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
1100 1139
@@ -1112,12 +1151,15 @@ skip_normal_probe:
1112 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); 1151 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
1113 readsize = le16_to_cpu(epread->wMaxPacketSize) * 1152 readsize = le16_to_cpu(epread->wMaxPacketSize) *
1114 (quirks == SINGLE_RX_URB ? 1 : 2); 1153 (quirks == SINGLE_RX_URB ? 1 : 2);
1154 acm->combined_interfaces = combined_interfaces;
1115 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; 1155 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
1116 acm->control = control_interface; 1156 acm->control = control_interface;
1117 acm->data = data_interface; 1157 acm->data = data_interface;
1118 acm->minor = minor; 1158 acm->minor = minor;
1119 acm->dev = usb_dev; 1159 acm->dev = usb_dev;
1120 acm->ctrl_caps = ac_management_function; 1160 acm->ctrl_caps = ac_management_function;
1161 if (quirks & NO_CAP_LINE)
1162 acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
1121 acm->ctrlsize = ctrlsize; 1163 acm->ctrlsize = ctrlsize;
1122 acm->readsize = readsize; 1164 acm->readsize = readsize;
1123 acm->rx_buflimit = num_rx_buf; 1165 acm->rx_buflimit = num_rx_buf;
@@ -1223,9 +1265,10 @@ skip_normal_probe:
1223 1265
1224skip_countries: 1266skip_countries:
1225 usb_fill_int_urb(acm->ctrlurb, usb_dev, 1267 usb_fill_int_urb(acm->ctrlurb, usb_dev,
1226 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), 1268 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1227 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, 1269 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
1228 epctrl->bInterval); 1270 /* works around buggy devices */
1271 epctrl->bInterval ? epctrl->bInterval : 0xff);
1229 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1272 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1230 acm->ctrlurb->transfer_dma = acm->ctrl_dma; 1273 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1231 1274
@@ -1312,7 +1355,8 @@ static void acm_disconnect(struct usb_interface *intf)
1312 acm->ctrl_dma); 1355 acm->ctrl_dma);
1313 acm_read_buffers_free(acm); 1356 acm_read_buffers_free(acm);
1314 1357
1315 usb_driver_release_interface(&acm_driver, intf == acm->control ? 1358 if (!acm->combined_interfaces)
1359 usb_driver_release_interface(&acm_driver, intf == acm->control ?
1316 acm->data : acm->control); 1360 acm->data : acm->control);
1317 1361
1318 if (acm->port.count == 0) { 1362 if (acm->port.count == 0) {
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 4c3856420add..1602324808ba 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -125,6 +125,7 @@ struct acm {
125 unsigned char clocal; /* termios CLOCAL */ 125 unsigned char clocal; /* termios CLOCAL */
126 unsigned int ctrl_caps; /* control capabilities from the class specific header */ 126 unsigned int ctrl_caps; /* control capabilities from the class specific header */
127 unsigned int susp_count; /* number of suspended interfaces */ 127 unsigned int susp_count; /* number of suspended interfaces */
128 int combined_interfaces:1; /* control and data collapsed */
128 struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ 129 struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
129}; 130};
130 131
@@ -133,3 +134,4 @@ struct acm {
133/* constants describing various quirks and errors */ 134/* constants describing various quirks and errors */
134#define NO_UNION_NORMAL 1 135#define NO_UNION_NORMAL 1
135#define SINGLE_RX_URB 2 136#define SINGLE_RX_URB 2
137#define NO_CAP_LINE 4