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