blob: 935a5400fe9c22dc88785af0205439537035830d [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
227/* the default data interface has no endpoints ... */
228static struct usb_interface_descriptor mbim_data_nop_intf = {
229 .bLength = sizeof mbim_data_nop_intf,
230 .bDescriptorType = USB_DT_INTERFACE,
231
232 /* .bInterfaceNumber = DYNAMIC */
233 .bAlternateSetting = 0,
234 .bNumEndpoints = 0,
235 .bInterfaceClass = 0x0a,
236 .bInterfaceSubClass = 0,
237 .bInterfaceProtocol = 0x02,
238 /* .iInterface = DYNAMIC */
239};
240
241/* ... but the "real" data interface has two bulk endpoints */
242static struct usb_interface_descriptor mbim_data_intf = {
243 .bLength = sizeof mbim_data_intf,
244 .bDescriptorType = USB_DT_INTERFACE,
245
246 /* .bInterfaceNumber = DYNAMIC */
247 .bAlternateSetting = 1,
248 .bNumEndpoints = 2,
249 .bInterfaceClass = 0x0a,
250 .bInterfaceSubClass = 0,
251 .bInterfaceProtocol = 0x02,
252 /* .iInterface = DYNAMIC */
253};
254
255/* full speed support: */
256
257static struct usb_endpoint_descriptor fs_mbim_notify_desc = {
258 .bLength = USB_DT_ENDPOINT_SIZE,
259 .bDescriptorType = USB_DT_ENDPOINT,
260
261 .bEndpointAddress = USB_DIR_IN,
262 .bmAttributes = USB_ENDPOINT_XFER_INT,
263 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
264 .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
265};
266
267static struct usb_endpoint_descriptor fs_mbim_in_desc = {
268 .bLength = USB_DT_ENDPOINT_SIZE,
269 .bDescriptorType = USB_DT_ENDPOINT,
270
271 .bEndpointAddress = USB_DIR_IN,
272 .bmAttributes = USB_ENDPOINT_XFER_BULK,
273};
274
275static struct usb_endpoint_descriptor fs_mbim_out_desc = {
276 .bLength = USB_DT_ENDPOINT_SIZE,
277 .bDescriptorType = USB_DT_ENDPOINT,
278
279 .bEndpointAddress = USB_DIR_OUT,
280 .bmAttributes = USB_ENDPOINT_XFER_BULK,
281};
282
283static struct usb_descriptor_header *mbim_fs_function[] = {
284 (struct usb_descriptor_header *) &mbim_iad_desc,
285 /* MBIM control descriptors */
286 (struct usb_descriptor_header *) &mbim_control_intf,
287 (struct usb_descriptor_header *) &mbim_header_desc,
288 (struct usb_descriptor_header *) &mbb_desc,
289 (struct usb_descriptor_header *) &fs_mbim_notify_desc,
290 /* data interface, altsettings 0 and 1 */
291 (struct usb_descriptor_header *) &mbim_data_nop_intf,
292 (struct usb_descriptor_header *) &mbim_data_intf,
293 (struct usb_descriptor_header *) &fs_mbim_in_desc,
294 (struct usb_descriptor_header *) &fs_mbim_out_desc,
295 NULL,
296};
297
298/* high speed support: */
299
300static struct usb_endpoint_descriptor hs_mbim_notify_desc = {
301 .bLength = USB_DT_ENDPOINT_SIZE,
302 .bDescriptorType = USB_DT_ENDPOINT,
303
304 .bEndpointAddress = USB_DIR_IN,
305 .bmAttributes = USB_ENDPOINT_XFER_INT,
306 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
307 .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
308};
309static struct usb_endpoint_descriptor hs_mbim_in_desc = {
310 .bLength = USB_DT_ENDPOINT_SIZE,
311 .bDescriptorType = USB_DT_ENDPOINT,
312
313 .bEndpointAddress = USB_DIR_IN,
314 .bmAttributes = USB_ENDPOINT_XFER_BULK,
315 .wMaxPacketSize = cpu_to_le16(512),
316};
317
318static struct usb_endpoint_descriptor hs_mbim_out_desc = {
319 .bLength = USB_DT_ENDPOINT_SIZE,
320 .bDescriptorType = USB_DT_ENDPOINT,
321
322 .bEndpointAddress = USB_DIR_OUT,
323 .bmAttributes = USB_ENDPOINT_XFER_BULK,
324 .wMaxPacketSize = cpu_to_le16(512),
325};
326
327static struct usb_descriptor_header *mbim_hs_function[] = {
328 (struct usb_descriptor_header *) &mbim_iad_desc,
329 /* MBIM control descriptors */
330 (struct usb_descriptor_header *) &mbim_control_intf,
331 (struct usb_descriptor_header *) &mbim_header_desc,
332 (struct usb_descriptor_header *) &mbb_desc,
333 (struct usb_descriptor_header *) &hs_mbim_notify_desc,
334 /* data interface, altsettings 0 and 1 */
335 (struct usb_descriptor_header *) &mbim_data_nop_intf,
336 (struct usb_descriptor_header *) &mbim_data_intf,
337 (struct usb_descriptor_header *) &hs_mbim_in_desc,
338 (struct usb_descriptor_header *) &hs_mbim_out_desc,
339 NULL,
340};
341
342/* string descriptors: */
343
344#define STRING_CTRL_IDX 0
345#define STRING_DATA_IDX 1
346
347static struct usb_string mbim_string_defs[] = {
348 [STRING_CTRL_IDX].s = "MBIM Control",
349 [STRING_DATA_IDX].s = "MBIM Data",
350 { } /* end of list */
351};
352
353static struct usb_gadget_strings mbim_string_table = {
354 .language = 0x0409, /* en-us */
355 .strings = mbim_string_defs,
356};
357
358static struct usb_gadget_strings *mbim_strings[] = {
359 &mbim_string_table,
360 NULL,
361};
362
Jack Pham2df2f702012-10-11 19:08:24 -0700363/* Microsoft OS Descriptors */
364
365/*
366 * We specify our own bMS_VendorCode byte which Windows will use
367 * as the bRequest value in subsequent device get requests.
368 */
369#define MBIM_VENDOR_CODE 0xA5
370
371/* Microsoft OS String */
372static u8 mbim_os_string[] = {
373 18, /* sizeof(mtp_os_string) */
374 USB_DT_STRING,
375 /* Signature field: "MSFT100" */
376 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
377 /* vendor code */
378 MBIM_VENDOR_CODE,
379 /* padding */
380 0
381};
382
383/* Microsoft Extended Configuration Descriptor Header Section */
384struct mbim_ext_config_desc_header {
385 __le32 dwLength;
386 __u16 bcdVersion;
387 __le16 wIndex;
388 __u8 bCount;
389 __u8 reserved[7];
390};
391
392/* Microsoft Extended Configuration Descriptor Function Section */
393struct mbim_ext_config_desc_function {
394 __u8 bFirstInterfaceNumber;
395 __u8 bInterfaceCount;
396 __u8 compatibleID[8];
397 __u8 subCompatibleID[8];
398 __u8 reserved[6];
399};
400
401/* Microsoft Extended Configuration Descriptor */
402static struct {
403 struct mbim_ext_config_desc_header header;
404 struct mbim_ext_config_desc_function function;
405} mbim_ext_config_desc = {
406 .header = {
407 .dwLength = __constant_cpu_to_le32(sizeof mbim_ext_config_desc),
408 .bcdVersion = __constant_cpu_to_le16(0x0100),
409 .wIndex = __constant_cpu_to_le16(4),
410 .bCount = 1,
411 },
412 .function = {
413 .bFirstInterfaceNumber = 0,
414 .bInterfaceCount = 1,
415 .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' },
416 /* .subCompatibleID = DYNAMIC */
417 },
418};
419
Anna Perela8c991d2012-04-09 16:44:46 +0300420/*
421 * Here are options for the Datagram Pointer table (NDP) parser.
422 * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
423 * in NDP16 offsets and sizes fields are 1 16bit word wide,
424 * in NDP32 -- 2 16bit words wide. Also signatures are different.
425 * To make the parser code the same, put the differences in the structure,
426 * and switch pointers to the structures when the format is changed.
427 */
428
429struct ndp_parser_opts {
430 u32 nth_sign;
431 u32 ndp_sign;
432 unsigned nth_size;
433 unsigned ndp_size;
434 unsigned ndplen_align;
435 /* sizes in u16 units */
436 unsigned dgram_item_len; /* index or length */
437 unsigned block_length;
438 unsigned fp_index;
439 unsigned reserved1;
440 unsigned reserved2;
441 unsigned next_fp_index;
442};
443
444#define INIT_NDP16_OPTS { \
445 .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
446 .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
447 .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
448 .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
449 .ndplen_align = 4, \
450 .dgram_item_len = 1, \
451 .block_length = 1, \
452 .fp_index = 1, \
453 .reserved1 = 0, \
454 .reserved2 = 0, \
455 .next_fp_index = 1, \
456}
457
458#define INIT_NDP32_OPTS { \
459 .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
460 .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
461 .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
462 .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
463 .ndplen_align = 8, \
464 .dgram_item_len = 2, \
465 .block_length = 2, \
466 .fp_index = 2, \
467 .reserved1 = 1, \
468 .reserved2 = 2, \
469 .next_fp_index = 2, \
470}
471
472static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
473static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
474
475static inline int mbim_lock(atomic_t *excl)
476{
477 if (atomic_inc_return(excl) == 1) {
478 return 0;
479 } else {
480 atomic_dec(excl);
481 return -EBUSY;
482 }
483}
484
485static inline void mbim_unlock(atomic_t *excl)
486{
487 atomic_dec(excl);
488}
489
490static struct ctrl_pkt *mbim_alloc_ctrl_pkt(unsigned len, gfp_t flags)
491{
492 struct ctrl_pkt *pkt;
493
494 pkt = kzalloc(sizeof(struct ctrl_pkt), flags);
495 if (!pkt)
496 return ERR_PTR(-ENOMEM);
497
498 pkt->buf = kmalloc(len, flags);
499 if (!pkt->buf) {
500 kfree(pkt);
501 return ERR_PTR(-ENOMEM);
502 }
503 pkt->len = len;
504
505 return pkt;
506}
507
508static void mbim_free_ctrl_pkt(struct ctrl_pkt *pkt)
509{
510 if (pkt) {
511 kfree(pkt->buf);
512 kfree(pkt);
513 }
514}
515
516static struct usb_request *mbim_alloc_req(struct usb_ep *ep, int buffer_size)
517{
518 struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
519 if (!req)
520 return NULL;
521
522 req->buf = kmalloc(buffer_size, GFP_KERNEL);
523 if (!req->buf) {
524 usb_ep_free_request(ep, req);
525 return NULL;
526 }
527 req->length = buffer_size;
528 return req;
529}
530
531void fmbim_free_req(struct usb_ep *ep, struct usb_request *req)
532{
533 if (req) {
534 kfree(req->buf);
535 usb_ep_free_request(ep, req);
536 }
537}
538
539static void fmbim_ctrl_response_available(struct f_mbim *dev)
540{
541 struct usb_request *req = dev->not_port.notify_req;
542 struct usb_cdc_notification *event = NULL;
543 unsigned long flags;
544 int ret;
545
Anna Perel68aeb172012-10-28 09:00:45 +0200546 pr_debug("dev:%p portno#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300547
548 spin_lock_irqsave(&dev->lock, flags);
549
550 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200551 pr_err("dev:%p is not online\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300552 spin_unlock_irqrestore(&dev->lock, flags);
553 return;
554 }
555
556 if (!req) {
Anna Perel20c91152012-10-30 16:26:44 +0200557 pr_err("dev:%p req is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300558 spin_unlock_irqrestore(&dev->lock, flags);
559 return;
560 }
561
562 if (!req->buf) {
Anna Perel20c91152012-10-30 16:26:44 +0200563 pr_err("dev:%p req->buf is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300564 spin_unlock_irqrestore(&dev->lock, flags);
565 return;
566 }
567
Anna Perel68aeb172012-10-28 09:00:45 +0200568 if (atomic_inc_return(&dev->not_port.notify_count) != 1) {
569 pr_debug("delay ep_queue: notifications queue is busy[%d]",
570 atomic_read(&dev->not_port.notify_count));
571 spin_unlock_irqrestore(&dev->lock, flags);
572 return;
573 }
Anna Perela8c991d2012-04-09 16:44:46 +0300574
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200575 req->length = sizeof *event;
Anna Perela8c991d2012-04-09 16:44:46 +0300576 event = req->buf;
577 event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
578 | USB_RECIP_INTERFACE;
579 event->bNotificationType = USB_CDC_NOTIFY_RESPONSE_AVAILABLE;
580 event->wValue = cpu_to_le16(0);
581 event->wIndex = cpu_to_le16(dev->ctrl_id);
582 event->wLength = cpu_to_le16(0);
583 spin_unlock_irqrestore(&dev->lock, flags);
584
Anna Perela8c991d2012-04-09 16:44:46 +0300585 ret = usb_ep_queue(dev->not_port.notify,
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200586 req, GFP_ATOMIC);
Anna Perela8c991d2012-04-09 16:44:46 +0300587 if (ret) {
588 atomic_dec(&dev->not_port.notify_count);
589 pr_err("ep enqueue error %d\n", ret);
590 }
591
Anna Perel68aeb172012-10-28 09:00:45 +0200592 pr_debug("Successful Exit");
Anna Perela8c991d2012-04-09 16:44:46 +0300593}
594
595static int
596fmbim_send_cpkt_response(struct f_mbim *gr, struct ctrl_pkt *cpkt)
597{
598 struct f_mbim *dev = gr;
599 unsigned long flags;
600
601 if (!gr || !cpkt) {
602 pr_err("Invalid cpkt, dev:%p cpkt:%p\n",
603 gr, cpkt);
604 return -ENODEV;
605 }
606
Anna Perel20c91152012-10-30 16:26:44 +0200607 pr_debug("dev:%p port_num#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300608
609 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200610 pr_err("dev:%p is not connected\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300611 mbim_free_ctrl_pkt(cpkt);
612 return 0;
613 }
614
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200615 if (dev->not_port.notify_state != NCM_NOTIFY_RESPONSE_AVAILABLE) {
616 pr_err("dev:%p state=%d, recover!!\n", dev,
617 dev->not_port.notify_state);
618 mbim_free_ctrl_pkt(cpkt);
619 return 0;
620 }
621
Anna Perela8c991d2012-04-09 16:44:46 +0300622 spin_lock_irqsave(&dev->lock, flags);
Anna Perel40c550c2012-04-11 14:09:27 +0300623 list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
Anna Perela8c991d2012-04-09 16:44:46 +0300624 spin_unlock_irqrestore(&dev->lock, flags);
625
626 fmbim_ctrl_response_available(dev);
627
628 return 0;
629}
630
631/* ---------------------------- BAM INTERFACE ----------------------------- */
632
633static int mbim_bam_setup(int no_ports)
634{
635 int ret;
636
637 pr_info("no_ports:%d\n", no_ports);
638
639 ret = bam_data_setup(no_ports);
640 if (ret) {
641 pr_err("bam_data_setup failed err: %d\n", ret);
642 return ret;
643 }
644
645 pr_info("Initialized %d ports\n", no_ports);
646 return 0;
647}
648
649static int mbim_bam_connect(struct f_mbim *dev)
650{
651 int ret;
652
653 pr_info("dev:%p portno:%d\n", dev, dev->port_num);
654
655 ret = bam_data_connect(&dev->bam_port, dev->port_num, dev->port_num);
656 if (ret) {
657 pr_err("bam_data_setup failed: err:%d\n",
658 ret);
659 return ret;
660 } else {
661 pr_info("mbim bam connected\n");
662 }
663
664 return 0;
665}
666
667static int mbim_bam_disconnect(struct f_mbim *dev)
668{
669 pr_info("dev:%p port:%d. Do nothing.\n",
670 dev, dev->port_num);
671
Amit Blay51bebe92012-12-25 18:48:10 +0200672 bam_data_disconnect(&dev->bam_port, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300673
674 return 0;
675}
676
677/* -------------------------------------------------------------------------*/
678
679static inline void mbim_reset_values(struct f_mbim *mbim)
680{
681 mbim->parser_opts = &ndp16_opts;
682
683 mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
684
Anna Perela8c991d2012-04-09 16:44:46 +0300685 atomic_set(&mbim->online, 0);
686}
687
Anna Perel86ea7c92012-04-24 14:31:29 +0300688static void mbim_reset_function_queue(struct f_mbim *dev)
689{
690 struct ctrl_pkt *cpkt = NULL;
691
692 pr_debug("Queue empty packet for QBI");
693
694 spin_lock(&dev->lock);
695 if (!dev->is_open) {
696 pr_err("%s: mbim file handler %p is not open", __func__, dev);
697 spin_unlock(&dev->lock);
698 return;
699 }
700
701 cpkt = mbim_alloc_ctrl_pkt(0, GFP_ATOMIC);
702 if (!cpkt) {
703 pr_err("%s: Unable to allocate reset function pkt\n", __func__);
704 spin_unlock(&dev->lock);
705 return;
706 }
707
708 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
709 spin_unlock(&dev->lock);
710
711 pr_debug("%s: Wake up read queue", __func__);
712 wake_up(&dev->read_wq);
713}
714
715static void fmbim_reset_cmd_complete(struct usb_ep *ep, struct usb_request *req)
716{
717 struct f_mbim *dev = req->context;
718
719 mbim_reset_function_queue(dev);
720}
721
722static void mbim_clear_queues(struct f_mbim *mbim)
723{
724 struct ctrl_pkt *cpkt = NULL;
725 struct list_head *act, *tmp;
726
727 spin_lock(&mbim->lock);
728 list_for_each_safe(act, tmp, &mbim->cpkt_req_q) {
729 cpkt = list_entry(act, struct ctrl_pkt, list);
730 list_del(&cpkt->list);
731 mbim_free_ctrl_pkt(cpkt);
732 }
733 list_for_each_safe(act, tmp, &mbim->cpkt_resp_q) {
734 cpkt = list_entry(act, struct ctrl_pkt, list);
735 list_del(&cpkt->list);
736 mbim_free_ctrl_pkt(cpkt);
737 }
738 spin_unlock(&mbim->lock);
739}
740
Anna Perela8c991d2012-04-09 16:44:46 +0300741/*
742 * Context: mbim->lock held
743 */
744static void mbim_do_notify(struct f_mbim *mbim)
745{
746 struct usb_request *req = mbim->not_port.notify_req;
747 struct usb_cdc_notification *event;
748 struct usb_composite_dev *cdev = mbim->cdev;
749 __le32 *data;
750 int status;
751
Anna Perel20c91152012-10-30 16:26:44 +0200752 pr_debug("notify_state: %d", mbim->not_port.notify_state);
Anna Perela8c991d2012-04-09 16:44:46 +0300753
754 if (!req)
755 return;
756
757 event = req->buf;
758
759 switch (mbim->not_port.notify_state) {
760
761 case NCM_NOTIFY_NONE:
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200762 if (atomic_read(&mbim->not_port.notify_count) > 0)
763 pr_err("Pending notifications in NCM_NOTIFY_NONE\n");
764 else
765 pr_debug("No pending notifications\n");
766
767 return;
768
769 case NCM_NOTIFY_RESPONSE_AVAILABLE:
Anna Perel68aeb172012-10-28 09:00:45 +0200770 pr_debug("Notification %02x sent\n", event->bNotificationType);
771
772 if (atomic_read(&mbim->not_port.notify_count) <= 0) {
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200773 pr_debug("notify_response_avaliable: done");
Anna Perel68aeb172012-10-28 09:00:45 +0200774 return;
775 }
776
777 spin_unlock(&mbim->lock);
778 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
779 spin_lock(&mbim->lock);
780 if (status) {
781 atomic_dec(&mbim->not_port.notify_count);
782 pr_err("Queue notify request failed, err: %d", status);
783 }
784
Anna Perela8c991d2012-04-09 16:44:46 +0300785 return;
786
787 case NCM_NOTIFY_CONNECT:
788 event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
789 if (mbim->is_open)
790 event->wValue = cpu_to_le16(1);
791 else
792 event->wValue = cpu_to_le16(0);
793 event->wLength = 0;
794 req->length = sizeof *event;
795
796 pr_info("notify connect %s\n",
797 mbim->is_open ? "true" : "false");
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +0200798 mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
Anna Perela8c991d2012-04-09 16:44:46 +0300799 break;
800
801 case NCM_NOTIFY_SPEED:
802 event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
803 event->wValue = cpu_to_le16(0);
804 event->wLength = cpu_to_le16(8);
805 req->length = NCM_STATUS_BYTECOUNT;
806
807 /* SPEED_CHANGE data is up/down speeds in bits/sec */
808 data = req->buf + sizeof *event;
809 data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
810 data[1] = data[0];
811
812 pr_info("notify speed %d\n",
813 mbim_bitrate(cdev->gadget));
814 mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
815 break;
816 }
Anna Perel68aeb172012-10-28 09:00:45 +0200817
Anna Perela8c991d2012-04-09 16:44:46 +0300818 event->bmRequestType = 0xA1;
819 event->wIndex = cpu_to_le16(mbim->ctrl_id);
820
Anna Perela8c991d2012-04-09 16:44:46 +0300821 /*
822 * In double buffering if there is a space in FIFO,
823 * completion callback can be called right after the call,
824 * so unlocking
825 */
Anna Perel68aeb172012-10-28 09:00:45 +0200826 atomic_inc(&mbim->not_port.notify_count);
827 pr_debug("queue request: notify_count = %d",
828 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300829 spin_unlock(&mbim->lock);
830 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
831 spin_lock(&mbim->lock);
Anna Perel68aeb172012-10-28 09:00:45 +0200832 if (status) {
Anna Perela8c991d2012-04-09 16:44:46 +0300833 atomic_dec(&mbim->not_port.notify_count);
834 pr_err("usb_ep_queue failed, err: %d", status);
835 }
836}
837
838/*
839 * Context: mbim->lock held
840 */
841static void mbim_notify(struct f_mbim *mbim)
842{
843 /*
844 * If mbim_notify() is called before the second (CONNECT)
845 * notification is sent, then it will reset to send the SPEED
846 * notificaion again (and again, and again), but it's not a problem
847 */
Anna Perel20c91152012-10-30 16:26:44 +0200848 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300849
Ido Shayevitzf1510c02013-02-07 11:48:49 +0200850 mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
Anna Perela8c991d2012-04-09 16:44:46 +0300851 mbim_do_notify(mbim);
852}
853
854static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
855{
856 struct f_mbim *mbim = req->context;
857 struct usb_cdc_notification *event = req->buf;
858
Anna Perel68aeb172012-10-28 09:00:45 +0200859 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300860
861 spin_lock(&mbim->lock);
862 switch (req->status) {
863 case 0:
Anna Perel68aeb172012-10-28 09:00:45 +0200864 atomic_dec(&mbim->not_port.notify_count);
865 pr_debug("notify_count = %d",
866 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300867 break;
868
869 case -ECONNRESET:
870 case -ESHUTDOWN:
871 /* connection gone */
872 mbim->not_port.notify_state = NCM_NOTIFY_NONE;
873 atomic_set(&mbim->not_port.notify_count, 0);
874 pr_info("ESHUTDOWN/ECONNRESET, connection gone");
Anna Perel86ea7c92012-04-24 14:31:29 +0300875 spin_unlock(&mbim->lock);
876 mbim_clear_queues(mbim);
877 mbim_reset_function_queue(mbim);
Anna Perel89ad1212012-06-13 17:17:24 +0300878 spin_lock(&mbim->lock);
Anna Perela8c991d2012-04-09 16:44:46 +0300879 break;
880 default:
881 pr_err("Unknown event %02x --> %d\n",
882 event->bNotificationType, req->status);
883 break;
884 }
885
Anna Perela8c991d2012-04-09 16:44:46 +0300886 mbim_do_notify(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300887 spin_unlock(&mbim->lock);
888
Anna Perel20c91152012-10-30 16:26:44 +0200889 pr_debug("dev:%p Exit\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300890}
891
892static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
893{
894 /* now for SET_NTB_INPUT_SIZE only */
895 unsigned in_size = 0;
896 struct usb_function *f = req->context;
897 struct f_mbim *mbim = func_to_mbim(f);
898 struct mbim_ntb_input_size *ntb = NULL;
899
Anna Perel20c91152012-10-30 16:26:44 +0200900 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300901
902 req->context = NULL;
903 if (req->status || req->actual != req->length) {
904 pr_err("Bad control-OUT transfer\n");
905 goto invalid;
906 }
907
908 if (req->length == 4) {
909 in_size = get_unaligned_le32(req->buf);
910 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
911 in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
912 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
913 goto invalid;
914 }
915 } else if (req->length == 8) {
916 ntb = (struct mbim_ntb_input_size *)req->buf;
917 in_size = get_unaligned_le32(&(ntb->ntb_input_size));
918 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
919 in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
920 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
921 goto invalid;
922 }
923 mbim->ntb_max_datagrams =
924 get_unaligned_le16(&(ntb->ntb_max_datagrams));
925 } else {
926 pr_err("Illegal NTB length %d\n", in_size);
927 goto invalid;
928 }
929
Anna Perel20c91152012-10-30 16:26:44 +0200930 pr_debug("Set NTB INPUT SIZE %d\n", in_size);
Anna Perela8c991d2012-04-09 16:44:46 +0300931
932 mbim->ntb_input_size = in_size;
933 return;
934
935invalid:
936 usb_ep_set_halt(ep);
937
938 pr_err("dev:%p Failed\n", mbim);
939
940 return;
941}
942
943static void
944fmbim_cmd_complete(struct usb_ep *ep, struct usb_request *req)
945{
946 struct f_mbim *dev = req->context;
947 struct ctrl_pkt *cpkt = NULL;
948 int len = req->actual;
949
950 if (!dev) {
951 pr_err("mbim dev is null\n");
952 return;
953 }
954
955 if (req->status < 0) {
956 pr_err("mbim command error %d\n", req->status);
957 return;
958 }
959
Anna Perel20c91152012-10-30 16:26:44 +0200960 pr_debug("dev:%p port#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300961
Anna Perela8c991d2012-04-09 16:44:46 +0300962 cpkt = mbim_alloc_ctrl_pkt(len, GFP_ATOMIC);
963 if (!cpkt) {
964 pr_err("Unable to allocate ctrl pkt\n");
Anna Perela8c991d2012-04-09 16:44:46 +0300965 return;
966 }
967
Anna Perel20c91152012-10-30 16:26:44 +0200968 pr_debug("Add to cpkt_req_q packet with len = %d\n", len);
Anna Perela8c991d2012-04-09 16:44:46 +0300969 memcpy(cpkt->buf, req->buf, len);
Anna Perel20c91152012-10-30 16:26:44 +0200970
Anna Perel182ab572012-11-18 10:10:12 +0200971 spin_lock(&dev->lock);
972 if (!dev->is_open) {
973 pr_err("mbim file handler %p is not open", dev);
974 spin_unlock(&dev->lock);
975 mbim_free_ctrl_pkt(cpkt);
976 return;
977 }
978
Anna Perela8c991d2012-04-09 16:44:46 +0300979 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
980 spin_unlock(&dev->lock);
981
982 /* wakeup read thread */
Anna Perel20c91152012-10-30 16:26:44 +0200983 pr_debug("Wake up read queue");
Anna Perela8c991d2012-04-09 16:44:46 +0300984 wake_up(&dev->read_wq);
985
986 return;
987}
988
989static int
990mbim_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
991{
992 struct f_mbim *mbim = func_to_mbim(f);
993 struct usb_composite_dev *cdev = mbim->cdev;
994 struct usb_request *req = cdev->req;
995 struct ctrl_pkt *cpkt = NULL;
996 int value = -EOPNOTSUPP;
997 u16 w_index = le16_to_cpu(ctrl->wIndex);
998 u16 w_value = le16_to_cpu(ctrl->wValue);
999 u16 w_length = le16_to_cpu(ctrl->wLength);
1000
1001 /*
1002 * composite driver infrastructure handles everything except
1003 * CDC class messages; interface activation uses set_alt().
1004 */
1005
1006 if (!atomic_read(&mbim->online)) {
1007 pr_info("usb cable is not connected\n");
1008 return -ENOTCONN;
1009 }
1010
1011 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
1012 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1013 | USB_CDC_RESET_FUNCTION:
1014
Anna Perel20c91152012-10-30 16:26:44 +02001015 pr_debug("USB_CDC_RESET_FUNCTION");
Anna Perela8c991d2012-04-09 16:44:46 +03001016 value = 0;
Anna Perel86ea7c92012-04-24 14:31:29 +03001017 req->complete = fmbim_reset_cmd_complete;
1018 req->context = mbim;
Anna Perela8c991d2012-04-09 16:44:46 +03001019 break;
1020
1021 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1022 | USB_CDC_SEND_ENCAPSULATED_COMMAND:
1023
Anna Perel20c91152012-10-30 16:26:44 +02001024 pr_debug("USB_CDC_SEND_ENCAPSULATED_COMMAND");
Anna Perela8c991d2012-04-09 16:44:46 +03001025
1026 if (w_length > req->length) {
Anna Perel20c91152012-10-30 16:26:44 +02001027 pr_debug("w_length > req->length: %d > %d",
Anna Perela8c991d2012-04-09 16:44:46 +03001028 w_length, req->length);
1029 }
1030 value = w_length;
1031 req->complete = fmbim_cmd_complete;
1032 req->context = mbim;
1033 break;
1034
1035 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1036 | USB_CDC_GET_ENCAPSULATED_RESPONSE:
1037
Anna Perel20c91152012-10-30 16:26:44 +02001038 pr_debug("USB_CDC_GET_ENCAPSULATED_RESPONSE");
Anna Perela8c991d2012-04-09 16:44:46 +03001039
1040 if (w_value) {
1041 pr_err("w_length > 0: %d", w_length);
1042 break;
1043 }
1044
Anna Perel20c91152012-10-30 16:26:44 +02001045 pr_debug("req%02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001046 ctrl->bRequestType, ctrl->bRequest,
1047 w_value, w_index, w_length);
1048
1049 spin_lock(&mbim->lock);
1050 if (list_empty(&mbim->cpkt_resp_q)) {
1051 pr_err("ctrl resp queue empty\n");
1052 spin_unlock(&mbim->lock);
1053 break;
1054 }
1055
1056 cpkt = list_first_entry(&mbim->cpkt_resp_q,
1057 struct ctrl_pkt, list);
1058 list_del(&cpkt->list);
1059 spin_unlock(&mbim->lock);
1060
1061 value = min_t(unsigned, w_length, cpkt->len);
1062 memcpy(req->buf, cpkt->buf, value);
1063 mbim_free_ctrl_pkt(cpkt);
1064
Anna Perel20c91152012-10-30 16:26:44 +02001065 pr_debug("copied encapsulated_response %d bytes",
Anna Perela8c991d2012-04-09 16:44:46 +03001066 value);
1067
1068 break;
1069
1070 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1071 | USB_CDC_GET_NTB_PARAMETERS:
1072
Anna Perel20c91152012-10-30 16:26:44 +02001073 pr_debug("USB_CDC_GET_NTB_PARAMETERS");
Anna Perela8c991d2012-04-09 16:44:46 +03001074
1075 if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
1076 break;
1077
1078 value = w_length > sizeof ntb_parameters ?
1079 sizeof ntb_parameters : w_length;
1080 memcpy(req->buf, &ntb_parameters, value);
1081 break;
1082
1083 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1084 | USB_CDC_GET_NTB_INPUT_SIZE:
1085
Anna Perel20c91152012-10-30 16:26:44 +02001086 pr_debug("USB_CDC_GET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001087
1088 if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
1089 break;
1090
1091 put_unaligned_le32(mbim->ntb_input_size, req->buf);
1092 value = 4;
Anna Perel20c91152012-10-30 16:26:44 +02001093 pr_debug("Reply to host INPUT SIZE %d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001094 mbim->ntb_input_size);
1095 break;
1096
1097 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1098 | USB_CDC_SET_NTB_INPUT_SIZE:
1099
Anna Perel20c91152012-10-30 16:26:44 +02001100 pr_debug("USB_CDC_SET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001101
1102 if (w_length != 4 && w_length != 8) {
1103 pr_err("wrong NTB length %d", w_length);
1104 break;
1105 }
1106
1107 if (w_value != 0 || w_index != mbim->ctrl_id)
1108 break;
1109
1110 req->complete = mbim_ep0out_complete;
1111 req->length = w_length;
1112 req->context = f;
1113
1114 value = req->length;
1115 break;
1116
1117 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1118 | USB_CDC_GET_NTB_FORMAT:
1119 {
1120 uint16_t format;
1121
Anna Perel20c91152012-10-30 16:26:44 +02001122 pr_debug("USB_CDC_GET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001123
1124 if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
1125 break;
1126
1127 format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
1128 put_unaligned_le16(format, req->buf);
1129 value = 2;
Anna Perel20c91152012-10-30 16:26:44 +02001130 pr_debug("NTB FORMAT: sending %d\n", format);
Anna Perela8c991d2012-04-09 16:44:46 +03001131 break;
1132 }
1133
1134 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1135 | USB_CDC_SET_NTB_FORMAT:
1136 {
Anna Perel20c91152012-10-30 16:26:44 +02001137 pr_debug("USB_CDC_SET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001138
1139 if (w_length != 0 || w_index != mbim->ctrl_id)
1140 break;
1141 switch (w_value) {
1142 case 0x0000:
1143 mbim->parser_opts = &ndp16_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001144 pr_debug("NCM16 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001145 break;
1146 case 0x0001:
1147 mbim->parser_opts = &ndp32_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001148 pr_debug("NCM32 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001149 break;
1150 default:
1151 break;
1152 }
1153 value = 0;
1154 break;
1155 }
1156
1157 /* optional in mbim descriptor: */
1158 /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
1159 /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
1160
1161 default:
1162 pr_err("invalid control req: %02x.%02x v%04x i%04x l%d\n",
1163 ctrl->bRequestType, ctrl->bRequest,
1164 w_value, w_index, w_length);
1165 }
1166
1167 /* respond with data transfer or status phase? */
1168 if (value >= 0) {
Anna Perel20c91152012-10-30 16:26:44 +02001169 pr_debug("control request: %02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001170 ctrl->bRequestType, ctrl->bRequest,
1171 w_value, w_index, w_length);
Anna Perel2dfcaca2012-04-18 17:25:59 +03001172 req->zero = (value < w_length);
Anna Perela8c991d2012-04-09 16:44:46 +03001173 req->length = value;
1174 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1175 if (value < 0) {
1176 pr_err("queueing req failed: %02x.%02x, err %d\n",
1177 ctrl->bRequestType,
1178 ctrl->bRequest, value);
1179 }
1180 } else {
1181 pr_err("ctrl req err %d: %02x.%02x v%04x i%04x l%d\n",
1182 value, ctrl->bRequestType, ctrl->bRequest,
1183 w_value, w_index, w_length);
1184 }
1185
1186 /* device either stalls (value < 0) or reports success */
1187 return value;
1188}
1189
Jack Pham2df2f702012-10-11 19:08:24 -07001190/*
1191 * This function handles the Microsoft-specific OS descriptor control
1192 * requests that are issued by Windows host drivers to determine the
1193 * configuration containing the MBIM function.
1194 *
1195 * Unlike mbim_setup() this function handles two specific device requests,
1196 * and only when a configuration has not yet been selected.
1197 */
1198static int mbim_ctrlrequest(struct usb_composite_dev *cdev,
1199 const struct usb_ctrlrequest *ctrl)
1200{
1201 int value = -EOPNOTSUPP;
1202 u16 w_index = le16_to_cpu(ctrl->wIndex);
1203 u16 w_value = le16_to_cpu(ctrl->wValue);
1204 u16 w_length = le16_to_cpu(ctrl->wLength);
1205
1206 /* only respond to OS desciptors when no configuration selected */
1207 if (cdev->config || !mbim_ext_config_desc.function.subCompatibleID[0])
1208 return value;
1209
1210 pr_debug("%02x.%02x v%04x i%04x l%u",
1211 ctrl->bRequestType, ctrl->bRequest,
1212 w_value, w_index, w_length);
1213
1214 /* Handle MSFT OS string */
1215 if (ctrl->bRequestType ==
1216 (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
1217 && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
1218 && (w_value >> 8) == USB_DT_STRING
1219 && (w_value & 0xFF) == MBIM_OS_STRING_ID) {
1220
1221 value = (w_length < sizeof(mbim_os_string) ?
1222 w_length : sizeof(mbim_os_string));
1223 memcpy(cdev->req->buf, mbim_os_string, value);
1224
1225 } else if (ctrl->bRequestType ==
1226 (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
1227 && ctrl->bRequest == MBIM_VENDOR_CODE && w_index == 4) {
1228
1229 /* Handle Extended OS descriptor */
1230 value = (w_length < sizeof(mbim_ext_config_desc) ?
1231 w_length : sizeof(mbim_ext_config_desc));
1232 memcpy(cdev->req->buf, &mbim_ext_config_desc, value);
1233 }
1234
1235 /* respond with data transfer or status phase? */
1236 if (value >= 0) {
1237 int rc;
1238 cdev->req->zero = value < w_length;
1239 cdev->req->length = value;
1240 rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
1241 if (rc < 0)
1242 pr_err("response queue error: %d", rc);
1243 }
1244 return value;
1245}
1246
Anna Perela8c991d2012-04-09 16:44:46 +03001247static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
1248{
1249 struct f_mbim *mbim = func_to_mbim(f);
1250 struct usb_composite_dev *cdev = mbim->cdev;
1251 int ret = 0;
1252
1253 /* Control interface has only altsetting 0 */
1254 if (intf == mbim->ctrl_id) {
1255
1256 pr_info("CONTROL_INTERFACE");
1257
1258 if (alt != 0)
1259 goto fail;
1260
1261 if (mbim->not_port.notify->driver_data) {
1262 pr_info("reset mbim control %d\n", intf);
1263 usb_ep_disable(mbim->not_port.notify);
1264 }
1265
1266 ret = config_ep_by_speed(cdev->gadget, f,
1267 mbim->not_port.notify);
1268 if (ret) {
1269 mbim->not_port.notify->desc = NULL;
1270 pr_err("Failed configuring notify ep %s: err %d\n",
1271 mbim->not_port.notify->name, ret);
1272 return ret;
1273 }
1274
1275 ret = usb_ep_enable(mbim->not_port.notify);
1276 if (ret) {
1277 pr_err("usb ep#%s enable failed, err#%d\n",
1278 mbim->not_port.notify->name, ret);
1279 return ret;
1280 }
1281 mbim->not_port.notify->driver_data = mbim;
1282
1283 /* Data interface has two altsettings, 0 and 1 */
1284 } else if (intf == mbim->data_id) {
1285
1286 pr_info("DATA_INTERFACE");
1287
1288 if (alt > 1)
1289 goto fail;
1290
1291 if (mbim->bam_port.in->driver_data) {
1292 pr_info("reset mbim\n");
1293 mbim_reset_values(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001294 }
1295
1296 /*
1297 * CDC Network only sends data in non-default altsettings.
1298 * Changing altsettings resets filters, statistics, etc.
1299 */
1300 if (alt == 1) {
1301 pr_info("Alt set 1, initialize ports");
1302
1303 if (!mbim->bam_port.in->desc) {
1304
1305 pr_info("Choose endpoints");
1306
1307 ret = config_ep_by_speed(cdev->gadget, f,
1308 mbim->bam_port.in);
1309 if (ret) {
1310 mbim->bam_port.in->desc = NULL;
1311 pr_err("IN ep %s failed: %d\n",
1312 mbim->bam_port.in->name, ret);
1313 return ret;
1314 }
1315
1316 pr_info("Set mbim port in_desc = 0x%p",
1317 mbim->bam_port.in->desc);
1318
1319 ret = config_ep_by_speed(cdev->gadget, f,
1320 mbim->bam_port.out);
1321 if (ret) {
1322 mbim->bam_port.out->desc = NULL;
1323 pr_err("OUT ep %s failed: %d\n",
1324 mbim->bam_port.out->name, ret);
1325 return ret;
1326 }
1327
1328 pr_info("Set mbim port out_desc = 0x%p",
1329 mbim->bam_port.out->desc);
Anna Perel6637bd72012-10-23 10:53:32 +02001330
1331 pr_debug("Activate mbim\n");
1332 mbim_bam_connect(mbim);
1333
Anna Perela8c991d2012-04-09 16:44:46 +03001334 } else {
1335 pr_info("PORTS already SET");
1336 }
Anna Perela8c991d2012-04-09 16:44:46 +03001337 }
1338
Bar Weinerb1c95f52012-12-23 09:09:13 +02001339 mbim->data_alt_int = alt;
Anna Perela8c991d2012-04-09 16:44:46 +03001340 spin_lock(&mbim->lock);
1341 mbim_notify(mbim);
1342 spin_unlock(&mbim->lock);
1343 } else {
1344 goto fail;
1345 }
1346
1347 atomic_set(&mbim->online, 1);
1348
1349 pr_info("SET DEVICE ONLINE");
1350
1351 /* wakeup file threads */
1352 wake_up(&mbim->read_wq);
1353 wake_up(&mbim->write_wq);
1354
1355 return 0;
1356
1357fail:
1358 pr_err("ERROR: Illegal Interface");
1359 return -EINVAL;
1360}
1361
1362/*
1363 * Because the data interface supports multiple altsettings,
1364 * this MBIM function *MUST* implement a get_alt() method.
1365 */
1366static int mbim_get_alt(struct usb_function *f, unsigned intf)
1367{
1368 struct f_mbim *mbim = func_to_mbim(f);
1369
1370 if (intf == mbim->ctrl_id)
1371 return 0;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001372 else if (intf == mbim->data_id)
1373 return mbim->data_alt_int;
1374
1375 return -EINVAL;
Anna Perela8c991d2012-04-09 16:44:46 +03001376}
1377
1378static void mbim_disable(struct usb_function *f)
1379{
1380 struct f_mbim *mbim = func_to_mbim(f);
1381
1382 pr_info("SET DEVICE OFFLINE");
1383 atomic_set(&mbim->online, 0);
1384
Ido Shayevitzbadc8ea2013-02-06 14:14:54 +02001385 mbim->not_port.notify_state = NCM_NOTIFY_NONE;
1386
Anna Perel86ea7c92012-04-24 14:31:29 +03001387 mbim_clear_queues(mbim);
1388 mbim_reset_function_queue(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001389
1390 mbim_bam_disconnect(mbim);
1391
1392 if (mbim->not_port.notify->driver_data) {
1393 usb_ep_disable(mbim->not_port.notify);
1394 mbim->not_port.notify->driver_data = NULL;
1395 }
1396
Anna Perel68aeb172012-10-28 09:00:45 +02001397 atomic_set(&mbim->not_port.notify_count, 0);
1398
Anna Perela8c991d2012-04-09 16:44:46 +03001399 pr_info("mbim deactivated\n");
1400}
1401
Anna Perel557bf722012-09-20 11:16:35 +03001402#define MBIM_ACTIVE_PORT 0
1403
1404static void mbim_suspend(struct usb_function *f)
1405{
1406 pr_info("mbim suspended\n");
1407 bam_data_suspend(MBIM_ACTIVE_PORT);
1408}
1409
1410static void mbim_resume(struct usb_function *f)
1411{
1412 pr_info("mbim resumed\n");
1413 bam_data_resume(MBIM_ACTIVE_PORT);
1414}
1415
Anna Perela8c991d2012-04-09 16:44:46 +03001416/*---------------------- function driver setup/binding ---------------------*/
1417
1418static int
1419mbim_bind(struct usb_configuration *c, struct usb_function *f)
1420{
1421 struct usb_composite_dev *cdev = c->cdev;
1422 struct f_mbim *mbim = func_to_mbim(f);
1423 int status;
1424 struct usb_ep *ep;
1425
1426 pr_info("Enter");
1427
1428 mbim->cdev = cdev;
1429
1430 /* allocate instance-specific interface IDs */
1431 status = usb_interface_id(c, f);
1432 if (status < 0)
1433 goto fail;
1434 mbim->ctrl_id = status;
1435 mbim_iad_desc.bFirstInterface = status;
1436
1437 mbim_control_intf.bInterfaceNumber = status;
1438 mbim_union_desc.bMasterInterface0 = status;
1439
1440 status = usb_interface_id(c, f);
1441 if (status < 0)
1442 goto fail;
1443 mbim->data_id = status;
Bar Weinerb1c95f52012-12-23 09:09:13 +02001444 mbim->data_alt_int = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001445
1446 mbim_data_nop_intf.bInterfaceNumber = status;
1447 mbim_data_intf.bInterfaceNumber = status;
1448 mbim_union_desc.bSlaveInterface0 = status;
1449
Anna Perel557bf722012-09-20 11:16:35 +03001450 mbim->bam_port.cdev = cdev;
1451
Anna Perela8c991d2012-04-09 16:44:46 +03001452 status = -ENODEV;
1453
1454 /* allocate instance-specific endpoints */
1455 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_in_desc);
1456 if (!ep) {
1457 pr_err("usb epin autoconfig failed\n");
1458 goto fail;
1459 }
1460 pr_info("usb epin autoconfig succeeded\n");
1461 ep->driver_data = cdev; /* claim */
1462 mbim->bam_port.in = ep;
1463
1464 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_out_desc);
1465 if (!ep) {
1466 pr_err("usb epout autoconfig failed\n");
1467 goto fail;
1468 }
1469 pr_info("usb epout autoconfig succeeded\n");
1470 ep->driver_data = cdev; /* claim */
1471 mbim->bam_port.out = ep;
1472
1473 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_notify_desc);
1474 if (!ep) {
1475 pr_err("usb notify ep autoconfig failed\n");
1476 goto fail;
1477 }
1478 pr_info("usb notify ep autoconfig succeeded\n");
1479 mbim->not_port.notify = ep;
1480 ep->driver_data = cdev; /* claim */
1481
1482 status = -ENOMEM;
1483
1484 /* allocate notification request and buffer */
1485 mbim->not_port.notify_req = mbim_alloc_req(ep, NCM_STATUS_BYTECOUNT);
1486 if (!mbim->not_port.notify_req) {
1487 pr_info("failed to allocate notify request\n");
1488 goto fail;
1489 }
1490 pr_info("allocated notify ep request & request buffer\n");
1491
1492 mbim->not_port.notify_req->context = mbim;
1493 mbim->not_port.notify_req->complete = mbim_notify_complete;
1494
1495 /* copy descriptors, and track endpoint copies */
1496 f->descriptors = usb_copy_descriptors(mbim_fs_function);
1497 if (!f->descriptors)
1498 goto fail;
1499
1500 /*
1501 * support all relevant hardware speeds... we expect that when
1502 * hardware is dual speed, all bulk-capable endpoints work at
1503 * both speeds
1504 */
1505 if (gadget_is_dualspeed(c->cdev->gadget)) {
1506 hs_mbim_in_desc.bEndpointAddress =
1507 fs_mbim_in_desc.bEndpointAddress;
1508 hs_mbim_out_desc.bEndpointAddress =
1509 fs_mbim_out_desc.bEndpointAddress;
1510 hs_mbim_notify_desc.bEndpointAddress =
1511 fs_mbim_notify_desc.bEndpointAddress;
1512
1513 /* copy descriptors, and track endpoint copies */
1514 f->hs_descriptors = usb_copy_descriptors(mbim_hs_function);
1515 if (!f->hs_descriptors)
1516 goto fail;
1517 }
1518
Jack Pham2df2f702012-10-11 19:08:24 -07001519 /*
1520 * If MBIM is bound in a config other than the first, tell Windows
1521 * about it by returning the num as a string in the OS descriptor's
1522 * subCompatibleID field. Windows only supports up to config #4.
1523 */
1524 if (c->bConfigurationValue >= 2 && c->bConfigurationValue <= 4) {
1525 pr_debug("MBIM in configuration %d", c->bConfigurationValue);
1526 mbim_ext_config_desc.function.subCompatibleID[0] =
1527 c->bConfigurationValue + '0';
1528 }
1529
Anna Perela8c991d2012-04-09 16:44:46 +03001530 pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
1531 mbim->port_num,
1532 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
1533 mbim->bam_port.in->name, mbim->bam_port.out->name,
1534 mbim->not_port.notify->name);
1535
1536 return 0;
1537
1538fail:
1539 pr_err("%s failed to bind, err %d\n", f->name, status);
1540
1541 if (f->descriptors)
1542 usb_free_descriptors(f->descriptors);
1543
1544 if (mbim->not_port.notify_req) {
1545 kfree(mbim->not_port.notify_req->buf);
1546 usb_ep_free_request(mbim->not_port.notify,
1547 mbim->not_port.notify_req);
1548 }
1549
1550 /* we might as well release our claims on endpoints */
1551 if (mbim->not_port.notify)
1552 mbim->not_port.notify->driver_data = NULL;
1553 if (mbim->bam_port.out)
1554 mbim->bam_port.out->driver_data = NULL;
1555 if (mbim->bam_port.in)
1556 mbim->bam_port.in->driver_data = NULL;
1557
1558 return status;
1559}
1560
1561static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
1562{
1563 struct f_mbim *mbim = func_to_mbim(f);
1564
1565 if (gadget_is_dualspeed(c->cdev->gadget))
1566 usb_free_descriptors(f->hs_descriptors);
1567 usb_free_descriptors(f->descriptors);
1568
1569 kfree(mbim->not_port.notify_req->buf);
1570 usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
Jack Pham2df2f702012-10-11 19:08:24 -07001571
1572 mbim_ext_config_desc.function.subCompatibleID[0] = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001573}
1574
1575/**
1576 * mbim_bind_config - add MBIM link to a configuration
1577 * @c: the configuration to support the network link
1578 * Context: single threaded during gadget setup
1579 * Returns zero on success, else negative errno.
1580 */
1581int mbim_bind_config(struct usb_configuration *c, unsigned portno)
1582{
1583 struct f_mbim *mbim = NULL;
1584 int status = 0;
1585
1586 pr_info("port number %u", portno);
1587
1588 if (portno >= nr_mbim_ports) {
1589 pr_err("Can not add port %u. Max ports = %d",
1590 portno, nr_mbim_ports);
1591 return -ENODEV;
1592 }
1593
1594 status = mbim_bam_setup(nr_mbim_ports);
1595 if (status) {
1596 pr_err("bam setup failed");
1597 return status;
1598 }
1599
1600 /* maybe allocate device-global string IDs */
1601 if (mbim_string_defs[0].id == 0) {
1602
1603 /* control interface label */
1604 status = usb_string_id(c->cdev);
1605 if (status < 0)
1606 return status;
1607 mbim_string_defs[STRING_CTRL_IDX].id = status;
1608 mbim_control_intf.iInterface = status;
1609
1610 /* data interface label */
1611 status = usb_string_id(c->cdev);
1612 if (status < 0)
1613 return status;
1614 mbim_string_defs[STRING_DATA_IDX].id = status;
1615 mbim_data_nop_intf.iInterface = status;
1616 mbim_data_intf.iInterface = status;
1617 }
1618
1619 /* allocate and initialize one new instance */
1620 mbim = mbim_ports[0].port;
1621 if (!mbim) {
1622 pr_info("mbim struct not allocated");
1623 return -ENOMEM;
1624 }
1625
1626 mbim->cdev = c->cdev;
1627
Anna Perela8c991d2012-04-09 16:44:46 +03001628 mbim_reset_values(mbim);
1629
1630 mbim->function.name = "usb_mbim";
1631 mbim->function.strings = mbim_strings;
1632 mbim->function.bind = mbim_bind;
1633 mbim->function.unbind = mbim_unbind;
1634 mbim->function.set_alt = mbim_set_alt;
1635 mbim->function.get_alt = mbim_get_alt;
1636 mbim->function.setup = mbim_setup;
1637 mbim->function.disable = mbim_disable;
Anna Perel557bf722012-09-20 11:16:35 +03001638 mbim->function.suspend = mbim_suspend;
1639 mbim->function.resume = mbim_resume;
Anna Perela8c991d2012-04-09 16:44:46 +03001640
1641 INIT_LIST_HEAD(&mbim->cpkt_req_q);
1642 INIT_LIST_HEAD(&mbim->cpkt_resp_q);
1643
1644 status = usb_add_function(c, &mbim->function);
1645
1646 pr_info("Exit status %d", status);
1647
1648 return status;
1649}
1650
1651/* ------------ MBIM DRIVER File Operations API for USER SPACE ------------ */
1652
1653static ssize_t
1654mbim_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
1655{
1656 struct f_mbim *dev = fp->private_data;
1657 struct ctrl_pkt *cpkt = NULL;
1658 int ret = 0;
1659
1660 pr_debug("Enter(%d)\n", count);
1661
1662 if (!dev) {
1663 pr_err("Received NULL mbim pointer\n");
1664 return -ENODEV;
1665 }
1666
1667 if (count > MBIM_BULK_BUFFER_SIZE) {
1668 pr_err("Buffer size is too big %d, should be at most %d\n",
1669 count, MBIM_BULK_BUFFER_SIZE);
1670 return -EINVAL;
1671 }
1672
1673 if (mbim_lock(&dev->read_excl)) {
1674 pr_err("Previous reading is not finished yet\n");
1675 return -EBUSY;
1676 }
1677
1678 /* block until mbim online */
1679 while (!(atomic_read(&dev->online) || atomic_read(&dev->error))) {
1680 pr_err("USB cable not connected. Wait.\n");
1681 ret = wait_event_interruptible(dev->read_wq,
1682 (atomic_read(&dev->online) ||
1683 atomic_read(&dev->error)));
1684 if (ret < 0) {
1685 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001686 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001687 }
1688 }
1689
1690 if (atomic_read(&dev->error)) {
1691 mbim_unlock(&dev->read_excl);
1692 return -EIO;
1693 }
1694
1695 while (list_empty(&dev->cpkt_req_q)) {
Anna Perel3747fdae2013-02-17 15:19:04 +02001696 pr_debug("Requests list is empty. Wait.\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001697 ret = wait_event_interruptible(dev->read_wq,
1698 !list_empty(&dev->cpkt_req_q));
1699 if (ret < 0) {
1700 pr_err("Waiting failed\n");
1701 mbim_unlock(&dev->read_excl);
Anna Perel96eea9d2012-12-09 14:08:04 +02001702 return -ERESTARTSYS;
Anna Perela8c991d2012-04-09 16:44:46 +03001703 }
1704 pr_debug("Received request packet\n");
1705 }
1706
1707 cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
1708 list);
1709 if (cpkt->len > count) {
1710 mbim_unlock(&dev->read_excl);
1711 pr_err("cpkt size too big:%d > buf size:%d\n",
1712 cpkt->len, count);
1713 return -ENOMEM;
1714 }
1715
1716 pr_debug("cpkt size:%d\n", cpkt->len);
1717
1718 list_del(&cpkt->list);
1719 mbim_unlock(&dev->read_excl);
1720
1721 ret = copy_to_user(buf, cpkt->buf, cpkt->len);
1722 if (ret) {
1723 pr_err("copy_to_user failed: err %d\n", ret);
Anna Perel96eea9d2012-12-09 14:08:04 +02001724 ret = -ENOMEM;
Anna Perela8c991d2012-04-09 16:44:46 +03001725 } else {
1726 pr_debug("copied %d bytes to user\n", cpkt->len);
1727 ret = cpkt->len;
1728 }
1729
1730 mbim_free_ctrl_pkt(cpkt);
1731
1732 return ret;
1733}
1734
1735static ssize_t
1736mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
1737{
1738 struct f_mbim *dev = fp->private_data;
1739 struct ctrl_pkt *cpkt = NULL;
1740 int ret = 0;
1741
1742 pr_debug("Enter(%d)", count);
1743
1744 if (!dev) {
1745 pr_err("Received NULL mbim pointer\n");
1746 return -ENODEV;
1747 }
1748
1749 if (!count) {
1750 pr_err("zero length ctrl pkt\n");
1751 return -ENODEV;
1752 }
1753
1754 if (count > MAX_CTRL_PKT_SIZE) {
1755 pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
1756 count, MAX_CTRL_PKT_SIZE);
1757 return -ENOMEM;
1758 }
1759
1760 if (mbim_lock(&dev->write_excl)) {
1761 pr_err("Previous writing not finished yet\n");
1762 return -EBUSY;
1763 }
1764
1765 if (!atomic_read(&dev->online)) {
1766 pr_err("USB cable not connected\n");
1767 mbim_unlock(&dev->write_excl);
1768 return -EPIPE;
1769 }
1770
1771 cpkt = mbim_alloc_ctrl_pkt(count, GFP_KERNEL);
1772 if (!cpkt) {
1773 pr_err("failed to allocate ctrl pkt\n");
1774 mbim_unlock(&dev->write_excl);
1775 return -ENOMEM;
1776 }
1777
1778 ret = copy_from_user(cpkt->buf, buf, count);
1779 if (ret) {
1780 pr_err("copy_from_user failed err:%d\n", ret);
1781 mbim_free_ctrl_pkt(cpkt);
1782 mbim_unlock(&dev->write_excl);
1783 return 0;
1784 }
1785
1786 fmbim_send_cpkt_response(dev, cpkt);
1787
1788 mbim_unlock(&dev->write_excl);
1789
1790 pr_debug("Exit(%d)", count);
1791
1792 return count;
Anna Perel89ad1212012-06-13 17:17:24 +03001793
Anna Perela8c991d2012-04-09 16:44:46 +03001794}
1795
1796static int mbim_open(struct inode *ip, struct file *fp)
1797{
1798 pr_info("Open mbim driver\n");
1799
1800 while (!_mbim_dev) {
1801 pr_err("mbim_dev not created yet\n");
1802 return -ENODEV;
1803 }
1804
1805 if (mbim_lock(&_mbim_dev->open_excl)) {
1806 pr_err("Already opened\n");
1807 return -EBUSY;
1808 }
1809
1810 pr_info("Lock mbim_dev->open_excl for open\n");
1811
1812 if (!atomic_read(&_mbim_dev->online))
1813 pr_err("USB cable not connected\n");
1814
Anna Perela8c991d2012-04-09 16:44:46 +03001815 fp->private_data = _mbim_dev;
1816
1817 atomic_set(&_mbim_dev->error, 0);
1818
1819 spin_lock(&_mbim_dev->lock);
1820 _mbim_dev->is_open = true;
Anna Perela8c991d2012-04-09 16:44:46 +03001821 spin_unlock(&_mbim_dev->lock);
1822
1823 pr_info("Exit, mbim file opened\n");
1824
1825 return 0;
1826}
1827
1828static int mbim_release(struct inode *ip, struct file *fp)
1829{
1830 struct f_mbim *mbim = fp->private_data;
1831
1832 pr_info("Close mbim file");
1833
1834 spin_lock(&mbim->lock);
1835 mbim->is_open = false;
Anna Perela8c991d2012-04-09 16:44:46 +03001836 spin_unlock(&mbim->lock);
1837
Anna Perela8c991d2012-04-09 16:44:46 +03001838 mbim_unlock(&_mbim_dev->open_excl);
1839
1840 return 0;
1841}
1842
1843static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
1844{
1845 struct f_mbim *mbim = fp->private_data;
1846 int ret = 0;
1847
Anna Perel20c91152012-10-30 16:26:44 +02001848 pr_debug("Received command %d", cmd);
Anna Perela8c991d2012-04-09 16:44:46 +03001849
1850 if (mbim_lock(&mbim->ioctl_excl))
1851 return -EBUSY;
1852
1853 switch (cmd) {
1854 case MBIM_GET_NTB_SIZE:
1855 ret = copy_to_user((void __user *)arg,
1856 &mbim->ntb_input_size, sizeof(mbim->ntb_input_size));
1857 if (ret) {
1858 pr_err("copying to user space failed");
1859 ret = -EFAULT;
1860 }
1861 pr_info("Sent NTB size %d", mbim->ntb_input_size);
1862 break;
1863 case MBIM_GET_DATAGRAM_COUNT:
1864 ret = copy_to_user((void __user *)arg,
1865 &mbim->ntb_max_datagrams,
1866 sizeof(mbim->ntb_max_datagrams));
1867 if (ret) {
1868 pr_err("copying to user space failed");
1869 ret = -EFAULT;
1870 }
1871 pr_info("Sent NTB datagrams count %d",
1872 mbim->ntb_max_datagrams);
1873 break;
1874 default:
1875 pr_err("wrong parameter");
1876 ret = -EINVAL;
1877 }
1878
1879 mbim_unlock(&mbim->ioctl_excl);
1880
1881 return ret;
1882}
1883
1884/* file operations for MBIM device /dev/android_mbim */
1885static const struct file_operations mbim_fops = {
1886 .owner = THIS_MODULE,
1887 .open = mbim_open,
1888 .release = mbim_release,
1889 .read = mbim_read,
1890 .write = mbim_write,
1891 .unlocked_ioctl = mbim_ioctl,
1892};
1893
1894static struct miscdevice mbim_device = {
1895 .minor = MISC_DYNAMIC_MINOR,
1896 .name = "android_mbim",
1897 .fops = &mbim_fops,
1898};
1899
1900static int mbim_init(int instances)
1901{
1902 int i;
1903 struct f_mbim *dev = NULL;
1904 int ret;
1905
1906 pr_info("initialize %d instances\n", instances);
1907
1908 if (instances > NR_MBIM_PORTS) {
1909 pr_err("Max-%d instances supported\n", NR_MBIM_PORTS);
1910 return -EINVAL;
1911 }
1912
1913 for (i = 0; i < instances; i++) {
1914 dev = kzalloc(sizeof(struct f_mbim), GFP_KERNEL);
1915 if (!dev) {
1916 pr_err("Failed to allocate mbim dev\n");
1917 ret = -ENOMEM;
1918 goto fail_probe;
1919 }
1920
1921 dev->port_num = i;
1922 spin_lock_init(&dev->lock);
1923 INIT_LIST_HEAD(&dev->cpkt_req_q);
1924 INIT_LIST_HEAD(&dev->cpkt_resp_q);
1925
1926 mbim_ports[i].port = dev;
1927 mbim_ports[i].port_num = i;
1928
1929 init_waitqueue_head(&dev->read_wq);
1930 init_waitqueue_head(&dev->write_wq);
1931
1932 atomic_set(&dev->open_excl, 0);
1933 atomic_set(&dev->ioctl_excl, 0);
1934 atomic_set(&dev->read_excl, 0);
1935 atomic_set(&dev->write_excl, 0);
1936
1937 nr_mbim_ports++;
1938
1939 }
1940
1941 _mbim_dev = dev;
1942 ret = misc_register(&mbim_device);
1943 if (ret) {
1944 pr_err("mbim driver failed to register");
1945 goto fail_probe;
1946 }
1947
1948 pr_info("Initialized %d ports\n", nr_mbim_ports);
1949
1950 return ret;
1951
1952fail_probe:
1953 pr_err("Failed");
1954 for (i = 0; i < nr_mbim_ports; i++) {
1955 kfree(mbim_ports[i].port);
1956 mbim_ports[i].port = NULL;
1957 }
1958
1959 return ret;
1960}
1961
1962static void fmbim_cleanup(void)
1963{
1964 int i = 0;
1965
1966 pr_info("Enter");
1967
1968 for (i = 0; i < nr_mbim_ports; i++) {
1969 kfree(mbim_ports[i].port);
1970 mbim_ports[i].port = NULL;
1971 }
1972 nr_mbim_ports = 0;
1973
1974 misc_deregister(&mbim_device);
1975
1976 _mbim_dev = NULL;
1977}
1978