static void bt3c_intr(void *context) { bt3c_softc_p sc = (bt3c_softc_p) context; u_int16_t control, status; if (sc == NULL || sc->ith == NULL) { printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE); return; } bt3c_read_control(sc, control); if ((control & 0x80) == 0) return; bt3c_read(sc, 0x7001, status); NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status); if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) { NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status); return; } /* Receive complete */ if (status & 0x0001) bt3c_receive(sc); /* Record status and schedule SWI */ sc->status |= status; swi_sched(sc->ith, 0); /* Complete interrupt */ bt3c_write(sc, 0x7001, 0x0000); bt3c_write_control(sc, control); } /* bt3c_intr */
static void bt3c_send(node_p node, hook_p hook, void *arg, int completed) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); struct mbuf *m = NULL; int i, wrote, len; if (sc == NULL) return; if (completed) sc->flags &= ~BT3C_XMIT; if (sc->flags & BT3C_XMIT) return; bt3c_set_address(sc, 0x7080); for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) { IF_DEQUEUE(&sc->outq, m); if (m == NULL) break; while (m != NULL) { len = min((BT3C_FIFO_SIZE - wrote), m->m_len); for (i = 0; i < len; i++) bt3c_write_data(sc, m->m_data[i]); wrote += len; m->m_data += len; m->m_len -= len; if (m->m_len > 0) break; m = m_free(m); } if (m != NULL) { IF_PREPEND(&sc->outq, m); break; } NG_BT3C_STAT_PCKTS_SENT(sc->stat); } if (wrote > 0) { NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote); NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote); bt3c_write(sc, 0x7005, wrote); sc->flags |= BT3C_XMIT; } } /* bt3c_send */
static void bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size) { ng_bt3c_firmware_block_ep const *block = NULL; u_int16_t const *data = NULL; int i, size; u_int8_t c; /* Reset */ device_printf(sc->dev, "Reseting the card...\n"); bt3c_write(sc, 0x8040, 0x0404); bt3c_write(sc, 0x8040, 0x0400); DELAY(1); bt3c_write(sc, 0x8040, 0x0404); DELAY(17); /* Download firmware */ device_printf(sc->dev, "Starting firmware download process...\n"); for (size = 0; size < firmware_size; ) { block = (ng_bt3c_firmware_block_ep const *)(firmware + size); data = (u_int16_t const *)(block + 1); if (bootverbose) device_printf(sc->dev, "Download firmware block, " \ "address=%#08x, size=%d words, aligment=%d\n", block->block_address, block->block_size, block->block_alignment); bt3c_set_address(sc, block->block_address); for (i = 0; i < block->block_size; i++) bt3c_write_data(sc, data[i]); size += (sizeof(*block) + (block->block_size * 2) + block->block_alignment); } DELAY(17); device_printf(sc->dev, "Firmware download process complete\n"); /* Boot */ device_printf(sc->dev, "Starting the card...\n"); bt3c_set_address(sc, 0x3000); bt3c_read_control(sc, c); bt3c_write_control(sc, (c | 0x40)); DELAY(17); /* Clear registers */ device_printf(sc->dev, "Clearing card registers...\n"); bt3c_write(sc, 0x7006, 0x0000); bt3c_write(sc, 0x7005, 0x0000); bt3c_write(sc, 0x7001, 0x0000); DELAY(1000); } /* bt3c_download_firmware */
static void bt3c_write_wakeup(bt3c_info_t *info, int from) { unsigned long flags; if (!info) { printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n"); return; } if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) return; spin_lock_irqsave(&(info->lock), flags); do { register unsigned int iobase = info->link.io.BasePort1; register struct sk_buff *skb; register int len; if (!(info->link.state & DEV_PRESENT)) break; if (!(skb = skb_dequeue(&(info->txq)))) { clear_bit(XMIT_SENDING, &(info->tx_state)); break; } /* Send frame */ len = bt3c_write(iobase, 256, skb->data, skb->len); if (len != skb->len) { printk(KERN_WARNING "bt3c_cs: very strange\n"); } dev_kfree_skb_any(skb); info->hdev.stat.byte_tx += len; } while (0); spin_unlock_irqrestore(&(info->lock), flags); }
/* * receive incoming data from device, store in mbuf chain and * pass on complete packets to bt device */ static void bt3c_receive(struct bt3c_softc *sc) { struct mbuf *m = sc->sc_rxp; int space = 0; uint16_t count; uint8_t b; /* * If we already started a packet, find the * trailing end of it. */ if (m) { while (m->m_next) m = m->m_next; space = M_TRAILINGSPACE(m); } count = bt3c_read(sc, BT3C_RX_COUNT); bt3c_set_address(sc, BT3C_RX_FIFO); while (count > 0) { if (space == 0) { if (m == NULL) { /* new packet */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { aprint_error_dev(sc->sc_dev, "out of memory\n"); sc->sc_stats.err_rx++; goto out; /* (lost sync) */ } sc->sc_rxp = m; m->m_pkthdr.len = m->m_len = 0; space = MHLEN; sc->sc_state = BT3C_RECV_PKT_TYPE; sc->sc_want = 1; } else { /* extend mbuf */ MGET(m->m_next, M_DONTWAIT, MT_DATA); if (m->m_next == NULL) { aprint_error_dev(sc->sc_dev, "out of memory\n"); sc->sc_stats.err_rx++; goto out; /* (lost sync) */ } m = m->m_next; m->m_len = 0; space = MLEN; if (sc->sc_want > MINCLSIZE) { MCLGET(m, M_DONTWAIT); if (m->m_flags & M_EXT) space = MCLBYTES; } } } b = bt3c_get(sc); mtod(m, uint8_t *)[m->m_len++] = b; count--; space--; sc->sc_rxp->m_pkthdr.len++; sc->sc_stats.byte_rx++; sc->sc_want--; if (sc->sc_want > 0) continue; /* want more */ switch (sc->sc_state) { case BT3C_RECV_PKT_TYPE: /* Got packet type */ switch (b) { case HCI_ACL_DATA_PKT: sc->sc_state = BT3C_RECV_ACL_HDR; sc->sc_want = sizeof(hci_acldata_hdr_t) - 1; break; case HCI_SCO_DATA_PKT: sc->sc_state = BT3C_RECV_SCO_HDR; sc->sc_want = sizeof(hci_scodata_hdr_t) - 1; break; case HCI_EVENT_PKT: sc->sc_state = BT3C_RECV_EVENT_HDR; sc->sc_want = sizeof(hci_event_hdr_t) - 1; break; default: aprint_error_dev(sc->sc_dev, "Unknown packet type=%#x!\n", b); sc->sc_stats.err_rx++; m_freem(sc->sc_rxp); sc->sc_rxp = NULL; goto out; /* (lost sync) */ } break; /* * we assume (correctly of course :) that the packet headers * all fit into a single pkthdr mbuf */ case BT3C_RECV_ACL_HDR: /* Got ACL Header */ sc->sc_state = BT3C_RECV_ACL_DATA; sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length; sc->sc_want = le16toh(sc->sc_want); break; case BT3C_RECV_SCO_HDR: /* Got SCO Header */ sc->sc_state = BT3C_RECV_SCO_DATA; sc->sc_want = mtod(m, hci_scodata_hdr_t *)->length; break; case BT3C_RECV_EVENT_HDR: /* Got Event Header */ sc->sc_state = BT3C_RECV_EVENT_DATA; sc->sc_want = mtod(m, hci_event_hdr_t *)->length; break; case BT3C_RECV_ACL_DATA: /* ACL Packet Complete */ if (!hci_input_acl(sc->sc_unit, sc->sc_rxp)) sc->sc_stats.err_rx++; sc->sc_stats.acl_rx++; sc->sc_rxp = m = NULL; space = 0; break; case BT3C_RECV_SCO_DATA: /* SCO Packet Complete */ if (!hci_input_sco(sc->sc_unit, sc->sc_rxp)) sc->sc_stats.err_rx++; sc->sc_stats.sco_rx++; sc->sc_rxp = m = NULL; space = 0; break; case BT3C_RECV_EVENT_DATA: /* Event Packet Complete */ if (!hci_input_event(sc->sc_unit, sc->sc_rxp)) sc->sc_stats.err_rx++; sc->sc_stats.evt_rx++; sc->sc_rxp = m = NULL; space = 0; break; default: panic("%s: invalid state %d!\n", device_xname(sc->sc_dev), sc->sc_state); } } out: bt3c_write(sc, BT3C_RX_COUNT, 0x0000); }
static void bt3c_receive(bt3c_softc_p sc) { u_int16_t i, count, c; /* Receive data from the card */ bt3c_read(sc, 0x7006, count); NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count); bt3c_set_address(sc, 0x7480); for (i = 0; i < count; i++) { /* Allocate new mbuf if needed */ if (sc->m == NULL) { sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; MGETHDR(sc->m, M_NOWAIT, MT_DATA); if (sc->m == NULL) { NG_BT3C_ERR(sc->dev, "Could not get mbuf\n"); NG_BT3C_STAT_IERROR(sc->stat); break; /* XXX lost of sync */ } if (!(MCLGET(sc->m, M_NOWAIT))) { NG_FREE_M(sc->m); NG_BT3C_ERR(sc->dev, "Could not get cluster\n"); NG_BT3C_STAT_IERROR(sc->stat); break; /* XXX lost of sync */ } sc->m->m_len = sc->m->m_pkthdr.len = 0; } /* Read and append character to mbuf */ bt3c_read_data(sc, c); if (sc->m->m_pkthdr.len >= MCLBYTES) { NG_BT3C_ERR(sc->dev, "Oversized frame\n"); NG_FREE_M(sc->m); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; break; /* XXX lost of sync */ } mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c; sc->m->m_pkthdr.len ++; NG_BT3C_INFO(sc->dev, "Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len); if (sc->m->m_pkthdr.len < sc->want) continue; /* wait for more */ switch (sc->state) { /* Got packet indicator */ case NG_BT3C_W4_PKT_IND: NG_BT3C_INFO(sc->dev, "Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *)); sc->state = NG_BT3C_W4_PKT_HDR; /* * Since packet indicator included in the packet * header just set sc->want to sizeof(packet header). */ switch (*mtod(sc->m, u_int8_t *)) { case NG_HCI_ACL_DATA_PKT: sc->want = sizeof(ng_hci_acldata_pkt_t); break; case NG_HCI_SCO_DATA_PKT: sc->want = sizeof(ng_hci_scodata_pkt_t); break; case NG_HCI_EVENT_PKT: sc->want = sizeof(ng_hci_event_pkt_t); break; default: NG_BT3C_ERR(sc->dev, "Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *)); NG_BT3C_STAT_IERROR(sc->stat); NG_FREE_M(sc->m); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; break; } break; /* Got packet header */ case NG_BT3C_W4_PKT_HDR: sc->state = NG_BT3C_W4_PKT_DATA; switch (*mtod(sc->m, u_int8_t *)) { case NG_HCI_ACL_DATA_PKT: c = le16toh(mtod(sc->m, ng_hci_acldata_pkt_t *)->length); break; case NG_HCI_SCO_DATA_PKT: c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length; break; case NG_HCI_EVENT_PKT: c = mtod(sc->m, ng_hci_event_pkt_t *)->length; break; default: KASSERT(0, ("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *))); break; } NG_BT3C_INFO(sc->dev, "Got packet header, packet type=%#x, got so far %d, payload size=%d\n", *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len, c); if (c > 0) { sc->want += c; break; } /* else FALLTHROUGH and deliver frame */ /* XXX is this true? should we deliver empty frame? */ /* Got packet data */ case NG_BT3C_W4_PKT_DATA: NG_BT3C_INFO(sc->dev, "Got full packet, packet type=%#x, packet size=%d\n", *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len); NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len); NG_BT3C_STAT_PCKTS_RECV(sc->stat); IF_LOCK(&sc->inq); if (_IF_QFULL(&sc->inq)) { NG_BT3C_ERR(sc->dev, "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len); NG_BT3C_STAT_IERROR(sc->stat); NG_FREE_M(sc->m); } else { _IF_ENQUEUE(&sc->inq, sc->m); sc->m = NULL; } IF_UNLOCK(&sc->inq); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; break; default: KASSERT(0, ("Invalid node state=%d", sc->state)); break; } } bt3c_write(sc, 0x7006, 0x0000); } /* bt3c_receive */