1 /*
2 * Dongle BUS interface
3 * USB Linux Implementation
4 *
5 * Copyright (C) 1999-2016, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
28 * $Id: dbus_usb_linux.c 564663 2015-06-18 02:34:42Z $
29 */
30
31 /**
32 * @file @brief
33 * This file contains DBUS code that is USB *and* OS (Linux) specific. DBUS is a Broadcom
34 * proprietary host specific abstraction layer.
35 */
36
37 #include <typedefs.h>
38 #include <osl.h>
39
40 /**
41 * DBUS_LINUX_RXDPC is created for router platform performance tuning. A separate thread is created
42 * to handle USB RX and avoid the call chain getting too long and enhance cache hit rate.
43 *
44 * DBUS_LINUX_RXDPC setting is in wlconfig file.
45 */
46
47 /*
48 * If DBUS_LINUX_RXDPC is off, spin_lock_bh() for CTFPOOL in
49 * linux_osl.c has to be changed to spin_lock_irqsave() because
50 * PKTGET/PKTFREE are no longer in bottom half.
51 *
52 * Right now we have another queue rpcq in wl_linux.c. Maybe we
53 * can eliminate that one to reduce the overhead.
54 *
55 * Enabling 2nd EP and DBUS_LINUX_RXDPC causing traffic from
56 * both EP's to be queued in the same rx queue. If we want
57 * RXDPC to work with 2nd EP. The EP for RPC call return
58 * should bypass the dpc and go directly up.
59 */
60
61 /* #define DBUS_LINUX_RXDPC */
62
63 /* Dbus histogram for ntxq, nrxq, dpc parameter tuning */
64 /* #define DBUS_LINUX_HIST */
65
66 #include <usbrdl.h>
67 #include <bcmendian.h>
68 #include <linux/init.h>
69 #include <linux/kernel.h>
70 #include <linux/slab.h>
71 #include <linux/usb.h>
72 #include <linux/skbuff.h>
73 #include <linux/netdevice.h>
74 #include <linux/random.h>
75 #include <linux/spinlock.h>
76 #include <linux/list.h>
77 #include <asm/uaccess.h>
78 #include <asm/unaligned.h>
79 #include <dbus.h>
80 #include <bcmutils.h>
81 #include <bcmdevs_legacy.h>
82 #include <bcmdevs.h>
83 #include <linux/usb.h>
84 #include <usbrdl.h>
85 #include <linux/firmware.h>
86 #include <dngl_stats.h>
87 #include <dhd.h>
88
89 #if defined(USBOS_THREAD) || defined(USBOS_TX_THREAD)
90
91 /**
92 * The usb-thread is designed to provide currency on multiprocessors and SMP linux kernels. On the
93 * dual cores platform, the WLAN driver, without threads, executed only on CPU0. The driver consumed
94 * almost of 100% on CPU0, while CPU1 remained idle. The behavior was observed on Broadcom's STB.
95 *
96 * The WLAN driver consumed most of CPU0 and not CPU1 because tasklets/queues, software irq, and
97 * hardware irq are executing from CPU0, only. CPU0 became the system's bottle-neck. TPUT is lower
98 * and system's responsiveness is slower.
99 *
100 * To improve system responsiveness and TPUT usb-thread was implemented. The system's threads could
101 * be scheduled to run on any core. One core could be processing data in the usb-layer and the other
102 * core could be processing data in the wl-layer.
103 *
104 * For further info see [WlThreadAndUsbThread] Twiki.
105 */
106
107 #include <linux/kthread.h>
108 #include <linux/interrupt.h>
109 #include <linux/irq.h>
110 #include <asm/hardirq.h>
111 #include <linux/list.h>
112 #include <linux_osl.h>
113 #endif /* USBOS_THREAD || USBOS_TX_THREAD */
114
115
116
117 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
118 #define KERNEL26
119 #endif
120
121 /**
122 * Starting with the 3.10 kernel release, dynamic PM support for USB is present whenever
123 * the kernel was built with CONFIG_PM_RUNTIME enabled. The CONFIG_USB_SUSPEND option has
124 * been eliminated.
125 */
126 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) && defined(CONFIG_USB_SUSPEND)) \
127 || ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && defined(CONFIG_PM_RUNTIME)) \
128 || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
129 /* For USB power management support, see Linux kernel: Documentation/usb/power-management.txt */
130 #define USB_SUSPEND_AVAILABLE
131 #endif
132
133 /* Define alternate fw/nvram paths used in Android */
134 #ifdef OEM_ANDROID
135 #define CONFIG_ANDROID_BCMDHD_FW_PATH "broadcom/dhd/firmware/fw.bin.trx"
136 #define CONFIG_ANDROID_BCMDHD_NVRAM_PATH "broadcom/dhd/nvrams/nvm.txt"
137 #endif /* OEM_ANDROID */
138
usb_submit_urb_linux(struct urb * urb)139 static inline int usb_submit_urb_linux(struct urb *urb)
140 {
141
142 #ifdef BCM_MAX_URB_LEN
143 if (urb && (urb->transfer_buffer_length > BCM_MAX_URB_LEN)) {
144 DBUSERR(("URB transfer length=%d exceeded %d ra=%p\n", urb->transfer_buffer_length,
145 BCM_MAX_URB_LEN, __builtin_return_address(0)));
146 return DBUS_ERR;
147 }
148 #endif
149
150 #ifdef KERNEL26
151 return usb_submit_urb(urb, GFP_ATOMIC);
152 #else
153 return usb_submit_urb(urb);
154 #endif
155
156 }
157
158 #define USB_SUBMIT_URB(urb) usb_submit_urb_linux(urb)
159
160 #ifdef KERNEL26
161
162 #define USB_ALLOC_URB() usb_alloc_urb(0, GFP_ATOMIC)
163 #define USB_UNLINK_URB(urb) (usb_kill_urb(urb))
164 #define USB_FREE_URB(urb) (usb_free_urb(urb))
165 #define USB_REGISTER() usb_register(&dbus_usbdev)
166 #define USB_DEREGISTER() usb_deregister(&dbus_usbdev)
167
168 #ifdef USB_SUSPEND_AVAILABLE
169
170 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))
171 #define USB_AUTOPM_SET_INTERFACE(intf) usb_autopm_set_interface(intf)
172 #else
173 #define USB_ENABLE_AUTOSUSPEND(udev) usb_enable_autosuspend(udev)
174 #define USB_DISABLE_AUTOSUSPEND(udev) usb_disable_autosuspend(udev)
175 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */
176
177 #define USB_AUTOPM_GET_INTERFACE(intf) usb_autopm_get_interface(intf)
178 #define USB_AUTOPM_PUT_INTERFACE(intf) usb_autopm_put_interface(intf)
179 #define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) usb_autopm_get_interface_async(intf)
180 #define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) usb_autopm_put_interface_async(intf)
181 #define USB_MARK_LAST_BUSY(dev) usb_mark_last_busy(dev)
182
183 #else /* USB_SUSPEND_AVAILABLE */
184
185 #define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0)
186 #define USB_AUTOPM_PUT_INTERFACE(intf) do {} while (0)
187 #define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0)
188 #define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0)
189 #define USB_MARK_LAST_BUSY(dev) do {} while (0)
190 #endif /* USB_SUSPEND_AVAILABLE */
191
192 #define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \
193 usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \
194 (data), (size), (timeout))
195 #define USB_BULK_MSG(dev, pipe, data, len, actual_length, timeout) \
196 usb_bulk_msg((dev), (pipe), (data), (len), (actual_length), (timeout))
197 #define USB_BUFFER_ALLOC(dev, size, mem, dma) usb_buffer_alloc(dev, size, mem, dma)
198 #define USB_BUFFER_FREE(dev, size, data, dma) usb_buffer_free(dev, size, data, dma)
199
200 #ifdef WL_URB_ZPKT
201 #define URB_QUEUE_BULK URB_ZERO_PACKET
202 #else
203 #define URB_QUEUE_BULK 0
204 #endif /* WL_URB_ZPKT */
205
206 #define CALLBACK_ARGS struct urb *urb, struct pt_regs *regs
207 #define CALLBACK_ARGS_DATA urb, regs
208 #define CONFIGDESC(usb) (&((usb)->actconfig)->desc)
209 #define IFPTR(usb, idx) ((usb)->actconfig->interface[idx])
210 #define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0])
211 #define IFDESC(usb, idx) IFALTS((usb), (idx)).desc
212 #define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]).desc
213
214 #else /* KERNEL26 */
215
216 #define USB_ALLOC_URB() usb_alloc_urb(0)
217 #define USB_UNLINK_URB(urb) usb_unlink_urb(urb)
218 #define USB_FREE_URB(urb) (usb_free_urb(urb))
219 #define USB_REGISTER() usb_register(&dbus_usbdev)
220 #define USB_DEREGISTER() usb_deregister(&dbus_usbdev)
221 #define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0)
222 #define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0)
223 #define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0)
224 #define USB_MARK_LAST_BUSY(dev) do {} while (0)
225
226 #define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \
227 usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \
228 (data), (size), (timeout))
229 #define USB_BUFFER_ALLOC(dev, size, mem, dma) kmalloc(size, mem)
230 #define USB_BUFFER_FREE(dev, size, data, dma) kfree(data)
231
232 #ifdef WL_URB_ZPKT
233 #define URB_QUEUE_BULK USB_QUEUE_BULK|URB_ZERO_PACKET
234 #else
235 #define URB_QUEUE_BULK 0
236 #endif /* WL_URB_ZPKT */
237
238 #define CALLBACK_ARGS struct urb *urb
239 #define CALLBACK_ARGS_DATA urb
240 #define CONFIGDESC(usb) ((usb)->actconfig)
241 #define IFPTR(usb, idx) (&(usb)->actconfig->interface[idx])
242 #define IFALTS(usb, idx) ((usb)->actconfig->interface[idx].altsetting[0])
243 #define IFDESC(usb, idx) IFALTS((usb), (idx))
244 #define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep])
245
246
247 #endif /* KERNEL26 */
248
249 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
250 #define USB_SPEED_SUPER 5
251 #endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) */
252
253 #define CONTROL_IF 0
254 #define BULK_IF 0
255
256 #ifdef BCMUSBDEV_COMPOSITE
257 #define USB_COMPIF_MAX 4
258
259 #define USB_CLASS_WIRELESS 0xe0
260 #define USB_CLASS_MISC 0xef
261 #define USB_SUBCLASS_COMMON 0x02
262 #define USB_PROTO_IAD 0x01
263 #define USB_PROTO_VENDOR 0xff
264
265 #define USB_QUIRK_NO_SET_INTF 0x04 /* device does not support set_interface */
266 #endif /* BCMUSBDEV_COMPOSITE */
267
268 #define USB_SYNC_WAIT_TIMEOUT 300 /* ms */
269
270 /* Private data kept in skb */
271 #define SKB_PRIV(skb, idx) (&((void **)skb->cb)[idx])
272 #define SKB_PRIV_URB(skb) (*(struct urb **)SKB_PRIV(skb, 0))
273
274 #ifndef DBUS_USB_RXQUEUE_BATCH_ADD
275 /* items to add each time within limit */
276 #define DBUS_USB_RXQUEUE_BATCH_ADD 8
277 #endif
278
279 #ifndef DBUS_USB_RXQUEUE_LOWER_WATERMARK
280 /* add a new batch req to rx queue when waiting item count reduce to this number */
281 #define DBUS_USB_RXQUEUE_LOWER_WATERMARK 4
282 #endif
283
284 enum usbos_suspend_state {
285 USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow suspend */
286 USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be suspended */
287 /* Wating PM to suspend */
288 USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */
289 };
290
291 enum usbos_request_state {
292 USBOS_REQUEST_STATE_UNSCHEDULED = 0, /* USB TX request not scheduled */
293 USBOS_REQUEST_STATE_SCHEDULED, /* USB TX request given to TX thread */
294 USBOS_REQUEST_STATE_SUBMITTED /* USB TX request submitted */
295 };
296
297 typedef struct {
298 uint32 notification;
299 uint32 reserved;
300 } intr_t;
301
302 typedef struct {
303 dbus_pub_t *pub;
304
305 void *cbarg;
306 dbus_intf_callbacks_t *cbs;
307
308 /* Imported */
309 struct usb_device *usb; /* USB device pointer from OS */
310 struct urb *intr_urb; /* URB for interrupt endpoint */
311 struct list_head req_rxfreeq;
312 struct list_head req_txfreeq;
313 struct list_head req_rxpostedq; /* Posted down to USB driver for RX */
314 struct list_head req_txpostedq; /* Posted down to USB driver for TX */
315 spinlock_t rxfree_lock; /* Lock for rx free list */
316 spinlock_t txfree_lock; /* Lock for tx free list */
317 spinlock_t rxposted_lock; /* Lock for rx posted list */
318 spinlock_t txposted_lock; /* Lock for tx posted list */
319 uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; /* Pipe numbers for USB I/O */
320 uint rxbuf_len;
321
322 struct list_head req_rxpendingq; /* RXDPC: Pending for dpc to send up */
323 spinlock_t rxpending_lock; /* RXDPC: Lock for rx pending list */
324 long dpc_pid;
325 struct semaphore dpc_sem;
326 struct completion dpc_exited;
327 int rxpending;
328
329 struct urb *ctl_urb;
330 int ctl_in_pipe, ctl_out_pipe;
331 struct usb_ctrlrequest ctl_write;
332 struct usb_ctrlrequest ctl_read;
333 struct semaphore ctl_lock; /* Lock for CTRL transfers via tx_thread */
334 #ifdef USBOS_TX_THREAD
335 enum usbos_request_state ctl_state;
336 #endif /* USBOS_TX_THREAD */
337
338 spinlock_t rxlock; /* Lock for rxq management */
339 spinlock_t txlock; /* Lock for txq management */
340
341 int intr_size; /* Size of interrupt message */
342 int interval; /* Interrupt polling interval */
343 intr_t intr; /* Data buffer for interrupt endpoint */
344
345 int maxps;
346 atomic_t txposted;
347 atomic_t rxposted;
348 atomic_t txallocated;
349 atomic_t rxallocated;
350 bool rxctl_deferrespok; /* Get a response for setup from dongle */
351
352 wait_queue_head_t wait;
353 bool waitdone;
354 int sync_urb_status;
355
356 struct urb *blk_urb; /* Used for downloading embedded image */
357
358 #ifdef USBOS_THREAD
359 spinlock_t ctrl_lock;
360 spinlock_t usbos_list_lock;
361 struct list_head usbos_list;
362 struct list_head usbos_free_list;
363 atomic_t usbos_list_cnt;
364 wait_queue_head_t usbos_queue_head;
365 struct task_struct *usbos_kt;
366 #endif /* USBOS_THREAD */
367
368 #ifdef USBOS_TX_THREAD
369 spinlock_t usbos_tx_list_lock;
370 struct list_head usbos_tx_list;
371 wait_queue_head_t usbos_tx_queue_head;
372 struct task_struct *usbos_tx_kt;
373 #endif /* USBOS_TX_THREAD */
374
375 struct dma_pool *qtd_pool; /* QTD pool for USB optimization only */
376 int tx_ep, rx_ep, rx2_ep; /* EPs for USB optimization */
377 struct usb_device *usb_device; /* USB device for optimization */
378 } usbos_info_t;
379
380 typedef struct urb_req {
381 void *pkt;
382 int buf_len;
383 struct urb *urb;
384 void *arg;
385 usbos_info_t *usbinfo;
386 struct list_head urb_list;
387 } urb_req_t;
388
389 #ifdef USBOS_THREAD
390 typedef struct usbos_list_entry {
391 struct list_head list; /* must be first */
392 void *urb_context;
393 int urb_length;
394 int urb_status;
395 } usbos_list_entry_t;
396
397 static void* dbus_usbos_thread_init(usbos_info_t *usbos_info);
398 static void dbus_usbos_thread_deinit(usbos_info_t *usbos_info);
399 static void dbus_usbos_dispatch_schedule(CALLBACK_ARGS);
400 static int dbus_usbos_thread_func(void *data);
401 #endif /* USBOS_THREAD */
402
403 #ifdef USBOS_TX_THREAD
404 void* dbus_usbos_tx_thread_init(usbos_info_t *usbos_info);
405 void dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info);
406 int dbus_usbos_tx_thread_func(void *data);
407 #endif /* USBOS_TX_THREAD */
408
409 /* Shared Function prototypes */
410 bool dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen);
411 int dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms);
412 bool dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len);
413 int dbus_write_membytes(usbos_info_t *usbinfo, bool set, uint32 address, uint8 *data, uint size);
414
415 /* Local function prototypes */
416 static void dbus_usbos_send_complete(CALLBACK_ARGS);
417 static void dbus_usbos_recv_complete(CALLBACK_ARGS);
418 static int dbus_usbos_errhandler(void *bus, int err);
419 static int dbus_usbos_state_change(void *bus, int state);
420 static void dbusos_stop(usbos_info_t *usbos_info);
421
422 #ifdef KERNEL26
423 static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id);
424 static void dbus_usbos_disconnect(struct usb_interface *intf);
425 #if defined(USB_SUSPEND_AVAILABLE)
426 static int dbus_usbos_resume(struct usb_interface *intf);
427 static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message);
428 /* at the moment, used for full dongle host driver only */
429 static int dbus_usbos_reset_resume(struct usb_interface *intf);
430 #endif /* USB_SUSPEND_AVAILABLE */
431 #else /* KERNEL26 */
432 static void *dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum,
433 const struct usb_device_id *id);
434 static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr);
435 #endif /* KERNEL26 */
436
437
438 /**
439 * have to disable missing-field-initializers warning as last element {} triggers it
440 * and different versions of kernel have different number of members so it is impossible
441 * to specify the initializer. BTW issuing the warning here is bug og GCC as universal
442 * zero {0} specified in C99 standard as correct way of initialization of struct to all zeros
443 */
444 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
445 4 && __GNUC_MINOR__ >= 6))
446 #pragma GCC diagnostic push
447 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
448 #endif
449
450 static struct usb_device_id devid_table[] = {
451 { USB_DEVICE(BCM_DNGL_VID, 0x0000) }, /* Configurable via register() */
452 #if defined(BCM_REQUEST_FW)
453 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4328) },
454 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4322) },
455 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4319) },
456 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43236) },
457 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43143) },
458 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43242) },
459 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4360) },
460 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4350) },
461 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43569) },
462 #endif
463 #ifdef EXTENDED_VID_PID
464 EXTENDED_VID_PID,
465 #endif /* EXTENDED_VID_PID */
466 { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BDC_PID) }, /* Default BDC */
467 { }
468 };
469
470 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
471 4 && __GNUC_MINOR__ >= 6))
472 #pragma GCC diagnostic pop
473 #endif
474
475 MODULE_DEVICE_TABLE(usb, devid_table);
476
477 /** functions called by the Linux kernel USB subsystem */
478 static struct usb_driver dbus_usbdev = {
479 name: "dbus_usbdev",
480 probe: dbus_usbos_probe,
481 disconnect: dbus_usbos_disconnect,
482 id_table: devid_table,
483 #if defined(USB_SUSPEND_AVAILABLE)
484 suspend: dbus_usbos_suspend,
485 resume: dbus_usbos_resume,
486 reset_resume: dbus_usbos_reset_resume,
487 /* Linux USB core will allow autosuspend for devices bound to this driver */
488 supports_autosuspend: 1
489 #endif /* USB_SUSPEND_AVAILABLE */
490 };
491
492 /**
493 * This stores USB info during Linux probe callback since attach() is not called yet at this point
494 */
495 typedef struct {
496 void *usbos_info;
497 struct usb_device *usb; /* USB device pointer from OS */
498 uint rx_pipe; /* Pipe numbers for USB I/O */
499 uint tx_pipe; /* Pipe numbers for USB I/O */
500 uint intr_pipe; /* Pipe numbers for USB I/O */
501 uint rx_pipe2; /* Pipe numbers for USB I/O */
502 int intr_size; /* Size of interrupt message */
503 int interval; /* Interrupt polling interval */
504 bool dldone;
505 int vid;
506 int pid;
507 bool dereged;
508 bool disc_cb_done;
509 DEVICE_SPEED device_speed;
510 enum usbos_suspend_state suspend_state;
511 struct usb_interface *intf;
512 } probe_info_t;
513
514 /* driver info, initialized when bcmsdh_register is called */
515 static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL};
516
517 /*
518 * USB Linux dbus_intf_t
519 */
520 static void *dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
521 static void dbus_usbos_intf_detach(dbus_pub_t *pub, void *info);
522 static int dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb);
523 static int dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb);
524 static int dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx);
525 static int dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb);
526 static int dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len);
527 static int dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len);
528 static int dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib);
529 static int dbus_usbos_intf_up(void *bus);
530 static int dbus_usbos_intf_down(void *bus);
531 static int dbus_usbos_intf_stop(void *bus);
532 static int dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value);
533 extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size);
534 int dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data);
535 static int dbus_usbos_intf_set_config(void *bus, dbus_config_t *config);
536 static bool dbus_usbos_intf_recv_needed(void *bus);
537 static void *dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args);
538 static void *dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args);
539 #ifdef BCMUSBDEV_COMPOSITE
540 static int dbus_usbos_intf_wlan(struct usb_device *usb);
541 #endif /* BCMUSBDEV_COMPOSITE */
542
543 /** functions called by dbus_usb.c */
544 static dbus_intf_t dbus_usbos_intf = {
545 .attach = dbus_usbos_intf_attach,
546 .detach = dbus_usbos_intf_detach,
547 .up = dbus_usbos_intf_up,
548 .down = dbus_usbos_intf_down,
549 .send_irb = dbus_usbos_intf_send_irb,
550 .recv_irb = dbus_usbos_intf_recv_irb,
551 .cancel_irb = dbus_usbos_intf_cancel_irb,
552 .send_ctl = dbus_usbos_intf_send_ctl,
553 .recv_ctl = dbus_usbos_intf_recv_ctl,
554 .get_stats = NULL,
555 .get_attrib = dbus_usbos_intf_get_attrib,
556 .remove = NULL,
557 .resume = NULL,
558 .suspend = NULL,
559 .stop = dbus_usbos_intf_stop,
560 .reset = NULL,
561 .pktget = NULL,
562 .pktfree = NULL,
563 .iovar_op = NULL,
564 .dump = NULL,
565 .set_config = dbus_usbos_intf_set_config,
566 .get_config = NULL,
567 .device_exists = NULL,
568 .dlneeded = NULL,
569 .dlstart = NULL,
570 .dlrun = NULL,
571 .recv_needed = dbus_usbos_intf_recv_needed,
572 .exec_rxlock = dbus_usbos_intf_exec_rxlock,
573 .exec_txlock = dbus_usbos_intf_exec_txlock,
574
575 .tx_timer_init = NULL,
576 .tx_timer_start = NULL,
577 .tx_timer_stop = NULL,
578
579 .sched_dpc = NULL,
580 .lock = NULL,
581 .unlock = NULL,
582 .sched_probe_cb = NULL,
583
584 .shutdown = NULL,
585
586 .recv_stop = NULL,
587 .recv_resume = NULL,
588
589 .recv_irb_from_ep = dbus_usbos_intf_recv_irb_from_ep,
590 .readreg = dbus_usbos_readreg
591 };
592
593 static probe_info_t g_probe_info;
594 static void *disc_arg = NULL;
595
596
597
598 static volatile int loopback_rx_cnt, loopback_tx_cnt;
599 int loopback_size;
600 bool is_loopback_pkt(void *buf);
601 int matches_loopback_pkt(void *buf);
602
603 /**
604 * multiple code paths in this file dequeue a URB request, this function makes sure that it happens
605 * in a concurrency save manner. Don't call this from a sleepable process context.
606 */
607 static urb_req_t *
dbus_usbos_qdeq(struct list_head * urbreq_q,spinlock_t * lock)608 dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock)
609 {
610 unsigned long flags;
611 urb_req_t *req;
612
613 ASSERT(urbreq_q != NULL);
614
615 spin_lock_irqsave(lock, flags);
616
617 if (list_empty(urbreq_q)) {
618 req = NULL;
619 } else {
620 ASSERT(urbreq_q->next != NULL);
621 ASSERT(urbreq_q->next != urbreq_q);
622 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
623 #pragma GCC diagnostic push
624 #pragma GCC diagnostic ignored "-Wcast-qual"
625 #endif
626 req = list_entry(urbreq_q->next, urb_req_t, urb_list);
627 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
628 #pragma GCC diagnostic pop
629 #endif
630 list_del_init(&req->urb_list);
631 }
632
633 spin_unlock_irqrestore(lock, flags);
634
635 return req;
636 }
637
638 static void
dbus_usbos_qenq(struct list_head * urbreq_q,urb_req_t * req,spinlock_t * lock)639 dbus_usbos_qenq(struct list_head *urbreq_q, urb_req_t *req, spinlock_t *lock)
640 {
641 unsigned long flags;
642
643 spin_lock_irqsave(lock, flags);
644
645 list_add_tail(&req->urb_list, urbreq_q);
646
647 spin_unlock_irqrestore(lock, flags);
648 }
649
650 /**
651 * multiple code paths in this file remove a URB request from a list, this function makes sure that
652 * it happens in a concurrency save manner. Don't call this from a sleepable process context.
653 * Is quite similar to dbus_usbos_qdeq(), I wonder why this function is needed.
654 */
655 static void
dbus_usbos_req_del(urb_req_t * req,spinlock_t * lock)656 dbus_usbos_req_del(urb_req_t *req, spinlock_t *lock)
657 {
658 unsigned long flags;
659
660 spin_lock_irqsave(lock, flags);
661
662 list_del_init(&req->urb_list);
663
664 spin_unlock_irqrestore(lock, flags);
665 }
666
667
668 /**
669 * Driver requires a pool of URBs to operate. This function is called during
670 * initialization (attach phase), allocates a number of URBs, and puts them
671 * on the free (req_rxfreeq and req_txfreeq) queue
672 */
673 static int
dbus_usbos_urbreqs_alloc(usbos_info_t * usbos_info,uint32 count,bool is_rx)674 dbus_usbos_urbreqs_alloc(usbos_info_t *usbos_info, uint32 count, bool is_rx)
675 {
676 int i;
677 int allocated = 0;
678 int err = DBUS_OK;
679
680 for (i = 0; i < count; i++) {
681 urb_req_t *req;
682
683 req = MALLOC(usbos_info->pub->osh, sizeof(urb_req_t));
684 if (req == NULL) {
685 DBUSERR(("%s: MALLOC req failed\n", __FUNCTION__));
686 err = DBUS_ERR_NOMEM;
687 goto fail;
688 }
689 bzero(req, sizeof(urb_req_t));
690
691 req->urb = USB_ALLOC_URB();
692 if (req->urb == NULL) {
693 DBUSERR(("%s: USB_ALLOC_URB req->urb failed\n", __FUNCTION__));
694 err = DBUS_ERR_NOMEM;
695 goto fail;
696 }
697
698 INIT_LIST_HEAD(&req->urb_list);
699
700 if (is_rx) {
701 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
702 /* don't allocate now. Do it on demand */
703 req->pkt = NULL;
704 #else
705 /* pre-allocate buffers never to be released */
706 req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len);
707 if (req->pkt == NULL) {
708 DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__));
709 err = DBUS_ERR_NOMEM;
710 goto fail;
711 }
712 #endif
713 req->buf_len = usbos_info->rxbuf_len;
714 dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
715 } else {
716 req->buf_len = 0;
717 dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
718 }
719 allocated++;
720 continue;
721
722 fail:
723 if (req) {
724 if (is_rx && req->pkt) {
725 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
726 /* req->pkt is NULL in "NOCOPY" mode */
727 #else
728 MFREE(usbos_info->pub->osh, req->pkt, req->buf_len);
729 #endif
730 }
731 if (req->urb) {
732 USB_FREE_URB(req->urb);
733 }
734 MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t));
735 }
736 break;
737 }
738
739 atomic_add(allocated, is_rx ? &usbos_info->rxallocated : &usbos_info->txallocated);
740
741 if (is_rx) {
742 DBUSTRACE(("%s: add %d (total %d) rx buf, each has %d bytes\n", __FUNCTION__,
743 allocated, atomic_read(&usbos_info->rxallocated), usbos_info->rxbuf_len));
744 } else {
745 DBUSTRACE(("%s: add %d (total %d) tx req\n", __FUNCTION__,
746 allocated, atomic_read(&usbos_info->txallocated)));
747 }
748
749 return err;
750 } /* dbus_usbos_urbreqs_alloc */
751
752 /** Typically called during detach or when attach failed. Don't call until all URBs unlinked */
753 static int
dbus_usbos_urbreqs_free(usbos_info_t * usbos_info,bool is_rx)754 dbus_usbos_urbreqs_free(usbos_info_t *usbos_info, bool is_rx)
755 {
756 int rtn = 0;
757 urb_req_t *req;
758 struct list_head *req_q;
759 spinlock_t *lock;
760
761 if (is_rx) {
762 req_q = &usbos_info->req_rxfreeq;
763 lock = &usbos_info->rxfree_lock;
764 } else {
765 req_q = &usbos_info->req_txfreeq;
766 lock = &usbos_info->txfree_lock;
767 }
768 while ((req = dbus_usbos_qdeq(req_q, lock)) != NULL) {
769
770 if (is_rx) {
771 if (req->pkt) {
772 /* We do MFREE instead of PKTFREE because the pkt has been
773 * converted to native already
774 */
775 MFREE(usbos_info->pub->osh, req->pkt, req->buf_len);
776 req->pkt = NULL;
777 req->buf_len = 0;
778 }
779 } else {
780 /* sending req should not be assigned pkt buffer */
781 ASSERT(req->pkt == NULL);
782 }
783
784 if (req->urb) {
785 USB_FREE_URB(req->urb);
786 req->urb = NULL;
787 }
788 MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t));
789
790 rtn++;
791 }
792 return rtn;
793 } /* dbus_usbos_urbreqs_free */
794
795 /**
796 * called by Linux kernel on URB completion. Upper DBUS layer (dbus_usb.c) has to be notified of
797 * send completion.
798 */
799 void
dbus_usbos_send_complete(CALLBACK_ARGS)800 dbus_usbos_send_complete(CALLBACK_ARGS)
801 {
802 urb_req_t *req = urb->context;
803 dbus_irb_tx_t *txirb = req->arg;
804 usbos_info_t *usbos_info = req->usbinfo;
805 unsigned long flags;
806 int status = DBUS_OK;
807 int txposted;
808
809 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
810
811 spin_lock_irqsave(&usbos_info->txlock, flags);
812
813 dbus_usbos_req_del(req, &usbos_info->txposted_lock);
814 txposted = atomic_dec_return(&usbos_info->txposted);
815 if (unlikely (txposted < 0)) {
816 DBUSERR(("%s ERROR: txposted is negative (%d)!!\n", __FUNCTION__, txposted));
817 }
818 spin_unlock_irqrestore(&usbos_info->txlock, flags);
819
820 if (unlikely (urb->status)) {
821 status = DBUS_ERR_TXFAIL;
822 DBUSTRACE(("txfail status %d\n", urb->status));
823 }
824
825 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
826 /* sending req should not be assigned pkt buffer */
827 ASSERT(req->pkt == NULL);
828 #endif
829 /* txirb should always be set, except for ZLP. ZLP is reusing this callback function. */
830 if (txirb != NULL) {
831 if (txirb->send_buf != NULL) {
832 MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len);
833 txirb->send_buf = NULL;
834 req->buf_len = 0;
835 }
836 if (likely (usbos_info->cbarg && usbos_info->cbs)) {
837 if (likely (usbos_info->cbs->send_irb_complete != NULL))
838 usbos_info->cbs->send_irb_complete(usbos_info->cbarg, txirb, status);
839 }
840 }
841
842 dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
843 } /* dbus_usbos_send_complete */
844
845 /**
846 * In order to receive USB traffic from the dongle, we need to supply the Linux kernel with a free
847 * URB that is going to contain received data.
848 */
849 static int
dbus_usbos_recv_urb_submit(usbos_info_t * usbos_info,dbus_irb_rx_t * rxirb,uint32 ep_idx)850 dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint32 ep_idx)
851 {
852 urb_req_t *req;
853 int ret = DBUS_OK;
854 unsigned long flags;
855 void *p;
856 uint rx_pipe;
857 int rxposted;
858
859 BCM_REFERENCE(rxposted);
860
861 if (!(req = dbus_usbos_qdeq(&usbos_info->req_rxfreeq, &usbos_info->rxfree_lock))) {
862 DBUSTRACE(("%s No free URB!\n", __FUNCTION__));
863 return DBUS_ERR_RXDROP;
864 }
865
866 spin_lock_irqsave(&usbos_info->rxlock, flags);
867
868 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
869 req->pkt = rxirb->pkt = PKTGET(usbos_info->pub->osh, req->buf_len, FALSE);
870 if (!rxirb->pkt) {
871 DBUSERR(("%s: PKTGET failed\n", __FUNCTION__));
872 dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
873 ret = DBUS_ERR_RXDROP;
874 goto fail;
875 }
876 /* consider the packet "native" so we don't count it as MALLOCED in the osl */
877 PKTTONATIVE(usbos_info->pub->osh, req->pkt);
878 rxirb->buf = NULL;
879 p = PKTDATA(usbos_info->pub->osh, req->pkt);
880 #else
881 if (req->buf_len != usbos_info->rxbuf_len) {
882 ASSERT(req->pkt);
883 MFREE(usbos_info->pub->osh, req->pkt, req->buf_len);
884 DBUSTRACE(("%s: replace rx buff: old len %d, new len %d\n", __FUNCTION__,
885 req->buf_len, usbos_info->rxbuf_len));
886 req->buf_len = 0;
887 req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len);
888 if (req->pkt == NULL) {
889 DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__));
890 ret = DBUS_ERR_NOMEM;
891 goto fail;
892 }
893 req->buf_len = usbos_info->rxbuf_len;
894 }
895 rxirb->buf = req->pkt;
896 p = rxirb->buf;
897 #endif /* defined(BCM_RPC_NOCOPY) */
898 rxirb->buf_len = req->buf_len;
899 req->usbinfo = usbos_info;
900 req->arg = rxirb;
901 if (ep_idx == 0) {
902 rx_pipe = usbos_info->rx_pipe;
903 } else {
904 rx_pipe = usbos_info->rx_pipe2;
905 ASSERT(usbos_info->rx_pipe2);
906 }
907 /* Prepare the URB */
908 usb_fill_bulk_urb(req->urb, usbos_info->usb, rx_pipe,
909 p,
910 rxirb->buf_len,
911 (usb_complete_t)dbus_usbos_recv_complete, req);
912 req->urb->transfer_flags |= URB_QUEUE_BULK;
913
914 if ((ret = USB_SUBMIT_URB(req->urb))) {
915 DBUSERR(("%s USB_SUBMIT_URB failed. status %d\n", __FUNCTION__, ret));
916 dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
917 ret = DBUS_ERR_RXFAIL;
918 goto fail;
919 }
920 rxposted = atomic_inc_return(&usbos_info->rxposted);
921
922 dbus_usbos_qenq(&usbos_info->req_rxpostedq, req, &usbos_info->rxposted_lock);
923 fail:
924 spin_unlock_irqrestore(&usbos_info->rxlock, flags);
925 return ret;
926 } /* dbus_usbos_recv_urb_submit */
927
928
929 /**
930 * Called by worked thread when a 'receive URB' completed or Linux kernel when it returns a URB to
931 * this driver.
932 */
933 static void
dbus_usbos_recv_complete_handle(urb_req_t * req,int len,int status)934 dbus_usbos_recv_complete_handle(urb_req_t *req, int len, int status)
935 {
936 dbus_irb_rx_t *rxirb = req->arg;
937 usbos_info_t *usbos_info = req->usbinfo;
938 unsigned long flags;
939 int rxallocated, rxposted;
940 int dbus_status = DBUS_OK;
941 bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0;
942
943 spin_lock_irqsave(&usbos_info->rxlock, flags);
944 dbus_usbos_req_del(req, &usbos_info->rxposted_lock);
945 rxposted = atomic_dec_return(&usbos_info->rxposted);
946 rxallocated = atomic_read(&usbos_info->rxallocated);
947 spin_unlock_irqrestore(&usbos_info->rxlock, flags);
948
949 if ((rxallocated < usbos_info->pub->nrxq) && (!status) &&
950 (rxposted == DBUS_USB_RXQUEUE_LOWER_WATERMARK)) {
951 DBUSTRACE(("%s: need more rx buf: rxallocated %d rxposted %d!\n",
952 __FUNCTION__, rxallocated, rxposted));
953 dbus_usbos_urbreqs_alloc(usbos_info,
954 MIN(DBUS_USB_RXQUEUE_BATCH_ADD,
955 usbos_info->pub->nrxq - rxallocated), TRUE);
956 }
957
958 /* Handle errors */
959 if (status) {
960 /*
961 * Linux 2.4 disconnect: -ENOENT or -EILSEQ for CRC error; rmmod: -ENOENT
962 * Linux 2.6 disconnect: -EPROTO, rmmod: -ESHUTDOWN
963 */
964 if ((status == -ENOENT && (!killed))|| status == -ESHUTDOWN) {
965 /* NOTE: unlink() can not be called from URB callback().
966 * Do not call dbusos_stop() here.
967 */
968 DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status));
969 dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN);
970 } else if (status == -EPROTO) {
971 DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status));
972 } else if (killed && (status == -EHOSTUNREACH || status == -ENOENT)) {
973 /* Device is suspended */
974 } else {
975 DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status));
976 dbus_usbos_errhandler(usbos_info, DBUS_ERR_RXFAIL);
977 }
978
979 /* On error, don't submit more URBs yet */
980 rxirb->buf = NULL;
981 rxirb->actual_len = 0;
982 dbus_status = DBUS_ERR_RXFAIL;
983 goto fail;
984 }
985
986 /* Make the skb represent the received urb */
987 rxirb->actual_len = len;
988
989 if (rxirb->actual_len < sizeof(uint32)) {
990 DBUSTRACE(("small pkt len %d, process as ZLP\n", rxirb->actual_len));
991 dbus_status = DBUS_ERR_RXZLP;
992 }
993
994 fail:
995 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
996 /* detach the packet from the queue */
997 req->pkt = NULL;
998 #endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY */
999
1000 if (usbos_info->cbarg && usbos_info->cbs) {
1001 if (usbos_info->cbs->recv_irb_complete) {
1002 usbos_info->cbs->recv_irb_complete(usbos_info->cbarg, rxirb, dbus_status);
1003 }
1004 }
1005
1006 dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock);
1007
1008 /* Mark the interface as busy to reset USB autosuspend timer */
1009 USB_MARK_LAST_BUSY(usbos_info->usb);
1010 } /* dbus_usbos_recv_complete_handle */
1011
1012 /** called by Linux kernel when it returns a URB to this driver */
1013 static void
dbus_usbos_recv_complete(CALLBACK_ARGS)1014 dbus_usbos_recv_complete(CALLBACK_ARGS)
1015 {
1016 #ifdef USBOS_THREAD
1017 dbus_usbos_dispatch_schedule(CALLBACK_ARGS_DATA);
1018 #else /* !USBOS_THREAD */
1019 dbus_usbos_recv_complete_handle(urb->context, urb->actual_length, urb->status);
1020 #endif /* USBOS_THREAD */
1021 }
1022
1023
1024 /**
1025 * If Linux notifies our driver that a control read or write URB has completed, we should notify
1026 * the DBUS layer above us (dbus_usb.c in this case).
1027 */
1028 static void
dbus_usbos_ctl_complete(usbos_info_t * usbos_info,int type,int urbstatus)1029 dbus_usbos_ctl_complete(usbos_info_t *usbos_info, int type, int urbstatus)
1030 {
1031 int status = DBUS_ERR;
1032
1033 if (usbos_info == NULL)
1034 return;
1035
1036 switch (urbstatus) {
1037 case 0:
1038 status = DBUS_OK;
1039 break;
1040 case -EINPROGRESS:
1041 case -ENOENT:
1042 default:
1043 #ifdef INTR_EP_ENABLE
1044 DBUSERR(("%s:%d fail status %d bus:%d susp:%d intr:%d ctli:%d ctlo:%d\n",
1045 __FUNCTION__, type, urbstatus,
1046 usbos_info->pub->busstate, g_probe_info.suspend_state,
1047 usbos_info->intr_urb_submitted, usbos_info->ctlin_urb_submitted,
1048 usbos_info->ctlout_urb_submitted));
1049 #else
1050 DBUSERR(("%s: failed with status %d\n", __FUNCTION__, urbstatus));
1051 status = DBUS_ERR;
1052 break;
1053 #endif /* INTR_EP_ENABLE */
1054 }
1055
1056 if (usbos_info->cbarg && usbos_info->cbs) {
1057 if (usbos_info->cbs->ctl_complete)
1058 usbos_info->cbs->ctl_complete(usbos_info->cbarg, type, status);
1059 }
1060 }
1061
1062 /** called by Linux */
1063 static void
dbus_usbos_ctlread_complete(CALLBACK_ARGS)1064 dbus_usbos_ctlread_complete(CALLBACK_ARGS)
1065 {
1066 usbos_info_t *usbos_info = (usbos_info_t *)urb->context;
1067
1068 ASSERT(urb);
1069 usbos_info = (usbos_info_t *)urb->context;
1070
1071 dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_READ, urb->status);
1072
1073 #ifdef USBOS_THREAD
1074 if (usbos_info->rxctl_deferrespok) {
1075 usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS |
1076 USB_RECIP_INTERFACE;
1077 usbos_info->ctl_read.bRequest = 1;
1078 }
1079 #endif
1080
1081 up(&usbos_info->ctl_lock);
1082
1083 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
1084 }
1085
1086 /** called by Linux */
1087 static void
dbus_usbos_ctlwrite_complete(CALLBACK_ARGS)1088 dbus_usbos_ctlwrite_complete(CALLBACK_ARGS)
1089 {
1090 usbos_info_t *usbos_info = (usbos_info_t *)urb->context;
1091
1092 ASSERT(urb);
1093 usbos_info = (usbos_info_t *)urb->context;
1094
1095 dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_WRITE, urb->status);
1096
1097 #ifdef USBOS_TX_THREAD
1098 usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
1099 #endif /* USBOS_TX_THREAD */
1100
1101 up(&usbos_info->ctl_lock);
1102
1103 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
1104 }
1105
1106 #ifdef INTR_EP_ENABLE
1107 /** called by Linux */
1108 static void
dbus_usbos_intr_complete(CALLBACK_ARGS)1109 dbus_usbos_intr_complete(CALLBACK_ARGS)
1110 {
1111 usbos_info_t *usbos_info = (usbos_info_t *)urb->context;
1112 bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0;
1113
1114 if (usbos_info == NULL || usbos_info->pub == NULL)
1115 return;
1116 if ((urb->status == -ENOENT && (!killed)) || urb->status == -ESHUTDOWN ||
1117 urb->status == -ENODEV) {
1118 dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN);
1119 }
1120
1121 if (usbos_info->pub->busstate == DBUS_STATE_DOWN) {
1122 DBUSERR(("%s: intr cb when DBUS down, ignoring\n", __FUNCTION__));
1123 return;
1124 }
1125 dbus_usbos_ctl_complete(usbos_info, DBUS_CBINTR_POLL, urb->status);
1126 }
1127 #endif /* INTR_EP_ENABLE */
1128
1129 /**
1130 * when the bus is going to sleep or halt, the Linux kernel requires us to take ownership of our
1131 * URBs again. Multiple code paths in this file require a list of URBs to be cancelled in a
1132 * concurrency save manner.
1133 */
1134 static void
dbus_usbos_unlink(struct list_head * urbreq_q,spinlock_t * lock)1135 dbus_usbos_unlink(struct list_head *urbreq_q, spinlock_t *lock)
1136 {
1137 urb_req_t *req;
1138
1139 /* dbus_usbos_recv_complete() adds req back to req_freeq */
1140 while ((req = dbus_usbos_qdeq(urbreq_q, lock)) != NULL) {
1141 ASSERT(req->urb != NULL);
1142 USB_UNLINK_URB(req->urb);
1143 }
1144 }
1145
1146 /** multiple code paths in this file require the bus to stop */
1147 static void
dbus_usbos_cancel_all_urbs(usbos_info_t * usbos_info)1148 dbus_usbos_cancel_all_urbs(usbos_info_t *usbos_info)
1149 {
1150 int rxposted, txposted;
1151
1152 DBUSTRACE(("%s: unlink all URBs\n", __FUNCTION__));
1153
1154 #ifdef USBOS_TX_THREAD
1155 usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
1156
1157 /* Yield the CPU to TX thread so all pending requests are submitted */
1158 while (!list_empty(&usbos_info->usbos_tx_list)) {
1159 wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
1160 OSL_SLEEP(10);
1161 }
1162 #endif /* USBOS_TX_THREAD */
1163
1164 /* tell Linux kernel to cancel a single intr, ctl and blk URB */
1165 if (usbos_info->intr_urb)
1166 USB_UNLINK_URB(usbos_info->intr_urb);
1167 if (usbos_info->ctl_urb)
1168 USB_UNLINK_URB(usbos_info->ctl_urb);
1169 if (usbos_info->blk_urb)
1170 USB_UNLINK_URB(usbos_info->blk_urb);
1171
1172 dbus_usbos_unlink(&usbos_info->req_txpostedq, &usbos_info->txposted_lock);
1173 dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock);
1174
1175 /* Wait until the callbacks for all submitted URBs have been called, because the
1176 * handler needs to know is an USB suspend is in progress.
1177 */
1178 SPINWAIT((atomic_read(&usbos_info->txposted) != 0 ||
1179 atomic_read(&usbos_info->rxposted) != 0), 10000);
1180
1181 txposted = atomic_read(&usbos_info->txposted);
1182 rxposted = atomic_read(&usbos_info->rxposted);
1183 if (txposted != 0 || rxposted != 0) {
1184 DBUSERR(("%s ERROR: REQs posted, rx=%d tx=%d!\n",
1185 __FUNCTION__, rxposted, txposted));
1186 }
1187 } /* dbus_usbos_cancel_all_urbs */
1188
1189 /** multiple code paths require the bus to stop */
1190 static void
dbusos_stop(usbos_info_t * usbos_info)1191 dbusos_stop(usbos_info_t *usbos_info)
1192 {
1193 urb_req_t *req;
1194 int rxposted;
1195 req = NULL;
1196 BCM_REFERENCE(req);
1197
1198 ASSERT(usbos_info);
1199
1200 dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN);
1201
1202 dbus_usbos_cancel_all_urbs(usbos_info);
1203
1204 #ifdef USBOS_THREAD
1205 /* yield the CPU to rx packet thread */
1206 while (1) {
1207 if (atomic_read(&usbos_info->usbos_list_cnt) <= 0) break;
1208 wake_up_interruptible(&usbos_info->usbos_queue_head);
1209 OSL_SLEEP(3);
1210 }
1211 #endif /* USBOS_THREAD */
1212
1213 rxposted = atomic_read(&usbos_info->rxposted);
1214 if (rxposted > 0) {
1215 DBUSERR(("%s ERROR: rx REQs posted=%d in stop!\n", __FUNCTION__,
1216 rxposted));
1217 }
1218
1219 ASSERT(atomic_read(&usbos_info->txposted) == 0 && rxposted == 0);
1220
1221 } /* dbusos_stop */
1222
1223 #if defined(USB_SUSPEND_AVAILABLE)
1224
1225 /**
1226 * Linux kernel sports a 'USB auto suspend' feature. See: http://lwn.net/Articles/373550/
1227 * The suspend method is called by the Linux kernel to warn the driver that the device is going to
1228 * be suspended. If the driver returns a negative error code, the suspend will be aborted. If the
1229 * driver returns 0, it must cancel all outstanding URBs (usb_kill_urb()) and not submit any more.
1230 */
1231 static int
dbus_usbos_suspend(struct usb_interface * intf,pm_message_t message)1232 dbus_usbos_suspend(struct usb_interface *intf,
1233 pm_message_t message)
1234 {
1235 usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info;
1236 int err = 0;
1237
1238 printf("%s Enter\n", __FUNCTION__);
1239
1240 /* DHD for full dongle model */
1241 g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING;
1242 if (drvinfo.suspend && disc_arg)
1243 err = drvinfo.suspend(disc_arg);
1244 if (err) {
1245 printf("%s: err=%d\n", __FUNCTION__, err);
1246 // g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
1247 // return err;
1248 }
1249 usbos_info->pub->busstate = DBUS_STATE_SLEEP;
1250
1251 dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info);
1252 g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
1253
1254 printf("%s Exit err=%d\n", __FUNCTION__, err);
1255 return err;
1256 }
1257
1258 /**
1259 * The resume method is called to tell the driver that the device has been resumed and the driver
1260 * can return to normal operation. URBs may once more be submitted.
1261 */
1262 static int
dbus_usbos_resume(struct usb_interface * intf)1263 dbus_usbos_resume(struct usb_interface *intf)
1264 {
1265 usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info;
1266
1267 printf("%s Enter\n", __FUNCTION__);
1268
1269 g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
1270 if (drvinfo.resume && disc_arg)
1271 drvinfo.resume(disc_arg);
1272 usbos_info->pub->busstate = DBUS_STATE_UP;
1273
1274 printf("%s Exit\n", __FUNCTION__);
1275 return 0;
1276 }
1277
1278 /**
1279 * This function is directly called by the Linux kernel, when the suspended device has been reset
1280 * instead of being resumed
1281 */
1282 static int
dbus_usbos_reset_resume(struct usb_interface * intf)1283 dbus_usbos_reset_resume(struct usb_interface *intf)
1284 {
1285 printf("%s Enter\n", __FUNCTION__);
1286
1287 g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
1288 if (drvinfo.resume && disc_arg)
1289 drvinfo.resume(disc_arg);
1290
1291 printf("%s Exit\n", __FUNCTION__);
1292 return 0;
1293 }
1294
1295 #endif /* USB_SUSPEND_AVAILABLE */
1296
1297 /**
1298 * Called by Linux kernel at initialization time, kernel wants to know if our driver will accept the
1299 * caller supplied USB interface. Note that USB drivers are bound to interfaces, and not to USB
1300 * devices.
1301 */
1302 #ifdef KERNEL26
1303 #define DBUS_USBOS_PROBE() static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id)
1304 #define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_interface *intf)
1305 #else
1306 #define DBUS_USBOS_PROBE() static void * dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, const struct usb_device_id *id)
1307 #define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr)
1308 #endif /* KERNEL26 */
1309
DBUS_USBOS_PROBE()1310 DBUS_USBOS_PROBE()
1311 {
1312 int ep;
1313 struct usb_endpoint_descriptor *endpoint;
1314 int ret = 0;
1315 #ifdef KERNEL26
1316 struct usb_device *usb = interface_to_usbdev(intf);
1317 #else
1318 int claimed = 0;
1319 #endif
1320 int num_of_eps;
1321 #ifdef BCMUSBDEV_COMPOSITE
1322 int wlan_if = -1;
1323 bool intr_ep = FALSE;
1324 #endif /* BCMUSBDEV_COMPOSITE */
1325 wifi_adapter_info_t *adapter;
1326
1327 DHD_MUTEX_LOCK();
1328
1329 DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__,
1330 usb->bus->busnum, usb->portnum));
1331 adapter = dhd_wifi_platform_attach_adapter(USB_BUS, usb->bus->busnum,
1332 usb->portnum, WIFI_STATUS_POWER_ON);
1333 if (adapter == NULL) {
1334 DBUSERR(("%s: can't find adapter info for this chip\n", __FUNCTION__));
1335 goto fail;
1336 }
1337
1338 #ifdef BCMUSBDEV_COMPOSITE
1339 wlan_if = dbus_usbos_intf_wlan(usb);
1340 #ifdef KERNEL26
1341 if ((wlan_if >= 0) && (IFPTR(usb, wlan_if) == intf))
1342 #else
1343 if (wlan_if == ifnum)
1344 #endif /* KERNEL26 */
1345 {
1346 #endif /* BCMUSBDEV_COMPOSITE */
1347 g_probe_info.usb = usb;
1348 g_probe_info.dldone = TRUE;
1349 #ifdef BCMUSBDEV_COMPOSITE
1350 } else {
1351 DBUSTRACE(("dbus_usbos_probe: skip probe for non WLAN interface\n"));
1352 ret = BCME_UNSUPPORTED;
1353 goto fail;
1354 }
1355 #endif /* BCMUSBDEV_COMPOSITE */
1356
1357 #ifdef KERNEL26
1358 g_probe_info.intf = intf;
1359 #endif /* KERNEL26 */
1360
1361 #ifdef BCMUSBDEV_COMPOSITE
1362 if (IFDESC(usb, wlan_if).bInterfaceNumber > USB_COMPIF_MAX)
1363 #else
1364 if (IFDESC(usb, CONTROL_IF).bInterfaceNumber)
1365 #endif /* BCMUSBDEV_COMPOSITE */
1366 {
1367 ret = -1;
1368 goto fail;
1369 }
1370 if (id != NULL) {
1371 g_probe_info.vid = id->idVendor;
1372 g_probe_info.pid = id->idProduct;
1373 }
1374
1375 #ifdef KERNEL26
1376 usb_set_intfdata(intf, &g_probe_info);
1377 #endif
1378
1379 /* Check that the device supports only one configuration */
1380 if (usb->descriptor.bNumConfigurations != 1) {
1381 ret = -1;
1382 goto fail;
1383 }
1384
1385 if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
1386 #ifdef BCMUSBDEV_COMPOSITE
1387 if ((usb->descriptor.bDeviceClass != USB_CLASS_MISC) &&
1388 (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS)) {
1389 #endif /* BCMUSBDEV_COMPOSITE */
1390 ret = -1;
1391 goto fail;
1392 #ifdef BCMUSBDEV_COMPOSITE
1393 }
1394 #endif /* BCMUSBDEV_COMPOSITE */
1395 }
1396
1397 /*
1398 * Only the BDC interface configuration is supported:
1399 * Device class: USB_CLASS_VENDOR_SPEC
1400 * if0 class: USB_CLASS_VENDOR_SPEC
1401 * if0/ep0: control
1402 * if0/ep1: bulk in
1403 * if0/ep2: bulk out (ok if swapped with bulk in)
1404 */
1405 if (CONFIGDESC(usb)->bNumInterfaces != 1) {
1406 #ifdef BCMUSBDEV_COMPOSITE
1407 if (CONFIGDESC(usb)->bNumInterfaces > USB_COMPIF_MAX) {
1408 #endif /* BCMUSBDEV_COMPOSITE */
1409 ret = -1;
1410 goto fail;
1411 #ifdef BCMUSBDEV_COMPOSITE
1412 }
1413 #endif /* BCMUSBDEV_COMPOSITE */
1414 }
1415
1416 /* Check interface */
1417 #ifndef KERNEL26
1418 #ifdef BCMUSBDEV_COMPOSITE
1419 if (usb_interface_claimed(IFPTR(usb, wlan_if)))
1420 #else
1421 if (usb_interface_claimed(IFPTR(usb, CONTROL_IF)))
1422 #endif /* BCMUSBDEV_COMPOSITE */
1423 {
1424 ret = -1;
1425 goto fail;
1426 }
1427 #endif /* !KERNEL26 */
1428
1429 #ifdef BCMUSBDEV_COMPOSITE
1430 if ((IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
1431 IFDESC(usb, wlan_if).bInterfaceSubClass != 2 ||
1432 IFDESC(usb, wlan_if).bInterfaceProtocol != 0xff) &&
1433 (IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_MISC ||
1434 IFDESC(usb, wlan_if).bInterfaceSubClass != USB_SUBCLASS_COMMON ||
1435 IFDESC(usb, wlan_if).bInterfaceProtocol != USB_PROTO_IAD))
1436 #else
1437 if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
1438 IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 ||
1439 IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff)
1440 #endif /* BCMUSBDEV_COMPOSITE */
1441 {
1442 #ifdef BCMUSBDEV_COMPOSITE
1443 DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n",
1444 __FUNCTION__,
1445 IFDESC(usb, wlan_if).bInterfaceClass,
1446 IFDESC(usb, wlan_if).bInterfaceSubClass,
1447 IFDESC(usb, wlan_if).bInterfaceProtocol));
1448 #else
1449 DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n",
1450 __FUNCTION__,
1451 IFDESC(usb, CONTROL_IF).bInterfaceClass,
1452 IFDESC(usb, CONTROL_IF).bInterfaceSubClass,
1453 IFDESC(usb, CONTROL_IF).bInterfaceProtocol));
1454 #endif /* BCMUSBDEV_COMPOSITE */
1455 ret = -1;
1456 goto fail;
1457 }
1458
1459 /* Check control endpoint */
1460 #ifdef BCMUSBDEV_COMPOSITE
1461 endpoint = &IFEPDESC(usb, wlan_if, 0);
1462 #else
1463 endpoint = &IFEPDESC(usb, CONTROL_IF, 0);
1464 #endif /* BCMUSBDEV_COMPOSITE */
1465 if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
1466 #ifdef BCMUSBDEV_COMPOSITE
1467 if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
1468 USB_ENDPOINT_XFER_BULK) {
1469 #endif /* BCMUSBDEV_COMPOSITE */
1470 DBUSERR(("%s: invalid control endpoint %d\n",
1471 __FUNCTION__, endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK));
1472 ret = -1;
1473 goto fail;
1474 #ifdef BCMUSBDEV_COMPOSITE
1475 }
1476 #endif /* BCMUSBDEV_COMPOSITE */
1477 }
1478
1479 #ifdef BCMUSBDEV_COMPOSITE
1480 if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
1481 #endif /* BCMUSBDEV_COMPOSITE */
1482 g_probe_info.intr_pipe =
1483 usb_rcvintpipe(usb, endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
1484 #ifdef BCMUSBDEV_COMPOSITE
1485 intr_ep = TRUE;
1486 }
1487 #endif /* BCMUSBDEV_COMPOSITE */
1488
1489 #ifndef KERNEL26
1490 /* Claim interface */
1491 #ifdef BCMUSBDEV_COMPOSITE
1492 usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, wlan_if), &g_probe_info);
1493 #else
1494 usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF), &g_probe_info);
1495 #endif /* BCMUSBDEV_COMPOSITE */
1496 claimed = 1;
1497 #endif /* !KERNEL26 */
1498 g_probe_info.rx_pipe = 0;
1499 g_probe_info.rx_pipe2 = 0;
1500 g_probe_info.tx_pipe = 0;
1501 #ifdef BCMUSBDEV_COMPOSITE
1502 if (intr_ep)
1503 ep = 1;
1504 else
1505 ep = 0;
1506 num_of_eps = IFDESC(usb, wlan_if).bNumEndpoints - 1;
1507 #else
1508 num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1;
1509 #endif /* BCMUSBDEV_COMPOSITE */
1510
1511 if ((num_of_eps != 2) && (num_of_eps != 3)) {
1512 #ifdef BCMUSBDEV_COMPOSITE
1513 if (num_of_eps > 7)
1514 #endif /* BCMUSBDEV_COMPOSITE */
1515 ASSERT(0);
1516 }
1517 /* Check data endpoints and get pipes */
1518 #ifdef BCMUSBDEV_COMPOSITE
1519 for (; ep <= num_of_eps; ep++)
1520 #else
1521 for (ep = 1; ep <= num_of_eps; ep++)
1522 #endif /* BCMUSBDEV_COMPOSITE */
1523 {
1524 #ifdef BCMUSBDEV_COMPOSITE
1525 endpoint = &IFEPDESC(usb, wlan_if, ep);
1526 #else
1527 endpoint = &IFEPDESC(usb, BULK_IF, ep);
1528 #endif /* BCMUSBDEV_COMPOSITE */
1529 if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
1530 USB_ENDPOINT_XFER_BULK) {
1531 DBUSERR(("%s: invalid data endpoint %d\n",
1532 __FUNCTION__, ep));
1533 ret = -1;
1534 goto fail;
1535 }
1536
1537 if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
1538 /* direction: dongle->host */
1539 if (!g_probe_info.rx_pipe) {
1540 g_probe_info.rx_pipe = usb_rcvbulkpipe(usb,
1541 (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK));
1542 } else {
1543 g_probe_info.rx_pipe2 = usb_rcvbulkpipe(usb,
1544 (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK));
1545 }
1546
1547 } else
1548 g_probe_info.tx_pipe = usb_sndbulkpipe(usb, (endpoint->bEndpointAddress &
1549 USB_ENDPOINT_NUMBER_MASK));
1550 }
1551
1552 /* Allocate interrupt URB and data buffer */
1553 /* RNDIS says 8-byte intr, our old drivers used 4-byte */
1554 #ifdef BCMUSBDEV_COMPOSITE
1555 g_probe_info.intr_size = (IFEPDESC(usb, wlan_if, 0).wMaxPacketSize == 16) ? 8 : 4;
1556 g_probe_info.interval = IFEPDESC(usb, wlan_if, 0).bInterval;
1557 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21))
1558 usb->quirks |= USB_QUIRK_NO_SET_INTF;
1559 #endif
1560 #else
1561 g_probe_info.intr_size = (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == 16) ? 8 : 4;
1562 g_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
1563 #endif /* BCMUSBDEV_COMPOSITE */
1564
1565 #ifndef KERNEL26
1566 /* usb_fill_int_urb does the interval decoding in 2.6 */
1567 if (usb->speed == USB_SPEED_HIGH)
1568 g_probe_info.interval = 1 << (g_probe_info.interval - 1);
1569 #endif
1570 if (usb->speed == USB_SPEED_SUPER) {
1571 g_probe_info.device_speed = SUPER_SPEED;
1572 DBUSERR(("super speed device detected\n"));
1573 } else if (usb->speed == USB_SPEED_HIGH) {
1574 g_probe_info.device_speed = HIGH_SPEED;
1575 DBUSERR(("high speed device detected\n"));
1576 } else {
1577 g_probe_info.device_speed = FULL_SPEED;
1578 DBUSERR(("full speed device detected\n"));
1579 }
1580 if (g_probe_info.dereged == FALSE && drvinfo.probe) {
1581 disc_arg = drvinfo.probe(usb->bus->busnum, usb->portnum, 0);
1582 }
1583
1584 g_probe_info.disc_cb_done = FALSE;
1585
1586 #ifdef KERNEL26
1587 intf->needs_remote_wakeup = 1;
1588 #endif /* KERNEL26 */
1589 DHD_MUTEX_UNLOCK();
1590
1591 /* Success */
1592 #ifdef KERNEL26
1593 return DBUS_OK;
1594 #else
1595 usb_inc_dev_use(usb);
1596 return &g_probe_info;
1597 #endif
1598
1599 fail:
1600 printf("%s: Exit ret=%d\n", __FUNCTION__, ret);
1601 #ifdef BCMUSBDEV_COMPOSITE
1602 if (ret != BCME_UNSUPPORTED)
1603 #endif /* BCMUSBDEV_COMPOSITE */
1604 DBUSERR(("%s: failed with errno %d\n", __FUNCTION__, ret));
1605 #ifndef KERNEL26
1606 if (claimed)
1607 #ifdef BCMUSBDEV_COMPOSITE
1608 usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if));
1609 #else
1610 usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF));
1611 #endif /* BCMUSBDEV_COMPOSITE */
1612 #endif /* !KERNEL26 */
1613
1614 DHD_MUTEX_UNLOCK();
1615 #ifdef KERNEL26
1616 usb_set_intfdata(intf, NULL);
1617 return ret;
1618 #else
1619 return NULL;
1620 #endif
1621 } /* dbus_usbos_probe */
1622
1623 /** Called by Linux kernel, is the counter part of dbus_usbos_probe() */
DBUS_USBOS_DISCONNECT()1624 DBUS_USBOS_DISCONNECT()
1625 {
1626 #ifdef KERNEL26
1627 struct usb_device *usb = interface_to_usbdev(intf);
1628 probe_info_t *probe_usb_init_data = usb_get_intfdata(intf);
1629 #else
1630 probe_info_t *probe_usb_init_data = (probe_info_t *) ptr;
1631 #endif
1632 usbos_info_t *usbos_info;
1633
1634 DHD_MUTEX_LOCK();
1635
1636 DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__,
1637 usb->bus->busnum, usb->portnum));
1638
1639 if (probe_usb_init_data) {
1640 usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info;
1641 if (usbos_info) {
1642 if ((probe_usb_init_data->dereged == FALSE) && drvinfo.remove && disc_arg) {
1643 drvinfo.remove(disc_arg);
1644 disc_arg = NULL;
1645 probe_usb_init_data->disc_cb_done = TRUE;
1646 }
1647 }
1648 }
1649
1650 if (usb) {
1651 #ifndef KERNEL26
1652 #ifdef BCMUSBDEV_COMPOSITE
1653 usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if));
1654 #else
1655 usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF));
1656 #endif /* BCMUSBDEV_COMPOSITE */
1657 usb_dec_dev_use(usb);
1658 #endif /* !KERNEL26 */
1659 }
1660 DHD_MUTEX_UNLOCK();
1661 } /* dbus_usbos_disconnect */
1662
1663 #define LOOPBACK_PKT_START 0xBABE1234
1664
is_loopback_pkt(void * buf)1665 bool is_loopback_pkt(void *buf)
1666 {
1667
1668 uint32 *buf_ptr = (uint32 *) buf;
1669
1670 if (*buf_ptr == LOOPBACK_PKT_START)
1671 return TRUE;
1672 return FALSE;
1673
1674 }
1675
matches_loopback_pkt(void * buf)1676 int matches_loopback_pkt(void *buf)
1677 {
1678 int i, j;
1679 unsigned char *cbuf = (unsigned char *) buf;
1680
1681 for (i = 4; i < loopback_size; i++) {
1682 if (cbuf[i] != (i % 256)) {
1683 printf("%s: mismatch at i=%d %d : ", __FUNCTION__, i, cbuf[i]);
1684 for (j = i; ((j < i+ 16) && (j < loopback_size)); j++) {
1685 printf("%d ", cbuf[j]);
1686 }
1687 printf("\n");
1688 return 0;
1689 }
1690 }
1691 loopback_rx_cnt++;
1692 return 1;
1693 }
1694
dbus_usbos_loopback_tx(void * usbos_info_ptr,int cnt,int size)1695 int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size)
1696 {
1697 usbos_info_t *usbos_info = (usbos_info_t *) usbos_info_ptr;
1698 unsigned char *buf;
1699 int j;
1700 void* p = NULL;
1701 int rc, last_rx_cnt;
1702 int tx_failed_cnt;
1703 int max_size = 1650;
1704 int usb_packet_size = 512;
1705 int min_packet_size = 10;
1706
1707 if (size % usb_packet_size == 0) {
1708 size = size - 1;
1709 DBUSERR(("%s: overriding size=%d \n", __FUNCTION__, size));
1710 }
1711
1712 if (size < min_packet_size) {
1713 size = min_packet_size;
1714 DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, min_packet_size));
1715 }
1716 if (size > max_size) {
1717 size = max_size;
1718 DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, max_size));
1719 }
1720
1721 loopback_tx_cnt = 0;
1722 loopback_rx_cnt = 0;
1723 tx_failed_cnt = 0;
1724 loopback_size = size;
1725
1726 while (loopback_tx_cnt < cnt) {
1727 uint32 *x;
1728 int pkt_size = loopback_size;
1729
1730 p = PKTGET(usbos_info->pub->osh, pkt_size, TRUE);
1731 if (p == NULL) {
1732 DBUSERR(("%s:%d Failed to allocate packet sz=%d\n",
1733 __FUNCTION__, __LINE__, pkt_size));
1734 return BCME_ERROR;
1735 }
1736 x = (uint32*) PKTDATA(usbos_info->pub->osh, p);
1737 *x = LOOPBACK_PKT_START;
1738 buf = (unsigned char*) x;
1739 for (j = 4; j < pkt_size; j++) {
1740 buf[j] = j % 256;
1741 }
1742 rc = dbus_send_buf(usbos_info->pub, buf, pkt_size, p);
1743 if (rc != BCME_OK) {
1744 DBUSERR(("%s:%d Freeing packet \n", __FUNCTION__, __LINE__));
1745 PKTFREE(usbos_info->pub->osh, p, TRUE);
1746 dbus_usbos_wait(usbos_info, 1);
1747 tx_failed_cnt++;
1748 } else {
1749 loopback_tx_cnt++;
1750 tx_failed_cnt = 0;
1751 }
1752 if (tx_failed_cnt == 5) {
1753 DBUSERR(("%s : Failed to send loopback packets cnt=%d loopback_tx_cnt=%d\n",
1754 __FUNCTION__, cnt, loopback_tx_cnt));
1755 break;
1756 }
1757 }
1758 printf("Transmitted %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size);
1759
1760 last_rx_cnt = loopback_rx_cnt;
1761 while (loopback_rx_cnt < loopback_tx_cnt) {
1762 dbus_usbos_wait(usbos_info, 1);
1763 if (loopback_rx_cnt <= last_rx_cnt) {
1764 DBUSERR(("%s: Matched rx cnt stuck at %d \n", __FUNCTION__, last_rx_cnt));
1765 return BCME_ERROR;
1766 }
1767 last_rx_cnt = loopback_rx_cnt;
1768 }
1769 printf("Received %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size);
1770
1771 return BCME_OK;
1772 } /* dbus_usbos_loopback_tx */
1773
1774 /**
1775 * Higher layer (dbus_usb.c) wants to transmit an I/O Request Block
1776 * @param[in] txirb txirb->pkt, if non-zero, contains a single or a chain of packets
1777 */
1778 static int
dbus_usbos_intf_send_irb(void * bus,dbus_irb_tx_t * txirb)1779 dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb)
1780 {
1781 usbos_info_t *usbos_info = (usbos_info_t *) bus;
1782 urb_req_t *req, *req_zlp = NULL;
1783 int ret = DBUS_OK;
1784 unsigned long flags;
1785 void *pkt;
1786 uint32 buffer_length;
1787 uint8 *buf;
1788
1789 if ((usbos_info == NULL) || !usbos_info->tx_pipe) {
1790 return DBUS_ERR;
1791 }
1792
1793 if (txirb->pkt != NULL) {
1794 buffer_length = pkttotlen(usbos_info->pub->osh, txirb->pkt);
1795 /* In case of multiple packets the values below may be overwritten */
1796 txirb->send_buf = NULL;
1797 buf = PKTDATA(usbos_info->pub->osh, txirb->pkt);
1798 } else { /* txirb->buf != NULL */
1799 ASSERT(txirb->buf != NULL);
1800 ASSERT(txirb->send_buf == NULL);
1801 buffer_length = txirb->len;
1802 buf = txirb->buf;
1803 }
1804
1805 if (!(req = dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) {
1806 DBUSERR(("%s No free URB!\n", __FUNCTION__));
1807 return DBUS_ERR_TXDROP;
1808 }
1809
1810 /* If not using standard Linux kernel functionality for handling Zero Length Packet(ZLP),
1811 * the dbus needs to generate ZLP when length is multiple of MaxPacketSize.
1812 */
1813 #ifndef WL_URB_ZPKT
1814 if (!(buffer_length % usbos_info->maxps)) {
1815 if (!(req_zlp =
1816 dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) {
1817 DBUSERR(("%s No free URB for ZLP!\n", __FUNCTION__));
1818 dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
1819 return DBUS_ERR_TXDROP;
1820 }
1821
1822 /* No txirb, so that dbus_usbos_send_complete can differentiate between
1823 * DATA and ZLP.
1824 */
1825 req_zlp->arg = NULL;
1826 req_zlp->usbinfo = usbos_info;
1827 req_zlp->buf_len = 0;
1828
1829 usb_fill_bulk_urb(req_zlp->urb, usbos_info->usb, usbos_info->tx_pipe, NULL,
1830 0, (usb_complete_t)dbus_usbos_send_complete, req_zlp);
1831
1832 req_zlp->urb->transfer_flags |= URB_QUEUE_BULK;
1833 }
1834 #endif /* !WL_URB_ZPKT */
1835
1836 #ifndef USBOS_TX_THREAD
1837 /* Disable USB autosuspend until this request completes, request USB resume if needed.
1838 * Because this call runs asynchronously, there is no guarantee the bus is resumed before
1839 * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid
1840 * this.
1841 */
1842 USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf);
1843 #endif /* !USBOS_TX_THREAD */
1844
1845 spin_lock_irqsave(&usbos_info->txlock, flags);
1846
1847 req->arg = txirb;
1848 req->usbinfo = usbos_info;
1849 req->buf_len = 0;
1850
1851 /* Prepare the URB */
1852 if (txirb->pkt != NULL) {
1853 uint32 pktlen;
1854 uint8 *transfer_buf;
1855
1856 /* For multiple packets, allocate contiguous buffer and copy packet data to it */
1857 if (PKTNEXT(usbos_info->pub->osh, txirb->pkt)) {
1858 transfer_buf = MALLOC(usbos_info->pub->osh, buffer_length);
1859 if (!transfer_buf) {
1860 ret = DBUS_ERR_TXDROP;
1861 DBUSERR(("fail to alloc to usb buffer\n"));
1862 goto fail;
1863 }
1864
1865 pkt = txirb->pkt;
1866 txirb->send_buf = transfer_buf;
1867 req->buf_len = buffer_length;
1868
1869 while (pkt) {
1870 pktlen = PKTLEN(usbos_info->pub->osh, pkt);
1871 bcopy(PKTDATA(usbos_info->pub->osh, pkt), transfer_buf, pktlen);
1872 transfer_buf += pktlen;
1873 pkt = PKTNEXT(usbos_info->pub->osh, pkt);
1874 }
1875
1876 ASSERT(((uint8 *) txirb->send_buf + buffer_length) == transfer_buf);
1877
1878 /* Overwrite buf pointer with pointer to allocated contiguous transfer_buf
1879 */
1880 buf = txirb->send_buf;
1881 }
1882 }
1883
1884 usb_fill_bulk_urb(req->urb, usbos_info->usb, usbos_info->tx_pipe, buf,
1885 buffer_length, (usb_complete_t)dbus_usbos_send_complete, req);
1886
1887 req->urb->transfer_flags |= URB_QUEUE_BULK;
1888
1889 #ifdef USBOS_TX_THREAD
1890 /* Enqueue TX request, the TX thread will resume the bus if needed and submit
1891 * it asynchronously
1892 */
1893 dbus_usbos_qenq(&usbos_info->usbos_tx_list, req, &usbos_info->usbos_tx_list_lock);
1894 if (req_zlp != NULL) {
1895 dbus_usbos_qenq(&usbos_info->usbos_tx_list, req_zlp,
1896 &usbos_info->usbos_tx_list_lock);
1897 }
1898 spin_unlock_irqrestore(&usbos_info->txlock, flags);
1899
1900 wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
1901 return DBUS_OK;
1902 #else
1903 if ((ret = USB_SUBMIT_URB(req->urb))) {
1904 ret = DBUS_ERR_TXDROP;
1905 goto fail;
1906 }
1907
1908 dbus_usbos_qenq(&usbos_info->req_txpostedq, req, &usbos_info->txposted_lock);
1909 atomic_inc(&usbos_info->txposted);
1910
1911 if (req_zlp != NULL) {
1912 if ((ret = USB_SUBMIT_URB(req_zlp->urb))) {
1913 DBUSERR(("failed to submit ZLP URB!\n"));
1914 ASSERT(0);
1915 ret = DBUS_ERR_TXDROP;
1916 goto fail2;
1917 }
1918
1919 dbus_usbos_qenq(&usbos_info->req_txpostedq, req_zlp, &usbos_info->txposted_lock);
1920 /* Also increment txposted for zlp packet, as it will be decremented in
1921 * dbus_usbos_send_complete()
1922 */
1923 atomic_inc(&usbos_info->txposted);
1924 }
1925
1926 spin_unlock_irqrestore(&usbos_info->txlock, flags);
1927 return DBUS_OK;
1928 #endif /* USBOS_TX_THREAD */
1929
1930 fail:
1931 if (txirb->send_buf != NULL) {
1932 MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len);
1933 txirb->send_buf = NULL;
1934 req->buf_len = 0;
1935 }
1936 dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
1937 #ifndef USBOS_TX_THREAD
1938 fail2:
1939 #endif
1940 if (req_zlp != NULL) {
1941 dbus_usbos_qenq(&usbos_info->req_txfreeq, req_zlp, &usbos_info->txfree_lock);
1942 }
1943
1944 spin_unlock_irqrestore(&usbos_info->txlock, flags);
1945
1946 #ifndef USBOS_TX_THREAD
1947 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
1948 #endif /* !USBOS_TX_THREAD */
1949
1950 return ret;
1951 } /* dbus_usbos_intf_send_irb */
1952
1953 /** Higher layer (dbus_usb.c) recycles a received (and used) packet. */
1954 static int
dbus_usbos_intf_recv_irb(void * bus,dbus_irb_rx_t * rxirb)1955 dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb)
1956 {
1957 usbos_info_t *usbos_info = (usbos_info_t *) bus;
1958 int ret = DBUS_OK;
1959
1960 if (usbos_info == NULL)
1961 return DBUS_ERR;
1962
1963 ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, 0);
1964 return ret;
1965 }
1966
1967 static int
dbus_usbos_intf_recv_irb_from_ep(void * bus,dbus_irb_rx_t * rxirb,uint32 ep_idx)1968 dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx)
1969 {
1970 usbos_info_t *usbos_info = (usbos_info_t *) bus;
1971 int ret = DBUS_OK;
1972
1973 if (usbos_info == NULL)
1974 return DBUS_ERR;
1975
1976 #ifdef INTR_EP_ENABLE
1977 /* By specifying the ep_idx value of 0xff, the cdc layer is asking to
1978 * submit an interrupt URB
1979 */
1980 if (rxirb == NULL && ep_idx == 0xff) {
1981 /* submit intr URB */
1982 if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb)) < 0) {
1983 DBUSERR(("%s intr USB_SUBMIT_URB failed, status %d\n",
1984 __FUNCTION__, ret));
1985 }
1986 return ret;
1987 }
1988 #else
1989 if (rxirb == NULL) {
1990 return DBUS_ERR;
1991 }
1992 #endif /* INTR_EP_ENABLE */
1993
1994 ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, ep_idx);
1995 return ret;
1996 }
1997
1998 /** Higher layer (dbus_usb.c) want to cancel an IRB */
1999 static int
dbus_usbos_intf_cancel_irb(void * bus,dbus_irb_tx_t * txirb)2000 dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb)
2001 {
2002 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2003
2004 if (usbos_info == NULL)
2005 return DBUS_ERR;
2006
2007 return DBUS_ERR;
2008 }
2009
2010 /** Only one CTL transfer can be pending at any time. This function may block. */
2011 static int
dbus_usbos_intf_send_ctl(void * bus,uint8 * buf,int len)2012 dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len)
2013 {
2014 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2015 uint16 size;
2016 #ifndef USBOS_TX_THREAD
2017 int status;
2018 #endif /* USBOS_TX_THREAD */
2019
2020 if ((usbos_info == NULL) || (buf == NULL) || (len == 0))
2021 return DBUS_ERR;
2022
2023 if (usbos_info->ctl_urb == NULL)
2024 return DBUS_ERR;
2025
2026 /* Block until a pending CTL transfer has completed */
2027 if (down_interruptible(&usbos_info->ctl_lock) != 0) {
2028 return DBUS_ERR_TXCTLFAIL;
2029 }
2030
2031 #ifdef USBOS_TX_THREAD
2032 ASSERT(usbos_info->ctl_state == USBOS_REQUEST_STATE_UNSCHEDULED);
2033 #else
2034 /* Disable USB autosuspend until this request completes, request USB resume if needed.
2035 * Because this call runs asynchronously, there is no guarantee the bus is resumed before
2036 * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid
2037 * this.
2038 */
2039 USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf);
2040 #endif /* USBOS_TX_THREAD */
2041
2042 size = len;
2043 usbos_info->ctl_write.wLength = cpu_to_le16p(&size);
2044 usbos_info->ctl_urb->transfer_buffer_length = size;
2045
2046 usb_fill_control_urb(usbos_info->ctl_urb,
2047 usbos_info->usb,
2048 usb_sndctrlpipe(usbos_info->usb, 0),
2049 (unsigned char *) &usbos_info->ctl_write,
2050 buf, size, (usb_complete_t)dbus_usbos_ctlwrite_complete, usbos_info);
2051
2052 #ifdef USBOS_TX_THREAD
2053 /* Enqueue CTRL request for transmission by the TX thread. The
2054 * USB bus will first be resumed if needed.
2055 */
2056 usbos_info->ctl_state = USBOS_REQUEST_STATE_SCHEDULED;
2057 wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
2058 #else
2059 status = USB_SUBMIT_URB(usbos_info->ctl_urb);
2060 if (status < 0) {
2061 DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status));
2062 up(&usbos_info->ctl_lock);
2063
2064 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
2065
2066 return DBUS_ERR_TXCTLFAIL;
2067 }
2068 #endif /* USBOS_TX_THREAD */
2069
2070 return DBUS_OK;
2071 } /* dbus_usbos_intf_send_ctl */
2072
2073 /** This function does not seem to be called by anyone, including dbus_usb.c */
2074 static int
dbus_usbos_intf_recv_ctl(void * bus,uint8 * buf,int len)2075 dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len)
2076 {
2077 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2078 int status;
2079 uint16 size;
2080
2081 if ((usbos_info == NULL) || (buf == NULL) || (len == 0))
2082 return DBUS_ERR;
2083
2084 if (usbos_info->ctl_urb == NULL)
2085 return DBUS_ERR;
2086
2087 /* Block until a pending CTRL transfer has completed */
2088 if (down_interruptible(&usbos_info->ctl_lock) != 0) {
2089 return DBUS_ERR_TXCTLFAIL;
2090 }
2091
2092 /* Disable USB autosuspend until this request completes, request USB resume if needed. */
2093 USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf);
2094
2095 size = len;
2096 usbos_info->ctl_read.wLength = cpu_to_le16p(&size);
2097 usbos_info->ctl_urb->transfer_buffer_length = size;
2098
2099 if (usbos_info->rxctl_deferrespok) {
2100 /* BMAC model */
2101 usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR |
2102 USB_RECIP_INTERFACE;
2103 usbos_info->ctl_read.bRequest = DL_DEFER_RESP_OK;
2104 } else {
2105 /* full dongle model */
2106 usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS |
2107 USB_RECIP_INTERFACE;
2108 usbos_info->ctl_read.bRequest = 1;
2109 }
2110
2111 usb_fill_control_urb(usbos_info->ctl_urb,
2112 usbos_info->usb,
2113 usb_rcvctrlpipe(usbos_info->usb, 0),
2114 (unsigned char *) &usbos_info->ctl_read,
2115 buf, size, (usb_complete_t)dbus_usbos_ctlread_complete, usbos_info);
2116
2117 status = USB_SUBMIT_URB(usbos_info->ctl_urb);
2118 if (status < 0) {
2119 DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status));
2120 up(&usbos_info->ctl_lock);
2121
2122 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
2123
2124 return DBUS_ERR_RXCTLFAIL;
2125 }
2126
2127 return DBUS_OK;
2128 }
2129
2130 static int
dbus_usbos_intf_get_attrib(void * bus,dbus_attrib_t * attrib)2131 dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib)
2132 {
2133 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2134
2135 if ((usbos_info == NULL) || (attrib == NULL))
2136 return DBUS_ERR;
2137
2138 attrib->bustype = DBUS_USB;
2139 attrib->vid = g_probe_info.vid;
2140 attrib->pid = g_probe_info.pid;
2141 attrib->devid = 0x4322;
2142
2143 attrib->nchan = 1;
2144
2145 /* MaxPacketSize for USB hi-speed bulk out is 512 bytes
2146 * and 64-bytes for full-speed.
2147 * When sending pkt > MaxPacketSize, Host SW breaks it
2148 * up into multiple packets.
2149 */
2150 attrib->mtu = usbos_info->maxps;
2151
2152 return DBUS_OK;
2153 }
2154
2155 /** Called by higher layer (dbus_usb.c) when it wants to 'up' the USB interface to the dongle */
2156 static int
dbus_usbos_intf_up(void * bus)2157 dbus_usbos_intf_up(void *bus)
2158 {
2159 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2160 uint16 ifnum;
2161 #ifdef BCMUSBDEV_COMPOSITE
2162 int wlan_if = 0;
2163 #endif
2164 if (usbos_info == NULL)
2165 return DBUS_ERR;
2166
2167 if (usbos_info->usb == NULL)
2168 return DBUS_ERR;
2169
2170 #if defined(INTR_EP_ENABLE)
2171 /* full dongle use intr EP, bmac doesn't use it */
2172 if (usbos_info->intr_urb) {
2173 int ret;
2174
2175 usb_fill_int_urb(usbos_info->intr_urb, usbos_info->usb,
2176 usbos_info->intr_pipe, &usbos_info->intr,
2177 usbos_info->intr_size, (usb_complete_t)dbus_usbos_intr_complete,
2178 usbos_info, usbos_info->interval);
2179
2180 if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb))) {
2181 DBUSERR(("%s USB_SUBMIT_URB failed with status %d\n", __FUNCTION__, ret));
2182 return DBUS_ERR;
2183 }
2184 }
2185 #endif
2186
2187 if (usbos_info->ctl_urb) {
2188 usbos_info->ctl_in_pipe = usb_rcvctrlpipe(usbos_info->usb, 0);
2189 usbos_info->ctl_out_pipe = usb_sndctrlpipe(usbos_info->usb, 0);
2190
2191 #ifdef BCMUSBDEV_COMPOSITE
2192 wlan_if = dbus_usbos_intf_wlan(usbos_info->usb);
2193 ifnum = cpu_to_le16(IFDESC(usbos_info->usb, wlan_if).bInterfaceNumber);
2194 #else
2195 ifnum = cpu_to_le16(IFDESC(usbos_info->usb, CONTROL_IF).bInterfaceNumber);
2196 #endif /* BCMUSBDEV_COMPOSITE */
2197 /* CTL Write */
2198 usbos_info->ctl_write.bRequestType =
2199 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
2200 usbos_info->ctl_write.bRequest = 0;
2201 usbos_info->ctl_write.wValue = cpu_to_le16(0);
2202 usbos_info->ctl_write.wIndex = cpu_to_le16p(&ifnum);
2203
2204 /* CTL Read */
2205 usbos_info->ctl_read.bRequestType =
2206 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
2207 usbos_info->ctl_read.bRequest = 1;
2208 usbos_info->ctl_read.wValue = cpu_to_le16(0);
2209 usbos_info->ctl_read.wIndex = cpu_to_le16p(&ifnum);
2210 }
2211
2212 /* Success, indicate usbos_info is fully up */
2213 dbus_usbos_state_change(usbos_info, DBUS_STATE_UP);
2214
2215 return DBUS_OK;
2216 } /* dbus_usbos_intf_up */
2217
2218 static int
dbus_usbos_intf_down(void * bus)2219 dbus_usbos_intf_down(void *bus)
2220 {
2221 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2222
2223 if (usbos_info == NULL)
2224 return DBUS_ERR;
2225
2226 dbusos_stop(usbos_info);
2227 return DBUS_OK;
2228 }
2229
2230 static int
dbus_usbos_intf_stop(void * bus)2231 dbus_usbos_intf_stop(void *bus)
2232 {
2233 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2234
2235 if (usbos_info == NULL)
2236 return DBUS_ERR;
2237
2238 dbusos_stop(usbos_info);
2239 return DBUS_OK;
2240 }
2241
2242
2243 /** Called by higher layer (dbus_usb.c) */
2244 static int
dbus_usbos_intf_set_config(void * bus,dbus_config_t * config)2245 dbus_usbos_intf_set_config(void *bus, dbus_config_t *config)
2246 {
2247 int err = DBUS_ERR;
2248 usbos_info_t* usbos_info = bus;
2249
2250 if (config->config_id == DBUS_CONFIG_ID_RXCTL_DEFERRES) {
2251 usbos_info->rxctl_deferrespok = config->rxctl_deferrespok;
2252 err = DBUS_OK;
2253 } else if (config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) {
2254 /* DBUS_CONFIG_ID_AGGR_LIMIT shouldn't be called after probe stage */
2255 ASSERT(disc_arg == NULL);
2256 ASSERT(config->aggr_param.maxrxsf > 0);
2257 ASSERT(config->aggr_param.maxrxsize > 0);
2258 if (config->aggr_param.maxrxsize > usbos_info->rxbuf_len) {
2259 int state = usbos_info->pub->busstate;
2260 dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock);
2261 while (atomic_read(&usbos_info->rxposted)) {
2262 DBUSTRACE(("%s rxposted is %d, delay 1 ms\n", __FUNCTION__,
2263 atomic_read(&usbos_info->rxposted)));
2264 dbus_usbos_wait(usbos_info, 1);
2265 }
2266 usbos_info->rxbuf_len = config->aggr_param.maxrxsize;
2267 dbus_usbos_state_change(usbos_info, state);
2268 }
2269 err = DBUS_OK;
2270 }
2271
2272 return err;
2273 }
2274
2275
2276 /** Called by dbus_usb.c when it wants to download firmware into the dongle */
2277 bool
dbus_usbos_dl_cmd(usbos_info_t * usbinfo,uint8 cmd,void * buffer,int buflen)2278 dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen)
2279 {
2280 int transferred;
2281 int index = 0;
2282 char *tmpbuf;
2283
2284 if ((usbinfo == NULL) || (buffer == NULL) || (buflen == 0))
2285 return FALSE;
2286
2287 tmpbuf = (char *) MALLOC(usbinfo->pub->osh, buflen);
2288 if (!tmpbuf) {
2289 DBUSERR(("%s: Unable to allocate memory \n", __FUNCTION__));
2290 return FALSE;
2291 }
2292
2293 #ifdef BCM_REQUEST_FW
2294 if (cmd == DL_GO) {
2295 index = 1;
2296 }
2297 #endif
2298
2299 /* Disable USB autosuspend until this request completes, request USB resume if needed. */
2300 USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
2301
2302 transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0),
2303 cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
2304 0, index,
2305 (void*) tmpbuf, buflen, USB_CTRL_EP_TIMEOUT);
2306 if (transferred == buflen) {
2307 memcpy(buffer, tmpbuf, buflen);
2308 } else {
2309 DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred));
2310 }
2311
2312 USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
2313
2314 MFREE(usbinfo->pub->osh, tmpbuf, buflen);
2315 return (transferred == buflen);
2316 }
2317
2318 /**
2319 * Called by dbus_usb.c when it wants to download a buffer into the dongle (e.g. as part of the
2320 * download process, when writing nvram variables).
2321 */
2322 int
dbus_write_membytes(usbos_info_t * usbinfo,bool set,uint32 address,uint8 * data,uint size)2323 dbus_write_membytes(usbos_info_t* usbinfo, bool set, uint32 address, uint8 *data, uint size)
2324 {
2325 hwacc_t hwacc;
2326 int write_bytes = 4;
2327 int status;
2328 int retval = 0;
2329
2330 DBUSTRACE(("Enter:%s\n", __FUNCTION__));
2331
2332 /* Read is not supported */
2333 if (set == 0) {
2334 DBUSERR(("Currently read is not supported!!\n"));
2335 return -1;
2336 }
2337
2338 USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
2339
2340 hwacc.cmd = DL_CMD_WRHW;
2341 hwacc.addr = address;
2342
2343 DBUSTRACE(("Address:%x size:%d", hwacc.addr, size));
2344 do {
2345 if (size >= 4) {
2346 write_bytes = 4;
2347 } else if (size >= 2) {
2348 write_bytes = 2;
2349 } else {
2350 write_bytes = 1;
2351 }
2352
2353 hwacc.len = write_bytes;
2354
2355 while (size >= write_bytes) {
2356 hwacc.data = *((unsigned int*)data);
2357
2358 status = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0),
2359 DL_WRHW, (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
2360 1, 0, (char *)&hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT);
2361
2362 if (status < 0) {
2363 retval = -1;
2364 DBUSERR((" Ctrl write hwacc failed w/status %d @ address:%x \n",
2365 status, hwacc.addr));
2366 goto err;
2367 }
2368
2369 hwacc.addr += write_bytes;
2370 data += write_bytes;
2371 size -= write_bytes;
2372 }
2373 } while (size > 0);
2374
2375 err:
2376 USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
2377
2378 return retval;
2379 }
2380
2381 int
dbus_usbos_readreg(void * bus,uint32 regaddr,int datalen,uint32 * value)2382 dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value)
2383 {
2384 usbos_info_t *usbinfo = (usbos_info_t *) bus;
2385 int ret = DBUS_OK;
2386 int transferred;
2387 uint32 cmd;
2388 hwacc_t hwacc;
2389
2390 if (usbinfo == NULL)
2391 return DBUS_ERR;
2392
2393 if (datalen == 1)
2394 cmd = DL_RDHW8;
2395 else if (datalen == 2)
2396 cmd = DL_RDHW16;
2397 else
2398 cmd = DL_RDHW32;
2399
2400 USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
2401
2402 transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0),
2403 cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
2404 (uint16)(regaddr), (uint16)(regaddr >> 16),
2405 (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT);
2406
2407 if (transferred >= sizeof(hwacc_t)) {
2408 *value = hwacc.data;
2409 } else {
2410 DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred));
2411 ret = DBUS_ERR;
2412 }
2413
2414 USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
2415
2416 return ret;
2417 }
2418
2419 int
dbus_usbos_writereg(void * bus,uint32 regaddr,int datalen,uint32 data)2420 dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data)
2421 {
2422 usbos_info_t *usbinfo = (usbos_info_t *) bus;
2423 int ret = DBUS_OK;
2424 int transferred;
2425 uint32 cmd = DL_WRHW;
2426 hwacc_t hwacc;
2427
2428 if (usbinfo == NULL)
2429 return DBUS_ERR;
2430
2431 USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
2432
2433 hwacc.cmd = DL_WRHW;
2434 hwacc.addr = regaddr;
2435 hwacc.data = data;
2436 hwacc.len = datalen;
2437
2438 transferred = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0),
2439 cmd, (USB_DIR_OUT| USB_TYPE_VENDOR | USB_RECIP_INTERFACE),
2440 1, 0,
2441 (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT);
2442
2443 if (transferred != sizeof(hwacc_t)) {
2444 DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred));
2445 ret = DBUS_ERR;
2446 }
2447
2448 USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
2449
2450 return ret;
2451 }
2452
2453 int
dbus_usbos_wait(usbos_info_t * usbinfo,uint16 ms)2454 dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms)
2455 {
2456 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
2457 if (in_interrupt())
2458 mdelay(ms);
2459 else
2460 msleep_interruptible(ms);
2461 #else
2462 wait_ms(ms);
2463 #endif
2464 return DBUS_OK;
2465 }
2466
2467 /** Called by dbus_usb.c as part of the firmware download process */
2468 bool
dbus_usbos_dl_send_bulk(usbos_info_t * usbinfo,void * buffer,int len)2469 dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len)
2470 {
2471 bool ret = TRUE;
2472 int status;
2473 int transferred = 0;
2474
2475 if (usbinfo == NULL)
2476 return DBUS_ERR;
2477
2478 USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
2479
2480 status = USB_BULK_MSG(usbinfo->usb, usbinfo->tx_pipe,
2481 buffer, len,
2482 &transferred, USB_BULK_EP_TIMEOUT);
2483
2484 if (status < 0) {
2485 DBUSERR(("%s: usb_bulk_msg failed %d\n", __FUNCTION__, status));
2486 ret = FALSE;
2487 }
2488
2489 USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf);
2490
2491 return ret;
2492 }
2493
2494 static bool
dbus_usbos_intf_recv_needed(void * bus)2495 dbus_usbos_intf_recv_needed(void *bus)
2496 {
2497 return FALSE;
2498 }
2499
2500 /**
2501 * Higher layer (dbus_usb.c) wants to execute a function on the condition that the rx spin lock has
2502 * been acquired.
2503 */
2504 static void*
dbus_usbos_intf_exec_rxlock(void * bus,exec_cb_t cb,struct exec_parms * args)2505 dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args)
2506 {
2507 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2508 void *ret;
2509 unsigned long flags;
2510
2511 if (usbos_info == NULL)
2512 return NULL;
2513
2514 spin_lock_irqsave(&usbos_info->rxlock, flags);
2515 ret = cb(args);
2516 spin_unlock_irqrestore(&usbos_info->rxlock, flags);
2517
2518 return ret;
2519 }
2520
2521 static void*
dbus_usbos_intf_exec_txlock(void * bus,exec_cb_t cb,struct exec_parms * args)2522 dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args)
2523 {
2524 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2525 void *ret;
2526 unsigned long flags;
2527
2528 if (usbos_info == NULL)
2529 return NULL;
2530
2531 spin_lock_irqsave(&usbos_info->txlock, flags);
2532 ret = cb(args);
2533 spin_unlock_irqrestore(&usbos_info->txlock, flags);
2534
2535 return ret;
2536 }
2537
2538 /**
2539 * if an error condition was detected in this module, the higher DBUS layer (dbus_usb.c) has to
2540 * be notified.
2541 */
2542 int
dbus_usbos_errhandler(void * bus,int err)2543 dbus_usbos_errhandler(void *bus, int err)
2544 {
2545 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2546
2547 if (usbos_info == NULL)
2548 return DBUS_ERR;
2549
2550 if (usbos_info->cbarg && usbos_info->cbs) {
2551 if (usbos_info->cbs->errhandler)
2552 usbos_info->cbs->errhandler(usbos_info->cbarg, err);
2553 }
2554
2555 return DBUS_OK;
2556 }
2557
2558 /**
2559 * if a change in bus state was detected in this module, the higher DBUS layer (dbus_usb.c) has to
2560 * be notified.
2561 */
2562 int
dbus_usbos_state_change(void * bus,int state)2563 dbus_usbos_state_change(void *bus, int state)
2564 {
2565 usbos_info_t *usbos_info = (usbos_info_t *) bus;
2566
2567 if (usbos_info == NULL)
2568 return DBUS_ERR;
2569
2570 if (usbos_info->cbarg && usbos_info->cbs) {
2571 if (usbos_info->cbs->state_change)
2572 usbos_info->cbs->state_change(usbos_info->cbarg, state);
2573 }
2574
2575 usbos_info->pub->busstate = state;
2576 return DBUS_OK;
2577 }
2578
2579 int
dbus_bus_osl_register(dbus_driver_t * driver,dbus_intf_t ** intf)2580 dbus_bus_osl_register(dbus_driver_t *driver, dbus_intf_t **intf)
2581 {
2582 bzero(&g_probe_info, sizeof(probe_info_t));
2583
2584 drvinfo = *driver;
2585 *intf = &dbus_usbos_intf;
2586
2587 USB_REGISTER();
2588
2589 return DBUS_ERR_NODEVICE;
2590 }
2591
2592 int
dbus_bus_osl_deregister()2593 dbus_bus_osl_deregister()
2594 {
2595 g_probe_info.dereged = TRUE;
2596
2597 DHD_MUTEX_LOCK();
2598 if (drvinfo.remove && disc_arg && (g_probe_info.disc_cb_done == FALSE)) {
2599 drvinfo.remove(disc_arg);
2600 disc_arg = NULL;
2601 }
2602 DHD_MUTEX_UNLOCK();
2603
2604 USB_DEREGISTER();
2605
2606 return DBUS_OK;
2607 }
2608
2609 void *
dbus_usbos_intf_attach(dbus_pub_t * pub,void * cbarg,dbus_intf_callbacks_t * cbs)2610 dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs)
2611 {
2612 usbos_info_t *usbos_info;
2613
2614 if (g_probe_info.dldone == FALSE) {
2615 DBUSERR(("%s: err device not downloaded!\n", __FUNCTION__));
2616 return NULL;
2617 }
2618
2619 /* Sanity check for BUS_INFO() */
2620 ASSERT(OFFSETOF(usbos_info_t, pub) == 0);
2621
2622 usbos_info = MALLOC(pub->osh, sizeof(usbos_info_t));
2623 if (usbos_info == NULL)
2624 return NULL;
2625
2626 bzero(usbos_info, sizeof(usbos_info_t));
2627
2628 usbos_info->pub = pub;
2629 usbos_info->cbarg = cbarg;
2630 usbos_info->cbs = cbs;
2631
2632 /* Needed for disconnect() */
2633 g_probe_info.usbos_info = usbos_info;
2634
2635 /* Update USB Info */
2636 usbos_info->usb = g_probe_info.usb;
2637 usbos_info->rx_pipe = g_probe_info.rx_pipe;
2638 usbos_info->rx_pipe2 = g_probe_info.rx_pipe2;
2639 usbos_info->tx_pipe = g_probe_info.tx_pipe;
2640 usbos_info->intr_pipe = g_probe_info.intr_pipe;
2641 usbos_info->intr_size = g_probe_info.intr_size;
2642 usbos_info->interval = g_probe_info.interval;
2643 usbos_info->pub->device_speed = g_probe_info.device_speed;
2644 if (usbos_info->rx_pipe2) {
2645 usbos_info->pub->attrib.has_2nd_bulk_in_ep = 1;
2646 } else {
2647 usbos_info->pub->attrib.has_2nd_bulk_in_ep = 0;
2648 }
2649
2650 if (usbos_info->tx_pipe)
2651 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0))
2652 usbos_info->maxps = usb_maxpacket(usbos_info->usb,
2653 usbos_info->tx_pipe);
2654 #else
2655 usbos_info->maxps = usb_maxpacket(usbos_info->usb,
2656 usbos_info->tx_pipe, usb_pipeout(usbos_info->tx_pipe));
2657 #endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)) */
2658
2659 INIT_LIST_HEAD(&usbos_info->req_rxfreeq);
2660 INIT_LIST_HEAD(&usbos_info->req_txfreeq);
2661 INIT_LIST_HEAD(&usbos_info->req_rxpostedq);
2662 INIT_LIST_HEAD(&usbos_info->req_txpostedq);
2663 spin_lock_init(&usbos_info->rxfree_lock);
2664 spin_lock_init(&usbos_info->txfree_lock);
2665 spin_lock_init(&usbos_info->rxposted_lock);
2666 spin_lock_init(&usbos_info->txposted_lock);
2667 spin_lock_init(&usbos_info->rxlock);
2668 spin_lock_init(&usbos_info->txlock);
2669
2670 atomic_set(&usbos_info->rxposted, 0);
2671 atomic_set(&usbos_info->txposted, 0);
2672
2673
2674 #ifdef USB_DISABLE_INT_EP
2675 usbos_info->intr_urb = NULL;
2676 #else
2677 if (!(usbos_info->intr_urb = USB_ALLOC_URB())) {
2678 DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__));
2679 goto fail;
2680 }
2681 #endif
2682
2683 if (!(usbos_info->ctl_urb = USB_ALLOC_URB())) {
2684 DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__));
2685 goto fail;
2686 }
2687
2688 init_waitqueue_head(&usbos_info->wait);
2689
2690 if (!(usbos_info->blk_urb = USB_ALLOC_URB())) { /* for embedded image downloading */
2691 DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__));
2692 goto fail;
2693 }
2694
2695 usbos_info->rxbuf_len = (uint)usbos_info->pub->rxsize;
2696
2697
2698
2699 atomic_set(&usbos_info->txallocated, 0);
2700 if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info,
2701 usbos_info->pub->ntxq, FALSE)) {
2702 goto fail;
2703 }
2704
2705 atomic_set(&usbos_info->rxallocated, 0);
2706 if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info,
2707 MIN(DBUS_USB_RXQUEUE_BATCH_ADD, usbos_info->pub->nrxq),
2708 TRUE)) {
2709 goto fail;
2710 }
2711
2712 sema_init(&usbos_info->ctl_lock, 1);
2713
2714 #ifdef USBOS_THREAD
2715 if (dbus_usbos_thread_init(usbos_info) == NULL)
2716 goto fail;
2717 #endif /* USBOS_THREAD */
2718
2719 #ifdef USBOS_TX_THREAD
2720 if (dbus_usbos_tx_thread_init(usbos_info) == NULL)
2721 goto fail;
2722 #endif /* USBOS_TX_THREAD */
2723
2724 pub->dev_info = g_probe_info.usb;
2725
2726
2727 return (void *) usbos_info;
2728 fail:
2729 if (usbos_info->intr_urb) {
2730 USB_FREE_URB(usbos_info->intr_urb);
2731 usbos_info->intr_urb = NULL;
2732 }
2733
2734 if (usbos_info->ctl_urb) {
2735 USB_FREE_URB(usbos_info->ctl_urb);
2736 usbos_info->ctl_urb = NULL;
2737 }
2738
2739 #if defined(BCM_REQUEST_FW)
2740 if (usbos_info->blk_urb) {
2741 USB_FREE_URB(usbos_info->blk_urb);
2742 usbos_info->blk_urb = NULL;
2743 }
2744 #endif
2745
2746 dbus_usbos_urbreqs_free(usbos_info, TRUE);
2747 atomic_set(&usbos_info->rxallocated, 0);
2748 dbus_usbos_urbreqs_free(usbos_info, FALSE);
2749 atomic_set(&usbos_info->txallocated, 0);
2750
2751 g_probe_info.usbos_info = NULL;
2752
2753 MFREE(pub->osh, usbos_info, sizeof(usbos_info_t));
2754 return NULL;
2755 } /* dbus_usbos_intf_attach */
2756
2757 void
dbus_usbos_intf_detach(dbus_pub_t * pub,void * info)2758 dbus_usbos_intf_detach(dbus_pub_t *pub, void *info)
2759 {
2760 usbos_info_t *usbos_info = (usbos_info_t *) info;
2761 osl_t *osh = pub->osh;
2762
2763 if (usbos_info == NULL) {
2764 return;
2765 }
2766
2767 #ifdef USBOS_TX_THREAD
2768 dbus_usbos_tx_thread_deinit(usbos_info);
2769 #endif /* USBOS_TX_THREAD */
2770
2771 /* Must unlink all URBs prior to driver unload;
2772 * otherwise an URB callback can occur after driver
2773 * has been de-allocated and rmmod'd
2774 */
2775 dbusos_stop(usbos_info);
2776
2777 if (usbos_info->intr_urb) {
2778 USB_FREE_URB(usbos_info->intr_urb);
2779 usbos_info->intr_urb = NULL;
2780 }
2781
2782 if (usbos_info->ctl_urb) {
2783 USB_FREE_URB(usbos_info->ctl_urb);
2784 usbos_info->ctl_urb = NULL;
2785 }
2786
2787 if (usbos_info->blk_urb) {
2788 USB_FREE_URB(usbos_info->blk_urb);
2789 usbos_info->blk_urb = NULL;
2790 }
2791
2792 dbus_usbos_urbreqs_free(usbos_info, TRUE);
2793 atomic_set(&usbos_info->rxallocated, 0);
2794 dbus_usbos_urbreqs_free(usbos_info, FALSE);
2795 atomic_set(&usbos_info->txallocated, 0);
2796
2797 #ifdef USBOS_THREAD
2798 dbus_usbos_thread_deinit(usbos_info);
2799 #endif /* USBOS_THREAD */
2800
2801 g_probe_info.usbos_info = NULL;
2802 MFREE(osh, usbos_info, sizeof(usbos_info_t));
2803 } /* dbus_usbos_intf_detach */
2804
2805
2806 #ifdef USBOS_TX_THREAD
2807
2808 void*
dbus_usbos_tx_thread_init(usbos_info_t * usbos_info)2809 dbus_usbos_tx_thread_init(usbos_info_t *usbos_info)
2810 {
2811 spin_lock_init(&usbos_info->usbos_tx_list_lock);
2812 INIT_LIST_HEAD(&usbos_info->usbos_tx_list);
2813 init_waitqueue_head(&usbos_info->usbos_tx_queue_head);
2814
2815 usbos_info->usbos_tx_kt = kthread_create(dbus_usbos_tx_thread_func,
2816 usbos_info, "usb-tx-thread");
2817
2818 if (IS_ERR(usbos_info->usbos_tx_kt)) {
2819 DBUSERR(("Thread Creation failed\n"));
2820 return (NULL);
2821 }
2822
2823 usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
2824 wake_up_process(usbos_info->usbos_tx_kt);
2825
2826 return (usbos_info->usbos_tx_kt);
2827 }
2828
2829 void
dbus_usbos_tx_thread_deinit(usbos_info_t * usbos_info)2830 dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info)
2831 {
2832 urb_req_t *req;
2833
2834 if (usbos_info->usbos_tx_kt) {
2835 wake_up_interruptible(&usbos_info->usbos_tx_queue_head);
2836 kthread_stop(usbos_info->usbos_tx_kt);
2837 }
2838
2839 /* Move pending requests to free queue so they can be freed */
2840 while ((req = dbus_usbos_qdeq(
2841 &usbos_info->usbos_tx_list, &usbos_info->usbos_tx_list_lock)) != NULL) {
2842 dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock);
2843 }
2844 }
2845
2846 /**
2847 * Allow USB in-band resume to block by submitting CTRL and DATA URBs on a separate thread.
2848 */
2849 int
dbus_usbos_tx_thread_func(void * data)2850 dbus_usbos_tx_thread_func(void *data)
2851 {
2852 usbos_info_t *usbos_info = (usbos_info_t *)data;
2853 urb_req_t *req;
2854 dbus_irb_tx_t *txirb;
2855 int ret;
2856 unsigned long flags;
2857
2858 #ifdef WL_THREADNICE
2859 set_user_nice(current, WL_THREADNICE);
2860 #endif
2861
2862 while (1) {
2863 /* Wait until there are URBs to submit */
2864 wait_event_interruptible_timeout(
2865 usbos_info->usbos_tx_queue_head,
2866 !list_empty(&usbos_info->usbos_tx_list) ||
2867 usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED,
2868 100);
2869
2870 if (kthread_should_stop())
2871 break;
2872
2873 /* Submit CTRL URB if needed */
2874 if (usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED) {
2875
2876 /* Disable USB autosuspend until this request completes. If the
2877 * interface was suspended, this call blocks until it has been resumed.
2878 */
2879 USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
2880
2881 usbos_info->ctl_state = USBOS_REQUEST_STATE_SUBMITTED;
2882
2883 ret = USB_SUBMIT_URB(usbos_info->ctl_urb);
2884 if (ret != 0) {
2885 DBUSERR(("%s CTRL USB_SUBMIT_URB failed, status %d\n",
2886 __FUNCTION__, ret));
2887
2888 usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED;
2889 up(&usbos_info->ctl_lock);
2890
2891 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
2892 }
2893 }
2894
2895 /* Submit all available TX URBs */
2896 while ((req = dbus_usbos_qdeq(&usbos_info->usbos_tx_list,
2897 &usbos_info->usbos_tx_list_lock)) != NULL) {
2898
2899 /* Disable USB autosuspend until this request completes. If the
2900 * interface was suspended, this call blocks until it has been resumed.
2901 */
2902 USB_AUTOPM_GET_INTERFACE(g_probe_info.intf);
2903
2904 spin_lock_irqsave(&usbos_info->txlock, flags);
2905
2906 ret = USB_SUBMIT_URB(req->urb);
2907 if (ret == 0) {
2908 /* URB submitted successfully */
2909 dbus_usbos_qenq(&usbos_info->req_txpostedq, req,
2910 &usbos_info->txposted_lock);
2911 atomic_inc(&usbos_info->txposted);
2912 } else {
2913 /* Submitting the URB failed. */
2914 DBUSERR(("%s TX USB_SUBMIT_URB failed, status %d\n",
2915 __FUNCTION__, ret));
2916
2917 USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf);
2918 }
2919
2920 spin_unlock_irqrestore(&usbos_info->txlock, flags);
2921
2922 if (ret != 0) {
2923 /* Cleanup and notify higher layers */
2924 dbus_usbos_qenq(&usbos_info->req_txfreeq, req,
2925 &usbos_info->txfree_lock);
2926
2927 txirb = req->arg;
2928 if (txirb->send_buf) {
2929 MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len);
2930 txirb->send_buf = NULL;
2931 req->buf_len = 0;
2932 }
2933
2934 if (likely (usbos_info->cbarg && usbos_info->cbs)) {
2935 if (likely (usbos_info->cbs->send_irb_complete != NULL))
2936 usbos_info->cbs->send_irb_complete(
2937 usbos_info->cbarg, txirb, DBUS_ERR_TXDROP);
2938 }
2939 }
2940 }
2941 }
2942
2943 return 0;
2944 } /* dbus_usbos_tx_thread_func */
2945
2946 #endif /* USBOS_TX_THREAD */
2947
2948 #ifdef USBOS_THREAD
2949
2950 /**
2951 * Increase system performance by creating a USB thread that runs parallel to other system
2952 * activity.
2953 */
2954 static void*
dbus_usbos_thread_init(usbos_info_t * usbos_info)2955 dbus_usbos_thread_init(usbos_info_t *usbos_info)
2956 {
2957 usbos_list_entry_t *entry;
2958 unsigned long flags, ii;
2959
2960 spin_lock_init(&usbos_info->usbos_list_lock);
2961 spin_lock_init(&usbos_info->ctrl_lock);
2962 INIT_LIST_HEAD(&usbos_info->usbos_list);
2963 INIT_LIST_HEAD(&usbos_info->usbos_free_list);
2964 init_waitqueue_head(&usbos_info->usbos_queue_head);
2965 atomic_set(&usbos_info->usbos_list_cnt, 0);
2966
2967
2968 for (ii = 0; ii < (usbos_info->pub->nrxq + usbos_info->pub->ntxq); ii++) {
2969 entry = MALLOC(usbos_info->pub->osh, sizeof(usbos_list_entry_t));
2970 if (entry) {
2971 spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
2972 list_add_tail((struct list_head*) entry, &usbos_info->usbos_free_list);
2973 spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
2974 } else {
2975 DBUSERR(("Failed to create list\n"));
2976 }
2977 }
2978
2979 usbos_info->usbos_kt = kthread_create(dbus_usbos_thread_func,
2980 usbos_info, "usb-thread");
2981
2982 if (IS_ERR(usbos_info->usbos_kt)) {
2983 DBUSERR(("Thread Creation failed\n"));
2984 return (NULL);
2985 }
2986
2987 wake_up_process(usbos_info->usbos_kt);
2988
2989 return (usbos_info->usbos_kt);
2990 }
2991
2992 static void
dbus_usbos_thread_deinit(usbos_info_t * usbos_info)2993 dbus_usbos_thread_deinit(usbos_info_t *usbos_info)
2994 {
2995 struct list_head *cur, *next;
2996 usbos_list_entry_t *entry;
2997 unsigned long flags;
2998
2999 if (usbos_info->usbos_kt) {
3000 wake_up_interruptible(&usbos_info->usbos_queue_head);
3001 kthread_stop(usbos_info->usbos_kt);
3002 }
3003 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3004 #pragma GCC diagnostic push
3005 #pragma GCC diagnostic ignored "-Wcast-qual"
3006 #endif
3007 list_for_each_safe(cur, next, &usbos_info->usbos_list)
3008 {
3009 entry = list_entry(cur, struct usbos_list_entry, list);
3010 /* detach this entry from the list and then free the entry */
3011 spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
3012 list_del(cur);
3013 MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t));
3014 spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
3015 }
3016
3017 list_for_each_safe(cur, next, &usbos_info->usbos_free_list)
3018 {
3019 entry = list_entry(cur, struct usbos_list_entry, list);
3020 /* detach this entry from the list and then free the entry */
3021 spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
3022 list_del(cur);
3023 MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t));
3024 spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
3025 }
3026 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3027 #pragma GCC diagnostic pop
3028 #endif
3029 }
3030
3031 /** Process completed URBs in a worker thread */
3032 static int
dbus_usbos_thread_func(void * data)3033 dbus_usbos_thread_func(void *data)
3034 {
3035 usbos_info_t *usbos_info = (usbos_info_t *)data;
3036 usbos_list_entry_t *entry;
3037 struct list_head *cur, *next;
3038 unsigned long flags;
3039
3040 #ifdef WL_THREADNICE
3041 set_user_nice(current, WL_THREADNICE);
3042 #endif
3043
3044 while (1) {
3045 /* If the list is empty, then go to sleep */
3046 wait_event_interruptible_timeout
3047 (usbos_info->usbos_queue_head,
3048 atomic_read(&usbos_info->usbos_list_cnt) > 0,
3049 100);
3050
3051 if (kthread_should_stop())
3052 break;
3053
3054 spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
3055
3056 /* For each entry on the list, process it. Remove the entry from
3057 * the list when done.
3058 */
3059 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3060 #pragma GCC diagnostic push
3061 #pragma GCC diagnostic ignored "-Wcast-qual"
3062 #endif
3063 list_for_each_safe(cur, next, &usbos_info->usbos_list)
3064 {
3065 urb_req_t *req;
3066 int len;
3067 int stat;
3068 usbos_info_t *usbos_info_local;
3069
3070 entry = list_entry(cur, struct usbos_list_entry, list);
3071 if (entry == NULL)
3072 break;
3073
3074 req = entry->urb_context;
3075 len = entry->urb_length;
3076 stat = entry->urb_status;
3077 usbos_info_local = req->usbinfo;
3078
3079 /* detach this entry from the list and attach it to the free list */
3080 list_del_init(cur);
3081 spin_unlock_irqrestore(&usbos_info_local->usbos_list_lock, flags);
3082
3083 dbus_usbos_recv_complete_handle(req, len, stat);
3084
3085 spin_lock_irqsave(&usbos_info_local->usbos_list_lock, flags);
3086
3087 list_add_tail(cur, &usbos_info_local->usbos_free_list);
3088
3089 atomic_dec(&usbos_info_local->usbos_list_cnt);
3090 }
3091
3092 spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
3093
3094 }
3095 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3096 #pragma GCC diagnostic pop
3097 #endif
3098
3099 return 0;
3100 } /* dbus_usbos_thread_func */
3101
3102 /** Called on Linux calling URB callback, see dbus_usbos_recv_complete() */
3103 static void
dbus_usbos_dispatch_schedule(CALLBACK_ARGS)3104 dbus_usbos_dispatch_schedule(CALLBACK_ARGS)
3105 {
3106 urb_req_t *req = urb->context;
3107 usbos_info_t *usbos_info = req->usbinfo;
3108 usbos_list_entry_t *entry;
3109 unsigned long flags;
3110 struct list_head *cur;
3111
3112 spin_lock_irqsave(&usbos_info->usbos_list_lock, flags);
3113
3114 cur = usbos_info->usbos_free_list.next;
3115 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3116 #pragma GCC diagnostic push
3117 #pragma GCC diagnostic ignored "-Wcast-qual"
3118 #endif
3119 entry = list_entry(cur, struct usbos_list_entry, list);
3120 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3121 #pragma GCC diagnostic pop
3122 #endif
3123
3124 /* detach this entry from the free list and prepare it insert it to use list */
3125 list_del_init(cur);
3126
3127 if (entry) {
3128 entry->urb_context = urb->context;
3129 entry->urb_length = urb->actual_length;
3130 entry->urb_status = urb->status;
3131
3132 atomic_inc(&usbos_info->usbos_list_cnt);
3133 list_add_tail(cur, &usbos_info->usbos_list);
3134 } else {
3135 DBUSERR(("!!!!!!OUT OF MEMORY!!!!!!!\n"));
3136 }
3137
3138 spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags);
3139
3140 /* thread */
3141 wake_up_interruptible(&usbos_info->usbos_queue_head);
3142 } /* dbus_usbos_dispatch_schedule */
3143
3144 #endif /* USBOS_THREAD */
3145
3146
3147
3148
3149 #ifdef BCM_REQUEST_FW
3150
3151 struct request_fw_context {
3152 const struct firmware *firmware;
3153 struct semaphore lock;
3154 };
3155
3156 /*
3157 * Callback for dbus_request_firmware().
3158 */
3159 static void
dbus_request_firmware_done(const struct firmware * firmware,void * ctx)3160 dbus_request_firmware_done(const struct firmware *firmware, void *ctx)
3161 {
3162 struct request_fw_context *context = (struct request_fw_context*)ctx;
3163
3164 /* Store the received firmware handle in the context and wake requester */
3165 context->firmware = firmware;
3166 up(&context->lock);
3167 }
3168
3169 /*
3170 * Send a firmware request and wait for completion.
3171 *
3172 * The use of the asynchronous version of request_firmware() is needed to avoid
3173 * kernel oopses when we just come out of system hibernate.
3174 */
3175 static int
dbus_request_firmware(const char * name,const struct firmware ** firmware)3176 dbus_request_firmware(const char *name, const struct firmware **firmware)
3177 {
3178 struct request_fw_context *context;
3179 int ret;
3180
3181 context = kzalloc(sizeof(*context), GFP_KERNEL);
3182 if (!context)
3183 return -ENOMEM;
3184
3185 sema_init(&context->lock, 0);
3186
3187 ret = request_firmware_nowait(THIS_MODULE, true, name, &g_probe_info.usb->dev,
3188 GFP_KERNEL, context, dbus_request_firmware_done);
3189 if (ret) {
3190 kfree(context);
3191 return ret;
3192 }
3193
3194 /* Wait for completion */
3195 if (down_interruptible(&context->lock) != 0) {
3196 kfree(context);
3197 return -ERESTARTSYS;
3198 }
3199
3200 *firmware = context->firmware;
3201 kfree(context);
3202
3203 return *firmware != NULL ? 0 : -ENOENT;
3204 }
3205
3206 #ifndef DHD_LINUX_STD_FW_API
3207 static void *
dbus_get_fwfile(int devid,int chiprev,uint8 ** fw,int * fwlen,uint16 boardtype,uint16 boardrev,char * path)3208 dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen,
3209 uint16 boardtype, uint16 boardrev, char *path)
3210 {
3211 const struct firmware *firmware = NULL;
3212 #ifndef OEM_ANDROID
3213 s8 *device_id = NULL;
3214 s8 *chip_rev = "";
3215 #endif /* OEM_ANDROID */
3216 s8 file_name[64];
3217 int ret;
3218
3219 #ifndef OEM_ANDROID
3220 switch (devid) {
3221 case BCM4350_CHIP_ID:
3222 case BCM4354_CHIP_ID:
3223 case BCM43556_CHIP_ID:
3224 case BCM43558_CHIP_ID:
3225 case BCM43566_CHIP_ID:
3226 case BCM43568_CHIP_ID:
3227 case BCM43570_CHIP_ID:
3228 case BCM4358_CHIP_ID:
3229 device_id = "4350";
3230 break;
3231 case BCM43143_CHIP_ID:
3232 device_id = "43143";
3233 break;
3234 case BCM43234_CHIP_ID:
3235 case BCM43235_CHIP_ID:
3236 case BCM43236_CHIP_ID:
3237 device_id = "43236";
3238 break;
3239 case BCM43242_CHIP_ID:
3240 device_id = "43242";
3241 break;
3242 case BCM43238_CHIP_ID:
3243 device_id = "43238";
3244 break;
3245 case BCM43526_CHIP_ID:
3246 device_id = "43526";
3247 break;
3248 case BCM43569_CHIP_ID:
3249 device_id = "43569";
3250 switch (chiprev) {
3251 case 0:
3252 chip_rev = "a0";
3253 break;
3254 case 2:
3255 chip_rev = "a2";
3256 break;
3257 default:
3258 break;
3259 }
3260 break;
3261 default:
3262 DBUSERR(("unsupported device %x\n", devid));
3263 return NULL;
3264 }
3265
3266 /* Load firmware */
3267 snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-firmware.bin", device_id, chip_rev);
3268 #else
3269 snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH);
3270 #endif /* OEM_ANDROID */
3271
3272 ret = dbus_request_firmware(path, &firmware);
3273 if (ret) {
3274 DBUSERR(("fail to request firmware %s\n", path));
3275 return NULL;
3276 } else
3277 DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size));
3278
3279 *fwlen = firmware->size;
3280 *fw = (uint8 *)firmware->data;
3281 return (void *)firmware;
3282
3283 }
3284
3285 static void *
dbus_get_nvfile(int devid,int chiprev,uint8 ** fw,int * fwlen,uint16 boardtype,uint16 boardrev,char * path)3286 dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen,
3287 uint16 boardtype, uint16 boardrev, char *path)
3288 {
3289 const struct firmware *firmware = NULL;
3290 #ifndef OEM_ANDROID
3291 s8 *device_id = NULL;
3292 s8 *chip_rev = "";
3293 #endif /* OEM_ANDROID */
3294 s8 file_name[64];
3295 int ret;
3296
3297 #ifndef OEM_ANDROID
3298 switch (devid) {
3299 case BCM4350_CHIP_ID:
3300 case BCM4354_CHIP_ID:
3301 case BCM43556_CHIP_ID:
3302 case BCM43558_CHIP_ID:
3303 case BCM43566_CHIP_ID:
3304 case BCM43568_CHIP_ID:
3305 case BCM43570_CHIP_ID:
3306 case BCM4358_CHIP_ID:
3307 device_id = "4350";
3308 break;
3309 case BCM43143_CHIP_ID:
3310 device_id = "43143";
3311 break;
3312 case BCM43234_CHIP_ID:
3313 device_id = "43234";
3314 break;
3315 case BCM43235_CHIP_ID:
3316 device_id = "43235";
3317 break;
3318 case BCM43236_CHIP_ID:
3319 device_id = "43236";
3320 break;
3321 case BCM43238_CHIP_ID:
3322 device_id = "43238";
3323 break;
3324 case BCM43242_CHIP_ID:
3325 device_id = "43242";
3326 break;
3327 case BCM43526_CHIP_ID:
3328 device_id = "43526";
3329 break;
3330 case BCM43569_CHIP_ID:
3331 device_id = "43569";
3332 switch (chiprev) {
3333 case 0:
3334 chip_rev = "a0";
3335 break;
3336 case 2:
3337 chip_rev = "a2";
3338 break;
3339 default:
3340 break;
3341 }
3342 break;
3343 default:
3344 DBUSERR(("unsupported device %x\n", devid));
3345 return NULL;
3346 }
3347
3348 /* Load board specific nvram file */
3349 snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-%2x-%2x.nvm",
3350 device_id, chip_rev, boardtype, boardrev);
3351 #else
3352 snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH);
3353 #endif /* OEM_ANDROID */
3354
3355 ret = dbus_request_firmware(path, &firmware);
3356 if (ret) {
3357 DBUSERR(("fail to request nvram %s\n", path));
3358
3359 #ifndef OEM_ANDROID
3360 /* Load generic nvram file */
3361 snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s.nvm",
3362 device_id, chip_rev);
3363
3364 ret = dbus_request_firmware(file_name, &firmware);
3365 #endif /* OEM_ANDROID */
3366
3367 if (ret) {
3368 DBUSERR(("fail to request nvram %s\n", path));
3369 return NULL;
3370 }
3371 } else
3372 DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size));
3373
3374 *fwlen = firmware->size;
3375 *fw = (uint8 *)firmware->data;
3376 return (void *)firmware;
3377 }
3378
3379 void *
dbus_get_fw_nvfile(int devid,int chiprev,uint8 ** fw,int * fwlen,int type,uint16 boardtype,uint16 boardrev,char * path)3380 dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype,
3381 uint16 boardrev, char *path)
3382 {
3383 switch (type) {
3384 case DBUS_FIRMWARE:
3385 return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path);
3386 case DBUS_NVFILE:
3387 return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path);
3388 default:
3389 return NULL;
3390 }
3391 }
3392 #else
3393 void *
dbus_get_fw_nvfile(int devid,int chiprev,uint8 ** fw,int * fwlen,int type,uint16 boardtype,uint16 boardrev,char * path)3394 dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype,
3395 uint16 boardrev, char *path)
3396 {
3397 const struct firmware *firmware = NULL;
3398 int err = DBUS_OK;
3399
3400 err = dbus_request_firmware(path, &firmware);
3401 if (err) {
3402 DBUSERR(("fail to request firmware %s\n", path));
3403 return NULL;
3404 } else {
3405 DBUSERR(("%s: %s (%zu bytes) open success\n",
3406 __FUNCTION__, path, firmware->size));
3407 }
3408
3409 *fwlen = firmware->size;
3410 *fw = (uint8 *)firmware->data;
3411 return (void *)firmware;
3412 }
3413 #endif
3414
3415 void
dbus_release_fw_nvfile(void * firmware)3416 dbus_release_fw_nvfile(void *firmware)
3417 {
3418 release_firmware((struct firmware *)firmware);
3419 }
3420 #endif /* BCM_REQUEST_FW */
3421
3422 #ifdef BCMUSBDEV_COMPOSITE
3423 /**
3424 * For a composite device the interface order is not guaranteed, scan the device struct for the WLAN
3425 * interface.
3426 */
3427 static int
dbus_usbos_intf_wlan(struct usb_device * usb)3428 dbus_usbos_intf_wlan(struct usb_device *usb)
3429 {
3430 int i, num_of_eps, ep, intf_wlan = -1;
3431 int num_intf = CONFIGDESC(usb)->bNumInterfaces;
3432 struct usb_endpoint_descriptor *endpoint;
3433
3434 for (i = 0; i < num_intf; i++) {
3435 if (IFDESC(usb, i).bInterfaceClass != USB_CLASS_VENDOR_SPEC)
3436 continue;
3437 num_of_eps = IFDESC(usb, i).bNumEndpoints;
3438
3439 for (ep = 0; ep < num_of_eps; ep++) {
3440 endpoint = &IFEPDESC(usb, i, ep);
3441 if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
3442 USB_ENDPOINT_XFER_BULK) {
3443 intf_wlan = i;
3444 break;
3445 }
3446 }
3447 if (ep < num_of_eps)
3448 break;
3449 }
3450
3451 return intf_wlan;
3452 }
3453 #endif /* BCMUSBDEV_COMPOSITE */
3454
3455 #ifdef LINUX
dbus_get_dev(void)3456 struct device * dbus_get_dev(void)
3457 {
3458 return &g_probe_info.usb->dev;
3459 }
3460 #endif /* LINUX */
3461