]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / netgraph / bluetooth / drivers / ubt / ng_ubt.c
1 /*
2  * ng_ubt.c
3  */
4
5 /*-
6  * Copyright (c) 2001-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $Id: ng_ubt.c,v 1.16 2003/10/10 19:15:06 max Exp $
31  * $FreeBSD$
32  */
33
34 /*
35  * NOTE: ng_ubt2 driver has a split personality. On one side it is
36  * a USB device driver and on the other it is a Netgraph node. This
37  * driver will *NOT* create traditional /dev/ enties, only Netgraph 
38  * node.
39  *
40  * NOTE ON LOCKS USED: ng_ubt2 drives uses 2 locks (mutexes)
41  *
42  * 1) sc_if_mtx - lock for device's interface #0 and #1. This lock is used
43  *    by USB for any USB request going over device's interface #0 and #1,
44  *    i.e. interrupt, control, bulk and isoc. transfers.
45  * 
46  * 2) sc_ng_mtx - this lock is used to protect shared (between USB, Netgraph
47  *    and Taskqueue) data, such as outgoing mbuf queues, task flags and hook
48  *    pointer. This lock *SHOULD NOT* be grabbed for a long time. In fact,
49  *    think of it as a spin lock.
50  *
51  * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 3 different contexts.
52  *
53  * 1) USB context. This is where all the USB related stuff happens. All
54  *    callbacks run in this context. All callbacks are called (by USB) with
55  *    appropriate interface lock held. It is (generally) allowed to grab
56  *    any additional locks.
57  *
58  * 2) Netgraph context. This is where all the Netgraph related stuff happens.
59  *    Since we mark node as WRITER, the Netgraph node will be "locked" (from
60  *    Netgraph point of view). Any variable that is only modified from the
61  *    Netgraph context does not require any additonal locking. It is generally
62  *    *NOT* allowed to grab *ANY* additional locks. Whatever you do, *DO NOT*
63  *    grab any lock in the Netgraph context that could cause de-scheduling of
64  *    the Netgraph thread for significant amount of time. In fact, the only
65  *    lock that is allowed in the Netgraph context is the sc_ng_mtx lock.
66  *    Also make sure that any code that is called from the Netgraph context
67  *    follows the rule above.
68  *
69  * 3) Taskqueue context. This is where ubt_task runs. Since we are generally
70  *    NOT allowed to grab any lock that could cause de-scheduling in the
71  *    Netgraph context, and, USB requires us to grab interface lock before
72  *    doing things with transfers, it is safer to transition from the Netgraph
73  *    context to the Taskqueue context before we can call into USB subsystem.
74  *
75  * So, to put everything together, the rules are as follows.
76  *      It is OK to call from the USB context or the Taskqueue context into
77  * the Netgraph context (i.e. call NG_SEND_xxx functions). In other words
78  * it is allowed to call into the Netgraph context with locks held.
79  *      Is it *NOT* OK to call from the Netgraph context into the USB context,
80  * because USB requires us to grab interface locks, and, it is safer to
81  * avoid it. So, to make things safer we set task flags to indicate which
82  * actions we want to perform and schedule ubt_task which would run in the
83  * Taskqueue context.
84  *      Is is OK to call from the Taskqueue context into the USB context,
85  * and, ubt_task does just that (i.e. grabs appropriate interface locks
86  * before calling into USB).
87  *      Access to the outgoing queues, task flags and hook pointer is
88  * controlled by the sc_ng_mtx lock. It is an unavoidable evil. Again,
89  * sc_ng_mtx should really be a spin lock (and it is very likely to an
90  * equivalent of spin lock due to adaptive nature of FreeBSD mutexes).
91  *      All USB callbacks accept softc pointer as a private data. USB ensures
92  * that this pointer is valid.
93  */
94
95 #include <sys/stdint.h>
96 #include <sys/stddef.h>
97 #include <sys/param.h>
98 #include <sys/queue.h>
99 #include <sys/types.h>
100 #include <sys/systm.h>
101 #include <sys/kernel.h>
102 #include <sys/bus.h>
103 #include <sys/linker_set.h>
104 #include <sys/module.h>
105 #include <sys/lock.h>
106 #include <sys/mutex.h>
107 #include <sys/condvar.h>
108 #include <sys/sysctl.h>
109 #include <sys/sx.h>
110 #include <sys/unistd.h>
111 #include <sys/callout.h>
112 #include <sys/malloc.h>
113 #include <sys/priv.h>
114
115 #include "usbdevs.h"
116 #include <dev/usb/usb.h>
117 #include <dev/usb/usbdi.h>
118 #include <dev/usb/usbdi_util.h>
119
120 #define USB_DEBUG_VAR usb_debug
121 #include <dev/usb/usb_debug.h>
122 #include <dev/usb/usb_busdma.h>
123
124 #include <sys/mbuf.h>
125 #include <sys/taskqueue.h>
126
127 #include <netgraph/ng_message.h>
128 #include <netgraph/netgraph.h>
129 #include <netgraph/ng_parse.h>
130 #include <netgraph/bluetooth/include/ng_bluetooth.h>
131 #include <netgraph/bluetooth/include/ng_hci.h>
132 #include <netgraph/bluetooth/include/ng_ubt.h>
133 #include <netgraph/bluetooth/drivers/ubt/ng_ubt_var.h>
134
135 static int              ubt_modevent(module_t, int, void *);
136 static device_probe_t   ubt_probe;
137 static device_attach_t  ubt_attach;
138 static device_detach_t  ubt_detach;
139
140 static void             ubt_task_schedule(ubt_softc_p, int);
141 static task_fn_t        ubt_task;
142
143 #define ubt_xfer_start(sc, i)   usbd_transfer_start((sc)->sc_xfer[(i)])
144
145 /* Netgraph methods */
146 static ng_constructor_t ng_ubt_constructor;
147 static ng_shutdown_t    ng_ubt_shutdown;
148 static ng_newhook_t     ng_ubt_newhook;
149 static ng_connect_t     ng_ubt_connect;
150 static ng_disconnect_t  ng_ubt_disconnect;
151 static ng_rcvmsg_t      ng_ubt_rcvmsg;
152 static ng_rcvdata_t     ng_ubt_rcvdata;
153
154 /* Queue length */
155 static const struct ng_parse_struct_field       ng_ubt_node_qlen_type_fields[] =
156 {
157         { "queue", &ng_parse_int32_type, },
158         { "qlen",  &ng_parse_int32_type, },
159         { NULL, }
160 };
161 static const struct ng_parse_type               ng_ubt_node_qlen_type =
162 {
163         &ng_parse_struct_type,
164         &ng_ubt_node_qlen_type_fields
165 };
166
167 /* Stat info */
168 static const struct ng_parse_struct_field       ng_ubt_node_stat_type_fields[] =
169 {
170         { "pckts_recv", &ng_parse_uint32_type, },
171         { "bytes_recv", &ng_parse_uint32_type, },
172         { "pckts_sent", &ng_parse_uint32_type, },
173         { "bytes_sent", &ng_parse_uint32_type, },
174         { "oerrors",    &ng_parse_uint32_type, },
175         { "ierrors",    &ng_parse_uint32_type, },
176         { NULL, }
177 };
178 static const struct ng_parse_type               ng_ubt_node_stat_type =
179 {
180         &ng_parse_struct_type,
181         &ng_ubt_node_stat_type_fields
182 };
183
184 /* Netgraph node command list */
185 static const struct ng_cmdlist                  ng_ubt_cmdlist[] =
186 {
187         {
188                 NGM_UBT_COOKIE,
189                 NGM_UBT_NODE_SET_DEBUG,
190                 "set_debug",
191                 &ng_parse_uint16_type,
192                 NULL
193         },
194         {
195                 NGM_UBT_COOKIE,
196                 NGM_UBT_NODE_GET_DEBUG,
197                 "get_debug",
198                 NULL,
199                 &ng_parse_uint16_type
200         },
201         {
202                 NGM_UBT_COOKIE,
203                 NGM_UBT_NODE_SET_QLEN,
204                 "set_qlen",
205                 &ng_ubt_node_qlen_type,
206                 NULL
207         },
208         {
209                 NGM_UBT_COOKIE,
210                 NGM_UBT_NODE_GET_QLEN,
211                 "get_qlen",
212                 &ng_ubt_node_qlen_type,
213                 &ng_ubt_node_qlen_type
214         },
215         {
216                 NGM_UBT_COOKIE,
217                 NGM_UBT_NODE_GET_STAT,
218                 "get_stat",
219                 NULL,
220                 &ng_ubt_node_stat_type
221         },
222         {
223                 NGM_UBT_COOKIE,
224                 NGM_UBT_NODE_RESET_STAT,
225                 "reset_stat",
226                 NULL,
227                 NULL
228         },
229         { 0, }
230 };
231
232 /* Netgraph node type */
233 static struct ng_type   typestruct =
234 {
235         .version =      NG_ABI_VERSION,
236         .name =         NG_UBT_NODE_TYPE,
237         .constructor =  ng_ubt_constructor,
238         .rcvmsg =       ng_ubt_rcvmsg,
239         .shutdown =     ng_ubt_shutdown,
240         .newhook =      ng_ubt_newhook,
241         .connect =      ng_ubt_connect,
242         .rcvdata =      ng_ubt_rcvdata,
243         .disconnect =   ng_ubt_disconnect,
244         .cmdlist =      ng_ubt_cmdlist
245 };
246
247 /****************************************************************************
248  ****************************************************************************
249  **                              USB specific
250  ****************************************************************************
251  ****************************************************************************/
252
253 /* USB methods */
254 static usb_callback_t   ubt_ctrl_write_callback;
255 static usb_callback_t   ubt_intr_read_callback;
256 static usb_callback_t   ubt_bulk_read_callback;
257 static usb_callback_t   ubt_bulk_write_callback;
258 static usb_callback_t   ubt_isoc_read_callback;
259 static usb_callback_t   ubt_isoc_write_callback;
260
261 static int              ubt_fwd_mbuf_up(ubt_softc_p, struct mbuf **);
262 static int              ubt_isoc_read_one_frame(struct usb_xfer *, int);
263
264 /*
265  * USB config
266  * 
267  * The following desribes usb transfers that could be submitted on USB device.
268  *
269  * Interface 0 on the USB device must present the following endpoints
270  *      1) Interrupt endpoint to receive HCI events
271  *      2) Bulk IN endpoint to receive ACL data
272  *      3) Bulk OUT endpoint to send ACL data
273  *
274  * Interface 1 on the USB device must present the following endpoints
275  *      1) Isochronous IN endpoint to receive SCO data
276  *      2) Isochronous OUT endpoint to send SCO data
277  */
278
279 static const struct usb_config          ubt_config[UBT_N_TRANSFER] =
280 {
281         /*
282          * Interface #0
283          */
284
285         /* Outgoing bulk transfer - ACL packets */
286         [UBT_IF_0_BULK_DT_WR] = {
287                 .type =         UE_BULK,
288                 .endpoint =     UE_ADDR_ANY,
289                 .direction =    UE_DIR_OUT,
290                 .if_index =     0,
291                 .bufsize =      UBT_BULK_WRITE_BUFFER_SIZE,
292                 .flags =        { .pipe_bof = 1, .force_short_xfer = 1, },
293                 .callback =     &ubt_bulk_write_callback,
294         },
295         /* Incoming bulk transfer - ACL packets */
296         [UBT_IF_0_BULK_DT_RD] = {
297                 .type =         UE_BULK,
298                 .endpoint =     UE_ADDR_ANY,
299                 .direction =    UE_DIR_IN,
300                 .if_index =     0,
301                 .bufsize =      UBT_BULK_READ_BUFFER_SIZE,
302                 .flags =        { .pipe_bof = 1, .short_xfer_ok = 1, },
303                 .callback =     &ubt_bulk_read_callback,
304         },
305         /* Incoming interrupt transfer - HCI events */
306         [UBT_IF_0_INTR_DT_RD] = {
307                 .type =         UE_INTERRUPT,
308                 .endpoint =     UE_ADDR_ANY,
309                 .direction =    UE_DIR_IN,
310                 .if_index =     0,
311                 .flags =        { .pipe_bof = 1, .short_xfer_ok = 1, },
312                 .bufsize =      UBT_INTR_BUFFER_SIZE,
313                 .callback =     &ubt_intr_read_callback,
314         },
315         /* Outgoing control transfer - HCI commands */
316         [UBT_IF_0_CTRL_DT_WR] = {
317                 .type =         UE_CONTROL,
318                 .endpoint =     0x00,   /* control pipe */
319                 .direction =    UE_DIR_ANY,
320                 .if_index =     0,
321                 .bufsize =      UBT_CTRL_BUFFER_SIZE,
322                 .callback =     &ubt_ctrl_write_callback,
323                 .timeout =      5000,   /* 5 seconds */
324         },
325
326         /*
327          * Interface #1
328          */
329
330         /* Incoming isochronous transfer #1 - SCO packets */
331         [UBT_IF_1_ISOC_DT_RD1] = {
332                 .type =         UE_ISOCHRONOUS,
333                 .endpoint =     UE_ADDR_ANY,
334                 .direction =    UE_DIR_IN,
335                 .if_index =     1,
336                 .bufsize =      0,      /* use "wMaxPacketSize * frames" */
337                 .frames =       UBT_ISOC_NFRAMES,
338                 .flags =        { .short_xfer_ok = 1, },
339                 .callback =     &ubt_isoc_read_callback,
340         },
341         /* Incoming isochronous transfer #2 - SCO packets */
342         [UBT_IF_1_ISOC_DT_RD2] = {
343                 .type =         UE_ISOCHRONOUS,
344                 .endpoint =     UE_ADDR_ANY,
345                 .direction =    UE_DIR_IN,
346                 .if_index =     1,
347                 .bufsize =      0,      /* use "wMaxPacketSize * frames" */
348                 .frames =       UBT_ISOC_NFRAMES,
349                 .flags =        { .short_xfer_ok = 1, },
350                 .callback =     &ubt_isoc_read_callback,
351         },
352         /* Outgoing isochronous transfer #1 - SCO packets */
353         [UBT_IF_1_ISOC_DT_WR1] = {
354                 .type =         UE_ISOCHRONOUS,
355                 .endpoint =     UE_ADDR_ANY,
356                 .direction =    UE_DIR_OUT,
357                 .if_index =     1,
358                 .bufsize =      0,      /* use "wMaxPacketSize * frames" */
359                 .frames =       UBT_ISOC_NFRAMES,
360                 .flags =        { .short_xfer_ok = 1, },
361                 .callback =     &ubt_isoc_write_callback,
362         },
363         /* Outgoing isochronous transfer #2 - SCO packets */
364         [UBT_IF_1_ISOC_DT_WR2] = {
365                 .type =         UE_ISOCHRONOUS,
366                 .endpoint =     UE_ADDR_ANY,
367                 .direction =    UE_DIR_OUT,
368                 .if_index =     1,
369                 .bufsize =      0,      /* use "wMaxPacketSize * frames" */
370                 .frames =       UBT_ISOC_NFRAMES,
371                 .flags =        { .short_xfer_ok = 1, },
372                 .callback =     &ubt_isoc_write_callback,
373         },
374 };
375
376 /*
377  * If for some reason device should not be attached then put
378  * VendorID/ProductID pair into the list below. The format is
379  * as follows:
380  *
381  *      { USB_VPI(VENDOR_ID, PRODUCT_ID, 0) },
382  *
383  * where VENDOR_ID and PRODUCT_ID are hex numbers.
384  */
385
386 static const struct usb_device_id ubt_ignore_devs[] = 
387 {
388         /* AVM USB Bluetooth-Adapter BlueFritz! v1.0 */
389         { USB_VPI(USB_VENDOR_AVM, 0x2200, 0) },
390 };
391
392 /* List of supported bluetooth devices */
393 static const struct usb_device_id ubt_devs[] =
394 {
395         /* Generic Bluetooth class devices */
396         { USB_IFACE_CLASS(UDCLASS_WIRELESS),
397           USB_IFACE_SUBCLASS(UDSUBCLASS_RF),
398           USB_IFACE_PROTOCOL(UDPROTO_BLUETOOTH) },
399
400         /* AVM USB Bluetooth-Adapter BlueFritz! v2.0 */
401         { USB_VPI(USB_VENDOR_AVM, 0x3800, 0) },
402 };
403
404 /*
405  * Probe for a USB Bluetooth device.
406  * USB context.
407  */
408
409 static int
410 ubt_probe(device_t dev)
411 {
412         struct usb_attach_arg   *uaa = device_get_ivars(dev);
413
414         if (uaa->usb_mode != USB_MODE_HOST)
415                 return (ENXIO);
416
417         if (uaa->info.bIfaceIndex != 0)
418                 return (ENXIO);
419
420         if (uaa->use_generic == 0)
421                 return (ENXIO);
422
423         if (usbd_lookup_id_by_uaa(ubt_ignore_devs,
424                         sizeof(ubt_ignore_devs), uaa) == 0)
425                 return (ENXIO);
426
427         return (usbd_lookup_id_by_uaa(ubt_devs, sizeof(ubt_devs), uaa));
428 } /* ubt_probe */
429
430 /*
431  * Attach the device.
432  * USB context.
433  */
434
435 static int
436 ubt_attach(device_t dev)
437 {
438         struct usb_attach_arg           *uaa = device_get_ivars(dev);
439         struct ubt_softc                *sc = device_get_softc(dev);
440         struct usb_endpoint_descriptor  *ed;
441         struct usb_interface_descriptor *id;
442         uint16_t                        wMaxPacketSize;
443         uint8_t                         alt_index, i, j;
444         uint8_t                         iface_index[2] = { 0, 1 };
445
446         device_set_usb_desc(dev);
447
448         sc->sc_dev = dev;
449         sc->sc_debug = NG_UBT_WARN_LEVEL;
450
451         /* 
452          * Create Netgraph node
453          */
454
455         if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) {
456                 UBT_ALERT(sc, "could not create Netgraph node\n");
457                 return (ENXIO);
458         }
459
460         /* Name Netgraph node */
461         if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) {
462                 UBT_ALERT(sc, "could not name Netgraph node\n");
463                 NG_NODE_UNREF(sc->sc_node);
464                 return (ENXIO);
465         }
466         NG_NODE_SET_PRIVATE(sc->sc_node, sc);
467         NG_NODE_FORCE_WRITER(sc->sc_node);
468
469         /*
470          * Initialize device softc structure
471          */
472
473         /* initialize locks */
474         mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF);
475         mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE);
476
477         /* initialize packet queues */
478         NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN);
479         NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN);
480         NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN);
481
482         /* initialize glue task */
483         TASK_INIT(&sc->sc_task, 0, ubt_task, sc);
484
485         /*
486          * Configure Bluetooth USB device. Discover all required USB
487          * interfaces and endpoints.
488          *
489          * USB device must present two interfaces:
490          * 1) Interface 0 that has 3 endpoints
491          *      1) Interrupt endpoint to receive HCI events
492          *      2) Bulk IN endpoint to receive ACL data
493          *      3) Bulk OUT endpoint to send ACL data
494          *
495          * 2) Interface 1 then has 2 endpoints
496          *      1) Isochronous IN endpoint to receive SCO data
497          *      2) Isochronous OUT endpoint to send SCO data
498          *
499          * Interface 1 (with isochronous endpoints) has several alternate
500          * configurations with different packet size.
501          */
502
503         /*
504          * For interface #1 search alternate settings, and find
505          * the descriptor with the largest wMaxPacketSize
506          */
507
508         wMaxPacketSize = 0;
509         alt_index = 0;
510         i = 0;
511         j = 0;
512         ed = NULL;
513
514         /* 
515          * Search through all the descriptors looking for the largest
516          * packet size:
517          */
518         while ((ed = (struct usb_endpoint_descriptor *)usb_desc_foreach(
519             usbd_get_config_descriptor(uaa->device), 
520             (struct usb_descriptor *)ed))) {
521
522                 if ((ed->bDescriptorType == UDESC_INTERFACE) &&
523                     (ed->bLength >= sizeof(*id))) {
524                         id = (struct usb_interface_descriptor *)ed;
525                         i = id->bInterfaceNumber;
526                         j = id->bAlternateSetting;
527                 }
528
529                 if ((ed->bDescriptorType == UDESC_ENDPOINT) &&
530                     (ed->bLength >= sizeof(*ed)) &&
531                     (i == 1)) {
532                         uint16_t temp;
533
534                         temp = UGETW(ed->wMaxPacketSize);
535                         if (temp > wMaxPacketSize) {
536                                 wMaxPacketSize = temp;
537                                 alt_index = j;
538                         }
539                 }
540         }
541
542         /* Set alt configuration on interface #1 only if we found it */
543         if (wMaxPacketSize > 0 &&
544             usbd_set_alt_interface_index(uaa->device, 1, alt_index)) {
545                 UBT_ALERT(sc, "could not set alternate setting %d " \
546                         "for interface 1!\n", alt_index);
547                 goto detach;
548         }
549
550         /* Setup transfers for both interfaces */
551         if (usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer,
552                         ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) {
553                 UBT_ALERT(sc, "could not allocate transfers\n");
554                 goto detach;
555         }
556
557         /* Claim all interfaces on the device */
558         for (i = 1; usbd_get_iface(uaa->device, i) != NULL; i ++)
559                 usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
560
561         return (0); /* success */
562
563 detach:
564         ubt_detach(dev);
565
566         return (ENXIO);
567 } /* ubt_attach */
568
569 /*
570  * Detach the device.
571  * USB context.
572  */
573
574 int
575 ubt_detach(device_t dev)
576 {
577         struct ubt_softc        *sc = device_get_softc(dev);
578         node_p                  node = sc->sc_node;
579
580         /* Destroy Netgraph node */
581         if (node != NULL) {
582                 sc->sc_node = NULL;
583                 NG_NODE_REALLY_DIE(node);
584                 ng_rmnode_self(node);
585         }
586
587         /* Make sure ubt_task in gone */
588         taskqueue_drain(taskqueue_swi, &sc->sc_task);
589
590         /* Free USB transfers, if any */
591         usbd_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER);
592
593         /* Destroy queues */
594         UBT_NG_LOCK(sc);
595         NG_BT_MBUFQ_DESTROY(&sc->sc_cmdq);
596         NG_BT_MBUFQ_DESTROY(&sc->sc_aclq);
597         NG_BT_MBUFQ_DESTROY(&sc->sc_scoq);
598         UBT_NG_UNLOCK(sc);
599
600         mtx_destroy(&sc->sc_if_mtx);
601         mtx_destroy(&sc->sc_ng_mtx);
602
603         return (0);
604 } /* ubt_detach */
605
606 /* 
607  * Called when outgoing control request (HCI command) has completed, i.e.
608  * HCI command was sent to the device.
609  * USB context.
610  */
611
612 static void
613 ubt_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error)
614 {
615         struct ubt_softc                *sc = usbd_xfer_softc(xfer);
616         struct usb_device_request       req;
617         struct mbuf                     *m;
618         struct usb_page_cache           *pc;
619         int                             actlen;
620
621         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
622
623         switch (USB_GET_STATE(xfer)) {
624         case USB_ST_TRANSFERRED:
625                 UBT_INFO(sc, "sent %d bytes to control pipe\n", actlen);
626                 UBT_STAT_BYTES_SENT(sc, actlen);
627                 UBT_STAT_PCKTS_SENT(sc);
628                 /* FALLTHROUGH */
629
630         case USB_ST_SETUP:
631 send_next:
632                 /* Get next command mbuf, if any */
633                 UBT_NG_LOCK(sc);
634                 NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
635                 UBT_NG_UNLOCK(sc);
636
637                 if (m == NULL) {
638                         UBT_INFO(sc, "HCI command queue is empty\n");
639                         break;  /* transfer complete */
640                 }
641
642                 /* Initialize a USB control request and then schedule it */
643                 bzero(&req, sizeof(req));
644                 req.bmRequestType = UBT_HCI_REQUEST;
645                 USETW(req.wLength, m->m_pkthdr.len);
646
647                 UBT_INFO(sc, "Sending control request, " \
648                         "bmRequestType=0x%02x, wLength=%d\n",
649                         req.bmRequestType, UGETW(req.wLength));
650
651                 pc = usbd_xfer_get_frame(xfer, 0);
652                 usbd_copy_in(pc, 0, &req, sizeof(req));
653                 pc = usbd_xfer_get_frame(xfer, 1);
654                 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
655
656                 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
657                 usbd_xfer_set_frame_len(xfer, 1, m->m_pkthdr.len);
658                 usbd_xfer_set_frames(xfer, 2);
659
660                 NG_FREE_M(m);
661
662                 usbd_transfer_submit(xfer);
663                 break;
664
665         default: /* Error */
666                 if (error != USB_ERR_CANCELLED) {
667                         UBT_WARN(sc, "control transfer failed: %s\n",
668                                 usbd_errstr(error));
669
670                         UBT_STAT_OERROR(sc);
671                         goto send_next;
672                 }
673
674                 /* transfer cancelled */
675                 break;
676         }
677 } /* ubt_ctrl_write_callback */
678
679 /* 
680  * Called when incoming interrupt transfer (HCI event) has completed, i.e.
681  * HCI event was received from the device.
682  * USB context.
683  */
684
685 static void
686 ubt_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
687 {
688         struct ubt_softc        *sc = usbd_xfer_softc(xfer);
689         struct mbuf             *m;
690         ng_hci_event_pkt_t      *hdr;
691         struct usb_page_cache   *pc;
692         int                     actlen;
693
694         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
695
696         m = NULL;
697
698         switch (USB_GET_STATE(xfer)) {
699         case USB_ST_TRANSFERRED:
700                 /* Allocate a new mbuf */
701                 MGETHDR(m, M_DONTWAIT, MT_DATA);
702                 if (m == NULL) {
703                         UBT_STAT_IERROR(sc);
704                         goto submit_next;
705                 }
706
707                 MCLGET(m, M_DONTWAIT);
708                 if (!(m->m_flags & M_EXT)) {
709                         UBT_STAT_IERROR(sc);
710                         goto submit_next;
711                 }
712
713                 /* Add HCI packet type */
714                 *mtod(m, uint8_t *)= NG_HCI_EVENT_PKT;
715                 m->m_pkthdr.len = m->m_len = 1;
716
717                 if (actlen > MCLBYTES - 1)
718                         actlen = MCLBYTES - 1;
719
720                 pc = usbd_xfer_get_frame(xfer, 0);
721                 usbd_copy_out(pc, 0, mtod(m, uint8_t *) + 1, actlen);
722                 m->m_pkthdr.len += actlen;
723                 m->m_len += actlen;
724
725                 UBT_INFO(sc, "got %d bytes from interrupt pipe\n",
726                         actlen);
727
728                 /* Validate packet and send it up the stack */
729                 if (m->m_pkthdr.len < sizeof(*hdr)) {
730                         UBT_INFO(sc, "HCI event packet is too short\n");
731
732                         UBT_STAT_IERROR(sc);
733                         goto submit_next;
734                 }
735
736                 hdr = mtod(m, ng_hci_event_pkt_t *);
737                 if (hdr->length != (m->m_pkthdr.len - sizeof(*hdr))) {
738                         UBT_ERR(sc, "Invalid HCI event packet size, " \
739                                 "length=%d, pktlen=%d\n",
740                                 hdr->length, m->m_pkthdr.len);
741
742                         UBT_STAT_IERROR(sc);
743                         goto submit_next;
744                 }
745
746                 UBT_INFO(sc, "got complete HCI event frame, pktlen=%d, " \
747                         "length=%d\n", m->m_pkthdr.len, hdr->length);
748
749                 UBT_STAT_PCKTS_RECV(sc);
750                 UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len);
751
752                 ubt_fwd_mbuf_up(sc, &m);
753                 /* m == NULL at this point */
754                 /* FALLTHROUGH */
755
756         case USB_ST_SETUP:
757 submit_next:
758                 NG_FREE_M(m); /* checks for m != NULL */
759
760                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
761                 usbd_transfer_submit(xfer);
762                 break;
763
764         default: /* Error */
765                 if (error != USB_ERR_CANCELLED) {
766                         UBT_WARN(sc, "interrupt transfer failed: %s\n",
767                                 usbd_errstr(error));
768
769                         /* Try to clear stall first */
770                         usbd_xfer_set_stall(xfer);
771                         goto submit_next;
772                 }
773                         /* transfer cancelled */
774                 break;
775         }
776 } /* ubt_intr_read_callback */
777
778 /*
779  * Called when incoming bulk transfer (ACL packet) has completed, i.e.
780  * ACL packet was received from the device.
781  * USB context.
782  */
783
784 static void
785 ubt_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
786 {
787         struct ubt_softc        *sc = usbd_xfer_softc(xfer);
788         struct mbuf             *m;
789         ng_hci_acldata_pkt_t    *hdr;
790         struct usb_page_cache   *pc;
791         uint16_t                len;
792         int                     actlen;
793
794         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
795
796         m = NULL;
797
798         switch (USB_GET_STATE(xfer)) {
799         case USB_ST_TRANSFERRED:
800                 /* Allocate new mbuf */
801                 MGETHDR(m, M_DONTWAIT, MT_DATA);
802                 if (m == NULL) {
803                         UBT_STAT_IERROR(sc);
804                         goto submit_next;
805                 }
806
807                 MCLGET(m, M_DONTWAIT);
808                 if (!(m->m_flags & M_EXT)) {
809                         UBT_STAT_IERROR(sc);
810                         goto submit_next;
811                 }
812
813                 /* Add HCI packet type */
814                 *mtod(m, uint8_t *)= NG_HCI_ACL_DATA_PKT;
815                 m->m_pkthdr.len = m->m_len = 1;
816
817                 if (actlen > MCLBYTES - 1)
818                         actlen = MCLBYTES - 1;
819
820                 pc = usbd_xfer_get_frame(xfer, 0);
821                 usbd_copy_out(pc, 0, mtod(m, uint8_t *) + 1, actlen);
822                 m->m_pkthdr.len += actlen;
823                 m->m_len += actlen;
824
825                 UBT_INFO(sc, "got %d bytes from bulk-in pipe\n",
826                         actlen);
827
828                 /* Validate packet and send it up the stack */
829                 if (m->m_pkthdr.len < sizeof(*hdr)) {
830                         UBT_INFO(sc, "HCI ACL packet is too short\n");
831
832                         UBT_STAT_IERROR(sc);
833                         goto submit_next;
834                 }
835
836                 hdr = mtod(m, ng_hci_acldata_pkt_t *);
837                 len = le16toh(hdr->length);
838                 if (len != (m->m_pkthdr.len - sizeof(*hdr))) {
839                         UBT_ERR(sc, "Invalid ACL packet size, length=%d, " \
840                                 "pktlen=%d\n", len, m->m_pkthdr.len);
841
842                         UBT_STAT_IERROR(sc);
843                         goto submit_next;
844                 }
845
846                 UBT_INFO(sc, "got complete ACL data packet, pktlen=%d, " \
847                         "length=%d\n", m->m_pkthdr.len, len);
848
849                 UBT_STAT_PCKTS_RECV(sc);
850                 UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len);
851
852                 ubt_fwd_mbuf_up(sc, &m);
853                 /* m == NULL at this point */
854                 /* FALLTHOUGH */
855
856         case USB_ST_SETUP:
857 submit_next:
858                 NG_FREE_M(m); /* checks for m != NULL */
859
860                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
861                 usbd_transfer_submit(xfer);
862                 break;
863
864         default: /* Error */
865                 if (error != USB_ERR_CANCELLED) {
866                         UBT_WARN(sc, "bulk-in transfer failed: %s\n",
867                                 usbd_errstr(error));
868
869                         /* Try to clear stall first */
870                         usbd_xfer_set_stall(xfer);
871                         goto submit_next;
872                 }
873                         /* transfer cancelled */
874                 break;
875         }
876 } /* ubt_bulk_read_callback */
877
878 /*
879  * Called when outgoing bulk transfer (ACL packet) has completed, i.e.
880  * ACL packet was sent to the device.
881  * USB context.
882  */
883
884 static void
885 ubt_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
886 {
887         struct ubt_softc        *sc = usbd_xfer_softc(xfer);
888         struct mbuf             *m;
889         struct usb_page_cache   *pc;
890         int                     actlen;
891
892         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
893
894         switch (USB_GET_STATE(xfer)) {
895         case USB_ST_TRANSFERRED:
896                 UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n", actlen);
897                 UBT_STAT_BYTES_SENT(sc, actlen);
898                 UBT_STAT_PCKTS_SENT(sc);
899                 /* FALLTHROUGH */
900
901         case USB_ST_SETUP:
902 send_next:
903                 /* Get next mbuf, if any */
904                 UBT_NG_LOCK(sc);
905                 NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m);
906                 UBT_NG_UNLOCK(sc);
907
908                 if (m == NULL) {
909                         UBT_INFO(sc, "ACL data queue is empty\n");
910                         break; /* transfer completed */
911                 }
912
913                 /*
914                  * Copy ACL data frame back to a linear USB transfer buffer
915                  * and schedule transfer
916                  */
917
918                 pc = usbd_xfer_get_frame(xfer, 0);
919                 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
920                 usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
921
922                 UBT_INFO(sc, "bulk-out transfer has been started, len=%d\n",
923                         m->m_pkthdr.len);
924
925                 NG_FREE_M(m);
926
927                 usbd_transfer_submit(xfer);
928                 break;
929
930         default: /* Error */
931                 if (error != USB_ERR_CANCELLED) {
932                         UBT_WARN(sc, "bulk-out transfer failed: %s\n",
933                                 usbd_errstr(error));
934
935                         UBT_STAT_OERROR(sc);
936
937                         /* try to clear stall first */
938                         usbd_xfer_set_stall(xfer);
939                         goto send_next;
940                 }
941                         /* transfer cancelled */
942                 break;
943         }
944 } /* ubt_bulk_write_callback */
945
946 /*
947  * Called when incoming isoc transfer (SCO packet) has completed, i.e.
948  * SCO packet was received from the device.
949  * USB context.
950  */
951
952 static void
953 ubt_isoc_read_callback(struct usb_xfer *xfer, usb_error_t error)
954 {
955         struct ubt_softc        *sc = usbd_xfer_softc(xfer);
956         int                     n;
957         int actlen, nframes;
958
959         usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes);
960
961         switch (USB_GET_STATE(xfer)) {
962         case USB_ST_TRANSFERRED:
963                 for (n = 0; n < nframes; n ++)
964                         if (ubt_isoc_read_one_frame(xfer, n) < 0)
965                                 break;
966                 /* FALLTHROUGH */
967
968         case USB_ST_SETUP:
969 read_next:
970                 for (n = 0; n < nframes; n ++)
971                         usbd_xfer_set_frame_len(xfer, n,
972                             usbd_xfer_max_framelen(xfer));
973
974                 usbd_transfer_submit(xfer);
975                 break;
976
977         default: /* Error */
978                 if (error != USB_ERR_CANCELLED) {
979                         UBT_STAT_IERROR(sc);
980                         goto read_next;
981                 }
982
983                 /* transfer cancelled */
984                 break;
985         }
986 } /* ubt_isoc_read_callback */
987
988 /*
989  * Helper function. Called from ubt_isoc_read_callback() to read
990  * SCO data from one frame.
991  * USB context.
992  */
993
994 static int
995 ubt_isoc_read_one_frame(struct usb_xfer *xfer, int frame_no)
996 {
997         struct ubt_softc        *sc = usbd_xfer_softc(xfer);
998         struct usb_page_cache   *pc;
999         struct mbuf             *m;
1000         int                     len, want, got, total;
1001
1002         /* Get existing SCO reassembly buffer */
1003         pc = usbd_xfer_get_frame(xfer, 0);
1004         m = sc->sc_isoc_in_buffer;
1005         total = usbd_xfer_frame_len(xfer, frame_no);
1006
1007         /* While we have data in the frame */
1008         while (total > 0) {
1009                 if (m == NULL) {
1010                         /* Start new reassembly buffer */
1011                         MGETHDR(m, M_DONTWAIT, MT_DATA);
1012                         if (m == NULL) {
1013                                 UBT_STAT_IERROR(sc);
1014                                 return (-1);    /* XXX out of sync! */
1015                         }
1016
1017                         MCLGET(m, M_DONTWAIT);
1018                         if (!(m->m_flags & M_EXT)) {
1019                                 UBT_STAT_IERROR(sc);
1020                                 NG_FREE_M(m);
1021                                 return (-1);    /* XXX out of sync! */
1022                         }
1023
1024                         /* Expect SCO header */
1025                         *mtod(m, uint8_t *) = NG_HCI_SCO_DATA_PKT;
1026                         m->m_pkthdr.len = m->m_len = got = 1;
1027                         want = sizeof(ng_hci_scodata_pkt_t);
1028                 } else {
1029                         /*
1030                          * Check if we have SCO header and if so 
1031                          * adjust amount of data we want
1032                          */
1033                         got = m->m_pkthdr.len;
1034                         want = sizeof(ng_hci_scodata_pkt_t);
1035
1036                         if (got >= want)
1037                                 want += mtod(m, ng_hci_scodata_pkt_t *)->length;
1038                 }
1039
1040                 /* Append frame data to the SCO reassembly buffer */
1041                 len = total;
1042                 if (got + len > want)
1043                         len = want - got;
1044
1045                 usbd_copy_out(pc, frame_no * usbd_xfer_max_framelen(xfer),
1046                         mtod(m, uint8_t *) + m->m_pkthdr.len, len);
1047
1048                 m->m_pkthdr.len += len;
1049                 m->m_len += len;
1050                 total -= len;
1051
1052                 /* Check if we got everything we wanted, if not - continue */
1053                 if (got != want)
1054                         continue;
1055
1056                 /* If we got here then we got complete SCO frame */
1057                 UBT_INFO(sc, "got complete SCO data frame, pktlen=%d, " \
1058                         "length=%d\n", m->m_pkthdr.len,
1059                         mtod(m, ng_hci_scodata_pkt_t *)->length);
1060
1061                 UBT_STAT_PCKTS_RECV(sc);
1062                 UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len);
1063
1064                 ubt_fwd_mbuf_up(sc, &m);
1065                 /* m == NULL at this point */
1066         }
1067
1068         /* Put SCO reassembly buffer back */
1069         sc->sc_isoc_in_buffer = m;
1070
1071         return (0);
1072 } /* ubt_isoc_read_one_frame */
1073
1074 /*
1075  * Called when outgoing isoc transfer (SCO packet) has completed, i.e.
1076  * SCO packet was sent to the device.
1077  * USB context.
1078  */
1079
1080 static void
1081 ubt_isoc_write_callback(struct usb_xfer *xfer, usb_error_t error)
1082 {
1083         struct ubt_softc        *sc = usbd_xfer_softc(xfer);
1084         struct usb_page_cache   *pc;
1085         struct mbuf             *m;
1086         int                     n, space, offset;
1087         int                     actlen, nframes;
1088
1089         usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes);
1090         pc = usbd_xfer_get_frame(xfer, 0);
1091
1092         switch (USB_GET_STATE(xfer)) {
1093         case USB_ST_TRANSFERRED:
1094                 UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n", actlen);
1095                 UBT_STAT_BYTES_SENT(sc, actlen);
1096                 UBT_STAT_PCKTS_SENT(sc);
1097                 /* FALLTHROUGH */
1098
1099         case USB_ST_SETUP:
1100 send_next:
1101                 offset = 0;
1102                 space = usbd_xfer_max_framelen(xfer) * nframes;
1103                 m = NULL;
1104
1105                 while (space > 0) {
1106                         if (m == NULL) {
1107                                 UBT_NG_LOCK(sc);
1108                                 NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m);
1109                                 UBT_NG_UNLOCK(sc);
1110
1111                                 if (m == NULL)
1112                                         break;
1113                         }
1114
1115                         n = min(space, m->m_pkthdr.len);
1116                         if (n > 0) {
1117                                 usbd_m_copy_in(pc, offset, m,0, n);
1118                                 m_adj(m, n);
1119
1120                                 offset += n;
1121                                 space -= n;
1122                         }
1123
1124                         if (m->m_pkthdr.len == 0)
1125                                 NG_FREE_M(m); /* sets m = NULL */
1126                 }
1127
1128                 /* Put whatever is left from mbuf back on queue */
1129                 if (m != NULL) {
1130                         UBT_NG_LOCK(sc);
1131                         NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m);
1132                         UBT_NG_UNLOCK(sc);
1133                 }
1134
1135                 /*
1136                  * Calculate sizes for isoc frames.
1137                  * Note that offset could be 0 at this point (i.e. we have
1138                  * nothing to send). That is fine, as we have isoc. transfers
1139                  * going in both directions all the time. In this case it
1140                  * would be just empty isoc. transfer.
1141                  */
1142
1143                 for (n = 0; n < nframes; n ++) {
1144                         usbd_xfer_set_frame_len(xfer, n,
1145                             min(offset, usbd_xfer_max_framelen(xfer)));
1146                         offset -= usbd_xfer_frame_len(xfer, n);
1147                 }
1148
1149                 usbd_transfer_submit(xfer);
1150                 break;
1151
1152         default: /* Error */
1153                 if (error != USB_ERR_CANCELLED) {
1154                         UBT_STAT_OERROR(sc);
1155                         goto send_next;
1156                 }
1157
1158                 /* transfer cancelled */
1159                 break;
1160         }
1161 }
1162
1163 /*
1164  * Utility function to forward provided mbuf upstream (i.e. up the stack).
1165  * Modifies value of the mbuf pointer (sets it to NULL).
1166  * Save to call from any context.
1167  */
1168
1169 static int
1170 ubt_fwd_mbuf_up(ubt_softc_p sc, struct mbuf **m)
1171 {
1172         hook_p  hook;
1173         int     error;
1174
1175         /*
1176          * Close the race with Netgraph hook newhook/disconnect methods.
1177          * Save the hook pointer atomically. Two cases are possible:
1178          *
1179          * 1) The hook pointer is NULL. It means disconnect method got
1180          *    there first. In this case we are done.
1181          *
1182          * 2) The hook pointer is not NULL. It means that hook pointer
1183          *    could be either in valid or invalid (i.e. in the process
1184          *    of disconnect) state. In any case grab an extra reference
1185          *    to protect the hook pointer.
1186          *
1187          * It is ok to pass hook in invalid state to NG_SEND_DATA_ONLY() as
1188          * it checks for it. Drop extra reference after NG_SEND_DATA_ONLY().
1189          */
1190
1191         UBT_NG_LOCK(sc);
1192         if ((hook = sc->sc_hook) != NULL)
1193                 NG_HOOK_REF(hook);
1194         UBT_NG_UNLOCK(sc);
1195
1196         if (hook == NULL) {
1197                 NG_FREE_M(*m);
1198                 return (ENETDOWN);
1199         }
1200
1201         NG_SEND_DATA_ONLY(error, hook, *m);
1202         NG_HOOK_UNREF(hook);
1203
1204         if (error != 0)
1205                 UBT_STAT_IERROR(sc);
1206
1207         return (error);
1208 } /* ubt_fwd_mbuf_up */
1209
1210 /****************************************************************************
1211  ****************************************************************************
1212  **                                 Glue 
1213  ****************************************************************************
1214  ****************************************************************************/
1215
1216 /*
1217  * Schedule glue task. Should be called with sc_ng_mtx held. 
1218  * Netgraph context.
1219  */
1220
1221 static void
1222 ubt_task_schedule(ubt_softc_p sc, int action)
1223 {
1224         mtx_assert(&sc->sc_ng_mtx, MA_OWNED);
1225
1226         /*
1227          * Try to handle corner case when "start all" and "stop all"
1228          * actions can both be set before task is executed.
1229          *
1230          * The rules are
1231          *
1232          * sc_task_flags        action          new sc_task_flags
1233          * ------------------------------------------------------
1234          * 0                    start           start
1235          * 0                    stop            stop
1236          * start                start           start
1237          * start                stop            stop
1238          * stop                 start           stop|start
1239          * stop                 stop            stop
1240          * stop|start           start           stop|start
1241          * stop|start           stop            stop
1242          */
1243
1244         if (action != 0) {
1245                 if ((action & UBT_FLAG_T_STOP_ALL) != 0)
1246                         sc->sc_task_flags &= ~UBT_FLAG_T_START_ALL;
1247
1248                 sc->sc_task_flags |= action;
1249         }
1250
1251         if (sc->sc_task_flags & UBT_FLAG_T_PENDING)
1252                 return;
1253
1254         if (taskqueue_enqueue(taskqueue_swi, &sc->sc_task) == 0) {
1255                 sc->sc_task_flags |= UBT_FLAG_T_PENDING;
1256                 return;
1257         }
1258
1259         /* XXX: i think this should never happen */
1260 } /* ubt_task_schedule */
1261
1262 /*
1263  * Glue task. Examines sc_task_flags and does things depending on it.
1264  * Taskqueue context.
1265  */
1266
1267 static void
1268 ubt_task(void *context, int pending)
1269 {
1270         ubt_softc_p     sc = context;
1271         int             task_flags, i;
1272
1273         UBT_NG_LOCK(sc);
1274         task_flags = sc->sc_task_flags;
1275         sc->sc_task_flags = 0;
1276         UBT_NG_UNLOCK(sc);
1277
1278         /*
1279          * Stop all USB transfers synchronously.
1280          * Stop interface #0 and #1 transfers at the same time and in the
1281          * same loop. usbd_transfer_drain() will do appropriate locking.
1282          */
1283
1284         if (task_flags & UBT_FLAG_T_STOP_ALL)
1285                 for (i = 0; i < UBT_N_TRANSFER; i ++)
1286                         usbd_transfer_drain(sc->sc_xfer[i]);
1287
1288         /* Start incoming interrupt and bulk, and all isoc. USB transfers */
1289         if (task_flags & UBT_FLAG_T_START_ALL) {
1290                 /*
1291                  * Interface #0
1292                  */
1293
1294                 mtx_lock(&sc->sc_if_mtx);
1295
1296                 ubt_xfer_start(sc, UBT_IF_0_INTR_DT_RD);
1297                 ubt_xfer_start(sc, UBT_IF_0_BULK_DT_RD);
1298
1299                 /*
1300                  * Interface #1
1301                  * Start both read and write isoc. transfers by default.
1302                  * Get them going all the time even if we have nothing
1303                  * to send to avoid any delays.
1304                  */
1305
1306                 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD1);
1307                 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD2);
1308                 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR1);
1309                 ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR2);
1310
1311                 mtx_unlock(&sc->sc_if_mtx);
1312         }
1313
1314         /* Start outgoing control transfer */
1315         if (task_flags & UBT_FLAG_T_START_CTRL) {
1316                 mtx_lock(&sc->sc_if_mtx);
1317                 ubt_xfer_start(sc, UBT_IF_0_CTRL_DT_WR);
1318                 mtx_unlock(&sc->sc_if_mtx);
1319         }
1320
1321         /* Start outgoing bulk transfer */
1322         if (task_flags & UBT_FLAG_T_START_BULK) {
1323                 mtx_lock(&sc->sc_if_mtx);
1324                 ubt_xfer_start(sc, UBT_IF_0_BULK_DT_WR);
1325                 mtx_unlock(&sc->sc_if_mtx);
1326         }
1327 } /* ubt_task */
1328
1329 /****************************************************************************
1330  ****************************************************************************
1331  **                        Netgraph specific
1332  ****************************************************************************
1333  ****************************************************************************/
1334
1335 /*
1336  * Netgraph node constructor. Do not allow to create node of this type.
1337  * Netgraph context.
1338  */
1339
1340 static int
1341 ng_ubt_constructor(node_p node)
1342 {
1343         return (EINVAL);
1344 } /* ng_ubt_constructor */
1345
1346 /*
1347  * Netgraph node destructor. Destroy node only when device has been detached.
1348  * Netgraph context.
1349  */
1350
1351 static int
1352 ng_ubt_shutdown(node_p node)
1353 {
1354         if (node->nd_flags & NGF_REALLY_DIE) {
1355                 /*
1356                  * We came here because the USB device is being
1357                  * detached, so stop being persistant.
1358                  */
1359                 NG_NODE_SET_PRIVATE(node, NULL);
1360                 NG_NODE_UNREF(node);
1361         } else
1362                 NG_NODE_REVIVE(node); /* tell ng_rmnode we are persisant */
1363
1364         return (0);
1365 } /* ng_ubt_shutdown */
1366
1367 /*
1368  * Create new hook. There can only be one.
1369  * Netgraph context.
1370  */
1371
1372 static int
1373 ng_ubt_newhook(node_p node, hook_p hook, char const *name)
1374 {
1375         struct ubt_softc        *sc = NG_NODE_PRIVATE(node);
1376
1377         if (strcmp(name, NG_UBT_HOOK) != 0)
1378                 return (EINVAL);
1379
1380         UBT_NG_LOCK(sc);
1381         if (sc->sc_hook != NULL) {
1382                 UBT_NG_UNLOCK(sc);
1383
1384                 return (EISCONN);
1385         }
1386
1387         sc->sc_hook = hook;
1388         UBT_NG_UNLOCK(sc);
1389
1390         return (0);
1391 } /* ng_ubt_newhook */
1392
1393 /*
1394  * Connect hook. Start incoming USB transfers.
1395  * Netgraph context.
1396  */
1397
1398 static int
1399 ng_ubt_connect(hook_p hook)
1400 {
1401         struct ubt_softc        *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1402
1403         NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
1404
1405         UBT_NG_LOCK(sc);
1406         ubt_task_schedule(sc, UBT_FLAG_T_START_ALL);
1407         UBT_NG_UNLOCK(sc);
1408
1409         return (0);
1410 } /* ng_ubt_connect */
1411
1412 /*
1413  * Disconnect hook.
1414  * Netgraph context.
1415  */
1416
1417 static int
1418 ng_ubt_disconnect(hook_p hook)
1419 {
1420         struct ubt_softc        *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1421
1422         UBT_NG_LOCK(sc);
1423
1424         if (hook != sc->sc_hook) {
1425                 UBT_NG_UNLOCK(sc);
1426
1427                 return (EINVAL);
1428         }
1429
1430         sc->sc_hook = NULL;
1431
1432         /* Kick off task to stop all USB xfers */
1433         ubt_task_schedule(sc, UBT_FLAG_T_STOP_ALL);
1434
1435         /* Drain queues */
1436         NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq);
1437         NG_BT_MBUFQ_DRAIN(&sc->sc_aclq);
1438         NG_BT_MBUFQ_DRAIN(&sc->sc_scoq);
1439
1440         UBT_NG_UNLOCK(sc);
1441
1442         return (0);
1443 } /* ng_ubt_disconnect */
1444         
1445 /*
1446  * Process control message.
1447  * Netgraph context.
1448  */
1449
1450 static int
1451 ng_ubt_rcvmsg(node_p node, item_p item, hook_p lasthook)
1452 {
1453         struct ubt_softc        *sc = NG_NODE_PRIVATE(node);
1454         struct ng_mesg          *msg, *rsp = NULL;
1455         struct ng_bt_mbufq      *q;
1456         int                     error = 0, queue, qlen;
1457
1458         NGI_GET_MSG(item, msg);
1459
1460         switch (msg->header.typecookie) {
1461         case NGM_GENERIC_COOKIE:
1462                 switch (msg->header.cmd) {
1463                 case NGM_TEXT_STATUS:
1464                         NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT);
1465                         if (rsp == NULL) {
1466                                 error = ENOMEM;
1467                                 break;
1468                         }
1469
1470                         snprintf(rsp->data, NG_TEXTRESPONSE,
1471                                 "Hook: %s\n" \
1472                                 "Task flags: %#x\n" \
1473                                 "Debug: %d\n" \
1474                                 "CMD queue: [have:%d,max:%d]\n" \
1475                                 "ACL queue: [have:%d,max:%d]\n" \
1476                                 "SCO queue: [have:%d,max:%d]",
1477                                 (sc->sc_hook != NULL) ? NG_UBT_HOOK : "",
1478                                 sc->sc_task_flags,
1479                                 sc->sc_debug,
1480                                 sc->sc_cmdq.len,
1481                                 sc->sc_cmdq.maxlen,
1482                                 sc->sc_aclq.len,
1483                                 sc->sc_aclq.maxlen,
1484                                 sc->sc_scoq.len,
1485                                 sc->sc_scoq.maxlen);
1486                         break;
1487
1488                 default:
1489                         error = EINVAL;
1490                         break;
1491                 }
1492                 break;
1493
1494         case NGM_UBT_COOKIE:
1495                 switch (msg->header.cmd) {
1496                 case NGM_UBT_NODE_SET_DEBUG:
1497                         if (msg->header.arglen != sizeof(ng_ubt_node_debug_ep)){
1498                                 error = EMSGSIZE;
1499                                 break;
1500                         }
1501
1502                         sc->sc_debug = *((ng_ubt_node_debug_ep *) (msg->data));
1503                         break;
1504
1505                 case NGM_UBT_NODE_GET_DEBUG:
1506                         NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_debug_ep),
1507                             M_NOWAIT);
1508                         if (rsp == NULL) {
1509                                 error = ENOMEM;
1510                                 break;
1511                         }
1512
1513                         *((ng_ubt_node_debug_ep *) (rsp->data)) = sc->sc_debug;
1514                         break;
1515
1516                 case NGM_UBT_NODE_SET_QLEN:
1517                         if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) {
1518                                 error = EMSGSIZE;
1519                                 break;
1520                         }
1521
1522                         queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue;
1523                         qlen = ((ng_ubt_node_qlen_ep *) (msg->data))->qlen;
1524
1525                         switch (queue) {
1526                         case NGM_UBT_NODE_QUEUE_CMD:
1527                                 q = &sc->sc_cmdq;
1528                                 break;
1529
1530                         case NGM_UBT_NODE_QUEUE_ACL:
1531                                 q = &sc->sc_aclq;
1532                                 break;
1533
1534                         case NGM_UBT_NODE_QUEUE_SCO:
1535                                 q = &sc->sc_scoq;
1536                                 break;
1537
1538                         default:
1539                                 error = EINVAL;
1540                                 goto done;
1541                                 /* NOT REACHED */
1542                         }
1543
1544                         q->maxlen = qlen;
1545                         break;
1546
1547                 case NGM_UBT_NODE_GET_QLEN:
1548                         if (msg->header.arglen != sizeof(ng_ubt_node_qlen_ep)) {
1549                                 error = EMSGSIZE;
1550                                 break;
1551                         }
1552
1553                         queue = ((ng_ubt_node_qlen_ep *) (msg->data))->queue;
1554
1555                         switch (queue) {
1556                         case NGM_UBT_NODE_QUEUE_CMD:
1557                                 q = &sc->sc_cmdq;
1558                                 break;
1559
1560                         case NGM_UBT_NODE_QUEUE_ACL:
1561                                 q = &sc->sc_aclq;
1562                                 break;
1563
1564                         case NGM_UBT_NODE_QUEUE_SCO:
1565                                 q = &sc->sc_scoq;
1566                                 break;
1567
1568                         default:
1569                                 error = EINVAL;
1570                                 goto done;
1571                                 /* NOT REACHED */
1572                         }
1573
1574                         NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_qlen_ep),
1575                                 M_NOWAIT);
1576                         if (rsp == NULL) {
1577                                 error = ENOMEM;
1578                                 break;
1579                         }
1580
1581                         ((ng_ubt_node_qlen_ep *) (rsp->data))->queue = queue;
1582                         ((ng_ubt_node_qlen_ep *) (rsp->data))->qlen = q->maxlen;
1583                         break;
1584
1585                 case NGM_UBT_NODE_GET_STAT:
1586                         NG_MKRESPONSE(rsp, msg, sizeof(ng_ubt_node_stat_ep),
1587                             M_NOWAIT);
1588                         if (rsp == NULL) {
1589                                 error = ENOMEM;
1590                                 break;
1591                         }
1592
1593                         bcopy(&sc->sc_stat, rsp->data,
1594                                 sizeof(ng_ubt_node_stat_ep));
1595                         break;
1596
1597                 case NGM_UBT_NODE_RESET_STAT:
1598                         UBT_STAT_RESET(sc);
1599                         break;
1600
1601                 default:
1602                         error = EINVAL;
1603                         break;
1604                 }
1605                 break;
1606
1607         default:
1608                 error = EINVAL;
1609                 break;
1610         }
1611 done:
1612         NG_RESPOND_MSG(error, node, item, rsp);
1613         NG_FREE_MSG(msg);
1614
1615         return (error);
1616 } /* ng_ubt_rcvmsg */
1617
1618 /*
1619  * Process data.
1620  * Netgraph context.
1621  */
1622
1623 static int
1624 ng_ubt_rcvdata(hook_p hook, item_p item)
1625 {
1626         struct ubt_softc        *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1627         struct mbuf             *m;
1628         struct ng_bt_mbufq      *q;
1629         int                     action, error = 0;
1630
1631         if (hook != sc->sc_hook) {
1632                 error = EINVAL;
1633                 goto done;
1634         }
1635
1636         /* Deatch mbuf and get HCI frame type */
1637         NGI_GET_M(item, m);
1638
1639         /*
1640          * Minimal size of the HCI frame is 4 bytes: 1 byte frame type,
1641          * 2 bytes connection handle and at least 1 byte of length.
1642          * Panic on data frame that has size smaller than 4 bytes (it
1643          * should not happen)
1644          */
1645
1646         if (m->m_pkthdr.len < 4)
1647                 panic("HCI frame size is too small! pktlen=%d\n",
1648                         m->m_pkthdr.len);
1649
1650         /* Process HCI frame */
1651         switch (*mtod(m, uint8_t *)) {  /* XXX call m_pullup ? */
1652         case NG_HCI_CMD_PKT:
1653                 if (m->m_pkthdr.len - 1 > UBT_CTRL_BUFFER_SIZE)
1654                         panic("HCI command frame size is too big! " \
1655                                 "buffer size=%zd, packet len=%d\n",
1656                                 UBT_CTRL_BUFFER_SIZE, m->m_pkthdr.len);
1657
1658                 q = &sc->sc_cmdq;
1659                 action = UBT_FLAG_T_START_CTRL;
1660                 break;
1661
1662         case NG_HCI_ACL_DATA_PKT:
1663                 if (m->m_pkthdr.len - 1 > UBT_BULK_WRITE_BUFFER_SIZE)
1664                         panic("ACL data frame size is too big! " \
1665                                 "buffer size=%d, packet len=%d\n",
1666                                 UBT_BULK_WRITE_BUFFER_SIZE, m->m_pkthdr.len);
1667
1668                 q = &sc->sc_aclq;
1669                 action = UBT_FLAG_T_START_BULK;
1670                 break;
1671
1672         case NG_HCI_SCO_DATA_PKT:
1673                 q = &sc->sc_scoq;
1674                 action = 0;
1675                 break;
1676
1677         default:
1678                 UBT_ERR(sc, "Dropping unsupported HCI frame, type=0x%02x, " \
1679                         "pktlen=%d\n", *mtod(m, uint8_t *), m->m_pkthdr.len);
1680
1681                 NG_FREE_M(m);
1682                 error = EINVAL;
1683                 goto done;
1684                 /* NOT REACHED */
1685         }
1686
1687         UBT_NG_LOCK(sc);
1688         if (NG_BT_MBUFQ_FULL(q)) {
1689                 NG_BT_MBUFQ_DROP(q);
1690                 UBT_NG_UNLOCK(sc);
1691                 
1692                 UBT_ERR(sc, "Dropping HCI frame 0x%02x, len=%d. Queue full\n",
1693                         *mtod(m, uint8_t *), m->m_pkthdr.len);
1694
1695                 NG_FREE_M(m);
1696         } else {
1697                 /* Loose HCI packet type, enqueue mbuf and kick off task */
1698                 m_adj(m, sizeof(uint8_t));
1699                 NG_BT_MBUFQ_ENQUEUE(q, m);
1700                 ubt_task_schedule(sc, action);
1701                 UBT_NG_UNLOCK(sc);
1702         }
1703 done:
1704         NG_FREE_ITEM(item);
1705
1706         return (error);
1707 } /* ng_ubt_rcvdata */
1708
1709 /****************************************************************************
1710  ****************************************************************************
1711  **                              Module
1712  ****************************************************************************
1713  ****************************************************************************/
1714
1715 /*
1716  * Load/Unload the driver module
1717  */
1718
1719 static int
1720 ubt_modevent(module_t mod, int event, void *data)
1721 {
1722         int     error;
1723
1724         switch (event) {
1725         case MOD_LOAD:
1726                 error = ng_newtype(&typestruct);
1727                 if (error != 0)
1728                         printf("%s: Could not register Netgraph node type, " \
1729                                 "error=%d\n", NG_UBT_NODE_TYPE, error);
1730                 break;
1731
1732         case MOD_UNLOAD:
1733                 error = ng_rmtype(&typestruct);
1734                 break;
1735
1736         default:
1737                 error = EOPNOTSUPP;
1738                 break;
1739         }
1740
1741         return (error);
1742 } /* ubt_modevent */
1743
1744 static devclass_t       ubt_devclass;
1745
1746 static device_method_t  ubt_methods[] =
1747 {
1748         DEVMETHOD(device_probe, ubt_probe),
1749         DEVMETHOD(device_attach, ubt_attach),
1750         DEVMETHOD(device_detach, ubt_detach),
1751         { 0, 0 }
1752 };
1753
1754 static driver_t         ubt_driver =
1755 {
1756         .name =    "ubt",
1757         .methods = ubt_methods,
1758         .size =    sizeof(struct ubt_softc),
1759 };
1760
1761 DRIVER_MODULE(ng_ubt, uhub, ubt_driver, ubt_devclass, ubt_modevent, 0);
1762 MODULE_VERSION(ng_ubt, NG_BLUETOOTH_VERSION);
1763 MODULE_DEPEND(ng_ubt, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
1764 MODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION);
1765 MODULE_DEPEND(ng_ubt, usb, 1, 1, 1);
1766