bth5.c revision 1.4.2.2 1 1.4.2.2 skrll /* $NetBSD: bth5.c,v 1.4.2.2 2017/08/28 17:52:01 skrll Exp $ */
2 1.4.2.2 skrll /*
3 1.4.2.2 skrll * Copyright (c) 2017 Nathanial Sloss <nathanialsloss (at) yahoo.com.au>
4 1.4.2.2 skrll * All rights reserved.
5 1.4.2.2 skrll *
6 1.4.2.2 skrll * Copyright (c) 2007 KIYOHARA Takashi
7 1.4.2.2 skrll * All rights reserved.
8 1.4.2.2 skrll *
9 1.4.2.2 skrll * Redistribution and use in source and binary forms, with or without
10 1.4.2.2 skrll * modification, are permitted provided that the following conditions
11 1.4.2.2 skrll * are met:
12 1.4.2.2 skrll * 1. Redistributions of source code must retain the above copyright
13 1.4.2.2 skrll * notice, this list of conditions and the following disclaimer.
14 1.4.2.2 skrll * 2. Redistributions in binary form must reproduce the above copyright
15 1.4.2.2 skrll * notice, this list of conditions and the following disclaimer in the
16 1.4.2.2 skrll * documentation and/or other materials provided with the distribution.
17 1.4.2.2 skrll *
18 1.4.2.2 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 1.4.2.2 skrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 1.4.2.2 skrll * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 1.4.2.2 skrll * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 1.4.2.2 skrll * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 1.4.2.2 skrll * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 1.4.2.2 skrll * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 1.4.2.2 skrll * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 1.4.2.2 skrll * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 1.4.2.2 skrll * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.4.2.2 skrll * POSSIBILITY OF SUCH DAMAGE.
29 1.4.2.2 skrll */
30 1.4.2.2 skrll
31 1.4.2.2 skrll #include <sys/cdefs.h>
32 1.4.2.2 skrll __KERNEL_RCSID(0, "$NetBSD: bth5.c,v 1.4.2.2 2017/08/28 17:52:01 skrll Exp $");
33 1.4.2.2 skrll
34 1.4.2.2 skrll #include <sys/types.h>
35 1.4.2.2 skrll #include <sys/param.h>
36 1.4.2.2 skrll #include <sys/callout.h>
37 1.4.2.2 skrll #include <sys/conf.h>
38 1.4.2.2 skrll #include <sys/device.h>
39 1.4.2.2 skrll #include <sys/errno.h>
40 1.4.2.2 skrll #include <sys/fcntl.h>
41 1.4.2.2 skrll #include <sys/kauth.h>
42 1.4.2.2 skrll #include <sys/kernel.h>
43 1.4.2.2 skrll #include <sys/malloc.h>
44 1.4.2.2 skrll #include <sys/mbuf.h>
45 1.4.2.2 skrll #include <sys/proc.h>
46 1.4.2.2 skrll #include <sys/sysctl.h>
47 1.4.2.2 skrll #include <sys/syslimits.h>
48 1.4.2.2 skrll #include <sys/systm.h>
49 1.4.2.2 skrll #include <sys/tty.h>
50 1.4.2.2 skrll
51 1.4.2.2 skrll #include <netbt/bluetooth.h>
52 1.4.2.2 skrll #include <netbt/hci.h>
53 1.4.2.2 skrll
54 1.4.2.2 skrll #include <dev/bluetooth/bth5.h>
55 1.4.2.2 skrll
56 1.4.2.2 skrll #include "ioconf.h"
57 1.4.2.2 skrll
58 1.4.2.2 skrll #ifdef BTH5_DEBUG
59 1.4.2.2 skrll #ifdef DPRINTF
60 1.4.2.2 skrll #undef DPRINTF
61 1.4.2.2 skrll #endif
62 1.4.2.2 skrll #ifdef DPRINTFN
63 1.4.2.2 skrll #undef DPRINTFN
64 1.4.2.2 skrll #endif
65 1.4.2.2 skrll
66 1.4.2.2 skrll #define DPRINTF(x) printf x
67 1.4.2.2 skrll #define DPRINTFN(n, x) do { if (bth5_debug > (n)) printf x; } while (0)
68 1.4.2.2 skrll int bth5_debug = 3;
69 1.4.2.2 skrll #else
70 1.4.2.2 skrll #undef DPRINTF
71 1.4.2.2 skrll #undef DPRINTFN
72 1.4.2.2 skrll
73 1.4.2.2 skrll #define DPRINTF(x)
74 1.4.2.2 skrll #define DPRINTFN(n, x)
75 1.4.2.2 skrll #endif
76 1.4.2.2 skrll
77 1.4.2.2 skrll struct bth5_softc {
78 1.4.2.2 skrll device_t sc_dev;
79 1.4.2.2 skrll
80 1.4.2.2 skrll struct tty *sc_tp;
81 1.4.2.2 skrll struct hci_unit *sc_unit; /* Bluetooth HCI Unit */
82 1.4.2.2 skrll struct bt_stats sc_stats;
83 1.4.2.2 skrll
84 1.4.2.2 skrll int sc_flags;
85 1.4.2.2 skrll
86 1.4.2.2 skrll /* output queues */
87 1.4.2.2 skrll MBUFQ_HEAD() sc_cmdq;
88 1.4.2.2 skrll MBUFQ_HEAD() sc_aclq;
89 1.4.2.2 skrll MBUFQ_HEAD() sc_scoq;
90 1.4.2.2 skrll
91 1.4.2.2 skrll int sc_baud;
92 1.4.2.2 skrll int sc_init_baud;
93 1.4.2.2 skrll
94 1.4.2.2 skrll /* variables of SLIP Layer */
95 1.4.2.2 skrll struct mbuf *sc_txp; /* outgoing packet */
96 1.4.2.2 skrll struct mbuf *sc_rxp; /* incoming packet */
97 1.4.2.2 skrll int sc_slip_txrsv; /* reserved byte data */
98 1.4.2.2 skrll int sc_slip_rxexp; /* expected byte data */
99 1.4.2.2 skrll void (*sc_transmit_callback)(struct bth5_softc *, struct mbuf *);
100 1.4.2.2 skrll
101 1.4.2.2 skrll /* variables of Packet Integrity Layer */
102 1.4.2.2 skrll int sc_pi_txcrc; /* use CRC, if true */
103 1.4.2.2 skrll
104 1.4.2.2 skrll /* variables of MUX Layer */
105 1.4.2.2 skrll bool sc_mux_send_ack; /* flag for send_ack */
106 1.4.2.2 skrll bool sc_mux_choke; /* Choke signal */
107 1.4.2.2 skrll struct timeval sc_mux_lastrx; /* Last Rx Pkt Time */
108 1.4.2.2 skrll
109 1.4.2.2 skrll /* variables of Sequencing Layer */
110 1.4.2.2 skrll MBUFQ_HEAD() sc_seqq; /* Sequencing Layer queue */
111 1.4.2.2 skrll MBUFQ_HEAD() sc_seq_retryq; /* retry queue */
112 1.4.2.2 skrll uint32_t sc_seq_txseq;
113 1.4.2.2 skrll uint32_t sc_seq_txack;
114 1.4.2.2 skrll uint32_t sc_seq_expected_rxseq;
115 1.4.2.2 skrll uint32_t sc_seq_winspace;
116 1.4.2.2 skrll uint32_t sc_seq_retries;
117 1.4.2.2 skrll callout_t sc_seq_timer;
118 1.4.2.2 skrll uint32_t sc_seq_timeout;
119 1.4.2.2 skrll uint32_t sc_seq_winsize;
120 1.4.2.2 skrll uint32_t sc_seq_retry_limit;
121 1.4.2.2 skrll
122 1.4.2.2 skrll /* variables of Datagram Queue Layer */
123 1.4.2.2 skrll MBUFQ_HEAD() sc_dgq; /* Datagram Queue Layer queue */
124 1.4.2.2 skrll
125 1.4.2.2 skrll /* variables of BTH5 Link Establishment Protocol */
126 1.4.2.2 skrll bool sc_le_muzzled;
127 1.4.2.2 skrll bth5_le_state_t sc_le_state;
128 1.4.2.2 skrll callout_t sc_le_timer;
129 1.4.2.2 skrll
130 1.4.2.2 skrll struct sysctllog *sc_log; /* sysctl log */
131 1.4.2.2 skrll };
132 1.4.2.2 skrll
133 1.4.2.2 skrll /* sc_flags */
134 1.4.2.2 skrll #define BTH5_XMIT (1 << 0) /* transmit active */
135 1.4.2.2 skrll #define BTH5_ENABLED (1 << 1) /* is enabled */
136 1.4.2.2 skrll
137 1.4.2.2 skrll static int bthfive_match(device_t, cfdata_t, void *);
138 1.4.2.2 skrll static void bthfive_attach(device_t, device_t, void *);
139 1.4.2.2 skrll static int bthfive_detach(device_t, int);
140 1.4.2.2 skrll
141 1.4.2.2 skrll /* tty functions */
142 1.4.2.2 skrll static int bth5open(dev_t, struct tty *);
143 1.4.2.2 skrll static int bth5close(struct tty *, int);
144 1.4.2.2 skrll static int bth5ioctl(struct tty *, u_long, void *, int, struct lwp *);
145 1.4.2.2 skrll
146 1.4.2.2 skrll static int bth5_slip_transmit(struct tty *);
147 1.4.2.2 skrll static int bth5_slip_receive(int, struct tty *);
148 1.4.2.2 skrll
149 1.4.2.2 skrll static void bth5_pktintegrity_transmit(struct bth5_softc *);
150 1.4.2.2 skrll static void bth5_pktintegrity_receive(struct bth5_softc *, struct mbuf *);
151 1.4.2.2 skrll static void bth5_crc_update(uint16_t *, uint8_t);
152 1.4.2.2 skrll static uint16_t bth5_crc_reverse(uint16_t);
153 1.4.2.2 skrll
154 1.4.2.2 skrll static void bth5_mux_transmit(struct bth5_softc *sc);
155 1.4.2.2 skrll static void bth5_mux_receive(struct bth5_softc *sc, struct mbuf *m);
156 1.4.2.2 skrll static __inline void bth5_send_ack_command(struct bth5_softc *sc);
157 1.4.2.2 skrll static __inline struct mbuf *bth5_create_ackpkt(void);
158 1.4.2.2 skrll static __inline void bth5_set_choke(struct bth5_softc *, bool);
159 1.4.2.2 skrll
160 1.4.2.2 skrll static void bth5_sequencing_receive(struct bth5_softc *, struct mbuf *);
161 1.4.2.2 skrll static bool bth5_tx_reliable_pkt(struct bth5_softc *, struct mbuf *, u_int);
162 1.4.2.2 skrll static __inline u_int bth5_get_txack(struct bth5_softc *);
163 1.4.2.2 skrll static void bth5_signal_rxack(struct bth5_softc *, uint32_t);
164 1.4.2.2 skrll static void bth5_reliabletx_callback(struct bth5_softc *, struct mbuf *);
165 1.4.2.2 skrll static void bth5_timer_timeout(void *);
166 1.4.2.2 skrll static void bth5_sequencing_reset(struct bth5_softc *);
167 1.4.2.2 skrll
168 1.4.2.2 skrll static void bth5_datagramq_receive(struct bth5_softc *, struct mbuf *);
169 1.4.2.2 skrll static bool bth5_tx_unreliable_pkt(struct bth5_softc *, struct mbuf *, u_int);
170 1.4.2.2 skrll static void bth5_unreliabletx_callback(struct bth5_softc *, struct mbuf *);
171 1.4.2.2 skrll
172 1.4.2.2 skrll static int bth5_start_le(struct bth5_softc *);
173 1.4.2.2 skrll static void bth5_terminate_le(struct bth5_softc *);
174 1.4.2.2 skrll static void bth5_input_le(struct bth5_softc *, struct mbuf *);
175 1.4.2.2 skrll static void bth5_le_timeout(void *);
176 1.4.2.2 skrll
177 1.4.2.2 skrll static void bth5_start(struct bth5_softc *);
178 1.4.2.2 skrll
179 1.4.2.2 skrll /* bluetooth hci functions */
180 1.4.2.2 skrll static int bth5_enable(device_t);
181 1.4.2.2 skrll static void bth5_disable(device_t);
182 1.4.2.2 skrll static void bth5_output_cmd(device_t, struct mbuf *);
183 1.4.2.2 skrll static void bth5_output_acl(device_t, struct mbuf *);
184 1.4.2.2 skrll static void bth5_output_sco(device_t, struct mbuf *);
185 1.4.2.2 skrll static void bth5_stats(device_t, struct bt_stats *, int);
186 1.4.2.2 skrll
187 1.4.2.2 skrll #ifdef BTH5_DEBUG
188 1.4.2.2 skrll static void bth5_packet_print(struct mbuf *m);
189 1.4.2.2 skrll #endif
190 1.4.2.2 skrll
191 1.4.2.2 skrll
192 1.4.2.2 skrll /*
193 1.4.2.2 skrll * It doesn't need to be exported, as only bth5attach() uses it,
194 1.4.2.2 skrll * but there's no "official" way to make it static.
195 1.4.2.2 skrll */
196 1.4.2.2 skrll CFATTACH_DECL_NEW(bthfive, sizeof(struct bth5_softc),
197 1.4.2.2 skrll bthfive_match, bthfive_attach, bthfive_detach, NULL);
198 1.4.2.2 skrll
199 1.4.2.2 skrll static struct linesw bth5_disc = {
200 1.4.2.2 skrll .l_name = "bth5",
201 1.4.2.2 skrll .l_open = bth5open,
202 1.4.2.2 skrll .l_close = bth5close,
203 1.4.2.2 skrll .l_read = ttyerrio,
204 1.4.2.2 skrll .l_write = ttyerrio,
205 1.4.2.2 skrll .l_ioctl = bth5ioctl,
206 1.4.2.2 skrll .l_rint = bth5_slip_receive,
207 1.4.2.2 skrll .l_start = bth5_slip_transmit,
208 1.4.2.2 skrll .l_modem = ttymodem,
209 1.4.2.2 skrll .l_poll = ttyerrpoll
210 1.4.2.2 skrll };
211 1.4.2.2 skrll
212 1.4.2.2 skrll static const struct hci_if bth5_hci = {
213 1.4.2.2 skrll .enable = bth5_enable,
214 1.4.2.2 skrll .disable = bth5_disable,
215 1.4.2.2 skrll .output_cmd = bth5_output_cmd,
216 1.4.2.2 skrll .output_acl = bth5_output_acl,
217 1.4.2.2 skrll .output_sco = bth5_output_sco,
218 1.4.2.2 skrll .get_stats = bth5_stats,
219 1.4.2.2 skrll .ipl = IPL_TTY,
220 1.4.2.2 skrll };
221 1.4.2.2 skrll
222 1.4.2.2 skrll /* ARGSUSED */
223 1.4.2.2 skrll void
224 1.4.2.2 skrll bthfiveattach(int num __unused)
225 1.4.2.2 skrll {
226 1.4.2.2 skrll int error;
227 1.4.2.2 skrll
228 1.4.2.2 skrll error = ttyldisc_attach(&bth5_disc);
229 1.4.2.2 skrll if (error) {
230 1.4.2.2 skrll aprint_error("%s: unable to register line discipline, "
231 1.4.2.2 skrll "error = %d\n", bthfive_cd.cd_name, error);
232 1.4.2.2 skrll return;
233 1.4.2.2 skrll }
234 1.4.2.2 skrll
235 1.4.2.2 skrll error = config_cfattach_attach(bthfive_cd.cd_name, &bthfive_ca);
236 1.4.2.2 skrll if (error) {
237 1.4.2.2 skrll aprint_error("%s: unable to register cfattach, error = %d\n",
238 1.4.2.2 skrll bthfive_cd.cd_name, error);
239 1.4.2.2 skrll config_cfdriver_detach(&bthfive_cd);
240 1.4.2.2 skrll (void) ttyldisc_detach(&bth5_disc);
241 1.4.2.2 skrll }
242 1.4.2.2 skrll }
243 1.4.2.2 skrll
244 1.4.2.2 skrll /*
245 1.4.2.2 skrll * Autoconf match routine.
246 1.4.2.2 skrll *
247 1.4.2.2 skrll * XXX: unused: config_attach_pseudo(9) does not call ca_match.
248 1.4.2.2 skrll */
249 1.4.2.2 skrll /* ARGSUSED */
250 1.4.2.2 skrll static int
251 1.4.2.2 skrll bthfive_match(device_t self __unused, cfdata_t cfdata __unused,
252 1.4.2.2 skrll void *arg __unused)
253 1.4.2.2 skrll {
254 1.4.2.2 skrll
255 1.4.2.2 skrll /* pseudo-device; always present */
256 1.4.2.2 skrll return 1;
257 1.4.2.2 skrll }
258 1.4.2.2 skrll
259 1.4.2.2 skrll /*
260 1.4.2.2 skrll * Autoconf attach routine. Called by config_attach_pseudo(9) when we
261 1.4.2.2 skrll * open the line discipline.
262 1.4.2.2 skrll */
263 1.4.2.2 skrll /* ARGSUSED */
264 1.4.2.2 skrll static void
265 1.4.2.2 skrll bthfive_attach(device_t parent __unused, device_t self, void *aux __unused)
266 1.4.2.2 skrll {
267 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
268 1.4.2.2 skrll const struct sysctlnode *node;
269 1.4.2.2 skrll int rc, bth5_node_num;
270 1.4.2.2 skrll
271 1.4.2.2 skrll aprint_normal("\n");
272 1.4.2.2 skrll aprint_naive("\n");
273 1.4.2.2 skrll
274 1.4.2.2 skrll sc->sc_dev = self;
275 1.4.2.2 skrll callout_init(&sc->sc_seq_timer, 0);
276 1.4.2.2 skrll callout_setfunc(&sc->sc_seq_timer, bth5_timer_timeout, sc);
277 1.4.2.2 skrll callout_init(&sc->sc_le_timer, 0);
278 1.4.2.2 skrll callout_setfunc(&sc->sc_le_timer, bth5_le_timeout, sc);
279 1.4.2.2 skrll sc->sc_seq_timeout = BTH5_SEQ_TX_TIMEOUT;
280 1.4.2.2 skrll sc->sc_seq_winsize = BTH5_SEQ_TX_WINSIZE;
281 1.4.2.2 skrll sc->sc_seq_retry_limit = BTH5_SEQ_TX_RETRY_LIMIT;
282 1.4.2.2 skrll MBUFQ_INIT(&sc->sc_seqq);
283 1.4.2.2 skrll MBUFQ_INIT(&sc->sc_seq_retryq);
284 1.4.2.2 skrll MBUFQ_INIT(&sc->sc_dgq);
285 1.4.2.2 skrll MBUFQ_INIT(&sc->sc_cmdq);
286 1.4.2.2 skrll MBUFQ_INIT(&sc->sc_aclq);
287 1.4.2.2 skrll MBUFQ_INIT(&sc->sc_scoq);
288 1.4.2.2 skrll
289 1.4.2.2 skrll /* Attach Bluetooth unit */
290 1.4.2.2 skrll sc->sc_unit = hci_attach_pcb(&bth5_hci, self, 0);
291 1.4.2.2 skrll
292 1.4.2.2 skrll if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
293 1.4.2.2 skrll 0, CTLTYPE_NODE, device_xname(self),
294 1.4.2.2 skrll SYSCTL_DESCR("bth5 controls"),
295 1.4.2.2 skrll NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
296 1.4.2.2 skrll goto err;
297 1.4.2.2 skrll }
298 1.4.2.2 skrll bth5_node_num = node->sysctl_num;
299 1.4.2.2 skrll if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
300 1.4.2.2 skrll CTLFLAG_READWRITE, CTLTYPE_BOOL,
301 1.4.2.2 skrll "muzzled", SYSCTL_DESCR("muzzled for Link-establishment Layer"),
302 1.4.2.2 skrll NULL, 0, &sc->sc_le_muzzled,
303 1.4.2.2 skrll 0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
304 1.4.2.2 skrll goto err;
305 1.4.2.2 skrll }
306 1.4.2.2 skrll if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
307 1.4.2.2 skrll CTLFLAG_READWRITE, CTLTYPE_INT,
308 1.4.2.2 skrll "txcrc", SYSCTL_DESCR("txcrc for Packet Integrity Layer"),
309 1.4.2.2 skrll NULL, 0, &sc->sc_pi_txcrc,
310 1.4.2.2 skrll 0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
311 1.4.2.2 skrll goto err;
312 1.4.2.2 skrll }
313 1.4.2.2 skrll if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
314 1.4.2.2 skrll CTLFLAG_READWRITE, CTLTYPE_INT,
315 1.4.2.2 skrll "timeout", SYSCTL_DESCR("timeout for Sequencing Layer"),
316 1.4.2.2 skrll NULL, 0, &sc->sc_seq_timeout,
317 1.4.2.2 skrll 0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
318 1.4.2.2 skrll goto err;
319 1.4.2.2 skrll }
320 1.4.2.2 skrll if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
321 1.4.2.2 skrll CTLFLAG_READWRITE, CTLTYPE_INT,
322 1.4.2.2 skrll "winsize", SYSCTL_DESCR("winsize for Sequencing Layer"),
323 1.4.2.2 skrll NULL, 0, &sc->sc_seq_winsize,
324 1.4.2.2 skrll 0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
325 1.4.2.2 skrll goto err;
326 1.4.2.2 skrll }
327 1.4.2.2 skrll if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
328 1.4.2.2 skrll CTLFLAG_READWRITE, CTLTYPE_INT,
329 1.4.2.2 skrll "retry_limit", SYSCTL_DESCR("retry limit for Sequencing Layer"),
330 1.4.2.2 skrll NULL, 0, &sc->sc_seq_retry_limit,
331 1.4.2.2 skrll 0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
332 1.4.2.2 skrll goto err;
333 1.4.2.2 skrll }
334 1.4.2.2 skrll return;
335 1.4.2.2 skrll
336 1.4.2.2 skrll err:
337 1.4.2.2 skrll aprint_error_dev(self, "sysctl_createv failed (rc = %d)\n", rc);
338 1.4.2.2 skrll }
339 1.4.2.2 skrll
340 1.4.2.2 skrll /*
341 1.4.2.2 skrll * Autoconf detach routine. Called when we close the line discipline.
342 1.4.2.2 skrll */
343 1.4.2.2 skrll /* ARGSUSED */
344 1.4.2.2 skrll static int
345 1.4.2.2 skrll bthfive_detach(device_t self, int flags __unused)
346 1.4.2.2 skrll {
347 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
348 1.4.2.2 skrll
349 1.4.2.2 skrll if (sc->sc_unit != NULL) {
350 1.4.2.2 skrll hci_detach_pcb(sc->sc_unit);
351 1.4.2.2 skrll sc->sc_unit = NULL;
352 1.4.2.2 skrll }
353 1.4.2.2 skrll
354 1.4.2.2 skrll callout_halt(&sc->sc_seq_timer, NULL);
355 1.4.2.2 skrll callout_destroy(&sc->sc_seq_timer);
356 1.4.2.2 skrll
357 1.4.2.2 skrll callout_halt(&sc->sc_le_timer, NULL);
358 1.4.2.2 skrll callout_destroy(&sc->sc_le_timer);
359 1.4.2.2 skrll
360 1.4.2.2 skrll return 0;
361 1.4.2.2 skrll }
362 1.4.2.2 skrll
363 1.4.2.2 skrll
364 1.4.2.2 skrll /*
365 1.4.2.2 skrll * Line discipline functions.
366 1.4.2.2 skrll */
367 1.4.2.2 skrll /* ARGSUSED */
368 1.4.2.2 skrll static int
369 1.4.2.2 skrll bth5open(dev_t device __unused, struct tty *tp)
370 1.4.2.2 skrll {
371 1.4.2.2 skrll struct bth5_softc *sc;
372 1.4.2.2 skrll device_t dev;
373 1.4.2.2 skrll cfdata_t cfdata;
374 1.4.2.2 skrll struct lwp *l = curlwp; /* XXX */
375 1.4.2.2 skrll int error, unit, s;
376 1.4.2.2 skrll static char name[] = "bthfive";
377 1.4.2.2 skrll
378 1.4.2.2 skrll error = kauth_authorize_device(l->l_cred, KAUTH_DEVICE_BLUETOOTH_BCSP,
379 1.4.2.2 skrll KAUTH_ARG(KAUTH_REQ_DEVICE_BLUETOOTH_BCSP_ADD), NULL, NULL, NULL);
380 1.4.2.2 skrll if (error)
381 1.4.2.2 skrll return (error);
382 1.4.2.2 skrll
383 1.4.2.2 skrll s = spltty();
384 1.4.2.2 skrll
385 1.4.2.2 skrll if (tp->t_linesw == &bth5_disc) {
386 1.4.2.2 skrll sc = tp->t_sc;
387 1.4.2.2 skrll if (sc != NULL) {
388 1.4.2.2 skrll splx(s);
389 1.4.2.2 skrll return EBUSY;
390 1.4.2.2 skrll }
391 1.4.2.2 skrll }
392 1.4.2.2 skrll
393 1.4.2.2 skrll KASSERT(tp->t_oproc != NULL);
394 1.4.2.2 skrll
395 1.4.2.2 skrll cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
396 1.4.2.2 skrll for (unit = 0; unit < bthfive_cd.cd_ndevs; unit++)
397 1.4.2.2 skrll if (device_lookup(&bthfive_cd, unit) == NULL)
398 1.4.2.2 skrll break;
399 1.4.2.2 skrll cfdata->cf_name = name;
400 1.4.2.2 skrll cfdata->cf_atname = name;
401 1.4.2.2 skrll cfdata->cf_unit = unit;
402 1.4.2.2 skrll cfdata->cf_fstate = FSTATE_STAR;
403 1.4.2.2 skrll
404 1.4.2.2 skrll aprint_normal("%s%d at tty major %llu minor %llu",
405 1.4.2.2 skrll name, unit, (unsigned long long)major(tp->t_dev),
406 1.4.2.2 skrll (unsigned long long)minor(tp->t_dev));
407 1.4.2.2 skrll dev = config_attach_pseudo(cfdata);
408 1.4.2.2 skrll if (dev == NULL) {
409 1.4.2.2 skrll splx(s);
410 1.4.2.2 skrll return EIO;
411 1.4.2.2 skrll }
412 1.4.2.2 skrll sc = device_private(dev);
413 1.4.2.2 skrll
414 1.4.2.2 skrll mutex_spin_enter(&tty_lock);
415 1.4.2.2 skrll tp->t_sc = sc;
416 1.4.2.2 skrll sc->sc_tp = tp;
417 1.4.2.2 skrll ttyflush(tp, FREAD | FWRITE);
418 1.4.2.2 skrll mutex_spin_exit(&tty_lock);
419 1.4.2.2 skrll
420 1.4.2.2 skrll splx(s);
421 1.4.2.2 skrll
422 1.4.2.2 skrll sc->sc_slip_txrsv = BTH5_SLIP_PKTSTART;
423 1.4.2.2 skrll bth5_sequencing_reset(sc);
424 1.4.2.2 skrll
425 1.4.2.2 skrll /* start link-establishment */
426 1.4.2.2 skrll bth5_start_le(sc);
427 1.4.2.2 skrll
428 1.4.2.2 skrll return 0;
429 1.4.2.2 skrll }
430 1.4.2.2 skrll
431 1.4.2.2 skrll /* ARGSUSED */
432 1.4.2.2 skrll static int
433 1.4.2.2 skrll bth5close(struct tty *tp, int flag __unused)
434 1.4.2.2 skrll {
435 1.4.2.2 skrll struct bth5_softc *sc = tp->t_sc;
436 1.4.2.2 skrll cfdata_t cfdata;
437 1.4.2.2 skrll int s;
438 1.4.2.2 skrll
439 1.4.2.2 skrll /* terminate link-establishment */
440 1.4.2.2 skrll bth5_terminate_le(sc);
441 1.4.2.2 skrll
442 1.4.2.2 skrll s = spltty();
443 1.4.2.2 skrll
444 1.4.2.2 skrll MBUFQ_DRAIN(&sc->sc_dgq);
445 1.4.2.2 skrll bth5_sequencing_reset(sc);
446 1.4.2.2 skrll
447 1.4.2.2 skrll mutex_spin_enter(&tty_lock);
448 1.4.2.2 skrll ttyflush(tp, FREAD | FWRITE);
449 1.4.2.2 skrll mutex_spin_exit(&tty_lock); /* XXX */
450 1.4.2.2 skrll ttyldisc_release(tp->t_linesw);
451 1.4.2.2 skrll tp->t_linesw = ttyldisc_default();
452 1.4.2.2 skrll if (sc != NULL) {
453 1.4.2.2 skrll tp->t_sc = NULL;
454 1.4.2.2 skrll if (sc->sc_tp == tp) {
455 1.4.2.2 skrll cfdata = device_cfdata(sc->sc_dev);
456 1.4.2.2 skrll config_detach(sc->sc_dev, 0);
457 1.4.2.2 skrll free(cfdata, M_DEVBUF);
458 1.4.2.2 skrll }
459 1.4.2.2 skrll
460 1.4.2.2 skrll }
461 1.4.2.2 skrll splx(s);
462 1.4.2.2 skrll return 0;
463 1.4.2.2 skrll }
464 1.4.2.2 skrll
465 1.4.2.2 skrll /* ARGSUSED */
466 1.4.2.2 skrll static int
467 1.4.2.2 skrll bth5ioctl(struct tty *tp, u_long cmd, void *data, int flag __unused,
468 1.4.2.2 skrll struct lwp *l __unused)
469 1.4.2.2 skrll {
470 1.4.2.2 skrll struct bth5_softc *sc = tp->t_sc;
471 1.4.2.2 skrll int error;
472 1.4.2.2 skrll
473 1.4.2.2 skrll if (sc == NULL || tp != sc->sc_tp)
474 1.4.2.2 skrll return EPASSTHROUGH;
475 1.4.2.2 skrll
476 1.4.2.2 skrll error = 0;
477 1.4.2.2 skrll switch (cmd) {
478 1.4.2.2 skrll default:
479 1.4.2.2 skrll error = EPASSTHROUGH;
480 1.4.2.2 skrll break;
481 1.4.2.2 skrll }
482 1.4.2.2 skrll
483 1.4.2.2 skrll return error;
484 1.4.2.2 skrll }
485 1.4.2.2 skrll
486 1.4.2.2 skrll
487 1.4.2.2 skrll /*
488 1.4.2.2 skrll * UART Driver Layer is supported by com-driver.
489 1.4.2.2 skrll */
490 1.4.2.2 skrll
491 1.4.2.2 skrll /*
492 1.4.2.2 skrll * BTH5 SLIP Layer functions:
493 1.4.2.2 skrll * Supports to transmit/receive a byte stream.
494 1.4.2.2 skrll * SLIP protocol described in Internet standard RFC 1055.
495 1.4.2.2 skrll */
496 1.4.2.2 skrll static int
497 1.4.2.2 skrll bth5_slip_transmit(struct tty *tp)
498 1.4.2.2 skrll {
499 1.4.2.2 skrll struct bth5_softc *sc = tp->t_sc;
500 1.4.2.2 skrll struct mbuf *m;
501 1.4.2.2 skrll int count, rlen;
502 1.4.2.2 skrll uint8_t *rptr;
503 1.4.2.2 skrll
504 1.4.2.2 skrll m = sc->sc_txp;
505 1.4.2.2 skrll if (m == NULL) {
506 1.4.2.2 skrll sc->sc_flags &= ~BTH5_XMIT;
507 1.4.2.2 skrll bth5_mux_transmit(sc);
508 1.4.2.2 skrll return 0;
509 1.4.2.2 skrll }
510 1.4.2.2 skrll
511 1.4.2.2 skrll count = 0;
512 1.4.2.2 skrll rlen = 0;
513 1.4.2.2 skrll rptr = mtod(m, uint8_t *);
514 1.4.2.2 skrll
515 1.4.2.2 skrll if (sc->sc_slip_txrsv != 0) {
516 1.4.2.2 skrll #ifdef BTH5_DEBUG
517 1.4.2.2 skrll if (sc->sc_slip_txrsv == BTH5_SLIP_PKTSTART)
518 1.4.2.2 skrll DPRINTFN(4, ("%s: slip transmit start\n",
519 1.4.2.2 skrll device_xname(sc->sc_dev)));
520 1.4.2.2 skrll else
521 1.4.2.2 skrll DPRINTFN(4, ("0x%02x ", sc->sc_slip_txrsv));
522 1.4.2.2 skrll #endif
523 1.4.2.2 skrll
524 1.4.2.2 skrll if (putc(sc->sc_slip_txrsv, &tp->t_outq) < 0)
525 1.4.2.2 skrll return 0;
526 1.4.2.2 skrll count++;
527 1.4.2.2 skrll
528 1.4.2.2 skrll if (sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_PKTEND ||
529 1.4.2.2 skrll sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_XON ||
530 1.4.2.2 skrll sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_XOFF ||
531 1.4.2.2 skrll sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_ESCAPE) {
532 1.4.2.2 skrll rlen++;
533 1.4.2.2 skrll rptr++;
534 1.4.2.2 skrll }
535 1.4.2.2 skrll sc->sc_slip_txrsv = 0;
536 1.4.2.2 skrll }
537 1.4.2.2 skrll
538 1.4.2.2 skrll for(;;) {
539 1.4.2.2 skrll if (rlen >= m->m_len) {
540 1.4.2.2 skrll m = m->m_next;
541 1.4.2.2 skrll if (m == NULL) {
542 1.4.2.2 skrll if (putc(BTH5_SLIP_PKTEND, &tp->t_outq) < 0)
543 1.4.2.2 skrll break;
544 1.4.2.2 skrll
545 1.4.2.2 skrll DPRINTFN(4, ("\n%s: slip transmit end\n",
546 1.4.2.2 skrll device_xname(sc->sc_dev)));
547 1.4.2.2 skrll
548 1.4.2.2 skrll m = sc->sc_txp;
549 1.4.2.2 skrll sc->sc_txp = NULL;
550 1.4.2.2 skrll sc->sc_slip_txrsv = BTH5_SLIP_PKTSTART;
551 1.4.2.2 skrll
552 1.4.2.2 skrll sc->sc_transmit_callback(sc, m);
553 1.4.2.2 skrll m = NULL;
554 1.4.2.2 skrll break;
555 1.4.2.2 skrll }
556 1.4.2.2 skrll
557 1.4.2.2 skrll rlen = 0;
558 1.4.2.2 skrll rptr = mtod(m, uint8_t *);
559 1.4.2.2 skrll continue;
560 1.4.2.2 skrll }
561 1.4.2.2 skrll
562 1.4.2.2 skrll if (*rptr == BTH5_SLIP_PKTEND) {
563 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
564 1.4.2.2 skrll break;
565 1.4.2.2 skrll count++;
566 1.4.2.2 skrll DPRINTFN(4, (" esc "));
567 1.4.2.2 skrll
568 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE_PKTEND, &tp->t_outq) < 0) {
569 1.4.2.2 skrll sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_PKTEND;
570 1.4.2.2 skrll break;
571 1.4.2.2 skrll }
572 1.4.2.2 skrll DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_PKTEND));
573 1.4.2.2 skrll rptr++;
574 1.4.2.2 skrll } else if (*rptr == BTH5_SLIP_XON) {
575 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
576 1.4.2.2 skrll break;
577 1.4.2.2 skrll count++;
578 1.4.2.2 skrll DPRINTFN(4, (" esc "));
579 1.4.2.2 skrll
580 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE_XON, &tp->t_outq) < 0) {
581 1.4.2.2 skrll sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_XON;
582 1.4.2.2 skrll break;
583 1.4.2.2 skrll }
584 1.4.2.2 skrll DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_XON));
585 1.4.2.2 skrll rptr++;
586 1.4.2.2 skrll } else if (*rptr == BTH5_SLIP_XOFF) {
587 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
588 1.4.2.2 skrll break;
589 1.4.2.2 skrll count++;
590 1.4.2.2 skrll DPRINTFN(4, (" esc "));
591 1.4.2.2 skrll
592 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE_XOFF, &tp->t_outq) < 0) {
593 1.4.2.2 skrll sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_XOFF;
594 1.4.2.2 skrll break;
595 1.4.2.2 skrll }
596 1.4.2.2 skrll DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_XOFF));
597 1.4.2.2 skrll rptr++;
598 1.4.2.2 skrll } else if (*rptr == BTH5_SLIP_ESCAPE) {
599 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
600 1.4.2.2 skrll break;
601 1.4.2.2 skrll count++;
602 1.4.2.2 skrll DPRINTFN(4, (" esc "));
603 1.4.2.2 skrll
604 1.4.2.2 skrll if (putc(BTH5_SLIP_ESCAPE_ESCAPE, &tp->t_outq) < 0) {
605 1.4.2.2 skrll sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_ESCAPE;
606 1.4.2.2 skrll break;
607 1.4.2.2 skrll }
608 1.4.2.2 skrll DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_ESCAPE));
609 1.4.2.2 skrll rptr++;
610 1.4.2.2 skrll } else {
611 1.4.2.2 skrll if (putc(*rptr++, &tp->t_outq) < 0)
612 1.4.2.2 skrll break;
613 1.4.2.2 skrll DPRINTFN(4, ("0x%02x ", *(rptr - 1)));
614 1.4.2.2 skrll }
615 1.4.2.2 skrll rlen++;
616 1.4.2.2 skrll count++;
617 1.4.2.2 skrll }
618 1.4.2.2 skrll if (m != NULL)
619 1.4.2.2 skrll m_adj(m, rlen);
620 1.4.2.2 skrll
621 1.4.2.2 skrll sc->sc_stats.byte_tx += count;
622 1.4.2.2 skrll
623 1.4.2.2 skrll if (tp->t_outq.c_cc != 0)
624 1.4.2.2 skrll (*tp->t_oproc)(tp);
625 1.4.2.2 skrll
626 1.4.2.2 skrll return 0;
627 1.4.2.2 skrll }
628 1.4.2.2 skrll
629 1.4.2.2 skrll static int
630 1.4.2.2 skrll bth5_slip_receive(int c, struct tty *tp)
631 1.4.2.2 skrll {
632 1.4.2.2 skrll struct bth5_softc *sc = tp->t_sc;
633 1.4.2.2 skrll struct mbuf *m = sc->sc_rxp;
634 1.4.2.2 skrll int discard = 0;
635 1.4.2.2 skrll const char *errstr;
636 1.4.2.2 skrll
637 1.4.2.2 skrll c &= TTY_CHARMASK;
638 1.4.2.2 skrll
639 1.4.2.2 skrll /* If we already started a packet, find the trailing end of it. */
640 1.4.2.2 skrll if (m) {
641 1.4.2.2 skrll while (m->m_next)
642 1.4.2.2 skrll m = m->m_next;
643 1.4.2.2 skrll
644 1.4.2.2 skrll if (M_TRAILINGSPACE(m) == 0) {
645 1.4.2.2 skrll /* extend mbuf */
646 1.4.2.2 skrll MGET(m->m_next, M_DONTWAIT, MT_DATA);
647 1.4.2.2 skrll if (m->m_next == NULL) {
648 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
649 1.4.2.2 skrll "out of memory\n");
650 1.4.2.2 skrll sc->sc_stats.err_rx++;
651 1.4.2.2 skrll return 0; /* (lost sync) */
652 1.4.2.2 skrll }
653 1.4.2.2 skrll
654 1.4.2.2 skrll m = m->m_next;
655 1.4.2.2 skrll m->m_len = 0;
656 1.4.2.2 skrll }
657 1.4.2.2 skrll } else
658 1.4.2.2 skrll if (c != BTH5_SLIP_PKTSTART) {
659 1.4.2.2 skrll discard = 1;
660 1.4.2.2 skrll errstr = "not sync";
661 1.4.2.2 skrll goto discarded;
662 1.4.2.2 skrll }
663 1.4.2.2 skrll
664 1.4.2.2 skrll switch (c) {
665 1.4.2.2 skrll case BTH5_SLIP_PKTSTART /* or _PKTEND */:
666 1.4.2.2 skrll if (m == NULL) {
667 1.4.2.2 skrll /* BTH5_SLIP_PKTSTART */
668 1.4.2.2 skrll
669 1.4.2.2 skrll DPRINTFN(4, ("%s: slip receive start\n",
670 1.4.2.2 skrll device_xname(sc->sc_dev)));
671 1.4.2.2 skrll
672 1.4.2.2 skrll /* new packet */
673 1.4.2.2 skrll MGETHDR(m, M_DONTWAIT, MT_DATA);
674 1.4.2.2 skrll if (m == NULL) {
675 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
676 1.4.2.2 skrll "out of memory\n");
677 1.4.2.2 skrll sc->sc_stats.err_rx++;
678 1.4.2.2 skrll return 0; /* (lost sync) */
679 1.4.2.2 skrll }
680 1.4.2.2 skrll
681 1.4.2.2 skrll sc->sc_rxp = m;
682 1.4.2.2 skrll m->m_pkthdr.len = m->m_len = 0;
683 1.4.2.2 skrll sc->sc_slip_rxexp = 0;
684 1.4.2.2 skrll } else {
685 1.4.2.2 skrll /* BTH5_SLIP_PKTEND */
686 1.4.2.2 skrll
687 1.4.2.2 skrll if (m == sc->sc_rxp && m->m_len == 0) {
688 1.4.2.2 skrll DPRINTFN(4, ("%s: resynchronises\n",
689 1.4.2.2 skrll device_xname(sc->sc_dev)));
690 1.4.2.2 skrll
691 1.4.2.2 skrll sc->sc_stats.byte_rx++;
692 1.4.2.2 skrll return 0;
693 1.4.2.2 skrll }
694 1.4.2.2 skrll
695 1.4.2.2 skrll DPRINTFN(4, ("%s%s: slip receive end\n",
696 1.4.2.2 skrll (m->m_len % 16 != 0) ? "\n" : "",
697 1.4.2.2 skrll device_xname(sc->sc_dev)));
698 1.4.2.2 skrll
699 1.4.2.2 skrll bth5_pktintegrity_receive(sc, sc->sc_rxp);
700 1.4.2.2 skrll sc->sc_rxp = NULL;
701 1.4.2.2 skrll sc->sc_slip_rxexp = BTH5_SLIP_PKTSTART;
702 1.4.2.2 skrll }
703 1.4.2.2 skrll sc->sc_stats.byte_rx++;
704 1.4.2.2 skrll return 0;
705 1.4.2.2 skrll
706 1.4.2.2 skrll case BTH5_SLIP_ESCAPE:
707 1.4.2.2 skrll
708 1.4.2.2 skrll DPRINTFN(4, (" esc"));
709 1.4.2.2 skrll
710 1.4.2.2 skrll if (sc->sc_slip_rxexp == BTH5_SLIP_ESCAPE) {
711 1.4.2.2 skrll discard = 1;
712 1.4.2.2 skrll errstr = "waiting 0xdc or 0xdb or 0xde of 0xdf";
713 1.4.2.2 skrll } else
714 1.4.2.2 skrll sc->sc_slip_rxexp = BTH5_SLIP_ESCAPE;
715 1.4.2.2 skrll break;
716 1.4.2.2 skrll
717 1.4.2.2 skrll default:
718 1.4.2.2 skrll DPRINTFN(4, (" 0x%02x%s",
719 1.4.2.2 skrll c, (m->m_len % 16 == 15) ? "\n" : ""));
720 1.4.2.2 skrll
721 1.4.2.2 skrll switch (sc->sc_slip_rxexp) {
722 1.4.2.2 skrll case BTH5_SLIP_PKTSTART:
723 1.4.2.2 skrll discard = 1;
724 1.4.2.2 skrll errstr = "waiting 0xc0";
725 1.4.2.2 skrll break;
726 1.4.2.2 skrll
727 1.4.2.2 skrll case BTH5_SLIP_ESCAPE:
728 1.4.2.2 skrll if (c == BTH5_SLIP_ESCAPE_PKTEND)
729 1.4.2.2 skrll mtod(m, uint8_t *)[m->m_len++] =
730 1.4.2.2 skrll BTH5_SLIP_PKTEND;
731 1.4.2.2 skrll else if (c == BTH5_SLIP_ESCAPE_XON)
732 1.4.2.2 skrll mtod(m, uint8_t *)[m->m_len++] =
733 1.4.2.2 skrll BTH5_SLIP_XON;
734 1.4.2.2 skrll else if (c == BTH5_SLIP_ESCAPE_XOFF)
735 1.4.2.2 skrll mtod(m, uint8_t *)[m->m_len++] =
736 1.4.2.2 skrll BTH5_SLIP_XOFF;
737 1.4.2.2 skrll else if (c == BTH5_SLIP_ESCAPE_ESCAPE)
738 1.4.2.2 skrll mtod(m, uint8_t *)[m->m_len++] =
739 1.4.2.2 skrll BTH5_SLIP_ESCAPE;
740 1.4.2.2 skrll else {
741 1.4.2.2 skrll discard = 1;
742 1.4.2.2 skrll errstr = "unknown escape";
743 1.4.2.2 skrll }
744 1.4.2.2 skrll sc->sc_slip_rxexp = 0;
745 1.4.2.2 skrll break;
746 1.4.2.2 skrll
747 1.4.2.2 skrll default:
748 1.4.2.2 skrll mtod(m, uint8_t *)[m->m_len++] = c;
749 1.4.2.2 skrll }
750 1.4.2.2 skrll sc->sc_rxp->m_pkthdr.len++;
751 1.4.2.2 skrll }
752 1.4.2.2 skrll if (discard) {
753 1.4.2.2 skrll discarded:
754 1.4.2.2 skrll #ifdef BTH5_DEBUG
755 1.4.2.2 skrll DPRINTFN(4, ("%s: receives unexpected byte 0x%02x: %s\n",
756 1.4.2.2 skrll device_xname(sc->sc_dev), c, errstr));
757 1.4.2.2 skrll #else
758 1.4.2.2 skrll __USE(errstr);
759 1.4.2.2 skrll #endif
760 1.4.2.2 skrll }
761 1.4.2.2 skrll sc->sc_stats.byte_rx++;
762 1.4.2.2 skrll
763 1.4.2.2 skrll return 0;
764 1.4.2.2 skrll }
765 1.4.2.2 skrll
766 1.4.2.2 skrll
767 1.4.2.2 skrll /*
768 1.4.2.2 skrll * BTH5 Packet Integrity Layer functions:
769 1.4.2.2 skrll * handling Payload Length, Checksum, CRC.
770 1.4.2.2 skrll */
771 1.4.2.2 skrll static void
772 1.4.2.2 skrll bth5_pktintegrity_transmit(struct bth5_softc *sc)
773 1.4.2.2 skrll {
774 1.4.2.2 skrll struct mbuf *m = sc->sc_txp;
775 1.4.2.2 skrll bth5_hdr_t *hdrp = mtod(m, bth5_hdr_t *);
776 1.4.2.2 skrll int pldlen;
777 1.4.2.2 skrll
778 1.4.2.2 skrll DPRINTFN(3, ("%s: pi transmit\n", device_xname(sc->sc_dev)));
779 1.4.2.2 skrll
780 1.4.2.2 skrll pldlen = m->m_pkthdr.len - sizeof(bth5_hdr_t);
781 1.4.2.2 skrll
782 1.4.2.2 skrll if (sc->sc_pi_txcrc)
783 1.4.2.2 skrll hdrp->flags |= BTH5_FLAGS_CRC_PRESENT;
784 1.4.2.2 skrll
785 1.4.2.2 skrll BTH5_SET_PLEN(hdrp, pldlen);
786 1.4.2.2 skrll BTH5_SET_CSUM(hdrp);
787 1.4.2.2 skrll
788 1.4.2.2 skrll if (sc->sc_pi_txcrc) {
789 1.4.2.2 skrll struct mbuf *_m;
790 1.4.2.2 skrll int n = 0;
791 1.4.2.2 skrll uint16_t crc = 0xffff;
792 1.4.2.2 skrll uint8_t *buf;
793 1.4.2.2 skrll
794 1.4.2.2 skrll for (_m = m; _m != NULL; _m = _m->m_next) {
795 1.4.2.2 skrll buf = mtod(_m, uint8_t *);
796 1.4.2.2 skrll for (n = 0; n < _m->m_len; n++)
797 1.4.2.2 skrll bth5_crc_update(&crc, *(buf + n));
798 1.4.2.2 skrll }
799 1.4.2.2 skrll crc = htobe16(bth5_crc_reverse(crc));
800 1.4.2.2 skrll m_copyback(m, m->m_pkthdr.len, sizeof(crc), &crc);
801 1.4.2.2 skrll }
802 1.4.2.2 skrll
803 1.4.2.2 skrll #ifdef BTH5_DEBUG
804 1.4.2.2 skrll if (bth5_debug == 3)
805 1.4.2.2 skrll bth5_packet_print(m);
806 1.4.2.2 skrll #endif
807 1.4.2.2 skrll
808 1.4.2.2 skrll bth5_slip_transmit(sc->sc_tp);
809 1.4.2.2 skrll }
810 1.4.2.2 skrll
811 1.4.2.2 skrll static void
812 1.4.2.2 skrll bth5_pktintegrity_receive(struct bth5_softc *sc, struct mbuf *m)
813 1.4.2.2 skrll {
814 1.4.2.2 skrll bth5_hdr_t *hdrp = mtod(m, bth5_hdr_t *);
815 1.4.2.2 skrll u_int pldlen;
816 1.4.2.2 skrll int discard = 0;
817 1.4.2.2 skrll uint16_t crc = 0xffff;
818 1.4.2.2 skrll const char *errstr;
819 1.4.2.2 skrll
820 1.4.2.2 skrll DPRINTFN(3, ("%s: pi receive\n", device_xname(sc->sc_dev)));
821 1.4.2.2 skrll #ifdef BTH5_DEBUG
822 1.4.2.2 skrll if (bth5_debug == 4)
823 1.4.2.2 skrll bth5_packet_print(m);
824 1.4.2.2 skrll #endif
825 1.4.2.2 skrll
826 1.4.2.2 skrll KASSERT(m->m_len >= sizeof(bth5_hdr_t));
827 1.4.2.2 skrll
828 1.4.2.2 skrll pldlen = m->m_pkthdr.len - sizeof(bth5_hdr_t) -
829 1.4.2.2 skrll ((hdrp->flags & BTH5_FLAGS_CRC_PRESENT) ? sizeof(crc) : 0);
830 1.4.2.2 skrll if (pldlen > 0xfff) {
831 1.4.2.2 skrll discard = 1;
832 1.4.2.2 skrll errstr = "Payload Length";
833 1.4.2.2 skrll goto discarded;
834 1.4.2.2 skrll }
835 1.4.2.2 skrll if (hdrp->csum != BTH5_GET_CSUM(hdrp)) {
836 1.4.2.2 skrll discard = 1;
837 1.4.2.2 skrll errstr = "Checksum";
838 1.4.2.2 skrll goto discarded;
839 1.4.2.2 skrll }
840 1.4.2.2 skrll if (BTH5_GET_PLEN(hdrp) != pldlen) {
841 1.4.2.2 skrll discard = 1;
842 1.4.2.2 skrll errstr = "Payload Length";
843 1.4.2.2 skrll goto discarded;
844 1.4.2.2 skrll }
845 1.4.2.2 skrll if (hdrp->flags & BTH5_FLAGS_CRC_PRESENT) {
846 1.4.2.2 skrll struct mbuf *_m;
847 1.4.2.2 skrll int i, n;
848 1.4.2.2 skrll uint16_t crc0;
849 1.4.2.2 skrll uint8_t *buf;
850 1.4.2.2 skrll
851 1.4.2.2 skrll i = 0;
852 1.4.2.2 skrll n = 0;
853 1.4.2.2 skrll for (_m = m; _m != NULL; _m = _m->m_next) {
854 1.4.2.2 skrll buf = mtod(m, uint8_t *);
855 1.4.2.2 skrll for (n = 0;
856 1.4.2.2 skrll n < _m->m_len && i < sizeof(bth5_hdr_t) + pldlen;
857 1.4.2.2 skrll n++, i++)
858 1.4.2.2 skrll bth5_crc_update(&crc, *(buf + n));
859 1.4.2.2 skrll }
860 1.4.2.2 skrll
861 1.4.2.2 skrll m_copydata(_m, n, sizeof(crc0), &crc0);
862 1.4.2.2 skrll if (be16toh(crc0) != bth5_crc_reverse(crc)) {
863 1.4.2.2 skrll discard = 1;
864 1.4.2.2 skrll errstr = "CRC";
865 1.4.2.2 skrll } else
866 1.4.2.2 skrll /* Shaves CRC */
867 1.4.2.2 skrll m_adj(m, (int)(0 - sizeof(crc)));
868 1.4.2.2 skrll }
869 1.4.2.2 skrll
870 1.4.2.2 skrll if (discard) {
871 1.4.2.2 skrll discarded:
872 1.4.2.2 skrll #ifdef BTH5_DEBUG
873 1.4.2.2 skrll DPRINTFN(3, ("%s: receives unexpected packet: %s\n",
874 1.4.2.2 skrll device_xname(sc->sc_dev), errstr));
875 1.4.2.2 skrll #else
876 1.4.2.2 skrll __USE(errstr);
877 1.4.2.2 skrll #endif
878 1.4.2.2 skrll m_freem(m);
879 1.4.2.2 skrll } else
880 1.4.2.2 skrll bth5_mux_receive(sc, m);
881 1.4.2.2 skrll }
882 1.4.2.2 skrll
883 1.4.2.2 skrll static const uint16_t crctbl[] = {
884 1.4.2.2 skrll 0x0000, 0x1081, 0x2102, 0x3183,
885 1.4.2.2 skrll 0x4204, 0x5285, 0x6306, 0x7387,
886 1.4.2.2 skrll 0x8408, 0x9489, 0xa50a, 0xb58b,
887 1.4.2.2 skrll 0xc60c, 0xd68d, 0xe70e, 0xf78f,
888 1.4.2.2 skrll };
889 1.4.2.2 skrll
890 1.4.2.2 skrll static void
891 1.4.2.2 skrll bth5_crc_update(uint16_t *crc, uint8_t d)
892 1.4.2.2 skrll {
893 1.4.2.2 skrll uint16_t reg = *crc;
894 1.4.2.2 skrll
895 1.4.2.2 skrll reg = (reg >> 4) ^ crctbl[(reg ^ d) & 0x000f];
896 1.4.2.2 skrll reg = (reg >> 4) ^ crctbl[(reg ^ (d >> 4)) & 0x000f];
897 1.4.2.2 skrll
898 1.4.2.2 skrll *crc = reg;
899 1.4.2.2 skrll }
900 1.4.2.2 skrll
901 1.4.2.2 skrll static uint16_t
902 1.4.2.2 skrll bth5_crc_reverse(uint16_t crc)
903 1.4.2.2 skrll {
904 1.4.2.2 skrll uint16_t b, rev;
905 1.4.2.2 skrll
906 1.4.2.2 skrll for (b = 0, rev = 0; b < 16; b++) {
907 1.4.2.2 skrll rev = rev << 1;
908 1.4.2.2 skrll rev |= (crc & 1);
909 1.4.2.2 skrll crc = crc >> 1;
910 1.4.2.2 skrll }
911 1.4.2.2 skrll
912 1.4.2.2 skrll return rev;
913 1.4.2.2 skrll }
914 1.4.2.2 skrll
915 1.4.2.2 skrll
916 1.4.2.2 skrll /*
917 1.4.2.2 skrll * BTH5 MUX Layer functions
918 1.4.2.2 skrll */
919 1.4.2.2 skrll static void
920 1.4.2.2 skrll bth5_mux_transmit(struct bth5_softc *sc)
921 1.4.2.2 skrll {
922 1.4.2.2 skrll struct mbuf *m;
923 1.4.2.2 skrll bth5_hdr_t *hdrp;
924 1.4.2.2 skrll
925 1.4.2.2 skrll DPRINTFN(2, ("%s: mux transmit: sc_flags=0x%x, choke=%d",
926 1.4.2.2 skrll device_xname(sc->sc_dev), sc->sc_flags, sc->sc_mux_choke));
927 1.4.2.2 skrll
928 1.4.2.2 skrll if (sc->sc_mux_choke) {
929 1.4.2.2 skrll struct mbuf *_m = NULL;
930 1.4.2.2 skrll
931 1.4.2.2 skrll /* In this case, send only Link Establishment packet */
932 1.4.2.2 skrll for (m = MBUFQ_FIRST(&sc->sc_dgq); m != NULL;
933 1.4.2.2 skrll _m = m, m = MBUFQ_NEXT(m)) {
934 1.4.2.2 skrll hdrp = mtod(m, bth5_hdr_t *);
935 1.4.2.2 skrll if (hdrp->ident == BTH5_CHANNEL_LE) {
936 1.4.2.2 skrll if (m == MBUFQ_FIRST(&sc->sc_dgq))
937 1.4.2.2 skrll MBUFQ_DEQUEUE(&sc->sc_dgq, m);
938 1.4.2.2 skrll else {
939 1.4.2.2 skrll if (m->m_nextpkt == NULL)
940 1.4.2.2 skrll sc->sc_dgq.mq_last =
941 1.4.2.2 skrll &_m->m_nextpkt;
942 1.4.2.2 skrll _m->m_nextpkt = m->m_nextpkt;
943 1.4.2.2 skrll m->m_nextpkt = NULL;
944 1.4.2.2 skrll }
945 1.4.2.2 skrll goto transmit;
946 1.4.2.2 skrll }
947 1.4.2.2 skrll }
948 1.4.2.2 skrll DPRINTFN(2, ("\n"));
949 1.4.2.2 skrll return;
950 1.4.2.2 skrll }
951 1.4.2.2 skrll
952 1.4.2.2 skrll /*
953 1.4.2.2 skrll * The MUX Layer always gives priority to packets from the Datagram
954 1.4.2.2 skrll * Queue Layer over the Sequencing Layer.
955 1.4.2.2 skrll */
956 1.4.2.2 skrll if (MBUFQ_FIRST(&sc->sc_dgq)) {
957 1.4.2.2 skrll MBUFQ_DEQUEUE(&sc->sc_dgq, m);
958 1.4.2.2 skrll goto transmit;
959 1.4.2.2 skrll }
960 1.4.2.2 skrll if (MBUFQ_FIRST(&sc->sc_seqq)) {
961 1.4.2.2 skrll MBUFQ_DEQUEUE(&sc->sc_seqq, m);
962 1.4.2.2 skrll hdrp = mtod(m, bth5_hdr_t *);
963 1.4.2.2 skrll hdrp->flags |= BTH5_FLAGS_PROTOCOL_REL; /* Reliable */
964 1.4.2.2 skrll goto transmit;
965 1.4.2.2 skrll }
966 1.4.2.2 skrll sc->sc_flags &= ~BTH5_XMIT;
967 1.4.2.2 skrll bth5_start(sc);
968 1.4.2.2 skrll if (sc->sc_mux_send_ack == true) {
969 1.4.2.2 skrll m = bth5_create_ackpkt();
970 1.4.2.2 skrll if (m != NULL)
971 1.4.2.2 skrll goto transmit;
972 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
973 1.4.2.2 skrll sc->sc_stats.err_tx++;
974 1.4.2.2 skrll }
975 1.4.2.2 skrll
976 1.4.2.2 skrll /* Nothing to send */
977 1.4.2.2 skrll DPRINTFN(2, ("\n"));
978 1.4.2.2 skrll return;
979 1.4.2.2 skrll
980 1.4.2.2 skrll transmit:
981 1.4.2.2 skrll DPRINTFN(2, (", txack=%d, send_ack=%d\n",
982 1.4.2.2 skrll bth5_get_txack(sc), sc->sc_mux_send_ack));
983 1.4.2.2 skrll
984 1.4.2.2 skrll hdrp = mtod(m, bth5_hdr_t *);
985 1.4.2.2 skrll hdrp->flags |=
986 1.4.2.2 skrll (bth5_get_txack(sc) << BTH5_FLAGS_ACK_SHIFT) & BTH5_FLAGS_ACK_MASK;
987 1.4.2.2 skrll if (sc->sc_mux_send_ack == true)
988 1.4.2.2 skrll sc->sc_mux_send_ack = false;
989 1.4.2.2 skrll
990 1.4.2.2 skrll #ifdef BTH5_DEBUG
991 1.4.2.2 skrll if (bth5_debug == 3)
992 1.4.2.2 skrll bth5_packet_print(m);
993 1.4.2.2 skrll #endif
994 1.4.2.2 skrll
995 1.4.2.2 skrll sc->sc_txp = m;
996 1.4.2.2 skrll bth5_pktintegrity_transmit(sc);
997 1.4.2.2 skrll }
998 1.4.2.2 skrll
999 1.4.2.2 skrll static void
1000 1.4.2.2 skrll bth5_mux_receive(struct bth5_softc *sc, struct mbuf *m)
1001 1.4.2.2 skrll {
1002 1.4.2.2 skrll bth5_hdr_t *hdrp = mtod(m, bth5_hdr_t *);
1003 1.4.2.2 skrll const u_int rxack = BTH5_FLAGS_ACK(hdrp->flags);
1004 1.4.2.2 skrll
1005 1.4.2.2 skrll DPRINTFN(2, ("%s: mux receive: flags=0x%x, ident=%d, rxack=%d\n",
1006 1.4.2.2 skrll device_xname(sc->sc_dev), hdrp->flags, hdrp->ident, rxack));
1007 1.4.2.2 skrll #ifdef BTH5_DEBUG
1008 1.4.2.2 skrll if (bth5_debug == 3)
1009 1.4.2.2 skrll bth5_packet_print(m);
1010 1.4.2.2 skrll #endif
1011 1.4.2.2 skrll
1012 1.4.2.2 skrll bth5_signal_rxack(sc, rxack);
1013 1.4.2.2 skrll
1014 1.4.2.2 skrll microtime(&sc->sc_mux_lastrx);
1015 1.4.2.2 skrll
1016 1.4.2.2 skrll /* if the Ack Packet received then discard */
1017 1.4.2.2 skrll if (BTH5_FLAGS_SEQ(hdrp->flags) == 0 &&
1018 1.4.2.2 skrll hdrp->ident == BTH5_IDENT_ACKPKT &&
1019 1.4.2.2 skrll BTH5_GET_PLEN(hdrp) == 0) {
1020 1.4.2.2 skrll m_freem(m);
1021 1.4.2.2 skrll return;
1022 1.4.2.2 skrll }
1023 1.4.2.2 skrll
1024 1.4.2.2 skrll if (hdrp->flags & BTH5_FLAGS_PROTOCOL_REL)
1025 1.4.2.2 skrll bth5_sequencing_receive(sc, m);
1026 1.4.2.2 skrll else
1027 1.4.2.2 skrll bth5_datagramq_receive(sc, m);
1028 1.4.2.2 skrll }
1029 1.4.2.2 skrll
1030 1.4.2.2 skrll static __inline void
1031 1.4.2.2 skrll bth5_send_ack_command(struct bth5_softc *sc)
1032 1.4.2.2 skrll {
1033 1.4.2.2 skrll
1034 1.4.2.2 skrll DPRINTFN(2, ("%s: mux send_ack_command\n", device_xname(sc->sc_dev)));
1035 1.4.2.2 skrll
1036 1.4.2.2 skrll sc->sc_mux_send_ack = true;
1037 1.4.2.2 skrll }
1038 1.4.2.2 skrll
1039 1.4.2.2 skrll static __inline struct mbuf *
1040 1.4.2.2 skrll bth5_create_ackpkt(void)
1041 1.4.2.2 skrll {
1042 1.4.2.2 skrll struct mbuf *m;
1043 1.4.2.2 skrll bth5_hdr_t *hdrp;
1044 1.4.2.2 skrll
1045 1.4.2.2 skrll MGETHDR(m, M_DONTWAIT, MT_DATA);
1046 1.4.2.2 skrll if (m != NULL) {
1047 1.4.2.2 skrll m->m_pkthdr.len = m->m_len = sizeof(bth5_hdr_t);
1048 1.4.2.2 skrll hdrp = mtod(m, bth5_hdr_t *);
1049 1.4.2.2 skrll /*
1050 1.4.2.2 skrll * An Ack Packet has the following fields:
1051 1.4.2.2 skrll * Ack Field: txack (not set yet)
1052 1.4.2.2 skrll * Seq Field: 0
1053 1.4.2.2 skrll * Protocol Identifier Field: 0
1054 1.4.2.2 skrll * Protocol Type Field: Any value
1055 1.4.2.2 skrll * Payload Length Field: 0
1056 1.4.2.2 skrll */
1057 1.4.2.2 skrll memset(hdrp, 0, sizeof(bth5_hdr_t));
1058 1.4.2.2 skrll }
1059 1.4.2.2 skrll return m;
1060 1.4.2.2 skrll }
1061 1.4.2.2 skrll
1062 1.4.2.2 skrll static __inline void
1063 1.4.2.2 skrll bth5_set_choke(struct bth5_softc *sc, bool choke)
1064 1.4.2.2 skrll {
1065 1.4.2.2 skrll
1066 1.4.2.2 skrll DPRINTFN(2, ("%s: mux set choke=%d\n", device_xname(sc->sc_dev), choke));
1067 1.4.2.2 skrll
1068 1.4.2.2 skrll sc->sc_mux_choke = choke;
1069 1.4.2.2 skrll }
1070 1.4.2.2 skrll
1071 1.4.2.2 skrll
1072 1.4.2.2 skrll /*
1073 1.4.2.2 skrll * BTH5 Sequencing Layer functions
1074 1.4.2.2 skrll */
1075 1.4.2.2 skrll static void
1076 1.4.2.2 skrll bth5_sequencing_receive(struct bth5_softc *sc, struct mbuf *m)
1077 1.4.2.2 skrll {
1078 1.4.2.2 skrll bth5_hdr_t hdr;
1079 1.4.2.2 skrll uint32_t exp_rxseq, rxseq;
1080 1.4.2.2 skrll
1081 1.4.2.2 skrll exp_rxseq = sc->sc_seq_expected_rxseq & BTH5_FLAGS_SEQ_MASK;
1082 1.4.2.2 skrll m_copydata(m, 0, sizeof(bth5_hdr_t), &hdr);
1083 1.4.2.2 skrll rxseq = BTH5_FLAGS_SEQ(hdr.flags);
1084 1.4.2.2 skrll
1085 1.4.2.2 skrll DPRINTFN(1, ("%s: seq receive: rxseq=%d, expected %d\n",
1086 1.4.2.2 skrll device_xname(sc->sc_dev), rxseq, exp_rxseq));
1087 1.4.2.2 skrll #ifdef BTH5_DEBUG
1088 1.4.2.2 skrll if (bth5_debug == 2)
1089 1.4.2.2 skrll bth5_packet_print(m);
1090 1.4.2.2 skrll #endif
1091 1.4.2.2 skrll
1092 1.4.2.2 skrll /*
1093 1.4.2.2 skrll * We remove the header of BTH5 and add the 'uint8_t type' of
1094 1.4.2.2 skrll * hci_*_hdr_t to the head.
1095 1.4.2.2 skrll */
1096 1.4.2.2 skrll m_adj(m, sizeof(bth5_hdr_t) - sizeof(uint8_t));
1097 1.4.2.2 skrll
1098 1.4.2.2 skrll if (rxseq != exp_rxseq) {
1099 1.4.2.2 skrll m_freem(m);
1100 1.4.2.2 skrll
1101 1.4.2.2 skrll bth5_send_ack_command(sc);
1102 1.4.2.2 skrll /* send ack packet, if needly */
1103 1.4.2.2 skrll bth5_mux_transmit(sc);
1104 1.4.2.2 skrll
1105 1.4.2.2 skrll return;
1106 1.4.2.2 skrll }
1107 1.4.2.2 skrll
1108 1.4.2.2 skrll switch (hdr.ident) {
1109 1.4.2.2 skrll case BTH5_CHANNEL_HCI_CMD:
1110 1.4.2.2 skrll *(mtod(m, uint8_t *)) = HCI_CMD_PKT;
1111 1.4.2.2 skrll if (!hci_input_event(sc->sc_unit, m))
1112 1.4.2.2 skrll sc->sc_stats.err_rx++;
1113 1.4.2.2 skrll
1114 1.4.2.2 skrll sc->sc_stats.evt_rx++;
1115 1.4.2.2 skrll break;
1116 1.4.2.2 skrll
1117 1.4.2.2 skrll case BTH5_CHANNEL_HCI_EVT:
1118 1.4.2.2 skrll *(mtod(m, uint8_t *)) = HCI_EVENT_PKT;
1119 1.4.2.2 skrll if (!hci_input_event(sc->sc_unit, m))
1120 1.4.2.2 skrll sc->sc_stats.err_rx++;
1121 1.4.2.2 skrll
1122 1.4.2.2 skrll sc->sc_stats.evt_rx++;
1123 1.4.2.2 skrll break;
1124 1.4.2.2 skrll
1125 1.4.2.2 skrll case BTH5_CHANNEL_HCI_ACL:
1126 1.4.2.2 skrll *(mtod(m, uint8_t *)) = HCI_ACL_DATA_PKT;
1127 1.4.2.2 skrll if (!hci_input_acl(sc->sc_unit, m))
1128 1.4.2.2 skrll sc->sc_stats.err_rx++;
1129 1.4.2.2 skrll
1130 1.4.2.2 skrll sc->sc_stats.acl_rx++;
1131 1.4.2.2 skrll break;
1132 1.4.2.2 skrll
1133 1.4.2.2 skrll case BTH5_CHANNEL_HCI_SCO:
1134 1.4.2.2 skrll *(mtod(m, uint8_t *)) = HCI_SCO_DATA_PKT;
1135 1.4.2.2 skrll if (!hci_input_sco(sc->sc_unit, m))
1136 1.4.2.2 skrll sc->sc_stats.err_rx++;
1137 1.4.2.2 skrll
1138 1.4.2.2 skrll sc->sc_stats.sco_rx++;
1139 1.4.2.2 skrll break;
1140 1.4.2.2 skrll
1141 1.4.2.2 skrll default:
1142 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1143 1.4.2.2 skrll "received reliable packet with not support channel %d\n",
1144 1.4.2.2 skrll hdr.ident);
1145 1.4.2.2 skrll m_freem(m);
1146 1.4.2.2 skrll break;
1147 1.4.2.2 skrll }
1148 1.4.2.2 skrll
1149 1.4.2.2 skrll if (sc->sc_seq_expected_rxseq / sc->sc_seq_winsize ==
1150 1.4.2.2 skrll sc->sc_seq_winsize) {
1151 1.4.2.2 skrll bth5_send_ack_command(sc);
1152 1.4.2.2 skrll sc->sc_seq_txack = sc->sc_seq_expected_rxseq & BTH5_FLAGS_SEQ_MASK;
1153 1.4.2.2 skrll } else
1154 1.4.2.2 skrll sc->sc_seq_txack = rxseq;
1155 1.4.2.2 skrll
1156 1.4.2.2 skrll sc->sc_seq_expected_rxseq =
1157 1.4.2.2 skrll (sc->sc_seq_expected_rxseq + 1);
1158 1.4.2.2 skrll }
1159 1.4.2.2 skrll
1160 1.4.2.2 skrll static bool
1161 1.4.2.2 skrll bth5_tx_reliable_pkt(struct bth5_softc *sc, struct mbuf *m, u_int protocol_id)
1162 1.4.2.2 skrll {
1163 1.4.2.2 skrll bth5_hdr_t *hdrp;
1164 1.4.2.2 skrll struct mbuf *_m;
1165 1.4.2.2 skrll struct mbuf *_retrans;
1166 1.4.2.2 skrll u_int pldlen;
1167 1.4.2.2 skrll int s;
1168 1.4.2.2 skrll
1169 1.4.2.2 skrll DPRINTFN(1, ("%s: seq transmit:"
1170 1.4.2.2 skrll "protocol_id=%d, winspace=%d, txseq=%d\n", device_xname(sc->sc_dev),
1171 1.4.2.2 skrll protocol_id, sc->sc_seq_winspace, sc->sc_seq_txseq));
1172 1.4.2.2 skrll
1173 1.4.2.2 skrll for (pldlen = 0, _m = m; _m != NULL; _m = _m->m_next) {
1174 1.4.2.2 skrll if (_m->m_len < 0)
1175 1.4.2.2 skrll goto out;
1176 1.4.2.2 skrll pldlen += _m->m_len;
1177 1.4.2.2 skrll }
1178 1.4.2.2 skrll if (pldlen > 0xfff)
1179 1.4.2.2 skrll goto out;
1180 1.4.2.2 skrll if (protocol_id == BTH5_IDENT_ACKPKT || protocol_id > 15)
1181 1.4.2.2 skrll goto out;
1182 1.4.2.2 skrll
1183 1.4.2.2 skrll if (sc->sc_seq_winspace == 0)
1184 1.4.2.2 skrll goto out;
1185 1.4.2.2 skrll
1186 1.4.2.2 skrll M_PREPEND(m, sizeof(bth5_hdr_t), M_DONTWAIT);
1187 1.4.2.2 skrll if (m == NULL) {
1188 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
1189 1.4.2.2 skrll return false;
1190 1.4.2.2 skrll }
1191 1.4.2.2 skrll KASSERT(m->m_len >= sizeof(bth5_hdr_t));
1192 1.4.2.2 skrll
1193 1.4.2.2 skrll hdrp = mtod(m, bth5_hdr_t *);
1194 1.4.2.2 skrll memset(hdrp, 0, sizeof(bth5_hdr_t));
1195 1.4.2.2 skrll hdrp->flags |= sc->sc_seq_txseq;
1196 1.4.2.2 skrll hdrp->ident = protocol_id;
1197 1.4.2.2 skrll
1198 1.4.2.2 skrll callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
1199 1.4.2.2 skrll
1200 1.4.2.2 skrll s = splserial();
1201 1.4.2.2 skrll MBUFQ_ENQUEUE(&sc->sc_seqq, m);
1202 1.4.2.2 skrll splx(s);
1203 1.4.2.2 skrll sc->sc_transmit_callback = bth5_reliabletx_callback;
1204 1.4.2.2 skrll
1205 1.4.2.2 skrll #ifdef BTH5_DEBUG
1206 1.4.2.2 skrll if (bth5_debug == 2)
1207 1.4.2.2 skrll bth5_packet_print(m);
1208 1.4.2.2 skrll #endif
1209 1.4.2.2 skrll
1210 1.4.2.2 skrll sc->sc_seq_txseq = (sc->sc_seq_txseq + 1) & BTH5_FLAGS_SEQ_MASK;
1211 1.4.2.2 skrll sc->sc_seq_winspace--;
1212 1.4.2.2 skrll _retrans = m_copym(m, 0, M_COPYALL, M_WAIT);
1213 1.4.2.2 skrll if (_retrans == NULL) {
1214 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
1215 1.4.2.2 skrll goto out;
1216 1.4.2.2 skrll }
1217 1.4.2.2 skrll MBUFQ_ENQUEUE(&sc->sc_seq_retryq, _retrans);
1218 1.4.2.2 skrll bth5_mux_transmit(sc);
1219 1.4.2.2 skrll
1220 1.4.2.2 skrll return true;
1221 1.4.2.2 skrll out:
1222 1.4.2.2 skrll m_freem(m);
1223 1.4.2.2 skrll return false;
1224 1.4.2.2 skrll }
1225 1.4.2.2 skrll
1226 1.4.2.2 skrll static __inline u_int
1227 1.4.2.2 skrll bth5_get_txack(struct bth5_softc *sc)
1228 1.4.2.2 skrll {
1229 1.4.2.2 skrll
1230 1.4.2.2 skrll return sc->sc_seq_txack;
1231 1.4.2.2 skrll }
1232 1.4.2.2 skrll
1233 1.4.2.2 skrll static void
1234 1.4.2.2 skrll bth5_signal_rxack(struct bth5_softc *sc, uint32_t rxack)
1235 1.4.2.2 skrll {
1236 1.4.2.2 skrll bth5_hdr_t *hdrp;
1237 1.4.2.2 skrll struct mbuf *m;
1238 1.4.2.2 skrll uint32_t seqno = (rxack - 1) & BTH5_FLAGS_SEQ_MASK;
1239 1.4.2.2 skrll int s;
1240 1.4.2.2 skrll
1241 1.4.2.2 skrll DPRINTFN(1, ("%s: seq signal rxack: rxack=%d\n",
1242 1.4.2.2 skrll device_xname(sc->sc_dev), rxack));
1243 1.4.2.2 skrll
1244 1.4.2.2 skrll s = splserial();
1245 1.4.2.2 skrll m = MBUFQ_FIRST(&sc->sc_seq_retryq);
1246 1.4.2.2 skrll while (m != NULL) {
1247 1.4.2.2 skrll hdrp = mtod(m, bth5_hdr_t *);
1248 1.4.2.2 skrll if (BTH5_FLAGS_SEQ(hdrp->flags) == seqno) {
1249 1.4.2.2 skrll struct mbuf *m0;
1250 1.4.2.2 skrll
1251 1.4.2.2 skrll for (m0 = MBUFQ_FIRST(&sc->sc_seq_retryq);
1252 1.4.2.2 skrll m0 != MBUFQ_NEXT(m);
1253 1.4.2.2 skrll m0 = MBUFQ_FIRST(&sc->sc_seq_retryq)) {
1254 1.4.2.2 skrll MBUFQ_DEQUEUE(&sc->sc_seq_retryq, m0);
1255 1.4.2.2 skrll m_freem(m0);
1256 1.4.2.2 skrll sc->sc_seq_winspace++;
1257 1.4.2.2 skrll }
1258 1.4.2.2 skrll break;
1259 1.4.2.2 skrll }
1260 1.4.2.2 skrll m = MBUFQ_NEXT(m);
1261 1.4.2.2 skrll }
1262 1.4.2.2 skrll splx(s);
1263 1.4.2.2 skrll sc->sc_seq_retries = 0;
1264 1.4.2.2 skrll
1265 1.4.2.2 skrll if (sc->sc_seq_winspace == sc->sc_seq_winsize)
1266 1.4.2.2 skrll callout_stop(&sc->sc_seq_timer);
1267 1.4.2.2 skrll else
1268 1.4.2.2 skrll callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
1269 1.4.2.2 skrll }
1270 1.4.2.2 skrll
1271 1.4.2.2 skrll static void
1272 1.4.2.2 skrll bth5_reliabletx_callback(struct bth5_softc *sc, struct mbuf *m)
1273 1.4.2.2 skrll {
1274 1.4.2.2 skrll
1275 1.4.2.2 skrll m_freem(m);
1276 1.4.2.2 skrll }
1277 1.4.2.2 skrll
1278 1.4.2.2 skrll static void
1279 1.4.2.2 skrll bth5_timer_timeout(void *arg)
1280 1.4.2.2 skrll {
1281 1.4.2.2 skrll struct bth5_softc *sc = arg;
1282 1.4.2.2 skrll struct mbuf *m, *_m;
1283 1.4.2.2 skrll int s, i = 0;
1284 1.4.2.2 skrll
1285 1.4.2.2 skrll DPRINTFN(1, ("%s: seq timeout: retries=%d\n",
1286 1.4.2.2 skrll device_xname(sc->sc_dev), sc->sc_seq_retries));
1287 1.4.2.2 skrll
1288 1.4.2.2 skrll s = splserial();
1289 1.4.2.2 skrll for (m = MBUFQ_FIRST(&sc->sc_seq_retryq); m != NULL;
1290 1.4.2.2 skrll m = MBUFQ_NEXT(m)) {
1291 1.4.2.2 skrll _m = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1292 1.4.2.2 skrll if (_m == NULL) {
1293 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
1294 1.4.2.2 skrll return;
1295 1.4.2.2 skrll }
1296 1.4.2.2 skrll MBUFQ_ENQUEUE(&sc->sc_seqq, _m);
1297 1.4.2.2 skrll i++;
1298 1.4.2.2 skrll }
1299 1.4.2.2 skrll splx(s);
1300 1.4.2.2 skrll
1301 1.4.2.2 skrll if (i != 0) {
1302 1.4.2.2 skrll if (++sc->sc_seq_retries < sc->sc_seq_retry_limit)
1303 1.4.2.2 skrll callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
1304 1.4.2.2 skrll else {
1305 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1306 1.4.2.2 skrll "reached the retry limit."
1307 1.4.2.2 skrll " restart the link-establishment\n");
1308 1.4.2.2 skrll bth5_sequencing_reset(sc);
1309 1.4.2.2 skrll bth5_start_le(sc);
1310 1.4.2.2 skrll return;
1311 1.4.2.2 skrll }
1312 1.4.2.2 skrll }
1313 1.4.2.2 skrll bth5_mux_transmit(sc);
1314 1.4.2.2 skrll }
1315 1.4.2.2 skrll
1316 1.4.2.2 skrll static void
1317 1.4.2.2 skrll bth5_sequencing_reset(struct bth5_softc *sc)
1318 1.4.2.2 skrll {
1319 1.4.2.2 skrll int s;
1320 1.4.2.2 skrll
1321 1.4.2.2 skrll s = splserial();
1322 1.4.2.2 skrll MBUFQ_DRAIN(&sc->sc_seqq);
1323 1.4.2.2 skrll MBUFQ_DRAIN(&sc->sc_seq_retryq);
1324 1.4.2.2 skrll splx(s);
1325 1.4.2.2 skrll
1326 1.4.2.2 skrll
1327 1.4.2.2 skrll sc->sc_seq_txseq = 0;
1328 1.4.2.2 skrll sc->sc_seq_txack = 0;
1329 1.4.2.2 skrll sc->sc_seq_winspace = sc->sc_seq_winsize;
1330 1.4.2.2 skrll sc->sc_seq_retries = 0;
1331 1.4.2.2 skrll callout_stop(&sc->sc_seq_timer);
1332 1.4.2.2 skrll
1333 1.4.2.2 skrll sc->sc_mux_send_ack = false;
1334 1.4.2.2 skrll
1335 1.4.2.2 skrll /* XXXX: expected_rxseq should be set by MUX Layer */
1336 1.4.2.2 skrll sc->sc_seq_expected_rxseq = 0;
1337 1.4.2.2 skrll }
1338 1.4.2.2 skrll
1339 1.4.2.2 skrll
1340 1.4.2.2 skrll /*
1341 1.4.2.2 skrll * BTH5 Datagram Queue Layer functions
1342 1.4.2.2 skrll */
1343 1.4.2.2 skrll static void
1344 1.4.2.2 skrll bth5_datagramq_receive(struct bth5_softc *sc, struct mbuf *m)
1345 1.4.2.2 skrll {
1346 1.4.2.2 skrll bth5_hdr_t hdr;
1347 1.4.2.2 skrll
1348 1.4.2.2 skrll DPRINTFN(1, ("%s: dgq receive\n", device_xname(sc->sc_dev)));
1349 1.4.2.2 skrll #ifdef BTH5_DEBUG
1350 1.4.2.2 skrll if (bth5_debug == 2)
1351 1.4.2.2 skrll bth5_packet_print(m);
1352 1.4.2.2 skrll #endif
1353 1.4.2.2 skrll
1354 1.4.2.2 skrll m_copydata(m, 0, sizeof(bth5_hdr_t), &hdr);
1355 1.4.2.2 skrll
1356 1.4.2.2 skrll switch (hdr.ident) {
1357 1.4.2.2 skrll case BTH5_CHANNEL_LE:
1358 1.4.2.2 skrll m_adj(m, sizeof(bth5_hdr_t));
1359 1.4.2.2 skrll bth5_input_le(sc, m);
1360 1.4.2.2 skrll break;
1361 1.4.2.2 skrll
1362 1.4.2.2 skrll case BTH5_CHANNEL_HCI_SCO:
1363 1.4.2.2 skrll /*
1364 1.4.2.2 skrll * We remove the header of BTH5 and add the 'uint8_t type' of
1365 1.4.2.2 skrll * hci_scodata_hdr_t to the head.
1366 1.4.2.2 skrll */
1367 1.4.2.2 skrll m_adj(m, sizeof(bth5_hdr_t) - sizeof(uint8_t));
1368 1.4.2.2 skrll *(mtod(m, uint8_t *)) = HCI_SCO_DATA_PKT;
1369 1.4.2.2 skrll if (!hci_input_sco(sc->sc_unit, m))
1370 1.4.2.2 skrll sc->sc_stats.err_rx++;
1371 1.4.2.2 skrll
1372 1.4.2.2 skrll sc->sc_stats.sco_rx++;
1373 1.4.2.2 skrll break;
1374 1.4.2.2 skrll
1375 1.4.2.2 skrll default:
1376 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1377 1.4.2.2 skrll "received unreliable packet with not support channel %d\n",
1378 1.4.2.2 skrll hdr.ident);
1379 1.4.2.2 skrll m_freem(m);
1380 1.4.2.2 skrll break;
1381 1.4.2.2 skrll }
1382 1.4.2.2 skrll }
1383 1.4.2.2 skrll
1384 1.4.2.2 skrll static bool
1385 1.4.2.2 skrll bth5_tx_unreliable_pkt(struct bth5_softc *sc, struct mbuf *m, u_int protocol_id)
1386 1.4.2.2 skrll {
1387 1.4.2.2 skrll bth5_hdr_t *hdrp;
1388 1.4.2.2 skrll struct mbuf *_m;
1389 1.4.2.2 skrll u_int pldlen;
1390 1.4.2.2 skrll int s;
1391 1.4.2.2 skrll
1392 1.4.2.2 skrll DPRINTFN(1, ("%s: dgq transmit: protocol_id=%d,",
1393 1.4.2.2 skrll device_xname(sc->sc_dev), protocol_id));
1394 1.4.2.2 skrll
1395 1.4.2.2 skrll for (pldlen = 0, _m = m; _m != NULL; _m = m->m_next) {
1396 1.4.2.2 skrll if (_m->m_len < 0)
1397 1.4.2.2 skrll goto out;
1398 1.4.2.2 skrll pldlen += _m->m_len;
1399 1.4.2.2 skrll }
1400 1.4.2.2 skrll DPRINTFN(1, (" pldlen=%d\n", pldlen));
1401 1.4.2.2 skrll if (pldlen > 0xfff)
1402 1.4.2.2 skrll goto out;
1403 1.4.2.2 skrll if (protocol_id == BTH5_IDENT_ACKPKT || protocol_id > 15)
1404 1.4.2.2 skrll goto out;
1405 1.4.2.2 skrll
1406 1.4.2.2 skrll M_PREPEND(m, sizeof(bth5_hdr_t), M_DONTWAIT);
1407 1.4.2.2 skrll if (m == NULL) {
1408 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
1409 1.4.2.2 skrll return false;
1410 1.4.2.2 skrll }
1411 1.4.2.2 skrll KASSERT(m->m_len >= sizeof(bth5_hdr_t));
1412 1.4.2.2 skrll
1413 1.4.2.2 skrll hdrp = mtod(m, bth5_hdr_t *);
1414 1.4.2.2 skrll memset(hdrp, 0, sizeof(bth5_hdr_t));
1415 1.4.2.2 skrll hdrp->ident = protocol_id;
1416 1.4.2.2 skrll
1417 1.4.2.2 skrll s = splserial();
1418 1.4.2.2 skrll MBUFQ_ENQUEUE(&sc->sc_dgq, m);
1419 1.4.2.2 skrll splx(s);
1420 1.4.2.2 skrll sc->sc_transmit_callback = bth5_unreliabletx_callback;
1421 1.4.2.2 skrll
1422 1.4.2.2 skrll #ifdef BTH5_DEBUG
1423 1.4.2.2 skrll if (bth5_debug == 2)
1424 1.4.2.2 skrll bth5_packet_print(m);
1425 1.4.2.2 skrll #endif
1426 1.4.2.2 skrll
1427 1.4.2.2 skrll bth5_mux_transmit(sc);
1428 1.4.2.2 skrll
1429 1.4.2.2 skrll return true;
1430 1.4.2.2 skrll out:
1431 1.4.2.2 skrll m_freem(m);
1432 1.4.2.2 skrll return false;
1433 1.4.2.2 skrll }
1434 1.4.2.2 skrll
1435 1.4.2.2 skrll static void
1436 1.4.2.2 skrll bth5_unreliabletx_callback(struct bth5_softc *sc, struct mbuf *m)
1437 1.4.2.2 skrll {
1438 1.4.2.2 skrll
1439 1.4.2.2 skrll if (M_GETCTX(m, void *) == NULL)
1440 1.4.2.2 skrll m_freem(m);
1441 1.4.2.2 skrll else if (!hci_complete_sco(sc->sc_unit, m))
1442 1.4.2.2 skrll sc->sc_stats.err_tx++;
1443 1.4.2.2 skrll }
1444 1.4.2.2 skrll
1445 1.4.2.2 skrll
1446 1.4.2.2 skrll /*
1447 1.4.2.2 skrll * BTUART H5 Link Establishment Protocol functions
1448 1.4.2.2 skrll */
1449 1.4.2.2 skrll static const uint8_t sync[] = BTH5_LE_SYNC;
1450 1.4.2.2 skrll static const uint8_t syncresp[] = BTH5_LE_SYNCRESP;
1451 1.4.2.2 skrll static const uint8_t conf[] = BTH5_LE_CONF;
1452 1.4.2.2 skrll static const uint8_t confresp[] = BTH5_LE_CONFRESP;
1453 1.4.2.2 skrll
1454 1.4.2.2 skrll static int
1455 1.4.2.2 skrll bth5_start_le(struct bth5_softc *sc)
1456 1.4.2.2 skrll {
1457 1.4.2.2 skrll
1458 1.4.2.2 skrll DPRINTF(("%s: start link-establish\n", device_xname(sc->sc_dev)));
1459 1.4.2.2 skrll
1460 1.4.2.2 skrll bth5_set_choke(sc, true);
1461 1.4.2.2 skrll
1462 1.4.2.2 skrll if (!sc->sc_le_muzzled) {
1463 1.4.2.2 skrll struct mbuf *m;
1464 1.4.2.2 skrll
1465 1.4.2.2 skrll m = m_gethdr(M_WAIT, MT_DATA);
1466 1.4.2.2 skrll m->m_pkthdr.len = m->m_len = 0;
1467 1.4.2.2 skrll m_copyback(m, 0, sizeof(sync), sync);
1468 1.4.2.2 skrll if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE)) {
1469 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1470 1.4.2.2 skrll "le-packet transmit failed\n");
1471 1.4.2.2 skrll return EINVAL;
1472 1.4.2.2 skrll }
1473 1.4.2.2 skrll }
1474 1.4.2.2 skrll callout_schedule(&sc->sc_le_timer, BTH5_LE_TSHY_TIMEOUT);
1475 1.4.2.2 skrll
1476 1.4.2.2 skrll sc->sc_le_state = le_state_shy;
1477 1.4.2.2 skrll return 0;
1478 1.4.2.2 skrll }
1479 1.4.2.2 skrll
1480 1.4.2.2 skrll static void
1481 1.4.2.2 skrll bth5_terminate_le(struct bth5_softc *sc)
1482 1.4.2.2 skrll {
1483 1.4.2.2 skrll struct mbuf *m;
1484 1.4.2.2 skrll
1485 1.4.2.2 skrll /* terminate link-establishment */
1486 1.4.2.2 skrll callout_stop(&sc->sc_le_timer);
1487 1.4.2.2 skrll bth5_set_choke(sc, true);
1488 1.4.2.2 skrll MGETHDR(m, M_DONTWAIT, MT_DATA);
1489 1.4.2.2 skrll if (m == NULL)
1490 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
1491 1.4.2.2 skrll else {
1492 1.4.2.2 skrll /* length of le packets is 4 */
1493 1.4.2.2 skrll m->m_pkthdr.len = m->m_len = 0;
1494 1.4.2.2 skrll m_copyback(m, 0, sizeof(sync), sync);
1495 1.4.2.2 skrll if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE))
1496 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1497 1.4.2.2 skrll "link-establishment terminations failed\n");
1498 1.4.2.2 skrll }
1499 1.4.2.2 skrll }
1500 1.4.2.2 skrll
1501 1.4.2.2 skrll static void
1502 1.4.2.2 skrll bth5_input_le(struct bth5_softc *sc, struct mbuf *m)
1503 1.4.2.2 skrll {
1504 1.4.2.2 skrll uint16_t *rcvpkt;
1505 1.4.2.2 skrll int i;
1506 1.4.2.2 skrll const uint8_t *rplypkt;
1507 1.4.2.2 skrll static struct {
1508 1.4.2.2 skrll const char *type;
1509 1.4.2.2 skrll const uint8_t *datap;
1510 1.4.2.2 skrll } pkt[] = {
1511 1.4.2.2 skrll { "sync", sync },
1512 1.4.2.2 skrll { "sync-resp", syncresp },
1513 1.4.2.2 skrll { "conf", conf },
1514 1.4.2.2 skrll { "conf-resp", confresp },
1515 1.4.2.2 skrll
1516 1.4.2.2 skrll { NULL, 0 }
1517 1.4.2.2 skrll };
1518 1.4.2.2 skrll
1519 1.4.2.2 skrll DPRINTFN(0, ("%s: le input: state %d, muzzled %d\n",
1520 1.4.2.2 skrll device_xname(sc->sc_dev), sc->sc_le_state, sc->sc_le_muzzled));
1521 1.4.2.2 skrll #ifdef BTH5_DEBUG
1522 1.4.2.2 skrll if (bth5_debug == 1)
1523 1.4.2.2 skrll bth5_packet_print(m);
1524 1.4.2.2 skrll #endif
1525 1.4.2.2 skrll
1526 1.4.2.2 skrll rcvpkt = mtod(m, uint16_t *);
1527 1.4.2.2 skrll i = 0;
1528 1.4.2.2 skrll
1529 1.4.2.2 skrll /* length of le packets is 2 */
1530 1.4.2.2 skrll if (m->m_len == sizeof(uint16_t))
1531 1.4.2.2 skrll for (i = 0; pkt[i].type != NULL; i++)
1532 1.4.2.2 skrll if (*(const uint16_t *)pkt[i].datap == *rcvpkt)
1533 1.4.2.2 skrll break;
1534 1.4.2.2 skrll if (m->m_len < sizeof(uint16_t) || pkt[i].type == NULL) {
1535 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "received unknown packet\n");
1536 1.4.2.2 skrll m_freem(m);
1537 1.4.2.2 skrll return;
1538 1.4.2.2 skrll }
1539 1.4.2.2 skrll
1540 1.4.2.2 skrll rplypkt = NULL;
1541 1.4.2.2 skrll switch (sc->sc_le_state) {
1542 1.4.2.2 skrll case le_state_shy:
1543 1.4.2.2 skrll if (*rcvpkt == *(const uint16_t *)sync) {
1544 1.4.2.2 skrll sc->sc_le_muzzled = false;
1545 1.4.2.2 skrll rplypkt = syncresp;
1546 1.4.2.2 skrll } else if (*rcvpkt == *(const uint16_t *)syncresp) {
1547 1.4.2.2 skrll DPRINTF(("%s: state change to curious\n",
1548 1.4.2.2 skrll device_xname(sc->sc_dev)));
1549 1.4.2.2 skrll rplypkt = conf;
1550 1.4.2.2 skrll callout_schedule(&sc->sc_le_timer,
1551 1.4.2.2 skrll BTH5_LE_TCONF_TIMEOUT);
1552 1.4.2.2 skrll sc->sc_le_state = le_state_curious;
1553 1.4.2.2 skrll } else
1554 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1555 1.4.2.2 skrll "received an unknown packet at shy\n");
1556 1.4.2.2 skrll break;
1557 1.4.2.2 skrll
1558 1.4.2.2 skrll case le_state_curious:
1559 1.4.2.2 skrll if (*rcvpkt == *(const uint16_t *)sync)
1560 1.4.2.2 skrll rplypkt = syncresp;
1561 1.4.2.2 skrll else if (*rcvpkt == *(const uint16_t *)syncresp)
1562 1.4.2.2 skrll rplypkt = conf;
1563 1.4.2.2 skrll else if (*rcvpkt == *(const uint16_t *)conf)
1564 1.4.2.2 skrll rplypkt = confresp;
1565 1.4.2.2 skrll else if (*rcvpkt == *(const uint16_t *)confresp) {
1566 1.4.2.2 skrll DPRINTF(("%s: state change to garrulous:\n",
1567 1.4.2.2 skrll device_xname(sc->sc_dev)));
1568 1.4.2.2 skrll
1569 1.4.2.2 skrll bth5_set_choke(sc, false);
1570 1.4.2.2 skrll callout_stop(&sc->sc_le_timer);
1571 1.4.2.2 skrll sc->sc_le_state = le_state_garrulous;
1572 1.4.2.2 skrll } else
1573 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1574 1.4.2.2 skrll "received unknown packet at curious\n");
1575 1.4.2.2 skrll break;
1576 1.4.2.2 skrll
1577 1.4.2.2 skrll case le_state_garrulous:
1578 1.4.2.2 skrll if (*rcvpkt == *(const uint16_t *)conf)
1579 1.4.2.2 skrll rplypkt = confresp;
1580 1.4.2.2 skrll else if (*rcvpkt == *(const uint16_t *)sync) {
1581 1.4.2.2 skrll /* XXXXX */
1582 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1583 1.4.2.2 skrll "received sync! peer to reset?\n");
1584 1.4.2.2 skrll
1585 1.4.2.2 skrll bth5_sequencing_reset(sc);
1586 1.4.2.2 skrll rplypkt = sync;
1587 1.4.2.2 skrll sc->sc_le_state = le_state_shy;
1588 1.4.2.2 skrll } else
1589 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1590 1.4.2.2 skrll "received unknown packet at garrulous\n");
1591 1.4.2.2 skrll break;
1592 1.4.2.2 skrll }
1593 1.4.2.2 skrll
1594 1.4.2.2 skrll int len = m->m_len;
1595 1.4.2.2 skrll m_freem(m);
1596 1.4.2.2 skrll
1597 1.4.2.2 skrll if (rplypkt != NULL) {
1598 1.4.2.2 skrll MGETHDR(m, M_DONTWAIT, MT_DATA);
1599 1.4.2.2 skrll if (m == NULL)
1600 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
1601 1.4.2.2 skrll else {
1602 1.4.2.2 skrll /* length of le packets is 2 */
1603 1.4.2.2 skrll m->m_pkthdr.len = m->m_len = 0;
1604 1.4.2.2 skrll if (rplypkt == confresp || rplypkt == conf)
1605 1.4.2.2 skrll m_copyback(m, 0, len, rplypkt);
1606 1.4.2.2 skrll else
1607 1.4.2.2 skrll m_copyback(m, 0, 2, rplypkt);
1608 1.4.2.2 skrll if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE))
1609 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1610 1.4.2.2 skrll "le-packet transmit failed\n");
1611 1.4.2.2 skrll }
1612 1.4.2.2 skrll }
1613 1.4.2.2 skrll }
1614 1.4.2.2 skrll
1615 1.4.2.2 skrll static void
1616 1.4.2.2 skrll bth5_le_timeout(void *arg)
1617 1.4.2.2 skrll {
1618 1.4.2.2 skrll struct bth5_softc *sc = arg;
1619 1.4.2.2 skrll struct mbuf *m;
1620 1.4.2.2 skrll int timeout;
1621 1.4.2.2 skrll const uint8_t *sndpkt = NULL;
1622 1.4.2.2 skrll
1623 1.4.2.2 skrll DPRINTFN(0, ("%s: le timeout: state %d, muzzled %d\n",
1624 1.4.2.2 skrll device_xname(sc->sc_dev), sc->sc_le_state, sc->sc_le_muzzled));
1625 1.4.2.2 skrll
1626 1.4.2.2 skrll switch (sc->sc_le_state) {
1627 1.4.2.2 skrll case le_state_shy:
1628 1.4.2.2 skrll if (!sc->sc_le_muzzled)
1629 1.4.2.2 skrll sndpkt = sync;
1630 1.4.2.2 skrll timeout = BTH5_LE_TSHY_TIMEOUT;
1631 1.4.2.2 skrll break;
1632 1.4.2.2 skrll
1633 1.4.2.2 skrll case le_state_curious:
1634 1.4.2.2 skrll sndpkt = conf;
1635 1.4.2.2 skrll timeout = BTH5_LE_TCONF_TIMEOUT;
1636 1.4.2.2 skrll break;
1637 1.4.2.2 skrll
1638 1.4.2.2 skrll default:
1639 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1640 1.4.2.2 skrll "timeout happen at unknown state %d\n", sc->sc_le_state);
1641 1.4.2.2 skrll return;
1642 1.4.2.2 skrll }
1643 1.4.2.2 skrll
1644 1.4.2.2 skrll if (sndpkt != NULL) {
1645 1.4.2.2 skrll MGETHDR(m, M_DONTWAIT, MT_DATA);
1646 1.4.2.2 skrll if (m == NULL)
1647 1.4.2.2 skrll aprint_error_dev(sc->sc_dev, "out of memory\n");
1648 1.4.2.2 skrll else {
1649 1.4.2.2 skrll /* length of le packets is 4 */
1650 1.4.2.2 skrll m->m_pkthdr.len = m->m_len = 0;
1651 1.4.2.2 skrll if (sndpkt == conf || sndpkt == confresp)
1652 1.4.2.2 skrll m_copyback(m, 0, 3, sndpkt);
1653 1.4.2.2 skrll else
1654 1.4.2.2 skrll m_copyback(m, 0, 2, sndpkt);
1655 1.4.2.2 skrll if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE))
1656 1.4.2.2 skrll aprint_error_dev(sc->sc_dev,
1657 1.4.2.2 skrll "le-packet transmit failed\n");
1658 1.4.2.2 skrll }
1659 1.4.2.2 skrll }
1660 1.4.2.2 skrll
1661 1.4.2.2 skrll callout_schedule(&sc->sc_le_timer, timeout);
1662 1.4.2.2 skrll }
1663 1.4.2.2 skrll
1664 1.4.2.2 skrll
1665 1.4.2.2 skrll /*
1666 1.4.2.2 skrll * BTUART H5 Serial Protocol functions.
1667 1.4.2.2 skrll */
1668 1.4.2.2 skrll static int
1669 1.4.2.2 skrll bth5_enable(device_t self)
1670 1.4.2.2 skrll {
1671 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
1672 1.4.2.2 skrll int s;
1673 1.4.2.2 skrll
1674 1.4.2.2 skrll if (sc->sc_flags & BTH5_ENABLED)
1675 1.4.2.2 skrll return 0;
1676 1.4.2.2 skrll
1677 1.4.2.2 skrll s = spltty();
1678 1.4.2.2 skrll
1679 1.4.2.2 skrll sc->sc_flags |= BTH5_ENABLED;
1680 1.4.2.2 skrll sc->sc_flags &= ~BTH5_XMIT;
1681 1.4.2.2 skrll
1682 1.4.2.2 skrll splx(s);
1683 1.4.2.2 skrll
1684 1.4.2.2 skrll return 0;
1685 1.4.2.2 skrll }
1686 1.4.2.2 skrll
1687 1.4.2.2 skrll static void
1688 1.4.2.2 skrll bth5_disable(device_t self)
1689 1.4.2.2 skrll {
1690 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
1691 1.4.2.2 skrll int s;
1692 1.4.2.2 skrll
1693 1.4.2.2 skrll if ((sc->sc_flags & BTH5_ENABLED) == 0)
1694 1.4.2.2 skrll return;
1695 1.4.2.2 skrll
1696 1.4.2.2 skrll s = spltty();
1697 1.4.2.2 skrll
1698 1.4.2.2 skrll if (sc->sc_rxp) {
1699 1.4.2.2 skrll m_freem(sc->sc_rxp);
1700 1.4.2.2 skrll sc->sc_rxp = NULL;
1701 1.4.2.2 skrll }
1702 1.4.2.2 skrll
1703 1.4.2.2 skrll if (sc->sc_txp) {
1704 1.4.2.2 skrll m_freem(sc->sc_txp);
1705 1.4.2.2 skrll sc->sc_txp = NULL;
1706 1.4.2.2 skrll }
1707 1.4.2.2 skrll
1708 1.4.2.2 skrll MBUFQ_DRAIN(&sc->sc_cmdq);
1709 1.4.2.2 skrll MBUFQ_DRAIN(&sc->sc_aclq);
1710 1.4.2.2 skrll MBUFQ_DRAIN(&sc->sc_scoq);
1711 1.4.2.2 skrll
1712 1.4.2.2 skrll sc->sc_flags &= ~BTH5_ENABLED;
1713 1.4.2.2 skrll splx(s);
1714 1.4.2.2 skrll }
1715 1.4.2.2 skrll
1716 1.4.2.2 skrll static void
1717 1.4.2.2 skrll bth5_start(struct bth5_softc *sc)
1718 1.4.2.2 skrll {
1719 1.4.2.2 skrll struct mbuf *m;
1720 1.4.2.2 skrll
1721 1.4.2.2 skrll KASSERT((sc->sc_flags & BTH5_XMIT) == 0);
1722 1.4.2.2 skrll KASSERT(sc->sc_txp == NULL);
1723 1.4.2.2 skrll
1724 1.4.2.2 skrll if (MBUFQ_FIRST(&sc->sc_aclq)) {
1725 1.4.2.2 skrll MBUFQ_DEQUEUE(&sc->sc_aclq, m);
1726 1.4.2.2 skrll sc->sc_stats.acl_tx++;
1727 1.4.2.2 skrll sc->sc_flags |= BTH5_XMIT;
1728 1.4.2.2 skrll bth5_tx_reliable_pkt(sc, m, BTH5_CHANNEL_HCI_ACL);
1729 1.4.2.2 skrll }
1730 1.4.2.2 skrll
1731 1.4.2.2 skrll if (MBUFQ_FIRST(&sc->sc_cmdq)) {
1732 1.4.2.2 skrll MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
1733 1.4.2.2 skrll sc->sc_stats.cmd_tx++;
1734 1.4.2.2 skrll sc->sc_flags |= BTH5_XMIT;
1735 1.4.2.2 skrll bth5_tx_reliable_pkt(sc, m, BTH5_CHANNEL_HCI_CMD);
1736 1.4.2.2 skrll }
1737 1.4.2.2 skrll
1738 1.4.2.2 skrll if (MBUFQ_FIRST(&sc->sc_scoq)) {
1739 1.4.2.2 skrll MBUFQ_DEQUEUE(&sc->sc_scoq, m);
1740 1.4.2.2 skrll sc->sc_stats.sco_tx++;
1741 1.4.2.2 skrll /* XXXX: We can transmit with reliable */
1742 1.4.2.2 skrll sc->sc_flags |= BTH5_XMIT;
1743 1.4.2.2 skrll bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_HCI_SCO);
1744 1.4.2.2 skrll }
1745 1.4.2.2 skrll
1746 1.4.2.2 skrll return;
1747 1.4.2.2 skrll }
1748 1.4.2.2 skrll
1749 1.4.2.2 skrll static void
1750 1.4.2.2 skrll bth5_output_cmd(device_t self, struct mbuf *m)
1751 1.4.2.2 skrll {
1752 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
1753 1.4.2.2 skrll int s;
1754 1.4.2.2 skrll
1755 1.4.2.2 skrll KASSERT(sc->sc_flags & BTH5_ENABLED);
1756 1.4.2.2 skrll
1757 1.4.2.2 skrll m_adj(m, sizeof(uint8_t));
1758 1.4.2.2 skrll M_SETCTX(m, NULL);
1759 1.4.2.2 skrll
1760 1.4.2.2 skrll s = spltty();
1761 1.4.2.2 skrll MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
1762 1.4.2.2 skrll if ((sc->sc_flags & BTH5_XMIT) == 0)
1763 1.4.2.2 skrll bth5_start(sc);
1764 1.4.2.2 skrll
1765 1.4.2.2 skrll splx(s);
1766 1.4.2.2 skrll }
1767 1.4.2.2 skrll
1768 1.4.2.2 skrll static void
1769 1.4.2.2 skrll bth5_output_acl(device_t self, struct mbuf *m)
1770 1.4.2.2 skrll {
1771 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
1772 1.4.2.2 skrll int s;
1773 1.4.2.2 skrll
1774 1.4.2.2 skrll KASSERT(sc->sc_flags & BTH5_ENABLED);
1775 1.4.2.2 skrll
1776 1.4.2.2 skrll m_adj(m, sizeof(uint8_t));
1777 1.4.2.2 skrll M_SETCTX(m, NULL);
1778 1.4.2.2 skrll
1779 1.4.2.2 skrll s = spltty();
1780 1.4.2.2 skrll MBUFQ_ENQUEUE(&sc->sc_aclq, m);
1781 1.4.2.2 skrll if ((sc->sc_flags & BTH5_XMIT) == 0)
1782 1.4.2.2 skrll bth5_start(sc);
1783 1.4.2.2 skrll
1784 1.4.2.2 skrll splx(s);
1785 1.4.2.2 skrll }
1786 1.4.2.2 skrll
1787 1.4.2.2 skrll static void
1788 1.4.2.2 skrll bth5_output_sco(device_t self, struct mbuf *m)
1789 1.4.2.2 skrll {
1790 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
1791 1.4.2.2 skrll int s;
1792 1.4.2.2 skrll
1793 1.4.2.2 skrll KASSERT(sc->sc_flags & BTH5_ENABLED);
1794 1.4.2.2 skrll
1795 1.4.2.2 skrll m_adj(m, sizeof(uint8_t));
1796 1.4.2.2 skrll
1797 1.4.2.2 skrll s = spltty();
1798 1.4.2.2 skrll MBUFQ_ENQUEUE(&sc->sc_scoq, m);
1799 1.4.2.2 skrll if ((sc->sc_flags & BTH5_XMIT) == 0)
1800 1.4.2.2 skrll bth5_start(sc);
1801 1.4.2.2 skrll
1802 1.4.2.2 skrll splx(s);
1803 1.4.2.2 skrll }
1804 1.4.2.2 skrll
1805 1.4.2.2 skrll static void
1806 1.4.2.2 skrll bth5_stats(device_t self, struct bt_stats *dest, int flush)
1807 1.4.2.2 skrll {
1808 1.4.2.2 skrll struct bth5_softc *sc = device_private(self);
1809 1.4.2.2 skrll int s;
1810 1.4.2.2 skrll
1811 1.4.2.2 skrll s = spltty();
1812 1.4.2.2 skrll memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
1813 1.4.2.2 skrll
1814 1.4.2.2 skrll if (flush)
1815 1.4.2.2 skrll memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
1816 1.4.2.2 skrll
1817 1.4.2.2 skrll splx(s);
1818 1.4.2.2 skrll }
1819 1.4.2.2 skrll
1820 1.4.2.2 skrll
1821 1.4.2.2 skrll #ifdef BTH5_DEBUG
1822 1.4.2.2 skrll static void
1823 1.4.2.2 skrll bth5_packet_print(struct mbuf *m)
1824 1.4.2.2 skrll {
1825 1.4.2.2 skrll int i;
1826 1.4.2.2 skrll uint8_t *p;
1827 1.4.2.2 skrll
1828 1.4.2.2 skrll for ( ; m != NULL; m = m->m_next) {
1829 1.4.2.2 skrll p = mtod(m, uint8_t *);
1830 1.4.2.2 skrll for (i = 0; i < m->m_len; i++) {
1831 1.4.2.2 skrll if (i % 16 == 0)
1832 1.4.2.2 skrll printf(" ");
1833 1.4.2.2 skrll printf(" %02x", *(p + i));
1834 1.4.2.2 skrll if (i % 16 == 15)
1835 1.4.2.2 skrll printf("\n");
1836 1.4.2.2 skrll }
1837 1.4.2.2 skrll printf("\n");
1838 1.4.2.2 skrll }
1839 1.4.2.2 skrll }
1840 1.4.2.2 skrll #endif
1841