Hi! Iain and all,
I am supporting NOKIA DTL-1/4 now. (SOCKET Bluetooth CF 8510-00159F and older version) Linux supported it by drivers/bluetooth/dtl1_cs.c. This obtains BDADDR now and does inquiry. However, this should attach/ detach the 4byte header at btuart. The support of DTL can change some parameters. I think that ioctl is necessary for that. @@ -191,6 +210,24 @@ sc->sc_unit = hci_attach(&btuart_hci, self, 0); if (sc->sc_unit == NULL) aprint_error_dev(self, "HCI attach failed\n"); + +if (1) { + struct hci_if *btuart_dtl_hci = + malloc(sizeof(struct hci_if), M_BLUETOOTH, M_ZERO | M_WAITOK); + + memcpy(btuart_dtl_hci, sc->sc_unit->hci_if, sizeof(struct hci_if)); + btuart_dtl_hci->output_cmd = btuart_dtl_output_cmd; + btuart_dtl_hci->output_acl = btuart_dtl_output_acl; + btuart_dtl_hci->output_sco = btuart_dtl_output_sco; + sc->sc_unit->hci_if = btuart_dtl_hci; + sc->sc_input = btuart_dtl_input; + sc->sc_state = BTUART_RECV_DTL_HDR; + sc->sc_want = sizeof(struct btuart_dtl_header); +} else { + sc->sc_input = btuart_input; + sc->sc_state = BTUART_RECV_PKT_TYPE; + sc->sc_want = 1; +} Should we support ioctl for this? Or, do you have a better idea? Thanks, -- kiyohara
Index: btuart.c =================================================================== RCS file: /cvsroot/src/sys/dev/bluetooth/btuart.c,v retrieving revision 1.23 diff -u -r1.23 btuart.c --- btuart.c 12 May 2009 12:10:46 -0000 1.23 +++ btuart.c 18 Jan 2010 12:01:42 -0000 @@ -1,7 +1,7 @@ /* $NetBSD: btuart.c,v 1.23 2009/05/12 12:10:46 cegger Exp $ */ /*- - * Copyright (c) 2006, 2007 KIYOHARA Takashi + * Copyright (c) 2006, 2007, 2010 KIYOHARA Takashi * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,6 +59,7 @@ struct hci_unit *sc_unit; /* Bluetooth HCI handle */ struct bt_stats sc_stats; + void (*sc_input)(struct btuart_softc *, struct mbuf *); int sc_state; /* receive state */ int sc_want; /* how much we want */ struct mbuf * sc_rxp; /* incoming packet */ @@ -73,13 +74,25 @@ }; /* sc_state */ -#define BTUART_RECV_PKT_TYPE 0 /* packet type */ -#define BTUART_RECV_ACL_HDR 1 /* acl header */ -#define BTUART_RECV_SCO_HDR 2 /* sco header */ -#define BTUART_RECV_EVENT_HDR 3 /* event header */ -#define BTUART_RECV_ACL_DATA 4 /* acl packet data */ -#define BTUART_RECV_SCO_DATA 5 /* sco packet data */ -#define BTUART_RECV_EVENT_DATA 6 /* event packet data */ +#define BTUART_RECV_PKT_TYPE 0 /* packet type */ +#define BTUART_RECV_ACL_HDR 1 /* acl header */ +#define BTUART_RECV_SCO_HDR 2 /* sco header */ +#define BTUART_RECV_EVENT_HDR 3 /* event header */ +#define BTUART_RECV_ACL_DATA 4 /* acl packet data */ +#define BTUART_RECV_SCO_DATA 5 /* sco packet data */ +#define BTUART_RECV_EVENT_DATA 6 /* event packet data */ +#define BTUART_RECV_DTL_HDR 7 /* DTL header */ +#define BTUART_RECV_DTL_CTRL_DATA 8 /* DTL control data */ +#define BTUART_RECV_DTL_ACL_DATA 9 /* DTL acl data */ +#define BTUART_RECV_DTL_SCO_DATA 10 /* DTL sco data */ +#define BTUART_RECV_DTL_EVENT_DATA 11 /* DTL event data */ + +struct btuart_dtl_header { /* NOKIA DTL-1/4 header */ + uint8_t type; + uint8_t rsvd; + uint16_t len; +} __packed; +#define BTUART_DTL_HEADER_TYPE 0x80 void btuartattach(int); static int btuart_match(device_t, cfdata_t, void *); @@ -99,6 +112,12 @@ static void btuart_output_sco(device_t, struct mbuf *); static void btuart_stats(device_t, struct bt_stats *, int); +static void btuart_input(struct btuart_softc *, struct mbuf *); +static void btuart_dtl_input(struct btuart_softc *, struct mbuf *); +static void btuart_dtl_output_cmd(device_t, struct mbuf *); +static void btuart_dtl_output_acl(device_t, struct mbuf *); +static void btuart_dtl_output_sco(device_t, struct mbuf *); + /* * It doesn't need to be exported, as only btuartattach() uses it, * but there's no "official" way to make it static. @@ -191,6 +210,24 @@ sc->sc_unit = hci_attach(&btuart_hci, self, 0); if (sc->sc_unit == NULL) aprint_error_dev(self, "HCI attach failed\n"); + +if (1) { + struct hci_if *btuart_dtl_hci = + malloc(sizeof(struct hci_if), M_BLUETOOTH, M_ZERO | M_WAITOK); + + memcpy(btuart_dtl_hci, sc->sc_unit->hci_if, sizeof(struct hci_if)); + btuart_dtl_hci->output_cmd = btuart_dtl_output_cmd; + btuart_dtl_hci->output_acl = btuart_dtl_output_acl; + btuart_dtl_hci->output_sco = btuart_dtl_output_sco; + sc->sc_unit->hci_if = btuart_dtl_hci; + sc->sc_input = btuart_dtl_input; + sc->sc_state = BTUART_RECV_DTL_HDR; + sc->sc_want = sizeof(struct btuart_dtl_header); +} else { + sc->sc_input = btuart_input; + sc->sc_state = BTUART_RECV_PKT_TYPE; + sc->sc_want = 1; +} } /* @@ -351,8 +388,7 @@ /* new packet */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { - aprint_error_dev(sc->sc_dev, - "out of memory\n"); + aprint_error_dev(sc->sc_dev, "out of memory\n"); sc->sc_stats.err_rx++; return 0; /* (lost sync) */ } @@ -360,15 +396,11 @@ sc->sc_rxp = m; m->m_pkthdr.len = m->m_len = 0; space = MHLEN; - - sc->sc_state = BTUART_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"); + aprint_error_dev(sc->sc_dev, "out of memory\n"); sc->sc_stats.err_rx++; return 0; /* (lost sync) */ } @@ -390,87 +422,8 @@ sc->sc_stats.byte_rx++; sc->sc_want--; - if (sc->sc_want > 0) - return 0; /* want more */ - - switch (sc->sc_state) { - case BTUART_RECV_PKT_TYPE: /* Got packet type */ - - switch (c) { - case HCI_ACL_DATA_PKT: - sc->sc_state = BTUART_RECV_ACL_HDR; - sc->sc_want = sizeof(hci_acldata_hdr_t) - 1; - break; - - case HCI_SCO_DATA_PKT: - sc->sc_state = BTUART_RECV_SCO_HDR; - sc->sc_want = sizeof(hci_scodata_hdr_t) - 1; - break; - - case HCI_EVENT_PKT: - sc->sc_state = BTUART_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", c); - sc->sc_stats.err_rx++; - m_freem(sc->sc_rxp); - sc->sc_rxp = NULL; - return 0; /* (lost sync) */ - } - - break; - - /* - * we assume (correctly of course :) that the packet headers all fit - * into a single pkthdr mbuf - */ - case BTUART_RECV_ACL_HDR: /* Got ACL Header */ - sc->sc_state = BTUART_RECV_ACL_DATA; - sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length; - sc->sc_want = le16toh(sc->sc_want); - break; - - case BTUART_RECV_SCO_HDR: /* Got SCO Header */ - sc->sc_state = BTUART_RECV_SCO_DATA; - sc->sc_want = mtod(m, hci_scodata_hdr_t *)->length; - break; - - case BTUART_RECV_EVENT_HDR: /* Got Event Header */ - sc->sc_state = BTUART_RECV_EVENT_DATA; - sc->sc_want = mtod(m, hci_event_hdr_t *)->length; - break; - - case BTUART_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; - break; - - case BTUART_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; - break; - - case BTUART_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; - break; - - default: - panic("%s: invalid state %d!\n", - device_xname(sc->sc_dev), sc->sc_state); - } + if (sc->sc_want == 0) + sc->sc_input(sc, m); return 0; } @@ -667,3 +620,304 @@ splx(s); } + + + +static void +btuart_input(struct btuart_softc *sc, struct mbuf *m) +{ + + switch (sc->sc_state) { + case BTUART_RECV_PKT_TYPE: /* Got packet type */ + switch (*mtod(m, uint8_t *)) { + case HCI_ACL_DATA_PKT: + sc->sc_state = BTUART_RECV_ACL_HDR; + sc->sc_want = sizeof(hci_acldata_hdr_t) - 1; + break; + + case HCI_SCO_DATA_PKT: + sc->sc_state = BTUART_RECV_SCO_HDR; + sc->sc_want = sizeof(hci_scodata_hdr_t) - 1; + break; + + case HCI_EVENT_PKT: + sc->sc_state = BTUART_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", *mtod(m, uint8_t *)); + sc->sc_stats.err_rx++; + m_freem(sc->sc_rxp); + sc->sc_rxp = NULL; /* (lost sync) */ + break; + } + + break; + + /* + * we assume (correctly of course :) that the packet headers all fit + * into a single pkthdr mbuf + */ + case BTUART_RECV_ACL_HDR: /* Got ACL Header */ + sc->sc_state = BTUART_RECV_ACL_DATA; + sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length; + sc->sc_want = le16toh(sc->sc_want); + break; + + case BTUART_RECV_SCO_HDR: /* Got SCO Header */ + sc->sc_state = BTUART_RECV_SCO_DATA; + sc->sc_want = mtod(m, hci_scodata_hdr_t *)->length; + break; + + case BTUART_RECV_EVENT_HDR: /* Got Event Header */ + sc->sc_state = BTUART_RECV_EVENT_DATA; + sc->sc_want = mtod(m, hci_event_hdr_t *)->length; + break; + + case BTUART_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_state = BTUART_RECV_PKT_TYPE; + sc->sc_want = 1; + sc->sc_rxp = NULL; + break; + + case BTUART_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_state = BTUART_RECV_PKT_TYPE; + sc->sc_want = 1; + sc->sc_rxp = NULL; + break; + + case BTUART_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_state = BTUART_RECV_PKT_TYPE; + sc->sc_want = 1; + sc->sc_rxp = NULL; + break; + + default: + panic("%s: invalid state %d!\n", + device_xname(sc->sc_dev), sc->sc_state); + } +} + +/* + * NOKIA DTL-1/4 functions + */ + +static void +btuart_dtl_input(struct btuart_softc *sc, struct mbuf *m) +{ + struct btuart_dtl_header *dtlh = + mtod(sc->sc_rxp, struct btuart_dtl_header *); + + switch (sc->sc_state) { + case BTUART_RECV_DTL_HDR: /* Got DTL header */ + switch (dtlh->type) { + case BTUART_DTL_HEADER_TYPE: + sc->sc_state = BTUART_RECV_DTL_CTRL_DATA; + break; + + case BTUART_DTL_HEADER_TYPE | HCI_ACL_DATA_PKT: + sc->sc_state = BTUART_RECV_DTL_ACL_DATA; + break; + + case BTUART_DTL_HEADER_TYPE | HCI_SCO_DATA_PKT: + sc->sc_state = BTUART_RECV_DTL_SCO_DATA; + break; + + case BTUART_DTL_HEADER_TYPE | HCI_EVENT_PKT: + sc->sc_state = BTUART_RECV_DTL_EVENT_DATA; + break; + + default: + aprint_error_dev(sc->sc_dev, + "Unknown packet type=%#x!\n", dtlh->type); + sc->sc_stats.err_rx++; + m_adj(m, 1); + sc->sc_want++; /* (lost sync) more 1byte... */ + return; + } + dtlh->len = le16toh(dtlh->len); + sc->sc_want = (dtlh->len + 1) & ~0x0001; + break; + + /* + * we assume (correctly of course :) that the packet headers all fit + * into a single pkthdr mbuf + */ + case BTUART_RECV_DTL_CTRL_DATA: /* Control Packet Complete */ + { + int i; + + aprint_normal_dev(sc->sc_dev, "Control Packet received:"); + for (i = 0; i < dtlh->len && i < m->m_len - sizeof(*dtlh); i++) + aprint_normal(" %02x", + mtod(sc->sc_rxp, uint8_t *)[sizeof(*dtlh) + i]); + if (i < dtlh->len) + aprint_normal("(more %dbyte%s)", + dtlh->len - i, dtlh->len - i > 1 ? "s" : ""); + aprint_normal("\n"); + m_freem(sc->sc_rxp); + sc->sc_state = BTUART_RECV_DTL_HDR; + sc->sc_want = sizeof(struct btuart_dtl_header); + sc->sc_rxp = NULL; + break; + } + + case BTUART_RECV_DTL_ACL_DATA: /* ACL Packet Complete */ + if (dtlh->len & 0x0001) + m_adj(m, -1); + m_adj(sc->sc_rxp, + sizeof(struct btuart_dtl_header) - sizeof(uint8_t)); + *mtod(sc->sc_rxp, uint8_t *) = HCI_ACL_DATA_PKT; + if (!hci_input_acl(sc->sc_unit, sc->sc_rxp)) + sc->sc_stats.err_rx++; + + sc->sc_stats.acl_rx++; + sc->sc_state = BTUART_RECV_DTL_HDR; + sc->sc_want = sizeof(struct btuart_dtl_header); + sc->sc_rxp = NULL; + break; + + case BTUART_RECV_DTL_SCO_DATA: /* SCO Packet Complete */ + if (dtlh->len & 0x0001) + m_adj(m, -1); + m_adj(sc->sc_rxp, + sizeof(struct btuart_dtl_header) - sizeof(uint8_t)); + *mtod(sc->sc_rxp, uint8_t *) = HCI_SCO_DATA_PKT; + if (!hci_input_sco(sc->sc_unit, sc->sc_rxp)) + sc->sc_stats.err_rx++; + + sc->sc_stats.sco_rx++; + sc->sc_state = BTUART_RECV_DTL_HDR; + sc->sc_want = sizeof(struct btuart_dtl_header); + sc->sc_rxp = NULL; + break; + + case BTUART_RECV_DTL_EVENT_DATA:/* Event Packet Complete */ + if (dtlh->len & 0x0001) + m_adj(m, -1); + m_adj(sc->sc_rxp, + sizeof(struct btuart_dtl_header) - sizeof(uint8_t)); + *mtod(sc->sc_rxp, uint8_t *) = HCI_EVENT_PKT; + if (!hci_input_event(sc->sc_unit, sc->sc_rxp)) + sc->sc_stats.err_rx++; + + sc->sc_stats.evt_rx++; + sc->sc_state = BTUART_RECV_DTL_HDR; + sc->sc_want = sizeof(struct btuart_dtl_header); + sc->sc_rxp = NULL; + break; + + default: + panic("%s: invalid state %d!\n", + device_xname(sc->sc_dev), sc->sc_state); + } +} + +static void +btuart_dtl_output_cmd(device_t self, struct mbuf *m) +{ + struct btuart_softc *sc = device_private(self); + struct btuart_dtl_header *dtlh; + hci_cmd_hdr_t hdr; + int s; + + KASSERT(sc->sc_enabled); + + m_copydata(m, 0, sizeof(hdr), &hdr); + m_adj(m, sizeof(hdr.type)); + + M_PREPEND(m, sizeof(struct btuart_dtl_header), M_WAITOK); + dtlh = mtod(m, struct btuart_dtl_header *); + dtlh->type = hdr.type | BTUART_DTL_HEADER_TYPE; + dtlh->rsvd = 0; + /* already adjusted size for type of header */ + dtlh->len = htole16(sizeof(hdr) - sizeof(hdr.type) + hdr.length); + if (dtlh->len & 0x1) + m_copyback(m, m->m_pkthdr.len, 1, &dtlh->rsvd); /* Add pad */ + + M_SETCTX(m, NULL); + + s = spltty(); + MBUFQ_ENQUEUE(&sc->sc_cmdq, m); + if (!sc->sc_xmit) + btuartstart(sc->sc_tp); + + splx(s); +} + +static void +btuart_dtl_output_acl(device_t self, struct mbuf *m) +{ + struct btuart_softc *sc = device_private(self); + struct btuart_dtl_header *dtlh; + hci_acldata_hdr_t hdr; + int s; + + KASSERT(sc->sc_enabled); + + m_copydata(m, 0, sizeof(hdr), &hdr); + m_adj(m, sizeof(hdr.type)); + + M_PREPEND(m, sizeof(struct btuart_dtl_header), M_WAITOK); + dtlh = mtod(m, struct btuart_dtl_header *); + dtlh->type = hdr.type | BTUART_DTL_HEADER_TYPE; + dtlh->rsvd = 0; + /* already adjusted size for type of header */ + dtlh->len = + htole16(sizeof(hdr) - sizeof(hdr.type) + le16toh(hdr.length)); + if (dtlh->len & 0x1) + m_copyback(m, m->m_pkthdr.len, 1, &dtlh->rsvd); /* Add pad */ + + M_SETCTX(m, NULL); + + s = spltty(); + MBUFQ_ENQUEUE(&sc->sc_aclq, m); + if (!sc->sc_xmit) + btuartstart(sc->sc_tp); + + splx(s); +} + +static void +btuart_dtl_output_sco(device_t self, struct mbuf *m) +{ + struct btuart_softc *sc = device_private(self); + struct btuart_dtl_header *dtlh; + hci_scodata_hdr_t hdr; + int s; + + KASSERT(sc->sc_enabled); + + m_copydata(m, 0, sizeof(hdr), &hdr); + m_adj(m, sizeof(hdr.type)); + + M_PREPEND(m, sizeof(struct btuart_dtl_header), M_WAITOK); + dtlh = mtod(m, struct btuart_dtl_header *); + dtlh->type = hdr.type | BTUART_DTL_HEADER_TYPE; + dtlh->rsvd = 0; + /* already adjusted size for type of header */ + dtlh->len = htole16(sizeof(hdr) - sizeof(hdr.type) + hdr.length); + if (dtlh->len & 0x1) + m_copyback(m, m->m_pkthdr.len, 1, &dtlh->rsvd); /* Add pad */ + + s = spltty(); + MBUFQ_ENQUEUE(&sc->sc_scoq, m); + if (!sc->sc_xmit) + btuartstart(sc->sc_tp); + + splx(s); +}