aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/qcserial.c
diff options
context:
space:
mode:
authorAnssi Hannula <anssi.hannula@gmail.com>2010-04-01 12:31:10 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-20 16:21:37 -0400
commite07896e62abbf7a741a5cd5b25ba7637bdf91ad0 (patch)
treee70a6c872a96283874faf8acbafeae97020d3095 /drivers/usb/serial/qcserial.c
parent3d7e59ad88fdb6bc50ae9b7e822d4bb5f68b68f9 (diff)
USB: qcserial: Add support for Qualcomm Gobi 2000 devices
Add ids for Qualcomm Gobi 2000 QDL and Modem modes. Gobi 2000 has a single altsetting in QDL mode, so adapt code to handle that. Firmware upload protocol is also slightly different, with an additional firmware file. However, qcserial doesn't handle firmware uploading. Tested on Lenovo Thinkpad T510. Signed-off-by: Anssi Hannula <anssi.hannula@gmail.com> Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/qcserial.c')
-rw-r--r--drivers/usb/serial/qcserial.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 9215f6c582c3..04bb759536bb 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -78,6 +78,8 @@ static const struct usb_device_id id_table[] = {
78 {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 78 {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
79 {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ 79 {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */
80 {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ 80 {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */
81 {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */
82 {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */
81 { } /* Terminating entry */ 83 { } /* Terminating entry */
82}; 84};
83MODULE_DEVICE_TABLE(usb, id_table); 85MODULE_DEVICE_TABLE(usb, id_table);
@@ -95,6 +97,7 @@ static struct usb_driver qcdriver = {
95static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) 97static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
96{ 98{
97 struct usb_wwan_intf_private *data; 99 struct usb_wwan_intf_private *data;
100 struct usb_host_interface *intf = serial->interface->cur_altsetting;
98 int retval = -ENODEV; 101 int retval = -ENODEV;
99 __u8 nintf; 102 __u8 nintf;
100 __u8 ifnum; 103 __u8 ifnum;
@@ -103,7 +106,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
103 106
104 nintf = serial->dev->actconfig->desc.bNumInterfaces; 107 nintf = serial->dev->actconfig->desc.bNumInterfaces;
105 dbg("Num Interfaces = %d", nintf); 108 dbg("Num Interfaces = %d", nintf);
106 ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; 109 ifnum = intf->desc.bInterfaceNumber;
107 dbg("This Interface = %d", ifnum); 110 dbg("This Interface = %d", ifnum);
108 111
109 data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), 112 data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
@@ -116,27 +119,32 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
116 switch (nintf) { 119 switch (nintf) {
117 case 1: 120 case 1:
118 /* QDL mode */ 121 /* QDL mode */
119 if (serial->interface->num_altsetting == 2) { 122 /* Gobi 2000 has a single altsetting, older ones have two */
120 struct usb_host_interface *intf; 123 if (serial->interface->num_altsetting == 2)
121
122 intf = &serial->interface->altsetting[1]; 124 intf = &serial->interface->altsetting[1];
123 if (intf->desc.bNumEndpoints == 2) { 125 else if (serial->interface->num_altsetting > 2)
124 if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && 126 break;
125 usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { 127
126 dbg("QDL port found"); 128 if (intf->desc.bNumEndpoints == 2 &&
127 retval = usb_set_interface(serial->dev, ifnum, 1); 129 usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
128 if (retval < 0) { 130 usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
129 dev_err(&serial->dev->dev, 131 dbg("QDL port found");
130 "Could not set interface, error %d\n", 132
131 retval); 133 if (serial->interface->num_altsetting == 1)
132 retval = -ENODEV; 134 return 0;
133 } 135
134 return retval; 136 retval = usb_set_interface(serial->dev, ifnum, 1);
135 } 137 if (retval < 0) {
138 dev_err(&serial->dev->dev,
139 "Could not set interface, error %d\n",
140 retval);
141 retval = -ENODEV;
136 } 142 }
143 return retval;
137 } 144 }
138 break; 145 break;
139 146
147 case 3:
140 case 4: 148 case 4:
141 /* Composite mode */ 149 /* Composite mode */
142 if (ifnum == 2) { 150 if (ifnum == 2) {