blob: a32dd15b10e58bf029d1dde91120763fc22e9a9c [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 {
66 NCM_NOTIFY_NONE,
67 NCM_NOTIFY_CONNECT,
68 NCM_NOTIFY_SPEED,
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +020069 NCM_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
87 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
97 struct ndp_parser_opts *parser_opts;
98
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
142#define NTB_DEFAULT_IN_SIZE (0x4000)
143#define NTB_OUT_SIZE (0x1000)
144#define NDP_IN_DIVISOR (0x4)
145
146#define FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
147
148static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
149 .wLength = sizeof ntb_parameters,
150 .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
151 .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
152 .wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
153 .wNdpInPayloadRemainder = cpu_to_le16(0),
154 .wNdpInAlignment = cpu_to_le16(4),
155
156 .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
157 .wNdpOutDivisor = cpu_to_le16(4),
158 .wNdpOutPayloadRemainder = cpu_to_le16(0),
159 .wNdpOutAlignment = cpu_to_le16(4),
Anna Perelf99cd0c2012-05-03 13:30:26 +0300160 .wNtbOutMaxDatagrams = 0,
Anna Perela8c991d2012-04-09 16:44:46 +0300161};
162
163/*
164 * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
165 * packet, to simplify cancellation; and a big transfer interval, to
166 * waste less bandwidth.
167 */
168
169#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
170#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
171
172static struct usb_interface_assoc_descriptor mbim_iad_desc = {
173 .bLength = sizeof mbim_iad_desc,
174 .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
175
176 /* .bFirstInterface = DYNAMIC, */
177 .bInterfaceCount = 2, /* control + data */
178 .bFunctionClass = 2,
179 .bFunctionSubClass = 0x0e,
180 .bFunctionProtocol = 0,
181 /* .iFunction = DYNAMIC */
182};
183
184/* interface descriptor: */
185static struct usb_interface_descriptor mbim_control_intf = {
186 .bLength = sizeof mbim_control_intf,
187 .bDescriptorType = USB_DT_INTERFACE,
188
189 /* .bInterfaceNumber = DYNAMIC */
190 .bNumEndpoints = 1,
191 .bInterfaceClass = 0x02,
192 .bInterfaceSubClass = 0x0e,
193 .bInterfaceProtocol = 0,
194 /* .iInterface = DYNAMIC */
195};
196
197static struct usb_cdc_header_desc mbim_header_desc = {
198 .bLength = sizeof mbim_header_desc,
199 .bDescriptorType = USB_DT_CS_INTERFACE,
200 .bDescriptorSubType = USB_CDC_HEADER_TYPE,
201
202 .bcdCDC = cpu_to_le16(0x0110),
203};
204
205static struct usb_cdc_union_desc mbim_union_desc = {
206 .bLength = sizeof(mbim_union_desc),
207 .bDescriptorType = USB_DT_CS_INTERFACE,
208 .bDescriptorSubType = USB_CDC_UNION_TYPE,
209 /* .bMasterInterface0 = DYNAMIC */
210 /* .bSlaveInterface0 = DYNAMIC */
211};
212
213static struct usb_cdc_mbb_desc mbb_desc = {
214 .bLength = sizeof mbb_desc,
215 .bDescriptorType = USB_DT_CS_INTERFACE,
216 .bDescriptorSubType = USB_CDC_MBB_TYPE,
217
218 .bcdMbbVersion = cpu_to_le16(0x0100),
219
220 .wMaxControlMessage = cpu_to_le16(0x1000),
Anna Perel3354bdc2012-12-09 12:08:10 +0200221 .bNumberFilters = 0x20,
Anna Perela8c991d2012-04-09 16:44:46 +0300222 .bMaxFilterSize = 0x80,
Anna Perel26ae27c2012-05-23 18:07:31 +0300223 .wMaxSegmentSize = cpu_to_le16(0xfe0),
Anna Perela8c991d2012-04-09 16:44:46 +0300224 .bmNetworkCapabilities = 0x20,
225};
226
Bar Weiner38c3e642013-02-12 10:25:17 +0200227static struct usb_cdc_ext_mbb_desc ext_mbb_desc = {
228 .bLength = sizeof ext_mbb_desc,
229 .bDescriptorType = USB_DT_CS_INTERFACE,
230 .bDescriptorSubType = USB_CDC_EXT_MBB_TYPE,
231
232 .bcdMbbExtendedVersion = cpu_to_le16(0x0100),
233 .bMaxOutstandingCmdMsges = 64,
234 .wMTU = 1500,
235};
236
Anna Perela8c991d2012-04-09 16:44:46 +0300237/* the default data interface has no endpoints ... */
238static struct usb_interface_descriptor mbim_data_nop_intf = {
239 .bLength = sizeof mbim_data_nop_intf,
240 .bDescriptorType = USB_DT_INTERFACE,
241
242 /* .bInterfaceNumber = DYNAMIC */
243 .bAlternateSetting = 0,
244 .bNumEndpoints = 0,
245 .bInterfaceClass = 0x0a,
246 .bInterfaceSubClass = 0,
247 .bInterfaceProtocol = 0x02,
248 /* .iInterface = DYNAMIC */
249};
250
251/* ... but the "real" data interface has two bulk endpoints */
252static struct usb_interface_descriptor mbim_data_intf = {
253 .bLength = sizeof mbim_data_intf,
254 .bDescriptorType = USB_DT_INTERFACE,
255
256 /* .bInterfaceNumber = DYNAMIC */
257 .bAlternateSetting = 1,
258 .bNumEndpoints = 2,
259 .bInterfaceClass = 0x0a,
260 .bInterfaceSubClass = 0,
261 .bInterfaceProtocol = 0x02,
262 /* .iInterface = DYNAMIC */
263};
264
265/* full speed support: */
266
267static struct usb_endpoint_descriptor fs_mbim_notify_desc = {
268 .bLength = USB_DT_ENDPOINT_SIZE,
269 .bDescriptorType = USB_DT_ENDPOINT,
270
271 .bEndpointAddress = USB_DIR_IN,
272 .bmAttributes = USB_ENDPOINT_XFER_INT,
273 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
274 .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
275};
276
277static struct usb_endpoint_descriptor fs_mbim_in_desc = {
278 .bLength = USB_DT_ENDPOINT_SIZE,
279 .bDescriptorType = USB_DT_ENDPOINT,
280
281 .bEndpointAddress = USB_DIR_IN,
282 .bmAttributes = USB_ENDPOINT_XFER_BULK,
283};
284
285static struct usb_endpoint_descriptor fs_mbim_out_desc = {
286 .bLength = USB_DT_ENDPOINT_SIZE,
287 .bDescriptorType = USB_DT_ENDPOINT,
288
289 .bEndpointAddress = USB_DIR_OUT,
290 .bmAttributes = USB_ENDPOINT_XFER_BULK,
291};
292
293static struct usb_descriptor_header *mbim_fs_function[] = {
294 (struct usb_descriptor_header *) &mbim_iad_desc,
295 /* MBIM control descriptors */
296 (struct usb_descriptor_header *) &mbim_control_intf,
297 (struct usb_descriptor_header *) &mbim_header_desc,
Anna Perel555a7b22013-02-26 13:14:32 +0200298 (struct usb_descriptor_header *) &mbim_union_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300299 (struct usb_descriptor_header *) &mbb_desc,
Bar Weiner38c3e642013-02-12 10:25:17 +0200300 (struct usb_descriptor_header *) &ext_mbb_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300301 (struct usb_descriptor_header *) &fs_mbim_notify_desc,
302 /* data interface, altsettings 0 and 1 */
303 (struct usb_descriptor_header *) &mbim_data_nop_intf,
304 (struct usb_descriptor_header *) &mbim_data_intf,
305 (struct usb_descriptor_header *) &fs_mbim_in_desc,
306 (struct usb_descriptor_header *) &fs_mbim_out_desc,
307 NULL,
308};
309
310/* high speed support: */
311
312static struct usb_endpoint_descriptor hs_mbim_notify_desc = {
313 .bLength = USB_DT_ENDPOINT_SIZE,
314 .bDescriptorType = USB_DT_ENDPOINT,
315
316 .bEndpointAddress = USB_DIR_IN,
317 .bmAttributes = USB_ENDPOINT_XFER_INT,
318 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
319 .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
320};
321static struct usb_endpoint_descriptor hs_mbim_in_desc = {
322 .bLength = USB_DT_ENDPOINT_SIZE,
323 .bDescriptorType = USB_DT_ENDPOINT,
324
325 .bEndpointAddress = USB_DIR_IN,
326 .bmAttributes = USB_ENDPOINT_XFER_BULK,
327 .wMaxPacketSize = cpu_to_le16(512),
328};
329
330static struct usb_endpoint_descriptor hs_mbim_out_desc = {
331 .bLength = USB_DT_ENDPOINT_SIZE,
332 .bDescriptorType = USB_DT_ENDPOINT,
333
334 .bEndpointAddress = USB_DIR_OUT,
335 .bmAttributes = USB_ENDPOINT_XFER_BULK,
336 .wMaxPacketSize = cpu_to_le16(512),
337};
338
339static struct usb_descriptor_header *mbim_hs_function[] = {
340 (struct usb_descriptor_header *) &mbim_iad_desc,
341 /* MBIM control descriptors */
342 (struct usb_descriptor_header *) &mbim_control_intf,
343 (struct usb_descriptor_header *) &mbim_header_desc,
344 (struct usb_descriptor_header *) &mbb_desc,
Bar Weiner38c3e642013-02-12 10:25:17 +0200345 (struct usb_descriptor_header *) &ext_mbb_desc,
Anna Perela8c991d2012-04-09 16:44:46 +0300346 (struct usb_descriptor_header *) &hs_mbim_notify_desc,
347 /* data interface, altsettings 0 and 1 */
348 (struct usb_descriptor_header *) &mbim_data_nop_intf,
349 (struct usb_descriptor_header *) &mbim_data_intf,
350 (struct usb_descriptor_header *) &hs_mbim_in_desc,
351 (struct usb_descriptor_header *) &hs_mbim_out_desc,
352 NULL,
353};
354
355/* string descriptors: */
356
357#define STRING_CTRL_IDX 0
358#define STRING_DATA_IDX 1
359
360static struct usb_string mbim_string_defs[] = {
361 [STRING_CTRL_IDX].s = "MBIM Control",
362 [STRING_DATA_IDX].s = "MBIM Data",
363 { } /* end of list */
364};
365
366static struct usb_gadget_strings mbim_string_table = {
367 .language = 0x0409, /* en-us */
368 .strings = mbim_string_defs,
369};
370
371static struct usb_gadget_strings *mbim_strings[] = {
372 &mbim_string_table,
373 NULL,
374};
375
Jack Pham2df2f702012-10-11 19:08:24 -0700376/* Microsoft OS Descriptors */
377
378/*
379 * We specify our own bMS_VendorCode byte which Windows will use
380 * as the bRequest value in subsequent device get requests.
381 */
382#define MBIM_VENDOR_CODE 0xA5
383
384/* Microsoft OS String */
385static u8 mbim_os_string[] = {
386 18, /* sizeof(mtp_os_string) */
387 USB_DT_STRING,
388 /* Signature field: "MSFT100" */
389 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
390 /* vendor code */
391 MBIM_VENDOR_CODE,
392 /* padding */
393 0
394};
395
396/* Microsoft Extended Configuration Descriptor Header Section */
397struct mbim_ext_config_desc_header {
398 __le32 dwLength;
399 __u16 bcdVersion;
400 __le16 wIndex;
401 __u8 bCount;
402 __u8 reserved[7];
403};
404
405/* Microsoft Extended Configuration Descriptor Function Section */
406struct mbim_ext_config_desc_function {
407 __u8 bFirstInterfaceNumber;
408 __u8 bInterfaceCount;
409 __u8 compatibleID[8];
410 __u8 subCompatibleID[8];
411 __u8 reserved[6];
412};
413
414/* Microsoft Extended Configuration Descriptor */
415static struct {
416 struct mbim_ext_config_desc_header header;
417 struct mbim_ext_config_desc_function function;
418} mbim_ext_config_desc = {
419 .header = {
420 .dwLength = __constant_cpu_to_le32(sizeof mbim_ext_config_desc),
421 .bcdVersion = __constant_cpu_to_le16(0x0100),
422 .wIndex = __constant_cpu_to_le16(4),
423 .bCount = 1,
424 },
425 .function = {
426 .bFirstInterfaceNumber = 0,
427 .bInterfaceCount = 1,
428 .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' },
429 /* .subCompatibleID = DYNAMIC */
430 },
431};
432
Anna Perela8c991d2012-04-09 16:44:46 +0300433/*
434 * Here are options for the Datagram Pointer table (NDP) parser.
435 * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
436 * in NDP16 offsets and sizes fields are 1 16bit word wide,
437 * in NDP32 -- 2 16bit words wide. Also signatures are different.
438 * To make the parser code the same, put the differences in the structure,
439 * and switch pointers to the structures when the format is changed.
440 */
441
442struct ndp_parser_opts {
443 u32 nth_sign;
444 u32 ndp_sign;
445 unsigned nth_size;
446 unsigned ndp_size;
447 unsigned ndplen_align;
448 /* sizes in u16 units */
449 unsigned dgram_item_len; /* index or length */
450 unsigned block_length;
451 unsigned fp_index;
452 unsigned reserved1;
453 unsigned reserved2;
454 unsigned next_fp_index;
455};
456
457#define INIT_NDP16_OPTS { \
458 .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
459 .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
460 .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
461 .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
462 .ndplen_align = 4, \
463 .dgram_item_len = 1, \
464 .block_length = 1, \
465 .fp_index = 1, \
466 .reserved1 = 0, \
467 .reserved2 = 0, \
468 .next_fp_index = 1, \
469}
470
471#define INIT_NDP32_OPTS { \
472 .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
473 .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
474 .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
475 .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
476 .ndplen_align = 8, \
477 .dgram_item_len = 2, \
478 .block_length = 2, \
479 .fp_index = 2, \
480 .reserved1 = 1, \
481 .reserved2 = 2, \
482 .next_fp_index = 2, \
483}
484
485static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
486static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
487
488static inline int mbim_lock(atomic_t *excl)
489{
490 if (atomic_inc_return(excl) == 1) {
491 return 0;
492 } else {
493 atomic_dec(excl);
494 return -EBUSY;
495 }
496}
497
498static inline void mbim_unlock(atomic_t *excl)
499{
500 atomic_dec(excl);
501}
502
503static struct ctrl_pkt *mbim_alloc_ctrl_pkt(unsigned len, gfp_t flags)
504{
505 struct ctrl_pkt *pkt;
506
507 pkt = kzalloc(sizeof(struct ctrl_pkt), flags);
508 if (!pkt)
509 return ERR_PTR(-ENOMEM);
510
511 pkt->buf = kmalloc(len, flags);
512 if (!pkt->buf) {
513 kfree(pkt);
514 return ERR_PTR(-ENOMEM);
515 }
516 pkt->len = len;
517
518 return pkt;
519}
520
521static void mbim_free_ctrl_pkt(struct ctrl_pkt *pkt)
522{
523 if (pkt) {
524 kfree(pkt->buf);
525 kfree(pkt);
526 }
527}
528
529static struct usb_request *mbim_alloc_req(struct usb_ep *ep, int buffer_size)
530{
531 struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
532 if (!req)
533 return NULL;
534
535 req->buf = kmalloc(buffer_size, GFP_KERNEL);
536 if (!req->buf) {
537 usb_ep_free_request(ep, req);
538 return NULL;
539 }
540 req->length = buffer_size;
541 return req;
542}
543
544void fmbim_free_req(struct usb_ep *ep, struct usb_request *req)
545{
546 if (req) {
547 kfree(req->buf);
548 usb_ep_free_request(ep, req);
549 }
550}
551
552static void fmbim_ctrl_response_available(struct f_mbim *dev)
553{
554 struct usb_request *req = dev->not_port.notify_req;
555 struct usb_cdc_notification *event = NULL;
556 unsigned long flags;
557 int ret;
558
Anna Perel68aeb172012-10-28 09:00:45 +0200559 pr_debug("dev:%p portno#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300560
561 spin_lock_irqsave(&dev->lock, flags);
562
563 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200564 pr_err("dev:%p is not online\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300565 spin_unlock_irqrestore(&dev->lock, flags);
566 return;
567 }
568
569 if (!req) {
Anna Perel20c91152012-10-30 16:26:44 +0200570 pr_err("dev:%p req is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300571 spin_unlock_irqrestore(&dev->lock, flags);
572 return;
573 }
574
575 if (!req->buf) {
Anna Perel20c91152012-10-30 16:26:44 +0200576 pr_err("dev:%p req->buf is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300577 spin_unlock_irqrestore(&dev->lock, flags);
578 return;
579 }
580
Anna Perel68aeb172012-10-28 09:00:45 +0200581 if (atomic_inc_return(&dev->not_port.notify_count) != 1) {
582 pr_debug("delay ep_queue: notifications queue is busy[%d]",
583 atomic_read(&dev->not_port.notify_count));
584 spin_unlock_irqrestore(&dev->lock, flags);
585 return;
586 }
Anna Perela8c991d2012-04-09 16:44:46 +0300587
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200588 req->length = sizeof *event;
Anna Perela8c991d2012-04-09 16:44:46 +0300589 event = req->buf;
590 event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
591 | USB_RECIP_INTERFACE;
592 event->bNotificationType = USB_CDC_NOTIFY_RESPONSE_AVAILABLE;
593 event->wValue = cpu_to_le16(0);
594 event->wIndex = cpu_to_le16(dev->ctrl_id);
595 event->wLength = cpu_to_le16(0);
596 spin_unlock_irqrestore(&dev->lock, flags);
597
Anna Perela8c991d2012-04-09 16:44:46 +0300598 ret = usb_ep_queue(dev->not_port.notify,
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200599 req, GFP_ATOMIC);
Anna Perela8c991d2012-04-09 16:44:46 +0300600 if (ret) {
601 atomic_dec(&dev->not_port.notify_count);
602 pr_err("ep enqueue error %d\n", ret);
603 }
604
Anna Perel68aeb172012-10-28 09:00:45 +0200605 pr_debug("Successful Exit");
Anna Perela8c991d2012-04-09 16:44:46 +0300606}
607
608static int
609fmbim_send_cpkt_response(struct f_mbim *gr, struct ctrl_pkt *cpkt)
610{
611 struct f_mbim *dev = gr;
612 unsigned long flags;
613
614 if (!gr || !cpkt) {
615 pr_err("Invalid cpkt, dev:%p cpkt:%p\n",
616 gr, cpkt);
617 return -ENODEV;
618 }
619
Anna Perel20c91152012-10-30 16:26:44 +0200620 pr_debug("dev:%p port_num#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300621
622 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200623 pr_err("dev:%p is not connected\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300624 mbim_free_ctrl_pkt(cpkt);
625 return 0;
626 }
627
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200628 if (dev->not_port.notify_state != NCM_NOTIFY_RESPONSE_AVAILABLE) {
629 pr_err("dev:%p state=%d, recover!!\n", dev,
630 dev->not_port.notify_state);
631 mbim_free_ctrl_pkt(cpkt);
632 return 0;
633 }
634
Anna Perela8c991d2012-04-09 16:44:46 +0300635 spin_lock_irqsave(&dev->lock, flags);
Anna Perel40c550c2012-04-11 14:09:27 +0300636 list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
Anna Perela8c991d2012-04-09 16:44:46 +0300637 spin_unlock_irqrestore(&dev->lock, flags);
638
639 fmbim_ctrl_response_available(dev);
640
641 return 0;
642}
643
644/* ---------------------------- BAM INTERFACE ----------------------------- */
645
646static int mbim_bam_setup(int no_ports)
647{
648 int ret;
649
650 pr_info("no_ports:%d\n", no_ports);
651
652 ret = bam_data_setup(no_ports);
653 if (ret) {
654 pr_err("bam_data_setup failed err: %d\n", ret);
655 return ret;
656 }
657
658 pr_info("Initialized %d ports\n", no_ports);
659 return 0;
660}
661
662static int mbim_bam_connect(struct f_mbim *dev)
663{
664 int ret;
665
666 pr_info("dev:%p portno:%d\n", dev, dev->port_num);
667
Amit Blayf9b352b2013-03-04 15:01:40 +0200668 ret = bam_data_connect(&dev->bam_port, dev->port_num,
669 USB_GADGET_XPORT_BAM2BAM, dev->port_num, USB_FUNC_MBIM);
Anna Perela8c991d2012-04-09 16:44:46 +0300670 if (ret) {
671 pr_err("bam_data_setup failed: err:%d\n",
672 ret);
673 return ret;
674 } else {
675 pr_info("mbim bam connected\n");
676 }
677
678 return 0;
679}
680
681static int mbim_bam_disconnect(struct f_mbim *dev)
682{
683 pr_info("dev:%p port:%d. Do nothing.\n",
684 dev, dev->port_num);
685
Amit Blay51bebe92012-12-25 18:48:10 +0200686 bam_data_disconnect(&dev->bam_port, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300687
688 return 0;
689}
690
691/* -------------------------------------------------------------------------*/
692
693static inline void mbim_reset_values(struct f_mbim *mbim)
694{
695 mbim->parser_opts = &ndp16_opts;
696
697 mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
698
Anna Perela8c991d2012-04-09 16:44:46 +0300699 atomic_set(&mbim->online, 0);
700}
701
Anna Perel86ea7c92012-04-24 14:31:29 +0300702static void mbim_reset_function_queue(struct f_mbim *dev)
703{
704 struct ctrl_pkt *cpkt = NULL;
705
706 pr_debug("Queue empty packet for QBI");
707
708 spin_lock(&dev->lock);
709 if (!dev->is_open) {
710 pr_err("%s: mbim file handler %p is not open", __func__, dev);
711 spin_unlock(&dev->lock);
712 return;
713 }
714
715 cpkt = mbim_alloc_ctrl_pkt(0, GFP_ATOMIC);
716 if (!cpkt) {
717 pr_err("%s: Unable to allocate reset function pkt\n", __func__);
718 spin_unlock(&dev->lock);
719 return;
720 }
721
722 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
723 spin_unlock(&dev->lock);
724
725 pr_debug("%s: Wake up read queue", __func__);
726 wake_up(&dev->read_wq);
727}
728
729static void fmbim_reset_cmd_complete(struct usb_ep *ep, struct usb_request *req)
730{
731 struct f_mbim *dev = req->context;
732
733 mbim_reset_function_queue(dev);
734}
735
736static void mbim_clear_queues(struct f_mbim *mbim)
737{
738 struct ctrl_pkt *cpkt = NULL;
739 struct list_head *act, *tmp;
740
741 spin_lock(&mbim->lock);
742 list_for_each_safe(act, tmp, &mbim->cpkt_req_q) {
743 cpkt = list_entry(act, struct ctrl_pkt, list);
744 list_del(&cpkt->list);
745 mbim_free_ctrl_pkt(cpkt);
746 }
747 list_for_each_safe(act, tmp, &mbim->cpkt_resp_q) {
748 cpkt = list_entry(act, struct ctrl_pkt, list);
749 list_del(&cpkt->list);
750 mbim_free_ctrl_pkt(cpkt);
751 }
752 spin_unlock(&mbim->lock);
753}
754
Anna Perela8c991d2012-04-09 16:44:46 +0300755/*
756 * Context: mbim->lock held
757 */
758static void mbim_do_notify(struct f_mbim *mbim)
759{
760 struct usb_request *req = mbim->not_port.notify_req;
761 struct usb_cdc_notification *event;
762 struct usb_composite_dev *cdev = mbim->cdev;
763 __le32 *data;
764 int status;
765
Anna Perel20c91152012-10-30 16:26:44 +0200766 pr_debug("notify_state: %d", mbim->not_port.notify_state);
Anna Perela8c991d2012-04-09 16:44:46 +0300767
768 if (!req)
769 return;
770
771 event = req->buf;
772
773 switch (mbim->not_port.notify_state) {
774
775 case NCM_NOTIFY_NONE:
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200776 if (atomic_read(&mbim->not_port.notify_count) > 0)
777 pr_err("Pending notifications in NCM_NOTIFY_NONE\n");
778 else
779 pr_debug("No pending notifications\n");
780
781 return;
782
783 case NCM_NOTIFY_RESPONSE_AVAILABLE:
Anna Perel68aeb172012-10-28 09:00:45 +0200784 pr_debug("Notification %02x sent\n", event->bNotificationType);
785
786 if (atomic_read(&mbim->not_port.notify_count) <= 0) {
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200787 pr_debug("notify_response_avaliable: done");
Anna Perel68aeb172012-10-28 09:00:45 +0200788 return;
789 }
790
791 spin_unlock(&mbim->lock);
792 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
793 spin_lock(&mbim->lock);
794 if (status) {
795 atomic_dec(&mbim->not_port.notify_count);
796 pr_err("Queue notify request failed, err: %d", status);
797 }
798
Anna Perela8c991d2012-04-09 16:44:46 +0300799 return;
800
801 case NCM_NOTIFY_CONNECT:
802 event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
803 if (mbim->is_open)
804 event->wValue = cpu_to_le16(1);
805 else
806 event->wValue = cpu_to_le16(0);
807 event->wLength = 0;
808 req->length = sizeof *event;
809
810 pr_info("notify connect %s\n",
811 mbim->is_open ? "true" : "false");
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200812 mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
Anna Perela8c991d2012-04-09 16:44:46 +0300813 break;
814
815 case NCM_NOTIFY_SPEED:
816 event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
817 event->wValue = cpu_to_le16(0);
818 event->wLength = cpu_to_le16(8);
819 req->length = NCM_STATUS_BYTECOUNT;
820
821 /* SPEED_CHANGE data is up/down speeds in bits/sec */
822 data = req->buf + sizeof *event;
823 data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
824 data[1] = data[0];
825
826 pr_info("notify speed %d\n",
827 mbim_bitrate(cdev->gadget));
828 mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
829 break;
830 }
Anna Perel68aeb172012-10-28 09:00:45 +0200831
Anna Perela8c991d2012-04-09 16:44:46 +0300832 event->bmRequestType = 0xA1;
833 event->wIndex = cpu_to_le16(mbim->ctrl_id);
834
Anna Perela8c991d2012-04-09 16:44:46 +0300835 /*
836 * In double buffering if there is a space in FIFO,
837 * completion callback can be called right after the call,
838 * so unlocking
839 */
Anna Perel68aeb172012-10-28 09:00:45 +0200840 atomic_inc(&mbim->not_port.notify_count);
841 pr_debug("queue request: notify_count = %d",
842 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300843 spin_unlock(&mbim->lock);
844 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
845 spin_lock(&mbim->lock);
Anna Perel68aeb172012-10-28 09:00:45 +0200846 if (status) {
Anna Perela8c991d2012-04-09 16:44:46 +0300847 atomic_dec(&mbim->not_port.notify_count);
848 pr_err("usb_ep_queue failed, err: %d", status);
849 }
850}
851
852/*
853 * Context: mbim->lock held
854 */
855static void mbim_notify(struct f_mbim *mbim)
856{
857 /*
858 * If mbim_notify() is called before the second (CONNECT)
859 * notification is sent, then it will reset to send the SPEED
860 * notificaion again (and again, and again), but it's not a problem
861 */
Anna Perel20c91152012-10-30 16:26:44 +0200862 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300863
Ido Shayevitzf1510c02013-02-07 11:48:49 +0200864 mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
Anna Perela8c991d2012-04-09 16:44:46 +0300865 mbim_do_notify(mbim);
866}
867
868static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
869{
870 struct f_mbim *mbim = req->context;
871 struct usb_cdc_notification *event = req->buf;
872
Anna Perel68aeb172012-10-28 09:00:45 +0200873 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300874
875 spin_lock(&mbim->lock);
876 switch (req->status) {
877 case 0:
Anna Perel68aeb172012-10-28 09:00:45 +0200878 atomic_dec(&mbim->not_port.notify_count);
879 pr_debug("notify_count = %d",
880 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300881 break;
882
883 case -ECONNRESET:
884 case -ESHUTDOWN:
885 /* connection gone */
886 mbim->not_port.notify_state = NCM_NOTIFY_NONE;
887 atomic_set(&mbim->not_port.notify_count, 0);
888 pr_info("ESHUTDOWN/ECONNRESET, connection gone");
Anna Perel86ea7c92012-04-24 14:31:29 +0300889 spin_unlock(&mbim->lock);
890 mbim_clear_queues(mbim);
891 mbim_reset_function_queue(mbim);
Anna Perel89ad1212012-06-13 17:17:24 +0300892 spin_lock(&mbim->lock);
Anna Perela8c991d2012-04-09 16:44:46 +0300893 break;
894 default:
895 pr_err("Unknown event %02x --> %d\n",
896 event->bNotificationType, req->status);
897 break;
898 }
899
Anna Perela8c991d2012-04-09 16:44:46 +0300900 mbim_do_notify(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300901 spin_unlock(&mbim->lock);
902
Anna Perel20c91152012-10-30 16:26:44 +0200903 pr_debug("dev:%p Exit\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300904}
905
906static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
907{
908 /* now for SET_NTB_INPUT_SIZE only */
909 unsigned in_size = 0;
910 struct usb_function *f = req->context;
911 struct f_mbim *mbim = func_to_mbim(f);
912 struct mbim_ntb_input_size *ntb = NULL;
913
Anna Perel20c91152012-10-30 16:26:44 +0200914 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300915
916 req->context = NULL;
917 if (req->status || req->actual != req->length) {
918 pr_err("Bad control-OUT transfer\n");
919 goto invalid;
920 }
921
922 if (req->length == 4) {
923 in_size = get_unaligned_le32(req->buf);
924 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
925 in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
926 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
927 goto invalid;
928 }
929 } else if (req->length == 8) {
930 ntb = (struct mbim_ntb_input_size *)req->buf;
931 in_size = get_unaligned_le32(&(ntb->ntb_input_size));
932 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
933 in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
934 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
935 goto invalid;
936 }
937 mbim->ntb_max_datagrams =
938 get_unaligned_le16(&(ntb->ntb_max_datagrams));
939 } else {
940 pr_err("Illegal NTB length %d\n", in_size);
941 goto invalid;
942 }
943
Anna Perel20c91152012-10-30 16:26:44 +0200944 pr_debug("Set NTB INPUT SIZE %d\n", in_size);
Anna Perela8c991d2012-04-09 16:44:46 +0300945
946 mbim->ntb_input_size = in_size;
947 return;
948
949invalid:
950 usb_ep_set_halt(ep);
951
952 pr_err("dev:%p Failed\n", mbim);
953
954 return;
955}
956
957static void
958fmbim_cmd_complete(struct usb_ep *ep, struct usb_request *req)
959{
960 struct f_mbim *dev = req->context;
961 struct ctrl_pkt *cpkt = NULL;
962 int len = req->actual;
963
964 if (!dev) {
965 pr_err("mbim dev is null\n");
966 return;
967 }
968
969 if (req->status < 0) {
970 pr_err("mbim command error %d\n", req->status);
971 return;
972 }
973
Anna Perel20c91152012-10-30 16:26:44 +0200974 pr_debug("dev:%p port#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300975
Anna Perela8c991d2012-04-09 16:44:46 +0300976 cpkt = mbim_alloc_ctrl_pkt(len, GFP_ATOMIC);
977 if (!cpkt) {
978 pr_err("Unable to allocate ctrl pkt\n");
Anna Perela8c991d2012-04-09 16:44:46 +0300979 return;
980 }
981
Anna Perel20c91152012-10-30 16:26:44 +0200982 pr_debug("Add to cpkt_req_q packet with len = %d\n", len);
Anna Perela8c991d2012-04-09 16:44:46 +0300983 memcpy(cpkt->buf, req->buf, len);
Anna Perel20c91152012-10-30 16:26:44 +0200984
Anna Perel182ab572012-11-18 10:10:12 +0200985 spin_lock(&dev->lock);
986 if (!dev->is_open) {
987 pr_err("mbim file handler %p is not open", dev);
988 spin_unlock(&dev->lock);
989 mbim_free_ctrl_pkt(cpkt);
990 return;
991 }
992
Anna Perela8c991d2012-04-09 16:44:46 +0300993 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
994 spin_unlock(&dev->lock);
995
996 /* wakeup read thread */
Anna Perel20c91152012-10-30 16:26:44 +0200997 pr_debug("Wake up read queue");
Anna Perela8c991d2012-04-09 16:44:46 +0300998 wake_up(&dev->read_wq);
999
1000 return;
1001}
1002
1003static int
1004mbim_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
1005{
1006 struct f_mbim *mbim = func_to_mbim(f);
1007 struct usb_composite_dev *cdev = mbim->cdev;
1008 struct usb_request *req = cdev->req;
1009 struct ctrl_pkt *cpkt = NULL;
1010 int value = -EOPNOTSUPP;
1011 u16 w_index = le16_to_cpu(ctrl->wIndex);
1012 u16 w_value = le16_to_cpu(ctrl->wValue);
1013 u16 w_length = le16_to_cpu(ctrl->wLength);
1014
1015 /*
1016 * composite driver infrastructure handles everything except
1017 * CDC class messages; interface activation uses set_alt().
1018 */
1019
1020 if (!atomic_read(&mbim->online)) {
1021 pr_info("usb cable is not connected\n");
1022 return -ENOTCONN;
1023 }
1024
1025 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
1026 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1027 | USB_CDC_RESET_FUNCTION:
1028
Anna Perel20c91152012-10-30 16:26:44 +02001029 pr_debug("USB_CDC_RESET_FUNCTION");
Anna Perela8c991d2012-04-09 16:44:46 +03001030 value = 0;
Anna Perel86ea7c92012-04-24 14:31:29 +03001031 req->complete = fmbim_reset_cmd_complete;
1032 req->context = mbim;
Anna Perela8c991d2012-04-09 16:44:46 +03001033 break;
1034
1035 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1036 | USB_CDC_SEND_ENCAPSULATED_COMMAND:
1037
Anna Perel20c91152012-10-30 16:26:44 +02001038 pr_debug("USB_CDC_SEND_ENCAPSULATED_COMMAND");
Anna Perela8c991d2012-04-09 16:44:46 +03001039
1040 if (w_length > req->length) {
Anna Perel20c91152012-10-30 16:26:44 +02001041 pr_debug("w_length > req->length: %d > %d",
Anna Perela8c991d2012-04-09 16:44:46 +03001042 w_length, req->length);
1043 }
1044 value = w_length;
1045 req->complete = fmbim_cmd_complete;
1046 req->context = mbim;
1047 break;
1048
1049 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1050 | USB_CDC_GET_ENCAPSULATED_RESPONSE:
1051
Anna Perel20c91152012-10-30 16:26:44 +02001052 pr_debug("USB_CDC_GET_ENCAPSULATED_RESPONSE");
Anna Perela8c991d2012-04-09 16:44:46 +03001053
1054 if (w_value) {
1055 pr_err("w_length > 0: %d", w_length);
1056 break;
1057 }
1058
Anna Perel20c91152012-10-30 16:26:44 +02001059 pr_debug("req%02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001060 ctrl->bRequestType, ctrl->bRequest,
1061 w_value, w_index, w_length);
1062
1063 spin_lock(&mbim->lock);
1064 if (list_empty(&mbim->cpkt_resp_q)) {
1065 pr_err("ctrl resp queue empty\n");
1066 spin_unlock(&mbim->lock);
1067 break;
1068 }
1069
1070 cpkt = list_first_entry(&mbim->cpkt_resp_q,
1071 struct ctrl_pkt, list);
1072 list_del(&cpkt->list);
1073 spin_unlock(&mbim->lock);
1074
1075 value = min_t(unsigned, w_length, cpkt->len);
1076 memcpy(req->buf, cpkt->buf, value);
1077 mbim_free_ctrl_pkt(cpkt);
1078
Anna Perel20c91152012-10-30 16:26:44 +02001079 pr_debug("copied encapsulated_response %d bytes",
Anna Perela8c991d2012-04-09 16:44:46 +03001080 value);
1081
1082 break;
1083
1084 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1085 | USB_CDC_GET_NTB_PARAMETERS:
1086
Anna Perel20c91152012-10-30 16:26:44 +02001087 pr_debug("USB_CDC_GET_NTB_PARAMETERS");
Anna Perela8c991d2012-04-09 16:44:46 +03001088
1089 if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
1090 break;
1091
1092 value = w_length > sizeof ntb_parameters ?
1093 sizeof ntb_parameters : w_length;
1094 memcpy(req->buf, &ntb_parameters, value);
1095 break;
1096
1097 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1098 | USB_CDC_GET_NTB_INPUT_SIZE:
1099
Anna Perel20c91152012-10-30 16:26:44 +02001100 pr_debug("USB_CDC_GET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001101
1102 if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
1103 break;
1104
1105 put_unaligned_le32(mbim->ntb_input_size, req->buf);
1106 value = 4;
Anna Perel20c91152012-10-30 16:26:44 +02001107 pr_debug("Reply to host INPUT SIZE %d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001108 mbim->ntb_input_size);
1109 break;
1110
1111 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1112 | USB_CDC_SET_NTB_INPUT_SIZE:
1113
Anna Perel20c91152012-10-30 16:26:44 +02001114 pr_debug("USB_CDC_SET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001115
1116 if (w_length != 4 && w_length != 8) {
1117 pr_err("wrong NTB length %d", w_length);
1118 break;
1119 }
1120
1121 if (w_value != 0 || w_index != mbim->ctrl_id)
1122 break;
1123
1124 req->complete = mbim_ep0out_complete;
1125 req->length = w_length;
1126 req->context = f;
1127
1128 value = req->length;
1129 break;
1130
1131 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1132 | USB_CDC_GET_NTB_FORMAT:
1133 {
1134 uint16_t format;
1135
Anna Perel20c91152012-10-30 16:26:44 +02001136 pr_debug("USB_CDC_GET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001137
1138 if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
1139 break;
1140
1141 format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
1142 put_unaligned_le16(format, req->buf);
1143 value = 2;
Anna Perel20c91152012-10-30 16:26:44 +02001144 pr_debug("NTB FORMAT: sending %d\n", format);
Anna Perela8c991d2012-04-09 16:44:46 +03001145 break;
1146 }
1147
1148 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1149 | USB_CDC_SET_NTB_FORMAT:
1150 {
Anna Perel20c91152012-10-30 16:26:44 +02001151 pr_debug("USB_CDC_SET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001152
1153 if (w_length != 0 || w_index != mbim->ctrl_id)
1154 break;
1155 switch (w_value) {
1156 case 0x0000:
1157 mbim->parser_opts = &ndp16_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001158 pr_debug("NCM16 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001159 break;
1160 case 0x0001:
1161 mbim->parser_opts = &ndp32_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001162 pr_debug("NCM32 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001163 break;
1164 default:
1165 break;
1166 }
1167 value = 0;
1168 break;
1169 }
1170
1171 /* optional in mbim descriptor: */
1172 /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
1173 /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
1174
1175 default:
1176 pr_err("invalid control req: %02x.%02x v%04x i%04x l%d\n",
1177 ctrl->bRequestType, ctrl->bRequest,
1178 w_value, w_index, w_length);
1179 }
1180
1181 /* respond with data transfer or status phase? */
1182 if (value >= 0) {
Anna Perel20c91152012-10-30 16:26:44 +02001183 pr_debug("control request: %02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001184 ctrl->bRequestType, ctrl->bRequest,
1185 w_value, w_index, w_length);
Anna Perel2dfcaca2012-04-18 17:25:59 +03001186 req->zero = (value < w_length);
Anna Perela8c991d2012-04-09 16:44:46 +03001187 req->length = value;
1188 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1189 if (value < 0) {
1190 pr_err("queueing req failed: %02x.%02x, err %d\n",
1191 ctrl->bRequestType,
1192 ctrl->bRequest, value);
1193 }
1194 } else {
1195 pr_err("ctrl req err %d: %02x.%02x v%04x i%04x l%d\n",
1196 value, ctrl->bRequestType, ctrl->bRequest,
1197 w_value, w_index, w_length);
1198 }
1199
1200 /* device either stalls (value < 0) or reports success */
1201 return value;
1202}
1203
Jack Pham2df2f702012-10-11 19:08:24 -07001204/*
1205 * This function handles the Microsoft-specific OS descriptor control
1206 * requests that are issued by Windows host drivers to determine the
1207 * configuration containing the MBIM function.
1208 *
1209 * Unlike mbim_setup() this function handles two specific device requests,
1210 * and only when a configuration has not yet been selected.
1211 */
1212static int mbim_ctrlrequest(struct usb_composite_dev *cdev,
1213 const struct usb_ctrlrequest *ctrl)
1214{
1215 int value = -EOPNOTSUPP;
1216 u16 w_index = le16_to_cpu(ctrl->wIndex);
1217 u16 w_value = le16_to_cpu(ctrl->wValue);
1218 u16 w_length = le16_to_cpu(ctrl->wLength);
1219
1220 /* only respond to OS desciptors when no configuration selected */
1221 if (cdev->config || !mbim_ext_config_desc.function.subCompatibleID[0])
1222 return value;
1223
1224 pr_debug("%02x.%02x v%04x i%04x l%u",
1225 ctrl->bRequestType, ctrl->bRequest,
1226 w_value, w_index, w_length);
1227
1228 /* Handle MSFT OS string */
1229 if (ctrl->bRequestType ==
1230 (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
1231 && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
1232 && (w_value >> 8) == USB_DT_STRING
1233 && (w_value & 0xFF) == MBIM_OS_STRING_ID) {
1234
1235 value = (w_length < sizeof(mbim_os_string) ?
1236 w_length : sizeof(mbim_os_string));
1237 memcpy(cdev->req->buf, mbim_os_string, value);
1238
1239 } else if (ctrl->bRequestType ==
1240 (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
1241 && ctrl->bRequest == MBIM_VENDOR_CODE && w_index == 4) {
1242
1243 /* Handle Extended OS descriptor */
1244 value = (w_length < sizeof(mbim_ext_config_desc) ?
1245 w_length : sizeof(mbim_ext_config_desc));
1246 memcpy(cdev->req->buf, &mbim_ext_config_desc, value);
1247 }
1248
1249 /* respond with data transfer or status phase? */
1250 if (value >= 0) {
1251 int rc;
1252 cdev->req->zero = value < w_length;
1253 cdev->req->length = value;
1254 rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
1255 if (rc < 0)
1256 pr_err("response queue error: %d", rc);
1257 }
1258 return value;
1259}
1260
Anna Perela8c991d2012-04-09 16:44:46 +03001261static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
1262{
1263 struct f_mbim *mbim = func_to_mbim(f);
1264 struct usb_composite_dev *cdev = mbim->cdev;
1265 int ret = 0;
1266
1267 /* Control interface has only altsetting 0 */
1268 if (intf == mbim->ctrl_id) {
1269
1270 pr_info("CONTROL_INTERFACE");
1271
1272 if (alt != 0)
1273 goto fail;
1274
1275 if (mbim->not_port.notify->driver_data) {
1276 pr_info("reset mbim control %d\n", intf);
1277 usb_ep_disable(mbim->not_port.notify);
1278 }
1279
1280 ret = config_ep_by_speed(cdev->gadget, f,
1281 mbim->not_port.notify);
1282 if (ret) {
1283 mbim->not_port.notify->desc = NULL;
1284 pr_err("Failed configuring notify ep %s: err %d\n",
1285 mbim->not_port.notify->name, ret);
1286 return ret;
1287 }
1288
1289 ret = usb_ep_enable(mbim->not_port.notify);
1290 if (ret) {
1291 pr_err("usb ep#%s enable failed, err#%d\n",
1292 mbim->not_port.notify->name, ret);
1293 return ret;
1294 }
1295 mbim->not_port.notify->driver_data = mbim;
1296
1297 /* Data interface has two altsettings, 0 and 1 */
1298 } else if (intf == mbim->data_id) {
1299
1300 pr_info("DATA_INTERFACE");
1301
1302 if (alt > 1)
1303 goto fail;
1304
1305 if (mbim->bam_port.in->driver_data) {
1306 pr_info("reset mbim\n");
1307 mbim_reset_values(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001308 }
1309
1310 /*
1311 * CDC Network only sends data in non-default altsettings.
1312 * Changing altsettings resets filters, statistics, etc.
1313 */
1314 if (alt == 1) {
1315 pr_info("Alt set 1, initialize ports");
1316
1317 if (!mbim->bam_port.in->desc) {
1318
1319 pr_info("Choose endpoints");
1320
1321 ret = config_ep_by_speed(cdev->gadget, f,
1322 mbim->bam_port.in);
1323 if (ret) {
1324 mbim->bam_port.in->desc = NULL;
1325 pr_err("IN ep %s failed: %d\n",
1326 mbim->bam_port.in->name, ret);
1327 return ret;
1328 }
1329
1330 pr_info("Set mbim port in_desc = 0x%p",
1331 mbim->bam_port.in->desc);
1332
1333 ret = config_ep_by_speed(cdev->gadget, f,
1334 mbim->bam_port.out);
1335 if (ret) {
1336 mbim->bam_port.out->desc = NULL;
1337 pr_err("OUT ep %s failed: %d\n",
1338 mbim->bam_port.out->name, ret);
1339 return ret;
1340 }
1341
1342 pr_info("Set mbim port out_desc = 0x%p",
1343 mbim->bam_port.out->desc);
Anna Perel6637bd72012-10-23 10:53:32 +02001344
1345 pr_debug("Activate mbim\n");
1346 mbim_bam_connect(mbim);
1347
Anna Perela8c991d2012-04-09 16:44:46 +03001348 } else {
1349 pr_info("PORTS already SET");
1350 }
Anna Perela8c991d2012-04-09 16:44:46 +03001351 }
1352
Bar Weinerb1c95f52012-12-23 09:09:13 +02001353 mbim->data_alt_int = alt;
Anna Perela8c991d2012-04-09 16:44:46 +03001354 spin_lock(&mbim->lock);
1355 mbim_notify(mbim);
1356 spin_unlock(&mbim->lock);
1357 } else {
1358 goto fail;
1359 }
1360
1361 atomic_set(&mbim->online, 1);
1362
1363 pr_info("SET DEVICE ONLINE");
1364
1365 /* wakeup file threads */
1366 wake_up(&mbim->read_wq);
1367 wake_up(&mbim->write_wq);
1368
1369 return 0;
1370
1371fail:
1372 pr_err("ERROR: Illegal Interface");
1373 return -EINVAL;
1374}
1375
1376/*
1377 * Because the data interface supports multiple altsettings,
1378 * this MBIM function *MUST* implement a get_alt() method.
1379 */
1380static int mbim_get_alt(struct usb_function *f, unsigned intf)
1381{
1382 struct f_mbim *mbim = func_to_mbim(f);
1383
1384 if (intf == mbim->ctrl_id)
1385 return 0;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001386 else if (intf == mbim->data_id)
1387 return mbim->data_alt_int;
1388
1389 return -EINVAL;
Anna Perela8c991d2012-04-09 16:44:46 +03001390}
1391
1392static void mbim_disable(struct usb_function *f)
1393{
1394 struct f_mbim *mbim = func_to_mbim(f);
1395
1396 pr_info("SET DEVICE OFFLINE");
1397 atomic_set(&mbim->online, 0);
1398
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +02001399 mbim->not_port.notify_state = NCM_NOTIFY_NONE;
1400
Anna Perel86ea7c92012-04-24 14:31:29 +03001401 mbim_clear_queues(mbim);
1402 mbim_reset_function_queue(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001403
1404 mbim_bam_disconnect(mbim);
1405
1406 if (mbim->not_port.notify->driver_data) {
1407 usb_ep_disable(mbim->not_port.notify);
1408 mbim->not_port.notify->driver_data = NULL;
1409 }
1410
Anna Perel68aeb172012-10-28 09:00:45 +02001411 atomic_set(&mbim->not_port.notify_count, 0);
1412
Anna Perela8c991d2012-04-09 16:44:46 +03001413 pr_info("mbim deactivated\n");
1414}
1415
Anna Perel557bf722012-09-20 11:16:35 +03001416#define MBIM_ACTIVE_PORT 0
1417
1418static void mbim_suspend(struct usb_function *f)
1419{
1420 pr_info("mbim suspended\n");
1421 bam_data_suspend(MBIM_ACTIVE_PORT);
1422}
1423
1424static void mbim_resume(struct usb_function *f)
1425{
1426 pr_info("mbim resumed\n");
1427 bam_data_resume(MBIM_ACTIVE_PORT);
1428}
1429
Anna Perela8c991d2012-04-09 16:44:46 +03001430/*---------------------- function driver setup/binding ---------------------*/
1431
1432static int
1433mbim_bind(struct usb_configuration *c, struct usb_function *f)
1434{
1435 struct usb_composite_dev *cdev = c->cdev;
1436 struct f_mbim *mbim = func_to_mbim(f);
1437 int status;
1438 struct usb_ep *ep;
1439
1440 pr_info("Enter");
1441
1442 mbim->cdev = cdev;
1443
1444 /* allocate instance-specific interface IDs */
1445 status = usb_interface_id(c, f);
1446 if (status < 0)
1447 goto fail;
1448 mbim->ctrl_id = status;
1449 mbim_iad_desc.bFirstInterface = status;
1450
1451 mbim_control_intf.bInterfaceNumber = status;
1452 mbim_union_desc.bMasterInterface0 = status;
1453
1454 status = usb_interface_id(c, f);
1455 if (status < 0)
1456 goto fail;
1457 mbim->data_id = status;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001458 mbim->data_alt_int = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001459
1460 mbim_data_nop_intf.bInterfaceNumber = status;
1461 mbim_data_intf.bInterfaceNumber = status;
1462 mbim_union_desc.bSlaveInterface0 = status;
1463
Anna Perel557bf722012-09-20 11:16:35 +03001464 mbim->bam_port.cdev = cdev;
1465
Anna Perela8c991d2012-04-09 16:44:46 +03001466 status = -ENODEV;
1467
1468 /* allocate instance-specific endpoints */
1469 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_in_desc);
1470 if (!ep) {
1471 pr_err("usb epin autoconfig failed\n");
1472 goto fail;
1473 }
1474 pr_info("usb epin autoconfig succeeded\n");
1475 ep->driver_data = cdev; /* claim */
1476 mbim->bam_port.in = ep;
1477
1478 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_out_desc);
1479 if (!ep) {
1480 pr_err("usb epout autoconfig failed\n");
1481 goto fail;
1482 }
1483 pr_info("usb epout autoconfig succeeded\n");
1484 ep->driver_data = cdev; /* claim */
1485 mbim->bam_port.out = ep;
1486
1487 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_notify_desc);
1488 if (!ep) {
1489 pr_err("usb notify ep autoconfig failed\n");
1490 goto fail;
1491 }
1492 pr_info("usb notify ep autoconfig succeeded\n");
1493 mbim->not_port.notify = ep;
1494 ep->driver_data = cdev; /* claim */
1495
1496 status = -ENOMEM;
1497
1498 /* allocate notification request and buffer */
1499 mbim->not_port.notify_req = mbim_alloc_req(ep, NCM_STATUS_BYTECOUNT);
1500 if (!mbim->not_port.notify_req) {
1501 pr_info("failed to allocate notify request\n");
1502 goto fail;
1503 }
1504 pr_info("allocated notify ep request & request buffer\n");
1505
1506 mbim->not_port.notify_req->context = mbim;
1507 mbim->not_port.notify_req->complete = mbim_notify_complete;
1508
1509 /* copy descriptors, and track endpoint copies */
1510 f->descriptors = usb_copy_descriptors(mbim_fs_function);
1511 if (!f->descriptors)
1512 goto fail;
1513
1514 /*
1515 * support all relevant hardware speeds... we expect that when
1516 * hardware is dual speed, all bulk-capable endpoints work at
1517 * both speeds
1518 */
1519 if (gadget_is_dualspeed(c->cdev->gadget)) {
1520 hs_mbim_in_desc.bEndpointAddress =
1521 fs_mbim_in_desc.bEndpointAddress;
1522 hs_mbim_out_desc.bEndpointAddress =
1523 fs_mbim_out_desc.bEndpointAddress;
1524 hs_mbim_notify_desc.bEndpointAddress =
1525 fs_mbim_notify_desc.bEndpointAddress;
1526
1527 /* copy descriptors, and track endpoint copies */
1528 f->hs_descriptors = usb_copy_descriptors(mbim_hs_function);
1529 if (!f->hs_descriptors)
1530 goto fail;
1531 }
1532
Jack Pham2df2f702012-10-11 19:08:24 -07001533 /*
1534 * If MBIM is bound in a config other than the first, tell Windows
1535 * about it by returning the num as a string in the OS descriptor's
1536 * subCompatibleID field. Windows only supports up to config #4.
1537 */
1538 if (c->bConfigurationValue >= 2 && c->bConfigurationValue <= 4) {
1539 pr_debug("MBIM in configuration %d", c->bConfigurationValue);
1540 mbim_ext_config_desc.function.subCompatibleID[0] =
1541 c->bConfigurationValue + '0';
1542 }
1543
Anna Perela8c991d2012-04-09 16:44:46 +03001544 pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
1545 mbim->port_num,
1546 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
1547 mbim->bam_port.in->name, mbim->bam_port.out->name,
1548 mbim->not_port.notify->name);
1549
1550 return 0;
1551
1552fail:
1553 pr_err("%s failed to bind, err %d\n", f->name, status);
1554
1555 if (f->descriptors)
1556 usb_free_descriptors(f->descriptors);
1557
1558 if (mbim->not_port.notify_req) {
1559 kfree(mbim->not_port.notify_req->buf);
1560 usb_ep_free_request(mbim->not_port.notify,
1561 mbim->not_port.notify_req);
1562 }
1563
1564 /* we might as well release our claims on endpoints */
1565 if (mbim->not_port.notify)
1566 mbim->not_port.notify->driver_data = NULL;
1567 if (mbim->bam_port.out)
1568 mbim->bam_port.out->driver_data = NULL;
1569 if (mbim->bam_port.in)
1570 mbim->bam_port.in->driver_data = NULL;
1571
1572 return status;
1573}
1574
1575static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
1576{
1577 struct f_mbim *mbim = func_to_mbim(f);
1578
1579 if (gadget_is_dualspeed(c->cdev->gadget))
1580 usb_free_descriptors(f->hs_descriptors);
1581 usb_free_descriptors(f->descriptors);
1582
1583 kfree(mbim->not_port.notify_req->buf);
1584 usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
Jack Pham2df2f702012-10-11 19:08:24 -07001585
1586 mbim_ext_config_desc.function.subCompatibleID[0] = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001587}
1588
1589/**
1590 * mbim_bind_config - add MBIM link to a configuration
1591 * @c: the configuration to support the network link
1592 * Context: single threaded during gadget setup
1593 * Returns zero on success, else negative errno.
1594 */
1595int mbim_bind_config(struct usb_configuration *c, unsigned portno)
1596{
1597 struct f_mbim *mbim = NULL;
1598 int status = 0;
1599
1600 pr_info("port number %u", portno);
1601
1602 if (portno >= nr_mbim_ports) {
1603 pr_err("Can not add port %u. Max ports = %d",
1604 portno, nr_mbim_ports);
1605 return -ENODEV;
1606 }
1607
1608 status = mbim_bam_setup(nr_mbim_ports);
1609 if (status) {
1610 pr_err("bam setup failed");
1611 return status;
1612 }
1613
1614 /* maybe allocate device-global string IDs */
1615 if (mbim_string_defs[0].id == 0) {
1616
1617 /* control interface label */
1618 status = usb_string_id(c->cdev);
1619 if (status < 0)
1620 return status;
1621 mbim_string_defs[STRING_CTRL_IDX].id = status;
1622 mbim_control_intf.iInterface = status;
1623
1624 /* data interface label */
1625 status = usb_string_id(c->cdev);
1626 if (status < 0)
1627 return status;
1628 mbim_string_defs[STRING_DATA_IDX].id = status;
1629 mbim_data_nop_intf.iInterface = status;
1630 mbim_data_intf.iInterface = status;
1631 }
1632
1633 /* allocate and initialize one new instance */
1634 mbim = mbim_ports[0].port;
1635 if (!mbim) {
1636 pr_info("mbim struct not allocated");
1637 return -ENOMEM;
1638 }
1639
1640 mbim->cdev = c->cdev;
1641
Anna Perela8c991d2012-04-09 16:44:46 +03001642 mbim_reset_values(mbim);
1643
1644 mbim->function.name = "usb_mbim";
1645 mbim->function.strings = mbim_strings;
1646 mbim->function.bind = mbim_bind;
1647 mbim->function.unbind = mbim_unbind;
1648 mbim->function.set_alt = mbim_set_alt;
1649 mbim->function.get_alt = mbim_get_alt;
1650 mbim->function.setup = mbim_setup;
1651 mbim->function.disable = mbim_disable;
Anna Perel557bf722012-09-20 11:16:35 +03001652 mbim->function.suspend = mbim_suspend;
1653 mbim->function.resume = mbim_resume;
Anna Perela8c991d2012-04-09 16:44:46 +03001654
1655 INIT_LIST_HEAD(&mbim->cpkt_req_q);
1656 INIT_LIST_HEAD(&mbim->cpkt_resp_q);
1657
1658 status = usb_add_function(c, &mbim->function);
1659
1660 pr_info("Exit status %d", status);
1661
1662 return status;
1663}
1664
1665/* ------------ MBIM DRIVER File Operations API for USER SPACE ------------ */
1666
1667static ssize_t
1668mbim_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
1669{
1670 struct f_mbim *dev = fp->private_data;
1671 struct ctrl_pkt *cpkt = NULL;
1672 int ret = 0;
1673
1674 pr_debug("Enter(%d)\n", count);
1675
1676 if (!dev) {
1677 pr_err("Received NULL mbim pointer\n");
1678 return -ENODEV;
1679 }
1680
1681 if (count > MBIM_BULK_BUFFER_SIZE) {
1682 pr_err("Buffer size is too big %d, should be at most %d\n",
1683 count, MBIM_BULK_BUFFER_SIZE);
1684 return -EINVAL;
1685 }
1686
1687 if (mbim_lock(&dev->read_excl)) {
1688 pr_err("Previous reading is not finished yet\n");
1689 return -EBUSY;
1690 }
1691
1692 /* block until mbim online */
1693 while (!(atomic_read(&dev->online) || atomic_read(&dev->error))) {
1694 pr_err("USB cable not connected. Wait.\n");
1695 ret = wait_event_interruptible(dev->read_wq,
1696 (atomic_read(&dev->online) ||
1697 atomic_read(&dev->error)));
1698 if (ret < 0) {
1699 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001700 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001701 }
1702 }
1703
1704 if (atomic_read(&dev->error)) {
1705 mbim_unlock(&dev->read_excl);
1706 return -EIO;
1707 }
1708
1709 while (list_empty(&dev->cpkt_req_q)) {
Anna Perel3747fdae2013-02-17 15:19:04 +02001710 pr_debug("Requests list is empty. Wait.\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001711 ret = wait_event_interruptible(dev->read_wq,
1712 !list_empty(&dev->cpkt_req_q));
1713 if (ret < 0) {
1714 pr_err("Waiting failed\n");
1715 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001716 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001717 }
1718 pr_debug("Received request packet\n");
1719 }
1720
1721 cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
1722 list);
1723 if (cpkt->len > count) {
1724 mbim_unlock(&dev->read_excl);
1725 pr_err("cpkt size too big:%d > buf size:%d\n",
1726 cpkt->len, count);
1727 return -ENOMEM;
1728 }
1729
1730 pr_debug("cpkt size:%d\n", cpkt->len);
1731
1732 list_del(&cpkt->list);
1733 mbim_unlock(&dev->read_excl);
1734
1735 ret = copy_to_user(buf, cpkt->buf, cpkt->len);
1736 if (ret) {
1737 pr_err("copy_to_user failed: err %d\n", ret);
Anna Perel96eea9d2012-12-09 14:08:04 +02001738 ret = -ENOMEM;
Anna Perela8c991d2012-04-09 16:44:46 +03001739 } else {
1740 pr_debug("copied %d bytes to user\n", cpkt->len);
1741 ret = cpkt->len;
1742 }
1743
1744 mbim_free_ctrl_pkt(cpkt);
1745
1746 return ret;
1747}
1748
1749static ssize_t
1750mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
1751{
1752 struct f_mbim *dev = fp->private_data;
1753 struct ctrl_pkt *cpkt = NULL;
1754 int ret = 0;
1755
1756 pr_debug("Enter(%d)", count);
1757
1758 if (!dev) {
1759 pr_err("Received NULL mbim pointer\n");
1760 return -ENODEV;
1761 }
1762
1763 if (!count) {
1764 pr_err("zero length ctrl pkt\n");
1765 return -ENODEV;
1766 }
1767
1768 if (count > MAX_CTRL_PKT_SIZE) {
1769 pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
1770 count, MAX_CTRL_PKT_SIZE);
1771 return -ENOMEM;
1772 }
1773
1774 if (mbim_lock(&dev->write_excl)) {
1775 pr_err("Previous writing not finished yet\n");
1776 return -EBUSY;
1777 }
1778
1779 if (!atomic_read(&dev->online)) {
1780 pr_err("USB cable not connected\n");
1781 mbim_unlock(&dev->write_excl);
1782 return -EPIPE;
1783 }
1784
1785 cpkt = mbim_alloc_ctrl_pkt(count, GFP_KERNEL);
1786 if (!cpkt) {
1787 pr_err("failed to allocate ctrl pkt\n");
1788 mbim_unlock(&dev->write_excl);
1789 return -ENOMEM;
1790 }
1791
1792 ret = copy_from_user(cpkt->buf, buf, count);
1793 if (ret) {
1794 pr_err("copy_from_user failed err:%d\n", ret);
1795 mbim_free_ctrl_pkt(cpkt);
1796 mbim_unlock(&dev->write_excl);
1797 return 0;
1798 }
1799
1800 fmbim_send_cpkt_response(dev, cpkt);
1801
1802 mbim_unlock(&dev->write_excl);
1803
1804 pr_debug("Exit(%d)", count);
1805
1806 return count;
Anna Perel89ad1212012-06-13 17:17:24 +03001807
Anna Perela8c991d2012-04-09 16:44:46 +03001808}
1809
1810static int mbim_open(struct inode *ip, struct file *fp)
1811{
1812 pr_info("Open mbim driver\n");
1813
1814 while (!_mbim_dev) {
1815 pr_err("mbim_dev not created yet\n");
1816 return -ENODEV;
1817 }
1818
1819 if (mbim_lock(&_mbim_dev->open_excl)) {
1820 pr_err("Already opened\n");
1821 return -EBUSY;
1822 }
1823
1824 pr_info("Lock mbim_dev->open_excl for open\n");
1825
1826 if (!atomic_read(&_mbim_dev->online))
1827 pr_err("USB cable not connected\n");
1828
Anna Perela8c991d2012-04-09 16:44:46 +03001829 fp->private_data = _mbim_dev;
1830
1831 atomic_set(&_mbim_dev->error, 0);
1832
1833 spin_lock(&_mbim_dev->lock);
1834 _mbim_dev->is_open = true;
Anna Perela8c991d2012-04-09 16:44:46 +03001835 spin_unlock(&_mbim_dev->lock);
1836
1837 pr_info("Exit, mbim file opened\n");
1838
1839 return 0;
1840}
1841
1842static int mbim_release(struct inode *ip, struct file *fp)
1843{
1844 struct f_mbim *mbim = fp->private_data;
1845
1846 pr_info("Close mbim file");
1847
1848 spin_lock(&mbim->lock);
1849 mbim->is_open = false;
Anna Perela8c991d2012-04-09 16:44:46 +03001850 spin_unlock(&mbim->lock);
1851
Anna Perela8c991d2012-04-09 16:44:46 +03001852 mbim_unlock(&_mbim_dev->open_excl);
1853
1854 return 0;
1855}
1856
1857static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
1858{
1859 struct f_mbim *mbim = fp->private_data;
1860 int ret = 0;
1861
Anna Perel20c91152012-10-30 16:26:44 +02001862 pr_debug("Received command %d", cmd);
Anna Perela8c991d2012-04-09 16:44:46 +03001863
1864 if (mbim_lock(&mbim->ioctl_excl))
1865 return -EBUSY;
1866
1867 switch (cmd) {
1868 case MBIM_GET_NTB_SIZE:
1869 ret = copy_to_user((void __user *)arg,
1870 &mbim->ntb_input_size, sizeof(mbim->ntb_input_size));
1871 if (ret) {
1872 pr_err("copying to user space failed");
1873 ret = -EFAULT;
1874 }
1875 pr_info("Sent NTB size %d", mbim->ntb_input_size);
1876 break;
1877 case MBIM_GET_DATAGRAM_COUNT:
1878 ret = copy_to_user((void __user *)arg,
1879 &mbim->ntb_max_datagrams,
1880 sizeof(mbim->ntb_max_datagrams));
1881 if (ret) {
1882 pr_err("copying to user space failed");
1883 ret = -EFAULT;
1884 }
1885 pr_info("Sent NTB datagrams count %d",
1886 mbim->ntb_max_datagrams);
1887 break;
1888 default:
1889 pr_err("wrong parameter");
1890 ret = -EINVAL;
1891 }
1892
1893 mbim_unlock(&mbim->ioctl_excl);
1894
1895 return ret;
1896}
1897
1898/* file operations for MBIM device /dev/android_mbim */
1899static const struct file_operations mbim_fops = {
1900 .owner = THIS_MODULE,
1901 .open = mbim_open,
1902 .release = mbim_release,
1903 .read = mbim_read,
1904 .write = mbim_write,
1905 .unlocked_ioctl = mbim_ioctl,
1906};
1907
1908static struct miscdevice mbim_device = {
1909 .minor = MISC_DYNAMIC_MINOR,
1910 .name = "android_mbim",
1911 .fops = &mbim_fops,
1912};
1913
1914static int mbim_init(int instances)
1915{
1916 int i;
1917 struct f_mbim *dev = NULL;
1918 int ret;
1919
1920 pr_info("initialize %d instances\n", instances);
1921
1922 if (instances > NR_MBIM_PORTS) {
1923 pr_err("Max-%d instances supported\n", NR_MBIM_PORTS);
1924 return -EINVAL;
1925 }
1926
1927 for (i = 0; i < instances; i++) {
1928 dev = kzalloc(sizeof(struct f_mbim), GFP_KERNEL);
1929 if (!dev) {
1930 pr_err("Failed to allocate mbim dev\n");
1931 ret = -ENOMEM;
1932 goto fail_probe;
1933 }
1934
1935 dev->port_num = i;
1936 spin_lock_init(&dev->lock);
1937 INIT_LIST_HEAD(&dev->cpkt_req_q);
1938 INIT_LIST_HEAD(&dev->cpkt_resp_q);
1939
1940 mbim_ports[i].port = dev;
1941 mbim_ports[i].port_num = i;
1942
1943 init_waitqueue_head(&dev->read_wq);
1944 init_waitqueue_head(&dev->write_wq);
1945
1946 atomic_set(&dev->open_excl, 0);
1947 atomic_set(&dev->ioctl_excl, 0);
1948 atomic_set(&dev->read_excl, 0);
1949 atomic_set(&dev->write_excl, 0);
1950
1951 nr_mbim_ports++;
1952
1953 }
1954
1955 _mbim_dev = dev;
1956 ret = misc_register(&mbim_device);
1957 if (ret) {
1958 pr_err("mbim driver failed to register");
1959 goto fail_probe;
1960 }
1961
1962 pr_info("Initialized %d ports\n", nr_mbim_ports);
1963
1964 return ret;
1965
1966fail_probe:
1967 pr_err("Failed");
1968 for (i = 0; i < nr_mbim_ports; i++) {
1969 kfree(mbim_ports[i].port);
1970 mbim_ports[i].port = NULL;
1971 }
1972
1973 return ret;
1974}
1975
1976static void fmbim_cleanup(void)
1977{
1978 int i = 0;
1979
1980 pr_info("Enter");
1981
1982 for (i = 0; i < nr_mbim_ports; i++) {
1983 kfree(mbim_ports[i].port);
1984 mbim_ports[i].port = NULL;
1985 }
1986 nr_mbim_ports = 0;
1987
1988 misc_deregister(&mbim_device);
1989
1990 _mbim_dev = NULL;
1991}
1992