blob: 15f20ca7c24afe94cd5c93d07cd18411fb17d11e [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;
Anna Perela8c991d2012-04-09 16:44:46 +030077
78 atomic_t open_excl;
79 atomic_t ioctl_excl;
80 atomic_t read_excl;
81 atomic_t write_excl;
82
83 wait_queue_head_t read_wq;
84 wait_queue_head_t write_wq;
85
Lena Salmandf7e7992013-03-15 09:46:27 +020086 enum transport_type xport;
Anna Perela8c991d2012-04-09 16:44:46 +030087 u8 port_num;
88 struct data_port bam_port;
89 struct mbim_notify_port not_port;
90
91 struct mbim_ep_descs fs;
92 struct mbim_ep_descs hs;
93
94 u8 ctrl_id, data_id;
Bar Weinerb1c95f52012-12-23 09:09:13 +020095 u8 data_alt_int;
Anna Perela8c991d2012-04-09 16:44:46 +030096
Vamsi Krishna2aae5532013-05-22 12:11:51 -070097 struct mbim_ndp_parser_opts *parser_opts;
Anna Perela8c991d2012-04-09 16:44:46 +030098
99 spinlock_t lock;
100
101 struct list_head cpkt_req_q;
102 struct list_head cpkt_resp_q;
103
104 u32 ntb_input_size;
105 u16 ntb_max_datagrams;
106
Anna Perela8c991d2012-04-09 16:44:46 +0300107 atomic_t error;
108};
109
110struct mbim_ntb_input_size {
111 u32 ntb_input_size;
112 u16 ntb_max_datagrams;
113 u16 reserved;
114};
115
116/* temporary variable used between mbim_open() and mbim_gadget_bind() */
117static struct f_mbim *_mbim_dev;
118
119static unsigned int nr_mbim_ports;
120
121static struct mbim_ports {
122 struct f_mbim *port;
123 unsigned port_num;
124} mbim_ports[NR_MBIM_PORTS];
125
126static inline struct f_mbim *func_to_mbim(struct usb_function *f)
127{
128 return container_of(f, struct f_mbim, function);
129}
130
131/* peak (theoretical) bulk transfer rate in bits-per-second */
132static inline unsigned mbim_bitrate(struct usb_gadget *g)
133{
134 if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
135 return 13 * 512 * 8 * 1000 * 8;
136 else
137 return 19 * 64 * 1 * 1000 * 8;
138}
139
140/*-------------------------------------------------------------------------*/
141
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700142#define MBIM_NTB_DEFAULT_IN_SIZE (0x4000)
143#define MBIM_NTB_OUT_SIZE (0x1000)
144#define MBIM_NDP_IN_DIVISOR (0x4)
Anna Perela8c991d2012-04-09 16:44:46 +0300145
Lena Salmandf7e7992013-03-15 09:46:27 +0200146#define NTB_DEFAULT_IN_SIZE_IPA (0x2000)
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700147#define MBIM_NTB_OUT_SIZE_IPA (0x2000)
Lena Salmandf7e7992013-03-15 09:46:27 +0200148
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700149#define MBIM_FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
Anna Perela8c991d2012-04-09 16:44:46 +0300150
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700151static struct usb_cdc_ncm_ntb_parameters mbim_ntb_parameters = {
152 .wLength = sizeof mbim_ntb_parameters,
153 .bmNtbFormatsSupported = cpu_to_le16(MBIM_FORMATS_SUPPORTED),
154 .dwNtbInMaxSize = cpu_to_le32(MBIM_NTB_DEFAULT_IN_SIZE),
155 .wNdpInDivisor = cpu_to_le16(MBIM_NDP_IN_DIVISOR),
Anna Perela8c991d2012-04-09 16:44:46 +0300156 .wNdpInPayloadRemainder = cpu_to_le16(0),
157 .wNdpInAlignment = cpu_to_le16(4),
158
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700159 .dwNtbOutMaxSize = cpu_to_le32(MBIM_NTB_OUT_SIZE),
Anna Perela8c991d2012-04-09 16:44:46 +0300160 .wNdpOutDivisor = cpu_to_le16(4),
161 .wNdpOutPayloadRemainder = cpu_to_le16(0),
162 .wNdpOutAlignment = cpu_to_le16(4),
Anna Perelf99cd0c2012-05-03 13:30:26 +0300163 .wNtbOutMaxDatagrams = 0,
Anna Perela8c991d2012-04-09 16:44:46 +0300164};
165
166/*
167 * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
168 * packet, to simplify cancellation; and a big transfer interval, to
169 * waste less bandwidth.
170 */
171
172#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
173#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
174
175static struct usb_interface_assoc_descriptor mbim_iad_desc = {
176 .bLength = sizeof mbim_iad_desc,
177 .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
178
179 /* .bFirstInterface = DYNAMIC, */
180 .bInterfaceCount = 2, /* control + data */
181 .bFunctionClass = 2,
182 .bFunctionSubClass = 0x0e,
183 .bFunctionProtocol = 0,
184 /* .iFunction = DYNAMIC */
185};
186
187/* interface descriptor: */
188static struct usb_interface_descriptor mbim_control_intf = {
189 .bLength = sizeof mbim_control_intf,
190 .bDescriptorType = USB_DT_INTERFACE,
191
192 /* .bInterfaceNumber = DYNAMIC */
193 .bNumEndpoints = 1,
194 .bInterfaceClass = 0x02,
195 .bInterfaceSubClass = 0x0e,
196 .bInterfaceProtocol = 0,
197 /* .iInterface = DYNAMIC */
198};
199
200static struct usb_cdc_header_desc mbim_header_desc = {
201 .bLength = sizeof mbim_header_desc,
202 .bDescriptorType = USB_DT_CS_INTERFACE,
203 .bDescriptorSubType = USB_CDC_HEADER_TYPE,
204
205 .bcdCDC = cpu_to_le16(0x0110),
206};
207
208static struct usb_cdc_union_desc mbim_union_desc = {
209 .bLength = sizeof(mbim_union_desc),
210 .bDescriptorType = USB_DT_CS_INTERFACE,
211 .bDescriptorSubType = USB_CDC_UNION_TYPE,
212 /* .bMasterInterface0 = DYNAMIC */
213 /* .bSlaveInterface0 = DYNAMIC */
214};
215
216static struct usb_cdc_mbb_desc mbb_desc = {
217 .bLength = sizeof mbb_desc,
218 .bDescriptorType = USB_DT_CS_INTERFACE,
219 .bDescriptorSubType = USB_CDC_MBB_TYPE,
220
221 .bcdMbbVersion = cpu_to_le16(0x0100),
222
223 .wMaxControlMessage = cpu_to_le16(0x1000),
Anna Perel3354bdc2012-12-09 12:08:10 +0200224 .bNumberFilters = 0x20,
Anna Perela8c991d2012-04-09 16:44:46 +0300225 .bMaxFilterSize = 0x80,
Anna Perel26ae27c2012-05-23 18:07:31 +0300226 .wMaxSegmentSize = cpu_to_le16(0xfe0),
Anna Perela8c991d2012-04-09 16:44:46 +0300227 .bmNetworkCapabilities = 0x20,
228};
229
Bar Weiner38c3e642013-02-12 10:25:17 +0200230static struct usb_cdc_ext_mbb_desc ext_mbb_desc = {
231 .bLength = sizeof ext_mbb_desc,
232 .bDescriptorType = USB_DT_CS_INTERFACE,
233 .bDescriptorSubType = USB_CDC_EXT_MBB_TYPE,
234
235 .bcdMbbExtendedVersion = cpu_to_le16(0x0100),
236 .bMaxOutstandingCmdMsges = 64,
237 .wMTU = 1500,
238};
239
Anna Perela8c991d2012-04-09 16:44:46 +0300240/* the default data interface has no endpoints ... */
241static struct usb_interface_descriptor mbim_data_nop_intf = {
242 .bLength = sizeof mbim_data_nop_intf,
243 .bDescriptorType = USB_DT_INTERFACE,
244
245 /* .bInterfaceNumber = DYNAMIC */
246 .bAlternateSetting = 0,
247 .bNumEndpoints = 0,
248 .bInterfaceClass = 0x0a,
249 .bInterfaceSubClass = 0,
250 .bInterfaceProtocol = 0x02,
251 /* .iInterface = DYNAMIC */
252};
253
254/* ... but the "real" data interface has two bulk endpoints */
255static struct usb_interface_descriptor mbim_data_intf = {
256 .bLength = sizeof mbim_data_intf,
257 .bDescriptorType = USB_DT_INTERFACE,
258
259 /* .bInterfaceNumber = DYNAMIC */
260 .bAlternateSetting = 1,
261 .bNumEndpoints = 2,
262 .bInterfaceClass = 0x0a,
263 .bInterfaceSubClass = 0,
264 .bInterfaceProtocol = 0x02,
265 /* .iInterface = DYNAMIC */
266};
267
268/* full speed support: */
269
270static struct usb_endpoint_descriptor fs_mbim_notify_desc = {
271 .bLength = USB_DT_ENDPOINT_SIZE,
272 .bDescriptorType = USB_DT_ENDPOINT,
273
274 .bEndpointAddress = USB_DIR_IN,
275 .bmAttributes = USB_ENDPOINT_XFER_INT,
276 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
277 .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
278};
279
280static struct usb_endpoint_descriptor fs_mbim_in_desc = {
281 .bLength = USB_DT_ENDPOINT_SIZE,
282 .bDescriptorType = USB_DT_ENDPOINT,
283
284 .bEndpointAddress = USB_DIR_IN,
285 .bmAttributes = USB_ENDPOINT_XFER_BULK,
286};
287
288static struct usb_endpoint_descriptor fs_mbim_out_desc = {
289 .bLength = USB_DT_ENDPOINT_SIZE,
290 .bDescriptorType = USB_DT_ENDPOINT,
291
292 .bEndpointAddress = USB_DIR_OUT,
293 .bmAttributes = USB_ENDPOINT_XFER_BULK,
294};
295
296static struct usb_descriptor_header *mbim_fs_function[] = {
297 (struct usb_descriptor_header *) &mbim_iad_desc,
298 /* MBIM control descriptors */
299 (struct usb_descriptor_header *) &mbim_control_intf,
300 (struct usb_descriptor_header *) &mbim_header_desc,
Anna Perel555a7b22013-02-26 13:14:32 +0200301 (struct usb_descriptor_header *) &mbim_union_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300302 (struct usb_descriptor_header *) &mbb_desc,
Bar Weiner38c3e642013-02-12 10:25:17 +0200303 (struct usb_descriptor_header *) &ext_mbb_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300304 (struct usb_descriptor_header *) &fs_mbim_notify_desc,
305 /* data interface, altsettings 0 and 1 */
306 (struct usb_descriptor_header *) &mbim_data_nop_intf,
307 (struct usb_descriptor_header *) &mbim_data_intf,
308 (struct usb_descriptor_header *) &fs_mbim_in_desc,
309 (struct usb_descriptor_header *) &fs_mbim_out_desc,
310 NULL,
311};
312
313/* high speed support: */
314
315static struct usb_endpoint_descriptor hs_mbim_notify_desc = {
316 .bLength = USB_DT_ENDPOINT_SIZE,
317 .bDescriptorType = USB_DT_ENDPOINT,
318
319 .bEndpointAddress = USB_DIR_IN,
320 .bmAttributes = USB_ENDPOINT_XFER_INT,
321 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
322 .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
323};
324static struct usb_endpoint_descriptor hs_mbim_in_desc = {
325 .bLength = USB_DT_ENDPOINT_SIZE,
326 .bDescriptorType = USB_DT_ENDPOINT,
327
328 .bEndpointAddress = USB_DIR_IN,
329 .bmAttributes = USB_ENDPOINT_XFER_BULK,
330 .wMaxPacketSize = cpu_to_le16(512),
331};
332
333static struct usb_endpoint_descriptor hs_mbim_out_desc = {
334 .bLength = USB_DT_ENDPOINT_SIZE,
335 .bDescriptorType = USB_DT_ENDPOINT,
336
337 .bEndpointAddress = USB_DIR_OUT,
338 .bmAttributes = USB_ENDPOINT_XFER_BULK,
339 .wMaxPacketSize = cpu_to_le16(512),
340};
341
342static struct usb_descriptor_header *mbim_hs_function[] = {
343 (struct usb_descriptor_header *) &mbim_iad_desc,
344 /* MBIM control descriptors */
345 (struct usb_descriptor_header *) &mbim_control_intf,
346 (struct usb_descriptor_header *) &mbim_header_desc,
Amit Blayfa105432013-03-27 15:46:08 +0200347 (struct usb_descriptor_header *) &mbim_union_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300348 (struct usb_descriptor_header *) &mbb_desc,
Bar Weiner38c3e642013-02-12 10:25:17 +0200349 (struct usb_descriptor_header *) &ext_mbb_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300350 (struct usb_descriptor_header *) &hs_mbim_notify_desc,
351 /* data interface, altsettings 0 and 1 */
352 (struct usb_descriptor_header *) &mbim_data_nop_intf,
353 (struct usb_descriptor_header *) &mbim_data_intf,
354 (struct usb_descriptor_header *) &hs_mbim_in_desc,
355 (struct usb_descriptor_header *) &hs_mbim_out_desc,
356 NULL,
357};
358
359/* string descriptors: */
360
361#define STRING_CTRL_IDX 0
362#define STRING_DATA_IDX 1
363
364static struct usb_string mbim_string_defs[] = {
365 [STRING_CTRL_IDX].s = "MBIM Control",
366 [STRING_DATA_IDX].s = "MBIM Data",
367 { } /* end of list */
368};
369
370static struct usb_gadget_strings mbim_string_table = {
371 .language = 0x0409, /* en-us */
372 .strings = mbim_string_defs,
373};
374
375static struct usb_gadget_strings *mbim_strings[] = {
376 &mbim_string_table,
377 NULL,
378};
379
Jack Pham2df2f702012-10-11 19:08:24 -0700380/* Microsoft OS Descriptors */
381
382/*
383 * We specify our own bMS_VendorCode byte which Windows will use
384 * as the bRequest value in subsequent device get requests.
385 */
386#define MBIM_VENDOR_CODE 0xA5
387
388/* Microsoft OS String */
389static u8 mbim_os_string[] = {
390 18, /* sizeof(mtp_os_string) */
391 USB_DT_STRING,
392 /* Signature field: "MSFT100" */
393 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
394 /* vendor code */
395 MBIM_VENDOR_CODE,
396 /* padding */
397 0
398};
399
400/* Microsoft Extended Configuration Descriptor Header Section */
401struct mbim_ext_config_desc_header {
402 __le32 dwLength;
403 __u16 bcdVersion;
404 __le16 wIndex;
405 __u8 bCount;
406 __u8 reserved[7];
407};
408
409/* Microsoft Extended Configuration Descriptor Function Section */
410struct mbim_ext_config_desc_function {
411 __u8 bFirstInterfaceNumber;
412 __u8 bInterfaceCount;
413 __u8 compatibleID[8];
414 __u8 subCompatibleID[8];
415 __u8 reserved[6];
416};
417
418/* Microsoft Extended Configuration Descriptor */
419static struct {
420 struct mbim_ext_config_desc_header header;
421 struct mbim_ext_config_desc_function function;
422} mbim_ext_config_desc = {
423 .header = {
424 .dwLength = __constant_cpu_to_le32(sizeof mbim_ext_config_desc),
425 .bcdVersion = __constant_cpu_to_le16(0x0100),
426 .wIndex = __constant_cpu_to_le16(4),
427 .bCount = 1,
428 },
429 .function = {
430 .bFirstInterfaceNumber = 0,
431 .bInterfaceCount = 1,
432 .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' },
433 /* .subCompatibleID = DYNAMIC */
434 },
435};
436
Anna Perela8c991d2012-04-09 16:44:46 +0300437/*
438 * Here are options for the Datagram Pointer table (NDP) parser.
439 * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
440 * in NDP16 offsets and sizes fields are 1 16bit word wide,
441 * in NDP32 -- 2 16bit words wide. Also signatures are different.
442 * To make the parser code the same, put the differences in the structure,
443 * and switch pointers to the structures when the format is changed.
444 */
445
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700446struct mbim_ndp_parser_opts {
Anna Perela8c991d2012-04-09 16:44:46 +0300447 u32 nth_sign;
448 u32 ndp_sign;
449 unsigned nth_size;
450 unsigned ndp_size;
451 unsigned ndplen_align;
452 /* sizes in u16 units */
453 unsigned dgram_item_len; /* index or length */
454 unsigned block_length;
455 unsigned fp_index;
456 unsigned reserved1;
457 unsigned reserved2;
458 unsigned next_fp_index;
459};
460
461#define INIT_NDP16_OPTS { \
462 .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
463 .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
464 .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
465 .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
466 .ndplen_align = 4, \
467 .dgram_item_len = 1, \
468 .block_length = 1, \
469 .fp_index = 1, \
470 .reserved1 = 0, \
471 .reserved2 = 0, \
472 .next_fp_index = 1, \
473}
474
475#define INIT_NDP32_OPTS { \
476 .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
477 .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
478 .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
479 .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
480 .ndplen_align = 8, \
481 .dgram_item_len = 2, \
482 .block_length = 2, \
483 .fp_index = 2, \
484 .reserved1 = 1, \
485 .reserved2 = 2, \
486 .next_fp_index = 2, \
487}
488
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700489static struct mbim_ndp_parser_opts mbim_ndp16_opts = INIT_NDP16_OPTS;
490static struct mbim_ndp_parser_opts mbim_ndp32_opts = INIT_NDP32_OPTS;
Anna Perela8c991d2012-04-09 16:44:46 +0300491
492static inline int mbim_lock(atomic_t *excl)
493{
494 if (atomic_inc_return(excl) == 1) {
495 return 0;
496 } else {
497 atomic_dec(excl);
498 return -EBUSY;
499 }
500}
501
502static inline void mbim_unlock(atomic_t *excl)
503{
504 atomic_dec(excl);
505}
506
507static struct ctrl_pkt *mbim_alloc_ctrl_pkt(unsigned len, gfp_t flags)
508{
509 struct ctrl_pkt *pkt;
510
511 pkt = kzalloc(sizeof(struct ctrl_pkt), flags);
512 if (!pkt)
513 return ERR_PTR(-ENOMEM);
514
515 pkt->buf = kmalloc(len, flags);
516 if (!pkt->buf) {
517 kfree(pkt);
518 return ERR_PTR(-ENOMEM);
519 }
520 pkt->len = len;
521
522 return pkt;
523}
524
525static void mbim_free_ctrl_pkt(struct ctrl_pkt *pkt)
526{
527 if (pkt) {
528 kfree(pkt->buf);
529 kfree(pkt);
530 }
531}
532
533static struct usb_request *mbim_alloc_req(struct usb_ep *ep, int buffer_size)
534{
535 struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
536 if (!req)
537 return NULL;
538
539 req->buf = kmalloc(buffer_size, GFP_KERNEL);
540 if (!req->buf) {
541 usb_ep_free_request(ep, req);
542 return NULL;
543 }
544 req->length = buffer_size;
545 return req;
546}
547
548void fmbim_free_req(struct usb_ep *ep, struct usb_request *req)
549{
550 if (req) {
551 kfree(req->buf);
552 usb_ep_free_request(ep, req);
553 }
554}
555
556static void fmbim_ctrl_response_available(struct f_mbim *dev)
557{
558 struct usb_request *req = dev->not_port.notify_req;
559 struct usb_cdc_notification *event = NULL;
560 unsigned long flags;
561 int ret;
562
Anna Perel68aeb172012-10-28 09:00:45 +0200563 pr_debug("dev:%p portno#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300564
565 spin_lock_irqsave(&dev->lock, flags);
566
567 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200568 pr_err("dev:%p is not online\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300569 spin_unlock_irqrestore(&dev->lock, flags);
570 return;
571 }
572
573 if (!req) {
Anna Perel20c91152012-10-30 16:26:44 +0200574 pr_err("dev:%p req is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300575 spin_unlock_irqrestore(&dev->lock, flags);
576 return;
577 }
578
579 if (!req->buf) {
Anna Perel20c91152012-10-30 16:26:44 +0200580 pr_err("dev:%p req->buf is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300581 spin_unlock_irqrestore(&dev->lock, flags);
582 return;
583 }
584
Anna Perel68aeb172012-10-28 09:00:45 +0200585 if (atomic_inc_return(&dev->not_port.notify_count) != 1) {
586 pr_debug("delay ep_queue: notifications queue is busy[%d]",
587 atomic_read(&dev->not_port.notify_count));
588 spin_unlock_irqrestore(&dev->lock, flags);
589 return;
590 }
Anna Perela8c991d2012-04-09 16:44:46 +0300591
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200592 req->length = sizeof *event;
Anna Perela8c991d2012-04-09 16:44:46 +0300593 event = req->buf;
594 event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
595 | USB_RECIP_INTERFACE;
596 event->bNotificationType = USB_CDC_NOTIFY_RESPONSE_AVAILABLE;
597 event->wValue = cpu_to_le16(0);
598 event->wIndex = cpu_to_le16(dev->ctrl_id);
599 event->wLength = cpu_to_le16(0);
600 spin_unlock_irqrestore(&dev->lock, flags);
601
Anna Perela8c991d2012-04-09 16:44:46 +0300602 ret = usb_ep_queue(dev->not_port.notify,
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200603 req, GFP_ATOMIC);
Anna Perela8c991d2012-04-09 16:44:46 +0300604 if (ret) {
605 atomic_dec(&dev->not_port.notify_count);
606 pr_err("ep enqueue error %d\n", ret);
607 }
608
Anna Perel68aeb172012-10-28 09:00:45 +0200609 pr_debug("Successful Exit");
Anna Perela8c991d2012-04-09 16:44:46 +0300610}
611
612static int
613fmbim_send_cpkt_response(struct f_mbim *gr, struct ctrl_pkt *cpkt)
614{
615 struct f_mbim *dev = gr;
616 unsigned long flags;
617
618 if (!gr || !cpkt) {
619 pr_err("Invalid cpkt, dev:%p cpkt:%p\n",
620 gr, cpkt);
621 return -ENODEV;
622 }
623
Anna Perel20c91152012-10-30 16:26:44 +0200624 pr_debug("dev:%p port_num#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300625
626 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200627 pr_err("dev:%p is not connected\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300628 mbim_free_ctrl_pkt(cpkt);
629 return 0;
630 }
631
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700632 if (dev->not_port.notify_state != MBIM_NOTIFY_RESPONSE_AVAILABLE) {
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200633 pr_err("dev:%p state=%d, recover!!\n", dev,
634 dev->not_port.notify_state);
635 mbim_free_ctrl_pkt(cpkt);
636 return 0;
637 }
638
Anna Perela8c991d2012-04-09 16:44:46 +0300639 spin_lock_irqsave(&dev->lock, flags);
Anna Perel40c550c2012-04-11 14:09:27 +0300640 list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
Anna Perela8c991d2012-04-09 16:44:46 +0300641 spin_unlock_irqrestore(&dev->lock, flags);
642
643 fmbim_ctrl_response_available(dev);
644
645 return 0;
646}
647
648/* ---------------------------- BAM INTERFACE ----------------------------- */
649
650static int mbim_bam_setup(int no_ports)
651{
652 int ret;
653
654 pr_info("no_ports:%d\n", no_ports);
655
656 ret = bam_data_setup(no_ports);
657 if (ret) {
658 pr_err("bam_data_setup failed err: %d\n", ret);
659 return ret;
660 }
661
662 pr_info("Initialized %d ports\n", no_ports);
663 return 0;
664}
665
Lena Salmandf7e7992013-03-15 09:46:27 +0200666int mbim_configure_params(void)
667{
668 struct teth_aggr_params aggr_params;
669 int ret = 0;
670
671 aggr_params.dl.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700672 aggr_params.dl.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
673 aggr_params.dl.max_transfer_size_byte =
674 mbim_ntb_parameters.dwNtbInMaxSize;
Lena Salmandf7e7992013-03-15 09:46:27 +0200675
676 aggr_params.ul.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700677 aggr_params.ul.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
678 aggr_params.ul.max_transfer_size_byte =
679 mbim_ntb_parameters.dwNtbOutMaxSize;
Lena Salmandf7e7992013-03-15 09:46:27 +0200680
681 ret = teth_bridge_set_aggr_params(&aggr_params);
682 if (ret)
683 pr_err("%s: teth_bridge_set_aggr_params failed\n", __func__);
684
685 return ret;
686}
687
Anna Perela8c991d2012-04-09 16:44:46 +0300688static int mbim_bam_connect(struct f_mbim *dev)
689{
690 int ret;
Shimrit Malichidbf43d72013-03-16 03:32:27 +0200691 u8 src_connection_idx, dst_connection_idx;
692 struct usb_gadget *gadget = dev->cdev->gadget;
Lena Salmandf7e7992013-03-15 09:46:27 +0200693 enum peer_bam bam_name = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
694 IPA_P_BAM : A2_P_BAM;
Anna Perela8c991d2012-04-09 16:44:46 +0300695
696 pr_info("dev:%p portno:%d\n", dev, dev->port_num);
697
Lena Salmandf7e7992013-03-15 09:46:27 +0200698 src_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
699 USB_TO_PEER_PERIPHERAL, dev->port_num);
700 dst_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
701 PEER_PERIPHERAL_TO_USB, dev->port_num);
Shimrit Malichidbf43d72013-03-16 03:32:27 +0200702 if (src_connection_idx < 0 || dst_connection_idx < 0) {
703 pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
704 return ret;
705 }
706
Amit Blayf9b352b2013-03-04 15:01:40 +0200707 ret = bam_data_connect(&dev->bam_port, dev->port_num,
Lena Salmandf7e7992013-03-15 09:46:27 +0200708 dev->xport, src_connection_idx, dst_connection_idx,
709 USB_FUNC_MBIM);
710
Anna Perela8c991d2012-04-09 16:44:46 +0300711 if (ret) {
712 pr_err("bam_data_setup failed: err:%d\n",
713 ret);
714 return ret;
Anna Perela8c991d2012-04-09 16:44:46 +0300715 }
716
Shimrit Malichidbf43d72013-03-16 03:32:27 +0200717 pr_info("mbim bam connected\n");
Anna Perela8c991d2012-04-09 16:44:46 +0300718 return 0;
719}
720
721static int mbim_bam_disconnect(struct f_mbim *dev)
722{
723 pr_info("dev:%p port:%d. Do nothing.\n",
724 dev, dev->port_num);
725
Amit Blay51bebe92012-12-25 18:48:10 +0200726 bam_data_disconnect(&dev->bam_port, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300727
728 return 0;
729}
730
731/* -------------------------------------------------------------------------*/
732
733static inline void mbim_reset_values(struct f_mbim *mbim)
734{
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700735 mbim->parser_opts = &mbim_ndp16_opts;
Anna Perela8c991d2012-04-09 16:44:46 +0300736
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700737 mbim->ntb_input_size = MBIM_NTB_DEFAULT_IN_SIZE;
Anna Perela8c991d2012-04-09 16:44:46 +0300738
Anna Perela8c991d2012-04-09 16:44:46 +0300739 atomic_set(&mbim->online, 0);
740}
741
Anna Perel86ea7c92012-04-24 14:31:29 +0300742static void mbim_reset_function_queue(struct f_mbim *dev)
743{
744 struct ctrl_pkt *cpkt = NULL;
745
746 pr_debug("Queue empty packet for QBI");
747
748 spin_lock(&dev->lock);
Anna Perel86ea7c92012-04-24 14:31:29 +0300749
750 cpkt = mbim_alloc_ctrl_pkt(0, GFP_ATOMIC);
751 if (!cpkt) {
752 pr_err("%s: Unable to allocate reset function pkt\n", __func__);
753 spin_unlock(&dev->lock);
754 return;
755 }
756
757 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
758 spin_unlock(&dev->lock);
759
760 pr_debug("%s: Wake up read queue", __func__);
761 wake_up(&dev->read_wq);
762}
763
764static void fmbim_reset_cmd_complete(struct usb_ep *ep, struct usb_request *req)
765{
766 struct f_mbim *dev = req->context;
767
768 mbim_reset_function_queue(dev);
769}
770
771static void mbim_clear_queues(struct f_mbim *mbim)
772{
773 struct ctrl_pkt *cpkt = NULL;
774 struct list_head *act, *tmp;
775
776 spin_lock(&mbim->lock);
777 list_for_each_safe(act, tmp, &mbim->cpkt_req_q) {
778 cpkt = list_entry(act, struct ctrl_pkt, list);
779 list_del(&cpkt->list);
780 mbim_free_ctrl_pkt(cpkt);
781 }
782 list_for_each_safe(act, tmp, &mbim->cpkt_resp_q) {
783 cpkt = list_entry(act, struct ctrl_pkt, list);
784 list_del(&cpkt->list);
785 mbim_free_ctrl_pkt(cpkt);
786 }
787 spin_unlock(&mbim->lock);
788}
789
Anna Perela8c991d2012-04-09 16:44:46 +0300790/*
791 * Context: mbim->lock held
792 */
793static void mbim_do_notify(struct f_mbim *mbim)
794{
795 struct usb_request *req = mbim->not_port.notify_req;
796 struct usb_cdc_notification *event;
Anna Perela8c991d2012-04-09 16:44:46 +0300797 int status;
798
Anna Perel20c91152012-10-30 16:26:44 +0200799 pr_debug("notify_state: %d", mbim->not_port.notify_state);
Anna Perela8c991d2012-04-09 16:44:46 +0300800
801 if (!req)
802 return;
803
804 event = req->buf;
805
806 switch (mbim->not_port.notify_state) {
807
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700808 case MBIM_NOTIFY_NONE:
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200809 if (atomic_read(&mbim->not_port.notify_count) > 0)
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700810 pr_err("Pending notifications in MBIM_NOTIFY_NONE\n");
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200811 else
812 pr_debug("No pending notifications\n");
813
814 return;
815
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700816 case MBIM_NOTIFY_RESPONSE_AVAILABLE:
Anna Perel68aeb172012-10-28 09:00:45 +0200817 pr_debug("Notification %02x sent\n", event->bNotificationType);
818
819 if (atomic_read(&mbim->not_port.notify_count) <= 0) {
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200820 pr_debug("notify_response_avaliable: done");
Anna Perel68aeb172012-10-28 09:00:45 +0200821 return;
822 }
823
824 spin_unlock(&mbim->lock);
825 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
826 spin_lock(&mbim->lock);
827 if (status) {
828 atomic_dec(&mbim->not_port.notify_count);
829 pr_err("Queue notify request failed, err: %d", status);
830 }
831
Anna Perela8c991d2012-04-09 16:44:46 +0300832 return;
Anna Perela8c991d2012-04-09 16:44:46 +0300833 }
Anna Perel68aeb172012-10-28 09:00:45 +0200834
Anna Perela8c991d2012-04-09 16:44:46 +0300835 event->bmRequestType = 0xA1;
836 event->wIndex = cpu_to_le16(mbim->ctrl_id);
837
Anna Perela8c991d2012-04-09 16:44:46 +0300838 /*
839 * In double buffering if there is a space in FIFO,
840 * completion callback can be called right after the call,
841 * so unlocking
842 */
Anna Perel68aeb172012-10-28 09:00:45 +0200843 atomic_inc(&mbim->not_port.notify_count);
844 pr_debug("queue request: notify_count = %d",
845 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300846 spin_unlock(&mbim->lock);
847 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
848 spin_lock(&mbim->lock);
Anna Perel68aeb172012-10-28 09:00:45 +0200849 if (status) {
Anna Perela8c991d2012-04-09 16:44:46 +0300850 atomic_dec(&mbim->not_port.notify_count);
851 pr_err("usb_ep_queue failed, err: %d", status);
852 }
853}
854
Anna Perela8c991d2012-04-09 16:44:46 +0300855static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
856{
857 struct f_mbim *mbim = req->context;
858 struct usb_cdc_notification *event = req->buf;
859
Anna Perel68aeb172012-10-28 09:00:45 +0200860 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300861
862 spin_lock(&mbim->lock);
863 switch (req->status) {
864 case 0:
Anna Perel68aeb172012-10-28 09:00:45 +0200865 atomic_dec(&mbim->not_port.notify_count);
866 pr_debug("notify_count = %d",
867 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300868 break;
869
870 case -ECONNRESET:
871 case -ESHUTDOWN:
872 /* connection gone */
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700873 mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
Anna Perela8c991d2012-04-09 16:44:46 +0300874 atomic_set(&mbim->not_port.notify_count, 0);
875 pr_info("ESHUTDOWN/ECONNRESET, connection gone");
Anna Perel86ea7c92012-04-24 14:31:29 +0300876 spin_unlock(&mbim->lock);
877 mbim_clear_queues(mbim);
878 mbim_reset_function_queue(mbim);
Anna Perel89ad1212012-06-13 17:17:24 +0300879 spin_lock(&mbim->lock);
Anna Perela8c991d2012-04-09 16:44:46 +0300880 break;
881 default:
882 pr_err("Unknown event %02x --> %d\n",
883 event->bNotificationType, req->status);
884 break;
885 }
886
Anna Perela8c991d2012-04-09 16:44:46 +0300887 mbim_do_notify(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300888 spin_unlock(&mbim->lock);
889
Anna Perel20c91152012-10-30 16:26:44 +0200890 pr_debug("dev:%p Exit\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300891}
892
893static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
894{
895 /* now for SET_NTB_INPUT_SIZE only */
896 unsigned in_size = 0;
897 struct usb_function *f = req->context;
898 struct f_mbim *mbim = func_to_mbim(f);
899 struct mbim_ntb_input_size *ntb = NULL;
900
Anna Perel20c91152012-10-30 16:26:44 +0200901 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300902
903 req->context = NULL;
904 if (req->status || req->actual != req->length) {
905 pr_err("Bad control-OUT transfer\n");
906 goto invalid;
907 }
908
909 if (req->length == 4) {
910 in_size = get_unaligned_le32(req->buf);
911 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700912 in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
Anna Perela8c991d2012-04-09 16:44:46 +0300913 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
914 goto invalid;
915 }
916 } else if (req->length == 8) {
917 ntb = (struct mbim_ntb_input_size *)req->buf;
918 in_size = get_unaligned_le32(&(ntb->ntb_input_size));
919 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
Vamsi Krishna2aae5532013-05-22 12:11:51 -0700920 in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
Anna Perela8c991d2012-04-09 16:44:46 +0300921 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
922 goto invalid;
923 }
924 mbim->ntb_max_datagrams =
925 get_unaligned_le16(&(ntb->ntb_max_datagrams));
926 } else {
927 pr_err("Illegal NTB length %d\n", in_size);
928 goto invalid;
929 }
930
Anna Perel20c91152012-10-30 16:26:44 +0200931 pr_debug("Set NTB INPUT SIZE %d\n", in_size);
Anna Perela8c991d2012-04-09 16:44:46 +0300932
933 mbim->ntb_input_size = in_size;
934 return;
935
936invalid:
937 usb_ep_set_halt(ep);
938
939 pr_err("dev:%p Failed\n", mbim);
940
941 return;
942}
943
944static void
945fmbim_cmd_complete(struct usb_ep *ep, struct usb_request *req)
946{
947 struct f_mbim *dev = req->context;
948 struct ctrl_pkt *cpkt = NULL;
949 int len = req->actual;
950
951 if (!dev) {
952 pr_err("mbim dev is null\n");
953 return;
954 }
955
956 if (req->status < 0) {
957 pr_err("mbim command error %d\n", req->status);
958 return;
959 }
960
Anna Perel20c91152012-10-30 16:26:44 +0200961 pr_debug("dev:%p port#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300962
Anna Perela8c991d2012-04-09 16:44:46 +0300963 cpkt = mbim_alloc_ctrl_pkt(len, GFP_ATOMIC);
964 if (!cpkt) {
965 pr_err("Unable to allocate ctrl pkt\n");
Anna Perela8c991d2012-04-09 16:44:46 +0300966 return;
967 }
968
Anna Perel20c91152012-10-30 16:26:44 +0200969 pr_debug("Add to cpkt_req_q packet with len = %d\n", len);
Anna Perela8c991d2012-04-09 16:44:46 +0300970 memcpy(cpkt->buf, req->buf, len);
Anna Perel20c91152012-10-30 16:26:44 +0200971
Anna Perel182ab572012-11-18 10:10:12 +0200972 spin_lock(&dev->lock);
Anna Perel182ab572012-11-18 10:10:12 +0200973
Anna Perela8c991d2012-04-09 16:44:46 +0300974 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
975 spin_unlock(&dev->lock);
976
977 /* wakeup read thread */
Anna Perel20c91152012-10-30 16:26:44 +0200978 pr_debug("Wake up read queue");
Anna Perela8c991d2012-04-09 16:44:46 +0300979 wake_up(&dev->read_wq);
980
981 return;
982}
983
984static int
985mbim_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
986{
987 struct f_mbim *mbim = func_to_mbim(f);
988 struct usb_composite_dev *cdev = mbim->cdev;
989 struct usb_request *req = cdev->req;
990 struct ctrl_pkt *cpkt = NULL;
991 int value = -EOPNOTSUPP;
992 u16 w_index = le16_to_cpu(ctrl->wIndex);
993 u16 w_value = le16_to_cpu(ctrl->wValue);
994 u16 w_length = le16_to_cpu(ctrl->wLength);
995
996 /*
997 * composite driver infrastructure handles everything except
998 * CDC class messages; interface activation uses set_alt().
999 */
1000
1001 if (!atomic_read(&mbim->online)) {
1002 pr_info("usb cable is not connected\n");
1003 return -ENOTCONN;
1004 }
1005
1006 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
1007 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1008 | USB_CDC_RESET_FUNCTION:
1009
Anna Perel20c91152012-10-30 16:26:44 +02001010 pr_debug("USB_CDC_RESET_FUNCTION");
Anna Perela8c991d2012-04-09 16:44:46 +03001011 value = 0;
Anna Perel86ea7c92012-04-24 14:31:29 +03001012 req->complete = fmbim_reset_cmd_complete;
1013 req->context = mbim;
Anna Perela8c991d2012-04-09 16:44:46 +03001014 break;
1015
1016 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1017 | USB_CDC_SEND_ENCAPSULATED_COMMAND:
1018
Anna Perel20c91152012-10-30 16:26:44 +02001019 pr_debug("USB_CDC_SEND_ENCAPSULATED_COMMAND");
Anna Perela8c991d2012-04-09 16:44:46 +03001020
1021 if (w_length > req->length) {
Anna Perel20c91152012-10-30 16:26:44 +02001022 pr_debug("w_length > req->length: %d > %d",
Anna Perela8c991d2012-04-09 16:44:46 +03001023 w_length, req->length);
1024 }
1025 value = w_length;
1026 req->complete = fmbim_cmd_complete;
1027 req->context = mbim;
1028 break;
1029
1030 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1031 | USB_CDC_GET_ENCAPSULATED_RESPONSE:
1032
Anna Perel20c91152012-10-30 16:26:44 +02001033 pr_debug("USB_CDC_GET_ENCAPSULATED_RESPONSE");
Anna Perela8c991d2012-04-09 16:44:46 +03001034
1035 if (w_value) {
1036 pr_err("w_length > 0: %d", w_length);
1037 break;
1038 }
1039
Anna Perel20c91152012-10-30 16:26:44 +02001040 pr_debug("req%02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001041 ctrl->bRequestType, ctrl->bRequest,
1042 w_value, w_index, w_length);
1043
1044 spin_lock(&mbim->lock);
1045 if (list_empty(&mbim->cpkt_resp_q)) {
1046 pr_err("ctrl resp queue empty\n");
1047 spin_unlock(&mbim->lock);
1048 break;
1049 }
1050
1051 cpkt = list_first_entry(&mbim->cpkt_resp_q,
1052 struct ctrl_pkt, list);
1053 list_del(&cpkt->list);
1054 spin_unlock(&mbim->lock);
1055
1056 value = min_t(unsigned, w_length, cpkt->len);
1057 memcpy(req->buf, cpkt->buf, value);
1058 mbim_free_ctrl_pkt(cpkt);
1059
Anna Perel20c91152012-10-30 16:26:44 +02001060 pr_debug("copied encapsulated_response %d bytes",
Anna Perela8c991d2012-04-09 16:44:46 +03001061 value);
1062
1063 break;
1064
1065 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1066 | USB_CDC_GET_NTB_PARAMETERS:
1067
Anna Perel20c91152012-10-30 16:26:44 +02001068 pr_debug("USB_CDC_GET_NTB_PARAMETERS");
Anna Perela8c991d2012-04-09 16:44:46 +03001069
1070 if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
1071 break;
1072
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001073 value = w_length > sizeof mbim_ntb_parameters ?
1074 sizeof mbim_ntb_parameters : w_length;
1075 memcpy(req->buf, &mbim_ntb_parameters, value);
Anna Perela8c991d2012-04-09 16:44:46 +03001076 break;
1077
1078 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1079 | USB_CDC_GET_NTB_INPUT_SIZE:
1080
Anna Perel20c91152012-10-30 16:26:44 +02001081 pr_debug("USB_CDC_GET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001082
1083 if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
1084 break;
1085
1086 put_unaligned_le32(mbim->ntb_input_size, req->buf);
1087 value = 4;
Anna Perel20c91152012-10-30 16:26:44 +02001088 pr_debug("Reply to host INPUT SIZE %d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001089 mbim->ntb_input_size);
1090 break;
1091
1092 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1093 | USB_CDC_SET_NTB_INPUT_SIZE:
1094
Anna Perel20c91152012-10-30 16:26:44 +02001095 pr_debug("USB_CDC_SET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001096
1097 if (w_length != 4 && w_length != 8) {
1098 pr_err("wrong NTB length %d", w_length);
1099 break;
1100 }
1101
1102 if (w_value != 0 || w_index != mbim->ctrl_id)
1103 break;
1104
1105 req->complete = mbim_ep0out_complete;
1106 req->length = w_length;
1107 req->context = f;
1108
1109 value = req->length;
1110 break;
1111
1112 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1113 | USB_CDC_GET_NTB_FORMAT:
1114 {
1115 uint16_t format;
1116
Anna Perel20c91152012-10-30 16:26:44 +02001117 pr_debug("USB_CDC_GET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001118
1119 if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
1120 break;
1121
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001122 format = (mbim->parser_opts == &mbim_ndp16_opts) ? 0 : 1;
Anna Perela8c991d2012-04-09 16:44:46 +03001123 put_unaligned_le16(format, req->buf);
1124 value = 2;
Anna Perel20c91152012-10-30 16:26:44 +02001125 pr_debug("NTB FORMAT: sending %d\n", format);
Anna Perela8c991d2012-04-09 16:44:46 +03001126 break;
1127 }
1128
1129 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1130 | USB_CDC_SET_NTB_FORMAT:
1131 {
Anna Perel20c91152012-10-30 16:26:44 +02001132 pr_debug("USB_CDC_SET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001133
1134 if (w_length != 0 || w_index != mbim->ctrl_id)
1135 break;
1136 switch (w_value) {
1137 case 0x0000:
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001138 mbim->parser_opts = &mbim_ndp16_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001139 pr_debug("NCM16 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001140 break;
1141 case 0x0001:
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001142 mbim->parser_opts = &mbim_ndp32_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001143 pr_debug("NCM32 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001144 break;
1145 default:
1146 break;
1147 }
1148 value = 0;
1149 break;
1150 }
1151
1152 /* optional in mbim descriptor: */
1153 /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
1154 /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
1155
1156 default:
1157 pr_err("invalid control req: %02x.%02x v%04x i%04x l%d\n",
1158 ctrl->bRequestType, ctrl->bRequest,
1159 w_value, w_index, w_length);
1160 }
1161
1162 /* respond with data transfer or status phase? */
1163 if (value >= 0) {
Anna Perel20c91152012-10-30 16:26:44 +02001164 pr_debug("control request: %02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001165 ctrl->bRequestType, ctrl->bRequest,
1166 w_value, w_index, w_length);
Anna Perel2dfcaca2012-04-18 17:25:59 +03001167 req->zero = (value < w_length);
Anna Perela8c991d2012-04-09 16:44:46 +03001168 req->length = value;
1169 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1170 if (value < 0) {
1171 pr_err("queueing req failed: %02x.%02x, err %d\n",
1172 ctrl->bRequestType,
1173 ctrl->bRequest, value);
1174 }
1175 } else {
1176 pr_err("ctrl req err %d: %02x.%02x v%04x i%04x l%d\n",
1177 value, ctrl->bRequestType, ctrl->bRequest,
1178 w_value, w_index, w_length);
1179 }
1180
1181 /* device either stalls (value < 0) or reports success */
1182 return value;
1183}
1184
Jack Pham2df2f702012-10-11 19:08:24 -07001185/*
1186 * This function handles the Microsoft-specific OS descriptor control
1187 * requests that are issued by Windows host drivers to determine the
1188 * configuration containing the MBIM function.
1189 *
1190 * Unlike mbim_setup() this function handles two specific device requests,
1191 * and only when a configuration has not yet been selected.
1192 */
1193static int mbim_ctrlrequest(struct usb_composite_dev *cdev,
1194 const struct usb_ctrlrequest *ctrl)
1195{
1196 int value = -EOPNOTSUPP;
1197 u16 w_index = le16_to_cpu(ctrl->wIndex);
1198 u16 w_value = le16_to_cpu(ctrl->wValue);
1199 u16 w_length = le16_to_cpu(ctrl->wLength);
1200
1201 /* only respond to OS desciptors when no configuration selected */
1202 if (cdev->config || !mbim_ext_config_desc.function.subCompatibleID[0])
1203 return value;
1204
1205 pr_debug("%02x.%02x v%04x i%04x l%u",
1206 ctrl->bRequestType, ctrl->bRequest,
1207 w_value, w_index, w_length);
1208
1209 /* Handle MSFT OS string */
1210 if (ctrl->bRequestType ==
1211 (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
1212 && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
1213 && (w_value >> 8) == USB_DT_STRING
1214 && (w_value & 0xFF) == MBIM_OS_STRING_ID) {
1215
1216 value = (w_length < sizeof(mbim_os_string) ?
1217 w_length : sizeof(mbim_os_string));
1218 memcpy(cdev->req->buf, mbim_os_string, value);
1219
1220 } else if (ctrl->bRequestType ==
1221 (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
1222 && ctrl->bRequest == MBIM_VENDOR_CODE && w_index == 4) {
1223
1224 /* Handle Extended OS descriptor */
1225 value = (w_length < sizeof(mbim_ext_config_desc) ?
1226 w_length : sizeof(mbim_ext_config_desc));
1227 memcpy(cdev->req->buf, &mbim_ext_config_desc, value);
1228 }
1229
1230 /* respond with data transfer or status phase? */
1231 if (value >= 0) {
1232 int rc;
1233 cdev->req->zero = value < w_length;
1234 cdev->req->length = value;
1235 rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
1236 if (rc < 0)
1237 pr_err("response queue error: %d", rc);
1238 }
1239 return value;
1240}
1241
Anna Perela8c991d2012-04-09 16:44:46 +03001242static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
1243{
1244 struct f_mbim *mbim = func_to_mbim(f);
1245 struct usb_composite_dev *cdev = mbim->cdev;
1246 int ret = 0;
1247
1248 /* Control interface has only altsetting 0 */
1249 if (intf == mbim->ctrl_id) {
1250
1251 pr_info("CONTROL_INTERFACE");
1252
1253 if (alt != 0)
1254 goto fail;
1255
1256 if (mbim->not_port.notify->driver_data) {
1257 pr_info("reset mbim control %d\n", intf);
1258 usb_ep_disable(mbim->not_port.notify);
1259 }
1260
1261 ret = config_ep_by_speed(cdev->gadget, f,
1262 mbim->not_port.notify);
1263 if (ret) {
1264 mbim->not_port.notify->desc = NULL;
1265 pr_err("Failed configuring notify ep %s: err %d\n",
1266 mbim->not_port.notify->name, ret);
1267 return ret;
1268 }
1269
1270 ret = usb_ep_enable(mbim->not_port.notify);
1271 if (ret) {
1272 pr_err("usb ep#%s enable failed, err#%d\n",
1273 mbim->not_port.notify->name, ret);
1274 return ret;
1275 }
1276 mbim->not_port.notify->driver_data = mbim;
1277
1278 /* Data interface has two altsettings, 0 and 1 */
1279 } else if (intf == mbim->data_id) {
1280
1281 pr_info("DATA_INTERFACE");
1282
1283 if (alt > 1)
1284 goto fail;
1285
1286 if (mbim->bam_port.in->driver_data) {
1287 pr_info("reset mbim\n");
1288 mbim_reset_values(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001289 }
1290
1291 /*
1292 * CDC Network only sends data in non-default altsettings.
1293 * Changing altsettings resets filters, statistics, etc.
1294 */
1295 if (alt == 1) {
1296 pr_info("Alt set 1, initialize ports");
1297
1298 if (!mbim->bam_port.in->desc) {
1299
1300 pr_info("Choose endpoints");
1301
1302 ret = config_ep_by_speed(cdev->gadget, f,
1303 mbim->bam_port.in);
1304 if (ret) {
1305 mbim->bam_port.in->desc = NULL;
1306 pr_err("IN ep %s failed: %d\n",
1307 mbim->bam_port.in->name, ret);
1308 return ret;
1309 }
1310
1311 pr_info("Set mbim port in_desc = 0x%p",
1312 mbim->bam_port.in->desc);
1313
1314 ret = config_ep_by_speed(cdev->gadget, f,
1315 mbim->bam_port.out);
1316 if (ret) {
1317 mbim->bam_port.out->desc = NULL;
1318 pr_err("OUT ep %s failed: %d\n",
1319 mbim->bam_port.out->name, ret);
1320 return ret;
1321 }
1322
1323 pr_info("Set mbim port out_desc = 0x%p",
1324 mbim->bam_port.out->desc);
Anna Perel6637bd72012-10-23 10:53:32 +02001325
1326 pr_debug("Activate mbim\n");
1327 mbim_bam_connect(mbim);
1328
Anna Perela8c991d2012-04-09 16:44:46 +03001329 } else {
1330 pr_info("PORTS already SET");
1331 }
Anna Perela8c991d2012-04-09 16:44:46 +03001332 }
1333
Bar Weinerb1c95f52012-12-23 09:09:13 +02001334 mbim->data_alt_int = alt;
Anna Perela8c991d2012-04-09 16:44:46 +03001335 spin_lock(&mbim->lock);
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001336 mbim->not_port.notify_state = MBIM_NOTIFY_RESPONSE_AVAILABLE;
Anna Perela8c991d2012-04-09 16:44:46 +03001337 spin_unlock(&mbim->lock);
1338 } else {
1339 goto fail;
1340 }
1341
1342 atomic_set(&mbim->online, 1);
1343
1344 pr_info("SET DEVICE ONLINE");
1345
1346 /* wakeup file threads */
1347 wake_up(&mbim->read_wq);
1348 wake_up(&mbim->write_wq);
1349
1350 return 0;
1351
1352fail:
1353 pr_err("ERROR: Illegal Interface");
1354 return -EINVAL;
1355}
1356
1357/*
1358 * Because the data interface supports multiple altsettings,
1359 * this MBIM function *MUST* implement a get_alt() method.
1360 */
1361static int mbim_get_alt(struct usb_function *f, unsigned intf)
1362{
1363 struct f_mbim *mbim = func_to_mbim(f);
1364
1365 if (intf == mbim->ctrl_id)
1366 return 0;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001367 else if (intf == mbim->data_id)
1368 return mbim->data_alt_int;
1369
1370 return -EINVAL;
Anna Perela8c991d2012-04-09 16:44:46 +03001371}
1372
1373static void mbim_disable(struct usb_function *f)
1374{
1375 struct f_mbim *mbim = func_to_mbim(f);
1376
1377 pr_info("SET DEVICE OFFLINE");
1378 atomic_set(&mbim->online, 0);
1379
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001380 mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +02001381
Anna Perel86ea7c92012-04-24 14:31:29 +03001382 mbim_clear_queues(mbim);
1383 mbim_reset_function_queue(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001384
1385 mbim_bam_disconnect(mbim);
1386
1387 if (mbim->not_port.notify->driver_data) {
1388 usb_ep_disable(mbim->not_port.notify);
1389 mbim->not_port.notify->driver_data = NULL;
1390 }
1391
Anna Perel68aeb172012-10-28 09:00:45 +02001392 atomic_set(&mbim->not_port.notify_count, 0);
1393
Anna Perela8c991d2012-04-09 16:44:46 +03001394 pr_info("mbim deactivated\n");
1395}
1396
Anna Perel557bf722012-09-20 11:16:35 +03001397#define MBIM_ACTIVE_PORT 0
1398
1399static void mbim_suspend(struct usb_function *f)
1400{
1401 pr_info("mbim suspended\n");
1402 bam_data_suspend(MBIM_ACTIVE_PORT);
1403}
1404
1405static void mbim_resume(struct usb_function *f)
1406{
1407 pr_info("mbim resumed\n");
1408 bam_data_resume(MBIM_ACTIVE_PORT);
1409}
1410
Anna Perela8c991d2012-04-09 16:44:46 +03001411/*---------------------- function driver setup/binding ---------------------*/
1412
1413static int
1414mbim_bind(struct usb_configuration *c, struct usb_function *f)
1415{
1416 struct usb_composite_dev *cdev = c->cdev;
1417 struct f_mbim *mbim = func_to_mbim(f);
1418 int status;
1419 struct usb_ep *ep;
1420
1421 pr_info("Enter");
1422
1423 mbim->cdev = cdev;
1424
1425 /* allocate instance-specific interface IDs */
1426 status = usb_interface_id(c, f);
1427 if (status < 0)
1428 goto fail;
1429 mbim->ctrl_id = status;
1430 mbim_iad_desc.bFirstInterface = status;
1431
1432 mbim_control_intf.bInterfaceNumber = status;
1433 mbim_union_desc.bMasterInterface0 = status;
1434
1435 status = usb_interface_id(c, f);
1436 if (status < 0)
1437 goto fail;
1438 mbim->data_id = status;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001439 mbim->data_alt_int = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001440
1441 mbim_data_nop_intf.bInterfaceNumber = status;
1442 mbim_data_intf.bInterfaceNumber = status;
1443 mbim_union_desc.bSlaveInterface0 = status;
1444
Anna Perel557bf722012-09-20 11:16:35 +03001445 mbim->bam_port.cdev = cdev;
Bar Weiner189bb3c2013-06-09 14:24:56 +03001446 mbim->bam_port.func = &mbim->function;
Anna Perel557bf722012-09-20 11:16:35 +03001447
Anna Perela8c991d2012-04-09 16:44:46 +03001448 status = -ENODEV;
1449
1450 /* allocate instance-specific endpoints */
1451 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_in_desc);
1452 if (!ep) {
1453 pr_err("usb epin autoconfig failed\n");
1454 goto fail;
1455 }
1456 pr_info("usb epin autoconfig succeeded\n");
1457 ep->driver_data = cdev; /* claim */
1458 mbim->bam_port.in = ep;
1459
1460 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_out_desc);
1461 if (!ep) {
1462 pr_err("usb epout autoconfig failed\n");
1463 goto fail;
1464 }
1465 pr_info("usb epout autoconfig succeeded\n");
1466 ep->driver_data = cdev; /* claim */
1467 mbim->bam_port.out = ep;
1468
1469 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_notify_desc);
1470 if (!ep) {
1471 pr_err("usb notify ep autoconfig failed\n");
1472 goto fail;
1473 }
1474 pr_info("usb notify ep autoconfig succeeded\n");
1475 mbim->not_port.notify = ep;
1476 ep->driver_data = cdev; /* claim */
1477
1478 status = -ENOMEM;
1479
1480 /* allocate notification request and buffer */
1481 mbim->not_port.notify_req = mbim_alloc_req(ep, NCM_STATUS_BYTECOUNT);
1482 if (!mbim->not_port.notify_req) {
1483 pr_info("failed to allocate notify request\n");
1484 goto fail;
1485 }
1486 pr_info("allocated notify ep request & request buffer\n");
1487
1488 mbim->not_port.notify_req->context = mbim;
1489 mbim->not_port.notify_req->complete = mbim_notify_complete;
1490
Anna Perelbb5f1452013-05-22 18:12:40 +03001491 if (mbim->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
1492 mbb_desc.wMaxSegmentSize = cpu_to_le16(0x800);
1493 else
1494 mbb_desc.wMaxSegmentSize = cpu_to_le16(0xfe0);
1495
Anna Perela8c991d2012-04-09 16:44:46 +03001496 /* copy descriptors, and track endpoint copies */
1497 f->descriptors = usb_copy_descriptors(mbim_fs_function);
1498 if (!f->descriptors)
1499 goto fail;
1500
1501 /*
1502 * support all relevant hardware speeds... we expect that when
1503 * hardware is dual speed, all bulk-capable endpoints work at
1504 * both speeds
1505 */
1506 if (gadget_is_dualspeed(c->cdev->gadget)) {
1507 hs_mbim_in_desc.bEndpointAddress =
1508 fs_mbim_in_desc.bEndpointAddress;
1509 hs_mbim_out_desc.bEndpointAddress =
1510 fs_mbim_out_desc.bEndpointAddress;
1511 hs_mbim_notify_desc.bEndpointAddress =
1512 fs_mbim_notify_desc.bEndpointAddress;
1513
1514 /* copy descriptors, and track endpoint copies */
1515 f->hs_descriptors = usb_copy_descriptors(mbim_hs_function);
1516 if (!f->hs_descriptors)
1517 goto fail;
1518 }
1519
Jack Pham2df2f702012-10-11 19:08:24 -07001520 /*
1521 * If MBIM is bound in a config other than the first, tell Windows
1522 * about it by returning the num as a string in the OS descriptor's
1523 * subCompatibleID field. Windows only supports up to config #4.
1524 */
1525 if (c->bConfigurationValue >= 2 && c->bConfigurationValue <= 4) {
1526 pr_debug("MBIM in configuration %d", c->bConfigurationValue);
1527 mbim_ext_config_desc.function.subCompatibleID[0] =
1528 c->bConfigurationValue + '0';
1529 }
1530
Anna Perela8c991d2012-04-09 16:44:46 +03001531 pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
1532 mbim->port_num,
1533 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
1534 mbim->bam_port.in->name, mbim->bam_port.out->name,
1535 mbim->not_port.notify->name);
1536
1537 return 0;
1538
1539fail:
1540 pr_err("%s failed to bind, err %d\n", f->name, status);
1541
1542 if (f->descriptors)
1543 usb_free_descriptors(f->descriptors);
1544
1545 if (mbim->not_port.notify_req) {
1546 kfree(mbim->not_port.notify_req->buf);
1547 usb_ep_free_request(mbim->not_port.notify,
1548 mbim->not_port.notify_req);
1549 }
1550
1551 /* we might as well release our claims on endpoints */
1552 if (mbim->not_port.notify)
1553 mbim->not_port.notify->driver_data = NULL;
1554 if (mbim->bam_port.out)
1555 mbim->bam_port.out->driver_data = NULL;
1556 if (mbim->bam_port.in)
1557 mbim->bam_port.in->driver_data = NULL;
1558
1559 return status;
1560}
1561
1562static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
1563{
1564 struct f_mbim *mbim = func_to_mbim(f);
1565
Bar Weiner189bb3c2013-06-09 14:24:56 +03001566 bam_data_destroy(mbim->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +03001567 if (gadget_is_dualspeed(c->cdev->gadget))
1568 usb_free_descriptors(f->hs_descriptors);
1569 usb_free_descriptors(f->descriptors);
1570
1571 kfree(mbim->not_port.notify_req->buf);
1572 usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
Jack Pham2df2f702012-10-11 19:08:24 -07001573
1574 mbim_ext_config_desc.function.subCompatibleID[0] = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001575}
1576
1577/**
1578 * mbim_bind_config - add MBIM link to a configuration
1579 * @c: the configuration to support the network link
1580 * Context: single threaded during gadget setup
1581 * Returns zero on success, else negative errno.
1582 */
Lena Salmandf7e7992013-03-15 09:46:27 +02001583int mbim_bind_config(struct usb_configuration *c, unsigned portno,
1584 char *xport_name)
Anna Perela8c991d2012-04-09 16:44:46 +03001585{
1586 struct f_mbim *mbim = NULL;
1587 int status = 0;
1588
1589 pr_info("port number %u", portno);
1590
1591 if (portno >= nr_mbim_ports) {
1592 pr_err("Can not add port %u. Max ports = %d",
1593 portno, nr_mbim_ports);
1594 return -ENODEV;
1595 }
1596
1597 status = mbim_bam_setup(nr_mbim_ports);
1598 if (status) {
1599 pr_err("bam setup failed");
1600 return status;
1601 }
1602
1603 /* maybe allocate device-global string IDs */
1604 if (mbim_string_defs[0].id == 0) {
1605
1606 /* control interface label */
1607 status = usb_string_id(c->cdev);
1608 if (status < 0)
1609 return status;
1610 mbim_string_defs[STRING_CTRL_IDX].id = status;
1611 mbim_control_intf.iInterface = status;
1612
1613 /* data interface label */
1614 status = usb_string_id(c->cdev);
1615 if (status < 0)
1616 return status;
1617 mbim_string_defs[STRING_DATA_IDX].id = status;
1618 mbim_data_nop_intf.iInterface = status;
1619 mbim_data_intf.iInterface = status;
1620 }
1621
1622 /* allocate and initialize one new instance */
1623 mbim = mbim_ports[0].port;
1624 if (!mbim) {
1625 pr_info("mbim struct not allocated");
1626 return -ENOMEM;
1627 }
1628
1629 mbim->cdev = c->cdev;
1630
Anna Perela8c991d2012-04-09 16:44:46 +03001631 mbim_reset_values(mbim);
1632
1633 mbim->function.name = "usb_mbim";
1634 mbim->function.strings = mbim_strings;
1635 mbim->function.bind = mbim_bind;
1636 mbim->function.unbind = mbim_unbind;
1637 mbim->function.set_alt = mbim_set_alt;
1638 mbim->function.get_alt = mbim_get_alt;
1639 mbim->function.setup = mbim_setup;
1640 mbim->function.disable = mbim_disable;
Anna Perel557bf722012-09-20 11:16:35 +03001641 mbim->function.suspend = mbim_suspend;
1642 mbim->function.resume = mbim_resume;
Lena Salmandf7e7992013-03-15 09:46:27 +02001643 mbim->xport = str_to_xport(xport_name);
1644
1645 if (mbim->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
1646 /* Use BAM2BAM by default if not IPA */
1647 mbim->xport = USB_GADGET_XPORT_BAM2BAM;
1648 } else {
1649 /* For IPA we use limit of 16 */
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001650 mbim_ntb_parameters.wNtbOutMaxDatagrams = 16;
Lena Salmandf7e7992013-03-15 09:46:27 +02001651 /* For IPA this is proven to give maximum throughput */
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001652 mbim_ntb_parameters.dwNtbInMaxSize =
Lena Salmandf7e7992013-03-15 09:46:27 +02001653 cpu_to_le32(NTB_DEFAULT_IN_SIZE_IPA);
Vamsi Krishna2aae5532013-05-22 12:11:51 -07001654 mbim_ntb_parameters.dwNtbOutMaxSize =
1655 cpu_to_le32(MBIM_NTB_OUT_SIZE_IPA);
1656 mbim_ntb_parameters.wNdpInDivisor = 1;
Lena Salmandf7e7992013-03-15 09:46:27 +02001657 }
Anna Perela8c991d2012-04-09 16:44:46 +03001658
1659 INIT_LIST_HEAD(&mbim->cpkt_req_q);
1660 INIT_LIST_HEAD(&mbim->cpkt_resp_q);
1661
1662 status = usb_add_function(c, &mbim->function);
1663
1664 pr_info("Exit status %d", status);
1665
1666 return status;
1667}
1668
1669/* ------------ MBIM DRIVER File Operations API for USER SPACE ------------ */
1670
1671static ssize_t
1672mbim_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
1673{
1674 struct f_mbim *dev = fp->private_data;
1675 struct ctrl_pkt *cpkt = NULL;
1676 int ret = 0;
1677
1678 pr_debug("Enter(%d)\n", count);
1679
1680 if (!dev) {
1681 pr_err("Received NULL mbim pointer\n");
1682 return -ENODEV;
1683 }
1684
1685 if (count > MBIM_BULK_BUFFER_SIZE) {
1686 pr_err("Buffer size is too big %d, should be at most %d\n",
1687 count, MBIM_BULK_BUFFER_SIZE);
1688 return -EINVAL;
1689 }
1690
1691 if (mbim_lock(&dev->read_excl)) {
1692 pr_err("Previous reading is not finished yet\n");
1693 return -EBUSY;
1694 }
1695
1696 /* block until mbim online */
1697 while (!(atomic_read(&dev->online) || atomic_read(&dev->error))) {
1698 pr_err("USB cable not connected. Wait.\n");
1699 ret = wait_event_interruptible(dev->read_wq,
1700 (atomic_read(&dev->online) ||
1701 atomic_read(&dev->error)));
1702 if (ret < 0) {
1703 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001704 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001705 }
1706 }
1707
1708 if (atomic_read(&dev->error)) {
1709 mbim_unlock(&dev->read_excl);
1710 return -EIO;
1711 }
1712
1713 while (list_empty(&dev->cpkt_req_q)) {
Anna Perel3747fdae2013-02-17 15:19:04 +02001714 pr_debug("Requests list is empty. Wait.\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001715 ret = wait_event_interruptible(dev->read_wq,
1716 !list_empty(&dev->cpkt_req_q));
1717 if (ret < 0) {
1718 pr_err("Waiting failed\n");
1719 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001720 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001721 }
1722 pr_debug("Received request packet\n");
1723 }
1724
1725 cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
1726 list);
1727 if (cpkt->len > count) {
1728 mbim_unlock(&dev->read_excl);
1729 pr_err("cpkt size too big:%d > buf size:%d\n",
1730 cpkt->len, count);
1731 return -ENOMEM;
1732 }
1733
1734 pr_debug("cpkt size:%d\n", cpkt->len);
1735
1736 list_del(&cpkt->list);
1737 mbim_unlock(&dev->read_excl);
1738
1739 ret = copy_to_user(buf, cpkt->buf, cpkt->len);
1740 if (ret) {
1741 pr_err("copy_to_user failed: err %d\n", ret);
Anna Perel96eea9d2012-12-09 14:08:04 +02001742 ret = -ENOMEM;
Anna Perela8c991d2012-04-09 16:44:46 +03001743 } else {
1744 pr_debug("copied %d bytes to user\n", cpkt->len);
1745 ret = cpkt->len;
1746 }
1747
1748 mbim_free_ctrl_pkt(cpkt);
1749
1750 return ret;
1751}
1752
1753static ssize_t
1754mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
1755{
1756 struct f_mbim *dev = fp->private_data;
1757 struct ctrl_pkt *cpkt = NULL;
1758 int ret = 0;
1759
1760 pr_debug("Enter(%d)", count);
1761
1762 if (!dev) {
1763 pr_err("Received NULL mbim pointer\n");
1764 return -ENODEV;
1765 }
1766
1767 if (!count) {
1768 pr_err("zero length ctrl pkt\n");
1769 return -ENODEV;
1770 }
1771
1772 if (count > MAX_CTRL_PKT_SIZE) {
1773 pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
1774 count, MAX_CTRL_PKT_SIZE);
1775 return -ENOMEM;
1776 }
1777
1778 if (mbim_lock(&dev->write_excl)) {
1779 pr_err("Previous writing not finished yet\n");
1780 return -EBUSY;
1781 }
1782
1783 if (!atomic_read(&dev->online)) {
1784 pr_err("USB cable not connected\n");
1785 mbim_unlock(&dev->write_excl);
1786 return -EPIPE;
1787 }
1788
1789 cpkt = mbim_alloc_ctrl_pkt(count, GFP_KERNEL);
1790 if (!cpkt) {
1791 pr_err("failed to allocate ctrl pkt\n");
1792 mbim_unlock(&dev->write_excl);
1793 return -ENOMEM;
1794 }
1795
1796 ret = copy_from_user(cpkt->buf, buf, count);
1797 if (ret) {
1798 pr_err("copy_from_user failed err:%d\n", ret);
1799 mbim_free_ctrl_pkt(cpkt);
1800 mbim_unlock(&dev->write_excl);
1801 return 0;
1802 }
1803
1804 fmbim_send_cpkt_response(dev, cpkt);
1805
1806 mbim_unlock(&dev->write_excl);
1807
1808 pr_debug("Exit(%d)", count);
1809
1810 return count;
Anna Perel89ad1212012-06-13 17:17:24 +03001811
Anna Perela8c991d2012-04-09 16:44:46 +03001812}
1813
1814static int mbim_open(struct inode *ip, struct file *fp)
1815{
1816 pr_info("Open mbim driver\n");
1817
1818 while (!_mbim_dev) {
1819 pr_err("mbim_dev not created yet\n");
1820 return -ENODEV;
1821 }
1822
1823 if (mbim_lock(&_mbim_dev->open_excl)) {
1824 pr_err("Already opened\n");
1825 return -EBUSY;
1826 }
1827
1828 pr_info("Lock mbim_dev->open_excl for open\n");
1829
1830 if (!atomic_read(&_mbim_dev->online))
1831 pr_err("USB cable not connected\n");
1832
Anna Perela8c991d2012-04-09 16:44:46 +03001833 fp->private_data = _mbim_dev;
1834
1835 atomic_set(&_mbim_dev->error, 0);
1836
Anna Perela8c991d2012-04-09 16:44:46 +03001837 pr_info("Exit, mbim file opened\n");
1838
1839 return 0;
1840}
1841
1842static int mbim_release(struct inode *ip, struct file *fp)
1843{
Anna Perela8c991d2012-04-09 16:44:46 +03001844 pr_info("Close mbim file");
1845
Anna Perela8c991d2012-04-09 16:44:46 +03001846 mbim_unlock(&_mbim_dev->open_excl);
1847
1848 return 0;
1849}
1850
1851static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
1852{
1853 struct f_mbim *mbim = fp->private_data;
1854 int ret = 0;
1855
Anna Perel20c91152012-10-30 16:26:44 +02001856 pr_debug("Received command %d", cmd);
Anna Perela8c991d2012-04-09 16:44:46 +03001857
1858 if (mbim_lock(&mbim->ioctl_excl))
1859 return -EBUSY;
1860
1861 switch (cmd) {
1862 case MBIM_GET_NTB_SIZE:
1863 ret = copy_to_user((void __user *)arg,
1864 &mbim->ntb_input_size, sizeof(mbim->ntb_input_size));
1865 if (ret) {
1866 pr_err("copying to user space failed");
1867 ret = -EFAULT;
1868 }
1869 pr_info("Sent NTB size %d", mbim->ntb_input_size);
1870 break;
1871 case MBIM_GET_DATAGRAM_COUNT:
1872 ret = copy_to_user((void __user *)arg,
1873 &mbim->ntb_max_datagrams,
1874 sizeof(mbim->ntb_max_datagrams));
1875 if (ret) {
1876 pr_err("copying to user space failed");
1877 ret = -EFAULT;
1878 }
1879 pr_info("Sent NTB datagrams count %d",
1880 mbim->ntb_max_datagrams);
1881 break;
1882 default:
1883 pr_err("wrong parameter");
1884 ret = -EINVAL;
1885 }
1886
1887 mbim_unlock(&mbim->ioctl_excl);
1888
1889 return ret;
1890}
1891
1892/* file operations for MBIM device /dev/android_mbim */
1893static const struct file_operations mbim_fops = {
1894 .owner = THIS_MODULE,
1895 .open = mbim_open,
1896 .release = mbim_release,
1897 .read = mbim_read,
1898 .write = mbim_write,
1899 .unlocked_ioctl = mbim_ioctl,
1900};
1901
1902static struct miscdevice mbim_device = {
1903 .minor = MISC_DYNAMIC_MINOR,
1904 .name = "android_mbim",
1905 .fops = &mbim_fops,
1906};
1907
1908static int mbim_init(int instances)
1909{
1910 int i;
1911 struct f_mbim *dev = NULL;
1912 int ret;
1913
1914 pr_info("initialize %d instances\n", instances);
1915
1916 if (instances > NR_MBIM_PORTS) {
1917 pr_err("Max-%d instances supported\n", NR_MBIM_PORTS);
1918 return -EINVAL;
1919 }
1920
1921 for (i = 0; i < instances; i++) {
1922 dev = kzalloc(sizeof(struct f_mbim), GFP_KERNEL);
1923 if (!dev) {
1924 pr_err("Failed to allocate mbim dev\n");
1925 ret = -ENOMEM;
1926 goto fail_probe;
1927 }
1928
1929 dev->port_num = i;
1930 spin_lock_init(&dev->lock);
1931 INIT_LIST_HEAD(&dev->cpkt_req_q);
1932 INIT_LIST_HEAD(&dev->cpkt_resp_q);
1933
1934 mbim_ports[i].port = dev;
1935 mbim_ports[i].port_num = i;
1936
1937 init_waitqueue_head(&dev->read_wq);
1938 init_waitqueue_head(&dev->write_wq);
1939
1940 atomic_set(&dev->open_excl, 0);
1941 atomic_set(&dev->ioctl_excl, 0);
1942 atomic_set(&dev->read_excl, 0);
1943 atomic_set(&dev->write_excl, 0);
1944
1945 nr_mbim_ports++;
1946
1947 }
1948
1949 _mbim_dev = dev;
1950 ret = misc_register(&mbim_device);
1951 if (ret) {
1952 pr_err("mbim driver failed to register");
1953 goto fail_probe;
1954 }
1955
1956 pr_info("Initialized %d ports\n", nr_mbim_ports);
1957
1958 return ret;
1959
1960fail_probe:
1961 pr_err("Failed");
1962 for (i = 0; i < nr_mbim_ports; i++) {
1963 kfree(mbim_ports[i].port);
1964 mbim_ports[i].port = NULL;
1965 }
1966
1967 return ret;
1968}
1969
1970static void fmbim_cleanup(void)
1971{
1972 int i = 0;
1973
1974 pr_info("Enter");
1975
1976 for (i = 0; i < nr_mbim_ports; i++) {
1977 kfree(mbim_ports[i].port);
1978 mbim_ports[i].port = NULL;
1979 }
1980 nr_mbim_ports = 0;
1981
1982 misc_deregister(&mbim_device);
1983
1984 _mbim_dev = NULL;
1985}
1986