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