1b06ebda0SMatthew Dillon /*
2b06ebda0SMatthew Dillon * ubtbcmfw.c
3b06ebda0SMatthew Dillon */
4b06ebda0SMatthew Dillon
5b06ebda0SMatthew Dillon /*-
6d2902f79SSascha Wildner * Copyright (c) 2003-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7b06ebda0SMatthew Dillon * All rights reserved.
8b06ebda0SMatthew Dillon *
9b06ebda0SMatthew Dillon * Redistribution and use in source and binary forms, with or without
10b06ebda0SMatthew Dillon * modification, are permitted provided that the following conditions
11b06ebda0SMatthew Dillon * are met:
12b06ebda0SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
13b06ebda0SMatthew Dillon * notice, this list of conditions and the following disclaimer.
14b06ebda0SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
15b06ebda0SMatthew Dillon * notice, this list of conditions and the following disclaimer in the
16b06ebda0SMatthew Dillon * documentation and/or other materials provided with the distribution.
17b06ebda0SMatthew Dillon *
18b06ebda0SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19b06ebda0SMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b06ebda0SMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21b06ebda0SMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b06ebda0SMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b06ebda0SMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24b06ebda0SMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25b06ebda0SMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b06ebda0SMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b06ebda0SMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b06ebda0SMatthew Dillon * SUCH DAMAGE.
29b06ebda0SMatthew Dillon *
30b06ebda0SMatthew Dillon * $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $
31d2902f79SSascha Wildner * $FreeBSD: head/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c 223486 2011-06-24 02:30:02Z hselasky $
32b06ebda0SMatthew Dillon */
33b06ebda0SMatthew Dillon
34d2902f79SSascha Wildner #include <sys/stdint.h>
35b06ebda0SMatthew Dillon #include <sys/param.h>
36d2902f79SSascha Wildner #include <sys/queue.h>
37d2902f79SSascha Wildner #include <sys/types.h>
38b06ebda0SMatthew Dillon #include <sys/systm.h>
39b06ebda0SMatthew Dillon #include <sys/kernel.h>
40d2902f79SSascha Wildner #include <sys/bus.h>
41b06ebda0SMatthew Dillon #include <sys/module.h>
42d2902f79SSascha Wildner #include <sys/lock.h>
43d2902f79SSascha Wildner #include <sys/condvar.h>
44b06ebda0SMatthew Dillon #include <sys/sysctl.h>
45d2902f79SSascha Wildner #include <sys/unistd.h>
46d2902f79SSascha Wildner #include <sys/callout.h>
47d2902f79SSascha Wildner #include <sys/malloc.h>
48*2b3f93eaSMatthew Dillon #include <sys/caps.h>
49d2902f79SSascha Wildner #include <sys/conf.h>
50d2902f79SSascha Wildner #include <sys/fcntl.h>
51b06ebda0SMatthew Dillon
52b06ebda0SMatthew Dillon #include "usbdevs.h"
53d2902f79SSascha Wildner #include <bus/u4b/usb.h>
54d2902f79SSascha Wildner #include <bus/u4b/usbdi.h>
55d2902f79SSascha Wildner #include <bus/u4b/usb_ioctl.h>
56d2902f79SSascha Wildner
57d2902f79SSascha Wildner #define USB_DEBUG_VAR usb_debug
58d2902f79SSascha Wildner #include <bus/u4b/usb_debug.h>
59d2902f79SSascha Wildner #include <bus/u4b/usb_dev.h>
60b06ebda0SMatthew Dillon
61b06ebda0SMatthew Dillon /*
62b06ebda0SMatthew Dillon * Download firmware to BCM2033.
63b06ebda0SMatthew Dillon */
64b06ebda0SMatthew Dillon
65b06ebda0SMatthew Dillon #define UBTBCMFW_CONFIG_NO 1 /* Config number */
66b06ebda0SMatthew Dillon #define UBTBCMFW_IFACE_IDX 0 /* Control interface */
67b06ebda0SMatthew Dillon
68d2902f79SSascha Wildner #define UBTBCMFW_BSIZE 1024
69d2902f79SSascha Wildner #define UBTBCMFW_IFQ_MAXLEN 2
70d2902f79SSascha Wildner
71d2902f79SSascha Wildner enum {
72d2902f79SSascha Wildner UBTBCMFW_BULK_DT_WR = 0,
73d2902f79SSascha Wildner UBTBCMFW_INTR_DT_RD,
74d2902f79SSascha Wildner UBTBCMFW_N_TRANSFER,
75b06ebda0SMatthew Dillon };
76b06ebda0SMatthew Dillon
77d2902f79SSascha Wildner struct ubtbcmfw_softc {
78d2902f79SSascha Wildner struct usb_device *sc_udev;
79d2902f79SSascha Wildner struct lock sc_lock;
80d2902f79SSascha Wildner struct usb_xfer *sc_xfer[UBTBCMFW_N_TRANSFER];
81d2902f79SSascha Wildner struct usb_fifo_sc sc_fifo;
82d2902f79SSascha Wildner };
83b06ebda0SMatthew Dillon
84b06ebda0SMatthew Dillon /*
85d2902f79SSascha Wildner * Prototypes
86b06ebda0SMatthew Dillon */
87b06ebda0SMatthew Dillon
88d2902f79SSascha Wildner static device_probe_t ubtbcmfw_probe;
89d2902f79SSascha Wildner static device_attach_t ubtbcmfw_attach;
90d2902f79SSascha Wildner static device_detach_t ubtbcmfw_detach;
91b06ebda0SMatthew Dillon
92d2902f79SSascha Wildner static usb_callback_t ubtbcmfw_write_callback;
93d2902f79SSascha Wildner static usb_callback_t ubtbcmfw_read_callback;
94b06ebda0SMatthew Dillon
95d2902f79SSascha Wildner static usb_fifo_close_t ubtbcmfw_close;
96d2902f79SSascha Wildner static usb_fifo_cmd_t ubtbcmfw_start_read;
97d2902f79SSascha Wildner static usb_fifo_cmd_t ubtbcmfw_start_write;
98d2902f79SSascha Wildner static usb_fifo_cmd_t ubtbcmfw_stop_read;
99d2902f79SSascha Wildner static usb_fifo_cmd_t ubtbcmfw_stop_write;
100d2902f79SSascha Wildner static usb_fifo_ioctl_t ubtbcmfw_ioctl;
101d2902f79SSascha Wildner static usb_fifo_open_t ubtbcmfw_open;
102d2902f79SSascha Wildner
103d2902f79SSascha Wildner static struct usb_fifo_methods ubtbcmfw_fifo_methods =
104d2902f79SSascha Wildner {
105d2902f79SSascha Wildner .f_close = &ubtbcmfw_close,
106d2902f79SSascha Wildner .f_ioctl = &ubtbcmfw_ioctl,
107d2902f79SSascha Wildner .f_open = &ubtbcmfw_open,
108d2902f79SSascha Wildner .f_start_read = &ubtbcmfw_start_read,
109d2902f79SSascha Wildner .f_start_write = &ubtbcmfw_start_write,
110d2902f79SSascha Wildner .f_stop_read = &ubtbcmfw_stop_read,
111d2902f79SSascha Wildner .f_stop_write = &ubtbcmfw_stop_write,
112d2902f79SSascha Wildner .basename[0] = "ubtbcmfw",
113d2902f79SSascha Wildner .basename[1] = "ubtbcmfw",
114d2902f79SSascha Wildner .basename[2] = "ubtbcmfw",
115d2902f79SSascha Wildner .postfix[0] = "",
116d2902f79SSascha Wildner .postfix[1] = ".1",
117d2902f79SSascha Wildner .postfix[2] = ".2",
118d2902f79SSascha Wildner };
119d2902f79SSascha Wildner
120d2902f79SSascha Wildner /*
121d2902f79SSascha Wildner * Device's config structure
122d2902f79SSascha Wildner */
123d2902f79SSascha Wildner
124d2902f79SSascha Wildner static const struct usb_config ubtbcmfw_config[UBTBCMFW_N_TRANSFER] =
125d2902f79SSascha Wildner {
126d2902f79SSascha Wildner [UBTBCMFW_BULK_DT_WR] = {
127d2902f79SSascha Wildner .type = UE_BULK,
128d2902f79SSascha Wildner .endpoint = 0x02, /* fixed */
129d2902f79SSascha Wildner .direction = UE_DIR_OUT,
130d2902f79SSascha Wildner .if_index = UBTBCMFW_IFACE_IDX,
131d2902f79SSascha Wildner .bufsize = UBTBCMFW_BSIZE,
132d2902f79SSascha Wildner .flags = { .pipe_bof = 1, .force_short_xfer = 1,
133d2902f79SSascha Wildner .proxy_buffer = 1, },
134d2902f79SSascha Wildner .callback = &ubtbcmfw_write_callback,
135d2902f79SSascha Wildner },
136d2902f79SSascha Wildner
137d2902f79SSascha Wildner [UBTBCMFW_INTR_DT_RD] = {
138d2902f79SSascha Wildner .type = UE_INTERRUPT,
139d2902f79SSascha Wildner .endpoint = 0x01, /* fixed */
140d2902f79SSascha Wildner .direction = UE_DIR_IN,
141d2902f79SSascha Wildner .if_index = UBTBCMFW_IFACE_IDX,
142d2902f79SSascha Wildner .bufsize = UBTBCMFW_BSIZE,
143d2902f79SSascha Wildner .flags = { .pipe_bof = 1, .short_xfer_ok = 1,
144d2902f79SSascha Wildner .proxy_buffer = 1, },
145d2902f79SSascha Wildner .callback = &ubtbcmfw_read_callback,
146d2902f79SSascha Wildner },
147b06ebda0SMatthew Dillon };
148b06ebda0SMatthew Dillon
149b06ebda0SMatthew Dillon /*
150b06ebda0SMatthew Dillon * Module
151b06ebda0SMatthew Dillon */
152b06ebda0SMatthew Dillon
153d2902f79SSascha Wildner static devclass_t ubtbcmfw_devclass;
154b06ebda0SMatthew Dillon
155d2902f79SSascha Wildner static device_method_t ubtbcmfw_methods[] =
156d2902f79SSascha Wildner {
157d2902f79SSascha Wildner DEVMETHOD(device_probe, ubtbcmfw_probe),
158b06ebda0SMatthew Dillon DEVMETHOD(device_attach, ubtbcmfw_attach),
159b06ebda0SMatthew Dillon DEVMETHOD(device_detach, ubtbcmfw_detach),
160b06ebda0SMatthew Dillon
161d3c9c58eSSascha Wildner DEVMETHOD_END
162b06ebda0SMatthew Dillon };
163b06ebda0SMatthew Dillon
164d2902f79SSascha Wildner static driver_t ubtbcmfw_driver =
165d2902f79SSascha Wildner {
166d2902f79SSascha Wildner .name = "ubtbcmfw",
167d2902f79SSascha Wildner .methods = ubtbcmfw_methods,
168d2902f79SSascha Wildner .size = sizeof(struct ubtbcmfw_softc),
169b06ebda0SMatthew Dillon };
170b06ebda0SMatthew Dillon
1713a25be87SSascha Wildner DRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, NULL, NULL);
172b06ebda0SMatthew Dillon MODULE_DEPEND(ubtbcmfw, usb, 1, 1, 1);
173b06ebda0SMatthew Dillon
174b06ebda0SMatthew Dillon /*
175b06ebda0SMatthew Dillon * Probe for a USB Bluetooth device
176b06ebda0SMatthew Dillon */
177b06ebda0SMatthew Dillon
178b06ebda0SMatthew Dillon static int
ubtbcmfw_probe(device_t dev)179d2902f79SSascha Wildner ubtbcmfw_probe(device_t dev)
180b06ebda0SMatthew Dillon {
181d2902f79SSascha Wildner static const STRUCT_USB_HOST_ID devs[] = {
182d2902f79SSascha Wildner /* Broadcom BCM2033 devices only */
183d2902f79SSascha Wildner { USB_VPI(USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033, 0) },
184d2902f79SSascha Wildner };
185b06ebda0SMatthew Dillon
186d2902f79SSascha Wildner struct usb_attach_arg *uaa = device_get_ivars(dev);
187b06ebda0SMatthew Dillon
188d2902f79SSascha Wildner if (uaa->usb_mode != USB_MODE_HOST)
189d2902f79SSascha Wildner return (ENXIO);
190b06ebda0SMatthew Dillon
191d2902f79SSascha Wildner if (uaa->info.bIfaceIndex != 0)
192d2902f79SSascha Wildner return (ENXIO);
193d2902f79SSascha Wildner
194d2902f79SSascha Wildner return (usbd_lookup_id_by_uaa(devs, sizeof(devs), uaa));
195d2902f79SSascha Wildner } /* ubtbcmfw_probe */
196b06ebda0SMatthew Dillon
197b06ebda0SMatthew Dillon /*
198b06ebda0SMatthew Dillon * Attach the device
199b06ebda0SMatthew Dillon */
200b06ebda0SMatthew Dillon
201b06ebda0SMatthew Dillon static int
ubtbcmfw_attach(device_t dev)202d2902f79SSascha Wildner ubtbcmfw_attach(device_t dev)
203b06ebda0SMatthew Dillon {
204d2902f79SSascha Wildner struct usb_attach_arg *uaa = device_get_ivars(dev);
205d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = device_get_softc(dev);
206d2902f79SSascha Wildner uint8_t iface_index;
207d2902f79SSascha Wildner int error;
208b06ebda0SMatthew Dillon
209b06ebda0SMatthew Dillon sc->sc_udev = uaa->device;
210b06ebda0SMatthew Dillon
211d2902f79SSascha Wildner device_set_usb_desc(dev);
212b06ebda0SMatthew Dillon
213d2902f79SSascha Wildner lockinit(&sc->sc_lock, "ubtbcmfw lock", 0, LK_CANRECURSE);
214d2902f79SSascha Wildner
215d2902f79SSascha Wildner iface_index = UBTBCMFW_IFACE_IDX;
216d2902f79SSascha Wildner error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
217d2902f79SSascha Wildner ubtbcmfw_config, UBTBCMFW_N_TRANSFER,
218d2902f79SSascha Wildner sc, &sc->sc_lock);
219d2902f79SSascha Wildner if (error != 0) {
220d2902f79SSascha Wildner device_printf(dev, "allocating USB transfers failed. %s\n",
221d2902f79SSascha Wildner usbd_errstr(error));
222d2902f79SSascha Wildner goto detach;
223b06ebda0SMatthew Dillon }
224b06ebda0SMatthew Dillon
225d2902f79SSascha Wildner error = usb_fifo_attach(uaa->device, sc, &sc->sc_lock,
226d2902f79SSascha Wildner &ubtbcmfw_fifo_methods, &sc->sc_fifo,
227d2902f79SSascha Wildner device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex,
228d2902f79SSascha Wildner UID_ROOT, GID_OPERATOR, 0644);
229d2902f79SSascha Wildner if (error != 0) {
230d2902f79SSascha Wildner device_printf(dev, "could not attach fifo. %s\n",
231d2902f79SSascha Wildner usbd_errstr(error));
232d2902f79SSascha Wildner goto detach;
233b06ebda0SMatthew Dillon }
234b06ebda0SMatthew Dillon
235d2902f79SSascha Wildner return (0); /* success */
236b06ebda0SMatthew Dillon
237d2902f79SSascha Wildner detach:
238d2902f79SSascha Wildner ubtbcmfw_detach(dev);
239b06ebda0SMatthew Dillon
240d2902f79SSascha Wildner return (ENXIO); /* failure */
241d2902f79SSascha Wildner } /* ubtbcmfw_attach */
242b06ebda0SMatthew Dillon
243b06ebda0SMatthew Dillon /*
244b06ebda0SMatthew Dillon * Detach the device
245b06ebda0SMatthew Dillon */
246b06ebda0SMatthew Dillon
247b06ebda0SMatthew Dillon static int
ubtbcmfw_detach(device_t dev)248d2902f79SSascha Wildner ubtbcmfw_detach(device_t dev)
249b06ebda0SMatthew Dillon {
250d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = device_get_softc(dev);
251b06ebda0SMatthew Dillon
252d2902f79SSascha Wildner usb_fifo_detach(&sc->sc_fifo);
253b06ebda0SMatthew Dillon
254d2902f79SSascha Wildner usbd_transfer_unsetup(sc->sc_xfer, UBTBCMFW_N_TRANSFER);
255b06ebda0SMatthew Dillon
256d2902f79SSascha Wildner lockuninit(&sc->sc_lock);
257b06ebda0SMatthew Dillon
258b06ebda0SMatthew Dillon return (0);
259d2902f79SSascha Wildner } /* ubtbcmfw_detach */
260b06ebda0SMatthew Dillon
261b06ebda0SMatthew Dillon /*
262d2902f79SSascha Wildner * USB write callback
263d2902f79SSascha Wildner */
264d2902f79SSascha Wildner
265d2902f79SSascha Wildner static void
ubtbcmfw_write_callback(struct usb_xfer * xfer,usb_error_t error)266d2902f79SSascha Wildner ubtbcmfw_write_callback(struct usb_xfer *xfer, usb_error_t error)
267d2902f79SSascha Wildner {
268d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usbd_xfer_softc(xfer);
269d2902f79SSascha Wildner struct usb_fifo *f = sc->sc_fifo.fp[USB_FIFO_TX];
270d2902f79SSascha Wildner struct usb_page_cache *pc;
271d2902f79SSascha Wildner uint32_t actlen;
272d2902f79SSascha Wildner
273d2902f79SSascha Wildner switch (USB_GET_STATE(xfer)) {
274d2902f79SSascha Wildner case USB_ST_SETUP:
275d2902f79SSascha Wildner case USB_ST_TRANSFERRED:
276d2902f79SSascha Wildner setup_next:
277d2902f79SSascha Wildner pc = usbd_xfer_get_frame(xfer, 0);
278d2902f79SSascha Wildner if (usb_fifo_get_data(f, pc, 0, usbd_xfer_max_len(xfer),
279d2902f79SSascha Wildner &actlen, 0)) {
280d2902f79SSascha Wildner usbd_xfer_set_frame_len(xfer, 0, actlen);
281d2902f79SSascha Wildner usbd_transfer_submit(xfer);
282d2902f79SSascha Wildner }
283d2902f79SSascha Wildner break;
284d2902f79SSascha Wildner
285d2902f79SSascha Wildner default: /* Error */
286d2902f79SSascha Wildner if (error != USB_ERR_CANCELLED) {
287d2902f79SSascha Wildner /* try to clear stall first */
288d2902f79SSascha Wildner usbd_xfer_set_stall(xfer);
289d2902f79SSascha Wildner goto setup_next;
290d2902f79SSascha Wildner }
291d2902f79SSascha Wildner break;
292d2902f79SSascha Wildner }
293d2902f79SSascha Wildner } /* ubtbcmfw_write_callback */
294d2902f79SSascha Wildner
295d2902f79SSascha Wildner /*
296d2902f79SSascha Wildner * USB read callback
297d2902f79SSascha Wildner */
298d2902f79SSascha Wildner
299d2902f79SSascha Wildner static void
ubtbcmfw_read_callback(struct usb_xfer * xfer,usb_error_t error)300d2902f79SSascha Wildner ubtbcmfw_read_callback(struct usb_xfer *xfer, usb_error_t error)
301d2902f79SSascha Wildner {
302d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usbd_xfer_softc(xfer);
303d2902f79SSascha Wildner struct usb_fifo *fifo = sc->sc_fifo.fp[USB_FIFO_RX];
304d2902f79SSascha Wildner struct usb_page_cache *pc;
305d2902f79SSascha Wildner int actlen;
306d2902f79SSascha Wildner
307d2902f79SSascha Wildner usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
308d2902f79SSascha Wildner
309d2902f79SSascha Wildner switch (USB_GET_STATE(xfer)) {
310d2902f79SSascha Wildner case USB_ST_TRANSFERRED:
311d2902f79SSascha Wildner pc = usbd_xfer_get_frame(xfer, 0);
312d2902f79SSascha Wildner usb_fifo_put_data(fifo, pc, 0, actlen, 1);
313d2902f79SSascha Wildner /* FALLTHROUGH */
314d2902f79SSascha Wildner
315d2902f79SSascha Wildner case USB_ST_SETUP:
316d2902f79SSascha Wildner setup_next:
317d2902f79SSascha Wildner if (usb_fifo_put_bytes_max(fifo) > 0) {
318d2902f79SSascha Wildner usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
319d2902f79SSascha Wildner usbd_transfer_submit(xfer);
320d2902f79SSascha Wildner }
321d2902f79SSascha Wildner break;
322d2902f79SSascha Wildner
323d2902f79SSascha Wildner default: /* Error */
324d2902f79SSascha Wildner if (error != USB_ERR_CANCELLED) {
325d2902f79SSascha Wildner /* try to clear stall first */
326d2902f79SSascha Wildner usbd_xfer_set_stall(xfer);
327d2902f79SSascha Wildner goto setup_next;
328d2902f79SSascha Wildner }
329d2902f79SSascha Wildner break;
330d2902f79SSascha Wildner }
331d2902f79SSascha Wildner } /* ubtbcmfw_read_callback */
332d2902f79SSascha Wildner
333d2902f79SSascha Wildner /*
334d2902f79SSascha Wildner * Called when we about to start read()ing from the device
335d2902f79SSascha Wildner */
336d2902f79SSascha Wildner
337d2902f79SSascha Wildner static void
ubtbcmfw_start_read(struct usb_fifo * fifo)338d2902f79SSascha Wildner ubtbcmfw_start_read(struct usb_fifo *fifo)
339d2902f79SSascha Wildner {
340d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
341d2902f79SSascha Wildner
342d2902f79SSascha Wildner usbd_transfer_start(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
343d2902f79SSascha Wildner } /* ubtbcmfw_start_read */
344d2902f79SSascha Wildner
345d2902f79SSascha Wildner /*
346d2902f79SSascha Wildner * Called when we about to stop reading (i.e. closing fifo)
347d2902f79SSascha Wildner */
348d2902f79SSascha Wildner
349d2902f79SSascha Wildner static void
ubtbcmfw_stop_read(struct usb_fifo * fifo)350d2902f79SSascha Wildner ubtbcmfw_stop_read(struct usb_fifo *fifo)
351d2902f79SSascha Wildner {
352d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
353d2902f79SSascha Wildner
354d2902f79SSascha Wildner usbd_transfer_stop(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
355d2902f79SSascha Wildner } /* ubtbcmfw_stop_read */
356d2902f79SSascha Wildner
357d2902f79SSascha Wildner /*
358d2902f79SSascha Wildner * Called when we about to start write()ing to the device, poll()ing
359d2902f79SSascha Wildner * for write or flushing fifo
360d2902f79SSascha Wildner */
361d2902f79SSascha Wildner
362d2902f79SSascha Wildner static void
ubtbcmfw_start_write(struct usb_fifo * fifo)363d2902f79SSascha Wildner ubtbcmfw_start_write(struct usb_fifo *fifo)
364d2902f79SSascha Wildner {
365d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
366d2902f79SSascha Wildner
367d2902f79SSascha Wildner usbd_transfer_start(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
368d2902f79SSascha Wildner } /* ubtbcmfw_start_write */
369d2902f79SSascha Wildner
370d2902f79SSascha Wildner /*
371d2902f79SSascha Wildner * Called when we about to stop writing (i.e. closing fifo)
372d2902f79SSascha Wildner */
373d2902f79SSascha Wildner
374d2902f79SSascha Wildner static void
ubtbcmfw_stop_write(struct usb_fifo * fifo)375d2902f79SSascha Wildner ubtbcmfw_stop_write(struct usb_fifo *fifo)
376d2902f79SSascha Wildner {
377d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
378d2902f79SSascha Wildner
379d2902f79SSascha Wildner usbd_transfer_stop(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
380d2902f79SSascha Wildner } /* ubtbcmfw_stop_write */
381d2902f79SSascha Wildner
382d2902f79SSascha Wildner /*
383d2902f79SSascha Wildner * Called when fifo is open
384b06ebda0SMatthew Dillon */
385b06ebda0SMatthew Dillon
386b06ebda0SMatthew Dillon static int
ubtbcmfw_open(struct usb_fifo * fifo,int fflags)387d2902f79SSascha Wildner ubtbcmfw_open(struct usb_fifo *fifo, int fflags)
388b06ebda0SMatthew Dillon {
389d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
390d2902f79SSascha Wildner struct usb_xfer *xfer;
391b06ebda0SMatthew Dillon
392b06ebda0SMatthew Dillon /*
393d2902f79SSascha Wildner * f_open fifo method can only be called with either FREAD
394d2902f79SSascha Wildner * or FWRITE flag set at one time.
395b06ebda0SMatthew Dillon */
396b06ebda0SMatthew Dillon
397d2902f79SSascha Wildner if (fflags & FREAD)
398d2902f79SSascha Wildner xfer = sc->sc_xfer[UBTBCMFW_INTR_DT_RD];
399d2902f79SSascha Wildner else if (fflags & FWRITE)
400d2902f79SSascha Wildner xfer = sc->sc_xfer[UBTBCMFW_BULK_DT_WR];
401d2902f79SSascha Wildner else
402d2902f79SSascha Wildner return (EINVAL); /* should not happen */
403b06ebda0SMatthew Dillon
404d2902f79SSascha Wildner if (usb_fifo_alloc_buffer(fifo, usbd_xfer_max_len(xfer),
405d2902f79SSascha Wildner UBTBCMFW_IFQ_MAXLEN) != 0)
406d2902f79SSascha Wildner return (ENOMEM);
407b06ebda0SMatthew Dillon
408b06ebda0SMatthew Dillon return (0);
409d2902f79SSascha Wildner } /* ubtbcmfw_open */
410b06ebda0SMatthew Dillon
411b06ebda0SMatthew Dillon /*
412d2902f79SSascha Wildner * Called when fifo is closed
413d2902f79SSascha Wildner */
414d2902f79SSascha Wildner
415d2902f79SSascha Wildner static void
ubtbcmfw_close(struct usb_fifo * fifo,int fflags)416d2902f79SSascha Wildner ubtbcmfw_close(struct usb_fifo *fifo, int fflags)
417d2902f79SSascha Wildner {
418d2902f79SSascha Wildner if (fflags & (FREAD | FWRITE))
419d2902f79SSascha Wildner usb_fifo_free_buffer(fifo);
420d2902f79SSascha Wildner } /* ubtbcmfw_close */
421d2902f79SSascha Wildner
422d2902f79SSascha Wildner /*
423d2902f79SSascha Wildner * Process ioctl() on USB device
424b06ebda0SMatthew Dillon */
425b06ebda0SMatthew Dillon
426b06ebda0SMatthew Dillon static int
ubtbcmfw_ioctl(struct usb_fifo * fifo,u_long cmd,void * data,int fflags)427d2902f79SSascha Wildner ubtbcmfw_ioctl(struct usb_fifo *fifo, u_long cmd, void *data,
428d2902f79SSascha Wildner int fflags)
429b06ebda0SMatthew Dillon {
430d2902f79SSascha Wildner struct ubtbcmfw_softc *sc = usb_fifo_softc(fifo);
431b06ebda0SMatthew Dillon int error = 0;
432b06ebda0SMatthew Dillon
433b06ebda0SMatthew Dillon switch (cmd) {
434b06ebda0SMatthew Dillon case USB_GET_DEVICE_DESC:
435d2902f79SSascha Wildner memcpy(data, usbd_get_device_descriptor(sc->sc_udev),
436d2902f79SSascha Wildner sizeof(struct usb_device_descriptor));
437b06ebda0SMatthew Dillon break;
438b06ebda0SMatthew Dillon
439b06ebda0SMatthew Dillon default:
440b06ebda0SMatthew Dillon error = EINVAL;
441b06ebda0SMatthew Dillon break;
442b06ebda0SMatthew Dillon }
443b06ebda0SMatthew Dillon
444b06ebda0SMatthew Dillon return (error);
445d2902f79SSascha Wildner } /* ubtbcmfw_ioctl */
446