diff options
Diffstat (limited to 'drivers/usb/serial/qcserial.c')
-rw-r--r-- | drivers/usb/serial/qcserial.c | 125 |
1 files changed, 71 insertions, 54 deletions
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 996015c5f1ac..8d103019d6aa 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c | |||
@@ -105,6 +105,10 @@ static const struct usb_device_id id_table[] = { | |||
105 | {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ | 105 | {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ |
106 | {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ | 106 | {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ |
107 | {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ | 107 | {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ |
108 | {USB_DEVICE(0x1199, 0x68a4)}, /* Sierra Wireless QDL */ | ||
109 | {USB_DEVICE(0x1199, 0x68a5)}, /* Sierra Wireless Modem */ | ||
110 | {USB_DEVICE(0x1199, 0x68a8)}, /* Sierra Wireless QDL */ | ||
111 | {USB_DEVICE(0x1199, 0x68a9)}, /* Sierra Wireless Modem */ | ||
108 | {USB_DEVICE(0x1199, 0x9010)}, /* Sierra Wireless Gobi 3000 QDL */ | 112 | {USB_DEVICE(0x1199, 0x9010)}, /* Sierra Wireless Gobi 3000 QDL */ |
109 | {USB_DEVICE(0x1199, 0x9012)}, /* Sierra Wireless Gobi 3000 QDL */ | 113 | {USB_DEVICE(0x1199, 0x9012)}, /* Sierra Wireless Gobi 3000 QDL */ |
110 | {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ | 114 | {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ |
@@ -112,8 +116,24 @@ static const struct usb_device_id id_table[] = { | |||
112 | {USB_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ | 116 | {USB_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ |
113 | {USB_DEVICE(0x1199, 0x9018)}, /* Sierra Wireless Gobi 3000 QDL */ | 117 | {USB_DEVICE(0x1199, 0x9018)}, /* Sierra Wireless Gobi 3000 QDL */ |
114 | {USB_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ | 118 | {USB_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ |
119 | {USB_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ | ||
115 | {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ | 120 | {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ |
116 | {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ | 121 | {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ |
122 | |||
123 | /* non Gobi Qualcomm serial devices */ | ||
124 | {USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 0)}, /* Sierra Wireless MC7700 Device Management */ | ||
125 | {USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 2)}, /* Sierra Wireless MC7700 NMEA */ | ||
126 | {USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 3)}, /* Sierra Wireless MC7700 Modem */ | ||
127 | {USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 0)}, /* Sierra Wireless MC7750 Device Management */ | ||
128 | {USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 2)}, /* Sierra Wireless MC7750 NMEA */ | ||
129 | {USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 3)}, /* Sierra Wireless MC7750 Modem */ | ||
130 | {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 0)}, /* Sierra Wireless MC7710 Device Management */ | ||
131 | {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 2)}, /* Sierra Wireless MC7710 NMEA */ | ||
132 | {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 3)}, /* Sierra Wireless MC7710 Modem */ | ||
133 | {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 0)}, /* Sierra Wireless EM7700 Device Management */ | ||
134 | {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 2)}, /* Sierra Wireless EM7700 NMEA */ | ||
135 | {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 3)}, /* Sierra Wireless EM7700 Modem */ | ||
136 | |||
117 | { } /* Terminating entry */ | 137 | { } /* Terminating entry */ |
118 | }; | 138 | }; |
119 | MODULE_DEVICE_TABLE(usb, id_table); | 139 | MODULE_DEVICE_TABLE(usb, id_table); |
@@ -127,6 +147,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) | |||
127 | __u8 nintf; | 147 | __u8 nintf; |
128 | __u8 ifnum; | 148 | __u8 ifnum; |
129 | bool is_gobi1k = id->driver_info ? true : false; | 149 | bool is_gobi1k = id->driver_info ? true : false; |
150 | int altsetting = -1; | ||
130 | 151 | ||
131 | dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k); | 152 | dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k); |
132 | 153 | ||
@@ -142,38 +163,43 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) | |||
142 | 163 | ||
143 | spin_lock_init(&data->susp_lock); | 164 | spin_lock_init(&data->susp_lock); |
144 | 165 | ||
145 | switch (nintf) { | 166 | if (nintf == 1) { |
146 | case 1: | ||
147 | /* QDL mode */ | 167 | /* QDL mode */ |
148 | /* Gobi 2000 has a single altsetting, older ones have two */ | 168 | /* Gobi 2000 has a single altsetting, older ones have two */ |
149 | if (serial->interface->num_altsetting == 2) | 169 | if (serial->interface->num_altsetting == 2) |
150 | intf = &serial->interface->altsetting[1]; | 170 | intf = &serial->interface->altsetting[1]; |
151 | else if (serial->interface->num_altsetting > 2) | 171 | else if (serial->interface->num_altsetting > 2) |
152 | break; | 172 | goto done; |
153 | 173 | ||
154 | if (intf->desc.bNumEndpoints == 2 && | 174 | if (intf->desc.bNumEndpoints == 2 && |
155 | usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && | 175 | usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && |
156 | usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { | 176 | usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { |
157 | dev_dbg(dev, "QDL port found\n"); | 177 | dev_dbg(dev, "QDL port found\n"); |
158 | 178 | ||
159 | if (serial->interface->num_altsetting == 1) { | 179 | if (serial->interface->num_altsetting == 1) |
160 | retval = 0; /* Success */ | 180 | retval = 0; /* Success */ |
161 | break; | 181 | else |
162 | } | 182 | altsetting = 1; |
163 | |||
164 | retval = usb_set_interface(serial->dev, ifnum, 1); | ||
165 | if (retval < 0) { | ||
166 | dev_err(dev, | ||
167 | "Could not set interface, error %d\n", | ||
168 | retval); | ||
169 | retval = -ENODEV; | ||
170 | kfree(data); | ||
171 | } | ||
172 | } | 183 | } |
173 | break; | 184 | goto done; |
174 | 185 | ||
175 | case 3: | 186 | } |
176 | case 4: | 187 | |
188 | /* allow any number of interfaces when doing direct interface match */ | ||
189 | if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) { | ||
190 | dev_dbg(dev, "Generic Qualcomm serial interface found\n"); | ||
191 | altsetting = 0; | ||
192 | goto done; | ||
193 | } | ||
194 | |||
195 | if (nintf < 3 || nintf > 4) { | ||
196 | dev_err(dev, "unknown number of interfaces: %d\n", nintf); | ||
197 | goto done; | ||
198 | } | ||
199 | |||
200 | /* default to enabling interface */ | ||
201 | altsetting = 0; | ||
202 | switch (ifnum) { | ||
177 | /* Composite mode; don't bind to the QMI/net interface as that | 203 | /* Composite mode; don't bind to the QMI/net interface as that |
178 | * gets handled by other drivers. | 204 | * gets handled by other drivers. |
179 | */ | 205 | */ |
@@ -191,53 +217,44 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) | |||
191 | * 3: NMEA | 217 | * 3: NMEA |
192 | */ | 218 | */ |
193 | 219 | ||
194 | if (ifnum == 1 && !is_gobi1k) { | 220 | case 1: |
221 | if (is_gobi1k) | ||
222 | altsetting = -1; | ||
223 | else | ||
195 | dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n"); | 224 | dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n"); |
196 | retval = usb_set_interface(serial->dev, ifnum, 0); | 225 | break; |
197 | if (retval < 0) { | 226 | case 2: |
198 | dev_err(dev, | 227 | dev_dbg(dev, "Modem port found\n"); |
199 | "Could not set interface, error %d\n", | 228 | break; |
200 | retval); | 229 | case 3: |
201 | retval = -ENODEV; | 230 | if (is_gobi1k) |
202 | kfree(data); | 231 | altsetting = -1; |
203 | } | 232 | else |
204 | } else if (ifnum == 2) { | ||
205 | dev_dbg(dev, "Modem port found\n"); | ||
206 | retval = usb_set_interface(serial->dev, ifnum, 0); | ||
207 | if (retval < 0) { | ||
208 | dev_err(dev, | ||
209 | "Could not set interface, error %d\n", | ||
210 | retval); | ||
211 | retval = -ENODEV; | ||
212 | kfree(data); | ||
213 | } | ||
214 | } else if (ifnum==3 && !is_gobi1k) { | ||
215 | /* | 233 | /* |
216 | * NMEA (serial line 9600 8N1) | 234 | * NMEA (serial line 9600 8N1) |
217 | * # echo "\$GPS_START" > /dev/ttyUSBx | 235 | * # echo "\$GPS_START" > /dev/ttyUSBx |
218 | * # echo "\$GPS_STOP" > /dev/ttyUSBx | 236 | * # echo "\$GPS_STOP" > /dev/ttyUSBx |
219 | */ | 237 | */ |
220 | dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n"); | 238 | dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n"); |
221 | retval = usb_set_interface(serial->dev, ifnum, 0); | 239 | } |
222 | if (retval < 0) { | ||
223 | dev_err(dev, | ||
224 | "Could not set interface, error %d\n", | ||
225 | retval); | ||
226 | retval = -ENODEV; | ||
227 | kfree(data); | ||
228 | } | ||
229 | } | ||
230 | break; | ||
231 | 240 | ||
232 | default: | 241 | done: |
233 | dev_err(dev, "unknown number of interfaces: %d\n", nintf); | 242 | if (altsetting >= 0) { |
234 | kfree(data); | 243 | retval = usb_set_interface(serial->dev, ifnum, altsetting); |
235 | retval = -ENODEV; | 244 | if (retval < 0) { |
245 | dev_err(dev, | ||
246 | "Could not set interface, error %d\n", | ||
247 | retval); | ||
248 | retval = -ENODEV; | ||
249 | } | ||
236 | } | 250 | } |
237 | 251 | ||
238 | /* Set serial->private if not returning -ENODEV */ | 252 | /* Set serial->private if not returning error */ |
239 | if (retval != -ENODEV) | 253 | if (retval == 0) |
240 | usb_set_serial_data(serial, data); | 254 | usb_set_serial_data(serial, data); |
255 | else | ||
256 | kfree(data); | ||
257 | |||
241 | return retval; | 258 | return retval; |
242 | } | 259 | } |
243 | 260 | ||