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