blob: 08a1712968e9672798556650284fa32e85157a7f [file] [log] [blame]
David Brownell61d8bae2008-06-19 18:18:50 -07001/*
2 * f_serial.c - generic USB serial function driver
3 *
4 * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
5 * Copyright (C) 2008 by David Brownell
6 * Copyright (C) 2008 by Nokia Corporation
7 *
8 * This software is distributed under the terms of the GNU General
9 * Public License ("GPL") as published by the Free Software Foundation,
10 * either version 2 of that License or (at your option) any later version.
11 */
12
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090013#include <linux/slab.h>
David Brownell61d8bae2008-06-19 18:18:50 -070014#include <linux/kernel.h>
15#include <linux/device.h>
Hemant Kumarbffd4142011-11-03 13:20:40 -070016#include <mach/usb_gadget_xport.h>
David Brownell61d8bae2008-06-19 18:18:50 -070017
18#include "u_serial.h"
19#include "gadget_chips.h"
20
21
22/*
23 * This function packages a simple "generic serial" port with no real
24 * control mechanisms, just raw data transfer over two bulk endpoints.
25 *
26 * Because it's not standardized, this isn't as interoperable as the
27 * CDC ACM driver. However, for many purposes it's just as functional
28 * if you can arrange appropriate host side drivers.
29 */
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +053030#define GSERIAL_NO_PORTS 3
David Brownell61d8bae2008-06-19 18:18:50 -070031
David Brownell61d8bae2008-06-19 18:18:50 -070032
33struct f_gser {
34 struct gserial port;
35 u8 data_id;
36 u8 port_num;
37
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038 u8 online;
39 enum transport_type transport;
40
41#ifdef CONFIG_MODEM_SUPPORT
42 u8 pending;
43 spinlock_t lock;
44 struct usb_ep *notify;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045 struct usb_request *notify_req;
46
47 struct usb_cdc_line_coding port_line_coding;
48
49 /* SetControlLineState request */
50 u16 port_handshake_bits;
51#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */
52#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */
53
54 /* SerialState notification */
55 u16 serial_state;
56#define ACM_CTRL_OVERRUN (1 << 6)
57#define ACM_CTRL_PARITY (1 << 5)
58#define ACM_CTRL_FRAMING (1 << 4)
59#define ACM_CTRL_RI (1 << 3)
60#define ACM_CTRL_BRK (1 << 2)
61#define ACM_CTRL_DSR (1 << 1)
62#define ACM_CTRL_DCD (1 << 0)
63#endif
David Brownell61d8bae2008-06-19 18:18:50 -070064};
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066static unsigned int no_tty_ports;
67static unsigned int no_sdio_ports;
68static unsigned int no_smd_ports;
Jack Pham427f6922011-11-23 19:42:00 -080069static unsigned int no_hsic_sports;
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +053070static unsigned int no_hsuart_sports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071static unsigned int nr_ports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072
73static struct port_info {
74 enum transport_type transport;
75 unsigned port_num;
76 unsigned client_port_num;
77} gserial_ports[GSERIAL_NO_PORTS];
78
79static inline bool is_transport_sdio(enum transport_type t)
80{
Hemant Kumarbffd4142011-11-03 13:20:40 -070081 if (t == USB_GADGET_XPORT_SDIO)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082 return 1;
83 return 0;
84}
85
David Brownell61d8bae2008-06-19 18:18:50 -070086static inline struct f_gser *func_to_gser(struct usb_function *f)
87{
88 return container_of(f, struct f_gser, port.func);
89}
90
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091#ifdef CONFIG_MODEM_SUPPORT
92static inline struct f_gser *port_to_gser(struct gserial *p)
93{
94 return container_of(p, struct f_gser, port);
95}
96#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
97#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */
98#endif
David Brownell61d8bae2008-06-19 18:18:50 -070099/*-------------------------------------------------------------------------*/
100
101/* interface descriptor: */
102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static struct usb_interface_descriptor gser_interface_desc = {
David Brownell61d8bae2008-06-19 18:18:50 -0700104 .bLength = USB_DT_INTERFACE_SIZE,
105 .bDescriptorType = USB_DT_INTERFACE,
106 /* .bInterfaceNumber = DYNAMIC */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107#ifdef CONFIG_MODEM_SUPPORT
108 .bNumEndpoints = 3,
109#else
David Brownell61d8bae2008-06-19 18:18:50 -0700110 .bNumEndpoints = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700112 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
113 .bInterfaceSubClass = 0,
114 .bInterfaceProtocol = 0,
115 /* .iInterface = DYNAMIC */
116};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117#ifdef CONFIG_MODEM_SUPPORT
118static struct usb_cdc_header_desc gser_header_desc = {
119 .bLength = sizeof(gser_header_desc),
120 .bDescriptorType = USB_DT_CS_INTERFACE,
121 .bDescriptorSubType = USB_CDC_HEADER_TYPE,
122 .bcdCDC = __constant_cpu_to_le16(0x0110),
123};
David Brownell61d8bae2008-06-19 18:18:50 -0700124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125static struct usb_cdc_call_mgmt_descriptor
126gser_call_mgmt_descriptor = {
127 .bLength = sizeof(gser_call_mgmt_descriptor),
128 .bDescriptorType = USB_DT_CS_INTERFACE,
129 .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
130 .bmCapabilities = 0,
131 /* .bDataInterface = DYNAMIC */
132};
133
134static struct usb_cdc_acm_descriptor gser_descriptor = {
135 .bLength = sizeof(gser_descriptor),
136 .bDescriptorType = USB_DT_CS_INTERFACE,
137 .bDescriptorSubType = USB_CDC_ACM_TYPE,
138 .bmCapabilities = USB_CDC_CAP_LINE,
139};
140
141static struct usb_cdc_union_desc gser_union_desc = {
142 .bLength = sizeof(gser_union_desc),
143 .bDescriptorType = USB_DT_CS_INTERFACE,
144 .bDescriptorSubType = USB_CDC_UNION_TYPE,
145 /* .bMasterInterface0 = DYNAMIC */
146 /* .bSlaveInterface0 = DYNAMIC */
147};
148#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700149/* full speed support: */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150#ifdef CONFIG_MODEM_SUPPORT
151static struct usb_endpoint_descriptor gser_fs_notify_desc = {
152 .bLength = USB_DT_ENDPOINT_SIZE,
153 .bDescriptorType = USB_DT_ENDPOINT,
154 .bEndpointAddress = USB_DIR_IN,
155 .bmAttributes = USB_ENDPOINT_XFER_INT,
156 .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
157 .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
158};
159#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700160
Manu Gautama4d993f2011-08-30 18:25:55 +0530161static struct usb_endpoint_descriptor gser_fs_in_desc = {
David Brownell61d8bae2008-06-19 18:18:50 -0700162 .bLength = USB_DT_ENDPOINT_SIZE,
163 .bDescriptorType = USB_DT_ENDPOINT,
164 .bEndpointAddress = USB_DIR_IN,
165 .bmAttributes = USB_ENDPOINT_XFER_BULK,
166};
167
Manu Gautama4d993f2011-08-30 18:25:55 +0530168static struct usb_endpoint_descriptor gser_fs_out_desc = {
David Brownell61d8bae2008-06-19 18:18:50 -0700169 .bLength = USB_DT_ENDPOINT_SIZE,
170 .bDescriptorType = USB_DT_ENDPOINT,
171 .bEndpointAddress = USB_DIR_OUT,
172 .bmAttributes = USB_ENDPOINT_XFER_BULK,
173};
174
Manu Gautama4d993f2011-08-30 18:25:55 +0530175static struct usb_descriptor_header *gser_fs_function[] = {
David Brownell61d8bae2008-06-19 18:18:50 -0700176 (struct usb_descriptor_header *) &gser_interface_desc,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177#ifdef CONFIG_MODEM_SUPPORT
178 (struct usb_descriptor_header *) &gser_header_desc,
179 (struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
180 (struct usb_descriptor_header *) &gser_descriptor,
181 (struct usb_descriptor_header *) &gser_union_desc,
182 (struct usb_descriptor_header *) &gser_fs_notify_desc,
183#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700184 (struct usb_descriptor_header *) &gser_fs_in_desc,
185 (struct usb_descriptor_header *) &gser_fs_out_desc,
186 NULL,
187};
188
189/* high speed support: */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190#ifdef CONFIG_MODEM_SUPPORT
191static struct usb_endpoint_descriptor gser_hs_notify_desc = {
192 .bLength = USB_DT_ENDPOINT_SIZE,
193 .bDescriptorType = USB_DT_ENDPOINT,
194 .bEndpointAddress = USB_DIR_IN,
195 .bmAttributes = USB_ENDPOINT_XFER_INT,
196 .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
197 .bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
198};
199#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700200
Manu Gautama4d993f2011-08-30 18:25:55 +0530201static struct usb_endpoint_descriptor gser_hs_in_desc = {
David Brownell61d8bae2008-06-19 18:18:50 -0700202 .bLength = USB_DT_ENDPOINT_SIZE,
203 .bDescriptorType = USB_DT_ENDPOINT,
204 .bmAttributes = USB_ENDPOINT_XFER_BULK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 .wMaxPacketSize = __constant_cpu_to_le16(512),
David Brownell61d8bae2008-06-19 18:18:50 -0700206};
207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208static struct usb_endpoint_descriptor gser_hs_out_desc = {
David Brownell61d8bae2008-06-19 18:18:50 -0700209 .bLength = USB_DT_ENDPOINT_SIZE,
210 .bDescriptorType = USB_DT_ENDPOINT,
211 .bmAttributes = USB_ENDPOINT_XFER_BULK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 .wMaxPacketSize = __constant_cpu_to_le16(512),
David Brownell61d8bae2008-06-19 18:18:50 -0700213};
214
Manu Gautama4d993f2011-08-30 18:25:55 +0530215static struct usb_descriptor_header *gser_hs_function[] = {
David Brownell61d8bae2008-06-19 18:18:50 -0700216 (struct usb_descriptor_header *) &gser_interface_desc,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217#ifdef CONFIG_MODEM_SUPPORT
218 (struct usb_descriptor_header *) &gser_header_desc,
219 (struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
220 (struct usb_descriptor_header *) &gser_descriptor,
221 (struct usb_descriptor_header *) &gser_union_desc,
222 (struct usb_descriptor_header *) &gser_hs_notify_desc,
223#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700224 (struct usb_descriptor_header *) &gser_hs_in_desc,
225 (struct usb_descriptor_header *) &gser_hs_out_desc,
226 NULL,
227};
228
229/* string descriptors: */
230
231static struct usb_string gser_string_defs[] = {
232 [0].s = "Generic Serial",
233 { } /* end of list */
234};
235
236static struct usb_gadget_strings gser_string_table = {
237 .language = 0x0409, /* en-us */
238 .strings = gser_string_defs,
239};
240
241static struct usb_gadget_strings *gser_strings[] = {
242 &gser_string_table,
243 NULL,
244};
245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246static int gport_setup(struct usb_configuration *c)
247{
248 int ret = 0;
Jack Pham427f6922011-11-23 19:42:00 -0800249 int port_idx;
250 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251
Jack Pham427f6922011-11-23 19:42:00 -0800252 pr_debug("%s: no_tty_ports: %u no_sdio_ports: %u"
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530253 " no_smd_ports: %u no_hsic_sports: %u no_hsuart_ports: %u nr_ports: %u\n",
Jack Pham427f6922011-11-23 19:42:00 -0800254 __func__, no_tty_ports, no_sdio_ports, no_smd_ports,
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530255 no_hsic_sports, no_hsuart_sports, nr_ports);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256
257 if (no_tty_ports)
258 ret = gserial_setup(c->cdev->gadget, no_tty_ports);
259 if (no_sdio_ports)
260 ret = gsdio_setup(c->cdev->gadget, no_sdio_ports);
261 if (no_smd_ports)
262 ret = gsmd_setup(c->cdev->gadget, no_smd_ports);
Jack Pham427f6922011-11-23 19:42:00 -0800263 if (no_hsic_sports) {
264 port_idx = ghsic_data_setup(no_hsic_sports, USB_GADGET_SERIAL);
265 if (port_idx < 0)
266 return port_idx;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267
Jack Pham427f6922011-11-23 19:42:00 -0800268 for (i = 0; i < nr_ports; i++) {
269 if (gserial_ports[i].transport ==
270 USB_GADGET_XPORT_HSIC) {
271 gserial_ports[i].client_port_num = port_idx;
272 port_idx++;
273 }
274 }
275
276 /*clinet port num is same for data setup and ctrl setup*/
277 ret = ghsic_ctrl_setup(no_hsic_sports, USB_GADGET_SERIAL);
278 if (ret < 0)
279 return ret;
280 return 0;
281 }
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530282 if (no_hsuart_sports) {
283 port_idx = ghsuart_data_setup(no_hsuart_sports,
284 USB_GADGET_SERIAL);
285 if (port_idx < 0)
286 return port_idx;
287
288 for (i = 0; i < nr_ports; i++) {
289 if (gserial_ports[i].transport ==
290 USB_GADGET_XPORT_HSUART) {
291 gserial_ports[i].client_port_num = port_idx;
292 port_idx++;
293 }
294 }
295
296 return 0;
297 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 return ret;
299}
Manu Gautama4d993f2011-08-30 18:25:55 +0530300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301static int gport_connect(struct f_gser *gser)
302{
Jack Pham427f6922011-11-23 19:42:00 -0800303 unsigned port_num;
304 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305
Jack Pham427f6922011-11-23 19:42:00 -0800306 pr_debug("%s: transport: %s f_gser: %p gserial: %p port_num: %d\n",
Hemant Kumar1b820d52011-11-03 15:08:28 -0700307 __func__, xport_to_str(gser->transport),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 gser, &gser->port, gser->port_num);
309
310 port_num = gserial_ports[gser->port_num].client_port_num;
311
312 switch (gser->transport) {
Hemant Kumarbffd4142011-11-03 13:20:40 -0700313 case USB_GADGET_XPORT_TTY:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 gserial_connect(&gser->port, port_num);
315 break;
Hemant Kumarbffd4142011-11-03 13:20:40 -0700316 case USB_GADGET_XPORT_SDIO:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 gsdio_connect(&gser->port, port_num);
318 break;
Hemant Kumarbffd4142011-11-03 13:20:40 -0700319 case USB_GADGET_XPORT_SMD:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 gsmd_connect(&gser->port, port_num);
321 break;
Jack Pham427f6922011-11-23 19:42:00 -0800322 case USB_GADGET_XPORT_HSIC:
323 ret = ghsic_ctrl_connect(&gser->port, port_num);
324 if (ret) {
325 pr_err("%s: ghsic_ctrl_connect failed: err:%d\n",
326 __func__, ret);
327 return ret;
328 }
329 ret = ghsic_data_connect(&gser->port, port_num);
330 if (ret) {
331 pr_err("%s: ghsic_data_connect failed: err:%d\n",
332 __func__, ret);
333 ghsic_ctrl_disconnect(&gser->port, port_num);
334 return ret;
335 }
336 break;
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530337 case USB_GADGET_XPORT_HSUART:
338 ret = ghsuart_data_connect(&gser->port, port_num);
339 if (ret) {
340 pr_err("%s: ghsuart_data_connect failed: err:%d\n",
341 __func__, ret);
342 return ret;
343 }
344 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 default:
346 pr_err("%s: Un-supported transport: %s\n", __func__,
Hemant Kumar1b820d52011-11-03 15:08:28 -0700347 xport_to_str(gser->transport));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 return -ENODEV;
349 }
350
351 return 0;
352}
353
354static int gport_disconnect(struct f_gser *gser)
355{
356 unsigned port_num;
357
Jack Pham427f6922011-11-23 19:42:00 -0800358 pr_debug("%s: transport: %s f_gser: %p gserial: %p port_num: %d\n",
Hemant Kumar1b820d52011-11-03 15:08:28 -0700359 __func__, xport_to_str(gser->transport),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 gser, &gser->port, gser->port_num);
361
362 port_num = gserial_ports[gser->port_num].client_port_num;
363
364 switch (gser->transport) {
Hemant Kumarbffd4142011-11-03 13:20:40 -0700365 case USB_GADGET_XPORT_TTY:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366 gserial_disconnect(&gser->port);
367 break;
Hemant Kumarbffd4142011-11-03 13:20:40 -0700368 case USB_GADGET_XPORT_SDIO:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369 gsdio_disconnect(&gser->port, port_num);
370 break;
Hemant Kumarbffd4142011-11-03 13:20:40 -0700371 case USB_GADGET_XPORT_SMD:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 gsmd_disconnect(&gser->port, port_num);
373 break;
Jack Pham427f6922011-11-23 19:42:00 -0800374 case USB_GADGET_XPORT_HSIC:
375 ghsic_ctrl_disconnect(&gser->port, port_num);
376 ghsic_data_disconnect(&gser->port, port_num);
377 break;
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530378 case USB_GADGET_XPORT_HSUART:
379 ghsuart_data_disconnect(&gser->port, port_num);
380 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 default:
382 pr_err("%s: Un-supported transport:%s\n", __func__,
Hemant Kumar1b820d52011-11-03 15:08:28 -0700383 xport_to_str(gser->transport));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 return -ENODEV;
385 }
386
387 return 0;
388}
389
390#ifdef CONFIG_MODEM_SUPPORT
391static void gser_complete_set_line_coding(struct usb_ep *ep,
392 struct usb_request *req)
393{
394 struct f_gser *gser = ep->driver_data;
395 struct usb_composite_dev *cdev = gser->port.func.config->cdev;
396
397 if (req->status != 0) {
398 DBG(cdev, "gser ttyGS%d completion, err %d\n",
399 gser->port_num, req->status);
400 return;
401 }
402
403 /* normal completion */
404 if (req->actual != sizeof(gser->port_line_coding)) {
405 DBG(cdev, "gser ttyGS%d short resp, len %d\n",
406 gser->port_num, req->actual);
407 usb_ep_set_halt(ep);
408 } else {
409 struct usb_cdc_line_coding *value = req->buf;
410 gser->port_line_coding = *value;
411 }
412}
David Brownell61d8bae2008-06-19 18:18:50 -0700413/*-------------------------------------------------------------------------*/
414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415static int
416gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
417{
418 struct f_gser *gser = func_to_gser(f);
419 struct usb_composite_dev *cdev = f->config->cdev;
420 struct usb_request *req = cdev->req;
421 int value = -EOPNOTSUPP;
422 u16 w_index = le16_to_cpu(ctrl->wIndex);
423 u16 w_value = le16_to_cpu(ctrl->wValue);
424 u16 w_length = le16_to_cpu(ctrl->wLength);
425
426 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
427
428 /* SET_LINE_CODING ... just read and save what the host sends */
429 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
430 | USB_CDC_REQ_SET_LINE_CODING:
431 if (w_length != sizeof(struct usb_cdc_line_coding))
432 goto invalid;
433
434 value = w_length;
435 cdev->gadget->ep0->driver_data = gser;
436 req->complete = gser_complete_set_line_coding;
437 break;
438
439 /* GET_LINE_CODING ... return what host sent, or initial value */
440 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
441 | USB_CDC_REQ_GET_LINE_CODING:
442 value = min_t(unsigned, w_length,
443 sizeof(struct usb_cdc_line_coding));
444 memcpy(req->buf, &gser->port_line_coding, value);
445 break;
446
447 /* SET_CONTROL_LINE_STATE ... save what the host sent */
448 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
449 | USB_CDC_REQ_SET_CONTROL_LINE_STATE:
450
451 value = 0;
452 gser->port_handshake_bits = w_value;
453 if (gser->port.notify_modem) {
454 unsigned port_num =
455 gserial_ports[gser->port_num].client_port_num;
456
457 gser->port.notify_modem(&gser->port,
458 port_num, w_value);
459 }
460 break;
461
462 default:
463invalid:
464 DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
465 ctrl->bRequestType, ctrl->bRequest,
466 w_value, w_index, w_length);
467 }
468
469 /* respond with data transfer or status phase? */
470 if (value >= 0) {
471 DBG(cdev, "gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
472 gser->port_num, ctrl->bRequestType, ctrl->bRequest,
473 w_value, w_index, w_length);
474 req->zero = 0;
475 req->length = value;
476 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
477 if (value < 0)
478 ERROR(cdev, "gser response on ttyGS%d, err %d\n",
479 gser->port_num, value);
480 }
481
482 /* device either stalls (value < 0) or reports success */
483 return value;
484}
485#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700486static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
487{
488 struct f_gser *gser = func_to_gser(f);
489 struct usb_composite_dev *cdev = f->config->cdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 int rc = 0;
David Brownell61d8bae2008-06-19 18:18:50 -0700491
492 /* we know alt == 0, so this is an activation or a reset */
493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494#ifdef CONFIG_MODEM_SUPPORT
495 if (gser->notify->driver_data) {
496 DBG(cdev, "reset generic ctl ttyGS%d\n", gser->port_num);
497 usb_ep_disable(gser->notify);
David Brownell61d8bae2008-06-19 18:18:50 -0700498 }
Tatyana Brokhman31ac3522011-06-28 15:33:50 +0200499
500 if (!gser->notify->desc) {
501 if (config_ep_by_speed(cdev->gadget, f, gser->notify)) {
502 gser->notify->desc = NULL;
503 return -EINVAL;
504 }
505 }
Tatyana Brokhmancf709c12011-06-28 16:33:48 +0300506 rc = usb_ep_enable(gser->notify);
Tatyana Brokhman31ac3522011-06-28 15:33:50 +0200507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 if (rc) {
509 ERROR(cdev, "can't enable %s, result %d\n",
510 gser->notify->name, rc);
511 return rc;
512 }
513 gser->notify->driver_data = gser;
514#endif
515
516 if (gser->port.in->driver_data) {
517 DBG(cdev, "reset generic data ttyGS%d\n", gser->port_num);
518 gport_disconnect(gser);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519 }
Tatyana Brokhman31ac3522011-06-28 15:33:50 +0200520 if (!gser->port.in->desc || !gser->port.out->desc) {
521 DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
522 if (config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
523 config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
524 gser->port.in->desc = NULL;
525 gser->port.out->desc = NULL;
526 return -EINVAL;
527 }
528 }
David Brownac5d1542012-02-06 10:37:22 -0800529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530 gport_connect(gser);
531
532 gser->online = 1;
533 return rc;
David Brownell61d8bae2008-06-19 18:18:50 -0700534}
535
536static void gser_disable(struct usb_function *f)
537{
538 struct f_gser *gser = func_to_gser(f);
539 struct usb_composite_dev *cdev = f->config->cdev;
540
541 DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542
543 gport_disconnect(gser);
544
545#ifdef CONFIG_MODEM_SUPPORT
546 usb_ep_fifo_flush(gser->notify);
547 usb_ep_disable(gser->notify);
548#endif
549 gser->online = 0;
550}
551#ifdef CONFIG_MODEM_SUPPORT
552static int gser_notify(struct f_gser *gser, u8 type, u16 value,
553 void *data, unsigned length)
554{
555 struct usb_ep *ep = gser->notify;
556 struct usb_request *req;
557 struct usb_cdc_notification *notify;
558 const unsigned len = sizeof(*notify) + length;
559 void *buf;
560 int status;
561 struct usb_composite_dev *cdev = gser->port.func.config->cdev;
562
563 req = gser->notify_req;
564 gser->notify_req = NULL;
565 gser->pending = false;
566
567 req->length = len;
568 notify = req->buf;
569 buf = notify + 1;
570
571 notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
572 | USB_RECIP_INTERFACE;
573 notify->bNotificationType = type;
574 notify->wValue = cpu_to_le16(value);
575 notify->wIndex = cpu_to_le16(gser->data_id);
576 notify->wLength = cpu_to_le16(length);
577 memcpy(buf, data, length);
578
579 status = usb_ep_queue(ep, req, GFP_ATOMIC);
580 if (status < 0) {
581 ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n",
582 gser->port_num, status);
583 gser->notify_req = req;
584 }
585
586 return status;
David Brownell61d8bae2008-06-19 18:18:50 -0700587}
588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589static int gser_notify_serial_state(struct f_gser *gser)
590{
591 int status;
592 unsigned long flags;
593 struct usb_composite_dev *cdev = gser->port.func.config->cdev;
594
595 spin_lock_irqsave(&gser->lock, flags);
596 if (gser->notify_req) {
597 DBG(cdev, "gser ttyGS%d serial state %04x\n",
598 gser->port_num, gser->serial_state);
599 status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE,
600 0, &gser->serial_state,
601 sizeof(gser->serial_state));
602 } else {
603 gser->pending = true;
604 status = 0;
605 }
606 spin_unlock_irqrestore(&gser->lock, flags);
607 return status;
608}
609
610static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req)
611{
612 struct f_gser *gser = req->context;
613 u8 doit = false;
614 unsigned long flags;
615
616 /* on this call path we do NOT hold the port spinlock,
617 * which is why ACM needs its own spinlock
618 */
619 spin_lock_irqsave(&gser->lock, flags);
620 if (req->status != -ESHUTDOWN)
621 doit = gser->pending;
622 gser->notify_req = req;
623 spin_unlock_irqrestore(&gser->lock, flags);
624
625 if (doit && gser->online)
626 gser_notify_serial_state(gser);
627}
628static void gser_connect(struct gserial *port)
629{
630 struct f_gser *gser = port_to_gser(port);
631
632 gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
633 gser_notify_serial_state(gser);
634}
635
636unsigned int gser_get_dtr(struct gserial *port)
637{
638 struct f_gser *gser = port_to_gser(port);
639
640 if (gser->port_handshake_bits & ACM_CTRL_DTR)
641 return 1;
642 else
643 return 0;
644}
645
646unsigned int gser_get_rts(struct gserial *port)
647{
648 struct f_gser *gser = port_to_gser(port);
649
650 if (gser->port_handshake_bits & ACM_CTRL_RTS)
651 return 1;
652 else
653 return 0;
654}
655
656unsigned int gser_send_carrier_detect(struct gserial *port, unsigned int yes)
657{
658 struct f_gser *gser = port_to_gser(port);
659 u16 state;
660
661 state = gser->serial_state;
662 state &= ~ACM_CTRL_DCD;
663 if (yes)
664 state |= ACM_CTRL_DCD;
665
666 gser->serial_state = state;
667 return gser_notify_serial_state(gser);
668
669}
670
671unsigned int gser_send_ring_indicator(struct gserial *port, unsigned int yes)
672{
673 struct f_gser *gser = port_to_gser(port);
674 u16 state;
675
676 state = gser->serial_state;
677 state &= ~ACM_CTRL_RI;
678 if (yes)
679 state |= ACM_CTRL_RI;
680
681 gser->serial_state = state;
682 return gser_notify_serial_state(gser);
683
684}
685static void gser_disconnect(struct gserial *port)
686{
687 struct f_gser *gser = port_to_gser(port);
688
689 gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
690 gser_notify_serial_state(gser);
691}
692
693static int gser_send_break(struct gserial *port, int duration)
694{
695 struct f_gser *gser = port_to_gser(port);
696 u16 state;
697
698 state = gser->serial_state;
699 state &= ~ACM_CTRL_BRK;
700 if (duration)
701 state |= ACM_CTRL_BRK;
702
703 gser->serial_state = state;
704 return gser_notify_serial_state(gser);
705}
706
707static int gser_send_modem_ctrl_bits(struct gserial *port, int ctrl_bits)
708{
709 struct f_gser *gser = port_to_gser(port);
710
711 gser->serial_state = ctrl_bits;
712
713 return gser_notify_serial_state(gser);
714}
715#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700716/*-------------------------------------------------------------------------*/
717
718/* serial function driver setup/binding */
719
Manu Gautama4d993f2011-08-30 18:25:55 +0530720static int
David Brownell61d8bae2008-06-19 18:18:50 -0700721gser_bind(struct usb_configuration *c, struct usb_function *f)
722{
723 struct usb_composite_dev *cdev = c->cdev;
724 struct f_gser *gser = func_to_gser(f);
725 int status;
726 struct usb_ep *ep;
727
728 /* allocate instance-specific interface IDs */
729 status = usb_interface_id(c, f);
730 if (status < 0)
731 goto fail;
732 gser->data_id = status;
733 gser_interface_desc.bInterfaceNumber = status;
734
735 status = -ENODEV;
736
737 /* allocate instance-specific endpoints */
738 ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
739 if (!ep)
740 goto fail;
741 gser->port.in = ep;
742 ep->driver_data = cdev; /* claim */
743
744 ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
745 if (!ep)
746 goto fail;
747 gser->port.out = ep;
748 ep->driver_data = cdev; /* claim */
749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750#ifdef CONFIG_MODEM_SUPPORT
751 ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
752 if (!ep)
753 goto fail;
754 gser->notify = ep;
755 ep->driver_data = cdev; /* claim */
756 /* allocate notification */
757 gser->notify_req = gs_alloc_req(ep,
758 sizeof(struct usb_cdc_notification) + 2,
759 GFP_KERNEL);
760 if (!gser->notify_req)
761 goto fail;
762
763 gser->notify_req->complete = gser_notify_complete;
764 gser->notify_req->context = gser;
765#endif
766
David Brownell61d8bae2008-06-19 18:18:50 -0700767 /* copy descriptors, and track endpoint copies */
768 f->descriptors = usb_copy_descriptors(gser_fs_function);
769
Pavankumar Kondetif0f95d82011-09-23 11:38:57 +0530770 if (!f->descriptors)
771 goto fail;
772
David Brownell61d8bae2008-06-19 18:18:50 -0700773 /* support all relevant hardware speeds... we expect that when
774 * hardware is dual speed, all bulk-capable endpoints work at
775 * both speeds
776 */
777 if (gadget_is_dualspeed(c->cdev->gadget)) {
778 gser_hs_in_desc.bEndpointAddress =
779 gser_fs_in_desc.bEndpointAddress;
780 gser_hs_out_desc.bEndpointAddress =
781 gser_fs_out_desc.bEndpointAddress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782#ifdef CONFIG_MODEM_SUPPORT
783 gser_hs_notify_desc.bEndpointAddress =
784 gser_fs_notify_desc.bEndpointAddress;
785#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700786
787 /* copy descriptors, and track endpoint copies */
788 f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
789
Pavankumar Kondetif0f95d82011-09-23 11:38:57 +0530790 if (!f->hs_descriptors)
791 goto fail;
792
David Brownell61d8bae2008-06-19 18:18:50 -0700793 }
794
795 DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
796 gser->port_num,
797 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
798 gser->port.in->name, gser->port.out->name);
799 return 0;
800
801fail:
Pavankumar Kondetif0f95d82011-09-23 11:38:57 +0530802 if (f->descriptors)
803 usb_free_descriptors(f->descriptors);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804#ifdef CONFIG_MODEM_SUPPORT
805 if (gser->notify_req)
806 gs_free_req(gser->notify, gser->notify_req);
807
808 /* we might as well release our claims on endpoints */
809 if (gser->notify)
810 gser->notify->driver_data = NULL;
811#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700812 /* we might as well release our claims on endpoints */
813 if (gser->port.out)
814 gser->port.out->driver_data = NULL;
815 if (gser->port.in)
816 gser->port.in->driver_data = NULL;
817
818 ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
819
820 return status;
821}
822
823static void
824gser_unbind(struct usb_configuration *c, struct usb_function *f)
825{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826#ifdef CONFIG_MODEM_SUPPORT
827 struct f_gser *gser = func_to_gser(f);
828#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700829 if (gadget_is_dualspeed(c->cdev->gadget))
830 usb_free_descriptors(f->hs_descriptors);
831 usb_free_descriptors(f->descriptors);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832#ifdef CONFIG_MODEM_SUPPORT
833 gs_free_req(gser->notify, gser->notify_req);
834#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700835 kfree(func_to_gser(f));
836}
837
838/**
839 * gser_bind_config - add a generic serial function to a configuration
840 * @c: the configuration to support the serial instance
841 * @port_num: /dev/ttyGS* port this interface will use
842 * Context: single threaded during gadget setup
843 *
844 * Returns zero on success, else negative errno.
845 *
846 * Caller must have called @gserial_setup() with enough ports to
847 * handle all the ones it binds. Caller is also responsible
848 * for calling @gserial_cleanup() before module unload.
849 */
Manu Gautama4d993f2011-08-30 18:25:55 +0530850int gser_bind_config(struct usb_configuration *c, u8 port_num)
David Brownell61d8bae2008-06-19 18:18:50 -0700851{
852 struct f_gser *gser;
853 int status;
854
855 /* REVISIT might want instance-specific strings to help
856 * distinguish instances ...
857 */
858
859 /* maybe allocate device-global string ID */
860 if (gser_string_defs[0].id == 0) {
861 status = usb_string_id(c->cdev);
862 if (status < 0)
863 return status;
864 gser_string_defs[0].id = status;
865 }
866
867 /* allocate and initialize one new instance */
868 gser = kzalloc(sizeof *gser, GFP_KERNEL);
869 if (!gser)
870 return -ENOMEM;
871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872#ifdef CONFIG_MODEM_SUPPORT
873 spin_lock_init(&gser->lock);
874#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700875 gser->port_num = port_num;
876
877 gser->port.func.name = "gser";
878 gser->port.func.strings = gser_strings;
879 gser->port.func.bind = gser_bind;
880 gser->port.func.unbind = gser_unbind;
881 gser->port.func.set_alt = gser_set_alt;
882 gser->port.func.disable = gser_disable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 gser->transport = gserial_ports[port_num].transport;
884#ifdef CONFIG_MODEM_SUPPORT
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530885 /* We support only three ports for now */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 if (port_num == 0)
887 gser->port.func.name = "modem";
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530888 else if (port_num == 1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 gser->port.func.name = "nmea";
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530890 else
891 gser->port.func.name = "modem2";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 gser->port.func.setup = gser_setup;
893 gser->port.connect = gser_connect;
894 gser->port.get_dtr = gser_get_dtr;
895 gser->port.get_rts = gser_get_rts;
896 gser->port.send_carrier_detect = gser_send_carrier_detect;
897 gser->port.send_ring_indicator = gser_send_ring_indicator;
898 gser->port.send_modem_ctrl_bits = gser_send_modem_ctrl_bits;
899 gser->port.disconnect = gser_disconnect;
900 gser->port.send_break = gser_send_break;
901#endif
David Brownell61d8bae2008-06-19 18:18:50 -0700902
903 status = usb_add_function(c, &gser->port.func);
904 if (status)
905 kfree(gser);
906 return status;
907}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908
Manu Gautama4d993f2011-08-30 18:25:55 +0530909/**
910 * gserial_init_port - bind a gserial_port to its transport
911 */
912static int gserial_init_port(int port_num, const char *name)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913{
Manu Gautama4d993f2011-08-30 18:25:55 +0530914 enum transport_type transport;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915
Manu Gautama4d993f2011-08-30 18:25:55 +0530916 if (port_num >= GSERIAL_NO_PORTS)
917 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918
Hemant Kumar1b820d52011-11-03 15:08:28 -0700919 transport = str_to_xport(name);
Manu Gautama4d993f2011-08-30 18:25:55 +0530920 pr_debug("%s, port:%d, transport:%s\n", __func__,
Jack Pham427f6922011-11-23 19:42:00 -0800921 port_num, xport_to_str(transport));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700922
Manu Gautama4d993f2011-08-30 18:25:55 +0530923 gserial_ports[port_num].transport = transport;
924 gserial_ports[port_num].port_num = port_num;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925
Manu Gautama4d993f2011-08-30 18:25:55 +0530926 switch (transport) {
Hemant Kumarbffd4142011-11-03 13:20:40 -0700927 case USB_GADGET_XPORT_TTY:
Manu Gautama4d993f2011-08-30 18:25:55 +0530928 gserial_ports[port_num].client_port_num = no_tty_ports;
929 no_tty_ports++;
930 break;
Hemant Kumarbffd4142011-11-03 13:20:40 -0700931 case USB_GADGET_XPORT_SDIO:
Manu Gautama4d993f2011-08-30 18:25:55 +0530932 gserial_ports[port_num].client_port_num = no_sdio_ports;
933 no_sdio_ports++;
934 break;
Hemant Kumarbffd4142011-11-03 13:20:40 -0700935 case USB_GADGET_XPORT_SMD:
Manu Gautama4d993f2011-08-30 18:25:55 +0530936 gserial_ports[port_num].client_port_num = no_smd_ports;
937 no_smd_ports++;
938 break;
Jack Pham427f6922011-11-23 19:42:00 -0800939 case USB_GADGET_XPORT_HSIC:
940 /*client port number will be updated in gport_setup*/
941 no_hsic_sports++;
942 break;
Vijayavardhan Vennapusaeb8d2392012-04-03 18:58:49 +0530943 case USB_GADGET_XPORT_HSUART:
944 /*client port number will be updated in gport_setup*/
945 no_hsuart_sports++;
946 break;
Manu Gautama4d993f2011-08-30 18:25:55 +0530947 default:
948 pr_err("%s: Un-supported transport transport: %u\n",
949 __func__, gserial_ports[port_num].transport);
950 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951 }
952
Manu Gautama4d993f2011-08-30 18:25:55 +0530953 nr_ports++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954
955 return 0;
956}