ubt.c revision 1.3.2.3 1 /* $NetBSD: ubt.c,v 1.3.2.3 2003/01/07 21:34:56 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart (at) augustsson.net) and
9 * David Sainty (David.Sainty (at) dtsp.co.nz).
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: ubt.c,v 1.3.2.3 2003/01/07 21:34:56 thorpej Exp $");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/device.h>
48 #include <sys/lock.h>
49 #include <sys/ioctl.h>
50 #include <sys/conf.h>
51 #include <sys/file.h>
52 #include <sys/poll.h>
53 #include <sys/select.h>
54 #include <sys/proc.h>
55
56 #include <dev/usb/ubtreg.h>
57 #include <dev/usb/usb.h>
58 #include <dev/usb/usbdi.h>
59 #include <dev/usb/usbdi_util.h>
60 #include <dev/usb/usbdevs.h>
61
62 #include <dev/bluetooth/bluetooth.h>
63
64 #ifdef UBT_DEBUG
65 #define DPRINTF(x) if (ubtdebug) logprintf x
66 #define DPRINTFN(n,x) if (ubtdebug>(n)) logprintf x
67 int ubtdebug = 99;
68 #else
69 #define DPRINTF(x)
70 #define DPRINTFN(n,x)
71 #endif
72
73 /*
74 * Protocol related definitions
75 */
76
77 struct ubt_softc {
78 USBBASEDEVICE sc_dev;
79 usbd_device_handle sc_udev;
80 usbd_interface_handle sc_ctl_iface;
81 usbd_interface_handle sc_isoc_iface;
82
83 /* Control */
84 usbd_pipe_handle sc_ctl_pipe;
85 usbd_xfer_handle sc_ctl_xfer;
86 u_int8_t *sc_ctl_buf;
87
88 /* Events */
89 int sc_evt_addr;
90 usbd_pipe_handle sc_evt_pipe;
91 usbd_xfer_handle sc_evt_xfer;
92 u_int8_t *sc_evt_buf;
93
94 /* ACL data (in) */
95 int sc_aclrd_addr;
96 usbd_pipe_handle sc_aclrd_pipe;
97 usbd_xfer_handle sc_aclrd_xfer;
98 u_int8_t *sc_aclrd_buf;
99 int sc_aclrd_running;
100
101 /* ACL data (out) */
102 int sc_aclwr_addr;
103 usbd_pipe_handle sc_aclwr_pipe;
104 usbd_xfer_handle sc_aclwr_xfer;
105 u_int8_t *sc_aclwr_buf;
106
107 struct device *sc_child;
108 struct btframe_callback_methods const *sc_cb;
109
110 unsigned int sc_blocked;
111
112 int sc_refcnt;
113 char sc_dying;
114 };
115
116 static int ubt_open(void *h, int flag, int mode, usb_proc_ptr p);
117 static int ubt_close(void *h, int flag, int mode, usb_proc_ptr p);
118
119 static int ubt_control(void *h, u_int8_t *data, size_t len);
120 static int ubt_sendacldata(void *h, u_int8_t *data, size_t len);
121 static int ubt_sendscodata(void *h, u_int8_t *data, size_t len);
122
123 static int ubt_splraise(void);
124 static unsigned int ubt_blockcb(void *h, unsigned int cbblocks);
125 static unsigned int ubt_unblockcb(void *h, unsigned int cbblocks);
126
127 static void ubt_event_cb(usbd_xfer_handle, usbd_private_handle, usbd_status);
128 static void ubt_aclrd_cb(usbd_xfer_handle, usbd_private_handle, usbd_status);
129 static void ubt_aclrd_request(struct ubt_softc *);
130
131 static struct btframe_methods const ubt_methods = {
132 ubt_open, ubt_close, ubt_control, ubt_sendacldata, ubt_sendscodata,
133 ubt_splraise, ubt_blockcb, ubt_unblockcb
134 };
135
136 USB_DECLARE_DRIVER(ubt);
137
138 USB_MATCH(ubt)
139 {
140 USB_MATCH_START(ubt, uaa);
141 usb_interface_descriptor_t *id;
142
143 DPRINTFN(50,("ubt_match\n"));
144
145 if (uaa->iface == NULL)
146 return (UMATCH_NONE);
147
148 id = usbd_get_interface_descriptor(uaa->iface);
149 if (id != NULL &&
150 id->bInterfaceClass == UICLASS_WIRELESS &&
151 id->bInterfaceSubClass == UISUBCLASS_RF &&
152 id->bInterfaceProtocol == UIPROTO_BLUETOOTH)
153 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
154 return (UMATCH_NONE);
155 }
156
157 USB_ATTACH(ubt)
158 {
159 USB_ATTACH_START(ubt, sc, uaa);
160 usbd_device_handle dev = uaa->device;
161 usbd_interface_handle iface = uaa->iface;
162 struct bt_attach_args bt;
163 usb_interface_descriptor_t const *id;
164 char devinfo[1024];
165 usb_endpoint_descriptor_t const *ed;
166 u_int8_t epcount;
167 int i;
168
169 DPRINTFN(10,("ubt_attach: sc=%p\n", sc));
170
171 usbd_devinfo(dev, 0, devinfo);
172 USB_ATTACH_SETUP;
173 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
174
175 sc->sc_udev = dev;
176 sc->sc_ctl_iface = iface;
177
178 /*
179 * The control interface comes before the isoc interface
180 * according to the spec, so we find it first.
181 */
182 epcount = 0;
183 (void)usbd_endpoint_count(iface, &epcount);
184
185 sc->sc_evt_addr = -1;
186 sc->sc_aclrd_addr = -1;
187 sc->sc_aclwr_addr = -1;
188
189 for (i = 0; i < epcount; i++) {
190 ed = usbd_interface2endpoint_descriptor(iface, i);
191 if (ed == NULL) {
192 printf("%s: couldn't get ep %d\n",
193 USBDEVNAME(sc->sc_dev), i);
194 USB_ATTACH_ERROR_RETURN;
195 }
196
197 DPRINTFN(10, ("%s: addr=%d attr=%d\n", __func__,
198 (int)ed->bEndpointAddress,
199 (int)ed->bmAttributes));
200
201 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
202 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
203 sc->sc_evt_addr = ed->bEndpointAddress;
204 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
205 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
206 sc->sc_aclrd_addr = ed->bEndpointAddress;
207 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
208 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
209 sc->sc_aclwr_addr = ed->bEndpointAddress;
210 }
211 }
212
213 if (sc->sc_evt_addr == -1 ||
214 sc->sc_aclrd_addr == -1 || sc->sc_aclwr_addr == -1) {
215 printf("%s: missing endpoint\n", USBDEVNAME(sc->sc_dev));
216 USB_ATTACH_ERROR_RETURN;
217 }
218
219 /* XXX works because isoc comes after ctl */
220 /* Grab isoc interface as well. */
221 for (i = 0; i < uaa->nifaces; i++) {
222 if (uaa->ifaces[i] == NULL)
223 continue;
224 id = usbd_get_interface_descriptor(uaa->ifaces[i]);
225 if (id != NULL &&
226 id->bInterfaceClass == UICLASS_WIRELESS &&
227 id->bInterfaceSubClass == UISUBCLASS_RF &&
228 id->bInterfaceProtocol == UIPROTO_BLUETOOTH) {
229 sc->sc_isoc_iface = uaa->ifaces[i];
230 uaa->ifaces[i] = NULL;
231 }
232 }
233
234 printf("%s: has%s isoc data\n", USBDEVNAME(sc->sc_dev),
235 sc->sc_isoc_iface != NULL ? "" : " no");
236
237 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
238 USBDEV(sc->sc_dev));
239
240 bt.bt_methods = &ubt_methods;
241 bt.bt_cb = &sc->sc_cb;
242
243 sc->sc_child = config_found(self, &bt, bt_print);
244
245 USB_ATTACH_SUCCESS_RETURN;
246 }
247
248 static void
249 ubt_abortdealloc(struct ubt_softc *sc)
250 {
251 DPRINTFN(0, ("%s: sc=%p\n", __func__, sc));
252
253 if (sc->sc_evt_pipe != NULL) {
254 usbd_abort_pipe(sc->sc_evt_pipe);
255 usbd_close_pipe(sc->sc_evt_pipe);
256 sc->sc_evt_pipe = NULL;
257 }
258 if (sc->sc_evt_buf != NULL) {
259 free(sc->sc_evt_buf, M_USBDEV);
260 sc->sc_evt_buf = NULL;
261 }
262 if (sc->sc_aclrd_pipe != NULL) {
263 usbd_abort_pipe(sc->sc_aclrd_pipe);
264 usbd_close_pipe(sc->sc_aclrd_pipe);
265 sc->sc_aclrd_pipe = NULL;
266 }
267 if (sc->sc_aclwr_pipe != NULL) {
268 usbd_abort_pipe(sc->sc_aclwr_pipe);
269 usbd_close_pipe(sc->sc_aclwr_pipe);
270 sc->sc_aclwr_pipe = NULL;
271 }
272 if (sc->sc_aclrd_xfer != NULL) {
273 usbd_free_xfer(sc->sc_aclrd_xfer);
274 sc->sc_aclrd_xfer = NULL;
275 sc->sc_aclrd_buf = NULL;
276 }
277 if (sc->sc_aclwr_xfer != NULL) {
278 usbd_free_xfer(sc->sc_aclwr_xfer);
279 sc->sc_aclwr_xfer = NULL;
280 sc->sc_aclwr_buf = NULL;
281 }
282 }
283
284 USB_DETACH(ubt)
285 {
286 USB_DETACH_START(ubt, sc);
287 int s;
288 int rv = 0;
289
290 DPRINTF(("%s: sc=%p flags=%d\n", __func__, sc, flags));
291
292 sc->sc_dying = 1;
293
294 /* Abort all pipes. Causes processes waiting for transfer to wake. */
295 ubt_abortdealloc(sc);
296
297 DPRINTFN(1, ("%s: waiting for USB detach\n", __func__));
298 s = splusb();
299 if (--sc->sc_refcnt >= 0) {
300 /* Wait for processes to go away. */
301 usb_detach_wait(USBDEV(sc->sc_dev));
302 }
303 splx(s);
304 DPRINTFN(1, ("%s: USB detach complete\n", __func__));
305
306 if (sc->sc_child != NULL) {
307 DPRINTFN(1, ("%s: waiting for child detach\n", __func__));
308 rv = config_detach(sc->sc_child, flags);
309 sc->sc_child = NULL;
310 DPRINTFN(1, ("%s: child detach complete\n", __func__));
311 }
312
313 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
314 USBDEV(sc->sc_dev));
315
316 DPRINTFN(1, ("%s: driver detached\n", __func__));
317
318 return (rv);
319 }
320
321 int
322 ubt_activate(device_ptr_t self, enum devact act)
323 {
324 struct ubt_softc *sc = (struct ubt_softc *)self;
325 int error = 0;
326
327 switch (act) {
328 case DVACT_ACTIVATE:
329 return (EOPNOTSUPP);
330 break;
331
332 case DVACT_DEACTIVATE:
333 sc->sc_dying = 1;
334 if (sc->sc_child != NULL)
335 error = config_deactivate(sc->sc_child);
336 break;
337 }
338 return (error);
339 }
340
341 static int
342 ubt_open(void *h, int flag, int mode, usb_proc_ptr p)
343 {
344 struct ubt_softc *sc = h;
345 int error;
346 usbd_status err;
347
348 DPRINTFN(0, ("%s: sc=%p\n", __func__, sc));
349
350 sc->sc_evt_buf = malloc(BTHCI_EVENT_MAX_LEN, M_USBDEV, M_NOWAIT);
351 if (sc->sc_evt_buf == NULL) {
352 error = ENOMEM;
353 goto bad0;
354 }
355
356 err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_evt_addr,
357 USBD_SHORT_XFER_OK, &sc->sc_evt_pipe,
358 sc, sc->sc_evt_buf, BTHCI_EVENT_MAX_LEN,
359 ubt_event_cb, UBT_EVENT_EP_INTERVAL);
360 if (err != USBD_NORMAL_COMPLETION) {
361 error = EIO;
362 goto bad1;
363 }
364
365 err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_aclrd_addr,
366 0, &sc->sc_aclrd_pipe);
367 if (err != USBD_NORMAL_COMPLETION) {
368 error = EIO;
369 goto bad2;
370 }
371
372 err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_aclwr_addr,
373 0, &sc->sc_aclwr_pipe);
374 if (err != USBD_NORMAL_COMPLETION) {
375 error = EIO;
376 goto bad3;
377 }
378
379 sc->sc_ctl_xfer = usbd_alloc_xfer(sc->sc_udev);
380 if (sc->sc_ctl_xfer == NULL) {
381 error = ENOMEM;
382 goto bad4;
383 }
384 sc->sc_aclrd_xfer = usbd_alloc_xfer(sc->sc_udev);
385 if (sc->sc_aclrd_xfer == NULL) {
386 error = ENOMEM;
387 goto bad5;
388 }
389 sc->sc_aclwr_xfer = usbd_alloc_xfer(sc->sc_udev);
390 if (sc->sc_aclwr_xfer == NULL) {
391 error = ENOMEM;
392 goto bad6;
393 }
394
395 /* Buffers */
396 sc->sc_ctl_buf = usbd_alloc_buffer(sc->sc_ctl_xfer,
397 BTHCI_COMMAND_MAX_LEN);
398 if (sc->sc_ctl_buf == NULL) {
399 error = ENOMEM;
400 goto bad7;
401 }
402 sc->sc_aclrd_buf = usbd_alloc_buffer(sc->sc_aclrd_xfer,
403 BTHCI_ACL_DATA_MAX_LEN);
404 if (sc->sc_aclrd_buf == NULL) {
405 error = ENOMEM;
406 goto bad7;
407 }
408 sc->sc_aclwr_buf = usbd_alloc_buffer(sc->sc_aclwr_xfer,
409 BTHCI_ACL_DATA_MAX_LEN);
410 if (sc->sc_aclwr_buf == NULL) {
411 error = ENOMEM;
412 goto bad7;
413 }
414
415 /* Start reading */
416 ubt_aclrd_request(sc);
417
418 return 0;
419
420 bad7:
421 usbd_free_xfer(sc->sc_aclwr_xfer);
422 sc->sc_aclwr_xfer = NULL;
423 bad6:
424 usbd_free_xfer(sc->sc_aclrd_xfer);
425 sc->sc_aclrd_xfer = NULL;
426 bad5:
427 usbd_free_xfer(sc->sc_ctl_xfer);
428 sc->sc_ctl_xfer = NULL;
429 bad4:
430 usbd_close_pipe(sc->sc_aclwr_pipe);
431 sc->sc_aclwr_pipe = NULL;
432 bad3:
433 usbd_close_pipe(sc->sc_aclrd_pipe);
434 sc->sc_aclrd_pipe = NULL;
435 bad2:
436 usbd_close_pipe(sc->sc_evt_pipe);
437 sc->sc_evt_pipe = NULL;
438 bad1:
439 free(sc->sc_evt_buf, M_USBDEV);
440 sc->sc_evt_buf = NULL;
441 bad0:
442 return error;
443 }
444
445 static int
446 ubt_close(void *h, int flag, int mode, usb_proc_ptr p)
447 {
448 struct ubt_softc *sc = h;
449
450 DPRINTFN(0, ("%s: sc=%p\n", __func__, sc));
451
452 ubt_abortdealloc(sc);
453
454 return 0;
455 }
456
457 static int
458 ubt_control(void *h, u_int8_t *data, size_t len)
459 {
460 struct ubt_softc *sc = h;
461 usb_device_request_t req;
462 usbd_status status;
463
464 DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
465
466 if (sc->sc_dying)
467 return EIO;
468
469 if (len < BTHCI_COMMAND_MIN_LEN || len > BTHCI_COMMAND_MAX_LEN)
470 return EINVAL;
471
472 sc->sc_refcnt++;
473
474 memset(&req, 0, sizeof(req));
475 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
476 USETW(req.wLength, len);
477
478 memcpy(sc->sc_ctl_buf, data, len);
479
480 usbd_setup_default_xfer(sc->sc_ctl_xfer,
481 sc->sc_udev,
482 sc,
483 USBD_DEFAULT_TIMEOUT,
484 &req, sc->sc_ctl_buf, len,
485 USBD_SYNCHRONOUS | USBD_NO_COPY, NULL);
486
487 status = usbd_transfer(sc->sc_ctl_xfer);
488
489 if (--sc->sc_refcnt < 0)
490 usb_detach_wakeup(USBDEV(sc->sc_dev));
491
492 if (status != USBD_NORMAL_COMPLETION)
493 return EIO;
494
495 return 0;
496 }
497
498 static int
499 ubt_sendacldata(void *h, u_int8_t *data, size_t len)
500 {
501 struct ubt_softc *sc = h;
502 usbd_status status;
503
504 DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
505
506 if (sc->sc_dying)
507 return EIO;
508
509 if (len < BTHCI_ACL_DATA_MIN_LEN || len > BTHCI_ACL_DATA_MAX_LEN)
510 return EINVAL;
511
512 sc->sc_refcnt++;
513
514 memcpy(sc->sc_aclwr_buf, data, len);
515
516 usbd_setup_xfer(sc->sc_aclwr_xfer,
517 sc->sc_aclwr_pipe,
518 (usbd_private_handle)sc,
519 sc->sc_aclwr_buf, len,
520 USBD_SYNCHRONOUS | USBD_NO_COPY,
521 USBD_DEFAULT_TIMEOUT,
522 NULL);
523
524 status = usbd_transfer(sc->sc_aclwr_xfer);
525
526 if (--sc->sc_refcnt < 0)
527 usb_detach_wakeup(USBDEV(sc->sc_dev));
528
529 if (status != USBD_NORMAL_COMPLETION)
530 return EIO;
531
532 return 0;
533 }
534
535 static int
536 ubt_sendscodata(void *h, u_int8_t *data, size_t len)
537 {
538 struct ubt_softc *sc = h;
539
540 DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
541
542 if (sc->sc_dying)
543 return EIO;
544
545 return ENXIO;
546 }
547
548 static void
549 ubt_event_cb(usbd_xfer_handle xfer, usbd_private_handle h, usbd_status status)
550 {
551 struct ubt_softc *sc = h;
552 void *buf;
553 u_int32_t size;
554
555 DPRINTFN(1,("%s: sc=%p status=%s\n", __func__, sc,
556 usbd_errstr(status)));
557
558 if (status != USBD_NORMAL_COMPLETION || sc->sc_dying ||
559 sc->sc_child == NULL)
560 return;
561
562 usbd_get_xfer_status(xfer, NULL, &buf, &size, NULL);
563
564 sc->sc_cb->bt_recveventdata(sc->sc_child, buf, (size_t)size);
565 }
566
567 static void
568 ubt_aclrd_request(struct ubt_softc *sc)
569 {
570 usbd_status status;
571 int s;
572
573 DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
574
575 if (sc->sc_dying)
576 return;
577
578 s = splusb();
579 if (sc->sc_aclrd_running) {
580 splx(s);
581 return;
582 }
583 sc->sc_aclrd_running = 1;
584 splx(s);
585
586 usbd_setup_xfer(sc->sc_aclrd_xfer, sc->sc_aclrd_pipe,
587 sc, sc->sc_aclrd_buf, BTHCI_ACL_DATA_MAX_LEN,
588 USBD_SHORT_XFER_OK | USBD_NO_COPY,
589 USBD_NO_TIMEOUT, ubt_aclrd_cb);
590
591 status = usbd_transfer(sc->sc_aclrd_xfer);
592 if (status == USBD_IN_PROGRESS || USBD_CANCELLED)
593 return;
594
595 DPRINTFN(1,("%s: read request failed: %s\n", __func__,
596 usbd_errstr(status)));
597
598 sc->sc_aclrd_running = 0;
599 sc->sc_blocked |= BT_CBBLOCK_ACL_DATA;
600 }
601
602 static void
603 ubt_aclrd_cb(usbd_xfer_handle xfer, usbd_private_handle h, usbd_status status)
604 {
605 struct ubt_softc *sc = h;
606 void *buf;
607 u_int32_t size;
608
609 DPRINTFN(1,("%s: sc=%p status=%s\n", __func__, sc,
610 usbd_errstr(status)));
611
612 sc->sc_aclrd_running = 0;
613
614 if (status != USBD_NORMAL_COMPLETION || sc->sc_dying ||
615 sc->sc_child == NULL)
616 return;
617
618 usbd_get_xfer_status(xfer, NULL, &buf, &size, NULL);
619
620 sc->sc_cb->bt_recvacldata(sc->sc_child, buf, (size_t)size);
621
622 /* Re-issue the request if not blocked */
623 if (!sc->sc_dying && !(sc->sc_blocked & BT_CBBLOCK_ACL_DATA))
624 ubt_aclrd_request(sc);
625 }
626
627 static unsigned int
628 ubt_blockcb(void *h, unsigned int cbblocks)
629 {
630 struct ubt_softc *sc = h;
631
632 sc->sc_blocked |= (cbblocks & BT_CBBLOCK_ACL_DATA);
633
634 return sc->sc_blocked;
635 }
636
637 static unsigned int
638 ubt_unblockcb(void *h, unsigned int cbblocks)
639 {
640 struct ubt_softc *sc = h;
641 unsigned int oblocks, changes;
642
643 oblocks = sc->sc_blocked;
644 sc->sc_blocked = oblocks & ~cbblocks;
645
646 changes = oblocks & cbblocks;
647
648 if (changes & BT_CBBLOCK_ACL_DATA)
649 /* Re-issue the request if action un-blocked reads */
650 ubt_aclrd_request(sc);
651
652 return sc->sc_blocked;
653 }
654
655 static int
656 ubt_splraise(void)
657 {
658 return splusb();
659 }
660