blob: aaacd4375cb73544e6868b65fb93889c43d40c98 [file] [log] [blame]
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +02001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Anna Perela8c991d2012-04-09 16:44:46 +03002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/device.h>
18
19#include <linux/usb/cdc.h>
20
21#include <linux/usb/composite.h>
Anna Perela8c991d2012-04-09 16:44:46 +030022#include <linux/platform_device.h>
23
24#include <linux/spinlock.h>
25
26/*
27 * This function is a "Mobile Broadband Interface Model" (MBIM) link.
28 * MBIM is intended to be used with high-speed network attachments.
29 *
30 * Note that MBIM requires the use of "alternate settings" for its data
31 * interface. This means that the set_alt() method has real work to do,
32 * and also means that a get_alt() method is required.
33 */
34
35#define MBIM_BULK_BUFFER_SIZE 4096
36
37#define MBIM_IOCTL_MAGIC 'o'
38#define MBIM_GET_NTB_SIZE _IOR(MBIM_IOCTL_MAGIC, 2, u32)
39#define MBIM_GET_DATAGRAM_COUNT _IOR(MBIM_IOCTL_MAGIC, 3, u16)
40
41#define NR_MBIM_PORTS 1
42
Jack Pham2df2f702012-10-11 19:08:24 -070043/* ID for Microsoft OS String */
44#define MBIM_OS_STRING_ID 0xEE
45
Anna Perela8c991d2012-04-09 16:44:46 +030046struct ctrl_pkt {
47 void *buf;
48 int len;
49 struct list_head list;
50};
51
52struct mbim_ep_descs {
53 struct usb_endpoint_descriptor *in;
54 struct usb_endpoint_descriptor *out;
55 struct usb_endpoint_descriptor *notify;
56};
57
58struct mbim_notify_port {
59 struct usb_ep *notify;
60 struct usb_request *notify_req;
61 u8 notify_state;
62 atomic_t notify_count;
63};
64
65enum mbim_notify_state {
Vamsi Krishna2aae5532013-05-22 12:11:51 -070066 MBIM_NOTIFY_NONE,
67 MBIM_NOTIFY_CONNECT,
68 MBIM_NOTIFY_SPEED,
69 MBIM_NOTIFY_RESPONSE_AVAILABLE,
Anna Perela8c991d2012-04-09 16:44:46 +030070};
71
72struct f_mbim {
Anna Perel557bf722012-09-20 11:16:35 +030073 struct usb_function function;
74 struct usb_composite_dev *cdev;
Anna Perela8c991d2012-04-09 16:44:46 +030075
76 atomic_t online;
77 bool is_open;
78
79 atomic_t open_excl;
80 atomic_t ioctl_excl;
81 atomic_t read_excl;
82 atomic_t write_excl;
83
84 wait_queue_head_t read_wq;
85 wait_queue_head_t write_wq;
86
Lena Salmandf7e7992013-03-15 09:46:27 +020087 enum transport_type xport;
Anna Perela8c991d2012-04-09 16:44:46 +030088 u8 port_num;
89 struct data_port bam_port;
90 struct mbim_notify_port not_port;
91
92 struct mbim_ep_descs fs;
93 struct mbim_ep_descs hs;
94
95 u8 ctrl_id, data_id;
Bar Weinerb1c95f52012-12-23 09:09:13 +020096 u8 data_alt_int;
Anna Perela8c991d2012-04-09 16:44:46 +030097
Vamsi Krishna2aae5532013-05-22 12:11:51 -070098 struct mbim_ndp_parser_opts *parser_opts;
Anna Perela8c991d2012-04-09 16:44:46 +030099
100 spinlock_t lock;
101
102 struct list_head cpkt_req_q;
103 struct list_head cpkt_resp_q;
104
105 u32 ntb_input_size;
106 u16 ntb_max_datagrams;
107
Anna Perela8c991d2012-04-09 16:44:46 +0300108 atomic_t error;
109};
110
111struct mbim_ntb_input_size {
112 u32 ntb_input_size;
113 u16 ntb_max_datagrams;
114 u16 reserved;
115};
116
117/* temporary variable used between mbim_open() and mbim_gadget_bind() */
118static struct f_mbim *_mbim_dev;
119
120static unsigned int nr_mbim_ports;
121
122static struct mbim_ports {
123 struct f_mbim *port;
124 unsigned port_num;
125} mbim_ports[NR_MBIM_PORTS];
126
127static inline struct f_mbim *func_to_mbim(struct usb_function *f)
128{
129 return container_of(f, struct f_mbim, function);
130}
131
132/* peak (theoretical) bulk transfer rate in bits-per-second */
133static inline unsigned mbim_bitrate(struct usb_gadget *g)
134{
135 if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
136 return 13 * 512 * 8 * 1000 * 8;
137 else
138 return 19 * 64 * 1 * 1000 * 8;
139}
140
141/*-------------------------------------------------------------------------*/
142
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700143#define MBIM_NTB_DEFAULT_IN_SIZE (0x4000)
144#define MBIM_NTB_OUT_SIZE (0x1000)
145#define MBIM_NDP_IN_DIVISOR (0x4)
Anna Perela8c991d2012-04-09 16:44:46 +0300146
Lena Salmandf7e7992013-03-15 09:46:27 +0200147#define NTB_DEFAULT_IN_SIZE_IPA (0x2000)
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700148#define MBIM_NTB_OUT_SIZE_IPA (0x2000)
Lena Salmandf7e7992013-03-15 09:46:27 +0200149
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700150#define MBIM_FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
Anna Perela8c991d2012-04-09 16:44:46 +0300151
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700152static struct usb_cdc_ncm_ntb_parameters mbim_ntb_parameters = {
153 .wLength = sizeof mbim_ntb_parameters,
154 .bmNtbFormatsSupported = cpu_to_le16(MBIM_FORMATS_SUPPORTED),
155 .dwNtbInMaxSize = cpu_to_le32(MBIM_NTB_DEFAULT_IN_SIZE),
156 .wNdpInDivisor = cpu_to_le16(MBIM_NDP_IN_DIVISOR),
Anna Perela8c991d2012-04-09 16:44:46 +0300157 .wNdpInPayloadRemainder = cpu_to_le16(0),
158 .wNdpInAlignment = cpu_to_le16(4),
159
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700160 .dwNtbOutMaxSize = cpu_to_le32(MBIM_NTB_OUT_SIZE),
Anna Perela8c991d2012-04-09 16:44:46 +0300161 .wNdpOutDivisor = cpu_to_le16(4),
162 .wNdpOutPayloadRemainder = cpu_to_le16(0),
163 .wNdpOutAlignment = cpu_to_le16(4),
Anna Perelf99cd0c2012-05-03 13:30:26 +0300164 .wNtbOutMaxDatagrams = 0,
Anna Perela8c991d2012-04-09 16:44:46 +0300165};
166
167/*
168 * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
169 * packet, to simplify cancellation; and a big transfer interval, to
170 * waste less bandwidth.
171 */
172
173#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
174#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
175
176static struct usb_interface_assoc_descriptor mbim_iad_desc = {
177 .bLength = sizeof mbim_iad_desc,
178 .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
179
180 /* .bFirstInterface = DYNAMIC, */
181 .bInterfaceCount = 2, /* control + data */
182 .bFunctionClass = 2,
183 .bFunctionSubClass = 0x0e,
184 .bFunctionProtocol = 0,
185 /* .iFunction = DYNAMIC */
186};
187
188/* interface descriptor: */
189static struct usb_interface_descriptor mbim_control_intf = {
190 .bLength = sizeof mbim_control_intf,
191 .bDescriptorType = USB_DT_INTERFACE,
192
193 /* .bInterfaceNumber = DYNAMIC */
194 .bNumEndpoints = 1,
195 .bInterfaceClass = 0x02,
196 .bInterfaceSubClass = 0x0e,
197 .bInterfaceProtocol = 0,
198 /* .iInterface = DYNAMIC */
199};
200
201static struct usb_cdc_header_desc mbim_header_desc = {
202 .bLength = sizeof mbim_header_desc,
203 .bDescriptorType = USB_DT_CS_INTERFACE,
204 .bDescriptorSubType = USB_CDC_HEADER_TYPE,
205
206 .bcdCDC = cpu_to_le16(0x0110),
207};
208
209static struct usb_cdc_union_desc mbim_union_desc = {
210 .bLength = sizeof(mbim_union_desc),
211 .bDescriptorType = USB_DT_CS_INTERFACE,
212 .bDescriptorSubType = USB_CDC_UNION_TYPE,
213 /* .bMasterInterface0 = DYNAMIC */
214 /* .bSlaveInterface0 = DYNAMIC */
215};
216
217static struct usb_cdc_mbb_desc mbb_desc = {
218 .bLength = sizeof mbb_desc,
219 .bDescriptorType = USB_DT_CS_INTERFACE,
220 .bDescriptorSubType = USB_CDC_MBB_TYPE,
221
222 .bcdMbbVersion = cpu_to_le16(0x0100),
223
224 .wMaxControlMessage = cpu_to_le16(0x1000),
Anna Perel3354bdc2012-12-09 12:08:10 +0200225 .bNumberFilters = 0x20,
Anna Perela8c991d2012-04-09 16:44:46 +0300226 .bMaxFilterSize = 0x80,
Anna Perel26ae27c2012-05-23 18:07:31 +0300227 .wMaxSegmentSize = cpu_to_le16(0xfe0),
Anna Perela8c991d2012-04-09 16:44:46 +0300228 .bmNetworkCapabilities = 0x20,
229};
230
Bar Weiner38c3e642013-02-12 10:25:17 +0200231static struct usb_cdc_ext_mbb_desc ext_mbb_desc = {
232 .bLength = sizeof ext_mbb_desc,
233 .bDescriptorType = USB_DT_CS_INTERFACE,
234 .bDescriptorSubType = USB_CDC_EXT_MBB_TYPE,
235
236 .bcdMbbExtendedVersion = cpu_to_le16(0x0100),
237 .bMaxOutstandingCmdMsges = 64,
238 .wMTU = 1500,
239};
240
Anna Perela8c991d2012-04-09 16:44:46 +0300241/* the default data interface has no endpoints ... */
242static struct usb_interface_descriptor mbim_data_nop_intf = {
243 .bLength = sizeof mbim_data_nop_intf,
244 .bDescriptorType = USB_DT_INTERFACE,
245
246 /* .bInterfaceNumber = DYNAMIC */
247 .bAlternateSetting = 0,
248 .bNumEndpoints = 0,
249 .bInterfaceClass = 0x0a,
250 .bInterfaceSubClass = 0,
251 .bInterfaceProtocol = 0x02,
252 /* .iInterface = DYNAMIC */
253};
254
255/* ... but the "real" data interface has two bulk endpoints */
256static struct usb_interface_descriptor mbim_data_intf = {
257 .bLength = sizeof mbim_data_intf,
258 .bDescriptorType = USB_DT_INTERFACE,
259
260 /* .bInterfaceNumber = DYNAMIC */
261 .bAlternateSetting = 1,
262 .bNumEndpoints = 2,
263 .bInterfaceClass = 0x0a,
264 .bInterfaceSubClass = 0,
265 .bInterfaceProtocol = 0x02,
266 /* .iInterface = DYNAMIC */
267};
268
269/* full speed support: */
270
271static struct usb_endpoint_descriptor fs_mbim_notify_desc = {
272 .bLength = USB_DT_ENDPOINT_SIZE,
273 .bDescriptorType = USB_DT_ENDPOINT,
274
275 .bEndpointAddress = USB_DIR_IN,
276 .bmAttributes = USB_ENDPOINT_XFER_INT,
277 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
278 .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
279};
280
281static struct usb_endpoint_descriptor fs_mbim_in_desc = {
282 .bLength = USB_DT_ENDPOINT_SIZE,
283 .bDescriptorType = USB_DT_ENDPOINT,
284
285 .bEndpointAddress = USB_DIR_IN,
286 .bmAttributes = USB_ENDPOINT_XFER_BULK,
287};
288
289static struct usb_endpoint_descriptor fs_mbim_out_desc = {
290 .bLength = USB_DT_ENDPOINT_SIZE,
291 .bDescriptorType = USB_DT_ENDPOINT,
292
293 .bEndpointAddress = USB_DIR_OUT,
294 .bmAttributes = USB_ENDPOINT_XFER_BULK,
295};
296
297static struct usb_descriptor_header *mbim_fs_function[] = {
298 (struct usb_descriptor_header *) &mbim_iad_desc,
299 /* MBIM control descriptors */
300 (struct usb_descriptor_header *) &mbim_control_intf,
301 (struct usb_descriptor_header *) &mbim_header_desc,
Anna Perel555a7b22013-02-26 13:14:32 +0200302 (struct usb_descriptor_header *) &mbim_union_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300303 (struct usb_descriptor_header *) &mbb_desc,
Bar Weiner38c3e642013-02-12 10:25:17 +0200304 (struct usb_descriptor_header *) &ext_mbb_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300305 (struct usb_descriptor_header *) &fs_mbim_notify_desc,
306 /* data interface, altsettings 0 and 1 */
307 (struct usb_descriptor_header *) &mbim_data_nop_intf,
308 (struct usb_descriptor_header *) &mbim_data_intf,
309 (struct usb_descriptor_header *) &fs_mbim_in_desc,
310 (struct usb_descriptor_header *) &fs_mbim_out_desc,
311 NULL,
312};
313
314/* high speed support: */
315
316static struct usb_endpoint_descriptor hs_mbim_notify_desc = {
317 .bLength = USB_DT_ENDPOINT_SIZE,
318 .bDescriptorType = USB_DT_ENDPOINT,
319
320 .bEndpointAddress = USB_DIR_IN,
321 .bmAttributes = USB_ENDPOINT_XFER_INT,
322 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
323 .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
324};
325static struct usb_endpoint_descriptor hs_mbim_in_desc = {
326 .bLength = USB_DT_ENDPOINT_SIZE,
327 .bDescriptorType = USB_DT_ENDPOINT,
328
329 .bEndpointAddress = USB_DIR_IN,
330 .bmAttributes = USB_ENDPOINT_XFER_BULK,
331 .wMaxPacketSize = cpu_to_le16(512),
332};
333
334static struct usb_endpoint_descriptor hs_mbim_out_desc = {
335 .bLength = USB_DT_ENDPOINT_SIZE,
336 .bDescriptorType = USB_DT_ENDPOINT,
337
338 .bEndpointAddress = USB_DIR_OUT,
339 .bmAttributes = USB_ENDPOINT_XFER_BULK,
340 .wMaxPacketSize = cpu_to_le16(512),
341};
342
343static struct usb_descriptor_header *mbim_hs_function[] = {
344 (struct usb_descriptor_header *) &mbim_iad_desc,
345 /* MBIM control descriptors */
346 (struct usb_descriptor_header *) &mbim_control_intf,
347 (struct usb_descriptor_header *) &mbim_header_desc,
Amit Blayfa105432013-03-27 15:46:08 +0200348 (struct usb_descriptor_header *) &mbim_union_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300349 (struct usb_descriptor_header *) &mbb_desc,
Bar Weiner38c3e642013-02-12 10:25:17 +0200350 (struct usb_descriptor_header *) &ext_mbb_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300351 (struct usb_descriptor_header *) &hs_mbim_notify_desc,
352 /* data interface, altsettings 0 and 1 */
353 (struct usb_descriptor_header *) &mbim_data_nop_intf,
354 (struct usb_descriptor_header *) &mbim_data_intf,
355 (struct usb_descriptor_header *) &hs_mbim_in_desc,
356 (struct usb_descriptor_header *) &hs_mbim_out_desc,
357 NULL,
358};
359
360/* string descriptors: */
361
362#define STRING_CTRL_IDX 0
363#define STRING_DATA_IDX 1
364
365static struct usb_string mbim_string_defs[] = {
366 [STRING_CTRL_IDX].s = "MBIM Control",
367 [STRING_DATA_IDX].s = "MBIM Data",
368 { } /* end of list */
369};
370
371static struct usb_gadget_strings mbim_string_table = {
372 .language = 0x0409, /* en-us */
373 .strings = mbim_string_defs,
374};
375
376static struct usb_gadget_strings *mbim_strings[] = {
377 &mbim_string_table,
378 NULL,
379};
380
Jack Pham2df2f702012-10-11 19:08:24 -0700381/* Microsoft OS Descriptors */
382
383/*
384 * We specify our own bMS_VendorCode byte which Windows will use
385 * as the bRequest value in subsequent device get requests.
386 */
387#define MBIM_VENDOR_CODE 0xA5
388
389/* Microsoft OS String */
390static u8 mbim_os_string[] = {
391 18, /* sizeof(mtp_os_string) */
392 USB_DT_STRING,
393 /* Signature field: "MSFT100" */
394 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
395 /* vendor code */
396 MBIM_VENDOR_CODE,
397 /* padding */
398 0
399};
400
401/* Microsoft Extended Configuration Descriptor Header Section */
402struct mbim_ext_config_desc_header {
403 __le32 dwLength;
404 __u16 bcdVersion;
405 __le16 wIndex;
406 __u8 bCount;
407 __u8 reserved[7];
408};
409
410/* Microsoft Extended Configuration Descriptor Function Section */
411struct mbim_ext_config_desc_function {
412 __u8 bFirstInterfaceNumber;
413 __u8 bInterfaceCount;
414 __u8 compatibleID[8];
415 __u8 subCompatibleID[8];
416 __u8 reserved[6];
417};
418
419/* Microsoft Extended Configuration Descriptor */
420static struct {
421 struct mbim_ext_config_desc_header header;
422 struct mbim_ext_config_desc_function function;
423} mbim_ext_config_desc = {
424 .header = {
425 .dwLength = __constant_cpu_to_le32(sizeof mbim_ext_config_desc),
426 .bcdVersion = __constant_cpu_to_le16(0x0100),
427 .wIndex = __constant_cpu_to_le16(4),
428 .bCount = 1,
429 },
430 .function = {
431 .bFirstInterfaceNumber = 0,
432 .bInterfaceCount = 1,
433 .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' },
434 /* .subCompatibleID = DYNAMIC */
435 },
436};
437
Anna Perela8c991d2012-04-09 16:44:46 +0300438/*
439 * Here are options for the Datagram Pointer table (NDP) parser.
440 * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
441 * in NDP16 offsets and sizes fields are 1 16bit word wide,
442 * in NDP32 -- 2 16bit words wide. Also signatures are different.
443 * To make the parser code the same, put the differences in the structure,
444 * and switch pointers to the structures when the format is changed.
445 */
446
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700447struct mbim_ndp_parser_opts {
Anna Perela8c991d2012-04-09 16:44:46 +0300448 u32 nth_sign;
449 u32 ndp_sign;
450 unsigned nth_size;
451 unsigned ndp_size;
452 unsigned ndplen_align;
453 /* sizes in u16 units */
454 unsigned dgram_item_len; /* index or length */
455 unsigned block_length;
456 unsigned fp_index;
457 unsigned reserved1;
458 unsigned reserved2;
459 unsigned next_fp_index;
460};
461
462#define INIT_NDP16_OPTS { \
463 .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
464 .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
465 .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
466 .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
467 .ndplen_align = 4, \
468 .dgram_item_len = 1, \
469 .block_length = 1, \
470 .fp_index = 1, \
471 .reserved1 = 0, \
472 .reserved2 = 0, \
473 .next_fp_index = 1, \
474}
475
476#define INIT_NDP32_OPTS { \
477 .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
478 .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
479 .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
480 .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
481 .ndplen_align = 8, \
482 .dgram_item_len = 2, \
483 .block_length = 2, \
484 .fp_index = 2, \
485 .reserved1 = 1, \
486 .reserved2 = 2, \
487 .next_fp_index = 2, \
488}
489
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700490static struct mbim_ndp_parser_opts mbim_ndp16_opts = INIT_NDP16_OPTS;
491static struct mbim_ndp_parser_opts mbim_ndp32_opts = INIT_NDP32_OPTS;
Anna Perela8c991d2012-04-09 16:44:46 +0300492
493static inline int mbim_lock(atomic_t *excl)
494{
495 if (atomic_inc_return(excl) == 1) {
496 return 0;
497 } else {
498 atomic_dec(excl);
499 return -EBUSY;
500 }
501}
502
503static inline void mbim_unlock(atomic_t *excl)
504{
505 atomic_dec(excl);
506}
507
508static struct ctrl_pkt *mbim_alloc_ctrl_pkt(unsigned len, gfp_t flags)
509{
510 struct ctrl_pkt *pkt;
511
512 pkt = kzalloc(sizeof(struct ctrl_pkt), flags);
513 if (!pkt)
514 return ERR_PTR(-ENOMEM);
515
516 pkt->buf = kmalloc(len, flags);
517 if (!pkt->buf) {
518 kfree(pkt);
519 return ERR_PTR(-ENOMEM);
520 }
521 pkt->len = len;
522
523 return pkt;
524}
525
526static void mbim_free_ctrl_pkt(struct ctrl_pkt *pkt)
527{
528 if (pkt) {
529 kfree(pkt->buf);
530 kfree(pkt);
531 }
532}
533
534static struct usb_request *mbim_alloc_req(struct usb_ep *ep, int buffer_size)
535{
536 struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
537 if (!req)
538 return NULL;
539
540 req->buf = kmalloc(buffer_size, GFP_KERNEL);
541 if (!req->buf) {
542 usb_ep_free_request(ep, req);
543 return NULL;
544 }
545 req->length = buffer_size;
546 return req;
547}
548
549void fmbim_free_req(struct usb_ep *ep, struct usb_request *req)
550{
551 if (req) {
552 kfree(req->buf);
553 usb_ep_free_request(ep, req);
554 }
555}
556
557static void fmbim_ctrl_response_available(struct f_mbim *dev)
558{
559 struct usb_request *req = dev->not_port.notify_req;
560 struct usb_cdc_notification *event = NULL;
561 unsigned long flags;
562 int ret;
563
Anna Perel68aeb172012-10-28 09:00:45 +0200564 pr_debug("dev:%p portno#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300565
566 spin_lock_irqsave(&dev->lock, flags);
567
568 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200569 pr_err("dev:%p is not online\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300570 spin_unlock_irqrestore(&dev->lock, flags);
571 return;
572 }
573
574 if (!req) {
Anna Perel20c91152012-10-30 16:26:44 +0200575 pr_err("dev:%p req is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300576 spin_unlock_irqrestore(&dev->lock, flags);
577 return;
578 }
579
580 if (!req->buf) {
Anna Perel20c91152012-10-30 16:26:44 +0200581 pr_err("dev:%p req->buf is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300582 spin_unlock_irqrestore(&dev->lock, flags);
583 return;
584 }
585
Anna Perel68aeb172012-10-28 09:00:45 +0200586 if (atomic_inc_return(&dev->not_port.notify_count) != 1) {
587 pr_debug("delay ep_queue: notifications queue is busy[%d]",
588 atomic_read(&dev->not_port.notify_count));
589 spin_unlock_irqrestore(&dev->lock, flags);
590 return;
591 }
Anna Perela8c991d2012-04-09 16:44:46 +0300592
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200593 req->length = sizeof *event;
Anna Perela8c991d2012-04-09 16:44:46 +0300594 event = req->buf;
595 event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
596 | USB_RECIP_INTERFACE;
597 event->bNotificationType = USB_CDC_NOTIFY_RESPONSE_AVAILABLE;
598 event->wValue = cpu_to_le16(0);
599 event->wIndex = cpu_to_le16(dev->ctrl_id);
600 event->wLength = cpu_to_le16(0);
601 spin_unlock_irqrestore(&dev->lock, flags);
602
Anna Perela8c991d2012-04-09 16:44:46 +0300603 ret = usb_ep_queue(dev->not_port.notify,
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200604 req, GFP_ATOMIC);
Anna Perela8c991d2012-04-09 16:44:46 +0300605 if (ret) {
606 atomic_dec(&dev->not_port.notify_count);
607 pr_err("ep enqueue error %d\n", ret);
608 }
609
Anna Perel68aeb172012-10-28 09:00:45 +0200610 pr_debug("Successful Exit");
Anna Perela8c991d2012-04-09 16:44:46 +0300611}
612
613static int
614fmbim_send_cpkt_response(struct f_mbim *gr, struct ctrl_pkt *cpkt)
615{
616 struct f_mbim *dev = gr;
617 unsigned long flags;
618
619 if (!gr || !cpkt) {
620 pr_err("Invalid cpkt, dev:%p cpkt:%p\n",
621 gr, cpkt);
622 return -ENODEV;
623 }
624
Anna Perel20c91152012-10-30 16:26:44 +0200625 pr_debug("dev:%p port_num#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300626
627 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200628 pr_err("dev:%p is not connected\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300629 mbim_free_ctrl_pkt(cpkt);
630 return 0;
631 }
632
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700633 if (dev->not_port.notify_state != MBIM_NOTIFY_RESPONSE_AVAILABLE) {
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200634 pr_err("dev:%p state=%d, recover!!\n", dev,
635 dev->not_port.notify_state);
636 mbim_free_ctrl_pkt(cpkt);
637 return 0;
638 }
639
Anna Perela8c991d2012-04-09 16:44:46 +0300640 spin_lock_irqsave(&dev->lock, flags);
Anna Perel40c550c2012-04-11 14:09:27 +0300641 list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
Anna Perela8c991d2012-04-09 16:44:46 +0300642 spin_unlock_irqrestore(&dev->lock, flags);
643
644 fmbim_ctrl_response_available(dev);
645
646 return 0;
647}
648
649/* ---------------------------- BAM INTERFACE ----------------------------- */
650
651static int mbim_bam_setup(int no_ports)
652{
653 int ret;
654
655 pr_info("no_ports:%d\n", no_ports);
656
657 ret = bam_data_setup(no_ports);
658 if (ret) {
659 pr_err("bam_data_setup failed err: %d\n", ret);
660 return ret;
661 }
662
663 pr_info("Initialized %d ports\n", no_ports);
664 return 0;
665}
666
Lena Salmandf7e7992013-03-15 09:46:27 +0200667int mbim_configure_params(void)
668{
669 struct teth_aggr_params aggr_params;
670 int ret = 0;
671
672 aggr_params.dl.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700673 aggr_params.dl.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
674 aggr_params.dl.max_transfer_size_byte =
675 mbim_ntb_parameters.dwNtbInMaxSize;
Lena Salmandf7e7992013-03-15 09:46:27 +0200676
677 aggr_params.ul.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700678 aggr_params.ul.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
679 aggr_params.ul.max_transfer_size_byte =
680 mbim_ntb_parameters.dwNtbOutMaxSize;
Lena Salmandf7e7992013-03-15 09:46:27 +0200681
682 ret = teth_bridge_set_aggr_params(&aggr_params);
683 if (ret)
684 pr_err("%s: teth_bridge_set_aggr_params failed\n", __func__);
685
686 return ret;
687}
688
Anna Perela8c991d2012-04-09 16:44:46 +0300689static int mbim_bam_connect(struct f_mbim *dev)
690{
691 int ret;
Shimrit Malichidbf43d72013-03-16 03:32:27 +0200692 u8 src_connection_idx, dst_connection_idx;
693 struct usb_gadget *gadget = dev->cdev->gadget;
Lena Salmandf7e7992013-03-15 09:46:27 +0200694 enum peer_bam bam_name = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
695 IPA_P_BAM : A2_P_BAM;
Anna Perela8c991d2012-04-09 16:44:46 +0300696
697 pr_info("dev:%p portno:%d\n", dev, dev->port_num);
698
Lena Salmandf7e7992013-03-15 09:46:27 +0200699 src_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
700 USB_TO_PEER_PERIPHERAL, dev->port_num);
701 dst_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
702 PEER_PERIPHERAL_TO_USB, dev->port_num);
Shimrit Malichidbf43d72013-03-16 03:32:27 +0200703 if (src_connection_idx < 0 || dst_connection_idx < 0) {
704 pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
705 return ret;
706 }
707
Amit Blayf9b352b2013-03-04 15:01:40 +0200708 ret = bam_data_connect(&dev->bam_port, dev->port_num,
Lena Salmandf7e7992013-03-15 09:46:27 +0200709 dev->xport, src_connection_idx, dst_connection_idx,
710 USB_FUNC_MBIM);
711
Anna Perela8c991d2012-04-09 16:44:46 +0300712 if (ret) {
713 pr_err("bam_data_setup failed: err:%d\n",
714 ret);
715 return ret;
Anna Perela8c991d2012-04-09 16:44:46 +0300716 }
717
Shimrit Malichidbf43d72013-03-16 03:32:27 +0200718 pr_info("mbim bam connected\n");
Anna Perela8c991d2012-04-09 16:44:46 +0300719 return 0;
720}
721
722static int mbim_bam_disconnect(struct f_mbim *dev)
723{
724 pr_info("dev:%p port:%d. Do nothing.\n",
725 dev, dev->port_num);
726
Amit Blay51bebe92012-12-25 18:48:10 +0200727 bam_data_disconnect(&dev->bam_port, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300728
729 return 0;
730}
731
732/* -------------------------------------------------------------------------*/
733
734static inline void mbim_reset_values(struct f_mbim *mbim)
735{
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700736 mbim->parser_opts = &mbim_ndp16_opts;
Anna Perela8c991d2012-04-09 16:44:46 +0300737
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700738 mbim->ntb_input_size = MBIM_NTB_DEFAULT_IN_SIZE;
Anna Perela8c991d2012-04-09 16:44:46 +0300739
Anna Perela8c991d2012-04-09 16:44:46 +0300740 atomic_set(&mbim->online, 0);
741}
742
Anna Perel86ea7c92012-04-24 14:31:29 +0300743static void mbim_reset_function_queue(struct f_mbim *dev)
744{
745 struct ctrl_pkt *cpkt = NULL;
746
747 pr_debug("Queue empty packet for QBI");
748
749 spin_lock(&dev->lock);
750 if (!dev->is_open) {
751 pr_err("%s: mbim file handler %p is not open", __func__, dev);
752 spin_unlock(&dev->lock);
753 return;
754 }
755
756 cpkt = mbim_alloc_ctrl_pkt(0, GFP_ATOMIC);
757 if (!cpkt) {
758 pr_err("%s: Unable to allocate reset function pkt\n", __func__);
759 spin_unlock(&dev->lock);
760 return;
761 }
762
763 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
764 spin_unlock(&dev->lock);
765
766 pr_debug("%s: Wake up read queue", __func__);
767 wake_up(&dev->read_wq);
768}
769
770static void fmbim_reset_cmd_complete(struct usb_ep *ep, struct usb_request *req)
771{
772 struct f_mbim *dev = req->context;
773
774 mbim_reset_function_queue(dev);
775}
776
777static void mbim_clear_queues(struct f_mbim *mbim)
778{
779 struct ctrl_pkt *cpkt = NULL;
780 struct list_head *act, *tmp;
781
782 spin_lock(&mbim->lock);
783 list_for_each_safe(act, tmp, &mbim->cpkt_req_q) {
784 cpkt = list_entry(act, struct ctrl_pkt, list);
785 list_del(&cpkt->list);
786 mbim_free_ctrl_pkt(cpkt);
787 }
788 list_for_each_safe(act, tmp, &mbim->cpkt_resp_q) {
789 cpkt = list_entry(act, struct ctrl_pkt, list);
790 list_del(&cpkt->list);
791 mbim_free_ctrl_pkt(cpkt);
792 }
793 spin_unlock(&mbim->lock);
794}
795
Anna Perela8c991d2012-04-09 16:44:46 +0300796/*
797 * Context: mbim->lock held
798 */
799static void mbim_do_notify(struct f_mbim *mbim)
800{
801 struct usb_request *req = mbim->not_port.notify_req;
802 struct usb_cdc_notification *event;
Anna Perela8c991d2012-04-09 16:44:46 +0300803 int status;
804
Anna Perel20c91152012-10-30 16:26:44 +0200805 pr_debug("notify_state: %d", mbim->not_port.notify_state);
Anna Perela8c991d2012-04-09 16:44:46 +0300806
807 if (!req)
808 return;
809
810 event = req->buf;
811
812 switch (mbim->not_port.notify_state) {
813
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700814 case MBIM_NOTIFY_NONE:
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200815 if (atomic_read(&mbim->not_port.notify_count) > 0)
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700816 pr_err("Pending notifications in MBIM_NOTIFY_NONE\n");
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200817 else
818 pr_debug("No pending notifications\n");
819
820 return;
821
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700822 case MBIM_NOTIFY_RESPONSE_AVAILABLE:
Anna Perel68aeb172012-10-28 09:00:45 +0200823 pr_debug("Notification %02x sent\n", event->bNotificationType);
824
825 if (atomic_read(&mbim->not_port.notify_count) <= 0) {
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200826 pr_debug("notify_response_avaliable: done");
Anna Perel68aeb172012-10-28 09:00:45 +0200827 return;
828 }
829
830 spin_unlock(&mbim->lock);
831 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
832 spin_lock(&mbim->lock);
833 if (status) {
834 atomic_dec(&mbim->not_port.notify_count);
835 pr_err("Queue notify request failed, err: %d", status);
836 }
837
Anna Perela8c991d2012-04-09 16:44:46 +0300838 return;
Anna Perela8c991d2012-04-09 16:44:46 +0300839 }
Anna Perel68aeb172012-10-28 09:00:45 +0200840
Anna Perela8c991d2012-04-09 16:44:46 +0300841 event->bmRequestType = 0xA1;
842 event->wIndex = cpu_to_le16(mbim->ctrl_id);
843
Anna Perela8c991d2012-04-09 16:44:46 +0300844 /*
845 * In double buffering if there is a space in FIFO,
846 * completion callback can be called right after the call,
847 * so unlocking
848 */
Anna Perel68aeb172012-10-28 09:00:45 +0200849 atomic_inc(&mbim->not_port.notify_count);
850 pr_debug("queue request: notify_count = %d",
851 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300852 spin_unlock(&mbim->lock);
853 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
854 spin_lock(&mbim->lock);
Anna Perel68aeb172012-10-28 09:00:45 +0200855 if (status) {
Anna Perela8c991d2012-04-09 16:44:46 +0300856 atomic_dec(&mbim->not_port.notify_count);
857 pr_err("usb_ep_queue failed, err: %d", status);
858 }
859}
860
Anna Perela8c991d2012-04-09 16:44:46 +0300861static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
862{
863 struct f_mbim *mbim = req->context;
864 struct usb_cdc_notification *event = req->buf;
865
Anna Perel68aeb172012-10-28 09:00:45 +0200866 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300867
868 spin_lock(&mbim->lock);
869 switch (req->status) {
870 case 0:
Anna Perel68aeb172012-10-28 09:00:45 +0200871 atomic_dec(&mbim->not_port.notify_count);
872 pr_debug("notify_count = %d",
873 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300874 break;
875
876 case -ECONNRESET:
877 case -ESHUTDOWN:
878 /* connection gone */
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700879 mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
Anna Perela8c991d2012-04-09 16:44:46 +0300880 atomic_set(&mbim->not_port.notify_count, 0);
881 pr_info("ESHUTDOWN/ECONNRESET, connection gone");
Anna Perel86ea7c92012-04-24 14:31:29 +0300882 spin_unlock(&mbim->lock);
883 mbim_clear_queues(mbim);
884 mbim_reset_function_queue(mbim);
Anna Perel89ad1212012-06-13 17:17:24 +0300885 spin_lock(&mbim->lock);
Anna Perela8c991d2012-04-09 16:44:46 +0300886 break;
887 default:
888 pr_err("Unknown event %02x --> %d\n",
889 event->bNotificationType, req->status);
890 break;
891 }
892
Anna Perela8c991d2012-04-09 16:44:46 +0300893 mbim_do_notify(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300894 spin_unlock(&mbim->lock);
895
Anna Perel20c91152012-10-30 16:26:44 +0200896 pr_debug("dev:%p Exit\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300897}
898
899static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
900{
901 /* now for SET_NTB_INPUT_SIZE only */
902 unsigned in_size = 0;
903 struct usb_function *f = req->context;
904 struct f_mbim *mbim = func_to_mbim(f);
905 struct mbim_ntb_input_size *ntb = NULL;
906
Anna Perel20c91152012-10-30 16:26:44 +0200907 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300908
909 req->context = NULL;
910 if (req->status || req->actual != req->length) {
911 pr_err("Bad control-OUT transfer\n");
912 goto invalid;
913 }
914
915 if (req->length == 4) {
916 in_size = get_unaligned_le32(req->buf);
917 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700918 in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
Anna Perela8c991d2012-04-09 16:44:46 +0300919 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
920 goto invalid;
921 }
922 } else if (req->length == 8) {
923 ntb = (struct mbim_ntb_input_size *)req->buf;
924 in_size = get_unaligned_le32(&(ntb->ntb_input_size));
925 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700926 in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
Anna Perela8c991d2012-04-09 16:44:46 +0300927 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
928 goto invalid;
929 }
930 mbim->ntb_max_datagrams =
931 get_unaligned_le16(&(ntb->ntb_max_datagrams));
932 } else {
933 pr_err("Illegal NTB length %d\n", in_size);
934 goto invalid;
935 }
936
Anna Perel20c91152012-10-30 16:26:44 +0200937 pr_debug("Set NTB INPUT SIZE %d\n", in_size);
Anna Perela8c991d2012-04-09 16:44:46 +0300938
939 mbim->ntb_input_size = in_size;
940 return;
941
942invalid:
943 usb_ep_set_halt(ep);
944
945 pr_err("dev:%p Failed\n", mbim);
946
947 return;
948}
949
950static void
951fmbim_cmd_complete(struct usb_ep *ep, struct usb_request *req)
952{
953 struct f_mbim *dev = req->context;
954 struct ctrl_pkt *cpkt = NULL;
955 int len = req->actual;
956
957 if (!dev) {
958 pr_err("mbim dev is null\n");
959 return;
960 }
961
962 if (req->status < 0) {
963 pr_err("mbim command error %d\n", req->status);
964 return;
965 }
966
Anna Perel20c91152012-10-30 16:26:44 +0200967 pr_debug("dev:%p port#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300968
Anna Perela8c991d2012-04-09 16:44:46 +0300969 cpkt = mbim_alloc_ctrl_pkt(len, GFP_ATOMIC);
970 if (!cpkt) {
971 pr_err("Unable to allocate ctrl pkt\n");
Anna Perela8c991d2012-04-09 16:44:46 +0300972 return;
973 }
974
Anna Perel20c91152012-10-30 16:26:44 +0200975 pr_debug("Add to cpkt_req_q packet with len = %d\n", len);
Anna Perela8c991d2012-04-09 16:44:46 +0300976 memcpy(cpkt->buf, req->buf, len);
Anna Perel20c91152012-10-30 16:26:44 +0200977
Anna Perel182ab572012-11-18 10:10:12 +0200978 spin_lock(&dev->lock);
979 if (!dev->is_open) {
980 pr_err("mbim file handler %p is not open", dev);
981 spin_unlock(&dev->lock);
982 mbim_free_ctrl_pkt(cpkt);
983 return;
984 }
985
Anna Perela8c991d2012-04-09 16:44:46 +0300986 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
987 spin_unlock(&dev->lock);
988
989 /* wakeup read thread */
Anna Perel20c91152012-10-30 16:26:44 +0200990 pr_debug("Wake up read queue");
Anna Perela8c991d2012-04-09 16:44:46 +0300991 wake_up(&dev->read_wq);
992
993 return;
994}
995
996static int
997mbim_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
998{
999 struct f_mbim *mbim = func_to_mbim(f);
1000 struct usb_composite_dev *cdev = mbim->cdev;
1001 struct usb_request *req = cdev->req;
1002 struct ctrl_pkt *cpkt = NULL;
1003 int value = -EOPNOTSUPP;
1004 u16 w_index = le16_to_cpu(ctrl->wIndex);
1005 u16 w_value = le16_to_cpu(ctrl->wValue);
1006 u16 w_length = le16_to_cpu(ctrl->wLength);
1007
1008 /*
1009 * composite driver infrastructure handles everything except
1010 * CDC class messages; interface activation uses set_alt().
1011 */
1012
1013 if (!atomic_read(&mbim->online)) {
1014 pr_info("usb cable is not connected\n");
1015 return -ENOTCONN;
1016 }
1017
1018 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
1019 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1020 | USB_CDC_RESET_FUNCTION:
1021
Anna Perel20c91152012-10-30 16:26:44 +02001022 pr_debug("USB_CDC_RESET_FUNCTION");
Anna Perela8c991d2012-04-09 16:44:46 +03001023 value = 0;
Anna Perel86ea7c92012-04-24 14:31:29 +03001024 req->complete = fmbim_reset_cmd_complete;
1025 req->context = mbim;
Anna Perela8c991d2012-04-09 16:44:46 +03001026 break;
1027
1028 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1029 | USB_CDC_SEND_ENCAPSULATED_COMMAND:
1030
Anna Perel20c91152012-10-30 16:26:44 +02001031 pr_debug("USB_CDC_SEND_ENCAPSULATED_COMMAND");
Anna Perela8c991d2012-04-09 16:44:46 +03001032
1033 if (w_length > req->length) {
Anna Perel20c91152012-10-30 16:26:44 +02001034 pr_debug("w_length > req->length: %d > %d",
Anna Perela8c991d2012-04-09 16:44:46 +03001035 w_length, req->length);
1036 }
1037 value = w_length;
1038 req->complete = fmbim_cmd_complete;
1039 req->context = mbim;
1040 break;
1041
1042 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1043 | USB_CDC_GET_ENCAPSULATED_RESPONSE:
1044
Anna Perel20c91152012-10-30 16:26:44 +02001045 pr_debug("USB_CDC_GET_ENCAPSULATED_RESPONSE");
Anna Perela8c991d2012-04-09 16:44:46 +03001046
1047 if (w_value) {
1048 pr_err("w_length > 0: %d", w_length);
1049 break;
1050 }
1051
Anna Perel20c91152012-10-30 16:26:44 +02001052 pr_debug("req%02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001053 ctrl->bRequestType, ctrl->bRequest,
1054 w_value, w_index, w_length);
1055
1056 spin_lock(&mbim->lock);
1057 if (list_empty(&mbim->cpkt_resp_q)) {
1058 pr_err("ctrl resp queue empty\n");
1059 spin_unlock(&mbim->lock);
1060 break;
1061 }
1062
1063 cpkt = list_first_entry(&mbim->cpkt_resp_q,
1064 struct ctrl_pkt, list);
1065 list_del(&cpkt->list);
1066 spin_unlock(&mbim->lock);
1067
1068 value = min_t(unsigned, w_length, cpkt->len);
1069 memcpy(req->buf, cpkt->buf, value);
1070 mbim_free_ctrl_pkt(cpkt);
1071
Anna Perel20c91152012-10-30 16:26:44 +02001072 pr_debug("copied encapsulated_response %d bytes",
Anna Perela8c991d2012-04-09 16:44:46 +03001073 value);
1074
1075 break;
1076
1077 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1078 | USB_CDC_GET_NTB_PARAMETERS:
1079
Anna Perel20c91152012-10-30 16:26:44 +02001080 pr_debug("USB_CDC_GET_NTB_PARAMETERS");
Anna Perela8c991d2012-04-09 16:44:46 +03001081
1082 if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
1083 break;
1084
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001085 value = w_length > sizeof mbim_ntb_parameters ?
1086 sizeof mbim_ntb_parameters : w_length;
1087 memcpy(req->buf, &mbim_ntb_parameters, value);
Anna Perela8c991d2012-04-09 16:44:46 +03001088 break;
1089
1090 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1091 | USB_CDC_GET_NTB_INPUT_SIZE:
1092
Anna Perel20c91152012-10-30 16:26:44 +02001093 pr_debug("USB_CDC_GET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001094
1095 if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
1096 break;
1097
1098 put_unaligned_le32(mbim->ntb_input_size, req->buf);
1099 value = 4;
Anna Perel20c91152012-10-30 16:26:44 +02001100 pr_debug("Reply to host INPUT SIZE %d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001101 mbim->ntb_input_size);
1102 break;
1103
1104 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1105 | USB_CDC_SET_NTB_INPUT_SIZE:
1106
Anna Perel20c91152012-10-30 16:26:44 +02001107 pr_debug("USB_CDC_SET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001108
1109 if (w_length != 4 && w_length != 8) {
1110 pr_err("wrong NTB length %d", w_length);
1111 break;
1112 }
1113
1114 if (w_value != 0 || w_index != mbim->ctrl_id)
1115 break;
1116
1117 req->complete = mbim_ep0out_complete;
1118 req->length = w_length;
1119 req->context = f;
1120
1121 value = req->length;
1122 break;
1123
1124 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1125 | USB_CDC_GET_NTB_FORMAT:
1126 {
1127 uint16_t format;
1128
Anna Perel20c91152012-10-30 16:26:44 +02001129 pr_debug("USB_CDC_GET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001130
1131 if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
1132 break;
1133
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001134 format = (mbim->parser_opts == &mbim_ndp16_opts) ? 0 : 1;
Anna Perela8c991d2012-04-09 16:44:46 +03001135 put_unaligned_le16(format, req->buf);
1136 value = 2;
Anna Perel20c91152012-10-30 16:26:44 +02001137 pr_debug("NTB FORMAT: sending %d\n", format);
Anna Perela8c991d2012-04-09 16:44:46 +03001138 break;
1139 }
1140
1141 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1142 | USB_CDC_SET_NTB_FORMAT:
1143 {
Anna Perel20c91152012-10-30 16:26:44 +02001144 pr_debug("USB_CDC_SET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001145
1146 if (w_length != 0 || w_index != mbim->ctrl_id)
1147 break;
1148 switch (w_value) {
1149 case 0x0000:
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001150 mbim->parser_opts = &mbim_ndp16_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001151 pr_debug("NCM16 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001152 break;
1153 case 0x0001:
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001154 mbim->parser_opts = &mbim_ndp32_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001155 pr_debug("NCM32 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001156 break;
1157 default:
1158 break;
1159 }
1160 value = 0;
1161 break;
1162 }
1163
1164 /* optional in mbim descriptor: */
1165 /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
1166 /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
1167
1168 default:
1169 pr_err("invalid control req: %02x.%02x v%04x i%04x l%d\n",
1170 ctrl->bRequestType, ctrl->bRequest,
1171 w_value, w_index, w_length);
1172 }
1173
1174 /* respond with data transfer or status phase? */
1175 if (value >= 0) {
Anna Perel20c91152012-10-30 16:26:44 +02001176 pr_debug("control request: %02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001177 ctrl->bRequestType, ctrl->bRequest,
1178 w_value, w_index, w_length);
Anna Perel2dfcaca2012-04-18 17:25:59 +03001179 req->zero = (value < w_length);
Anna Perela8c991d2012-04-09 16:44:46 +03001180 req->length = value;
1181 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1182 if (value < 0) {
1183 pr_err("queueing req failed: %02x.%02x, err %d\n",
1184 ctrl->bRequestType,
1185 ctrl->bRequest, value);
1186 }
1187 } else {
1188 pr_err("ctrl req err %d: %02x.%02x v%04x i%04x l%d\n",
1189 value, ctrl->bRequestType, ctrl->bRequest,
1190 w_value, w_index, w_length);
1191 }
1192
1193 /* device either stalls (value < 0) or reports success */
1194 return value;
1195}
1196
Jack Pham2df2f702012-10-11 19:08:24 -07001197/*
1198 * This function handles the Microsoft-specific OS descriptor control
1199 * requests that are issued by Windows host drivers to determine the
1200 * configuration containing the MBIM function.
1201 *
1202 * Unlike mbim_setup() this function handles two specific device requests,
1203 * and only when a configuration has not yet been selected.
1204 */
1205static int mbim_ctrlrequest(struct usb_composite_dev *cdev,
1206 const struct usb_ctrlrequest *ctrl)
1207{
1208 int value = -EOPNOTSUPP;
1209 u16 w_index = le16_to_cpu(ctrl->wIndex);
1210 u16 w_value = le16_to_cpu(ctrl->wValue);
1211 u16 w_length = le16_to_cpu(ctrl->wLength);
1212
1213 /* only respond to OS desciptors when no configuration selected */
1214 if (cdev->config || !mbim_ext_config_desc.function.subCompatibleID[0])
1215 return value;
1216
1217 pr_debug("%02x.%02x v%04x i%04x l%u",
1218 ctrl->bRequestType, ctrl->bRequest,
1219 w_value, w_index, w_length);
1220
1221 /* Handle MSFT OS string */
1222 if (ctrl->bRequestType ==
1223 (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
1224 && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
1225 && (w_value >> 8) == USB_DT_STRING
1226 && (w_value & 0xFF) == MBIM_OS_STRING_ID) {
1227
1228 value = (w_length < sizeof(mbim_os_string) ?
1229 w_length : sizeof(mbim_os_string));
1230 memcpy(cdev->req->buf, mbim_os_string, value);
1231
1232 } else if (ctrl->bRequestType ==
1233 (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
1234 && ctrl->bRequest == MBIM_VENDOR_CODE && w_index == 4) {
1235
1236 /* Handle Extended OS descriptor */
1237 value = (w_length < sizeof(mbim_ext_config_desc) ?
1238 w_length : sizeof(mbim_ext_config_desc));
1239 memcpy(cdev->req->buf, &mbim_ext_config_desc, value);
1240 }
1241
1242 /* respond with data transfer or status phase? */
1243 if (value >= 0) {
1244 int rc;
1245 cdev->req->zero = value < w_length;
1246 cdev->req->length = value;
1247 rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
1248 if (rc < 0)
1249 pr_err("response queue error: %d", rc);
1250 }
1251 return value;
1252}
1253
Anna Perela8c991d2012-04-09 16:44:46 +03001254static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
1255{
1256 struct f_mbim *mbim = func_to_mbim(f);
1257 struct usb_composite_dev *cdev = mbim->cdev;
1258 int ret = 0;
1259
1260 /* Control interface has only altsetting 0 */
1261 if (intf == mbim->ctrl_id) {
1262
1263 pr_info("CONTROL_INTERFACE");
1264
1265 if (alt != 0)
1266 goto fail;
1267
1268 if (mbim->not_port.notify->driver_data) {
1269 pr_info("reset mbim control %d\n", intf);
1270 usb_ep_disable(mbim->not_port.notify);
1271 }
1272
1273 ret = config_ep_by_speed(cdev->gadget, f,
1274 mbim->not_port.notify);
1275 if (ret) {
1276 mbim->not_port.notify->desc = NULL;
1277 pr_err("Failed configuring notify ep %s: err %d\n",
1278 mbim->not_port.notify->name, ret);
1279 return ret;
1280 }
1281
1282 ret = usb_ep_enable(mbim->not_port.notify);
1283 if (ret) {
1284 pr_err("usb ep#%s enable failed, err#%d\n",
1285 mbim->not_port.notify->name, ret);
1286 return ret;
1287 }
1288 mbim->not_port.notify->driver_data = mbim;
1289
1290 /* Data interface has two altsettings, 0 and 1 */
1291 } else if (intf == mbim->data_id) {
1292
1293 pr_info("DATA_INTERFACE");
1294
1295 if (alt > 1)
1296 goto fail;
1297
1298 if (mbim->bam_port.in->driver_data) {
1299 pr_info("reset mbim\n");
1300 mbim_reset_values(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001301 }
1302
1303 /*
1304 * CDC Network only sends data in non-default altsettings.
1305 * Changing altsettings resets filters, statistics, etc.
1306 */
1307 if (alt == 1) {
1308 pr_info("Alt set 1, initialize ports");
1309
1310 if (!mbim->bam_port.in->desc) {
1311
1312 pr_info("Choose endpoints");
1313
1314 ret = config_ep_by_speed(cdev->gadget, f,
1315 mbim->bam_port.in);
1316 if (ret) {
1317 mbim->bam_port.in->desc = NULL;
1318 pr_err("IN ep %s failed: %d\n",
1319 mbim->bam_port.in->name, ret);
1320 return ret;
1321 }
1322
1323 pr_info("Set mbim port in_desc = 0x%p",
1324 mbim->bam_port.in->desc);
1325
1326 ret = config_ep_by_speed(cdev->gadget, f,
1327 mbim->bam_port.out);
1328 if (ret) {
1329 mbim->bam_port.out->desc = NULL;
1330 pr_err("OUT ep %s failed: %d\n",
1331 mbim->bam_port.out->name, ret);
1332 return ret;
1333 }
1334
1335 pr_info("Set mbim port out_desc = 0x%p",
1336 mbim->bam_port.out->desc);
Anna Perel6637bd72012-10-23 10:53:32 +02001337
1338 pr_debug("Activate mbim\n");
1339 mbim_bam_connect(mbim);
1340
Anna Perela8c991d2012-04-09 16:44:46 +03001341 } else {
1342 pr_info("PORTS already SET");
1343 }
Anna Perela8c991d2012-04-09 16:44:46 +03001344 }
1345
Bar Weinerb1c95f52012-12-23 09:09:13 +02001346 mbim->data_alt_int = alt;
Anna Perela8c991d2012-04-09 16:44:46 +03001347 spin_lock(&mbim->lock);
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001348 mbim->not_port.notify_state = MBIM_NOTIFY_RESPONSE_AVAILABLE;
Anna Perela8c991d2012-04-09 16:44:46 +03001349 spin_unlock(&mbim->lock);
1350 } else {
1351 goto fail;
1352 }
1353
1354 atomic_set(&mbim->online, 1);
1355
1356 pr_info("SET DEVICE ONLINE");
1357
1358 /* wakeup file threads */
1359 wake_up(&mbim->read_wq);
1360 wake_up(&mbim->write_wq);
1361
1362 return 0;
1363
1364fail:
1365 pr_err("ERROR: Illegal Interface");
1366 return -EINVAL;
1367}
1368
1369/*
1370 * Because the data interface supports multiple altsettings,
1371 * this MBIM function *MUST* implement a get_alt() method.
1372 */
1373static int mbim_get_alt(struct usb_function *f, unsigned intf)
1374{
1375 struct f_mbim *mbim = func_to_mbim(f);
1376
1377 if (intf == mbim->ctrl_id)
1378 return 0;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001379 else if (intf == mbim->data_id)
1380 return mbim->data_alt_int;
1381
1382 return -EINVAL;
Anna Perela8c991d2012-04-09 16:44:46 +03001383}
1384
1385static void mbim_disable(struct usb_function *f)
1386{
1387 struct f_mbim *mbim = func_to_mbim(f);
1388
1389 pr_info("SET DEVICE OFFLINE");
1390 atomic_set(&mbim->online, 0);
1391
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001392 mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +02001393
Anna Perel86ea7c92012-04-24 14:31:29 +03001394 mbim_clear_queues(mbim);
1395 mbim_reset_function_queue(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001396
1397 mbim_bam_disconnect(mbim);
1398
1399 if (mbim->not_port.notify->driver_data) {
1400 usb_ep_disable(mbim->not_port.notify);
1401 mbim->not_port.notify->driver_data = NULL;
1402 }
1403
Anna Perel68aeb172012-10-28 09:00:45 +02001404 atomic_set(&mbim->not_port.notify_count, 0);
1405
Anna Perela8c991d2012-04-09 16:44:46 +03001406 pr_info("mbim deactivated\n");
1407}
1408
Anna Perel557bf722012-09-20 11:16:35 +03001409#define MBIM_ACTIVE_PORT 0
1410
1411static void mbim_suspend(struct usb_function *f)
1412{
1413 pr_info("mbim suspended\n");
1414 bam_data_suspend(MBIM_ACTIVE_PORT);
1415}
1416
1417static void mbim_resume(struct usb_function *f)
1418{
1419 pr_info("mbim resumed\n");
1420 bam_data_resume(MBIM_ACTIVE_PORT);
1421}
1422
Anna Perela8c991d2012-04-09 16:44:46 +03001423/*---------------------- function driver setup/binding ---------------------*/
1424
1425static int
1426mbim_bind(struct usb_configuration *c, struct usb_function *f)
1427{
1428 struct usb_composite_dev *cdev = c->cdev;
1429 struct f_mbim *mbim = func_to_mbim(f);
1430 int status;
1431 struct usb_ep *ep;
1432
1433 pr_info("Enter");
1434
1435 mbim->cdev = cdev;
1436
1437 /* allocate instance-specific interface IDs */
1438 status = usb_interface_id(c, f);
1439 if (status < 0)
1440 goto fail;
1441 mbim->ctrl_id = status;
1442 mbim_iad_desc.bFirstInterface = status;
1443
1444 mbim_control_intf.bInterfaceNumber = status;
1445 mbim_union_desc.bMasterInterface0 = status;
1446
1447 status = usb_interface_id(c, f);
1448 if (status < 0)
1449 goto fail;
1450 mbim->data_id = status;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001451 mbim->data_alt_int = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001452
1453 mbim_data_nop_intf.bInterfaceNumber = status;
1454 mbim_data_intf.bInterfaceNumber = status;
1455 mbim_union_desc.bSlaveInterface0 = status;
1456
Anna Perel557bf722012-09-20 11:16:35 +03001457 mbim->bam_port.cdev = cdev;
1458
Anna Perela8c991d2012-04-09 16:44:46 +03001459 status = -ENODEV;
1460
1461 /* allocate instance-specific endpoints */
1462 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_in_desc);
1463 if (!ep) {
1464 pr_err("usb epin autoconfig failed\n");
1465 goto fail;
1466 }
1467 pr_info("usb epin autoconfig succeeded\n");
1468 ep->driver_data = cdev; /* claim */
1469 mbim->bam_port.in = ep;
1470
1471 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_out_desc);
1472 if (!ep) {
1473 pr_err("usb epout autoconfig failed\n");
1474 goto fail;
1475 }
1476 pr_info("usb epout autoconfig succeeded\n");
1477 ep->driver_data = cdev; /* claim */
1478 mbim->bam_port.out = ep;
1479
1480 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_notify_desc);
1481 if (!ep) {
1482 pr_err("usb notify ep autoconfig failed\n");
1483 goto fail;
1484 }
1485 pr_info("usb notify ep autoconfig succeeded\n");
1486 mbim->not_port.notify = ep;
1487 ep->driver_data = cdev; /* claim */
1488
1489 status = -ENOMEM;
1490
1491 /* allocate notification request and buffer */
1492 mbim->not_port.notify_req = mbim_alloc_req(ep, NCM_STATUS_BYTECOUNT);
1493 if (!mbim->not_port.notify_req) {
1494 pr_info("failed to allocate notify request\n");
1495 goto fail;
1496 }
1497 pr_info("allocated notify ep request & request buffer\n");
1498
1499 mbim->not_port.notify_req->context = mbim;
1500 mbim->not_port.notify_req->complete = mbim_notify_complete;
1501
Anna Perelbb5f1452013-05-22 18:12:40 +03001502 if (mbim->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
1503 mbb_desc.wMaxSegmentSize = cpu_to_le16(0x800);
1504 else
1505 mbb_desc.wMaxSegmentSize = cpu_to_le16(0xfe0);
1506
Anna Perela8c991d2012-04-09 16:44:46 +03001507 /* copy descriptors, and track endpoint copies */
1508 f->descriptors = usb_copy_descriptors(mbim_fs_function);
1509 if (!f->descriptors)
1510 goto fail;
1511
1512 /*
1513 * support all relevant hardware speeds... we expect that when
1514 * hardware is dual speed, all bulk-capable endpoints work at
1515 * both speeds
1516 */
1517 if (gadget_is_dualspeed(c->cdev->gadget)) {
1518 hs_mbim_in_desc.bEndpointAddress =
1519 fs_mbim_in_desc.bEndpointAddress;
1520 hs_mbim_out_desc.bEndpointAddress =
1521 fs_mbim_out_desc.bEndpointAddress;
1522 hs_mbim_notify_desc.bEndpointAddress =
1523 fs_mbim_notify_desc.bEndpointAddress;
1524
1525 /* copy descriptors, and track endpoint copies */
1526 f->hs_descriptors = usb_copy_descriptors(mbim_hs_function);
1527 if (!f->hs_descriptors)
1528 goto fail;
1529 }
1530
Jack Pham2df2f702012-10-11 19:08:24 -07001531 /*
1532 * If MBIM is bound in a config other than the first, tell Windows
1533 * about it by returning the num as a string in the OS descriptor's
1534 * subCompatibleID field. Windows only supports up to config #4.
1535 */
1536 if (c->bConfigurationValue >= 2 && c->bConfigurationValue <= 4) {
1537 pr_debug("MBIM in configuration %d", c->bConfigurationValue);
1538 mbim_ext_config_desc.function.subCompatibleID[0] =
1539 c->bConfigurationValue + '0';
1540 }
1541
Anna Perela8c991d2012-04-09 16:44:46 +03001542 pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
1543 mbim->port_num,
1544 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
1545 mbim->bam_port.in->name, mbim->bam_port.out->name,
1546 mbim->not_port.notify->name);
1547
1548 return 0;
1549
1550fail:
1551 pr_err("%s failed to bind, err %d\n", f->name, status);
1552
1553 if (f->descriptors)
1554 usb_free_descriptors(f->descriptors);
1555
1556 if (mbim->not_port.notify_req) {
1557 kfree(mbim->not_port.notify_req->buf);
1558 usb_ep_free_request(mbim->not_port.notify,
1559 mbim->not_port.notify_req);
1560 }
1561
1562 /* we might as well release our claims on endpoints */
1563 if (mbim->not_port.notify)
1564 mbim->not_port.notify->driver_data = NULL;
1565 if (mbim->bam_port.out)
1566 mbim->bam_port.out->driver_data = NULL;
1567 if (mbim->bam_port.in)
1568 mbim->bam_port.in->driver_data = NULL;
1569
1570 return status;
1571}
1572
1573static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
1574{
1575 struct f_mbim *mbim = func_to_mbim(f);
1576
1577 if (gadget_is_dualspeed(c->cdev->gadget))
1578 usb_free_descriptors(f->hs_descriptors);
1579 usb_free_descriptors(f->descriptors);
1580
1581 kfree(mbim->not_port.notify_req->buf);
1582 usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
Jack Pham2df2f702012-10-11 19:08:24 -07001583
1584 mbim_ext_config_desc.function.subCompatibleID[0] = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001585}
1586
1587/**
1588 * mbim_bind_config - add MBIM link to a configuration
1589 * @c: the configuration to support the network link
1590 * Context: single threaded during gadget setup
1591 * Returns zero on success, else negative errno.
1592 */
Lena Salmandf7e7992013-03-15 09:46:27 +02001593int mbim_bind_config(struct usb_configuration *c, unsigned portno,
1594 char *xport_name)
Anna Perela8c991d2012-04-09 16:44:46 +03001595{
1596 struct f_mbim *mbim = NULL;
1597 int status = 0;
1598
1599 pr_info("port number %u", portno);
1600
1601 if (portno >= nr_mbim_ports) {
1602 pr_err("Can not add port %u. Max ports = %d",
1603 portno, nr_mbim_ports);
1604 return -ENODEV;
1605 }
1606
1607 status = mbim_bam_setup(nr_mbim_ports);
1608 if (status) {
1609 pr_err("bam setup failed");
1610 return status;
1611 }
1612
1613 /* maybe allocate device-global string IDs */
1614 if (mbim_string_defs[0].id == 0) {
1615
1616 /* control interface label */
1617 status = usb_string_id(c->cdev);
1618 if (status < 0)
1619 return status;
1620 mbim_string_defs[STRING_CTRL_IDX].id = status;
1621 mbim_control_intf.iInterface = status;
1622
1623 /* data interface label */
1624 status = usb_string_id(c->cdev);
1625 if (status < 0)
1626 return status;
1627 mbim_string_defs[STRING_DATA_IDX].id = status;
1628 mbim_data_nop_intf.iInterface = status;
1629 mbim_data_intf.iInterface = status;
1630 }
1631
1632 /* allocate and initialize one new instance */
1633 mbim = mbim_ports[0].port;
1634 if (!mbim) {
1635 pr_info("mbim struct not allocated");
1636 return -ENOMEM;
1637 }
1638
1639 mbim->cdev = c->cdev;
1640
Anna Perela8c991d2012-04-09 16:44:46 +03001641 mbim_reset_values(mbim);
1642
1643 mbim->function.name = "usb_mbim";
1644 mbim->function.strings = mbim_strings;
1645 mbim->function.bind = mbim_bind;
1646 mbim->function.unbind = mbim_unbind;
1647 mbim->function.set_alt = mbim_set_alt;
1648 mbim->function.get_alt = mbim_get_alt;
1649 mbim->function.setup = mbim_setup;
1650 mbim->function.disable = mbim_disable;
Anna Perel557bf722012-09-20 11:16:35 +03001651 mbim->function.suspend = mbim_suspend;
1652 mbim->function.resume = mbim_resume;
Lena Salmandf7e7992013-03-15 09:46:27 +02001653 mbim->xport = str_to_xport(xport_name);
1654
1655 if (mbim->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
1656 /* Use BAM2BAM by default if not IPA */
1657 mbim->xport = USB_GADGET_XPORT_BAM2BAM;
1658 } else {
1659 /* For IPA we use limit of 16 */
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001660 mbim_ntb_parameters.wNtbOutMaxDatagrams = 16;
Lena Salmandf7e7992013-03-15 09:46:27 +02001661 /* For IPA this is proven to give maximum throughput */
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001662 mbim_ntb_parameters.dwNtbInMaxSize =
Lena Salmandf7e7992013-03-15 09:46:27 +02001663 cpu_to_le32(NTB_DEFAULT_IN_SIZE_IPA);
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001664 mbim_ntb_parameters.dwNtbOutMaxSize =
1665 cpu_to_le32(MBIM_NTB_OUT_SIZE_IPA);
1666 mbim_ntb_parameters.wNdpInDivisor = 1;
Lena Salmandf7e7992013-03-15 09:46:27 +02001667 }
Anna Perela8c991d2012-04-09 16:44:46 +03001668
1669 INIT_LIST_HEAD(&mbim->cpkt_req_q);
1670 INIT_LIST_HEAD(&mbim->cpkt_resp_q);
1671
1672 status = usb_add_function(c, &mbim->function);
1673
1674 pr_info("Exit status %d", status);
1675
1676 return status;
1677}
1678
1679/* ------------ MBIM DRIVER File Operations API for USER SPACE ------------ */
1680
1681static ssize_t
1682mbim_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
1683{
1684 struct f_mbim *dev = fp->private_data;
1685 struct ctrl_pkt *cpkt = NULL;
1686 int ret = 0;
1687
1688 pr_debug("Enter(%d)\n", count);
1689
1690 if (!dev) {
1691 pr_err("Received NULL mbim pointer\n");
1692 return -ENODEV;
1693 }
1694
1695 if (count > MBIM_BULK_BUFFER_SIZE) {
1696 pr_err("Buffer size is too big %d, should be at most %d\n",
1697 count, MBIM_BULK_BUFFER_SIZE);
1698 return -EINVAL;
1699 }
1700
1701 if (mbim_lock(&dev->read_excl)) {
1702 pr_err("Previous reading is not finished yet\n");
1703 return -EBUSY;
1704 }
1705
1706 /* block until mbim online */
1707 while (!(atomic_read(&dev->online) || atomic_read(&dev->error))) {
1708 pr_err("USB cable not connected. Wait.\n");
1709 ret = wait_event_interruptible(dev->read_wq,
1710 (atomic_read(&dev->online) ||
1711 atomic_read(&dev->error)));
1712 if (ret < 0) {
1713 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001714 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001715 }
1716 }
1717
1718 if (atomic_read(&dev->error)) {
1719 mbim_unlock(&dev->read_excl);
1720 return -EIO;
1721 }
1722
1723 while (list_empty(&dev->cpkt_req_q)) {
Anna Perel3747fdae2013-02-17 15:19:04 +02001724 pr_debug("Requests list is empty. Wait.\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001725 ret = wait_event_interruptible(dev->read_wq,
1726 !list_empty(&dev->cpkt_req_q));
1727 if (ret < 0) {
1728 pr_err("Waiting failed\n");
1729 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001730 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001731 }
1732 pr_debug("Received request packet\n");
1733 }
1734
1735 cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
1736 list);
1737 if (cpkt->len > count) {
1738 mbim_unlock(&dev->read_excl);
1739 pr_err("cpkt size too big:%d > buf size:%d\n",
1740 cpkt->len, count);
1741 return -ENOMEM;
1742 }
1743
1744 pr_debug("cpkt size:%d\n", cpkt->len);
1745
1746 list_del(&cpkt->list);
1747 mbim_unlock(&dev->read_excl);
1748
1749 ret = copy_to_user(buf, cpkt->buf, cpkt->len);
1750 if (ret) {
1751 pr_err("copy_to_user failed: err %d\n", ret);
Anna Perel96eea9d2012-12-09 14:08:04 +02001752 ret = -ENOMEM;
Anna Perela8c991d2012-04-09 16:44:46 +03001753 } else {
1754 pr_debug("copied %d bytes to user\n", cpkt->len);
1755 ret = cpkt->len;
1756 }
1757
1758 mbim_free_ctrl_pkt(cpkt);
1759
1760 return ret;
1761}
1762
1763static ssize_t
1764mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
1765{
1766 struct f_mbim *dev = fp->private_data;
1767 struct ctrl_pkt *cpkt = NULL;
1768 int ret = 0;
1769
1770 pr_debug("Enter(%d)", count);
1771
1772 if (!dev) {
1773 pr_err("Received NULL mbim pointer\n");
1774 return -ENODEV;
1775 }
1776
1777 if (!count) {
1778 pr_err("zero length ctrl pkt\n");
1779 return -ENODEV;
1780 }
1781
1782 if (count > MAX_CTRL_PKT_SIZE) {
1783 pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
1784 count, MAX_CTRL_PKT_SIZE);
1785 return -ENOMEM;
1786 }
1787
1788 if (mbim_lock(&dev->write_excl)) {
1789 pr_err("Previous writing not finished yet\n");
1790 return -EBUSY;
1791 }
1792
1793 if (!atomic_read(&dev->online)) {
1794 pr_err("USB cable not connected\n");
1795 mbim_unlock(&dev->write_excl);
1796 return -EPIPE;
1797 }
1798
1799 cpkt = mbim_alloc_ctrl_pkt(count, GFP_KERNEL);
1800 if (!cpkt) {
1801 pr_err("failed to allocate ctrl pkt\n");
1802 mbim_unlock(&dev->write_excl);
1803 return -ENOMEM;
1804 }
1805
1806 ret = copy_from_user(cpkt->buf, buf, count);
1807 if (ret) {
1808 pr_err("copy_from_user failed err:%d\n", ret);
1809 mbim_free_ctrl_pkt(cpkt);
1810 mbim_unlock(&dev->write_excl);
1811 return 0;
1812 }
1813
1814 fmbim_send_cpkt_response(dev, cpkt);
1815
1816 mbim_unlock(&dev->write_excl);
1817
1818 pr_debug("Exit(%d)", count);
1819
1820 return count;
Anna Perel89ad1212012-06-13 17:17:24 +03001821
Anna Perela8c991d2012-04-09 16:44:46 +03001822}
1823
1824static int mbim_open(struct inode *ip, struct file *fp)
1825{
1826 pr_info("Open mbim driver\n");
1827
1828 while (!_mbim_dev) {
1829 pr_err("mbim_dev not created yet\n");
1830 return -ENODEV;
1831 }
1832
1833 if (mbim_lock(&_mbim_dev->open_excl)) {
1834 pr_err("Already opened\n");
1835 return -EBUSY;
1836 }
1837
1838 pr_info("Lock mbim_dev->open_excl for open\n");
1839
1840 if (!atomic_read(&_mbim_dev->online))
1841 pr_err("USB cable not connected\n");
1842
Anna Perela8c991d2012-04-09 16:44:46 +03001843 fp->private_data = _mbim_dev;
1844
1845 atomic_set(&_mbim_dev->error, 0);
1846
1847 spin_lock(&_mbim_dev->lock);
1848 _mbim_dev->is_open = true;
Anna Perela8c991d2012-04-09 16:44:46 +03001849 spin_unlock(&_mbim_dev->lock);
1850
1851 pr_info("Exit, mbim file opened\n");
1852
1853 return 0;
1854}
1855
1856static int mbim_release(struct inode *ip, struct file *fp)
1857{
1858 struct f_mbim *mbim = fp->private_data;
1859
1860 pr_info("Close mbim file");
1861
1862 spin_lock(&mbim->lock);
1863 mbim->is_open = false;
Anna Perela8c991d2012-04-09 16:44:46 +03001864 spin_unlock(&mbim->lock);
1865
Anna Perela8c991d2012-04-09 16:44:46 +03001866 mbim_unlock(&_mbim_dev->open_excl);
1867
1868 return 0;
1869}
1870
1871static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
1872{
1873 struct f_mbim *mbim = fp->private_data;
1874 int ret = 0;
1875
Anna Perel20c91152012-10-30 16:26:44 +02001876 pr_debug("Received command %d", cmd);
Anna Perela8c991d2012-04-09 16:44:46 +03001877
1878 if (mbim_lock(&mbim->ioctl_excl))
1879 return -EBUSY;
1880
1881 switch (cmd) {
1882 case MBIM_GET_NTB_SIZE:
1883 ret = copy_to_user((void __user *)arg,
1884 &mbim->ntb_input_size, sizeof(mbim->ntb_input_size));
1885 if (ret) {
1886 pr_err("copying to user space failed");
1887 ret = -EFAULT;
1888 }
1889 pr_info("Sent NTB size %d", mbim->ntb_input_size);
1890 break;
1891 case MBIM_GET_DATAGRAM_COUNT:
1892 ret = copy_to_user((void __user *)arg,
1893 &mbim->ntb_max_datagrams,
1894 sizeof(mbim->ntb_max_datagrams));
1895 if (ret) {
1896 pr_err("copying to user space failed");
1897 ret = -EFAULT;
1898 }
1899 pr_info("Sent NTB datagrams count %d",
1900 mbim->ntb_max_datagrams);
1901 break;
1902 default:
1903 pr_err("wrong parameter");
1904 ret = -EINVAL;
1905 }
1906
1907 mbim_unlock(&mbim->ioctl_excl);
1908
1909 return ret;
1910}
1911
1912/* file operations for MBIM device /dev/android_mbim */
1913static const struct file_operations mbim_fops = {
1914 .owner = THIS_MODULE,
1915 .open = mbim_open,
1916 .release = mbim_release,
1917 .read = mbim_read,
1918 .write = mbim_write,
1919 .unlocked_ioctl = mbim_ioctl,
1920};
1921
1922static struct miscdevice mbim_device = {
1923 .minor = MISC_DYNAMIC_MINOR,
1924 .name = "android_mbim",
1925 .fops = &mbim_fops,
1926};
1927
1928static int mbim_init(int instances)
1929{
1930 int i;
1931 struct f_mbim *dev = NULL;
1932 int ret;
1933
1934 pr_info("initialize %d instances\n", instances);
1935
1936 if (instances > NR_MBIM_PORTS) {
1937 pr_err("Max-%d instances supported\n", NR_MBIM_PORTS);
1938 return -EINVAL;
1939 }
1940
1941 for (i = 0; i < instances; i++) {
1942 dev = kzalloc(sizeof(struct f_mbim), GFP_KERNEL);
1943 if (!dev) {
1944 pr_err("Failed to allocate mbim dev\n");
1945 ret = -ENOMEM;
1946 goto fail_probe;
1947 }
1948
1949 dev->port_num = i;
1950 spin_lock_init(&dev->lock);
1951 INIT_LIST_HEAD(&dev->cpkt_req_q);
1952 INIT_LIST_HEAD(&dev->cpkt_resp_q);
1953
1954 mbim_ports[i].port = dev;
1955 mbim_ports[i].port_num = i;
1956
1957 init_waitqueue_head(&dev->read_wq);
1958 init_waitqueue_head(&dev->write_wq);
1959
1960 atomic_set(&dev->open_excl, 0);
1961 atomic_set(&dev->ioctl_excl, 0);
1962 atomic_set(&dev->read_excl, 0);
1963 atomic_set(&dev->write_excl, 0);
1964
1965 nr_mbim_ports++;
1966
1967 }
1968
1969 _mbim_dev = dev;
1970 ret = misc_register(&mbim_device);
1971 if (ret) {
1972 pr_err("mbim driver failed to register");
1973 goto fail_probe;
1974 }
1975
1976 pr_info("Initialized %d ports\n", nr_mbim_ports);
1977
1978 return ret;
1979
1980fail_probe:
1981 pr_err("Failed");
1982 for (i = 0; i < nr_mbim_ports; i++) {
1983 kfree(mbim_ports[i].port);
1984 mbim_ports[i].port = NULL;
1985 }
1986
1987 return ret;
1988}
1989
1990static void fmbim_cleanup(void)
1991{
1992 int i = 0;
1993
1994 pr_info("Enter");
1995
1996 for (i = 0; i < nr_mbim_ports; i++) {
1997 kfree(mbim_ports[i].port);
1998 mbim_ports[i].port = NULL;
1999 }
2000 nr_mbim_ports = 0;
2001
2002 misc_deregister(&mbim_device);
2003
2004 _mbim_dev = NULL;
2005}
2006