]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c
Merge lldb release_80 branch r351543, and resolve conflicts.
[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         return (0);
681 bad:
682         if (sc->ith != NULL) {
683                 swi_remove(sc->ith);
684                 sc->ith = NULL;
685         }
686
687         if (sc->irq != NULL) {
688                 if (sc->irq_cookie != NULL)
689                         bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
690
691                 bus_release_resource(dev, SYS_RES_IRQ,
692                         sc->irq_rid, sc->irq);
693
694                 sc->irq = NULL;
695                 sc->irq_rid = 0;
696         }
697
698         if (sc->iobase != NULL) {
699                 bus_release_resource(dev, SYS_RES_IOPORT,
700                         sc->iobase_rid, sc->iobase);
701
702                 sc->iobase = NULL;
703                 sc->iobase_rid = 0;
704         }
705
706         return (ENXIO);
707 } /* bt3c_pccacd_attach */
708
709 /*
710  * PC Card (PCMCIA) detach routine
711  */
712
713 static int
714 bt3c_pccard_detach(device_t dev)
715 {
716         bt3c_softc_p    sc = (bt3c_softc_p) device_get_softc(dev);
717
718         if (sc == NULL)
719                 return (0);
720
721         swi_remove(sc->ith);
722         sc->ith = NULL;
723
724         bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
725         bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
726         sc->irq_cookie = NULL;
727         sc->irq = NULL;
728         sc->irq_rid = 0;
729
730         bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
731         sc->iobase = NULL;
732         sc->iobase_rid = 0;
733
734         if (sc->node != NULL) {
735                 NG_NODE_SET_PRIVATE(sc->node, NULL);
736                 ng_rmnode_self(sc->node);
737                 sc->node = NULL;
738         }
739
740         NG_FREE_M(sc->m);
741         IF_DRAIN(&sc->inq);
742         IF_DRAIN(&sc->outq);
743
744         mtx_destroy(&sc->inq.ifq_mtx);
745         mtx_destroy(&sc->outq.ifq_mtx);
746
747         return (0);
748 } /* bt3c_pccacd_detach */
749
750 /*
751  * Interrupt service routine's
752  */
753
754 static void
755 bt3c_intr(void *context)
756 {
757         bt3c_softc_p    sc = (bt3c_softc_p) context;
758         u_int16_t       control, status;
759
760         if (sc == NULL || sc->ith == NULL) {
761                 printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE);
762                 return;
763         }
764
765         bt3c_read_control(sc, control);
766         if ((control & 0x80) == 0)
767                 return;
768
769         bt3c_read(sc, 0x7001, status);
770         NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status);
771
772         if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) {
773                 NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status);
774                 return;
775         }
776
777         /* Receive complete */
778         if (status & 0x0001)
779                 bt3c_receive(sc);
780
781         /* Record status and schedule SWI */
782         sc->status |= status;
783         swi_sched(sc->ith, 0);
784
785         /* Complete interrupt */
786         bt3c_write(sc, 0x7001, 0x0000);
787         bt3c_write_control(sc, control);
788 } /* bt3c_intr */
789
790 /*
791  * Receive data
792  */
793
794 static void
795 bt3c_receive(bt3c_softc_p sc)
796 {
797         u_int16_t       i, count, c;
798
799         /* Receive data from the card */
800         bt3c_read(sc, 0x7006, count);
801         NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count);
802
803         bt3c_set_address(sc, 0x7480);
804
805         for (i = 0; i < count; i++) {
806                 /* Allocate new mbuf if needed */
807                 if (sc->m == NULL) {
808                         sc->state = NG_BT3C_W4_PKT_IND;
809                         sc->want = 1;
810
811                         MGETHDR(sc->m, M_NOWAIT, MT_DATA);
812                         if (sc->m == NULL) {
813                                 NG_BT3C_ERR(sc->dev, "Could not get mbuf\n");
814                                 NG_BT3C_STAT_IERROR(sc->stat);
815
816                                 break; /* XXX lost of sync */
817                         }
818
819                         if (!(MCLGET(sc->m, M_NOWAIT))) {
820                                 NG_FREE_M(sc->m);
821
822                                 NG_BT3C_ERR(sc->dev, "Could not get cluster\n");
823                                 NG_BT3C_STAT_IERROR(sc->stat);
824
825                                 break; /* XXX lost of sync */
826                         }
827
828                         sc->m->m_len = sc->m->m_pkthdr.len = 0;
829                 }
830
831                 /* Read and append character to mbuf */
832                 bt3c_read_data(sc, c);
833                 if (sc->m->m_pkthdr.len >= MCLBYTES) {
834                         NG_BT3C_ERR(sc->dev, "Oversized frame\n");
835         
836                         NG_FREE_M(sc->m);
837                         sc->state = NG_BT3C_W4_PKT_IND;
838                         sc->want = 1;
839
840                         break; /* XXX lost of sync */
841                 }
842
843                 mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c;
844                 sc->m->m_pkthdr.len ++;
845
846                 NG_BT3C_INFO(sc->dev,
847 "Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len);
848
849                 if (sc->m->m_pkthdr.len < sc->want)
850                         continue; /* wait for more */
851
852                 switch (sc->state) {
853                 /* Got packet indicator */
854                 case NG_BT3C_W4_PKT_IND:
855                         NG_BT3C_INFO(sc->dev,
856 "Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *));
857
858                         sc->state = NG_BT3C_W4_PKT_HDR;
859
860                         /*
861                          * Since packet indicator included in the packet 
862                          * header just set sc->want to sizeof(packet header).
863                          */
864
865                         switch (*mtod(sc->m, u_int8_t *)) {
866                         case NG_HCI_ACL_DATA_PKT:
867                                 sc->want = sizeof(ng_hci_acldata_pkt_t);
868                                 break;
869
870                         case NG_HCI_SCO_DATA_PKT:
871                                 sc->want = sizeof(ng_hci_scodata_pkt_t);
872                                 break;
873
874                         case NG_HCI_EVENT_PKT:
875                                 sc->want = sizeof(ng_hci_event_pkt_t);
876                                 break;
877
878                         default:
879                                 NG_BT3C_ERR(sc->dev,
880 "Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *));
881
882                                 NG_BT3C_STAT_IERROR(sc->stat);
883
884                                 NG_FREE_M(sc->m);
885                                 sc->state = NG_BT3C_W4_PKT_IND;
886                                 sc->want = 1;
887                                 break;
888                         }
889                         break;
890
891                 /* Got packet header */
892                 case NG_BT3C_W4_PKT_HDR:
893                         sc->state = NG_BT3C_W4_PKT_DATA;
894
895                         switch (*mtod(sc->m, u_int8_t *)) {
896                         case NG_HCI_ACL_DATA_PKT:
897                                 c = le16toh(mtod(sc->m,
898                                         ng_hci_acldata_pkt_t *)->length);
899                                 break;
900
901                         case NG_HCI_SCO_DATA_PKT:
902                                 c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length;
903                                 break;
904
905                         case NG_HCI_EVENT_PKT:
906                                 c = mtod(sc->m, ng_hci_event_pkt_t *)->length;
907                                 break;
908
909                         default:
910                                 KASSERT(0,
911 ("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *)));
912                                 break;
913                          }
914
915                         NG_BT3C_INFO(sc->dev,
916 "Got packet header, packet type=%#x, got so far %d, payload size=%d\n",
917                                 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len,
918                                 c);
919
920                         if (c > 0) {
921                                 sc->want += c;
922                                 break;
923                         }
924
925                         /* else FALLTHROUGH and deliver frame */
926                         /* XXX is this true? should we deliver empty frame? */
927
928                 /* Got packet data */
929                 case NG_BT3C_W4_PKT_DATA:
930                         NG_BT3C_INFO(sc->dev,
931 "Got full packet, packet type=%#x, packet size=%d\n",
932                                 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len);
933
934                         NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len);
935                         NG_BT3C_STAT_PCKTS_RECV(sc->stat);
936
937                         IF_LOCK(&sc->inq);
938                         if (_IF_QFULL(&sc->inq)) {
939                                 NG_BT3C_ERR(sc->dev,
940 "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len);
941
942                                 NG_BT3C_STAT_IERROR(sc->stat);
943
944                                 NG_FREE_M(sc->m);
945                         } else {
946                                 _IF_ENQUEUE(&sc->inq, sc->m);
947                                 sc->m = NULL;
948                         }
949                         IF_UNLOCK(&sc->inq);
950
951                         sc->state = NG_BT3C_W4_PKT_IND;
952                         sc->want = 1;
953                         break;
954
955                 default:
956                         KASSERT(0,
957 ("Invalid node state=%d", sc->state));
958                         break;
959                 }
960         }
961
962         bt3c_write(sc, 0x7006, 0x0000);
963 } /* bt3c_receive */
964
965 /*
966  * SWI interrupt handler
967  * Netgraph part is handled via ng_send_fn() to avoid race with hook
968  * connection/disconnection
969  */
970
971 static void
972 bt3c_swi_intr(void *context)
973 {
974         bt3c_softc_p    sc = (bt3c_softc_p) context;
975         u_int16_t       data;
976
977         /* Receive complete */
978         if (sc->status & 0x0001) {
979                 sc->status &= ~0x0001; /* XXX is it safe? */
980
981                 if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0)
982                         NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n");
983         }
984
985         /* Send complete */
986         if (sc->status & 0x0002) {
987                 sc->status &= ~0x0002; /* XXX is it safe */
988
989                 if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0)
990                         NG_BT3C_ALERT(sc->dev, "Could not send frames!\n");
991         }
992
993         /* Antenna position */
994         if (sc->status & 0x0020) { 
995                 sc->status &= ~0x0020; /* XXX is it safe */
996
997                 bt3c_read(sc, 0x7002, data);
998                 data &= 0x10;
999
1000                 if (data)
1001                         sc->flags |= BT3C_ANTENNA_OUT;
1002                 else
1003                         sc->flags &= ~BT3C_ANTENNA_OUT;
1004
1005                 NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN");
1006         }
1007 } /* bt3c_swi_intr */
1008
1009 /*
1010  * Send all incoming frames to the upper layer
1011  */
1012
1013 static void
1014 bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2)
1015 {
1016         bt3c_softc_p     sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1017         struct mbuf     *m = NULL;
1018         int              error;
1019
1020         if (sc == NULL)
1021                 return;
1022
1023         if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
1024                 for (;;) {
1025                         IF_DEQUEUE(&sc->inq, m);
1026                         if (m == NULL)
1027                                 break;
1028
1029                         NG_SEND_DATA_ONLY(error, sc->hook, m);
1030                         if (error != 0)
1031                                 NG_BT3C_STAT_IERROR(sc->stat);
1032                 }
1033         } else {
1034                 IF_LOCK(&sc->inq);
1035                 for (;;) {
1036                         _IF_DEQUEUE(&sc->inq, m);
1037                         if (m == NULL)
1038                                 break;
1039
1040                         NG_BT3C_STAT_IERROR(sc->stat);
1041                         NG_FREE_M(m);
1042                 }
1043                 IF_UNLOCK(&sc->inq);
1044         }
1045 } /* bt3c_forward */
1046
1047 /*
1048  * Send more data to the device. Must be called when node is locked
1049  */
1050
1051 static void
1052 bt3c_send(node_p node, hook_p hook, void *arg, int completed)
1053 {
1054         bt3c_softc_p     sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1055         struct mbuf     *m = NULL;
1056         int              i, wrote, len;
1057
1058         if (sc == NULL)
1059                 return;
1060
1061         if (completed)
1062                 sc->flags &= ~BT3C_XMIT;
1063
1064         if (sc->flags & BT3C_XMIT)
1065                 return;
1066
1067         bt3c_set_address(sc, 0x7080);
1068
1069         for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) {
1070                 IF_DEQUEUE(&sc->outq, m);
1071                 if (m == NULL)
1072                         break;
1073
1074                 while (m != NULL) {
1075                         len = min((BT3C_FIFO_SIZE - wrote), m->m_len);
1076
1077                         for (i = 0; i < len; i++)
1078                                 bt3c_write_data(sc, m->m_data[i]);
1079
1080                         wrote += len;
1081                         m->m_data += len;
1082                         m->m_len -= len;
1083
1084                         if (m->m_len > 0)
1085                                 break;
1086
1087                         m = m_free(m);
1088                 }
1089
1090                 if (m != NULL) {
1091                         IF_PREPEND(&sc->outq, m);
1092                         break;
1093                 }
1094
1095                 NG_BT3C_STAT_PCKTS_SENT(sc->stat);
1096         }
1097
1098         if (wrote > 0) {
1099                 NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote);
1100                 NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote);
1101
1102                 bt3c_write(sc, 0x7005, wrote);
1103                 sc->flags |= BT3C_XMIT;
1104         }
1105 } /* bt3c_send */
1106
1107 /*
1108  * Download chip firmware
1109  */
1110
1111 static void
1112 bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size)
1113 {
1114         ng_bt3c_firmware_block_ep const *block = NULL;
1115         u_int16_t const                 *data = NULL;
1116         int                              i, size;
1117         u_int8_t                         c;
1118
1119         /* Reset */
1120         device_printf(sc->dev, "Reseting the card...\n");
1121         bt3c_write(sc, 0x8040, 0x0404);
1122         bt3c_write(sc, 0x8040, 0x0400);
1123         DELAY(1);
1124
1125         bt3c_write(sc, 0x8040, 0x0404);
1126         DELAY(17);
1127
1128         /* Download firmware */
1129         device_printf(sc->dev, "Starting firmware download process...\n");
1130
1131         for (size = 0; size < firmware_size; ) {
1132                 block = (ng_bt3c_firmware_block_ep const *)(firmware + size);
1133                 data = (u_int16_t const *)(block + 1);
1134
1135                 if (bootverbose)
1136                         device_printf(sc->dev, "Download firmware block, " \
1137                                 "address=%#08x, size=%d words, aligment=%d\n",
1138                                 block->block_address, block->block_size,
1139                                 block->block_alignment);
1140
1141                 bt3c_set_address(sc, block->block_address);
1142                 for (i = 0; i < block->block_size; i++)
1143                         bt3c_write_data(sc, data[i]);
1144
1145                 size += (sizeof(*block) + (block->block_size * 2) + 
1146                                 block->block_alignment);
1147         }
1148
1149         DELAY(17);
1150         device_printf(sc->dev, "Firmware download process complete\n");
1151
1152         /* Boot */
1153         device_printf(sc->dev, "Starting the card...\n");
1154         bt3c_set_address(sc, 0x3000);
1155         bt3c_read_control(sc, c);
1156         bt3c_write_control(sc, (c | 0x40));
1157         DELAY(17);
1158
1159         /* Clear registers */
1160         device_printf(sc->dev, "Clearing card registers...\n");
1161         bt3c_write(sc, 0x7006, 0x0000);
1162         bt3c_write(sc, 0x7005, 0x0000);
1163         bt3c_write(sc, 0x7001, 0x0000);
1164         DELAY(1000);
1165 } /* bt3c_download_firmware */
1166
1167 /****************************************************************************
1168  ****************************************************************************
1169  **                           Driver module
1170  ****************************************************************************
1171  ****************************************************************************/
1172
1173 /*
1174  * PC Card (PCMCIA) driver
1175  */
1176
1177 static device_method_t  bt3c_pccard_methods[] = {
1178         /* Device interface */
1179         DEVMETHOD(device_probe,         bt3c_pccard_probe),
1180         DEVMETHOD(device_attach,        bt3c_pccard_attach),
1181         DEVMETHOD(device_detach,        bt3c_pccard_detach),
1182
1183         { 0, 0 }
1184 };
1185
1186 static driver_t         bt3c_pccard_driver = {
1187         NG_BT3C_NODE_TYPE,
1188         bt3c_pccard_methods,
1189         sizeof(bt3c_softc_t)
1190 };
1191
1192 static devclass_t       bt3c_devclass;
1193
1194  
1195 /*
1196  * Load/Unload the driver module
1197  */
1198  
1199 static int
1200 bt3c_modevent(module_t mod, int event, void *data)
1201 {
1202         int     error;
1203  
1204         switch (event) {
1205         case MOD_LOAD:
1206                 error = ng_newtype(&typestruct);
1207                 if (error != 0)
1208                         printf("%s: Could not register Netgraph node type, " \
1209                                 "error=%d\n", NG_BT3C_NODE_TYPE, error);
1210                 break;
1211
1212         case MOD_UNLOAD:
1213                 error = ng_rmtype(&typestruct);
1214                 break;
1215
1216         default:
1217                 error = EOPNOTSUPP;
1218                 break;
1219         }
1220
1221         return (error);
1222 } /* bt3c_modevent */
1223
1224 DRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0);
1225 MODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION);
1226 MODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION);
1227 PCCARD_PNP_INFO(bt3c_pccard_products);