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