blob: 65b48909ebc93949a2b29420bdba828d4ce0d9dc [file] [log] [blame]
Anna Perela8c991d2012-04-09 16:44:46 +03001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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,
69};
70
71struct f_mbim {
Anna Perel557bf722012-09-20 11:16:35 +030072 struct usb_function function;
73 struct usb_composite_dev *cdev;
Anna Perela8c991d2012-04-09 16:44:46 +030074
75 atomic_t online;
76 bool is_open;
77
78 atomic_t open_excl;
79 atomic_t ioctl_excl;
80 atomic_t read_excl;
81 atomic_t write_excl;
82
83 wait_queue_head_t read_wq;
84 wait_queue_head_t write_wq;
85
86 u8 port_num;
87 struct data_port bam_port;
88 struct mbim_notify_port not_port;
89
90 struct mbim_ep_descs fs;
91 struct mbim_ep_descs hs;
92
93 u8 ctrl_id, data_id;
94
95 struct ndp_parser_opts *parser_opts;
96
97 spinlock_t lock;
98
99 struct list_head cpkt_req_q;
100 struct list_head cpkt_resp_q;
101
102 u32 ntb_input_size;
103 u16 ntb_max_datagrams;
104
Anna Perela8c991d2012-04-09 16:44:46 +0300105 atomic_t error;
106};
107
108struct mbim_ntb_input_size {
109 u32 ntb_input_size;
110 u16 ntb_max_datagrams;
111 u16 reserved;
112};
113
114/* temporary variable used between mbim_open() and mbim_gadget_bind() */
115static struct f_mbim *_mbim_dev;
116
117static unsigned int nr_mbim_ports;
118
119static struct mbim_ports {
120 struct f_mbim *port;
121 unsigned port_num;
122} mbim_ports[NR_MBIM_PORTS];
123
124static inline struct f_mbim *func_to_mbim(struct usb_function *f)
125{
126 return container_of(f, struct f_mbim, function);
127}
128
129/* peak (theoretical) bulk transfer rate in bits-per-second */
130static inline unsigned mbim_bitrate(struct usb_gadget *g)
131{
132 if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
133 return 13 * 512 * 8 * 1000 * 8;
134 else
135 return 19 * 64 * 1 * 1000 * 8;
136}
137
138/*-------------------------------------------------------------------------*/
139
140#define NTB_DEFAULT_IN_SIZE (0x4000)
141#define NTB_OUT_SIZE (0x1000)
142#define NDP_IN_DIVISOR (0x4)
143
144#define FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
145
146static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
147 .wLength = sizeof ntb_parameters,
148 .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
149 .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
150 .wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
151 .wNdpInPayloadRemainder = cpu_to_le16(0),
152 .wNdpInAlignment = cpu_to_le16(4),
153
154 .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
155 .wNdpOutDivisor = cpu_to_le16(4),
156 .wNdpOutPayloadRemainder = cpu_to_le16(0),
157 .wNdpOutAlignment = cpu_to_le16(4),
Anna Perelf99cd0c2012-05-03 13:30:26 +0300158 .wNtbOutMaxDatagrams = 0,
Anna Perela8c991d2012-04-09 16:44:46 +0300159};
160
161/*
162 * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
163 * packet, to simplify cancellation; and a big transfer interval, to
164 * waste less bandwidth.
165 */
166
167#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
168#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
169
170static struct usb_interface_assoc_descriptor mbim_iad_desc = {
171 .bLength = sizeof mbim_iad_desc,
172 .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
173
174 /* .bFirstInterface = DYNAMIC, */
175 .bInterfaceCount = 2, /* control + data */
176 .bFunctionClass = 2,
177 .bFunctionSubClass = 0x0e,
178 .bFunctionProtocol = 0,
179 /* .iFunction = DYNAMIC */
180};
181
182/* interface descriptor: */
183static struct usb_interface_descriptor mbim_control_intf = {
184 .bLength = sizeof mbim_control_intf,
185 .bDescriptorType = USB_DT_INTERFACE,
186
187 /* .bInterfaceNumber = DYNAMIC */
188 .bNumEndpoints = 1,
189 .bInterfaceClass = 0x02,
190 .bInterfaceSubClass = 0x0e,
191 .bInterfaceProtocol = 0,
192 /* .iInterface = DYNAMIC */
193};
194
195static struct usb_cdc_header_desc mbim_header_desc = {
196 .bLength = sizeof mbim_header_desc,
197 .bDescriptorType = USB_DT_CS_INTERFACE,
198 .bDescriptorSubType = USB_CDC_HEADER_TYPE,
199
200 .bcdCDC = cpu_to_le16(0x0110),
201};
202
203static struct usb_cdc_union_desc mbim_union_desc = {
204 .bLength = sizeof(mbim_union_desc),
205 .bDescriptorType = USB_DT_CS_INTERFACE,
206 .bDescriptorSubType = USB_CDC_UNION_TYPE,
207 /* .bMasterInterface0 = DYNAMIC */
208 /* .bSlaveInterface0 = DYNAMIC */
209};
210
211static struct usb_cdc_mbb_desc mbb_desc = {
212 .bLength = sizeof mbb_desc,
213 .bDescriptorType = USB_DT_CS_INTERFACE,
214 .bDescriptorSubType = USB_CDC_MBB_TYPE,
215
216 .bcdMbbVersion = cpu_to_le16(0x0100),
217
218 .wMaxControlMessage = cpu_to_le16(0x1000),
Anna Perel3354bdc2012-12-09 12:08:10 +0200219 .bNumberFilters = 0x20,
Anna Perela8c991d2012-04-09 16:44:46 +0300220 .bMaxFilterSize = 0x80,
Anna Perel26ae27c2012-05-23 18:07:31 +0300221 .wMaxSegmentSize = cpu_to_le16(0xfe0),
Anna Perela8c991d2012-04-09 16:44:46 +0300222 .bmNetworkCapabilities = 0x20,
223};
224
225/* the default data interface has no endpoints ... */
226static struct usb_interface_descriptor mbim_data_nop_intf = {
227 .bLength = sizeof mbim_data_nop_intf,
228 .bDescriptorType = USB_DT_INTERFACE,
229
230 /* .bInterfaceNumber = DYNAMIC */
231 .bAlternateSetting = 0,
232 .bNumEndpoints = 0,
233 .bInterfaceClass = 0x0a,
234 .bInterfaceSubClass = 0,
235 .bInterfaceProtocol = 0x02,
236 /* .iInterface = DYNAMIC */
237};
238
239/* ... but the "real" data interface has two bulk endpoints */
240static struct usb_interface_descriptor mbim_data_intf = {
241 .bLength = sizeof mbim_data_intf,
242 .bDescriptorType = USB_DT_INTERFACE,
243
244 /* .bInterfaceNumber = DYNAMIC */
245 .bAlternateSetting = 1,
246 .bNumEndpoints = 2,
247 .bInterfaceClass = 0x0a,
248 .bInterfaceSubClass = 0,
249 .bInterfaceProtocol = 0x02,
250 /* .iInterface = DYNAMIC */
251};
252
253/* full speed support: */
254
255static struct usb_endpoint_descriptor fs_mbim_notify_desc = {
256 .bLength = USB_DT_ENDPOINT_SIZE,
257 .bDescriptorType = USB_DT_ENDPOINT,
258
259 .bEndpointAddress = USB_DIR_IN,
260 .bmAttributes = USB_ENDPOINT_XFER_INT,
261 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
262 .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
263};
264
265static struct usb_endpoint_descriptor fs_mbim_in_desc = {
266 .bLength = USB_DT_ENDPOINT_SIZE,
267 .bDescriptorType = USB_DT_ENDPOINT,
268
269 .bEndpointAddress = USB_DIR_IN,
270 .bmAttributes = USB_ENDPOINT_XFER_BULK,
271};
272
273static struct usb_endpoint_descriptor fs_mbim_out_desc = {
274 .bLength = USB_DT_ENDPOINT_SIZE,
275 .bDescriptorType = USB_DT_ENDPOINT,
276
277 .bEndpointAddress = USB_DIR_OUT,
278 .bmAttributes = USB_ENDPOINT_XFER_BULK,
279};
280
281static struct usb_descriptor_header *mbim_fs_function[] = {
282 (struct usb_descriptor_header *) &mbim_iad_desc,
283 /* MBIM control descriptors */
284 (struct usb_descriptor_header *) &mbim_control_intf,
285 (struct usb_descriptor_header *) &mbim_header_desc,
286 (struct usb_descriptor_header *) &mbb_desc,
287 (struct usb_descriptor_header *) &fs_mbim_notify_desc,
288 /* data interface, altsettings 0 and 1 */
289 (struct usb_descriptor_header *) &mbim_data_nop_intf,
290 (struct usb_descriptor_header *) &mbim_data_intf,
291 (struct usb_descriptor_header *) &fs_mbim_in_desc,
292 (struct usb_descriptor_header *) &fs_mbim_out_desc,
293 NULL,
294};
295
296/* high speed support: */
297
298static struct usb_endpoint_descriptor hs_mbim_notify_desc = {
299 .bLength = USB_DT_ENDPOINT_SIZE,
300 .bDescriptorType = USB_DT_ENDPOINT,
301
302 .bEndpointAddress = USB_DIR_IN,
303 .bmAttributes = USB_ENDPOINT_XFER_INT,
304 .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
305 .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
306};
307static struct usb_endpoint_descriptor hs_mbim_in_desc = {
308 .bLength = USB_DT_ENDPOINT_SIZE,
309 .bDescriptorType = USB_DT_ENDPOINT,
310
311 .bEndpointAddress = USB_DIR_IN,
312 .bmAttributes = USB_ENDPOINT_XFER_BULK,
313 .wMaxPacketSize = cpu_to_le16(512),
314};
315
316static struct usb_endpoint_descriptor hs_mbim_out_desc = {
317 .bLength = USB_DT_ENDPOINT_SIZE,
318 .bDescriptorType = USB_DT_ENDPOINT,
319
320 .bEndpointAddress = USB_DIR_OUT,
321 .bmAttributes = USB_ENDPOINT_XFER_BULK,
322 .wMaxPacketSize = cpu_to_le16(512),
323};
324
325static struct usb_descriptor_header *mbim_hs_function[] = {
326 (struct usb_descriptor_header *) &mbim_iad_desc,
327 /* MBIM control descriptors */
328 (struct usb_descriptor_header *) &mbim_control_intf,
329 (struct usb_descriptor_header *) &mbim_header_desc,
330 (struct usb_descriptor_header *) &mbb_desc,
331 (struct usb_descriptor_header *) &hs_mbim_notify_desc,
332 /* data interface, altsettings 0 and 1 */
333 (struct usb_descriptor_header *) &mbim_data_nop_intf,
334 (struct usb_descriptor_header *) &mbim_data_intf,
335 (struct usb_descriptor_header *) &hs_mbim_in_desc,
336 (struct usb_descriptor_header *) &hs_mbim_out_desc,
337 NULL,
338};
339
340/* string descriptors: */
341
342#define STRING_CTRL_IDX 0
343#define STRING_DATA_IDX 1
344
345static struct usb_string mbim_string_defs[] = {
346 [STRING_CTRL_IDX].s = "MBIM Control",
347 [STRING_DATA_IDX].s = "MBIM Data",
348 { } /* end of list */
349};
350
351static struct usb_gadget_strings mbim_string_table = {
352 .language = 0x0409, /* en-us */
353 .strings = mbim_string_defs,
354};
355
356static struct usb_gadget_strings *mbim_strings[] = {
357 &mbim_string_table,
358 NULL,
359};
360
Jack Pham2df2f702012-10-11 19:08:24 -0700361/* Microsoft OS Descriptors */
362
363/*
364 * We specify our own bMS_VendorCode byte which Windows will use
365 * as the bRequest value in subsequent device get requests.
366 */
367#define MBIM_VENDOR_CODE 0xA5
368
369/* Microsoft OS String */
370static u8 mbim_os_string[] = {
371 18, /* sizeof(mtp_os_string) */
372 USB_DT_STRING,
373 /* Signature field: "MSFT100" */
374 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
375 /* vendor code */
376 MBIM_VENDOR_CODE,
377 /* padding */
378 0
379};
380
381/* Microsoft Extended Configuration Descriptor Header Section */
382struct mbim_ext_config_desc_header {
383 __le32 dwLength;
384 __u16 bcdVersion;
385 __le16 wIndex;
386 __u8 bCount;
387 __u8 reserved[7];
388};
389
390/* Microsoft Extended Configuration Descriptor Function Section */
391struct mbim_ext_config_desc_function {
392 __u8 bFirstInterfaceNumber;
393 __u8 bInterfaceCount;
394 __u8 compatibleID[8];
395 __u8 subCompatibleID[8];
396 __u8 reserved[6];
397};
398
399/* Microsoft Extended Configuration Descriptor */
400static struct {
401 struct mbim_ext_config_desc_header header;
402 struct mbim_ext_config_desc_function function;
403} mbim_ext_config_desc = {
404 .header = {
405 .dwLength = __constant_cpu_to_le32(sizeof mbim_ext_config_desc),
406 .bcdVersion = __constant_cpu_to_le16(0x0100),
407 .wIndex = __constant_cpu_to_le16(4),
408 .bCount = 1,
409 },
410 .function = {
411 .bFirstInterfaceNumber = 0,
412 .bInterfaceCount = 1,
413 .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' },
414 /* .subCompatibleID = DYNAMIC */
415 },
416};
417
Anna Perela8c991d2012-04-09 16:44:46 +0300418/*
419 * Here are options for the Datagram Pointer table (NDP) parser.
420 * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
421 * in NDP16 offsets and sizes fields are 1 16bit word wide,
422 * in NDP32 -- 2 16bit words wide. Also signatures are different.
423 * To make the parser code the same, put the differences in the structure,
424 * and switch pointers to the structures when the format is changed.
425 */
426
427struct ndp_parser_opts {
428 u32 nth_sign;
429 u32 ndp_sign;
430 unsigned nth_size;
431 unsigned ndp_size;
432 unsigned ndplen_align;
433 /* sizes in u16 units */
434 unsigned dgram_item_len; /* index or length */
435 unsigned block_length;
436 unsigned fp_index;
437 unsigned reserved1;
438 unsigned reserved2;
439 unsigned next_fp_index;
440};
441
442#define INIT_NDP16_OPTS { \
443 .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
444 .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
445 .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
446 .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
447 .ndplen_align = 4, \
448 .dgram_item_len = 1, \
449 .block_length = 1, \
450 .fp_index = 1, \
451 .reserved1 = 0, \
452 .reserved2 = 0, \
453 .next_fp_index = 1, \
454}
455
456#define INIT_NDP32_OPTS { \
457 .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
458 .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
459 .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
460 .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
461 .ndplen_align = 8, \
462 .dgram_item_len = 2, \
463 .block_length = 2, \
464 .fp_index = 2, \
465 .reserved1 = 1, \
466 .reserved2 = 2, \
467 .next_fp_index = 2, \
468}
469
470static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
471static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
472
473static inline int mbim_lock(atomic_t *excl)
474{
475 if (atomic_inc_return(excl) == 1) {
476 return 0;
477 } else {
478 atomic_dec(excl);
479 return -EBUSY;
480 }
481}
482
483static inline void mbim_unlock(atomic_t *excl)
484{
485 atomic_dec(excl);
486}
487
488static struct ctrl_pkt *mbim_alloc_ctrl_pkt(unsigned len, gfp_t flags)
489{
490 struct ctrl_pkt *pkt;
491
492 pkt = kzalloc(sizeof(struct ctrl_pkt), flags);
493 if (!pkt)
494 return ERR_PTR(-ENOMEM);
495
496 pkt->buf = kmalloc(len, flags);
497 if (!pkt->buf) {
498 kfree(pkt);
499 return ERR_PTR(-ENOMEM);
500 }
501 pkt->len = len;
502
503 return pkt;
504}
505
506static void mbim_free_ctrl_pkt(struct ctrl_pkt *pkt)
507{
508 if (pkt) {
509 kfree(pkt->buf);
510 kfree(pkt);
511 }
512}
513
514static struct usb_request *mbim_alloc_req(struct usb_ep *ep, int buffer_size)
515{
516 struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
517 if (!req)
518 return NULL;
519
520 req->buf = kmalloc(buffer_size, GFP_KERNEL);
521 if (!req->buf) {
522 usb_ep_free_request(ep, req);
523 return NULL;
524 }
525 req->length = buffer_size;
526 return req;
527}
528
529void fmbim_free_req(struct usb_ep *ep, struct usb_request *req)
530{
531 if (req) {
532 kfree(req->buf);
533 usb_ep_free_request(ep, req);
534 }
535}
536
537static void fmbim_ctrl_response_available(struct f_mbim *dev)
538{
539 struct usb_request *req = dev->not_port.notify_req;
540 struct usb_cdc_notification *event = NULL;
541 unsigned long flags;
542 int ret;
543
Anna Perel68aeb172012-10-28 09:00:45 +0200544 pr_debug("dev:%p portno#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300545
546 spin_lock_irqsave(&dev->lock, flags);
547
548 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200549 pr_err("dev:%p is not online\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300550 spin_unlock_irqrestore(&dev->lock, flags);
551 return;
552 }
553
554 if (!req) {
Anna Perel20c91152012-10-30 16:26:44 +0200555 pr_err("dev:%p req is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300556 spin_unlock_irqrestore(&dev->lock, flags);
557 return;
558 }
559
560 if (!req->buf) {
Anna Perel20c91152012-10-30 16:26:44 +0200561 pr_err("dev:%p req->buf is NULL\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300562 spin_unlock_irqrestore(&dev->lock, flags);
563 return;
564 }
565
Anna Perel68aeb172012-10-28 09:00:45 +0200566 if (atomic_inc_return(&dev->not_port.notify_count) != 1) {
567 pr_debug("delay ep_queue: notifications queue is busy[%d]",
568 atomic_read(&dev->not_port.notify_count));
569 spin_unlock_irqrestore(&dev->lock, flags);
570 return;
571 }
Anna Perela8c991d2012-04-09 16:44:46 +0300572
573 event = req->buf;
574 event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
575 | USB_RECIP_INTERFACE;
576 event->bNotificationType = USB_CDC_NOTIFY_RESPONSE_AVAILABLE;
577 event->wValue = cpu_to_le16(0);
578 event->wIndex = cpu_to_le16(dev->ctrl_id);
579 event->wLength = cpu_to_le16(0);
580 spin_unlock_irqrestore(&dev->lock, flags);
581
Anna Perela8c991d2012-04-09 16:44:46 +0300582 ret = usb_ep_queue(dev->not_port.notify,
583 dev->not_port.notify_req, GFP_ATOMIC);
584 if (ret) {
585 atomic_dec(&dev->not_port.notify_count);
586 pr_err("ep enqueue error %d\n", ret);
587 }
588
Anna Perel68aeb172012-10-28 09:00:45 +0200589 pr_debug("Successful Exit");
Anna Perela8c991d2012-04-09 16:44:46 +0300590}
591
592static int
593fmbim_send_cpkt_response(struct f_mbim *gr, struct ctrl_pkt *cpkt)
594{
595 struct f_mbim *dev = gr;
596 unsigned long flags;
597
598 if (!gr || !cpkt) {
599 pr_err("Invalid cpkt, dev:%p cpkt:%p\n",
600 gr, cpkt);
601 return -ENODEV;
602 }
603
Anna Perel20c91152012-10-30 16:26:44 +0200604 pr_debug("dev:%p port_num#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300605
606 if (!atomic_read(&dev->online)) {
Anna Perel20c91152012-10-30 16:26:44 +0200607 pr_err("dev:%p is not connected\n", dev);
Anna Perela8c991d2012-04-09 16:44:46 +0300608 mbim_free_ctrl_pkt(cpkt);
609 return 0;
610 }
611
612 spin_lock_irqsave(&dev->lock, flags);
Anna Perel40c550c2012-04-11 14:09:27 +0300613 list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
Anna Perela8c991d2012-04-09 16:44:46 +0300614 spin_unlock_irqrestore(&dev->lock, flags);
615
616 fmbim_ctrl_response_available(dev);
617
618 return 0;
619}
620
621/* ---------------------------- BAM INTERFACE ----------------------------- */
622
623static int mbim_bam_setup(int no_ports)
624{
625 int ret;
626
627 pr_info("no_ports:%d\n", no_ports);
628
629 ret = bam_data_setup(no_ports);
630 if (ret) {
631 pr_err("bam_data_setup failed err: %d\n", ret);
632 return ret;
633 }
634
635 pr_info("Initialized %d ports\n", no_ports);
636 return 0;
637}
638
639static int mbim_bam_connect(struct f_mbim *dev)
640{
641 int ret;
642
643 pr_info("dev:%p portno:%d\n", dev, dev->port_num);
644
645 ret = bam_data_connect(&dev->bam_port, dev->port_num, dev->port_num);
646 if (ret) {
647 pr_err("bam_data_setup failed: err:%d\n",
648 ret);
649 return ret;
650 } else {
651 pr_info("mbim bam connected\n");
652 }
653
654 return 0;
655}
656
657static int mbim_bam_disconnect(struct f_mbim *dev)
658{
659 pr_info("dev:%p port:%d. Do nothing.\n",
660 dev, dev->port_num);
661
662 /* bam_data_disconnect(&dev->bam_port, dev->port_num); */
663
664 return 0;
665}
666
667/* -------------------------------------------------------------------------*/
668
669static inline void mbim_reset_values(struct f_mbim *mbim)
670{
671 mbim->parser_opts = &ndp16_opts;
672
673 mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
674
Anna Perela8c991d2012-04-09 16:44:46 +0300675 atomic_set(&mbim->online, 0);
676}
677
Anna Perel86ea7c92012-04-24 14:31:29 +0300678static void mbim_reset_function_queue(struct f_mbim *dev)
679{
680 struct ctrl_pkt *cpkt = NULL;
681
682 pr_debug("Queue empty packet for QBI");
683
684 spin_lock(&dev->lock);
685 if (!dev->is_open) {
686 pr_err("%s: mbim file handler %p is not open", __func__, dev);
687 spin_unlock(&dev->lock);
688 return;
689 }
690
691 cpkt = mbim_alloc_ctrl_pkt(0, GFP_ATOMIC);
692 if (!cpkt) {
693 pr_err("%s: Unable to allocate reset function pkt\n", __func__);
694 spin_unlock(&dev->lock);
695 return;
696 }
697
698 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
699 spin_unlock(&dev->lock);
700
701 pr_debug("%s: Wake up read queue", __func__);
702 wake_up(&dev->read_wq);
703}
704
705static void fmbim_reset_cmd_complete(struct usb_ep *ep, struct usb_request *req)
706{
707 struct f_mbim *dev = req->context;
708
709 mbim_reset_function_queue(dev);
710}
711
712static void mbim_clear_queues(struct f_mbim *mbim)
713{
714 struct ctrl_pkt *cpkt = NULL;
715 struct list_head *act, *tmp;
716
717 spin_lock(&mbim->lock);
718 list_for_each_safe(act, tmp, &mbim->cpkt_req_q) {
719 cpkt = list_entry(act, struct ctrl_pkt, list);
720 list_del(&cpkt->list);
721 mbim_free_ctrl_pkt(cpkt);
722 }
723 list_for_each_safe(act, tmp, &mbim->cpkt_resp_q) {
724 cpkt = list_entry(act, struct ctrl_pkt, list);
725 list_del(&cpkt->list);
726 mbim_free_ctrl_pkt(cpkt);
727 }
728 spin_unlock(&mbim->lock);
729}
730
Anna Perela8c991d2012-04-09 16:44:46 +0300731/*
732 * Context: mbim->lock held
733 */
734static void mbim_do_notify(struct f_mbim *mbim)
735{
736 struct usb_request *req = mbim->not_port.notify_req;
737 struct usb_cdc_notification *event;
738 struct usb_composite_dev *cdev = mbim->cdev;
739 __le32 *data;
740 int status;
741
Anna Perel20c91152012-10-30 16:26:44 +0200742 pr_debug("notify_state: %d", mbim->not_port.notify_state);
Anna Perela8c991d2012-04-09 16:44:46 +0300743
744 if (!req)
745 return;
746
747 event = req->buf;
748
749 switch (mbim->not_port.notify_state) {
750
751 case NCM_NOTIFY_NONE:
Anna Perel68aeb172012-10-28 09:00:45 +0200752 pr_debug("Notification %02x sent\n", event->bNotificationType);
753
754 if (atomic_read(&mbim->not_port.notify_count) <= 0) {
755 pr_debug("notify_none: done");
756 return;
757 }
758
759 spin_unlock(&mbim->lock);
760 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
761 spin_lock(&mbim->lock);
762 if (status) {
763 atomic_dec(&mbim->not_port.notify_count);
764 pr_err("Queue notify request failed, err: %d", status);
765 }
766
Anna Perela8c991d2012-04-09 16:44:46 +0300767 return;
768
769 case NCM_NOTIFY_CONNECT:
770 event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
771 if (mbim->is_open)
772 event->wValue = cpu_to_le16(1);
773 else
774 event->wValue = cpu_to_le16(0);
775 event->wLength = 0;
776 req->length = sizeof *event;
777
778 pr_info("notify connect %s\n",
779 mbim->is_open ? "true" : "false");
780 mbim->not_port.notify_state = NCM_NOTIFY_NONE;
781 break;
782
783 case NCM_NOTIFY_SPEED:
784 event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
785 event->wValue = cpu_to_le16(0);
786 event->wLength = cpu_to_le16(8);
787 req->length = NCM_STATUS_BYTECOUNT;
788
789 /* SPEED_CHANGE data is up/down speeds in bits/sec */
790 data = req->buf + sizeof *event;
791 data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
792 data[1] = data[0];
793
794 pr_info("notify speed %d\n",
795 mbim_bitrate(cdev->gadget));
796 mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
797 break;
798 }
Anna Perel68aeb172012-10-28 09:00:45 +0200799
Anna Perela8c991d2012-04-09 16:44:46 +0300800 event->bmRequestType = 0xA1;
801 event->wIndex = cpu_to_le16(mbim->ctrl_id);
802
Anna Perela8c991d2012-04-09 16:44:46 +0300803 /*
804 * In double buffering if there is a space in FIFO,
805 * completion callback can be called right after the call,
806 * so unlocking
807 */
Anna Perel68aeb172012-10-28 09:00:45 +0200808 atomic_inc(&mbim->not_port.notify_count);
809 pr_debug("queue request: notify_count = %d",
810 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300811 spin_unlock(&mbim->lock);
812 status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
813 spin_lock(&mbim->lock);
Anna Perel68aeb172012-10-28 09:00:45 +0200814 if (status) {
Anna Perela8c991d2012-04-09 16:44:46 +0300815 atomic_dec(&mbim->not_port.notify_count);
816 pr_err("usb_ep_queue failed, err: %d", status);
817 }
818}
819
820/*
821 * Context: mbim->lock held
822 */
823static void mbim_notify(struct f_mbim *mbim)
824{
825 /*
826 * If mbim_notify() is called before the second (CONNECT)
827 * notification is sent, then it will reset to send the SPEED
828 * notificaion again (and again, and again), but it's not a problem
829 */
Anna Perel20c91152012-10-30 16:26:44 +0200830 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300831
832 mbim->not_port.notify_state = NCM_NOTIFY_SPEED;
833 mbim_do_notify(mbim);
834}
835
836static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
837{
838 struct f_mbim *mbim = req->context;
839 struct usb_cdc_notification *event = req->buf;
840
Anna Perel68aeb172012-10-28 09:00:45 +0200841 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300842
843 spin_lock(&mbim->lock);
844 switch (req->status) {
845 case 0:
Anna Perel68aeb172012-10-28 09:00:45 +0200846 atomic_dec(&mbim->not_port.notify_count);
847 pr_debug("notify_count = %d",
848 atomic_read(&mbim->not_port.notify_count));
Anna Perela8c991d2012-04-09 16:44:46 +0300849 break;
850
851 case -ECONNRESET:
852 case -ESHUTDOWN:
853 /* connection gone */
854 mbim->not_port.notify_state = NCM_NOTIFY_NONE;
855 atomic_set(&mbim->not_port.notify_count, 0);
856 pr_info("ESHUTDOWN/ECONNRESET, connection gone");
Anna Perel86ea7c92012-04-24 14:31:29 +0300857 spin_unlock(&mbim->lock);
858 mbim_clear_queues(mbim);
859 mbim_reset_function_queue(mbim);
Anna Perel89ad1212012-06-13 17:17:24 +0300860 spin_lock(&mbim->lock);
Anna Perela8c991d2012-04-09 16:44:46 +0300861 break;
862 default:
863 pr_err("Unknown event %02x --> %d\n",
864 event->bNotificationType, req->status);
865 break;
866 }
867
Anna Perela8c991d2012-04-09 16:44:46 +0300868 mbim_do_notify(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300869 spin_unlock(&mbim->lock);
870
Anna Perel20c91152012-10-30 16:26:44 +0200871 pr_debug("dev:%p Exit\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300872}
873
874static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
875{
876 /* now for SET_NTB_INPUT_SIZE only */
877 unsigned in_size = 0;
878 struct usb_function *f = req->context;
879 struct f_mbim *mbim = func_to_mbim(f);
880 struct mbim_ntb_input_size *ntb = NULL;
881
Anna Perel20c91152012-10-30 16:26:44 +0200882 pr_debug("dev:%p\n", mbim);
Anna Perela8c991d2012-04-09 16:44:46 +0300883
884 req->context = NULL;
885 if (req->status || req->actual != req->length) {
886 pr_err("Bad control-OUT transfer\n");
887 goto invalid;
888 }
889
890 if (req->length == 4) {
891 in_size = get_unaligned_le32(req->buf);
892 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
893 in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
894 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
895 goto invalid;
896 }
897 } else if (req->length == 8) {
898 ntb = (struct mbim_ntb_input_size *)req->buf;
899 in_size = get_unaligned_le32(&(ntb->ntb_input_size));
900 if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
901 in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
902 pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
903 goto invalid;
904 }
905 mbim->ntb_max_datagrams =
906 get_unaligned_le16(&(ntb->ntb_max_datagrams));
907 } else {
908 pr_err("Illegal NTB length %d\n", in_size);
909 goto invalid;
910 }
911
Anna Perel20c91152012-10-30 16:26:44 +0200912 pr_debug("Set NTB INPUT SIZE %d\n", in_size);
Anna Perela8c991d2012-04-09 16:44:46 +0300913
914 mbim->ntb_input_size = in_size;
915 return;
916
917invalid:
918 usb_ep_set_halt(ep);
919
920 pr_err("dev:%p Failed\n", mbim);
921
922 return;
923}
924
925static void
926fmbim_cmd_complete(struct usb_ep *ep, struct usb_request *req)
927{
928 struct f_mbim *dev = req->context;
929 struct ctrl_pkt *cpkt = NULL;
930 int len = req->actual;
931
932 if (!dev) {
933 pr_err("mbim dev is null\n");
934 return;
935 }
936
937 if (req->status < 0) {
938 pr_err("mbim command error %d\n", req->status);
939 return;
940 }
941
Anna Perel20c91152012-10-30 16:26:44 +0200942 pr_debug("dev:%p port#%d\n", dev, dev->port_num);
Anna Perela8c991d2012-04-09 16:44:46 +0300943
Anna Perela8c991d2012-04-09 16:44:46 +0300944 cpkt = mbim_alloc_ctrl_pkt(len, GFP_ATOMIC);
945 if (!cpkt) {
946 pr_err("Unable to allocate ctrl pkt\n");
Anna Perela8c991d2012-04-09 16:44:46 +0300947 return;
948 }
949
Anna Perel20c91152012-10-30 16:26:44 +0200950 pr_debug("Add to cpkt_req_q packet with len = %d\n", len);
Anna Perela8c991d2012-04-09 16:44:46 +0300951 memcpy(cpkt->buf, req->buf, len);
Anna Perel20c91152012-10-30 16:26:44 +0200952
Anna Perel182ab572012-11-18 10:10:12 +0200953 spin_lock(&dev->lock);
954 if (!dev->is_open) {
955 pr_err("mbim file handler %p is not open", dev);
956 spin_unlock(&dev->lock);
957 mbim_free_ctrl_pkt(cpkt);
958 return;
959 }
960
Anna Perela8c991d2012-04-09 16:44:46 +0300961 list_add_tail(&cpkt->list, &dev->cpkt_req_q);
962 spin_unlock(&dev->lock);
963
964 /* wakeup read thread */
Anna Perel20c91152012-10-30 16:26:44 +0200965 pr_debug("Wake up read queue");
Anna Perela8c991d2012-04-09 16:44:46 +0300966 wake_up(&dev->read_wq);
967
968 return;
969}
970
971static int
972mbim_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
973{
974 struct f_mbim *mbim = func_to_mbim(f);
975 struct usb_composite_dev *cdev = mbim->cdev;
976 struct usb_request *req = cdev->req;
977 struct ctrl_pkt *cpkt = NULL;
978 int value = -EOPNOTSUPP;
979 u16 w_index = le16_to_cpu(ctrl->wIndex);
980 u16 w_value = le16_to_cpu(ctrl->wValue);
981 u16 w_length = le16_to_cpu(ctrl->wLength);
982
983 /*
984 * composite driver infrastructure handles everything except
985 * CDC class messages; interface activation uses set_alt().
986 */
987
988 if (!atomic_read(&mbim->online)) {
989 pr_info("usb cable is not connected\n");
990 return -ENOTCONN;
991 }
992
993 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
994 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
995 | USB_CDC_RESET_FUNCTION:
996
Anna Perel20c91152012-10-30 16:26:44 +0200997 pr_debug("USB_CDC_RESET_FUNCTION");
Anna Perela8c991d2012-04-09 16:44:46 +0300998 value = 0;
Anna Perel86ea7c92012-04-24 14:31:29 +0300999 req->complete = fmbim_reset_cmd_complete;
1000 req->context = mbim;
Anna Perela8c991d2012-04-09 16:44:46 +03001001 break;
1002
1003 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1004 | USB_CDC_SEND_ENCAPSULATED_COMMAND:
1005
Anna Perel20c91152012-10-30 16:26:44 +02001006 pr_debug("USB_CDC_SEND_ENCAPSULATED_COMMAND");
Anna Perela8c991d2012-04-09 16:44:46 +03001007
1008 if (w_length > req->length) {
Anna Perel20c91152012-10-30 16:26:44 +02001009 pr_debug("w_length > req->length: %d > %d",
Anna Perela8c991d2012-04-09 16:44:46 +03001010 w_length, req->length);
1011 }
1012 value = w_length;
1013 req->complete = fmbim_cmd_complete;
1014 req->context = mbim;
1015 break;
1016
1017 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1018 | USB_CDC_GET_ENCAPSULATED_RESPONSE:
1019
Anna Perel20c91152012-10-30 16:26:44 +02001020 pr_debug("USB_CDC_GET_ENCAPSULATED_RESPONSE");
Anna Perela8c991d2012-04-09 16:44:46 +03001021
1022 if (w_value) {
1023 pr_err("w_length > 0: %d", w_length);
1024 break;
1025 }
1026
Anna Perel20c91152012-10-30 16:26:44 +02001027 pr_debug("req%02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001028 ctrl->bRequestType, ctrl->bRequest,
1029 w_value, w_index, w_length);
1030
1031 spin_lock(&mbim->lock);
1032 if (list_empty(&mbim->cpkt_resp_q)) {
1033 pr_err("ctrl resp queue empty\n");
1034 spin_unlock(&mbim->lock);
1035 break;
1036 }
1037
1038 cpkt = list_first_entry(&mbim->cpkt_resp_q,
1039 struct ctrl_pkt, list);
1040 list_del(&cpkt->list);
1041 spin_unlock(&mbim->lock);
1042
1043 value = min_t(unsigned, w_length, cpkt->len);
1044 memcpy(req->buf, cpkt->buf, value);
1045 mbim_free_ctrl_pkt(cpkt);
1046
Anna Perel20c91152012-10-30 16:26:44 +02001047 pr_debug("copied encapsulated_response %d bytes",
Anna Perela8c991d2012-04-09 16:44:46 +03001048 value);
1049
1050 break;
1051
1052 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1053 | USB_CDC_GET_NTB_PARAMETERS:
1054
Anna Perel20c91152012-10-30 16:26:44 +02001055 pr_debug("USB_CDC_GET_NTB_PARAMETERS");
Anna Perela8c991d2012-04-09 16:44:46 +03001056
1057 if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
1058 break;
1059
1060 value = w_length > sizeof ntb_parameters ?
1061 sizeof ntb_parameters : w_length;
1062 memcpy(req->buf, &ntb_parameters, value);
1063 break;
1064
1065 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1066 | USB_CDC_GET_NTB_INPUT_SIZE:
1067
Anna Perel20c91152012-10-30 16:26:44 +02001068 pr_debug("USB_CDC_GET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001069
1070 if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
1071 break;
1072
1073 put_unaligned_le32(mbim->ntb_input_size, req->buf);
1074 value = 4;
Anna Perel20c91152012-10-30 16:26:44 +02001075 pr_debug("Reply to host INPUT SIZE %d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001076 mbim->ntb_input_size);
1077 break;
1078
1079 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1080 | USB_CDC_SET_NTB_INPUT_SIZE:
1081
Anna Perel20c91152012-10-30 16:26:44 +02001082 pr_debug("USB_CDC_SET_NTB_INPUT_SIZE");
Anna Perela8c991d2012-04-09 16:44:46 +03001083
1084 if (w_length != 4 && w_length != 8) {
1085 pr_err("wrong NTB length %d", w_length);
1086 break;
1087 }
1088
1089 if (w_value != 0 || w_index != mbim->ctrl_id)
1090 break;
1091
1092 req->complete = mbim_ep0out_complete;
1093 req->length = w_length;
1094 req->context = f;
1095
1096 value = req->length;
1097 break;
1098
1099 case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1100 | USB_CDC_GET_NTB_FORMAT:
1101 {
1102 uint16_t format;
1103
Anna Perel20c91152012-10-30 16:26:44 +02001104 pr_debug("USB_CDC_GET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001105
1106 if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
1107 break;
1108
1109 format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
1110 put_unaligned_le16(format, req->buf);
1111 value = 2;
Anna Perel20c91152012-10-30 16:26:44 +02001112 pr_debug("NTB FORMAT: sending %d\n", format);
Anna Perela8c991d2012-04-09 16:44:46 +03001113 break;
1114 }
1115
1116 case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
1117 | USB_CDC_SET_NTB_FORMAT:
1118 {
Anna Perel20c91152012-10-30 16:26:44 +02001119 pr_debug("USB_CDC_SET_NTB_FORMAT");
Anna Perela8c991d2012-04-09 16:44:46 +03001120
1121 if (w_length != 0 || w_index != mbim->ctrl_id)
1122 break;
1123 switch (w_value) {
1124 case 0x0000:
1125 mbim->parser_opts = &ndp16_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001126 pr_debug("NCM16 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001127 break;
1128 case 0x0001:
1129 mbim->parser_opts = &ndp32_opts;
Anna Perel20c91152012-10-30 16:26:44 +02001130 pr_debug("NCM32 selected\n");
Anna Perela8c991d2012-04-09 16:44:46 +03001131 break;
1132 default:
1133 break;
1134 }
1135 value = 0;
1136 break;
1137 }
1138
1139 /* optional in mbim descriptor: */
1140 /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
1141 /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
1142
1143 default:
1144 pr_err("invalid control req: %02x.%02x v%04x i%04x l%d\n",
1145 ctrl->bRequestType, ctrl->bRequest,
1146 w_value, w_index, w_length);
1147 }
1148
1149 /* respond with data transfer or status phase? */
1150 if (value >= 0) {
Anna Perel20c91152012-10-30 16:26:44 +02001151 pr_debug("control request: %02x.%02x v%04x i%04x l%d\n",
Anna Perela8c991d2012-04-09 16:44:46 +03001152 ctrl->bRequestType, ctrl->bRequest,
1153 w_value, w_index, w_length);
Anna Perel2dfcaca2012-04-18 17:25:59 +03001154 req->zero = (value < w_length);
Anna Perela8c991d2012-04-09 16:44:46 +03001155 req->length = value;
1156 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1157 if (value < 0) {
1158 pr_err("queueing req failed: %02x.%02x, err %d\n",
1159 ctrl->bRequestType,
1160 ctrl->bRequest, value);
1161 }
1162 } else {
1163 pr_err("ctrl req err %d: %02x.%02x v%04x i%04x l%d\n",
1164 value, ctrl->bRequestType, ctrl->bRequest,
1165 w_value, w_index, w_length);
1166 }
1167
1168 /* device either stalls (value < 0) or reports success */
1169 return value;
1170}
1171
Jack Pham2df2f702012-10-11 19:08:24 -07001172/*
1173 * This function handles the Microsoft-specific OS descriptor control
1174 * requests that are issued by Windows host drivers to determine the
1175 * configuration containing the MBIM function.
1176 *
1177 * Unlike mbim_setup() this function handles two specific device requests,
1178 * and only when a configuration has not yet been selected.
1179 */
1180static int mbim_ctrlrequest(struct usb_composite_dev *cdev,
1181 const struct usb_ctrlrequest *ctrl)
1182{
1183 int value = -EOPNOTSUPP;
1184 u16 w_index = le16_to_cpu(ctrl->wIndex);
1185 u16 w_value = le16_to_cpu(ctrl->wValue);
1186 u16 w_length = le16_to_cpu(ctrl->wLength);
1187
1188 /* only respond to OS desciptors when no configuration selected */
1189 if (cdev->config || !mbim_ext_config_desc.function.subCompatibleID[0])
1190 return value;
1191
1192 pr_debug("%02x.%02x v%04x i%04x l%u",
1193 ctrl->bRequestType, ctrl->bRequest,
1194 w_value, w_index, w_length);
1195
1196 /* Handle MSFT OS string */
1197 if (ctrl->bRequestType ==
1198 (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
1199 && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
1200 && (w_value >> 8) == USB_DT_STRING
1201 && (w_value & 0xFF) == MBIM_OS_STRING_ID) {
1202
1203 value = (w_length < sizeof(mbim_os_string) ?
1204 w_length : sizeof(mbim_os_string));
1205 memcpy(cdev->req->buf, mbim_os_string, value);
1206
1207 } else if (ctrl->bRequestType ==
1208 (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
1209 && ctrl->bRequest == MBIM_VENDOR_CODE && w_index == 4) {
1210
1211 /* Handle Extended OS descriptor */
1212 value = (w_length < sizeof(mbim_ext_config_desc) ?
1213 w_length : sizeof(mbim_ext_config_desc));
1214 memcpy(cdev->req->buf, &mbim_ext_config_desc, value);
1215 }
1216
1217 /* respond with data transfer or status phase? */
1218 if (value >= 0) {
1219 int rc;
1220 cdev->req->zero = value < w_length;
1221 cdev->req->length = value;
1222 rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
1223 if (rc < 0)
1224 pr_err("response queue error: %d", rc);
1225 }
1226 return value;
1227}
1228
Anna Perela8c991d2012-04-09 16:44:46 +03001229static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
1230{
1231 struct f_mbim *mbim = func_to_mbim(f);
1232 struct usb_composite_dev *cdev = mbim->cdev;
1233 int ret = 0;
1234
1235 /* Control interface has only altsetting 0 */
1236 if (intf == mbim->ctrl_id) {
1237
1238 pr_info("CONTROL_INTERFACE");
1239
1240 if (alt != 0)
1241 goto fail;
1242
1243 if (mbim->not_port.notify->driver_data) {
1244 pr_info("reset mbim control %d\n", intf);
1245 usb_ep_disable(mbim->not_port.notify);
1246 }
1247
1248 ret = config_ep_by_speed(cdev->gadget, f,
1249 mbim->not_port.notify);
1250 if (ret) {
1251 mbim->not_port.notify->desc = NULL;
1252 pr_err("Failed configuring notify ep %s: err %d\n",
1253 mbim->not_port.notify->name, ret);
1254 return ret;
1255 }
1256
1257 ret = usb_ep_enable(mbim->not_port.notify);
1258 if (ret) {
1259 pr_err("usb ep#%s enable failed, err#%d\n",
1260 mbim->not_port.notify->name, ret);
1261 return ret;
1262 }
1263 mbim->not_port.notify->driver_data = mbim;
1264
1265 /* Data interface has two altsettings, 0 and 1 */
1266 } else if (intf == mbim->data_id) {
1267
1268 pr_info("DATA_INTERFACE");
1269
1270 if (alt > 1)
1271 goto fail;
1272
1273 if (mbim->bam_port.in->driver_data) {
1274 pr_info("reset mbim\n");
1275 mbim_reset_values(mbim);
1276 mbim_bam_disconnect(mbim);
1277 }
1278
1279 /*
1280 * CDC Network only sends data in non-default altsettings.
1281 * Changing altsettings resets filters, statistics, etc.
1282 */
1283 if (alt == 1) {
1284 pr_info("Alt set 1, initialize ports");
1285
1286 if (!mbim->bam_port.in->desc) {
1287
1288 pr_info("Choose endpoints");
1289
1290 ret = config_ep_by_speed(cdev->gadget, f,
1291 mbim->bam_port.in);
1292 if (ret) {
1293 mbim->bam_port.in->desc = NULL;
1294 pr_err("IN ep %s failed: %d\n",
1295 mbim->bam_port.in->name, ret);
1296 return ret;
1297 }
1298
1299 pr_info("Set mbim port in_desc = 0x%p",
1300 mbim->bam_port.in->desc);
1301
1302 ret = config_ep_by_speed(cdev->gadget, f,
1303 mbim->bam_port.out);
1304 if (ret) {
1305 mbim->bam_port.out->desc = NULL;
1306 pr_err("OUT ep %s failed: %d\n",
1307 mbim->bam_port.out->name, ret);
1308 return ret;
1309 }
1310
1311 pr_info("Set mbim port out_desc = 0x%p",
1312 mbim->bam_port.out->desc);
Anna Perel6637bd72012-10-23 10:53:32 +02001313
1314 pr_debug("Activate mbim\n");
1315 mbim_bam_connect(mbim);
1316
Anna Perela8c991d2012-04-09 16:44:46 +03001317 } else {
1318 pr_info("PORTS already SET");
1319 }
Anna Perela8c991d2012-04-09 16:44:46 +03001320 }
1321
1322 spin_lock(&mbim->lock);
1323 mbim_notify(mbim);
1324 spin_unlock(&mbim->lock);
1325 } else {
1326 goto fail;
1327 }
1328
1329 atomic_set(&mbim->online, 1);
1330
1331 pr_info("SET DEVICE ONLINE");
1332
1333 /* wakeup file threads */
1334 wake_up(&mbim->read_wq);
1335 wake_up(&mbim->write_wq);
1336
1337 return 0;
1338
1339fail:
1340 pr_err("ERROR: Illegal Interface");
1341 return -EINVAL;
1342}
1343
1344/*
1345 * Because the data interface supports multiple altsettings,
1346 * this MBIM function *MUST* implement a get_alt() method.
1347 */
1348static int mbim_get_alt(struct usb_function *f, unsigned intf)
1349{
1350 struct f_mbim *mbim = func_to_mbim(f);
1351
1352 if (intf == mbim->ctrl_id)
1353 return 0;
1354 return mbim->bam_port.in->driver_data ? 1 : 0;
1355}
1356
1357static void mbim_disable(struct usb_function *f)
1358{
1359 struct f_mbim *mbim = func_to_mbim(f);
1360
1361 pr_info("SET DEVICE OFFLINE");
1362 atomic_set(&mbim->online, 0);
1363
Anna Perel86ea7c92012-04-24 14:31:29 +03001364 mbim_clear_queues(mbim);
1365 mbim_reset_function_queue(mbim);
Anna Perela8c991d2012-04-09 16:44:46 +03001366
1367 mbim_bam_disconnect(mbim);
1368
1369 if (mbim->not_port.notify->driver_data) {
1370 usb_ep_disable(mbim->not_port.notify);
1371 mbim->not_port.notify->driver_data = NULL;
1372 }
1373
Anna Perel68aeb172012-10-28 09:00:45 +02001374 atomic_set(&mbim->not_port.notify_count, 0);
1375
Anna Perela8c991d2012-04-09 16:44:46 +03001376 pr_info("mbim deactivated\n");
1377}
1378
Anna Perel557bf722012-09-20 11:16:35 +03001379#define MBIM_ACTIVE_PORT 0
1380
1381static void mbim_suspend(struct usb_function *f)
1382{
1383 pr_info("mbim suspended\n");
1384 bam_data_suspend(MBIM_ACTIVE_PORT);
1385}
1386
1387static void mbim_resume(struct usb_function *f)
1388{
1389 pr_info("mbim resumed\n");
1390 bam_data_resume(MBIM_ACTIVE_PORT);
1391}
1392
Anna Perela8c991d2012-04-09 16:44:46 +03001393/*---------------------- function driver setup/binding ---------------------*/
1394
1395static int
1396mbim_bind(struct usb_configuration *c, struct usb_function *f)
1397{
1398 struct usb_composite_dev *cdev = c->cdev;
1399 struct f_mbim *mbim = func_to_mbim(f);
1400 int status;
1401 struct usb_ep *ep;
1402
1403 pr_info("Enter");
1404
1405 mbim->cdev = cdev;
1406
1407 /* allocate instance-specific interface IDs */
1408 status = usb_interface_id(c, f);
1409 if (status < 0)
1410 goto fail;
1411 mbim->ctrl_id = status;
1412 mbim_iad_desc.bFirstInterface = status;
1413
1414 mbim_control_intf.bInterfaceNumber = status;
1415 mbim_union_desc.bMasterInterface0 = status;
1416
1417 status = usb_interface_id(c, f);
1418 if (status < 0)
1419 goto fail;
1420 mbim->data_id = status;
1421
1422 mbim_data_nop_intf.bInterfaceNumber = status;
1423 mbim_data_intf.bInterfaceNumber = status;
1424 mbim_union_desc.bSlaveInterface0 = status;
1425
Anna Perel557bf722012-09-20 11:16:35 +03001426 mbim->bam_port.cdev = cdev;
1427
Anna Perela8c991d2012-04-09 16:44:46 +03001428 status = -ENODEV;
1429
1430 /* allocate instance-specific endpoints */
1431 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_in_desc);
1432 if (!ep) {
1433 pr_err("usb epin autoconfig failed\n");
1434 goto fail;
1435 }
1436 pr_info("usb epin autoconfig succeeded\n");
1437 ep->driver_data = cdev; /* claim */
1438 mbim->bam_port.in = ep;
1439
1440 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_out_desc);
1441 if (!ep) {
1442 pr_err("usb epout autoconfig failed\n");
1443 goto fail;
1444 }
1445 pr_info("usb epout autoconfig succeeded\n");
1446 ep->driver_data = cdev; /* claim */
1447 mbim->bam_port.out = ep;
1448
1449 ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_notify_desc);
1450 if (!ep) {
1451 pr_err("usb notify ep autoconfig failed\n");
1452 goto fail;
1453 }
1454 pr_info("usb notify ep autoconfig succeeded\n");
1455 mbim->not_port.notify = ep;
1456 ep->driver_data = cdev; /* claim */
1457
1458 status = -ENOMEM;
1459
1460 /* allocate notification request and buffer */
1461 mbim->not_port.notify_req = mbim_alloc_req(ep, NCM_STATUS_BYTECOUNT);
1462 if (!mbim->not_port.notify_req) {
1463 pr_info("failed to allocate notify request\n");
1464 goto fail;
1465 }
1466 pr_info("allocated notify ep request & request buffer\n");
1467
1468 mbim->not_port.notify_req->context = mbim;
1469 mbim->not_port.notify_req->complete = mbim_notify_complete;
1470
1471 /* copy descriptors, and track endpoint copies */
1472 f->descriptors = usb_copy_descriptors(mbim_fs_function);
1473 if (!f->descriptors)
1474 goto fail;
1475
1476 /*
1477 * support all relevant hardware speeds... we expect that when
1478 * hardware is dual speed, all bulk-capable endpoints work at
1479 * both speeds
1480 */
1481 if (gadget_is_dualspeed(c->cdev->gadget)) {
1482 hs_mbim_in_desc.bEndpointAddress =
1483 fs_mbim_in_desc.bEndpointAddress;
1484 hs_mbim_out_desc.bEndpointAddress =
1485 fs_mbim_out_desc.bEndpointAddress;
1486 hs_mbim_notify_desc.bEndpointAddress =
1487 fs_mbim_notify_desc.bEndpointAddress;
1488
1489 /* copy descriptors, and track endpoint copies */
1490 f->hs_descriptors = usb_copy_descriptors(mbim_hs_function);
1491 if (!f->hs_descriptors)
1492 goto fail;
1493 }
1494
Jack Pham2df2f702012-10-11 19:08:24 -07001495 /*
1496 * If MBIM is bound in a config other than the first, tell Windows
1497 * about it by returning the num as a string in the OS descriptor's
1498 * subCompatibleID field. Windows only supports up to config #4.
1499 */
1500 if (c->bConfigurationValue >= 2 && c->bConfigurationValue <= 4) {
1501 pr_debug("MBIM in configuration %d", c->bConfigurationValue);
1502 mbim_ext_config_desc.function.subCompatibleID[0] =
1503 c->bConfigurationValue + '0';
1504 }
1505
Anna Perela8c991d2012-04-09 16:44:46 +03001506 pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
1507 mbim->port_num,
1508 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
1509 mbim->bam_port.in->name, mbim->bam_port.out->name,
1510 mbim->not_port.notify->name);
1511
1512 return 0;
1513
1514fail:
1515 pr_err("%s failed to bind, err %d\n", f->name, status);
1516
1517 if (f->descriptors)
1518 usb_free_descriptors(f->descriptors);
1519
1520 if (mbim->not_port.notify_req) {
1521 kfree(mbim->not_port.notify_req->buf);
1522 usb_ep_free_request(mbim->not_port.notify,
1523 mbim->not_port.notify_req);
1524 }
1525
1526 /* we might as well release our claims on endpoints */
1527 if (mbim->not_port.notify)
1528 mbim->not_port.notify->driver_data = NULL;
1529 if (mbim->bam_port.out)
1530 mbim->bam_port.out->driver_data = NULL;
1531 if (mbim->bam_port.in)
1532 mbim->bam_port.in->driver_data = NULL;
1533
1534 return status;
1535}
1536
1537static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
1538{
1539 struct f_mbim *mbim = func_to_mbim(f);
1540
1541 if (gadget_is_dualspeed(c->cdev->gadget))
1542 usb_free_descriptors(f->hs_descriptors);
1543 usb_free_descriptors(f->descriptors);
1544
1545 kfree(mbim->not_port.notify_req->buf);
1546 usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
Jack Pham2df2f702012-10-11 19:08:24 -07001547
1548 mbim_ext_config_desc.function.subCompatibleID[0] = 0;
Anna Perela8c991d2012-04-09 16:44:46 +03001549}
1550
1551/**
1552 * mbim_bind_config - add MBIM link to a configuration
1553 * @c: the configuration to support the network link
1554 * Context: single threaded during gadget setup
1555 * Returns zero on success, else negative errno.
1556 */
1557int mbim_bind_config(struct usb_configuration *c, unsigned portno)
1558{
1559 struct f_mbim *mbim = NULL;
1560 int status = 0;
1561
1562 pr_info("port number %u", portno);
1563
1564 if (portno >= nr_mbim_ports) {
1565 pr_err("Can not add port %u. Max ports = %d",
1566 portno, nr_mbim_ports);
1567 return -ENODEV;
1568 }
1569
1570 status = mbim_bam_setup(nr_mbim_ports);
1571 if (status) {
1572 pr_err("bam setup failed");
1573 return status;
1574 }
1575
1576 /* maybe allocate device-global string IDs */
1577 if (mbim_string_defs[0].id == 0) {
1578
1579 /* control interface label */
1580 status = usb_string_id(c->cdev);
1581 if (status < 0)
1582 return status;
1583 mbim_string_defs[STRING_CTRL_IDX].id = status;
1584 mbim_control_intf.iInterface = status;
1585
1586 /* data interface label */
1587 status = usb_string_id(c->cdev);
1588 if (status < 0)
1589 return status;
1590 mbim_string_defs[STRING_DATA_IDX].id = status;
1591 mbim_data_nop_intf.iInterface = status;
1592 mbim_data_intf.iInterface = status;
1593 }
1594
1595 /* allocate and initialize one new instance */
1596 mbim = mbim_ports[0].port;
1597 if (!mbim) {
1598 pr_info("mbim struct not allocated");
1599 return -ENOMEM;
1600 }
1601
1602 mbim->cdev = c->cdev;
1603
Anna Perela8c991d2012-04-09 16:44:46 +03001604 mbim_reset_values(mbim);
1605
1606 mbim->function.name = "usb_mbim";
1607 mbim->function.strings = mbim_strings;
1608 mbim->function.bind = mbim_bind;
1609 mbim->function.unbind = mbim_unbind;
1610 mbim->function.set_alt = mbim_set_alt;
1611 mbim->function.get_alt = mbim_get_alt;
1612 mbim->function.setup = mbim_setup;
1613 mbim->function.disable = mbim_disable;
Anna Perel557bf722012-09-20 11:16:35 +03001614 mbim->function.suspend = mbim_suspend;
1615 mbim->function.resume = mbim_resume;
Anna Perela8c991d2012-04-09 16:44:46 +03001616
1617 INIT_LIST_HEAD(&mbim->cpkt_req_q);
1618 INIT_LIST_HEAD(&mbim->cpkt_resp_q);
1619
1620 status = usb_add_function(c, &mbim->function);
1621
1622 pr_info("Exit status %d", status);
1623
1624 return status;
1625}
1626
1627/* ------------ MBIM DRIVER File Operations API for USER SPACE ------------ */
1628
1629static ssize_t
1630mbim_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
1631{
1632 struct f_mbim *dev = fp->private_data;
1633 struct ctrl_pkt *cpkt = NULL;
1634 int ret = 0;
1635
1636 pr_debug("Enter(%d)\n", count);
1637
1638 if (!dev) {
1639 pr_err("Received NULL mbim pointer\n");
1640 return -ENODEV;
1641 }
1642
1643 if (count > MBIM_BULK_BUFFER_SIZE) {
1644 pr_err("Buffer size is too big %d, should be at most %d\n",
1645 count, MBIM_BULK_BUFFER_SIZE);
1646 return -EINVAL;
1647 }
1648
1649 if (mbim_lock(&dev->read_excl)) {
1650 pr_err("Previous reading is not finished yet\n");
1651 return -EBUSY;
1652 }
1653
1654 /* block until mbim online */
1655 while (!(atomic_read(&dev->online) || atomic_read(&dev->error))) {
1656 pr_err("USB cable not connected. Wait.\n");
1657 ret = wait_event_interruptible(dev->read_wq,
1658 (atomic_read(&dev->online) ||
1659 atomic_read(&dev->error)));
1660 if (ret < 0) {
1661 mbim_unlock(&dev->read_excl);
1662 return 0;
1663 }
1664 }
1665
1666 if (atomic_read(&dev->error)) {
1667 mbim_unlock(&dev->read_excl);
1668 return -EIO;
1669 }
1670
1671 while (list_empty(&dev->cpkt_req_q)) {
1672 pr_err("Requests list is empty. Wait.\n");
1673 ret = wait_event_interruptible(dev->read_wq,
1674 !list_empty(&dev->cpkt_req_q));
1675 if (ret < 0) {
1676 pr_err("Waiting failed\n");
1677 mbim_unlock(&dev->read_excl);
1678 return 0;
1679 }
1680 pr_debug("Received request packet\n");
1681 }
1682
1683 cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
1684 list);
1685 if (cpkt->len > count) {
1686 mbim_unlock(&dev->read_excl);
1687 pr_err("cpkt size too big:%d > buf size:%d\n",
1688 cpkt->len, count);
1689 return -ENOMEM;
1690 }
1691
1692 pr_debug("cpkt size:%d\n", cpkt->len);
1693
1694 list_del(&cpkt->list);
1695 mbim_unlock(&dev->read_excl);
1696
1697 ret = copy_to_user(buf, cpkt->buf, cpkt->len);
1698 if (ret) {
1699 pr_err("copy_to_user failed: err %d\n", ret);
1700 ret = 0;
1701 } else {
1702 pr_debug("copied %d bytes to user\n", cpkt->len);
1703 ret = cpkt->len;
1704 }
1705
1706 mbim_free_ctrl_pkt(cpkt);
1707
1708 return ret;
1709}
1710
1711static ssize_t
1712mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
1713{
1714 struct f_mbim *dev = fp->private_data;
1715 struct ctrl_pkt *cpkt = NULL;
1716 int ret = 0;
1717
1718 pr_debug("Enter(%d)", count);
1719
1720 if (!dev) {
1721 pr_err("Received NULL mbim pointer\n");
1722 return -ENODEV;
1723 }
1724
1725 if (!count) {
1726 pr_err("zero length ctrl pkt\n");
1727 return -ENODEV;
1728 }
1729
1730 if (count > MAX_CTRL_PKT_SIZE) {
1731 pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
1732 count, MAX_CTRL_PKT_SIZE);
1733 return -ENOMEM;
1734 }
1735
1736 if (mbim_lock(&dev->write_excl)) {
1737 pr_err("Previous writing not finished yet\n");
1738 return -EBUSY;
1739 }
1740
1741 if (!atomic_read(&dev->online)) {
1742 pr_err("USB cable not connected\n");
1743 mbim_unlock(&dev->write_excl);
1744 return -EPIPE;
1745 }
1746
1747 cpkt = mbim_alloc_ctrl_pkt(count, GFP_KERNEL);
1748 if (!cpkt) {
1749 pr_err("failed to allocate ctrl pkt\n");
1750 mbim_unlock(&dev->write_excl);
1751 return -ENOMEM;
1752 }
1753
1754 ret = copy_from_user(cpkt->buf, buf, count);
1755 if (ret) {
1756 pr_err("copy_from_user failed err:%d\n", ret);
1757 mbim_free_ctrl_pkt(cpkt);
1758 mbim_unlock(&dev->write_excl);
1759 return 0;
1760 }
1761
1762 fmbim_send_cpkt_response(dev, cpkt);
1763
1764 mbim_unlock(&dev->write_excl);
1765
1766 pr_debug("Exit(%d)", count);
1767
1768 return count;
Anna Perel89ad1212012-06-13 17:17:24 +03001769
Anna Perela8c991d2012-04-09 16:44:46 +03001770}
1771
1772static int mbim_open(struct inode *ip, struct file *fp)
1773{
1774 pr_info("Open mbim driver\n");
1775
1776 while (!_mbim_dev) {
1777 pr_err("mbim_dev not created yet\n");
1778 return -ENODEV;
1779 }
1780
1781 if (mbim_lock(&_mbim_dev->open_excl)) {
1782 pr_err("Already opened\n");
1783 return -EBUSY;
1784 }
1785
1786 pr_info("Lock mbim_dev->open_excl for open\n");
1787
1788 if (!atomic_read(&_mbim_dev->online))
1789 pr_err("USB cable not connected\n");
1790
Anna Perela8c991d2012-04-09 16:44:46 +03001791 fp->private_data = _mbim_dev;
1792
1793 atomic_set(&_mbim_dev->error, 0);
1794
1795 spin_lock(&_mbim_dev->lock);
1796 _mbim_dev->is_open = true;
Anna Perela8c991d2012-04-09 16:44:46 +03001797 spin_unlock(&_mbim_dev->lock);
1798
1799 pr_info("Exit, mbim file opened\n");
1800
1801 return 0;
1802}
1803
1804static int mbim_release(struct inode *ip, struct file *fp)
1805{
1806 struct f_mbim *mbim = fp->private_data;
1807
1808 pr_info("Close mbim file");
1809
1810 spin_lock(&mbim->lock);
1811 mbim->is_open = false;
Anna Perela8c991d2012-04-09 16:44:46 +03001812 spin_unlock(&mbim->lock);
1813
Anna Perela8c991d2012-04-09 16:44:46 +03001814 mbim_unlock(&_mbim_dev->open_excl);
1815
1816 return 0;
1817}
1818
1819static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
1820{
1821 struct f_mbim *mbim = fp->private_data;
1822 int ret = 0;
1823
Anna Perel20c91152012-10-30 16:26:44 +02001824 pr_debug("Received command %d", cmd);
Anna Perela8c991d2012-04-09 16:44:46 +03001825
1826 if (mbim_lock(&mbim->ioctl_excl))
1827 return -EBUSY;
1828
1829 switch (cmd) {
1830 case MBIM_GET_NTB_SIZE:
1831 ret = copy_to_user((void __user *)arg,
1832 &mbim->ntb_input_size, sizeof(mbim->ntb_input_size));
1833 if (ret) {
1834 pr_err("copying to user space failed");
1835 ret = -EFAULT;
1836 }
1837 pr_info("Sent NTB size %d", mbim->ntb_input_size);
1838 break;
1839 case MBIM_GET_DATAGRAM_COUNT:
1840 ret = copy_to_user((void __user *)arg,
1841 &mbim->ntb_max_datagrams,
1842 sizeof(mbim->ntb_max_datagrams));
1843 if (ret) {
1844 pr_err("copying to user space failed");
1845 ret = -EFAULT;
1846 }
1847 pr_info("Sent NTB datagrams count %d",
1848 mbim->ntb_max_datagrams);
1849 break;
1850 default:
1851 pr_err("wrong parameter");
1852 ret = -EINVAL;
1853 }
1854
1855 mbim_unlock(&mbim->ioctl_excl);
1856
1857 return ret;
1858}
1859
1860/* file operations for MBIM device /dev/android_mbim */
1861static const struct file_operations mbim_fops = {
1862 .owner = THIS_MODULE,
1863 .open = mbim_open,
1864 .release = mbim_release,
1865 .read = mbim_read,
1866 .write = mbim_write,
1867 .unlocked_ioctl = mbim_ioctl,
1868};
1869
1870static struct miscdevice mbim_device = {
1871 .minor = MISC_DYNAMIC_MINOR,
1872 .name = "android_mbim",
1873 .fops = &mbim_fops,
1874};
1875
1876static int mbim_init(int instances)
1877{
1878 int i;
1879 struct f_mbim *dev = NULL;
1880 int ret;
1881
1882 pr_info("initialize %d instances\n", instances);
1883
1884 if (instances > NR_MBIM_PORTS) {
1885 pr_err("Max-%d instances supported\n", NR_MBIM_PORTS);
1886 return -EINVAL;
1887 }
1888
1889 for (i = 0; i < instances; i++) {
1890 dev = kzalloc(sizeof(struct f_mbim), GFP_KERNEL);
1891 if (!dev) {
1892 pr_err("Failed to allocate mbim dev\n");
1893 ret = -ENOMEM;
1894 goto fail_probe;
1895 }
1896
1897 dev->port_num = i;
1898 spin_lock_init(&dev->lock);
1899 INIT_LIST_HEAD(&dev->cpkt_req_q);
1900 INIT_LIST_HEAD(&dev->cpkt_resp_q);
1901
1902 mbim_ports[i].port = dev;
1903 mbim_ports[i].port_num = i;
1904
1905 init_waitqueue_head(&dev->read_wq);
1906 init_waitqueue_head(&dev->write_wq);
1907
1908 atomic_set(&dev->open_excl, 0);
1909 atomic_set(&dev->ioctl_excl, 0);
1910 atomic_set(&dev->read_excl, 0);
1911 atomic_set(&dev->write_excl, 0);
1912
1913 nr_mbim_ports++;
1914
1915 }
1916
1917 _mbim_dev = dev;
1918 ret = misc_register(&mbim_device);
1919 if (ret) {
1920 pr_err("mbim driver failed to register");
1921 goto fail_probe;
1922 }
1923
1924 pr_info("Initialized %d ports\n", nr_mbim_ports);
1925
1926 return ret;
1927
1928fail_probe:
1929 pr_err("Failed");
1930 for (i = 0; i < nr_mbim_ports; i++) {
1931 kfree(mbim_ports[i].port);
1932 mbim_ports[i].port = NULL;
1933 }
1934
1935 return ret;
1936}
1937
1938static void fmbim_cleanup(void)
1939{
1940 int i = 0;
1941
1942 pr_info("Enter");
1943
1944 for (i = 0; i < nr_mbim_ports; i++) {
1945 kfree(mbim_ports[i].port);
1946 mbim_ports[i].port = NULL;
1947 }
1948 nr_mbim_ports = 0;
1949
1950 misc_deregister(&mbim_device);
1951
1952 _mbim_dev = NULL;
1953}
1954