1 1.24 rin /* $NetBSD: bt3c.c,v 1.24 2024/07/05 04:31:51 rin Exp $ */ 2 1.1 gdamore 3 1.1 gdamore /*- 4 1.1 gdamore * Copyright (c) 2005 Iain D. Hibbert, 5 1.1 gdamore * All rights reserved. 6 1.1 gdamore * 7 1.1 gdamore * Redistribution and use in source and binary forms, with or without 8 1.1 gdamore * modification, are permitted provided that the following conditions 9 1.1 gdamore * are met: 10 1.1 gdamore * 1. Redistributions of source code must retain the above copyright 11 1.1 gdamore * notice, this list of conditions and the following disclaimer. 12 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 gdamore * notice, this list of conditions and the following disclaimer in the 14 1.1 gdamore * documentation and/or other materials provided with the distribution. 15 1.1 gdamore * 3. The name of the author may not be used to endorse or promote products 16 1.1 gdamore * derived from this software without specific prior written permission. 17 1.1 gdamore * 18 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 gdamore * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 gdamore * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 gdamore * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 gdamore * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 gdamore * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 gdamore * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 gdamore * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 gdamore * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 gdamore * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 gdamore */ 29 1.1 gdamore 30 1.1 gdamore /* 31 1.1 gdamore * Driver for the 3Com Bluetooth PC Card 3CRWB6096, written with reference to 32 1.1 gdamore * FreeBSD and BlueZ drivers for same, with credit for those going to: 33 1.1 gdamore * 34 1.1 gdamore * Maksim Yevmenkin <m_evmenkin (at) yahoo.com> (FreeBSD) 35 1.1 gdamore * Marcel Holtmann <marcel (at) holtmann.org> (BlueZ) 36 1.1 gdamore * Jose Orlando Pereira <jop (at) di.uminho.pt> (BlueZ) 37 1.1 gdamore * David Hinds <dahinds (at) users.sourceforge.net> (Original Code) 38 1.1 gdamore */ 39 1.1 gdamore 40 1.1 gdamore /* 41 1.1 gdamore * The CIS info from my card: 42 1.1 gdamore * 43 1.1 gdamore * pcmcia1: CIS tuple chain: 44 1.1 gdamore * CISTPL_DEVICE type=null speed=null 45 1.1 gdamore * 01 03 00 00 ff 46 1.1 gdamore * CISTPL_VERS_1 47 1.1 gdamore * 15 24 05 00 33 43 4f 4d 00 33 43 52 57 42 36 30 48 1.1 gdamore * 2d 41 00 42 6c 75 65 74 6f 6f 74 68 20 50 43 20 49 1.1 gdamore * 43 61 72 64 00 ff 50 1.1 gdamore * CISTPL_MANFID 51 1.1 gdamore * 20 04 01 01 40 00 52 1.1 gdamore * CISTPL_FUNCID 53 1.1 gdamore * 21 02 02 01 54 1.1 gdamore * CISTPL_CONFIG 55 1.1 gdamore * 1a 06 05 30 20 03 17 00 56 1.1 gdamore * CISTPL_CFTABLE_ENTRY 57 1.1 gdamore * 1b 09 f0 41 18 a0 40 07 30 ff ff 58 1.1 gdamore * unhandled CISTPL 80 59 1.1 gdamore * 80 0a 02 01 40 00 2d 00 00 00 00 ff 60 1.1 gdamore * CISTPL_NO_LINK 61 1.1 gdamore * 14 00 62 1.1 gdamore * CISTPL_END 63 1.1 gdamore * ff 64 1.1 gdamore * pcmcia1: CIS version PC Card Standard 5.0 65 1.1 gdamore * pcmcia1: CIS info: 3COM, 3CRWB60-A, Bluetooth PC Card 66 1.1 gdamore * pcmcia1: Manufacturer code 0x101, product 0x40 67 1.1 gdamore * pcmcia1: function 0: serial port, ccr addr 320 mask 17 68 1.1 gdamore * pcmcia1: function 0, config table entry 48: I/O card; irq mask ffff; iomask 0, iospace 0-7; rdybsy_active io8 irqlevel 69 1.1 gdamore */ 70 1.1 gdamore 71 1.1 gdamore #include <sys/cdefs.h> 72 1.24 rin __KERNEL_RCSID(0, "$NetBSD: bt3c.c,v 1.24 2024/07/05 04:31:51 rin Exp $"); 73 1.1 gdamore 74 1.1 gdamore #include <sys/param.h> 75 1.1 gdamore #include <sys/device.h> 76 1.1 gdamore #include <sys/mbuf.h> 77 1.1 gdamore #include <sys/systm.h> 78 1.1 gdamore 79 1.12 ad #include <sys/cpu.h> 80 1.12 ad #include <sys/bus.h> 81 1.12 ad #include <sys/intr.h> 82 1.1 gdamore 83 1.1 gdamore #include <dev/pcmcia/pcmciareg.h> 84 1.1 gdamore #include <dev/pcmcia/pcmciavar.h> 85 1.1 gdamore #include <dev/pcmcia/pcmciadevs.h> 86 1.1 gdamore 87 1.1 gdamore #include <netbt/bluetooth.h> 88 1.1 gdamore #include <netbt/hci.h> 89 1.1 gdamore 90 1.1 gdamore #include <dev/firmload.h> 91 1.1 gdamore #define BT3C_FIRMWARE_FILE "BT3CPCC.bin" 92 1.1 gdamore 93 1.1 gdamore /************************************************************************** 94 1.1 gdamore * 95 1.1 gdamore * bt3c autoconfig glue 96 1.1 gdamore */ 97 1.1 gdamore 98 1.1 gdamore struct bt3c_softc { 99 1.13 plunky device_t sc_dev; 100 1.1 gdamore 101 1.1 gdamore struct pcmcia_function *sc_pf; /* our PCMCIA function */ 102 1.1 gdamore struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 103 1.1 gdamore int sc_iow; /* our i/o window */ 104 1.1 gdamore int sc_flags; /* flags */ 105 1.1 gdamore 106 1.16 plunky struct hci_unit *sc_unit; /* Bluetooth HCI Unit */ 107 1.16 plunky struct bt_stats sc_stats; /* HCI stats */ 108 1.1 gdamore 109 1.1 gdamore /* hardware interrupt */ 110 1.1 gdamore void *sc_intr; /* cookie */ 111 1.1 gdamore int sc_state; /* receive state */ 112 1.1 gdamore int sc_want; /* how much we want */ 113 1.1 gdamore struct mbuf *sc_rxp; /* incoming packet */ 114 1.1 gdamore struct mbuf *sc_txp; /* outgoing packet */ 115 1.16 plunky 116 1.16 plunky /* transmit queues */ 117 1.16 plunky MBUFQ_HEAD() sc_cmdq; /* commands */ 118 1.16 plunky MBUFQ_HEAD() sc_aclq; /* ACL data */ 119 1.16 plunky MBUFQ_HEAD() sc_scoq; /* SCO data */ 120 1.1 gdamore }; 121 1.1 gdamore 122 1.1 gdamore /* sc_state */ /* receiving */ 123 1.1 gdamore #define BT3C_RECV_PKT_TYPE 0 /* packet type */ 124 1.1 gdamore #define BT3C_RECV_ACL_HDR 1 /* acl header */ 125 1.1 gdamore #define BT3C_RECV_SCO_HDR 2 /* sco header */ 126 1.1 gdamore #define BT3C_RECV_EVENT_HDR 3 /* event header */ 127 1.1 gdamore #define BT3C_RECV_ACL_DATA 4 /* acl packet data */ 128 1.1 gdamore #define BT3C_RECV_SCO_DATA 5 /* sco packet data */ 129 1.1 gdamore #define BT3C_RECV_EVENT_DATA 6 /* event packet data */ 130 1.1 gdamore 131 1.1 gdamore /* sc_flags */ 132 1.16 plunky #define BT3C_XMIT (1 << 1) /* transmit active */ 133 1.16 plunky #define BT3C_ENABLED (1 << 2) /* enabled */ 134 1.1 gdamore 135 1.19 cegger static int bt3c_match(device_t, cfdata_t, void *); 136 1.13 plunky static void bt3c_attach(device_t, device_t, void *); 137 1.13 plunky static int bt3c_detach(device_t, int); 138 1.21 dyoung static bool bt3c_suspend(device_t, const pmf_qual_t *); 139 1.21 dyoung static bool bt3c_resume(device_t, const pmf_qual_t *); 140 1.1 gdamore 141 1.13 plunky CFATTACH_DECL_NEW(bt3c, sizeof(struct bt3c_softc), 142 1.11 plunky bt3c_match, bt3c_attach, bt3c_detach, NULL); 143 1.1 gdamore 144 1.14 plunky static int bt3c_enable(device_t); 145 1.14 plunky static void bt3c_disable(device_t); 146 1.16 plunky static void bt3c_output_cmd(device_t, struct mbuf *); 147 1.16 plunky static void bt3c_output_acl(device_t, struct mbuf *); 148 1.16 plunky static void bt3c_output_sco(device_t, struct mbuf *); 149 1.16 plunky static void bt3c_stats(device_t, struct bt_stats *, int); 150 1.16 plunky 151 1.16 plunky static const struct hci_if bt3c_hci = { 152 1.16 plunky .enable = bt3c_enable, 153 1.16 plunky .disable = bt3c_disable, 154 1.16 plunky .output_cmd = bt3c_output_cmd, 155 1.16 plunky .output_acl = bt3c_output_acl, 156 1.16 plunky .output_sco = bt3c_output_sco, 157 1.16 plunky .get_stats = bt3c_stats, 158 1.16 plunky .ipl = IPL_TTY, 159 1.16 plunky }; 160 1.16 plunky 161 1.16 plunky static void bt3c_start(struct bt3c_softc *); 162 1.1 gdamore 163 1.1 gdamore /************************************************************************** 164 1.1 gdamore * 165 1.1 gdamore * Hardware Definitions & IO routines 166 1.1 gdamore * 167 1.1 gdamore * I made up the names for most of these defs since we dont have 168 1.1 gdamore * manufacturers recommendations, but I dont like raw numbers.. 169 1.1 gdamore * 170 1.1 gdamore * all hardware routines are running at IPL_TTY 171 1.1 gdamore * 172 1.1 gdamore */ 173 1.1 gdamore #define BT3C_ISR 0x7001 /* Interrupt Status Register */ 174 1.1 gdamore #define BT3C_ISR_RXRDY (1<<0) /* Device has data */ 175 1.1 gdamore #define BT3C_ISR_TXRDY (1<<1) /* Finished sending data */ 176 1.1 gdamore #define BT3C_ISR_ANTENNA (1<<5) /* Antenna position changed */ 177 1.1 gdamore 178 1.1 gdamore #define BT3C_CSR 0x7002 /* Card Status Register */ 179 1.1 gdamore #define BT3C_CSR_ANTENNA (1<<4) /* Antenna position */ 180 1.1 gdamore 181 1.1 gdamore #define BT3C_TX_COUNT 0x7005 /* Tx fifo contents */ 182 1.1 gdamore #define BT3C_TX_FIFO 0x7080 /* Transmit Fifo */ 183 1.1 gdamore #define BT3C_RX_COUNT 0x7006 /* Rx fifo contents */ 184 1.1 gdamore #define BT3C_RX_FIFO 0x7480 /* Receive Fifo */ 185 1.1 gdamore #define BT3C_FIFO_SIZE 256 186 1.1 gdamore 187 1.1 gdamore /* IO Registers */ 188 1.1 gdamore #define BT3C_IOR_DATA_L 0x00 /* data low byte */ 189 1.1 gdamore #define BT3C_IOR_DATA_H 0x01 /* data high byte */ 190 1.1 gdamore #define BT3C_IOR_ADDR_L 0x02 /* address low byte */ 191 1.1 gdamore #define BT3C_IOR_ADDR_H 0x03 /* address high byte */ 192 1.1 gdamore #define BT3C_IOR_CNTL 0x04 /* control byte */ 193 1.1 gdamore #define BT3C_IOR_CNTL_BOOT (1<<6) /* Boot Card */ 194 1.1 gdamore #define BT3C_IOR_CNTL_INTR (1<<7) /* Interrupt Requested */ 195 1.1 gdamore #define BT3C_IOR_LEN 0x05 196 1.1 gdamore 197 1.1 gdamore static inline uint16_t 198 1.1 gdamore bt3c_get(struct bt3c_softc *sc) 199 1.1 gdamore { 200 1.1 gdamore uint16_t data; 201 1.1 gdamore 202 1.1 gdamore bus_space_barrier(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 203 1.1 gdamore 0, BT3C_IOR_LEN, BUS_SPACE_BARRIER_READ); 204 1.1 gdamore data = bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 205 1.1 gdamore BT3C_IOR_DATA_L); 206 1.1 gdamore data |= bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 207 1.1 gdamore BT3C_IOR_DATA_H) << 8; 208 1.1 gdamore 209 1.1 gdamore return data; 210 1.1 gdamore } 211 1.1 gdamore 212 1.1 gdamore static inline void 213 1.1 gdamore bt3c_put(struct bt3c_softc *sc, uint16_t data) 214 1.1 gdamore { 215 1.1 gdamore 216 1.1 gdamore bus_space_barrier(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 217 1.1 gdamore 0, BT3C_IOR_LEN, BUS_SPACE_BARRIER_WRITE); 218 1.1 gdamore bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 219 1.1 gdamore BT3C_IOR_DATA_L, data & 0xff); 220 1.1 gdamore bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 221 1.1 gdamore BT3C_IOR_DATA_H, (data >> 8) & 0xff); 222 1.1 gdamore } 223 1.1 gdamore 224 1.1 gdamore static inline uint8_t 225 1.1 gdamore bt3c_read_control(struct bt3c_softc *sc) 226 1.1 gdamore { 227 1.1 gdamore 228 1.1 gdamore bus_space_barrier(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 229 1.1 gdamore 0, BT3C_IOR_LEN, BUS_SPACE_BARRIER_READ); 230 1.1 gdamore return bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 231 1.1 gdamore BT3C_IOR_CNTL); 232 1.1 gdamore } 233 1.1 gdamore 234 1.1 gdamore static inline void 235 1.1 gdamore bt3c_write_control(struct bt3c_softc *sc, uint8_t data) 236 1.1 gdamore { 237 1.1 gdamore 238 1.1 gdamore bus_space_barrier(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 239 1.1 gdamore 0, BT3C_IOR_LEN, BUS_SPACE_BARRIER_WRITE); 240 1.1 gdamore bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 241 1.1 gdamore BT3C_IOR_CNTL, data); 242 1.1 gdamore } 243 1.1 gdamore 244 1.1 gdamore static inline void 245 1.1 gdamore bt3c_set_address(struct bt3c_softc *sc, uint16_t addr) 246 1.1 gdamore { 247 1.1 gdamore 248 1.1 gdamore bus_space_barrier(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 249 1.1 gdamore 0, BT3C_IOR_LEN, BUS_SPACE_BARRIER_WRITE); 250 1.1 gdamore bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 251 1.1 gdamore BT3C_IOR_ADDR_L, addr & 0xff); 252 1.1 gdamore bus_space_write_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh, 253 1.1 gdamore BT3C_IOR_ADDR_H, (addr >> 8) & 0xff); 254 1.1 gdamore } 255 1.1 gdamore 256 1.1 gdamore static inline uint16_t 257 1.1 gdamore bt3c_read(struct bt3c_softc *sc, uint16_t addr) 258 1.1 gdamore { 259 1.1 gdamore 260 1.1 gdamore bt3c_set_address(sc, addr); 261 1.1 gdamore return bt3c_get(sc); 262 1.1 gdamore } 263 1.1 gdamore 264 1.1 gdamore static inline void 265 1.1 gdamore bt3c_write(struct bt3c_softc *sc, uint16_t addr, uint16_t data) 266 1.1 gdamore { 267 1.1 gdamore 268 1.1 gdamore bt3c_set_address(sc, addr); 269 1.1 gdamore bt3c_put(sc, data); 270 1.1 gdamore } 271 1.1 gdamore 272 1.1 gdamore /* 273 1.1 gdamore * receive incoming data from device, store in mbuf chain and 274 1.1 gdamore * pass on complete packets to bt device 275 1.1 gdamore */ 276 1.1 gdamore static void 277 1.1 gdamore bt3c_receive(struct bt3c_softc *sc) 278 1.1 gdamore { 279 1.1 gdamore struct mbuf *m = sc->sc_rxp; 280 1.1 gdamore int space = 0; 281 1.1 gdamore uint16_t count; 282 1.1 gdamore uint8_t b; 283 1.1 gdamore 284 1.1 gdamore /* 285 1.1 gdamore * If we already started a packet, find the 286 1.1 gdamore * trailing end of it. 287 1.1 gdamore */ 288 1.1 gdamore if (m) { 289 1.1 gdamore while (m->m_next) 290 1.1 gdamore m = m->m_next; 291 1.1 gdamore 292 1.1 gdamore space = M_TRAILINGSPACE(m); 293 1.1 gdamore } 294 1.1 gdamore 295 1.1 gdamore count = bt3c_read(sc, BT3C_RX_COUNT); 296 1.1 gdamore bt3c_set_address(sc, BT3C_RX_FIFO); 297 1.1 gdamore 298 1.1 gdamore while (count > 0) { 299 1.1 gdamore if (space == 0) { 300 1.1 gdamore if (m == NULL) { 301 1.1 gdamore /* new packet */ 302 1.1 gdamore MGETHDR(m, M_DONTWAIT, MT_DATA); 303 1.1 gdamore if (m == NULL) { 304 1.15 plunky aprint_error_dev(sc->sc_dev, 305 1.15 plunky "out of memory\n"); 306 1.16 plunky sc->sc_stats.err_rx++; 307 1.1 gdamore goto out; /* (lost sync) */ 308 1.1 gdamore } 309 1.1 gdamore 310 1.1 gdamore sc->sc_rxp = m; 311 1.1 gdamore m->m_pkthdr.len = m->m_len = 0; 312 1.1 gdamore space = MHLEN; 313 1.1 gdamore 314 1.1 gdamore sc->sc_state = BT3C_RECV_PKT_TYPE; 315 1.1 gdamore sc->sc_want = 1; 316 1.1 gdamore } else { 317 1.1 gdamore /* extend mbuf */ 318 1.1 gdamore MGET(m->m_next, M_DONTWAIT, MT_DATA); 319 1.1 gdamore if (m->m_next == NULL) { 320 1.15 plunky aprint_error_dev(sc->sc_dev, 321 1.15 plunky "out of memory\n"); 322 1.16 plunky sc->sc_stats.err_rx++; 323 1.1 gdamore goto out; /* (lost sync) */ 324 1.1 gdamore } 325 1.1 gdamore 326 1.1 gdamore m = m->m_next; 327 1.1 gdamore m->m_len = 0; 328 1.1 gdamore space = MLEN; 329 1.1 gdamore 330 1.1 gdamore if (sc->sc_want > MINCLSIZE) { 331 1.1 gdamore MCLGET(m, M_DONTWAIT); 332 1.1 gdamore if (m->m_flags & M_EXT) 333 1.1 gdamore space = MCLBYTES; 334 1.1 gdamore } 335 1.1 gdamore } 336 1.1 gdamore } 337 1.1 gdamore 338 1.1 gdamore b = bt3c_get(sc); 339 1.1 gdamore mtod(m, uint8_t *)[m->m_len++] = b; 340 1.1 gdamore count--; 341 1.1 gdamore space--; 342 1.1 gdamore sc->sc_rxp->m_pkthdr.len++; 343 1.16 plunky sc->sc_stats.byte_rx++; 344 1.1 gdamore 345 1.1 gdamore sc->sc_want--; 346 1.1 gdamore if (sc->sc_want > 0) 347 1.1 gdamore continue; /* want more */ 348 1.1 gdamore 349 1.1 gdamore switch (sc->sc_state) { 350 1.1 gdamore case BT3C_RECV_PKT_TYPE: /* Got packet type */ 351 1.1 gdamore 352 1.1 gdamore switch (b) { 353 1.1 gdamore case HCI_ACL_DATA_PKT: 354 1.1 gdamore sc->sc_state = BT3C_RECV_ACL_HDR; 355 1.1 gdamore sc->sc_want = sizeof(hci_acldata_hdr_t) - 1; 356 1.1 gdamore break; 357 1.1 gdamore 358 1.1 gdamore case HCI_SCO_DATA_PKT: 359 1.1 gdamore sc->sc_state = BT3C_RECV_SCO_HDR; 360 1.1 gdamore sc->sc_want = sizeof(hci_scodata_hdr_t) - 1; 361 1.1 gdamore break; 362 1.1 gdamore 363 1.1 gdamore case HCI_EVENT_PKT: 364 1.1 gdamore sc->sc_state = BT3C_RECV_EVENT_HDR; 365 1.1 gdamore sc->sc_want = sizeof(hci_event_hdr_t) - 1; 366 1.1 gdamore break; 367 1.1 gdamore 368 1.1 gdamore default: 369 1.15 plunky aprint_error_dev(sc->sc_dev, 370 1.15 plunky "Unknown packet type=%#x!\n", b); 371 1.16 plunky sc->sc_stats.err_rx++; 372 1.1 gdamore m_freem(sc->sc_rxp); 373 1.1 gdamore sc->sc_rxp = NULL; 374 1.1 gdamore goto out; /* (lost sync) */ 375 1.1 gdamore } 376 1.1 gdamore 377 1.1 gdamore break; 378 1.1 gdamore 379 1.1 gdamore /* 380 1.1 gdamore * we assume (correctly of course :) that the packet headers 381 1.1 gdamore * all fit into a single pkthdr mbuf 382 1.1 gdamore */ 383 1.1 gdamore case BT3C_RECV_ACL_HDR: /* Got ACL Header */ 384 1.1 gdamore sc->sc_state = BT3C_RECV_ACL_DATA; 385 1.1 gdamore sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length; 386 1.1 gdamore sc->sc_want = le16toh(sc->sc_want); 387 1.1 gdamore break; 388 1.1 gdamore 389 1.1 gdamore case BT3C_RECV_SCO_HDR: /* Got SCO Header */ 390 1.1 gdamore sc->sc_state = BT3C_RECV_SCO_DATA; 391 1.1 gdamore sc->sc_want = mtod(m, hci_scodata_hdr_t *)->length; 392 1.1 gdamore break; 393 1.1 gdamore 394 1.1 gdamore case BT3C_RECV_EVENT_HDR: /* Got Event Header */ 395 1.1 gdamore sc->sc_state = BT3C_RECV_EVENT_DATA; 396 1.1 gdamore sc->sc_want = mtod(m, hci_event_hdr_t *)->length; 397 1.1 gdamore break; 398 1.1 gdamore 399 1.1 gdamore case BT3C_RECV_ACL_DATA: /* ACL Packet Complete */ 400 1.16 plunky if (!hci_input_acl(sc->sc_unit, sc->sc_rxp)) 401 1.16 plunky sc->sc_stats.err_rx++; 402 1.16 plunky 403 1.16 plunky sc->sc_stats.acl_rx++; 404 1.1 gdamore sc->sc_rxp = m = NULL; 405 1.1 gdamore space = 0; 406 1.1 gdamore break; 407 1.1 gdamore 408 1.1 gdamore case BT3C_RECV_SCO_DATA: /* SCO Packet Complete */ 409 1.16 plunky if (!hci_input_sco(sc->sc_unit, sc->sc_rxp)) 410 1.16 plunky sc->sc_stats.err_rx++; 411 1.16 plunky 412 1.16 plunky sc->sc_stats.sco_rx++; 413 1.1 gdamore sc->sc_rxp = m = NULL; 414 1.1 gdamore space = 0; 415 1.1 gdamore break; 416 1.1 gdamore 417 1.1 gdamore case BT3C_RECV_EVENT_DATA: /* Event Packet Complete */ 418 1.16 plunky if (!hci_input_event(sc->sc_unit, sc->sc_rxp)) 419 1.16 plunky sc->sc_stats.err_rx++; 420 1.16 plunky 421 1.16 plunky sc->sc_stats.evt_rx++; 422 1.1 gdamore sc->sc_rxp = m = NULL; 423 1.1 gdamore space = 0; 424 1.1 gdamore break; 425 1.1 gdamore 426 1.1 gdamore default: 427 1.1 gdamore panic("%s: invalid state %d!\n", 428 1.13 plunky device_xname(sc->sc_dev), sc->sc_state); 429 1.1 gdamore } 430 1.1 gdamore } 431 1.1 gdamore 432 1.1 gdamore out: 433 1.1 gdamore bt3c_write(sc, BT3C_RX_COUNT, 0x0000); 434 1.1 gdamore } 435 1.1 gdamore 436 1.1 gdamore /* 437 1.1 gdamore * write data from current packet to Transmit FIFO. 438 1.1 gdamore * restart when done. 439 1.1 gdamore */ 440 1.1 gdamore static void 441 1.1 gdamore bt3c_transmit(struct bt3c_softc *sc) 442 1.1 gdamore { 443 1.1 gdamore struct mbuf *m; 444 1.1 gdamore int count, rlen; 445 1.1 gdamore uint8_t *rptr; 446 1.1 gdamore 447 1.1 gdamore m = sc->sc_txp; 448 1.1 gdamore if (m == NULL) { 449 1.16 plunky sc->sc_flags &= ~BT3C_XMIT; 450 1.16 plunky bt3c_start(sc); 451 1.1 gdamore return; 452 1.1 gdamore } 453 1.1 gdamore 454 1.1 gdamore count = 0; 455 1.1 gdamore rlen = 0; 456 1.1 gdamore rptr = mtod(m, uint8_t *); 457 1.1 gdamore 458 1.1 gdamore bt3c_set_address(sc, BT3C_TX_FIFO); 459 1.1 gdamore 460 1.1 gdamore for(;;) { 461 1.1 gdamore if (rlen >= m->m_len) { 462 1.1 gdamore m = m->m_next; 463 1.1 gdamore if (m == NULL) { 464 1.1 gdamore m = sc->sc_txp; 465 1.1 gdamore sc->sc_txp = NULL; 466 1.1 gdamore 467 1.1 gdamore if (M_GETCTX(m, void *) == NULL) 468 1.1 gdamore m_freem(m); 469 1.16 plunky else if (!hci_complete_sco(sc->sc_unit, m)) 470 1.16 plunky sc->sc_stats.err_tx++; 471 1.1 gdamore 472 1.1 gdamore break; 473 1.1 gdamore } 474 1.1 gdamore 475 1.1 gdamore rlen = 0; 476 1.1 gdamore rptr = mtod(m, uint8_t *); 477 1.1 gdamore continue; 478 1.1 gdamore } 479 1.1 gdamore 480 1.1 gdamore if (count >= BT3C_FIFO_SIZE) { 481 1.1 gdamore m_adj(m, rlen); 482 1.1 gdamore break; 483 1.1 gdamore } 484 1.1 gdamore 485 1.1 gdamore bt3c_put(sc, *rptr++); 486 1.1 gdamore rlen++; 487 1.1 gdamore count++; 488 1.1 gdamore } 489 1.1 gdamore 490 1.1 gdamore bt3c_write(sc, BT3C_TX_COUNT, count); 491 1.16 plunky sc->sc_stats.byte_tx += count; 492 1.1 gdamore } 493 1.1 gdamore 494 1.1 gdamore /* 495 1.1 gdamore * interrupt routine 496 1.1 gdamore */ 497 1.1 gdamore static int 498 1.1 gdamore bt3c_intr(void *arg) 499 1.1 gdamore { 500 1.1 gdamore struct bt3c_softc *sc = arg; 501 1.1 gdamore uint16_t control, isr; 502 1.1 gdamore 503 1.1 gdamore control = bt3c_read_control(sc); 504 1.1 gdamore if (control & BT3C_IOR_CNTL_INTR) { 505 1.1 gdamore isr = bt3c_read(sc, BT3C_ISR); 506 1.1 gdamore if ((isr & 0xff) == 0x7f) { 507 1.15 plunky aprint_error_dev(sc->sc_dev, "strange ISR=%04x\n", isr); 508 1.1 gdamore } else if ((isr & 0xff) != 0xff) { 509 1.1 gdamore 510 1.1 gdamore if (isr & BT3C_ISR_RXRDY) 511 1.1 gdamore bt3c_receive(sc); 512 1.1 gdamore 513 1.1 gdamore if (isr & BT3C_ISR_TXRDY) 514 1.1 gdamore bt3c_transmit(sc); 515 1.1 gdamore 516 1.1 gdamore #ifdef DIAGNOSTIC 517 1.1 gdamore if (isr & BT3C_ISR_ANTENNA) { 518 1.1 gdamore if (bt3c_read(sc, BT3C_CSR) & BT3C_CSR_ANTENNA) 519 1.15 plunky aprint_verbose_dev(sc->sc_dev, 520 1.15 plunky "Antenna Out\n"); 521 1.1 gdamore else 522 1.15 plunky aprint_verbose_dev(sc->sc_dev, 523 1.15 plunky "Antenna In\n"); 524 1.1 gdamore } 525 1.1 gdamore #endif 526 1.1 gdamore 527 1.1 gdamore bt3c_write(sc, BT3C_ISR, 0x0000); 528 1.1 gdamore bt3c_write_control(sc, control); 529 1.1 gdamore 530 1.1 gdamore return 1; /* handled */ 531 1.1 gdamore } 532 1.1 gdamore } 533 1.1 gdamore 534 1.1 gdamore return 0; /* not handled */ 535 1.1 gdamore } 536 1.1 gdamore 537 1.1 gdamore /* 538 1.1 gdamore * load firmware for the device 539 1.1 gdamore * 540 1.10 plunky * The firmware file is a plain ASCII file in the Motorola S-Record format, 541 1.10 plunky * with lines in the format: 542 1.1 gdamore * 543 1.1 gdamore * S<Digit><Len><Address><Data1><Data2>...<DataN><Checksum> 544 1.1 gdamore * 545 1.10 plunky * <Digit>: 0 header 546 1.10 plunky * 3 data record (4 byte address) 547 1.10 plunky * 7 boot record (4 byte address) 548 1.1 gdamore * 549 1.1 gdamore * <Len>: 1 byte, and is the number of bytes in the rest of the line 550 1.1 gdamore * <Address>: 4 byte address (only 2 bytes are valid for bt3c I think) 551 1.1 gdamore * <Data>: 2 byte data word to be written to the address 552 1.1 gdamore * <Checksum>: checksum of all bytes in the line including <Len> 553 1.1 gdamore * 554 1.1 gdamore * all bytes are in hexadecimal 555 1.1 gdamore */ 556 1.1 gdamore static inline int32_t 557 1.1 gdamore hex(const uint8_t *p, int n) 558 1.1 gdamore { 559 1.1 gdamore uint32_t val = 0; 560 1.1 gdamore 561 1.1 gdamore while (n > 0) { 562 1.1 gdamore val <<= 4; 563 1.1 gdamore 564 1.1 gdamore if ('0' <= *p && *p <= '9') 565 1.1 gdamore val += (*p - '0'); 566 1.1 gdamore else if ('a' <= *p && *p <= 'f') 567 1.1 gdamore val += (*p - 'a' + 0xa); 568 1.1 gdamore else if ('A' <= *p && *p <= 'F') 569 1.1 gdamore val += (*p - 'A' + 0xa); 570 1.1 gdamore else 571 1.1 gdamore return -1; 572 1.1 gdamore 573 1.1 gdamore p++; 574 1.1 gdamore n--; 575 1.1 gdamore } 576 1.1 gdamore 577 1.1 gdamore return val; 578 1.1 gdamore } 579 1.1 gdamore 580 1.1 gdamore static int 581 1.1 gdamore bt3c_load_firmware(struct bt3c_softc *sc) 582 1.1 gdamore { 583 1.1 gdamore uint8_t *buf, *line, *next, *p; 584 1.1 gdamore int32_t addr, data; 585 1.1 gdamore int err, sum, len; 586 1.1 gdamore firmware_handle_t fh; 587 1.19 cegger cfdata_t cf = device_cfdata(sc->sc_dev); 588 1.1 gdamore size_t size; 589 1.1 gdamore 590 1.13 plunky err = firmware_open(cf->cf_name, 591 1.1 gdamore BT3C_FIRMWARE_FILE, &fh); 592 1.1 gdamore if (err) { 593 1.15 plunky aprint_error_dev(sc->sc_dev, "Cannot open firmware %s/%s\n", 594 1.15 plunky cf->cf_name, BT3C_FIRMWARE_FILE); 595 1.1 gdamore return err; 596 1.1 gdamore } 597 1.1 gdamore 598 1.1 gdamore size = (size_t)firmware_get_size(fh); 599 1.2 christos if (size > 10 * 1024) { /* sanity check */ 600 1.15 plunky aprint_error_dev(sc->sc_dev, "insane firmware file size!\n"); 601 1.9 dogcow firmware_close(fh); 602 1.9 dogcow return EFBIG; 603 1.1 gdamore } 604 1.1 gdamore 605 1.1 gdamore buf = firmware_malloc(size); 606 1.1 gdamore KASSERT(buf != NULL); 607 1.1 gdamore 608 1.1 gdamore err = firmware_read(fh, 0, buf, size); 609 1.1 gdamore if (err) { 610 1.15 plunky aprint_error_dev(sc->sc_dev, "Firmware read failed (%d)\n", err); 611 1.1 gdamore goto out; 612 1.1 gdamore } 613 1.1 gdamore 614 1.1 gdamore /* Reset */ 615 1.1 gdamore bt3c_write(sc, 0x8040, 0x0404); 616 1.1 gdamore bt3c_write(sc, 0x8040, 0x0400); 617 1.1 gdamore DELAY(1); 618 1.1 gdamore bt3c_write(sc, 0x8040, 0x0404); 619 1.1 gdamore DELAY(17); 620 1.1 gdamore 621 1.1 gdamore next = buf; 622 1.1 gdamore err = EFTYPE; 623 1.1 gdamore 624 1.1 gdamore while (next < buf + size) { 625 1.1 gdamore line = next; 626 1.1 gdamore 627 1.1 gdamore while (*next != '\r' && *next != '\n') { 628 1.1 gdamore if (next >= buf + size) 629 1.1 gdamore goto out; 630 1.1 gdamore 631 1.1 gdamore next++; 632 1.1 gdamore } 633 1.1 gdamore 634 1.1 gdamore /* 14 covers address and checksum minimum */ 635 1.1 gdamore if (next - line < 14) 636 1.1 gdamore goto out; 637 1.1 gdamore 638 1.1 gdamore if (line[0] != 'S') 639 1.1 gdamore goto out; 640 1.1 gdamore 641 1.1 gdamore /* verify line length */ 642 1.1 gdamore len = hex(line + 2, 2); 643 1.1 gdamore if (len < 0 || next - line != len * 2 + 4) 644 1.1 gdamore goto out; 645 1.1 gdamore 646 1.1 gdamore /* checksum the line */ 647 1.1 gdamore sum = 0; 648 1.1 gdamore for (p = line + 2 ; p < next ; p += 2) 649 1.1 gdamore sum += hex(p, 2); 650 1.1 gdamore 651 1.1 gdamore if ((sum & 0xff) != 0xff) 652 1.1 gdamore goto out; 653 1.1 gdamore 654 1.1 gdamore /* extract relevant data */ 655 1.1 gdamore switch (line[1]) { 656 1.1 gdamore case '0': 657 1.10 plunky /* we ignore the header */ 658 1.1 gdamore break; 659 1.1 gdamore 660 1.1 gdamore case '3': 661 1.1 gdamore /* find number of data words */ 662 1.1 gdamore len = (len - 5) / 2; 663 1.1 gdamore if (len > 15) 664 1.1 gdamore goto out; 665 1.1 gdamore 666 1.1 gdamore addr = hex(line + 8, 4); 667 1.1 gdamore if (addr < 0) 668 1.1 gdamore goto out; 669 1.1 gdamore 670 1.1 gdamore bt3c_set_address(sc, addr); 671 1.1 gdamore 672 1.1 gdamore for (p = line + 12 ; p + 4 < next ; p += 4) { 673 1.1 gdamore data = hex(p, 4); 674 1.1 gdamore if (data < 0) 675 1.1 gdamore goto out; 676 1.1 gdamore 677 1.1 gdamore bt3c_put(sc, data); 678 1.1 gdamore } 679 1.1 gdamore break; 680 1.1 gdamore 681 1.1 gdamore case '7': 682 1.10 plunky /* 683 1.10 plunky * for some reason we ignore this record 684 1.10 plunky * and boot from 0x3000 which happens to 685 1.10 plunky * be the first record in the file. 686 1.10 plunky */ 687 1.1 gdamore break; 688 1.1 gdamore 689 1.1 gdamore default: 690 1.1 gdamore goto out; 691 1.1 gdamore } 692 1.1 gdamore 693 1.1 gdamore /* skip to start of next line */ 694 1.1 gdamore while (next < buf + size && (*next == '\r' || *next == '\n')) 695 1.1 gdamore next++; 696 1.1 gdamore } 697 1.1 gdamore 698 1.1 gdamore err = 0; 699 1.1 gdamore DELAY(17); 700 1.1 gdamore 701 1.1 gdamore /* Boot */ 702 1.1 gdamore bt3c_set_address(sc, 0x3000); 703 1.1 gdamore bt3c_write_control(sc, (bt3c_read_control(sc) | BT3C_IOR_CNTL_BOOT)); 704 1.1 gdamore DELAY(17); 705 1.1 gdamore 706 1.1 gdamore /* Clear Registers */ 707 1.1 gdamore bt3c_write(sc, BT3C_RX_COUNT, 0x0000); 708 1.1 gdamore bt3c_write(sc, BT3C_TX_COUNT, 0x0000); 709 1.1 gdamore bt3c_write(sc, BT3C_ISR, 0x0000); 710 1.1 gdamore DELAY(1000); 711 1.1 gdamore 712 1.1 gdamore out: 713 1.1 gdamore firmware_free(buf, size); 714 1.1 gdamore firmware_close(fh); 715 1.1 gdamore return err; 716 1.1 gdamore } 717 1.1 gdamore 718 1.1 gdamore /************************************************************************** 719 1.1 gdamore * 720 1.16 plunky * bt device callbacks 721 1.1 gdamore */ 722 1.1 gdamore 723 1.1 gdamore /* 724 1.1 gdamore * start sending on bt3c 725 1.16 plunky * should be called at spltty() when BT3C_XMIT is not set 726 1.1 gdamore */ 727 1.1 gdamore static void 728 1.16 plunky bt3c_start(struct bt3c_softc *sc) 729 1.1 gdamore { 730 1.1 gdamore struct mbuf *m; 731 1.1 gdamore 732 1.16 plunky KASSERT((sc->sc_flags & BT3C_XMIT) == 0); 733 1.1 gdamore KASSERT(sc->sc_txp == NULL); 734 1.1 gdamore 735 1.16 plunky if (MBUFQ_FIRST(&sc->sc_cmdq)) { 736 1.16 plunky MBUFQ_DEQUEUE(&sc->sc_cmdq, m); 737 1.16 plunky sc->sc_stats.cmd_tx++; 738 1.1 gdamore goto start; 739 1.1 gdamore } 740 1.1 gdamore 741 1.16 plunky if (MBUFQ_FIRST(&sc->sc_scoq)) { 742 1.16 plunky MBUFQ_DEQUEUE(&sc->sc_scoq, m); 743 1.16 plunky sc->sc_stats.sco_tx++; 744 1.1 gdamore goto start; 745 1.1 gdamore } 746 1.1 gdamore 747 1.16 plunky if (MBUFQ_FIRST(&sc->sc_aclq)) { 748 1.16 plunky MBUFQ_DEQUEUE(&sc->sc_aclq, m); 749 1.16 plunky sc->sc_stats.acl_tx++; 750 1.1 gdamore goto start; 751 1.1 gdamore } 752 1.1 gdamore 753 1.1 gdamore /* Nothing to send */ 754 1.1 gdamore return; 755 1.1 gdamore 756 1.1 gdamore start: 757 1.1 gdamore sc->sc_txp = m; 758 1.16 plunky sc->sc_flags |= BT3C_XMIT; 759 1.1 gdamore bt3c_transmit(sc); 760 1.1 gdamore } 761 1.1 gdamore 762 1.16 plunky static void 763 1.16 plunky bt3c_output_cmd(device_t self, struct mbuf *m) 764 1.16 plunky { 765 1.16 plunky struct bt3c_softc *sc = device_private(self); 766 1.16 plunky int s; 767 1.16 plunky 768 1.16 plunky KASSERT(sc->sc_flags & BT3C_ENABLED); 769 1.16 plunky 770 1.16 plunky M_SETCTX(m, NULL); 771 1.16 plunky 772 1.16 plunky s = spltty(); 773 1.16 plunky MBUFQ_ENQUEUE(&sc->sc_cmdq, m); 774 1.16 plunky if ((sc->sc_flags & BT3C_XMIT) == 0) 775 1.16 plunky bt3c_start(sc); 776 1.16 plunky 777 1.16 plunky splx(s); 778 1.16 plunky } 779 1.16 plunky 780 1.16 plunky static void 781 1.16 plunky bt3c_output_acl(device_t self, struct mbuf *m) 782 1.16 plunky { 783 1.16 plunky struct bt3c_softc *sc = device_private(self); 784 1.16 plunky int s; 785 1.16 plunky 786 1.16 plunky KASSERT(sc->sc_flags & BT3C_ENABLED); 787 1.16 plunky 788 1.16 plunky M_SETCTX(m, NULL); 789 1.16 plunky 790 1.16 plunky s = spltty(); 791 1.16 plunky MBUFQ_ENQUEUE(&sc->sc_aclq, m); 792 1.16 plunky if ((sc->sc_flags & BT3C_XMIT) == 0) 793 1.16 plunky bt3c_start(sc); 794 1.16 plunky 795 1.16 plunky splx(s); 796 1.16 plunky } 797 1.16 plunky 798 1.16 plunky static void 799 1.16 plunky bt3c_output_sco(device_t self, struct mbuf *m) 800 1.16 plunky { 801 1.16 plunky struct bt3c_softc *sc = device_private(self); 802 1.16 plunky int s; 803 1.16 plunky 804 1.16 plunky KASSERT(sc->sc_flags & BT3C_ENABLED); 805 1.16 plunky 806 1.16 plunky s = spltty(); 807 1.16 plunky MBUFQ_ENQUEUE(&sc->sc_scoq, m); 808 1.16 plunky if ((sc->sc_flags & BT3C_XMIT) == 0) 809 1.16 plunky bt3c_start(sc); 810 1.16 plunky 811 1.16 plunky splx(s); 812 1.16 plunky } 813 1.16 plunky 814 1.1 gdamore /* 815 1.1 gdamore * enable device 816 1.1 gdamore * turn on card 817 1.1 gdamore * load firmware 818 1.1 gdamore * establish interrupts 819 1.1 gdamore */ 820 1.1 gdamore static int 821 1.14 plunky bt3c_enable(device_t self) 822 1.1 gdamore { 823 1.14 plunky struct bt3c_softc *sc = device_private(self); 824 1.16 plunky int err, s; 825 1.1 gdamore 826 1.16 plunky if (sc->sc_flags & BT3C_ENABLED) 827 1.1 gdamore return 0; 828 1.1 gdamore 829 1.16 plunky s = spltty(); 830 1.16 plunky 831 1.1 gdamore sc->sc_intr = pcmcia_intr_establish(sc->sc_pf, IPL_TTY, bt3c_intr, sc); 832 1.1 gdamore if (sc->sc_intr == NULL) { 833 1.1 gdamore err = EIO; 834 1.1 gdamore goto bad; 835 1.1 gdamore } 836 1.1 gdamore 837 1.1 gdamore err = pcmcia_function_enable(sc->sc_pf); 838 1.1 gdamore if (err) 839 1.1 gdamore goto bad1; 840 1.1 gdamore 841 1.1 gdamore err = bt3c_load_firmware(sc); 842 1.1 gdamore if (err) 843 1.1 gdamore goto bad2; 844 1.1 gdamore 845 1.16 plunky sc->sc_flags |= BT3C_ENABLED; 846 1.16 plunky sc->sc_flags &= ~BT3C_XMIT; 847 1.1 gdamore 848 1.16 plunky splx(s); 849 1.1 gdamore 850 1.1 gdamore return 0; 851 1.1 gdamore 852 1.1 gdamore bad2: 853 1.1 gdamore pcmcia_function_disable(sc->sc_pf); 854 1.1 gdamore bad1: 855 1.1 gdamore pcmcia_intr_disestablish(sc->sc_pf, sc->sc_intr); 856 1.1 gdamore sc->sc_intr = NULL; 857 1.1 gdamore bad: 858 1.16 plunky splx(s); 859 1.1 gdamore return err; 860 1.1 gdamore } 861 1.1 gdamore 862 1.1 gdamore /* 863 1.1 gdamore * disable device 864 1.1 gdamore * shut down card 865 1.1 gdamore * disestablish interrupts 866 1.1 gdamore * free held packets 867 1.1 gdamore */ 868 1.1 gdamore static void 869 1.14 plunky bt3c_disable(device_t self) 870 1.1 gdamore { 871 1.14 plunky struct bt3c_softc *sc = device_private(self); 872 1.16 plunky int s; 873 1.1 gdamore 874 1.16 plunky if ((sc->sc_flags & BT3C_ENABLED) == 0) 875 1.1 gdamore return; 876 1.1 gdamore 877 1.16 plunky s = spltty(); 878 1.16 plunky 879 1.1 gdamore pcmcia_function_disable(sc->sc_pf); 880 1.1 gdamore 881 1.1 gdamore if (sc->sc_intr) { 882 1.1 gdamore pcmcia_intr_disestablish(sc->sc_pf, sc->sc_intr); 883 1.1 gdamore sc->sc_intr = NULL; 884 1.1 gdamore } 885 1.1 gdamore 886 1.24 rin m_freem(sc->sc_rxp); 887 1.24 rin sc->sc_rxp = NULL; 888 1.1 gdamore 889 1.24 rin m_freem(sc->sc_txp); 890 1.24 rin sc->sc_txp = NULL; 891 1.1 gdamore 892 1.16 plunky MBUFQ_DRAIN(&sc->sc_cmdq); 893 1.16 plunky MBUFQ_DRAIN(&sc->sc_aclq); 894 1.16 plunky MBUFQ_DRAIN(&sc->sc_scoq); 895 1.16 plunky 896 1.16 plunky sc->sc_flags &= ~BT3C_ENABLED; 897 1.16 plunky splx(s); 898 1.16 plunky } 899 1.16 plunky 900 1.16 plunky void 901 1.16 plunky bt3c_stats(device_t self, struct bt_stats *dest, int flush) 902 1.16 plunky { 903 1.16 plunky struct bt3c_softc *sc = device_private(self); 904 1.16 plunky int s; 905 1.16 plunky 906 1.16 plunky s = spltty(); 907 1.16 plunky memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats)); 908 1.16 plunky 909 1.16 plunky if (flush) 910 1.16 plunky memset(&sc->sc_stats, 0, sizeof(struct bt_stats)); 911 1.16 plunky 912 1.16 plunky splx(s); 913 1.1 gdamore } 914 1.1 gdamore 915 1.1 gdamore /************************************************************************** 916 1.1 gdamore * 917 1.1 gdamore * bt3c PCMCIA autoconfig glue 918 1.1 gdamore */ 919 1.1 gdamore 920 1.1 gdamore static int 921 1.19 cegger bt3c_match(device_t parent, cfdata_t match, void *aux) 922 1.1 gdamore { 923 1.1 gdamore struct pcmcia_attach_args *pa = aux; 924 1.1 gdamore 925 1.1 gdamore if (pa->manufacturer == PCMCIA_VENDOR_3COM && 926 1.1 gdamore pa->product == PCMCIA_PRODUCT_3COM_3CRWB6096) 927 1.1 gdamore return 10; /* 'com' also claims this, so trump them */ 928 1.1 gdamore 929 1.1 gdamore return 0; 930 1.1 gdamore } 931 1.1 gdamore 932 1.1 gdamore static void 933 1.13 plunky bt3c_attach(device_t parent, device_t self, void *aux) 934 1.1 gdamore { 935 1.13 plunky struct bt3c_softc *sc = device_private(self); 936 1.1 gdamore struct pcmcia_attach_args *pa = aux; 937 1.1 gdamore struct pcmcia_config_entry *cfe; 938 1.1 gdamore 939 1.13 plunky sc->sc_dev = self; 940 1.1 gdamore sc->sc_pf = pa->pf; 941 1.1 gdamore 942 1.16 plunky MBUFQ_INIT(&sc->sc_cmdq); 943 1.16 plunky MBUFQ_INIT(&sc->sc_aclq); 944 1.16 plunky MBUFQ_INIT(&sc->sc_scoq); 945 1.16 plunky 946 1.1 gdamore /* Find a PCMCIA config entry we can use */ 947 1.1 gdamore SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) { 948 1.1 gdamore if (cfe->num_memspace != 0) 949 1.1 gdamore continue; 950 1.1 gdamore 951 1.1 gdamore if (cfe->num_iospace != 1) 952 1.1 gdamore continue; 953 1.1 gdamore 954 1.1 gdamore if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, 955 1.1 gdamore cfe->iospace[0].length, 0, &sc->sc_pcioh) == 0) 956 1.1 gdamore break; 957 1.1 gdamore } 958 1.1 gdamore 959 1.1 gdamore if (cfe == 0) { 960 1.17 plunky aprint_error_dev(self, "cannot allocate io space\n"); 961 1.1 gdamore goto no_config_entry; 962 1.1 gdamore } 963 1.1 gdamore 964 1.1 gdamore /* Initialise it */ 965 1.1 gdamore pcmcia_function_init(pa->pf, cfe); 966 1.1 gdamore 967 1.1 gdamore /* Map in the io space */ 968 1.1 gdamore if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 969 1.1 gdamore &sc->sc_pcioh, &sc->sc_iow)) { 970 1.17 plunky aprint_error_dev(self, "cannot map io space\n"); 971 1.1 gdamore goto iomap_failed; 972 1.1 gdamore } 973 1.1 gdamore 974 1.1 gdamore /* Attach Bluetooth unit */ 975 1.23 rmind sc->sc_unit = hci_attach_pcb(&bt3c_hci, self, BTF_POWER_UP_NOOP); 976 1.18 plunky if (sc->sc_unit == NULL) 977 1.18 plunky aprint_error_dev(self, "HCI attach failed\n"); 978 1.18 plunky 979 1.18 plunky if (!pmf_device_register(self, bt3c_suspend, bt3c_resume)) 980 1.18 plunky aprint_error_dev(self, "couldn't establish power handler\n"); 981 1.1 gdamore 982 1.1 gdamore return; 983 1.1 gdamore 984 1.1 gdamore iomap_failed: 985 1.1 gdamore /* unmap io space */ 986 1.1 gdamore pcmcia_io_free(pa->pf, &sc->sc_pcioh); 987 1.1 gdamore 988 1.1 gdamore no_config_entry: 989 1.1 gdamore sc->sc_iow = -1; 990 1.1 gdamore } 991 1.1 gdamore 992 1.1 gdamore static int 993 1.13 plunky bt3c_detach(device_t self, int flags) 994 1.1 gdamore { 995 1.13 plunky struct bt3c_softc *sc = device_private(self); 996 1.1 gdamore int err = 0; 997 1.1 gdamore 998 1.18 plunky pmf_device_deregister(self); 999 1.14 plunky bt3c_disable(self); 1000 1.1 gdamore 1001 1.16 plunky if (sc->sc_unit) { 1002 1.23 rmind hci_detach_pcb(sc->sc_unit); 1003 1.16 plunky sc->sc_unit = NULL; 1004 1.16 plunky } 1005 1.1 gdamore 1006 1.1 gdamore if (sc->sc_iow != -1) { 1007 1.1 gdamore pcmcia_io_unmap(sc->sc_pf, sc->sc_iow); 1008 1.1 gdamore pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh); 1009 1.1 gdamore sc->sc_iow = -1; 1010 1.1 gdamore } 1011 1.1 gdamore 1012 1.1 gdamore return err; 1013 1.1 gdamore } 1014 1.1 gdamore 1015 1.18 plunky static bool 1016 1.21 dyoung bt3c_suspend(device_t self, const pmf_qual_t *qual) 1017 1.1 gdamore { 1018 1.18 plunky struct bt3c_softc *sc = device_private(self); 1019 1.18 plunky 1020 1.18 plunky if (sc->sc_unit) { 1021 1.23 rmind hci_detach_pcb(sc->sc_unit); 1022 1.18 plunky sc->sc_unit = NULL; 1023 1.18 plunky } 1024 1.1 gdamore 1025 1.18 plunky return true; 1026 1.18 plunky } 1027 1.3 plunky 1028 1.18 plunky static bool 1029 1.21 dyoung bt3c_resume(device_t self, const pmf_qual_t *qual) 1030 1.18 plunky { 1031 1.18 plunky struct bt3c_softc *sc = device_private(self); 1032 1.1 gdamore 1033 1.18 plunky KASSERT(sc->sc_unit == NULL); 1034 1.3 plunky 1035 1.23 rmind sc->sc_unit = hci_attach_pcb(&bt3c_hci, self, BTF_POWER_UP_NOOP); 1036 1.18 plunky if (sc->sc_unit == NULL) 1037 1.18 plunky return false; 1038 1.1 gdamore 1039 1.18 plunky return true; 1040 1.1 gdamore } 1041