Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pcmcia / btbc.c
blobb7391f2dfeb1924f30e2243de68892a09407649e
1 /* $NetBSD: btbc.c,v 1.12 2008/04/06 18:55:33 plunky Exp $ */
2 /*
3 * Copyright (c) 2007 KIYOHARA Takashi
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
28 * This driver is support to the AnyCom BlueCard. written with reference to
29 * Linux driver: (drivers/bluetooth/bluecard_cs.c)
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: btbc.c,v 1.12 2008/04/06 18:55:33 plunky Exp $");
35 #include <sys/param.h>
36 #include <sys/callout.h>
37 #include <sys/device.h>
38 #include <sys/errno.h>
39 #include <sys/kernel.h>
40 #include <sys/mbuf.h>
41 #include <sys/proc.h>
43 #include <sys/bus.h>
44 #include <sys/intr.h>
46 #include <dev/pcmcia/pcmciareg.h>
47 #include <dev/pcmcia/pcmciavar.h>
48 #include <dev/pcmcia/pcmciadevs.h>
50 #include <netbt/bluetooth.h>
51 #include <netbt/hci.h>
53 #include <dev/pcmcia/bluecardreg.h>
56 /* sc_state */ /* receiving */
57 #define BTBC_RECV_PKT_TYPE 0 /* packet type */
58 #define BTBC_RECV_ACL_HDR 1 /* acl header */
59 #define BTBC_RECV_SCO_HDR 2 /* sco header */
60 #define BTBC_RECV_EVENT_HDR 3 /* event header */
61 #define BTBC_RECV_ACL_DATA 4 /* acl packet data */
62 #define BTBC_RECV_SCO_DATA 5 /* sco packet data */
63 #define BTBC_RECV_EVENT_DATA 6 /* event packet data */
65 /* sc_flags */
66 #define BTBC_XMIT (1 << 1) /* transmit active */
67 #define BTBC_ENABLED (1 << 2) /* is enabled */
69 /* Default baud rate: 57600, 115200, 230400 or 460800 */
70 #ifndef BTBC_DEFAULT_BAUDRATE
71 #define BTBC_DEFAULT_BAUDRATE 57600
72 #endif
74 struct btbc_softc {
75 device_t sc_dev;
77 struct pcmcia_function *sc_pf; /* our PCMCIA function */
78 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
79 int sc_flags; /* flags */
81 struct hci_unit *sc_unit; /* Bluetooth HCI Unit */
82 struct bt_stats sc_stats; /* HCI stats */
84 /* hardware interrupt */
85 void *sc_intr; /* cookie */
86 int sc_state; /* receive state */
87 int sc_want; /* how much we want */
88 struct mbuf *sc_rxp; /* incoming packet */
89 struct mbuf *sc_txp; /* outgoing packet */
90 int sc_txstate;
91 #define TXBUF1_EMPTY (1 << 0)
92 #define TXBUF2_EMPTY (1 << 1)
93 #define TXBUF_MASK (1 << 2)
95 /* output queues */
96 MBUFQ_HEAD() sc_cmdq;
97 MBUFQ_HEAD() sc_aclq;
98 MBUFQ_HEAD() sc_scoq;
100 callout_t sc_ledch; /* callout handler for LED */
101 uint8_t sc_ctrlreg; /* value for control register */
104 static int btbc_match(device_t, cfdata_t, void *);
105 static void btbc_attach(device_t, device_t, void *);
106 static int btbc_detach(device_t, int);
107 static bool btbc_suspend(device_t PMF_FN_PROTO);
108 static bool btbc_resume(device_t PMF_FN_PROTO);
110 static void btbc_activity_led_timeout(void *);
111 static void btbc_enable_activity_led(struct btbc_softc *);
112 static int btbc_read(struct btbc_softc *, uint32_t, uint8_t *, int);
113 static int btbc_write(struct btbc_softc *, uint32_t, uint8_t *, int);
114 static int btbc_set_baudrate(struct btbc_softc *, int);
115 static void btbc_receive(struct btbc_softc *, uint32_t);
116 static void btbc_transmit(struct btbc_softc *);
117 static int btbc_intr(void *);
118 static void btbc_start(struct btbc_softc *);
120 static int btbc_enable(device_t);
121 static void btbc_disable(device_t);
122 static void btbc_output_cmd(device_t, struct mbuf *);
123 static void btbc_output_acl(device_t, struct mbuf *);
124 static void btbc_output_sco(device_t, struct mbuf *);
125 static void btbc_stats(device_t, struct bt_stats *, int);
127 CFATTACH_DECL_NEW(btbc, sizeof(struct btbc_softc),
128 btbc_match, btbc_attach, btbc_detach, NULL);
130 static const struct hci_if btbc_hci = {
131 .enable = btbc_enable,
132 .disable = btbc_disable,
133 .output_cmd = btbc_output_cmd,
134 .output_acl = btbc_output_acl,
135 .output_sco = btbc_output_sco,
136 .get_stats = btbc_stats,
137 .ipl = IPL_TTY,
140 /* ARGSUSED */
141 static int
142 btbc_match(device_t parent, cfdata_t match, void *aux)
144 struct pcmcia_attach_args *pa = aux;
146 if (pa->manufacturer == PCMCIA_VENDOR_ANYCOM)
147 if ((pa->product == PCMCIA_PRODUCT_ANYCOM_LSE041) ||
148 (pa->product == PCMCIA_PRODUCT_ANYCOM_LSE039) ||
149 (pa->product == PCMCIA_PRODUCT_ANYCOM_LSE139))
150 return 1;
151 return 0;
154 static int
155 btbc_pcmcia_validate_config(struct pcmcia_config_entry *cfe)
158 if (cfe->iftype != PCMCIA_IFTYPE_IO ||
159 cfe->num_iospace < 1 || cfe->num_iospace > 2)
160 return EINVAL;
161 return 0;
164 /* ARGSUSED */
165 static void
166 btbc_attach(device_t parent, device_t self, void *aux)
168 struct btbc_softc *sc = device_private(self);
169 struct pcmcia_attach_args *pa = aux;
170 struct pcmcia_config_entry *cfe;
171 int error;
173 sc->sc_dev = self;
174 sc->sc_pf = pa->pf;
176 MBUFQ_INIT(&sc->sc_cmdq);
177 MBUFQ_INIT(&sc->sc_aclq);
178 MBUFQ_INIT(&sc->sc_scoq);
180 if ((error = pcmcia_function_configure(pa->pf,
181 btbc_pcmcia_validate_config)) != 0) {
182 aprint_error_dev(self, "configure failed, error=%d\n", error);
183 return;
186 cfe = pa->pf->cfe;
187 sc->sc_pcioh = cfe->iospace[0].handle;
189 /* Attach Bluetooth unit */
190 sc->sc_unit = hci_attach(&btbc_hci, self, 0);
191 if (sc->sc_unit == NULL)
192 aprint_error_dev(self, "HCI attach failed\n");
194 if (!pmf_device_register(self, btbc_suspend, btbc_resume))
195 aprint_error_dev(self, "couldn't establish power handler\n");
197 callout_init(&sc->sc_ledch, 0);
198 callout_setfunc(&sc->sc_ledch, btbc_activity_led_timeout, sc);
200 return;
203 /* ARGSUSED */
204 static int
205 btbc_detach(device_t self, int flags)
207 struct btbc_softc *sc = device_private(self);
208 int err = 0;
210 pmf_device_deregister(self);
211 btbc_disable(sc->sc_dev);
213 callout_stop(&sc->sc_ledch);
214 callout_destroy(&sc->sc_ledch);
216 if (sc->sc_unit) {
217 hci_detach(sc->sc_unit);
218 sc->sc_unit = NULL;
221 pcmcia_function_unconfigure(sc->sc_pf);
223 return err;
226 static bool
227 btbc_suspend(device_t self PMF_FN_ARGS)
229 struct btbc_softc *sc = device_private(self);
231 if (sc->sc_unit) {
232 hci_detach(sc->sc_unit);
233 sc->sc_unit = NULL;
236 return true;
240 static bool
241 btbc_resume(device_t self PMF_FN_ARGS)
243 struct btbc_softc *sc = device_private(self);
245 KASSERT(sc->sc_unit == NULL);
247 sc->sc_unit = hci_attach(&btbc_hci, sc->sc_dev, 0);
248 if (sc->sc_unit == NULL)
249 return false;
251 return true;
254 static void
255 btbc_activity_led_timeout(void *arg)
257 struct btbc_softc *sc = arg;
258 uint8_t id;
260 id = bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
261 BLUECARD_LEDCONTROL);
262 if (id & 0x20)
263 /* Disable activity LED */
264 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
265 BLUECARD_LEDCONTROL, 0x08 | 0x20);
266 else
267 /* Disable power LED */
268 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
269 BLUECARD_LEDCONTROL, 0x00);
272 static void
273 btbc_enable_activity_led(struct btbc_softc *sc)
275 uint8_t id;
277 id = bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
278 BLUECARD_LEDCONTROL);
279 if (id & 0x20) {
280 /* Enable activity LED */
281 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
282 BLUECARD_LEDCONTROL, 0x10 | 0x40);
284 /* Stop the LED after hz/4 */
285 callout_schedule(&sc->sc_ledch, hz / 4);
286 } else {
287 /* Enable power LED */
288 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
289 BLUECARD_LEDCONTROL, 0x08 | 0x20);
291 /* Stop the LED after HZ/2 */
292 callout_schedule(&sc->sc_ledch, hz / 2);
296 static int
297 btbc_read(struct btbc_softc *sc, uint32_t offset, uint8_t *buf, int buflen)
299 int i, n, len;
301 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
302 BLUECARD_COMMAND, BLUECARD_COMMAND_RXWIN1);
303 len = bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, offset);
305 n = 0;
306 i = 1;
307 while (n < len) {
308 if (i == 16) {
309 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
310 BLUECARD_COMMAND, BLUECARD_COMMAND_RXWIN2);
311 i = 0;
314 buf[n] = bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
315 offset + i);
316 i++;
317 if (++n > buflen)
318 break;
320 return len;
323 static int
324 btbc_write(struct btbc_softc *sc, uint32_t offset, uint8_t *buf, int buflen)
326 int i, actual;
328 actual = (buflen > 15) ? 15 : buflen;
329 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, offset, actual);
330 for (i = 0; i < actual; i++)
331 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
332 offset + i + 1, buf[i]);
333 return actual;
337 * send Ericsson baud rate command
339 static int
340 btbc_set_baudrate(struct btbc_softc *sc, int baud)
342 hci_cmd_hdr_t *p;
343 struct mbuf *m;
344 const uint16_t opcode = htole16(HCI_CMD_ERICSSON_SET_UART_BAUD_RATE);
345 uint8_t param;
347 m = m_gethdr(M_WAIT, MT_DATA);
349 switch (baud) {
350 case 460800:
351 param = 0x00;
352 break;
354 case 230400:
355 param = 0x01;
356 break;
358 case 115200:
359 param = 0x02;
360 break;
362 case 57600:
363 default:
364 param = 0x03;
365 break;
368 p = mtod(m, hci_cmd_hdr_t *);
369 p->type = HCI_CMD_PKT;
370 p->opcode = opcode;
371 p->length = sizeof(param);
372 m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
373 m_copyback(m, sizeof(hci_cmd_hdr_t), p->length, &param);
375 btbc_output_cmd(sc->sc_dev, m);
376 return 0;
379 static void
380 btbc_receive(struct btbc_softc *sc, uint32_t offset)
382 struct mbuf *m = sc->sc_rxp;
383 int count, space = 0, i;
384 uint8_t buf[31];
386 btbc_enable_activity_led(sc);
389 * If we already started a packet, find the
390 * trailing end of it.
392 if (m) {
393 while (m->m_next)
394 m = m->m_next;
396 space = M_TRAILINGSPACE(m);
399 count = btbc_read(sc, offset, buf, sizeof(buf));
400 i = 0;
402 while (i < count) {
403 if (space == 0) {
404 if (m == NULL) {
405 /* new packet */
406 MGETHDR(m, M_DONTWAIT, MT_DATA);
407 if (m == NULL) {
408 aprint_error_dev(sc->sc_dev,
409 "out of memory\n");
410 sc->sc_stats.err_rx++;
411 return; /* (lost sync) */
414 sc->sc_rxp = m;
415 m->m_pkthdr.len = m->m_len = 0;
416 space = MHLEN;
418 sc->sc_state = BTBC_RECV_PKT_TYPE;
419 sc->sc_want = 1;
420 } else {
421 /* extend mbuf */
422 MGET(m->m_next, M_DONTWAIT, MT_DATA);
423 if (m->m_next == NULL) {
424 aprint_error_dev(sc->sc_dev,
425 "out of memory\n");
426 sc->sc_stats.err_rx++;
427 return; /* (lost sync) */
430 m = m->m_next;
431 m->m_len = 0;
432 space = MLEN;
434 if (sc->sc_want > MINCLSIZE) {
435 MCLGET(m, M_DONTWAIT);
436 if (m->m_flags & M_EXT)
437 space = MCLBYTES;
442 mtod(m, uint8_t *)[m->m_len++] = buf[i];
443 space--;
444 sc->sc_rxp->m_pkthdr.len++;
445 sc->sc_stats.byte_rx++;
447 sc->sc_want--;
448 if (sc->sc_want > 0) {
449 i++;
450 continue; /* want more */
453 switch (sc->sc_state) {
454 case BTBC_RECV_PKT_TYPE: /* Got packet type */
455 switch (buf[i]) {
456 case 0x00: /* init packet */
457 m_freem(sc->sc_rxp);
458 sc->sc_rxp = NULL;
459 break;
461 case HCI_ACL_DATA_PKT:
462 sc->sc_state = BTBC_RECV_ACL_HDR;
463 sc->sc_want = sizeof(hci_acldata_hdr_t) - 1;
464 break;
466 case HCI_SCO_DATA_PKT:
467 sc->sc_state = BTBC_RECV_SCO_HDR;
468 sc->sc_want = sizeof(hci_scodata_hdr_t) - 1;
469 break;
471 case HCI_EVENT_PKT:
472 sc->sc_state = BTBC_RECV_EVENT_HDR;
473 sc->sc_want = sizeof(hci_event_hdr_t) - 1;
474 break;
476 default:
477 aprint_error_dev(sc->sc_dev,
478 "Unknown packet type=%#x!\n", buf[i]);
479 sc->sc_stats.err_rx++;
480 m_freem(sc->sc_rxp);
481 sc->sc_rxp = NULL;
482 return; /* (lost sync) */
485 break;
488 * we assume (correctly of course :) that the packet headers
489 * all fit into a single pkthdr mbuf
491 case BTBC_RECV_ACL_HDR: /* Got ACL Header */
492 sc->sc_state = BTBC_RECV_ACL_DATA;
493 sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length;
494 sc->sc_want = le16toh(sc->sc_want);
495 break;
497 case BTBC_RECV_SCO_HDR: /* Got SCO Header */
498 sc->sc_state = BTBC_RECV_SCO_DATA;
499 sc->sc_want = mtod(m, hci_scodata_hdr_t *)->length;
500 break;
502 case BTBC_RECV_EVENT_HDR: /* Got Event Header */
503 sc->sc_state = BTBC_RECV_EVENT_DATA;
504 sc->sc_want = mtod(m, hci_event_hdr_t *)->length;
505 break;
507 case BTBC_RECV_ACL_DATA: /* ACL Packet Complete */
508 if (!hci_input_acl(sc->sc_unit, sc->sc_rxp))
509 sc->sc_stats.err_rx++;
511 sc->sc_stats.acl_rx++;
512 sc->sc_rxp = m = NULL;
513 space = 0;
514 break;
516 case BTBC_RECV_SCO_DATA: /* SCO Packet Complete */
517 if (!hci_input_sco(sc->sc_unit, sc->sc_rxp))
518 sc->sc_stats.err_rx++;
520 sc->sc_stats.sco_rx++;
521 sc->sc_rxp = m = NULL;
522 space = 0;
523 break;
525 case BTBC_RECV_EVENT_DATA: /* Event Packet Complete */
526 if (!hci_input_event(sc->sc_unit, sc->sc_rxp))
527 sc->sc_stats.err_rx++;
529 sc->sc_stats.evt_rx++;
530 sc->sc_rxp = m = NULL;
531 space = 0;
532 break;
534 default:
535 panic("%s: invalid state %d!\n",
536 device_xname(sc->sc_dev), sc->sc_state);
538 i++;
543 * write data from current packet to Transmit FIFO.
544 * restart when done.
546 static void
547 btbc_transmit(struct btbc_softc *sc)
549 hci_cmd_hdr_t *p;
550 struct mbuf *m;
551 int count, set_baudrate, n, s;
552 uint32_t offset, command;
553 uint8_t *rptr;
555 m = sc->sc_txp;
556 if (m == NULL) {
557 sc->sc_flags &= ~BTBC_XMIT;
558 btbc_start(sc);
559 return;
562 set_baudrate = 0;
563 p = mtod(m, hci_cmd_hdr_t *);
564 if ((void *)m->m_pktdat == (void *)p) {
565 const uint16_t opcode =
566 htole16(HCI_CMD_ERICSSON_SET_UART_BAUD_RATE);
568 if (p->type == HCI_CMD_PKT &&
569 p->opcode == opcode &&
570 p->length == 1) {
571 set_baudrate = 1;
572 sc->sc_txp = NULL; /* safe reentrant */
576 count = 0;
577 rptr = mtod(m, uint8_t *);
578 for(;;) {
579 if (m->m_len == 0) {
580 m = m->m_next;
581 if (m == NULL) {
582 m = sc->sc_txp;
583 sc->sc_txp = NULL;
585 if (M_GETCTX(m, void *) == NULL)
586 m_freem(m);
587 else if (!hci_complete_sco(sc->sc_unit, m))
588 sc->sc_stats.err_tx++;
590 break;
593 rptr = mtod(m, uint8_t *);
594 continue;
597 s = splhigh();
598 if (sc->sc_txstate & TXBUF_MASK) {
599 if (sc->sc_txstate & TXBUF2_EMPTY) {
600 offset = BLUECARD_BUF2;
601 command = BLUECARD_COMMAND_TXBUF2;
602 sc->sc_txstate &= ~(TXBUF2_EMPTY | TXBUF_MASK);
603 } else {
604 splx(s);
605 break;
607 } else {
608 if (sc->sc_txstate & TXBUF1_EMPTY) {
609 offset = BLUECARD_BUF1;
610 command = BLUECARD_COMMAND_TXBUF1;
611 sc->sc_txstate &= ~TXBUF1_EMPTY;
612 sc->sc_txstate |= TXBUF_MASK;
613 } else {
614 splx(s);
615 break;
618 splx(s);
620 if (set_baudrate) {
621 /* Disable RTS */
622 sc->sc_ctrlreg |= BLUECARD_CONTROL_RTS;
623 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
624 BLUECARD_CONTROL, sc->sc_ctrlreg);
627 /* Activate LED */
628 btbc_enable_activity_led(sc);
630 /* Send frame */
631 n = btbc_write(sc, offset, rptr, m->m_len);
632 count += n;
633 rptr += n;
634 m_adj(m, n);
636 /* Tell the FPGA to send the data */
637 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
638 BLUECARD_COMMAND, command);
640 if (set_baudrate) {
641 unsigned char baud_reg;
643 switch (*(uint8_t *)(p + 1)) {
644 case 0x00: /* baud rate 460800 */
645 baud_reg = BLUECARD_CONTROL_BAUDRATE_460800;
646 break;
647 case 0x01: /* baud rate 230400 */
648 baud_reg = BLUECARD_CONTROL_BAUDRATE_230400;
649 break;
650 case 0x02: /* baud rate 115200 */
651 baud_reg = BLUECARD_CONTROL_BAUDRATE_115200;
652 break;
653 case 0x03: /* baud rate 57600 */
654 default:
655 baud_reg = BLUECARD_CONTROL_BAUDRATE_57600;
656 break;
659 /* Wait until the command reaches the baseband */
660 tsleep(sc, PCATCH, "btbc_wait", hz / 5);
662 /* Set baud on baseband */
663 sc->sc_ctrlreg &= ~BLUECARD_CONTROL_BAUDRATE_MASK;
664 sc->sc_ctrlreg |= baud_reg;
665 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
666 BLUECARD_CONTROL, sc->sc_ctrlreg);
668 /* Enable RTS */
669 sc->sc_ctrlreg &= ~BLUECARD_CONTROL_RTS;
670 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
671 BLUECARD_CONTROL, sc->sc_ctrlreg);
673 /* Wait before the next HCI packet can be send */
674 tsleep(sc, PCATCH, "btbc_wait", hz);
676 m_freem(m);
677 break;
680 sc->sc_stats.byte_tx += count;
683 static int
684 btbc_intr(void *arg)
686 struct btbc_softc *sc = arg;
687 int handled = 0;
688 uint8_t isr;
690 isr = bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
691 BLUECARD_INTERRUPT);
692 if (isr != 0x00 && isr != 0xff) {
693 if (isr & BLUECARD_INTERRUPT_RXBUF1) {
694 isr &= ~BLUECARD_INTERRUPT_RXBUF1;
695 handled = 1;
696 btbc_receive(sc, BLUECARD_BUF1);
697 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
698 BLUECARD_INTERRUPT, BLUECARD_INTERRUPT_RXBUF1);
699 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
700 BLUECARD_COMMAND, BLUECARD_COMMAND_RXBUF1);
702 if (isr & BLUECARD_INTERRUPT_RXBUF2) {
703 isr &= ~BLUECARD_INTERRUPT_RXBUF2;
704 handled = 1;
705 btbc_receive(sc, BLUECARD_BUF2);
706 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
707 BLUECARD_INTERRUPT, BLUECARD_INTERRUPT_RXBUF2);
708 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
709 BLUECARD_COMMAND, BLUECARD_COMMAND_RXBUF2);
711 if (isr & BLUECARD_INTERRUPT_TXBUF1) {
712 isr &= ~BLUECARD_INTERRUPT_TXBUF1;
713 handled = 1;
714 sc->sc_txstate |= TXBUF1_EMPTY;
715 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
716 BLUECARD_INTERRUPT, BLUECARD_INTERRUPT_TXBUF1);
717 btbc_transmit(sc);
719 if (isr & BLUECARD_INTERRUPT_TXBUF2) {
720 isr &= ~BLUECARD_INTERRUPT_TXBUF2;
721 handled = 1;
722 sc->sc_txstate |= TXBUF2_EMPTY;
723 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
724 BLUECARD_INTERRUPT, BLUECARD_INTERRUPT_TXBUF2);
725 btbc_transmit(sc);
728 if (isr & 0x40) { /* card eject ? */
729 aprint_normal_dev(sc->sc_dev, "card eject?\n");
730 isr &= ~0x40;
731 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
732 BLUECARD_INTERRUPT, 0x40);
734 if (isr != 0x00) {
735 aprint_error_dev(sc->sc_dev,
736 "unknown interrupt: isr=0x%x\n", isr);
737 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
738 BLUECARD_INTERRUPT, isr);
742 return handled;
746 * start sending on btbc
748 * should be called at spltty() and when BTBC_XMIT is not set
750 static void
751 btbc_start(struct btbc_softc *sc)
753 struct mbuf *m;
755 KASSERT((sc->sc_flags & BTBC_XMIT) == 0);
756 KASSERT(sc->sc_txp == NULL);
758 if (MBUFQ_FIRST(&sc->sc_cmdq)) {
759 MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
760 sc->sc_stats.cmd_tx++;
761 goto start;
764 if (MBUFQ_FIRST(&sc->sc_scoq)) {
765 MBUFQ_DEQUEUE(&sc->sc_scoq, m);
766 sc->sc_stats.sco_tx++;
767 goto start;
770 if (MBUFQ_FIRST(&sc->sc_aclq)) {
771 MBUFQ_DEQUEUE(&sc->sc_aclq, m);
772 sc->sc_stats.acl_tx++;
773 goto start;
776 /* Nothing to send */
777 return;
779 start:
780 sc->sc_txp = m;
781 sc->sc_flags |= BTBC_XMIT;
782 btbc_transmit(sc);
785 static int
786 btbc_enable(device_t self)
788 struct btbc_softc *sc = device_private(self);
789 int err, s;
790 uint8_t id, ctrl;
792 if (sc->sc_flags & BTBC_ENABLED)
793 return 0;
795 s = spltty();
797 sc->sc_txstate = TXBUF1_EMPTY | TXBUF2_EMPTY;
798 sc->sc_intr = pcmcia_intr_establish(sc->sc_pf, IPL_TTY, btbc_intr, sc);
799 if (sc->sc_intr == NULL) {
800 err = EIO;
801 goto fail1;
804 err = pcmcia_function_enable(sc->sc_pf);
805 if (err)
806 goto fail2;
808 sc->sc_flags |= BTBC_ENABLED;
809 sc->sc_flags &= ~BTBC_XMIT;
811 /* Reset card */
812 ctrl = BLUECARD_CONTROL_RESET | BLUECARD_CONTROL_CARDRESET;
813 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, BLUECARD_CONTROL,
814 ctrl);
816 /* Turn FPGA off */
817 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
818 BLUECARD_CARDRESET, 0x80);
820 /* Wait some time */
821 tsleep(sc, PCATCH, "btbc_reset", 1);
823 /* Turn FPGA on */
824 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
825 BLUECARD_CARDRESET, 0x00);
827 /* Activate card */
828 ctrl = BLUECARD_CONTROL_ON | BLUECARD_CONTROL_RESPU;
829 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, BLUECARD_CONTROL,
830 ctrl);
832 tsleep(sc, PCATCH, "btbc_enable", 1);
833 sc->sc_ctrlreg = ctrl;
835 /* Enable interrupt */
836 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
837 BLUECARD_INTERRUPT, 0xff);
838 sc->sc_ctrlreg |= BLUECARD_CONTROL_INTERRUPT;
839 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, BLUECARD_CONTROL,
840 sc->sc_ctrlreg);
842 id = bus_space_read_1(sc->sc_pcioh.iot,
843 sc->sc_pcioh.ioh, BLUECARD_LEDCONTROL);
844 switch (id & 0x0f) {
845 case 0x02:
846 /* Enable LED */
847 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
848 BLUECARD_LEDCONTROL, 0x08 | 0x20);
849 break;
851 case 0x03:
852 /* Disable RTS */
853 ctrl |= BLUECARD_CONTROL_RTS;
854 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
855 BLUECARD_CONTROL, ctrl);
857 /* Set baud rate */
858 ctrl |= BLUECARD_CONTROL_BAUDRATE_460800;
859 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
860 BLUECARD_CONTROL, ctrl);
862 /* Enable RTS */
863 ctrl &= ~BLUECARD_CONTROL_RTS;
864 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
865 BLUECARD_CONTROL, ctrl);
866 break;
869 /* Start the RX buffers */
870 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
871 BLUECARD_COMMAND, BLUECARD_COMMAND_RXBUF1);
872 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
873 BLUECARD_COMMAND, BLUECARD_COMMAND_RXBUF2);
875 /* XXX: Control the point at which RTS is enabled */
876 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
877 BLUECARD_RXCONTROL, BLUECARD_RXCONTROL_RTSLEVEL(0x0f) | 1);
879 /* Timeout before it is safe to send the first HCI packet */
880 tsleep(sc, PCATCH, "btbc_enable", hz * 2);
882 btbc_set_baudrate(sc, BTBC_DEFAULT_BAUDRATE);
884 splx(s);
885 return 0;
887 fail2:
888 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_intr);
889 sc->sc_intr = NULL;
890 fail1:
891 splx(s);
892 return err;
895 static void
896 btbc_disable(device_t self)
898 struct btbc_softc *sc = device_private(self);
899 int s;
901 if ((sc->sc_flags & BTBC_ENABLED) == 0)
902 return;
904 s = spltty();
906 pcmcia_function_disable(sc->sc_pf);
908 if (sc->sc_intr) {
909 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_intr);
910 sc->sc_intr = NULL;
913 if (sc->sc_rxp) {
914 m_freem(sc->sc_rxp);
915 sc->sc_rxp = NULL;
918 if (sc->sc_txp) {
919 m_freem(sc->sc_txp);
920 sc->sc_txp = NULL;
923 MBUFQ_DRAIN(&sc->sc_cmdq);
924 MBUFQ_DRAIN(&sc->sc_aclq);
925 MBUFQ_DRAIN(&sc->sc_scoq);
927 sc->sc_flags &= ~BTBC_ENABLED;
929 /* Disable LED */
930 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
931 BLUECARD_LEDCONTROL, 0x00);
933 /* Reset card */
934 sc->sc_ctrlreg = BLUECARD_CONTROL_RESET | BLUECARD_CONTROL_CARDRESET;
935 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, BLUECARD_CONTROL,
936 sc->sc_ctrlreg);
938 /* Turn FPGA off */
939 bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
940 BLUECARD_CARDRESET, 0x80);
942 splx(s);
945 static void
946 btbc_output_cmd(device_t self, struct mbuf *m)
948 struct btbc_softc *sc = device_private(self);
949 int s;
951 KASSERT(sc->sc_flags & BTBC_ENABLED);
953 M_SETCTX(m, NULL);
955 s = spltty();
956 MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
957 if ((sc->sc_flags & BTBC_XMIT) == 0)
958 btbc_start(sc);
960 splx(s);
963 static void
964 btbc_output_acl(device_t self, struct mbuf *m)
966 struct btbc_softc *sc = device_private(self);
967 int s;
969 KASSERT(sc->sc_flags & BTBC_ENABLED);
971 M_SETCTX(m, NULL);
973 s = spltty();
974 MBUFQ_ENQUEUE(&sc->sc_aclq, m);
975 if ((sc->sc_flags & BTBC_XMIT) == 0)
976 btbc_start(sc);
978 splx(s);
981 static void
982 btbc_output_sco(device_t self, struct mbuf *m)
984 struct btbc_softc *sc = device_private(self);
985 int s;
987 KASSERT(sc->sc_flags & BTBC_ENABLED);
989 s = spltty();
990 MBUFQ_ENQUEUE(&sc->sc_scoq, m);
991 if ((sc->sc_flags & BTBC_XMIT) == 0)
992 btbc_start(sc);
994 splx(s);
997 static void
998 btbc_stats(device_t self, struct bt_stats *dest, int flush)
1000 struct btbc_softc *sc = device_private(self);
1001 int s;
1003 s = spltty();
1004 memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
1006 if (flush)
1007 memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
1009 splx(s);