]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c
MFC: 364430:
[FreeBSD/FreeBSD.git] / sys / netgraph / bluetooth / drivers / bt3c / ng_bt3c_pccard.c
1 /*
2  * ng_bt3c_pccard.c
3  */
4
5 /*-
6  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7  *
8  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: ng_bt3c_pccard.c,v 1.5 2003/04/01 18:15:21 max Exp $
33  * $FreeBSD$
34  *
35  * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 
36  *
37  * Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt>
38  * and disassembled w2k driver.
39  *
40  * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX 
41  *
42  */
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46
47 #include <sys/bus.h>
48 #include <machine/bus.h>
49
50 #include <sys/conf.h>
51 #include <sys/endian.h>
52 #include <sys/interrupt.h>
53 #include <sys/kernel.h>
54 #include <sys/mbuf.h>
55 #include <sys/module.h>
56
57 #include <machine/resource.h>
58 #include <sys/rman.h>
59
60 #include <sys/socket.h>
61 #include <net/if.h>
62 #include <net/if_var.h>
63
64 #include <dev/pccard/pccardreg.h>
65 #include <dev/pccard/pccardvar.h>
66 #include "pccarddevs.h"
67
68 #include <netgraph/ng_message.h>
69 #include <netgraph/netgraph.h>
70 #include <netgraph/ng_parse.h>
71 #include <netgraph/bluetooth/include/ng_bluetooth.h>
72 #include <netgraph/bluetooth/include/ng_hci.h>
73 #include <netgraph/bluetooth/include/ng_bt3c.h>
74 #include <netgraph/bluetooth/drivers/bt3c/ng_bt3c_var.h>
75
76 /* Netgraph methods */
77 static ng_constructor_t ng_bt3c_constructor;
78 static ng_shutdown_t    ng_bt3c_shutdown;
79 static ng_newhook_t     ng_bt3c_newhook;
80 static ng_connect_t     ng_bt3c_connect;
81 static ng_disconnect_t  ng_bt3c_disconnect;
82 static ng_rcvmsg_t      ng_bt3c_rcvmsg;
83 static ng_rcvdata_t     ng_bt3c_rcvdata;
84
85 /* PCMCIA driver methods */
86 static int      bt3c_pccard_probe       (device_t);
87 static int      bt3c_pccard_attach      (device_t);
88 static int      bt3c_pccard_detach      (device_t);
89
90 static void     bt3c_intr               (void *);
91 static void     bt3c_receive            (bt3c_softc_p);
92
93 static void     bt3c_swi_intr           (void *);
94 static void     bt3c_forward            (node_p, hook_p, void *, int);
95 static void     bt3c_send               (node_p, hook_p, void *, int);
96
97 static void     bt3c_download_firmware  (bt3c_softc_p, char const *, int);
98
99 #define bt3c_set_address(sc, address) \
100 do { \
101         bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_L, ((address) & 0xff)); \
102         bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_H, (((address) >> 8) & 0xff)); \
103 } while (0)
104
105 #define bt3c_read_data(sc, data) \
106 do { \
107         (data)  = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_L); \
108         (data) |= ((bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_H) & 0xff) << 8); \
109 } while (0)
110
111 #define bt3c_write_data(sc, data) \
112 do { \
113         bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_L, ((data) & 0xff)); \
114         bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_H, (((data) >> 8) & 0xff)); \
115 } while (0)
116
117 #define bt3c_read_control(sc, data) \
118 do { \
119         (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_CONTROL); \
120 } while (0)
121
122 #define bt3c_write_control(sc, data) \
123 do { \
124         bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_CONTROL, (data)); \
125 } while (0)
126
127 #define bt3c_read(sc, address, data) \
128 do { \
129         bt3c_set_address((sc), (address)); \
130         bt3c_read_data((sc), (data)); \
131 } while(0)
132
133 #define bt3c_write(sc, address, data) \
134 do { \
135         bt3c_set_address((sc), (address)); \
136         bt3c_write_data((sc), (data)); \
137 } while(0)
138
139 static MALLOC_DEFINE(M_BT3C, "bt3c", "bt3c data structures");
140         
141 /****************************************************************************
142  ****************************************************************************
143  **                           Netgraph specific
144  ****************************************************************************
145  ****************************************************************************/
146
147 /*
148  * Netgraph node type
149  */
150
151 /* Queue length */
152 static const struct ng_parse_struct_field       ng_bt3c_node_qlen_type_fields[] =
153 {
154         { "queue", &ng_parse_int32_type, },
155         { "qlen",  &ng_parse_int32_type, },
156         { NULL, }
157 };
158 static const struct ng_parse_type               ng_bt3c_node_qlen_type = {
159         &ng_parse_struct_type,
160         &ng_bt3c_node_qlen_type_fields
161 };
162
163 /* Stat info */
164 static const struct ng_parse_struct_field       ng_bt3c_node_stat_type_fields[] =
165 {
166         { "pckts_recv", &ng_parse_uint32_type, },
167         { "bytes_recv", &ng_parse_uint32_type, },
168         { "pckts_sent", &ng_parse_uint32_type, },
169         { "bytes_sent", &ng_parse_uint32_type, },
170         { "oerrors",    &ng_parse_uint32_type, },
171         { "ierrors",    &ng_parse_uint32_type, },
172         { NULL, }
173 };
174 static const struct ng_parse_type               ng_bt3c_node_stat_type = {
175         &ng_parse_struct_type,
176         &ng_bt3c_node_stat_type_fields
177 };
178
179 static const struct ng_cmdlist  ng_bt3c_cmdlist[] = {
180 {
181         NGM_BT3C_COOKIE,
182         NGM_BT3C_NODE_GET_STATE,
183         "get_state",
184         NULL,
185         &ng_parse_uint16_type
186 },
187 {
188         NGM_BT3C_COOKIE,
189         NGM_BT3C_NODE_SET_DEBUG,
190         "set_debug",
191         &ng_parse_uint16_type,
192         NULL
193 },
194 {
195         NGM_BT3C_COOKIE,
196         NGM_BT3C_NODE_GET_DEBUG,
197         "get_debug",
198         NULL,
199         &ng_parse_uint16_type
200 },
201 {
202         NGM_BT3C_COOKIE,
203         NGM_BT3C_NODE_GET_QLEN,
204         "get_qlen",
205         NULL,
206         &ng_bt3c_node_qlen_type
207 },
208 {
209         NGM_BT3C_COOKIE,
210         NGM_BT3C_NODE_SET_QLEN,
211         "set_qlen",
212         &ng_bt3c_node_qlen_type,
213         NULL
214 },
215 {
216         NGM_BT3C_COOKIE,
217         NGM_BT3C_NODE_GET_STAT,
218         "get_stat",
219         NULL,
220         &ng_bt3c_node_stat_type
221 },
222 {
223         NGM_BT3C_COOKIE,
224         NGM_BT3C_NODE_RESET_STAT,
225         "reset_stat",
226         NULL,
227         NULL
228 },
229 { 0, }
230 };
231
232 static struct ng_type   typestruct = {
233         .version =      NG_ABI_VERSION,
234         .name =         NG_BT3C_NODE_TYPE,
235         .constructor =  ng_bt3c_constructor,
236         .rcvmsg =       ng_bt3c_rcvmsg,
237         .shutdown =     ng_bt3c_shutdown,
238         .newhook =      ng_bt3c_newhook,
239         .connect =      ng_bt3c_connect,
240         .rcvdata =      ng_bt3c_rcvdata,
241         .disconnect =   ng_bt3c_disconnect,
242         .cmdlist =      ng_bt3c_cmdlist 
243 };
244
245 /*
246  * Netgraph node constructor. Do not allow to create node of this type.
247  */
248
249 static int
250 ng_bt3c_constructor(node_p node)
251 {
252         return (EINVAL);
253 } /* ng_bt3c_constructor */
254
255 /*
256  * Netgraph node destructor. Destroy node only when device has been detached
257  */
258
259 static int
260 ng_bt3c_shutdown(node_p node)
261 {
262         bt3c_softc_p    sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
263
264         /* Let old node go */
265         NG_NODE_SET_PRIVATE(node, NULL);
266         NG_NODE_UNREF(node);
267
268         /* Create new fresh one if we are not going down */
269         if (sc == NULL)
270                 goto out;
271
272         /* Create new Netgraph node */
273         if (ng_make_node_common(&typestruct, &sc->node) != 0) {
274                 device_printf(sc->dev, "Could not create Netgraph node\n");
275                 sc->node = NULL;
276                 goto out;
277         }
278
279         /* Name new Netgraph node */
280         if (ng_name_node(sc->node,  device_get_nameunit(sc->dev)) != 0) {
281                 device_printf(sc->dev, "Could not name Netgraph node\n");
282                 NG_NODE_UNREF(sc->node);
283                 sc->node = NULL;
284                 goto out;
285         }
286
287         NG_NODE_SET_PRIVATE(sc->node, sc);
288 out:
289         return (0);
290 } /* ng_bt3c_shutdown */
291
292 /*
293  * Create new hook. There can only be one.
294  */
295
296 static int
297 ng_bt3c_newhook(node_p node, hook_p hook, char const *name)
298 {
299         bt3c_softc_p    sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
300
301         if (strcmp(name, NG_BT3C_HOOK) != 0)
302                 return (EINVAL);
303
304         if (sc->hook != NULL)
305                 return (EISCONN);
306
307         sc->hook = hook;
308
309         return (0);
310 } /* ng_bt3c_newhook */
311
312 /*
313  * Connect hook. Say YEP, that's OK with me.
314  */
315
316 static int
317 ng_bt3c_connect(hook_p hook)
318 {
319         bt3c_softc_p    sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
320
321         if (hook != sc->hook) {
322                 sc->hook = NULL;
323                 return (EINVAL);
324         }
325
326         /* set the hook into queueing mode (for incoming (from wire) packets) */
327         NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
328
329         return (0);
330 } /* ng_bt3c_connect */
331
332 /*
333  * Disconnect hook
334  */
335
336 static int
337 ng_bt3c_disconnect(hook_p hook)
338 {
339         bt3c_softc_p    sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
340
341         /*
342          * We need to check for sc != NULL because we can be called from
343          * bt3c_pccard_detach() via ng_rmnode_self()
344          */
345
346         if (sc != NULL) {
347                 if (hook != sc->hook)
348                         return (EINVAL);
349
350                 IF_DRAIN(&sc->inq);
351                 IF_DRAIN(&sc->outq);
352
353                 sc->hook = NULL;
354         }
355
356         return (0);
357 } /* ng_bt3c_disconnect */
358
359 /*
360  * Process control message
361  */
362
363 static int
364 ng_bt3c_rcvmsg(node_p node, item_p item, hook_p lasthook)
365 {
366         bt3c_softc_p     sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
367         struct ng_mesg  *msg = NULL, *rsp = NULL;
368         int              error = 0;
369
370         if (sc == NULL) {
371                 NG_FREE_ITEM(item);
372                 return (EHOSTDOWN);
373         }
374
375         NGI_GET_MSG(item, msg);
376
377         switch (msg->header.typecookie) {
378         case NGM_GENERIC_COOKIE:
379                 switch (msg->header.cmd) {
380                 case NGM_TEXT_STATUS:
381                         NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT);
382                         if (rsp == NULL)
383                                 error = ENOMEM;
384                         else
385                                 snprintf(rsp->data, NG_TEXTRESPONSE,
386                                         "Hook: %s\n" \
387                                         "Flags: %#x\n" \
388                                         "Debug: %d\n"  \
389                                         "State: %d\n"  \
390                                         "IncmQ: [len:%d,max:%d]\n" \
391                                         "OutgQ: [len:%d,max:%d]\n",
392                                         (sc->hook != NULL)? NG_BT3C_HOOK : "",
393                                         sc->flags,
394                                         sc->debug,
395                                         sc->state,
396                                         _IF_QLEN(&sc->inq), /* XXX */
397                                         sc->inq.ifq_maxlen, /* XXX */
398                                         _IF_QLEN(&sc->outq), /* XXX */
399                                         sc->outq.ifq_maxlen /* XXX */
400                                         );
401                         break;
402
403                 default:
404                         error = EINVAL;
405                         break;
406                 }
407                 break;
408
409         case NGM_BT3C_COOKIE:
410                 switch (msg->header.cmd) {
411                 case NGM_BT3C_NODE_GET_STATE:
412                         NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_state_ep),
413                                 M_NOWAIT);
414                         if (rsp == NULL)
415                                 error = ENOMEM;
416                         else
417                                 *((ng_bt3c_node_state_ep *)(rsp->data)) = 
418                                         sc->state;
419                         break;
420
421                 case NGM_BT3C_NODE_SET_DEBUG:
422                         if (msg->header.arglen != sizeof(ng_bt3c_node_debug_ep))
423                                 error = EMSGSIZE;
424                         else
425                                 sc->debug =
426                                         *((ng_bt3c_node_debug_ep *)(msg->data));
427                         break;
428
429                 case NGM_BT3C_NODE_GET_DEBUG:
430                         NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_debug_ep),
431                                 M_NOWAIT);
432                         if (rsp == NULL)
433                                 error = ENOMEM;
434                         else
435                                 *((ng_bt3c_node_debug_ep *)(rsp->data)) = 
436                                         sc->debug;
437                         break;
438
439                 case NGM_BT3C_NODE_GET_QLEN:
440                         NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_qlen_ep),
441                                 M_NOWAIT);
442                         if (rsp == NULL) {
443                                 error = ENOMEM;
444                                 break;
445                         }
446
447                         switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) {
448                         case NGM_BT3C_NODE_IN_QUEUE:
449                                 ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue =
450                                         NGM_BT3C_NODE_IN_QUEUE;
451                                 ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen =
452                                         sc->inq.ifq_maxlen;
453                                 break;
454
455                         case NGM_BT3C_NODE_OUT_QUEUE:
456                                 ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue =
457                                         NGM_BT3C_NODE_OUT_QUEUE;
458                                 ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen =
459                                         sc->outq.ifq_maxlen;
460                                 break;
461
462                         default:
463                                 NG_FREE_MSG(rsp);
464                                 error = EINVAL;
465                                 break;
466                         }
467                         break;
468
469                 case NGM_BT3C_NODE_SET_QLEN:
470                         if (msg->header.arglen != sizeof(ng_bt3c_node_qlen_ep)){
471                                 error = EMSGSIZE;
472                                 break;
473                         }
474
475                         if (((ng_bt3c_node_qlen_ep *)(msg->data))->qlen <= 0) {
476                                 error = EINVAL;
477                                 break;
478                         }
479
480                         switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) {
481                         case NGM_BT3C_NODE_IN_QUEUE:
482                                 sc->inq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *)
483                                         (msg->data))->qlen; /* XXX */
484                                 break;
485
486                         case NGM_BT3C_NODE_OUT_QUEUE:
487                                 sc->outq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *)
488                                         (msg->data))->qlen; /* XXX */
489                                 break;
490
491                         default:
492                                 error = EINVAL;
493                                 break;
494                         }
495                         break;
496
497                 case NGM_BT3C_NODE_GET_STAT:
498                         NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_stat_ep),
499                                 M_NOWAIT);
500                         if (rsp == NULL)
501                                 error = ENOMEM;
502                         else
503                                 bcopy(&sc->stat, rsp->data,
504                                         sizeof(ng_bt3c_node_stat_ep));
505                         break;
506
507                 case NGM_BT3C_NODE_RESET_STAT:
508                         NG_BT3C_STAT_RESET(sc->stat);
509                         break;
510
511                 case NGM_BT3C_NODE_DOWNLOAD_FIRMWARE:
512                         if (msg->header.arglen < 
513                                         sizeof(ng_bt3c_firmware_block_ep))
514                                 error = EMSGSIZE;
515                         else    
516                                 bt3c_download_firmware(sc, msg->data,
517                                                         msg->header.arglen);
518                         break;
519
520                 default:
521                         error = EINVAL;
522                         break;
523                 }
524                 break;
525
526         default:
527                 error = EINVAL;
528                 break;
529         }
530
531         NG_RESPOND_MSG(error, node, item, rsp);
532         NG_FREE_MSG(msg);
533
534         return (error);
535 } /* ng_bt3c_rcvmsg */
536
537 /*
538  * Process data
539  */
540
541 static int
542 ng_bt3c_rcvdata(hook_p hook, item_p item)
543 {
544         bt3c_softc_p     sc = (bt3c_softc_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
545         struct mbuf     *m = NULL;
546         int              error = 0;
547
548         if (sc == NULL) {
549                 error = EHOSTDOWN;
550                 goto out;
551         }
552
553         if (hook != sc->hook) {
554                 error = EINVAL;
555                 goto out;
556         }
557
558         NGI_GET_M(item, m);
559
560         IF_LOCK(&sc->outq);
561         if (_IF_QFULL(&sc->outq)) {
562                 NG_BT3C_ERR(sc->dev,
563 "Outgoing queue is full. Dropping mbuf, len=%d\n", m->m_pkthdr.len);
564
565                 NG_BT3C_STAT_OERROR(sc->stat);
566
567                 NG_FREE_M(m);
568         } else 
569                 _IF_ENQUEUE(&sc->outq, m);
570         IF_UNLOCK(&sc->outq);
571
572         error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */);
573 out:
574         NG_FREE_ITEM(item);
575
576         return (error);
577 } /* ng_bt3c_rcvdata */
578
579 /****************************************************************************
580  ****************************************************************************
581  **                         PCMCIA driver specific
582  ****************************************************************************
583  ****************************************************************************/
584
585 /*
586  * PC Card (PCMCIA) probe routine
587  */
588
589 static struct pccard_product const      bt3c_pccard_products[] = {
590         PCMCIA_CARD(3COM, 3CRWB609),
591         { NULL, }
592 };
593
594 static int
595 bt3c_pccard_probe(device_t dev)
596 {
597         struct pccard_product const     *pp = NULL;
598
599         pp = pccard_product_lookup(dev, bt3c_pccard_products,
600                         sizeof(bt3c_pccard_products[0]), NULL);
601         if (pp == NULL)
602                 return (ENXIO);
603
604         device_set_desc(dev, pp->pp_name);
605
606         return (0);
607 } /* bt3c_pccard_probe */
608
609 /*
610  * PC Card (PCMCIA) attach routine
611  */
612
613 static int
614 bt3c_pccard_attach(device_t dev)
615 {
616         bt3c_softc_p    sc = (bt3c_softc_p) device_get_softc(dev);
617
618         /* Allocate I/O ports */
619         sc->iobase_rid = 0;
620         sc->iobase = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT,
621                         &sc->iobase_rid, 8, RF_ACTIVE);
622         if (sc->iobase == NULL) {
623                 device_printf(dev, "Could not allocate I/O ports\n");
624                 goto bad;
625         }
626         sc->iot = rman_get_bustag(sc->iobase);
627         sc->ioh = rman_get_bushandle(sc->iobase);
628
629         /* Allocate IRQ */
630         sc->irq_rid = 0;
631         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
632                         RF_ACTIVE);
633         if (sc->irq == NULL) {
634                 device_printf(dev, "Could not allocate IRQ\n");
635                 goto bad;
636         }
637
638         sc->irq_cookie = NULL;
639         if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, NULL, bt3c_intr, sc,
640                         &sc->irq_cookie) != 0) {
641                 device_printf(dev, "Could not setup ISR\n");
642                 goto bad;
643         }
644
645         /* Attach handler to TTY SWI thread */
646         sc->ith = NULL;
647         if (swi_add(&tty_intr_event, device_get_nameunit(dev),
648                         bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) {
649                 device_printf(dev, "Could not setup SWI ISR\n");
650                 goto bad;
651         }
652
653         /* Create Netgraph node */
654         if (ng_make_node_common(&typestruct, &sc->node) != 0) {
655                 device_printf(dev, "Could not create Netgraph node\n");
656                 sc->node = NULL;
657                 goto bad;
658         }
659
660         /* Name Netgraph node */
661         if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) {
662                 device_printf(dev, "Could not name Netgraph node\n");
663                 NG_NODE_UNREF(sc->node);
664                 sc->node = NULL;
665                 goto bad;
666         }
667
668         sc->dev = dev;
669         sc->debug = NG_BT3C_WARN_LEVEL;
670
671         sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN;
672         mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF);
673         mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF);
674
675         sc->state = NG_BT3C_W4_PKT_IND;
676         sc->want = 1;
677
678         NG_NODE_SET_PRIVATE(sc->node, sc);
679
680         gone_in_dev(dev, 13, "pccard removed");
681
682         return (0);
683 bad:
684         if (sc->ith != NULL) {
685                 swi_remove(sc->ith);
686                 sc->ith = NULL;
687         }
688
689         if (sc->irq != NULL) {
690                 if (sc->irq_cookie != NULL)
691                         bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
692
693                 bus_release_resource(dev, SYS_RES_IRQ,
694                         sc->irq_rid, sc->irq);
695
696                 sc->irq = NULL;
697                 sc->irq_rid = 0;
698         }
699
700         if (sc->iobase != NULL) {
701                 bus_release_resource(dev, SYS_RES_IOPORT,
702                         sc->iobase_rid, sc->iobase);
703
704                 sc->iobase = NULL;
705                 sc->iobase_rid = 0;
706         }
707
708         return (ENXIO);
709 } /* bt3c_pccacd_attach */
710
711 /*
712  * PC Card (PCMCIA) detach routine
713  */
714
715 static int
716 bt3c_pccard_detach(device_t dev)
717 {
718         bt3c_softc_p    sc = (bt3c_softc_p) device_get_softc(dev);
719
720         if (sc == NULL)
721                 return (0);
722
723         swi_remove(sc->ith);
724         sc->ith = NULL;
725
726         bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
727         bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
728         sc->irq_cookie = NULL;
729         sc->irq = NULL;
730         sc->irq_rid = 0;
731
732         bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
733         sc->iobase = NULL;
734         sc->iobase_rid = 0;
735
736         if (sc->node != NULL) {
737                 NG_NODE_SET_PRIVATE(sc->node, NULL);
738                 ng_rmnode_self(sc->node);
739                 sc->node = NULL;
740         }
741
742         NG_FREE_M(sc->m);
743         IF_DRAIN(&sc->inq);
744         IF_DRAIN(&sc->outq);
745
746         mtx_destroy(&sc->inq.ifq_mtx);
747         mtx_destroy(&sc->outq.ifq_mtx);
748
749         return (0);
750 } /* bt3c_pccacd_detach */
751
752 /*
753  * Interrupt service routine's
754  */
755
756 static void
757 bt3c_intr(void *context)
758 {
759         bt3c_softc_p    sc = (bt3c_softc_p) context;
760         u_int16_t       control, status;
761
762         if (sc == NULL || sc->ith == NULL) {
763                 printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE);
764                 return;
765         }
766
767         bt3c_read_control(sc, control);
768         if ((control & 0x80) == 0)
769                 return;
770
771         bt3c_read(sc, 0x7001, status);
772         NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status);
773
774         if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) {
775                 NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status);
776                 return;
777         }
778
779         /* Receive complete */
780         if (status & 0x0001)
781                 bt3c_receive(sc);
782
783         /* Record status and schedule SWI */
784         sc->status |= status;
785         swi_sched(sc->ith, 0);
786
787         /* Complete interrupt */
788         bt3c_write(sc, 0x7001, 0x0000);
789         bt3c_write_control(sc, control);
790 } /* bt3c_intr */
791
792 /*
793  * Receive data
794  */
795
796 static void
797 bt3c_receive(bt3c_softc_p sc)
798 {
799         u_int16_t       i, count, c;
800
801         /* Receive data from the card */
802         bt3c_read(sc, 0x7006, count);
803         NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count);
804
805         bt3c_set_address(sc, 0x7480);
806
807         for (i = 0; i < count; i++) {
808                 /* Allocate new mbuf if needed */
809                 if (sc->m == NULL) {
810                         sc->state = NG_BT3C_W4_PKT_IND;
811                         sc->want = 1;
812
813                         MGETHDR(sc->m, M_NOWAIT, MT_DATA);
814                         if (sc->m == NULL) {
815                                 NG_BT3C_ERR(sc->dev, "Could not get mbuf\n");
816                                 NG_BT3C_STAT_IERROR(sc->stat);
817
818                                 break; /* XXX lost of sync */
819                         }
820
821                         if (!(MCLGET(sc->m, M_NOWAIT))) {
822                                 NG_FREE_M(sc->m);
823
824                                 NG_BT3C_ERR(sc->dev, "Could not get cluster\n");
825                                 NG_BT3C_STAT_IERROR(sc->stat);
826
827                                 break; /* XXX lost of sync */
828                         }
829
830                         sc->m->m_len = sc->m->m_pkthdr.len = 0;
831                 }
832
833                 /* Read and append character to mbuf */
834                 bt3c_read_data(sc, c);
835                 if (sc->m->m_pkthdr.len >= MCLBYTES) {
836                         NG_BT3C_ERR(sc->dev, "Oversized frame\n");
837         
838                         NG_FREE_M(sc->m);
839                         sc->state = NG_BT3C_W4_PKT_IND;
840                         sc->want = 1;
841
842                         break; /* XXX lost of sync */
843                 }
844
845                 mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c;
846                 sc->m->m_pkthdr.len ++;
847
848                 NG_BT3C_INFO(sc->dev,
849 "Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len);
850
851                 if (sc->m->m_pkthdr.len < sc->want)
852                         continue; /* wait for more */
853
854                 switch (sc->state) {
855                 /* Got packet indicator */
856                 case NG_BT3C_W4_PKT_IND:
857                         NG_BT3C_INFO(sc->dev,
858 "Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *));
859
860                         sc->state = NG_BT3C_W4_PKT_HDR;
861
862                         /*
863                          * Since packet indicator included in the packet 
864                          * header just set sc->want to sizeof(packet header).
865                          */
866
867                         switch (*mtod(sc->m, u_int8_t *)) {
868                         case NG_HCI_ACL_DATA_PKT:
869                                 sc->want = sizeof(ng_hci_acldata_pkt_t);
870                                 break;
871
872                         case NG_HCI_SCO_DATA_PKT:
873                                 sc->want = sizeof(ng_hci_scodata_pkt_t);
874                                 break;
875
876                         case NG_HCI_EVENT_PKT:
877                                 sc->want = sizeof(ng_hci_event_pkt_t);
878                                 break;
879
880                         default:
881                                 NG_BT3C_ERR(sc->dev,
882 "Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *));
883
884                                 NG_BT3C_STAT_IERROR(sc->stat);
885
886                                 NG_FREE_M(sc->m);
887                                 sc->state = NG_BT3C_W4_PKT_IND;
888                                 sc->want = 1;
889                                 break;
890                         }
891                         break;
892
893                 /* Got packet header */
894                 case NG_BT3C_W4_PKT_HDR:
895                         sc->state = NG_BT3C_W4_PKT_DATA;
896
897                         switch (*mtod(sc->m, u_int8_t *)) {
898                         case NG_HCI_ACL_DATA_PKT:
899                                 c = le16toh(mtod(sc->m,
900                                         ng_hci_acldata_pkt_t *)->length);
901                                 break;
902
903                         case NG_HCI_SCO_DATA_PKT:
904                                 c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length;
905                                 break;
906
907                         case NG_HCI_EVENT_PKT:
908                                 c = mtod(sc->m, ng_hci_event_pkt_t *)->length;
909                                 break;
910
911                         default:
912                                 KASSERT(0,
913 ("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *)));
914                                 break;
915                          }
916
917                         NG_BT3C_INFO(sc->dev,
918 "Got packet header, packet type=%#x, got so far %d, payload size=%d\n",
919                                 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len,
920                                 c);
921
922                         if (c > 0) {
923                                 sc->want += c;
924                                 break;
925                         }
926
927                         /* else FALLTHROUGH and deliver frame */
928                         /* XXX is this true? should we deliver empty frame? */
929
930                 /* Got packet data */
931                 case NG_BT3C_W4_PKT_DATA:
932                         NG_BT3C_INFO(sc->dev,
933 "Got full packet, packet type=%#x, packet size=%d\n",
934                                 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len);
935
936                         NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len);
937                         NG_BT3C_STAT_PCKTS_RECV(sc->stat);
938
939                         IF_LOCK(&sc->inq);
940                         if (_IF_QFULL(&sc->inq)) {
941                                 NG_BT3C_ERR(sc->dev,
942 "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len);
943
944                                 NG_BT3C_STAT_IERROR(sc->stat);
945
946                                 NG_FREE_M(sc->m);
947                         } else {
948                                 _IF_ENQUEUE(&sc->inq, sc->m);
949                                 sc->m = NULL;
950                         }
951                         IF_UNLOCK(&sc->inq);
952
953                         sc->state = NG_BT3C_W4_PKT_IND;
954                         sc->want = 1;
955                         break;
956
957                 default:
958                         KASSERT(0,
959 ("Invalid node state=%d", sc->state));
960                         break;
961                 }
962         }
963
964         bt3c_write(sc, 0x7006, 0x0000);
965 } /* bt3c_receive */
966
967 /*
968  * SWI interrupt handler
969  * Netgraph part is handled via ng_send_fn() to avoid race with hook
970  * connection/disconnection
971  */
972
973 static void
974 bt3c_swi_intr(void *context)
975 {
976         bt3c_softc_p    sc = (bt3c_softc_p) context;
977         u_int16_t       data;
978
979         /* Receive complete */
980         if (sc->status & 0x0001) {
981                 sc->status &= ~0x0001; /* XXX is it safe? */
982
983                 if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0)
984                         NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n");
985         }
986
987         /* Send complete */
988         if (sc->status & 0x0002) {
989                 sc->status &= ~0x0002; /* XXX is it safe */
990
991                 if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0)
992                         NG_BT3C_ALERT(sc->dev, "Could not send frames!\n");
993         }
994
995         /* Antenna position */
996         if (sc->status & 0x0020) { 
997                 sc->status &= ~0x0020; /* XXX is it safe */
998
999                 bt3c_read(sc, 0x7002, data);
1000                 data &= 0x10;
1001
1002                 if (data)
1003                         sc->flags |= BT3C_ANTENNA_OUT;
1004                 else
1005                         sc->flags &= ~BT3C_ANTENNA_OUT;
1006
1007                 NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN");
1008         }
1009 } /* bt3c_swi_intr */
1010
1011 /*
1012  * Send all incoming frames to the upper layer
1013  */
1014
1015 static void
1016 bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2)
1017 {
1018         bt3c_softc_p     sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1019         struct mbuf     *m = NULL;
1020         int              error;
1021
1022         if (sc == NULL)
1023                 return;
1024
1025         if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
1026                 for (;;) {
1027                         IF_DEQUEUE(&sc->inq, m);
1028                         if (m == NULL)
1029                                 break;
1030
1031                         NG_SEND_DATA_ONLY(error, sc->hook, m);
1032                         if (error != 0)
1033                                 NG_BT3C_STAT_IERROR(sc->stat);
1034                 }
1035         } else {
1036                 IF_LOCK(&sc->inq);
1037                 for (;;) {
1038                         _IF_DEQUEUE(&sc->inq, m);
1039                         if (m == NULL)
1040                                 break;
1041
1042                         NG_BT3C_STAT_IERROR(sc->stat);
1043                         NG_FREE_M(m);
1044                 }
1045                 IF_UNLOCK(&sc->inq);
1046         }
1047 } /* bt3c_forward */
1048
1049 /*
1050  * Send more data to the device. Must be called when node is locked
1051  */
1052
1053 static void
1054 bt3c_send(node_p node, hook_p hook, void *arg, int completed)
1055 {
1056         bt3c_softc_p     sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1057         struct mbuf     *m = NULL;
1058         int              i, wrote, len;
1059
1060         if (sc == NULL)
1061                 return;
1062
1063         if (completed)
1064                 sc->flags &= ~BT3C_XMIT;
1065
1066         if (sc->flags & BT3C_XMIT)
1067                 return;
1068
1069         bt3c_set_address(sc, 0x7080);
1070
1071         for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) {
1072                 IF_DEQUEUE(&sc->outq, m);
1073                 if (m == NULL)
1074                         break;
1075
1076                 while (m != NULL) {
1077                         len = min((BT3C_FIFO_SIZE - wrote), m->m_len);
1078
1079                         for (i = 0; i < len; i++)
1080                                 bt3c_write_data(sc, m->m_data[i]);
1081
1082                         wrote += len;
1083                         m->m_data += len;
1084                         m->m_len -= len;
1085
1086                         if (m->m_len > 0)
1087                                 break;
1088
1089                         m = m_free(m);
1090                 }
1091
1092                 if (m != NULL) {
1093                         IF_PREPEND(&sc->outq, m);
1094                         break;
1095                 }
1096
1097                 NG_BT3C_STAT_PCKTS_SENT(sc->stat);
1098         }
1099
1100         if (wrote > 0) {
1101                 NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote);
1102                 NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote);
1103
1104                 bt3c_write(sc, 0x7005, wrote);
1105                 sc->flags |= BT3C_XMIT;
1106         }
1107 } /* bt3c_send */
1108
1109 /*
1110  * Download chip firmware
1111  */
1112
1113 static void
1114 bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size)
1115 {
1116         ng_bt3c_firmware_block_ep const *block = NULL;
1117         u_int16_t const                 *data = NULL;
1118         int                              i, size;
1119         u_int8_t                         c;
1120
1121         /* Reset */
1122         device_printf(sc->dev, "Reseting the card...\n");
1123         bt3c_write(sc, 0x8040, 0x0404);
1124         bt3c_write(sc, 0x8040, 0x0400);
1125         DELAY(1);
1126
1127         bt3c_write(sc, 0x8040, 0x0404);
1128         DELAY(17);
1129
1130         /* Download firmware */
1131         device_printf(sc->dev, "Starting firmware download process...\n");
1132
1133         for (size = 0; size < firmware_size; ) {
1134                 block = (ng_bt3c_firmware_block_ep const *)(firmware + size);
1135                 data = (u_int16_t const *)(block + 1);
1136
1137                 if (bootverbose)
1138                         device_printf(sc->dev, "Download firmware block, " \
1139                                 "address=%#08x, size=%d words, aligment=%d\n",
1140                                 block->block_address, block->block_size,
1141                                 block->block_alignment);
1142
1143                 bt3c_set_address(sc, block->block_address);
1144                 for (i = 0; i < block->block_size; i++)
1145                         bt3c_write_data(sc, data[i]);
1146
1147                 size += (sizeof(*block) + (block->block_size * 2) + 
1148                                 block->block_alignment);
1149         }
1150
1151         DELAY(17);
1152         device_printf(sc->dev, "Firmware download process complete\n");
1153
1154         /* Boot */
1155         device_printf(sc->dev, "Starting the card...\n");
1156         bt3c_set_address(sc, 0x3000);
1157         bt3c_read_control(sc, c);
1158         bt3c_write_control(sc, (c | 0x40));
1159         DELAY(17);
1160
1161         /* Clear registers */
1162         device_printf(sc->dev, "Clearing card registers...\n");
1163         bt3c_write(sc, 0x7006, 0x0000);
1164         bt3c_write(sc, 0x7005, 0x0000);
1165         bt3c_write(sc, 0x7001, 0x0000);
1166         DELAY(1000);
1167 } /* bt3c_download_firmware */
1168
1169 /****************************************************************************
1170  ****************************************************************************
1171  **                           Driver module
1172  ****************************************************************************
1173  ****************************************************************************/
1174
1175 /*
1176  * PC Card (PCMCIA) driver
1177  */
1178
1179 static device_method_t  bt3c_pccard_methods[] = {
1180         /* Device interface */
1181         DEVMETHOD(device_probe,         bt3c_pccard_probe),
1182         DEVMETHOD(device_attach,        bt3c_pccard_attach),
1183         DEVMETHOD(device_detach,        bt3c_pccard_detach),
1184
1185         { 0, 0 }
1186 };
1187
1188 static driver_t         bt3c_pccard_driver = {
1189         NG_BT3C_NODE_TYPE,
1190         bt3c_pccard_methods,
1191         sizeof(bt3c_softc_t)
1192 };
1193
1194 static devclass_t       bt3c_devclass;
1195
1196  
1197 /*
1198  * Load/Unload the driver module
1199  */
1200  
1201 static int
1202 bt3c_modevent(module_t mod, int event, void *data)
1203 {
1204         int     error;
1205  
1206         switch (event) {
1207         case MOD_LOAD:
1208                 error = ng_newtype(&typestruct);
1209                 if (error != 0)
1210                         printf("%s: Could not register Netgraph node type, " \
1211                                 "error=%d\n", NG_BT3C_NODE_TYPE, error);
1212                 break;
1213
1214         case MOD_UNLOAD:
1215                 error = ng_rmtype(&typestruct);
1216                 break;
1217
1218         default:
1219                 error = EOPNOTSUPP;
1220                 break;
1221         }
1222
1223         return (error);
1224 } /* bt3c_modevent */
1225
1226 DRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0);
1227 MODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION);
1228 MODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION);
1229 PCCARD_PNP_INFO(bt3c_pccard_products);