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