6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $Id: ng_bt3c_pccard.c,v 1.5 2003/04/01 18:15:21 max Exp $
33 * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
35 * Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt>
36 * and disassembled w2k driver.
38 * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
42 #include <sys/param.h>
43 #include <sys/systm.h>
46 #include <machine/bus.h>
49 #include <sys/endian.h>
50 #include <sys/interrupt.h>
51 #include <sys/kernel.h>
53 #include <sys/module.h>
55 #include <machine/resource.h>
58 #include <sys/socket.h>
60 #include <net/if_var.h>
62 #include <dev/pccard/pccardreg.h>
63 #include <dev/pccard/pccardvar.h>
64 #include "pccarddevs.h"
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>
74 /* Netgraph methods */
75 static ng_constructor_t ng_bt3c_constructor;
76 static ng_shutdown_t ng_bt3c_shutdown;
77 static ng_newhook_t ng_bt3c_newhook;
78 static ng_connect_t ng_bt3c_connect;
79 static ng_disconnect_t ng_bt3c_disconnect;
80 static ng_rcvmsg_t ng_bt3c_rcvmsg;
81 static ng_rcvdata_t ng_bt3c_rcvdata;
83 /* PCMCIA driver methods */
84 static int bt3c_pccard_match (device_t);
85 static int bt3c_pccard_probe (device_t);
86 static int bt3c_pccard_attach (device_t);
87 static int bt3c_pccard_detach (device_t);
89 static void bt3c_intr (void *);
90 static void bt3c_receive (bt3c_softc_p);
92 static void bt3c_swi_intr (void *);
93 static void bt3c_forward (node_p, hook_p, void *, int);
94 static void bt3c_send (node_p, hook_p, void *, int);
96 static void bt3c_download_firmware (bt3c_softc_p, char const *, int);
98 #define bt3c_set_address(sc, address) \
100 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_L, ((address) & 0xff)); \
101 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_H, (((address) >> 8) & 0xff)); \
104 #define bt3c_read_data(sc, data) \
106 (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_L); \
107 (data) |= ((bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_H) & 0xff) << 8); \
110 #define bt3c_write_data(sc, data) \
112 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_L, ((data) & 0xff)); \
113 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_H, (((data) >> 8) & 0xff)); \
116 #define bt3c_read_control(sc, data) \
118 (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_CONTROL); \
121 #define bt3c_write_control(sc, data) \
123 bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_CONTROL, (data)); \
126 #define bt3c_read(sc, address, data) \
128 bt3c_set_address((sc), (address)); \
129 bt3c_read_data((sc), (data)); \
132 #define bt3c_write(sc, address, data) \
134 bt3c_set_address((sc), (address)); \
135 bt3c_write_data((sc), (data)); \
138 static MALLOC_DEFINE(M_BT3C, "bt3c", "bt3c data structures");
140 /****************************************************************************
141 ****************************************************************************
143 ****************************************************************************
144 ****************************************************************************/
151 static const struct ng_parse_struct_field ng_bt3c_node_qlen_type_fields[] =
153 { "queue", &ng_parse_int32_type, },
154 { "qlen", &ng_parse_int32_type, },
157 static const struct ng_parse_type ng_bt3c_node_qlen_type = {
158 &ng_parse_struct_type,
159 &ng_bt3c_node_qlen_type_fields
163 static const struct ng_parse_struct_field ng_bt3c_node_stat_type_fields[] =
165 { "pckts_recv", &ng_parse_uint32_type, },
166 { "bytes_recv", &ng_parse_uint32_type, },
167 { "pckts_sent", &ng_parse_uint32_type, },
168 { "bytes_sent", &ng_parse_uint32_type, },
169 { "oerrors", &ng_parse_uint32_type, },
170 { "ierrors", &ng_parse_uint32_type, },
173 static const struct ng_parse_type ng_bt3c_node_stat_type = {
174 &ng_parse_struct_type,
175 &ng_bt3c_node_stat_type_fields
178 static const struct ng_cmdlist ng_bt3c_cmdlist[] = {
181 NGM_BT3C_NODE_GET_STATE,
184 &ng_parse_uint16_type
188 NGM_BT3C_NODE_SET_DEBUG,
190 &ng_parse_uint16_type,
195 NGM_BT3C_NODE_GET_DEBUG,
198 &ng_parse_uint16_type
202 NGM_BT3C_NODE_GET_QLEN,
205 &ng_bt3c_node_qlen_type
209 NGM_BT3C_NODE_SET_QLEN,
211 &ng_bt3c_node_qlen_type,
216 NGM_BT3C_NODE_GET_STAT,
219 &ng_bt3c_node_stat_type
223 NGM_BT3C_NODE_RESET_STAT,
231 static struct ng_type typestruct = {
232 .version = NG_ABI_VERSION,
233 .name = NG_BT3C_NODE_TYPE,
234 .constructor = ng_bt3c_constructor,
235 .rcvmsg = ng_bt3c_rcvmsg,
236 .shutdown = ng_bt3c_shutdown,
237 .newhook = ng_bt3c_newhook,
238 .connect = ng_bt3c_connect,
239 .rcvdata = ng_bt3c_rcvdata,
240 .disconnect = ng_bt3c_disconnect,
241 .cmdlist = ng_bt3c_cmdlist
245 * Netgraph node constructor. Do not allow to create node of this type.
249 ng_bt3c_constructor(node_p node)
252 } /* ng_bt3c_constructor */
255 * Netgraph node destructor. Destroy node only when device has been detached
259 ng_bt3c_shutdown(node_p node)
261 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
263 /* Let old node go */
264 NG_NODE_SET_PRIVATE(node, NULL);
267 /* Create new fresh one if we are not going down */
271 /* Create new Netgraph node */
272 if (ng_make_node_common(&typestruct, &sc->node) != 0) {
273 device_printf(sc->dev, "Could not create Netgraph node\n");
278 /* Name new Netgraph node */
279 if (ng_name_node(sc->node, device_get_nameunit(sc->dev)) != 0) {
280 device_printf(sc->dev, "Could not name Netgraph node\n");
281 NG_NODE_UNREF(sc->node);
286 NG_NODE_SET_PRIVATE(sc->node, sc);
289 } /* ng_bt3c_shutdown */
292 * Create new hook. There can only be one.
296 ng_bt3c_newhook(node_p node, hook_p hook, char const *name)
298 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
300 if (strcmp(name, NG_BT3C_HOOK) != 0)
303 if (sc->hook != NULL)
309 } /* ng_bt3c_newhook */
312 * Connect hook. Say YEP, that's OK with me.
316 ng_bt3c_connect(hook_p hook)
318 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
320 if (hook != sc->hook) {
325 /* set the hook into queueing mode (for incoming (from wire) packets) */
326 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
329 } /* ng_bt3c_connect */
336 ng_bt3c_disconnect(hook_p hook)
338 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
341 * We need to check for sc != NULL because we can be called from
342 * bt3c_pccard_detach() via ng_rmnode_self()
346 if (hook != sc->hook)
356 } /* ng_bt3c_disconnect */
359 * Process control message
363 ng_bt3c_rcvmsg(node_p node, item_p item, hook_p lasthook)
365 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
366 struct ng_mesg *msg = NULL, *rsp = NULL;
374 NGI_GET_MSG(item, msg);
376 switch (msg->header.typecookie) {
377 case NGM_GENERIC_COOKIE:
378 switch (msg->header.cmd) {
379 case NGM_TEXT_STATUS:
380 NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT);
384 snprintf(rsp->data, NG_TEXTRESPONSE,
389 "IncmQ: [len:%d,max:%d]\n" \
390 "OutgQ: [len:%d,max:%d]\n",
391 (sc->hook != NULL)? NG_BT3C_HOOK : "",
395 _IF_QLEN(&sc->inq), /* XXX */
396 sc->inq.ifq_maxlen, /* XXX */
397 _IF_QLEN(&sc->outq), /* XXX */
398 sc->outq.ifq_maxlen /* XXX */
408 case NGM_BT3C_COOKIE:
409 switch (msg->header.cmd) {
410 case NGM_BT3C_NODE_GET_STATE:
411 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_state_ep),
416 *((ng_bt3c_node_state_ep *)(rsp->data)) =
420 case NGM_BT3C_NODE_SET_DEBUG:
421 if (msg->header.arglen != sizeof(ng_bt3c_node_debug_ep))
425 *((ng_bt3c_node_debug_ep *)(msg->data));
428 case NGM_BT3C_NODE_GET_DEBUG:
429 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_debug_ep),
434 *((ng_bt3c_node_debug_ep *)(rsp->data)) =
438 case NGM_BT3C_NODE_GET_QLEN:
439 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_qlen_ep),
446 switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) {
447 case NGM_BT3C_NODE_IN_QUEUE:
448 ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue =
449 NGM_BT3C_NODE_IN_QUEUE;
450 ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen =
454 case NGM_BT3C_NODE_OUT_QUEUE:
455 ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue =
456 NGM_BT3C_NODE_OUT_QUEUE;
457 ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen =
468 case NGM_BT3C_NODE_SET_QLEN:
469 if (msg->header.arglen != sizeof(ng_bt3c_node_qlen_ep)){
474 if (((ng_bt3c_node_qlen_ep *)(msg->data))->qlen <= 0) {
479 switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) {
480 case NGM_BT3C_NODE_IN_QUEUE:
481 sc->inq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *)
482 (msg->data))->qlen; /* XXX */
485 case NGM_BT3C_NODE_OUT_QUEUE:
486 sc->outq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *)
487 (msg->data))->qlen; /* XXX */
496 case NGM_BT3C_NODE_GET_STAT:
497 NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_stat_ep),
502 bcopy(&sc->stat, rsp->data,
503 sizeof(ng_bt3c_node_stat_ep));
506 case NGM_BT3C_NODE_RESET_STAT:
507 NG_BT3C_STAT_RESET(sc->stat);
510 case NGM_BT3C_NODE_DOWNLOAD_FIRMWARE:
511 if (msg->header.arglen <
512 sizeof(ng_bt3c_firmware_block_ep))
515 bt3c_download_firmware(sc, msg->data,
530 NG_RESPOND_MSG(error, node, item, rsp);
534 } /* ng_bt3c_rcvmsg */
541 ng_bt3c_rcvdata(hook_p hook, item_p item)
543 bt3c_softc_p sc = (bt3c_softc_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
544 struct mbuf *m = NULL;
552 if (hook != sc->hook) {
560 if (_IF_QFULL(&sc->outq)) {
562 "Outgoing queue is full. Dropping mbuf, len=%d\n", m->m_pkthdr.len);
565 NG_BT3C_STAT_OERROR(sc->stat);
569 _IF_ENQUEUE(&sc->outq, m);
570 IF_UNLOCK(&sc->outq);
572 error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */);
577 } /* ng_bt3c_rcvdata */
579 /****************************************************************************
580 ****************************************************************************
581 ** PCMCIA driver specific
582 ****************************************************************************
583 ****************************************************************************/
586 * PC-Card (PCMCIA) match routine
590 bt3c_pccard_match(device_t dev)
592 static struct pccard_product const bt3c_pccard_products[] = {
593 PCMCIA_CARD(3COM, 3CRWB609),
597 struct pccard_product const *pp = NULL;
599 pp = pccard_product_lookup(dev, bt3c_pccard_products,
600 sizeof(bt3c_pccard_products[0]), NULL);
604 device_set_desc(dev, pp->pp_name);
607 } /* bt3c_pccacd_match */
610 * PC-Card (PCMCIA) probe routine
615 bt3c_pccard_probe(device_t dev)
618 } /* bt3c_pccacd_probe */
621 * PC-Card (PCMCIA) attach routine
625 bt3c_pccard_attach(device_t dev)
627 bt3c_softc_p sc = NULL;
629 sc = (bt3c_softc_p) malloc(sizeof(*sc), M_BT3C, M_NOWAIT|M_ZERO);
633 /* Allocate I/O ports */
635 sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid,
636 0, ~0, 8, RF_ACTIVE);
637 if (sc->iobase == NULL) {
638 device_printf(dev, "Could not allocate I/O ports\n");
641 sc->iot = rman_get_bustag(sc->iobase);
642 sc->ioh = rman_get_bushandle(sc->iobase);
646 sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
648 if (sc->irq == NULL) {
649 device_printf(dev, "Could not allocate IRQ\n");
653 sc->irq_cookie = NULL;
654 if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, bt3c_intr, sc,
655 &sc->irq_cookie) != 0) {
656 device_printf(dev, "Could not setup ISR\n");
660 /* Attach handler to TTY SWI thread */
662 if (swi_add(&tty_intr_event, device_get_nameunit(dev),
663 bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) {
664 device_printf(dev, "Could not setup SWI ISR\n");
668 /* Create Netgraph node */
669 if (ng_make_node_common(&typestruct, &sc->node) != 0) {
670 device_printf(dev, "Could not create Netgraph node\n");
675 /* Name Netgraph node */
676 if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) {
677 device_printf(dev, "Could not name Netgraph node\n");
678 NG_NODE_UNREF(sc->node);
684 sc->debug = NG_BT3C_WARN_LEVEL;
686 sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN;
687 mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF);
688 mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF);
690 sc->state = NG_BT3C_W4_PKT_IND;
693 NG_NODE_SET_PRIVATE(sc->node, sc);
694 device_set_softc(dev, sc);
698 if (sc->ith != NULL) {
703 if (sc->irq != NULL) {
704 if (sc->irq_cookie != NULL)
705 bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
707 bus_release_resource(dev, SYS_RES_IRQ,
708 sc->irq_rid, sc->irq);
714 if (sc->iobase != NULL) {
715 bus_release_resource(dev, SYS_RES_IOPORT,
716 sc->iobase_rid, sc->iobase);
725 } /* bt3c_pccacd_attach */
728 * PC-Card (PCMCIA) detach routine
732 bt3c_pccard_detach(device_t dev)
734 bt3c_softc_p sc = (bt3c_softc_p) device_get_softc(dev);
739 device_set_softc(dev, NULL);
744 bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
745 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
746 sc->irq_cookie = NULL;
750 bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
754 if (sc->node != NULL) {
755 NG_NODE_SET_PRIVATE(sc->node, NULL);
756 ng_rmnode_self(sc->node);
764 mtx_destroy(&sc->inq.ifq_mtx);
765 mtx_destroy(&sc->outq.ifq_mtx);
767 bzero(sc, sizeof(*sc));
771 } /* bt3c_pccacd_detach */
774 * Interrupt service routine's
778 bt3c_intr(void *context)
780 bt3c_softc_p sc = (bt3c_softc_p) context;
781 u_int16_t control, status;
783 if (sc == NULL || sc->ith == NULL) {
784 printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE);
788 bt3c_read_control(sc, control);
789 if ((control & 0x80) == 0)
792 bt3c_read(sc, 0x7001, status);
793 NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status);
795 if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) {
796 NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status);
800 /* Receive complete */
804 /* Record status and schedule SWI */
805 sc->status |= status;
806 swi_sched(sc->ith, 0);
808 /* Complete interrupt */
809 bt3c_write(sc, 0x7001, 0x0000);
810 bt3c_write_control(sc, control);
818 bt3c_receive(bt3c_softc_p sc)
820 u_int16_t i, count, c;
822 /* Receive data from the card */
823 bt3c_read(sc, 0x7006, count);
824 NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count);
826 bt3c_set_address(sc, 0x7480);
828 for (i = 0; i < count; i++) {
829 /* Allocate new mbuf if needed */
831 sc->state = NG_BT3C_W4_PKT_IND;
834 MGETHDR(sc->m, M_DONTWAIT, MT_DATA);
836 NG_BT3C_ERR(sc->dev, "Could not get mbuf\n");
837 NG_BT3C_STAT_IERROR(sc->stat);
839 break; /* XXX lost of sync */
842 MCLGET(sc->m, M_DONTWAIT);
843 if (!(sc->m->m_flags & M_EXT)) {
846 NG_BT3C_ERR(sc->dev, "Could not get cluster\n");
847 NG_BT3C_STAT_IERROR(sc->stat);
849 break; /* XXX lost of sync */
852 sc->m->m_len = sc->m->m_pkthdr.len = 0;
855 /* Read and append character to mbuf */
856 bt3c_read_data(sc, c);
857 if (sc->m->m_pkthdr.len >= MCLBYTES) {
858 NG_BT3C_ERR(sc->dev, "Oversized frame\n");
861 sc->state = NG_BT3C_W4_PKT_IND;
864 break; /* XXX lost of sync */
867 mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c;
868 sc->m->m_pkthdr.len ++;
870 NG_BT3C_INFO(sc->dev,
871 "Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len);
873 if (sc->m->m_pkthdr.len < sc->want)
874 continue; /* wait for more */
877 /* Got packet indicator */
878 case NG_BT3C_W4_PKT_IND:
879 NG_BT3C_INFO(sc->dev,
880 "Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *));
882 sc->state = NG_BT3C_W4_PKT_HDR;
885 * Since packet indicator included in the packet
886 * header just set sc->want to sizeof(packet header).
889 switch (*mtod(sc->m, u_int8_t *)) {
890 case NG_HCI_ACL_DATA_PKT:
891 sc->want = sizeof(ng_hci_acldata_pkt_t);
894 case NG_HCI_SCO_DATA_PKT:
895 sc->want = sizeof(ng_hci_scodata_pkt_t);
898 case NG_HCI_EVENT_PKT:
899 sc->want = sizeof(ng_hci_event_pkt_t);
904 "Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *));
906 NG_BT3C_STAT_IERROR(sc->stat);
909 sc->state = NG_BT3C_W4_PKT_IND;
915 /* Got packet header */
916 case NG_BT3C_W4_PKT_HDR:
917 sc->state = NG_BT3C_W4_PKT_DATA;
919 switch (*mtod(sc->m, u_int8_t *)) {
920 case NG_HCI_ACL_DATA_PKT:
921 c = le16toh(mtod(sc->m,
922 ng_hci_acldata_pkt_t *)->length);
925 case NG_HCI_SCO_DATA_PKT:
926 c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length;
929 case NG_HCI_EVENT_PKT:
930 c = mtod(sc->m, ng_hci_event_pkt_t *)->length;
935 ("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *)));
939 NG_BT3C_INFO(sc->dev,
940 "Got packet header, packet type=%#x, got so far %d, payload size=%d\n",
941 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len,
949 /* else FALLTHROUGH and deliver frame */
950 /* XXX is this true? should we deliver empty frame? */
952 /* Got packet data */
953 case NG_BT3C_W4_PKT_DATA:
954 NG_BT3C_INFO(sc->dev,
955 "Got full packet, packet type=%#x, packet size=%d\n",
956 *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len);
958 NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len);
959 NG_BT3C_STAT_PCKTS_RECV(sc->stat);
962 if (_IF_QFULL(&sc->inq)) {
964 "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len);
967 NG_BT3C_STAT_IERROR(sc->stat);
971 _IF_ENQUEUE(&sc->inq, sc->m);
976 sc->state = NG_BT3C_W4_PKT_IND;
982 ("Invalid node state=%d", sc->state));
987 bt3c_write(sc, 0x7006, 0x0000);
991 * SWI interrupt handler
992 * Netgraph part is handled via ng_send_fn() to avoid race with hook
993 * connection/disconnection
997 bt3c_swi_intr(void *context)
999 bt3c_softc_p sc = (bt3c_softc_p) context;
1002 /* Receive complete */
1003 if (sc->status & 0x0001) {
1004 sc->status &= ~0x0001; /* XXX is it safe? */
1006 if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0)
1007 NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n");
1011 if (sc->status & 0x0002) {
1012 sc->status &= ~0x0002; /* XXX is it safe */
1014 if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0)
1015 NG_BT3C_ALERT(sc->dev, "Could not send frames!\n");
1018 /* Antenna position */
1019 if (sc->status & 0x0020) {
1020 sc->status &= ~0x0020; /* XXX is it safe */
1022 bt3c_read(sc, 0x7002, data);
1026 sc->flags |= BT3C_ANTENNA_OUT;
1028 sc->flags &= ~BT3C_ANTENNA_OUT;
1030 NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN");
1032 } /* bt3c_swi_intr */
1035 * Send all incoming frames to the upper layer
1039 bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2)
1041 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1042 struct mbuf *m = NULL;
1048 if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
1050 IF_DEQUEUE(&sc->inq, m);
1054 NG_SEND_DATA_ONLY(error, sc->hook, m);
1056 NG_BT3C_STAT_IERROR(sc->stat);
1061 _IF_DEQUEUE(&sc->inq, m);
1065 NG_BT3C_STAT_IERROR(sc->stat);
1068 IF_UNLOCK(&sc->inq);
1070 } /* bt3c_forward */
1073 * Send more data to the device. Must be called when node is locked
1077 bt3c_send(node_p node, hook_p hook, void *arg, int completed)
1079 bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1080 struct mbuf *m = NULL;
1087 sc->flags &= ~BT3C_XMIT;
1089 if (sc->flags & BT3C_XMIT)
1092 bt3c_set_address(sc, 0x7080);
1094 for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) {
1095 IF_DEQUEUE(&sc->outq, m);
1100 len = min((BT3C_FIFO_SIZE - wrote), m->m_len);
1102 for (i = 0; i < len; i++)
1103 bt3c_write_data(sc, m->m_data[i]);
1116 IF_PREPEND(&sc->outq, m);
1120 NG_BT3C_STAT_PCKTS_SENT(sc->stat);
1124 NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote);
1125 NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote);
1127 bt3c_write(sc, 0x7005, wrote);
1128 sc->flags |= BT3C_XMIT;
1133 * Download chip firmware
1137 bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size)
1139 ng_bt3c_firmware_block_ep const *block = NULL;
1140 u_int16_t const *data = NULL;
1145 device_printf(sc->dev, "Reseting the card...\n");
1146 bt3c_write(sc, 0x8040, 0x0404);
1147 bt3c_write(sc, 0x8040, 0x0400);
1150 bt3c_write(sc, 0x8040, 0x0404);
1153 /* Download firmware */
1154 device_printf(sc->dev, "Starting firmware download process...\n");
1156 for (size = 0; size < firmware_size; ) {
1157 block = (ng_bt3c_firmware_block_ep const *)(firmware + size);
1158 data = (u_int16_t const *)(block + 1);
1161 device_printf(sc->dev, "Download firmware block, " \
1162 "address=%#08x, size=%d words, aligment=%d\n",
1163 block->block_address, block->block_size,
1164 block->block_alignment);
1166 bt3c_set_address(sc, block->block_address);
1167 for (i = 0; i < block->block_size; i++)
1168 bt3c_write_data(sc, data[i]);
1170 size += (sizeof(*block) + (block->block_size * 2) +
1171 block->block_alignment);
1175 device_printf(sc->dev, "Firmware download process complete\n");
1178 device_printf(sc->dev, "Starting the card...\n");
1179 bt3c_set_address(sc, 0x3000);
1180 bt3c_read_control(sc, c);
1181 bt3c_write_control(sc, (c | 0x40));
1184 /* Clear registers */
1185 device_printf(sc->dev, "Clearing card registers...\n");
1186 bt3c_write(sc, 0x7006, 0x0000);
1187 bt3c_write(sc, 0x7005, 0x0000);
1188 bt3c_write(sc, 0x7001, 0x0000);
1190 } /* bt3c_download_firmware */
1192 /****************************************************************************
1193 ****************************************************************************
1195 ****************************************************************************
1196 ****************************************************************************/
1199 * PC-Card (PCMCIA) driver
1202 static device_method_t bt3c_pccard_methods[] = {
1203 /* Device interface */
1204 DEVMETHOD(device_probe, pccard_compat_probe),
1205 DEVMETHOD(device_attach, pccard_compat_attach),
1206 DEVMETHOD(device_detach, bt3c_pccard_detach),
1208 /* Card interface */
1209 DEVMETHOD(card_compat_match, bt3c_pccard_match),
1210 DEVMETHOD(card_compat_probe, bt3c_pccard_probe),
1211 DEVMETHOD(card_compat_attach, bt3c_pccard_attach),
1215 static driver_t bt3c_pccard_driver = {
1217 bt3c_pccard_methods,
1221 static devclass_t bt3c_devclass;
1225 * Load/Unload the driver module
1229 bt3c_modevent(module_t mod, int event, void *data)
1235 error = ng_newtype(&typestruct);
1237 printf("%s: Could not register Netgraph node type, " \
1238 "error=%d\n", NG_BT3C_NODE_TYPE, error);
1242 error = ng_rmtype(&typestruct);
1251 } /* bt3c_modevent */
1253 DRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0);
1254 MODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION);
1255 MODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION);