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