aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/qcserial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/qcserial.c')
-rw-r--r--drivers/usb/serial/qcserial.c64
1 files changed, 47 insertions, 17 deletions
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 53a2d5a935a2..04bb759536bb 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -15,6 +15,8 @@
15#include <linux/tty_flip.h> 15#include <linux/tty_flip.h>
16#include <linux/usb.h> 16#include <linux/usb.h>
17#include <linux/usb/serial.h> 17#include <linux/usb/serial.h>
18#include <linux/slab.h>
19#include "usb-wwan.h"
18 20
19#define DRIVER_AUTHOR "Qualcomm Inc" 21#define DRIVER_AUTHOR "Qualcomm Inc"
20#define DRIVER_DESC "Qualcomm USB Serial driver" 22#define DRIVER_DESC "Qualcomm USB Serial driver"
@@ -76,6 +78,8 @@ static const struct usb_device_id id_table[] = {
76 {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 78 {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
77 {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ 79 {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */
78 {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 */
79 { } /* Terminating entry */ 83 { } /* Terminating entry */
80}; 84};
81MODULE_DEVICE_TABLE(usb, id_table); 85MODULE_DEVICE_TABLE(usb, id_table);
@@ -92,6 +96,8 @@ static struct usb_driver qcdriver = {
92 96
93static 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)
94{ 98{
99 struct usb_wwan_intf_private *data;
100 struct usb_host_interface *intf = serial->interface->cur_altsetting;
95 int retval = -ENODEV; 101 int retval = -ENODEV;
96 __u8 nintf; 102 __u8 nintf;
97 __u8 ifnum; 103 __u8 ifnum;
@@ -100,33 +106,45 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
100 106
101 nintf = serial->dev->actconfig->desc.bNumInterfaces; 107 nintf = serial->dev->actconfig->desc.bNumInterfaces;
102 dbg("Num Interfaces = %d", nintf); 108 dbg("Num Interfaces = %d", nintf);
103 ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; 109 ifnum = intf->desc.bInterfaceNumber;
104 dbg("This Interface = %d", ifnum); 110 dbg("This Interface = %d", ifnum);
105 111
112 data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
113 GFP_KERNEL);
114 if (!data)
115 return -ENOMEM;
116
117 spin_lock_init(&data->susp_lock);
118
106 switch (nintf) { 119 switch (nintf) {
107 case 1: 120 case 1:
108 /* QDL mode */ 121 /* QDL mode */
109 if (serial->interface->num_altsetting == 2) { 122 /* Gobi 2000 has a single altsetting, older ones have two */
110 struct usb_host_interface *intf; 123 if (serial->interface->num_altsetting == 2)
111
112 intf = &serial->interface->altsetting[1]; 124 intf = &serial->interface->altsetting[1];
113 if (intf->desc.bNumEndpoints == 2) { 125 else if (serial->interface->num_altsetting > 2)
114 if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && 126 break;
115 usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { 127
116 dbg("QDL port found"); 128 if (intf->desc.bNumEndpoints == 2 &&
117 retval = usb_set_interface(serial->dev, ifnum, 1); 129 usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
118 if (retval < 0) { 130 usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
119 dev_err(&serial->dev->dev, 131 dbg("QDL port found");
120 "Could not set interface, error %d\n", 132
121 retval); 133 if (serial->interface->num_altsetting == 1)
122 retval = -ENODEV; 134 return 0;
123 } 135
124 return retval; 136 retval = usb_set_interface(serial->dev, ifnum, 1);
125 } 137 if (retval < 0) {
138 dev_err(&serial->dev->dev,
139 "Could not set interface, error %d\n",
140 retval);
141 retval = -ENODEV;
126 } 142 }
143 return retval;
127 } 144 }
128 break; 145 break;
129 146
147 case 3:
130 case 4: 148 case 4:
131 /* Composite mode */ 149 /* Composite mode */
132 if (ifnum == 2) { 150 if (ifnum == 2) {
@@ -161,6 +179,18 @@ static struct usb_serial_driver qcdevice = {
161 .usb_driver = &qcdriver, 179 .usb_driver = &qcdriver,
162 .num_ports = 1, 180 .num_ports = 1,
163 .probe = qcprobe, 181 .probe = qcprobe,
182 .open = usb_wwan_open,
183 .close = usb_wwan_close,
184 .write = usb_wwan_write,
185 .write_room = usb_wwan_write_room,
186 .chars_in_buffer = usb_wwan_chars_in_buffer,
187 .attach = usb_wwan_startup,
188 .disconnect = usb_wwan_disconnect,
189 .release = usb_wwan_release,
190#ifdef CONFIG_PM
191 .suspend = usb_wwan_suspend,
192 .resume = usb_wwan_resume,
193#endif
164}; 194};
165 195
166static int __init qcinit(void) 196static int __init qcinit(void)