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