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: src/sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c,v 1.20 2007/02/23 12:19:02 piso Exp $
32  * $DragonFly: src/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c,v 1.2 2008/06/26 23:05:40 dillon Exp $
33  * $DragonFly: src/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c,v 1.2 2008/06/26 23:05:40 dillon Exp $
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 "ng_message.h"
69 #include "netgraph.h"
70 #include "ng_parse.h"
71 #include "bluetooth/include/ng_bluetooth.h"
72 #include "bluetooth/include/ng_hci.h"
73 #include "bluetooth/include/ng_bt3c.h"
74 #include "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_WAITOK | M_NULLOK);
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_WAITOK | M_NULLOK);
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_WAITOK | M_NULLOK);
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_WAITOK | M_NULLOK);
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_WAITOK | M_NULLOK);
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 		_IF_DROP(&sc->outq);
566 		NG_BT3C_STAT_OERROR(sc->stat);
567 
568 		NG_FREE_M(m);
569 	} else
570 		_IF_ENQUEUE(&sc->outq, m);
571 	IF_UNLOCK(&sc->outq);
572 
573 	error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */);
574 out:
575         NG_FREE_ITEM(item);
576 
577 	return (error);
578 } /* ng_bt3c_rcvdata */
579 
580 /****************************************************************************
581  ****************************************************************************
582  **                         PCMCIA driver specific
583  ****************************************************************************
584  ****************************************************************************/
585 
586 /*
587  * PC Card (PCMCIA) probe routine
588  */
589 
590 static int
591 bt3c_pccard_probe(device_t dev)
592 {
593 	static struct pccard_product const	bt3c_pccard_products[] = {
594 		PCMCIA_CARD(3COM, 3CRWB609),
595 		{ NULL, }
596 	};
597 
598 	struct pccard_product const	*pp = NULL;
599 
600 	pp = pccard_product_lookup(dev, bt3c_pccard_products,
601 			sizeof(bt3c_pccard_products[0]), NULL);
602 	if (pp == NULL)
603 		return (ENXIO);
604 
605 	device_set_desc(dev, pp->pp_name);
606 
607 	return (0);
608 } /* bt3c_pccard_probe */
609 
610 /*
611  * PC Card (PCMCIA) attach routine
612  */
613 
614 static int
615 bt3c_pccard_attach(device_t dev)
616 {
617 	bt3c_softc_p	sc = (bt3c_softc_p) device_get_softc(dev);
618 
619 	/* Allocate I/O ports */
620 	sc->iobase_rid = 0;
621 	sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid,
622 			0, ~0, 8, RF_ACTIVE);
623 	if (sc->iobase == NULL) {
624 		device_printf(dev, "Could not allocate I/O ports\n");
625 		goto bad;
626 	}
627 	sc->iot = rman_get_bustag(sc->iobase);
628 	sc->ioh = rman_get_bushandle(sc->iobase);
629 
630 	/* Allocate IRQ */
631 	sc->irq_rid = 0;
632 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
633 			RF_ACTIVE);
634 	if (sc->irq == NULL) {
635 		device_printf(dev, "Could not allocate IRQ\n");
636 		goto bad;
637 	}
638 
639 	sc->irq_cookie = NULL;
640 	if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, NULL, bt3c_intr, sc,
641 			&sc->irq_cookie) != 0) {
642 		device_printf(dev, "Could not setup ISR\n");
643 		goto bad;
644 	}
645 
646 	/* Attach handler to TTY SWI thread */
647 	sc->ith = NULL;
648 	if (swi_add(&tty_intr_event, device_get_nameunit(dev),
649 			bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) {
650 		device_printf(dev, "Could not setup SWI ISR\n");
651 		goto bad;
652 	}
653 
654 	/* Create Netgraph node */
655 	if (ng_make_node_common(&typestruct, &sc->node) != 0) {
656 		device_printf(dev, "Could not create Netgraph node\n");
657 		sc->node = NULL;
658 		goto bad;
659 	}
660 
661 	/* Name Netgraph node */
662 	if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) {
663 		device_printf(dev, "Could not name Netgraph node\n");
664 		NG_NODE_UNREF(sc->node);
665 		sc->node = NULL;
666 		goto bad;
667 	}
668 
669 	sc->dev = dev;
670 	sc->debug = NG_BT3C_WARN_LEVEL;
671 
672 	sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN;
673 	mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF);
674 	mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF);
675 
676 	sc->state = NG_BT3C_W4_PKT_IND;
677 	sc->want = 1;
678 
679 	NG_NODE_SET_PRIVATE(sc->node, sc);
680 
681 	return (0);
682 bad:
683 	if (sc->ith != NULL) {
684 		swi_remove(sc->ith);
685 		sc->ith = NULL;
686 	}
687 
688 	if (sc->irq != NULL) {
689 		if (sc->irq_cookie != NULL)
690 			bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
691 
692 		bus_release_resource(dev, SYS_RES_IRQ,
693 			sc->irq_rid, sc->irq);
694 
695 		sc->irq = NULL;
696 		sc->irq_rid = 0;
697 	}
698 
699 	if (sc->iobase != NULL) {
700 		bus_release_resource(dev, SYS_RES_IOPORT,
701 			sc->iobase_rid, sc->iobase);
702 
703 		sc->iobase = NULL;
704 		sc->iobase_rid = 0;
705 	}
706 
707 	return (ENXIO);
708 } /* bt3c_pccacd_attach */
709 
710 /*
711  * PC Card (PCMCIA) detach routine
712  */
713 
714 static int
715 bt3c_pccard_detach(device_t dev)
716 {
717 	bt3c_softc_p	sc = (bt3c_softc_p) device_get_softc(dev);
718 
719 	if (sc == NULL)
720 		return (0);
721 
722 	swi_remove(sc->ith);
723 	sc->ith = NULL;
724 
725 	bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
726 	bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
727 	sc->irq_cookie = NULL;
728 	sc->irq = NULL;
729 	sc->irq_rid = 0;
730 
731 	bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
732 	sc->iobase = NULL;
733 	sc->iobase_rid = 0;
734 
735 	if (sc->node != NULL) {
736 		NG_NODE_SET_PRIVATE(sc->node, NULL);
737 		ng_rmnode_self(sc->node);
738 		sc->node = NULL;
739 	}
740 
741 	NG_FREE_M(sc->m);
742 	IF_DRAIN(&sc->inq);
743 	IF_DRAIN(&sc->outq);
744 
745 	mtx_destroy(&sc->inq.ifq_mtx);
746 	mtx_destroy(&sc->outq.ifq_mtx);
747 
748 	return (0);
749 } /* bt3c_pccacd_detach */
750 
751 /*
752  * Interrupt service routine's
753  */
754 
755 static void
756 bt3c_intr(void *context)
757 {
758 	bt3c_softc_p	sc = (bt3c_softc_p) context;
759 	u_int16_t	control, status;
760 
761 	if (sc == NULL || sc->ith == NULL) {
762 		printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE);
763 		return;
764 	}
765 
766 	bt3c_read_control(sc, control);
767 	if ((control & 0x80) == 0)
768 		return;
769 
770 	bt3c_read(sc, 0x7001, status);
771 	NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status);
772 
773 	if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) {
774 		NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status);
775 		return;
776 	}
777 
778 	/* Receive complete */
779 	if (status & 0x0001)
780 		bt3c_receive(sc);
781 
782 	/* Record status and schedule SWI */
783 	sc->status |= status;
784 	swi_sched(sc->ith, 0);
785 
786 	/* Complete interrupt */
787 	bt3c_write(sc, 0x7001, 0x0000);
788 	bt3c_write_control(sc, control);
789 } /* bt3c_intr */
790 
791 /*
792  * Receive data
793  */
794 
795 static void
796 bt3c_receive(bt3c_softc_p sc)
797 {
798 	u_int16_t	i, count, c;
799 
800 	/* Receive data from the card */
801 	bt3c_read(sc, 0x7006, count);
802 	NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count);
803 
804 	bt3c_set_address(sc, 0x7480);
805 
806 	for (i = 0; i < count; i++) {
807 		/* Allocate new mbuf if needed */
808 		if (sc->m == NULL) {
809 			sc->state = NG_BT3C_W4_PKT_IND;
810 			sc->want = 1;
811 
812 			MGETHDR(sc->m, MB_DONTWAIT, MT_DATA);
813 			if (sc->m == NULL) {
814 				NG_BT3C_ERR(sc->dev, "Could not get mbuf\n");
815 				NG_BT3C_STAT_IERROR(sc->stat);
816 
817 				break; /* XXX lost of sync */
818 			}
819 
820 			MCLGET(sc->m, MB_DONTWAIT);
821 			if (!(sc->m->m_flags & M_EXT)) {
822 				NG_FREE_M(sc->m);
823 
824 				NG_BT3C_ERR(sc->dev, "Could not get cluster\n");
825 				NG_BT3C_STAT_IERROR(sc->stat);
826 
827 				break; /* XXX lost of sync */
828 			}
829 
830 			sc->m->m_len = sc->m->m_pkthdr.len = 0;
831 		}
832 
833 		/* Read and append character to mbuf */
834 		bt3c_read_data(sc, c);
835 		if (sc->m->m_pkthdr.len >= MCLBYTES) {
836 			NG_BT3C_ERR(sc->dev, "Oversized frame\n");
837 
838 			NG_FREE_M(sc->m);
839 			sc->state = NG_BT3C_W4_PKT_IND;
840 			sc->want = 1;
841 
842 			break; /* XXX lost of sync */
843 		}
844 
845 		mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c;
846 		sc->m->m_pkthdr.len ++;
847 
848 		NG_BT3C_INFO(sc->dev,
849 "Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len);
850 
851 		if (sc->m->m_pkthdr.len < sc->want)
852 			continue; /* wait for more */
853 
854 		switch (sc->state) {
855 		/* Got packet indicator */
856 		case NG_BT3C_W4_PKT_IND:
857 			NG_BT3C_INFO(sc->dev,
858 "Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *));
859 
860 			sc->state = NG_BT3C_W4_PKT_HDR;
861 
862 			/*
863 			 * Since packet indicator included in the packet
864 			 * header just set sc->want to sizeof(packet header).
865 			 */
866 
867 			switch (*mtod(sc->m, u_int8_t *)) {
868 			case NG_HCI_ACL_DATA_PKT:
869 				sc->want = sizeof(ng_hci_acldata_pkt_t);
870 				break;
871 
872 			case NG_HCI_SCO_DATA_PKT:
873 				sc->want = sizeof(ng_hci_scodata_pkt_t);
874 				break;
875 
876 			case NG_HCI_EVENT_PKT:
877 				sc->want = sizeof(ng_hci_event_pkt_t);
878 				break;
879 
880 			default:
881        	                	NG_BT3C_ERR(sc->dev,
882 "Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *));
883 
884 				NG_BT3C_STAT_IERROR(sc->stat);
885 
886 				NG_FREE_M(sc->m);
887 				sc->state = NG_BT3C_W4_PKT_IND;
888 				sc->want = 1;
889 				break;
890 			}
891 			break;
892 
893 		/* Got packet header */
894 		case NG_BT3C_W4_PKT_HDR:
895 			sc->state = NG_BT3C_W4_PKT_DATA;
896 
897 			switch (*mtod(sc->m, u_int8_t *)) {
898 			case NG_HCI_ACL_DATA_PKT:
899 				c = le16toh(mtod(sc->m,
900 					ng_hci_acldata_pkt_t *)->length);
901 				break;
902 
903 			case NG_HCI_SCO_DATA_PKT:
904 				c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length;
905 				break;
906 
907 			case NG_HCI_EVENT_PKT:
908 				c = mtod(sc->m, ng_hci_event_pkt_t *)->length;
909 				break;
910 
911 			default:
912 				KASSERT(0,
913 ("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *)));
914 				break;
915        	        	 }
916 
917 			NG_BT3C_INFO(sc->dev,
918 "Got packet header, packet type=%#x, got so far %d, payload size=%d\n",
919 				*mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len,
920 				c);
921 
922 			if (c > 0) {
923 				sc->want += c;
924 				break;
925 			}
926 
927 			/* else FALLTHROUGH and deliver frame */
928 			/* XXX is this true? should we deliver empty frame? */
929 
930 		/* Got packet data */
931 		case NG_BT3C_W4_PKT_DATA:
932 			NG_BT3C_INFO(sc->dev,
933 "Got full packet, packet type=%#x, packet size=%d\n",
934 				*mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len);
935 
936 			NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len);
937 			NG_BT3C_STAT_PCKTS_RECV(sc->stat);
938 
939 			IF_LOCK(&sc->inq);
940 			if (_IF_QFULL(&sc->inq)) {
941 				NG_BT3C_ERR(sc->dev,
942 "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len);
943 
944 				_IF_DROP(&sc->inq);
945 				NG_BT3C_STAT_IERROR(sc->stat);
946 
947 				NG_FREE_M(sc->m);
948 			} else {
949 				_IF_ENQUEUE(&sc->inq, sc->m);
950 				sc->m = NULL;
951 			}
952 			IF_UNLOCK(&sc->inq);
953 
954 			sc->state = NG_BT3C_W4_PKT_IND;
955 			sc->want = 1;
956 			break;
957 
958 		default:
959 			KASSERT(0,
960 ("Invalid node state=%d", sc->state));
961 			break;
962 		}
963 	}
964 
965 	bt3c_write(sc, 0x7006, 0x0000);
966 } /* bt3c_receive */
967 
968 /*
969  * SWI interrupt handler
970  * Netgraph part is handled via ng_send_fn() to avoid race with hook
971  * connection/disconnection
972  */
973 
974 static void
975 bt3c_swi_intr(void *context)
976 {
977 	bt3c_softc_p	sc = (bt3c_softc_p) context;
978 	u_int16_t	data;
979 
980 	/* Receive complete */
981 	if (sc->status & 0x0001) {
982 		sc->status &= ~0x0001; /* XXX is it safe? */
983 
984 		if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0)
985 			NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n");
986 	}
987 
988 	/* Send complete */
989 	if (sc->status & 0x0002) {
990 		sc->status &= ~0x0002; /* XXX is it safe */
991 
992 		if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0)
993 			NG_BT3C_ALERT(sc->dev, "Could not send frames!\n");
994 	}
995 
996 	/* Antenna position */
997 	if (sc->status & 0x0020) {
998 		sc->status &= ~0x0020; /* XXX is it safe */
999 
1000 		bt3c_read(sc, 0x7002, data);
1001 		data &= 0x10;
1002 
1003 		if (data)
1004 			sc->flags |= BT3C_ANTENNA_OUT;
1005 		else
1006 			sc->flags &= ~BT3C_ANTENNA_OUT;
1007 
1008 		NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN");
1009 	}
1010 } /* bt3c_swi_intr */
1011 
1012 /*
1013  * Send all incoming frames to the upper layer
1014  */
1015 
1016 static void
1017 bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2)
1018 {
1019 	bt3c_softc_p	 sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1020 	struct mbuf	*m = NULL;
1021 	int		 error;
1022 
1023 	if (sc == NULL)
1024 		return;
1025 
1026 	if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
1027 		for (;;) {
1028 			IF_DEQUEUE(&sc->inq, m);
1029 			if (m == NULL)
1030 				break;
1031 
1032 			NG_SEND_DATA_ONLY(error, sc->hook, m);
1033 			if (error != 0)
1034 				NG_BT3C_STAT_IERROR(sc->stat);
1035 		}
1036 	} else {
1037 		IF_LOCK(&sc->inq);
1038 		for (;;) {
1039 			_IF_DEQUEUE(&sc->inq, m);
1040 			if (m == NULL)
1041 				break;
1042 
1043 			NG_BT3C_STAT_IERROR(sc->stat);
1044 			NG_FREE_M(m);
1045 		}
1046 		IF_UNLOCK(&sc->inq);
1047 	}
1048 } /* bt3c_forward */
1049 
1050 /*
1051  * Send more data to the device. Must be called when node is locked
1052  */
1053 
1054 static void
1055 bt3c_send(node_p node, hook_p hook, void *arg, int completed)
1056 {
1057 	bt3c_softc_p	 sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1058 	struct mbuf	*m = NULL;
1059 	int		 i, wrote, len;
1060 
1061 	if (sc == NULL)
1062 		return;
1063 
1064 	if (completed)
1065 		sc->flags &= ~BT3C_XMIT;
1066 
1067 	if (sc->flags & BT3C_XMIT)
1068 		return;
1069 
1070 	bt3c_set_address(sc, 0x7080);
1071 
1072 	for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) {
1073 		IF_DEQUEUE(&sc->outq, m);
1074 		if (m == NULL)
1075 			break;
1076 
1077 		while (m != NULL) {
1078 			len = min((BT3C_FIFO_SIZE - wrote), m->m_len);
1079 
1080 			for (i = 0; i < len; i++)
1081 				bt3c_write_data(sc, m->m_data[i]);
1082 
1083 			wrote += len;
1084 			m->m_data += len;
1085 			m->m_len -= len;
1086 
1087 			if (m->m_len > 0)
1088 				break;
1089 
1090 			m = m_free(m);
1091 		}
1092 
1093 		if (m != NULL) {
1094 			IF_PREPEND(&sc->outq, m);
1095 			break;
1096 		}
1097 
1098 		NG_BT3C_STAT_PCKTS_SENT(sc->stat);
1099 	}
1100 
1101 	if (wrote > 0) {
1102 		NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote);
1103 		NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote);
1104 
1105 		bt3c_write(sc, 0x7005, wrote);
1106 		sc->flags |= BT3C_XMIT;
1107 	}
1108 } /* bt3c_send */
1109 
1110 /*
1111  * Download chip firmware
1112  */
1113 
1114 static void
1115 bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size)
1116 {
1117 	ng_bt3c_firmware_block_ep const	*block = NULL;
1118 	u_int16_t const			*data = NULL;
1119 	int				 i, size;
1120 	u_int8_t			 c;
1121 
1122 	/* Reset */
1123 	device_printf(sc->dev, "Reseting the card...\n");
1124 	bt3c_write(sc, 0x8040, 0x0404);
1125 	bt3c_write(sc, 0x8040, 0x0400);
1126 	DELAY(1);
1127 
1128 	bt3c_write(sc, 0x8040, 0x0404);
1129 	DELAY(17);
1130 
1131 	/* Download firmware */
1132 	device_printf(sc->dev, "Starting firmware download process...\n");
1133 
1134 	for (size = 0; size < firmware_size; ) {
1135 		block = (ng_bt3c_firmware_block_ep const *)(firmware + size);
1136 		data = (u_int16_t const *)(block + 1);
1137 
1138 		if (bootverbose)
1139 			device_printf(sc->dev, "Download firmware block, " \
1140 				"address=%#08x, size=%d words, aligment=%d\n",
1141 				block->block_address, block->block_size,
1142 				block->block_alignment);
1143 
1144 		bt3c_set_address(sc, block->block_address);
1145 		for (i = 0; i < block->block_size; i++)
1146 			bt3c_write_data(sc, data[i]);
1147 
1148 		size += (sizeof(*block) + (block->block_size * 2) +
1149 				block->block_alignment);
1150 	}
1151 
1152 	DELAY(17);
1153 	device_printf(sc->dev, "Firmware download process complete\n");
1154 
1155 	/* Boot */
1156 	device_printf(sc->dev, "Starting the card...\n");
1157 	bt3c_set_address(sc, 0x3000);
1158 	bt3c_read_control(sc, c);
1159 	bt3c_write_control(sc, (c | 0x40));
1160 	DELAY(17);
1161 
1162 	/* Clear registers */
1163 	device_printf(sc->dev, "Clearing card registers...\n");
1164 	bt3c_write(sc, 0x7006, 0x0000);
1165 	bt3c_write(sc, 0x7005, 0x0000);
1166 	bt3c_write(sc, 0x7001, 0x0000);
1167 	DELAY(1000);
1168 } /* bt3c_download_firmware */
1169 
1170 /****************************************************************************
1171  ****************************************************************************
1172  **                           Driver module
1173  ****************************************************************************
1174  ****************************************************************************/
1175 
1176 /*
1177  * PC Card (PCMCIA) driver
1178  */
1179 
1180 static device_method_t	bt3c_pccard_methods[] = {
1181 	/* Device interface */
1182 	DEVMETHOD(device_probe,		bt3c_pccard_probe),
1183 	DEVMETHOD(device_attach,	bt3c_pccard_attach),
1184 	DEVMETHOD(device_detach,	bt3c_pccard_detach),
1185 
1186 	{ 0, 0 }
1187 };
1188 
1189 static driver_t		bt3c_pccard_driver = {
1190 	NG_BT3C_NODE_TYPE,
1191 	bt3c_pccard_methods,
1192 	sizeof(bt3c_softc_t)
1193 };
1194 
1195 static devclass_t	bt3c_devclass;
1196 
1197 
1198 /*
1199  * Load/Unload the driver module
1200  */
1201 
1202 static int
1203 bt3c_modevent(module_t mod, int event, void *data)
1204 {
1205 	int	error;
1206 
1207 	switch (event) {
1208 	case MOD_LOAD:
1209 		error = ng_newtype(&typestruct);
1210 		if (error != 0)
1211 			printf("%s: Could not register Netgraph node type, " \
1212 				"error=%d\n", NG_BT3C_NODE_TYPE, error);
1213 		break;
1214 
1215 	case MOD_UNLOAD:
1216 		error = ng_rmtype(&typestruct);
1217 		break;
1218 
1219 	default:
1220 		error = EOPNOTSUPP;
1221 		break;
1222 	}
1223 
1224 	return (error);
1225 } /* bt3c_modevent */
1226 
1227 DRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0);
1228 MODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION);
1229 MODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION);
1230 
1231