ubtbcmfw.c revision 188746
1184610Salfred/*
2184610Salfred * ubtbcmfw.c
3184610Salfred */
4184610Salfred
5184610Salfred/*-
6187866Semax * Copyright (c) 2003-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7184610Salfred * All rights reserved.
8184610Salfred *
9184610Salfred * Redistribution and use in source and binary forms, with or without
10184610Salfred * modification, are permitted provided that the following conditions
11184610Salfred * are met:
12184610Salfred * 1. Redistributions of source code must retain the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer.
14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
15184610Salfred *    notice, this list of conditions and the following disclaimer in the
16184610Salfred *    documentation and/or other materials provided with the distribution.
17184610Salfred *
18184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28184610Salfred * SUCH DAMAGE.
29184610Salfred *
30184610Salfred * $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $
31184610Salfred * $FreeBSD: head/sys/dev/usb2/bluetooth/ubtbcmfw2.c 188746 2009-02-18 06:33:10Z thompsa $
32184610Salfred */
33184610Salfred
34188746Sthompsa#include "usbdevs.h"
35184610Salfred#include <dev/usb2/include/usb2_standard.h>
36184610Salfred#include <dev/usb2/include/usb2_mfunc.h>
37184610Salfred#include <dev/usb2/include/usb2_error.h>
38184610Salfred#include <dev/usb2/include/usb2_ioctl.h>
39184610Salfred
40184610Salfred#define	USB_DEBUG_VAR usb2_debug
41184610Salfred
42184610Salfred#include <dev/usb2/core/usb2_core.h>
43184610Salfred#include <dev/usb2/core/usb2_debug.h>
44184610Salfred#include <dev/usb2/core/usb2_parse.h>
45184610Salfred#include <dev/usb2/core/usb2_lookup.h>
46184610Salfred#include <dev/usb2/core/usb2_util.h>
47184610Salfred#include <dev/usb2/core/usb2_busdma.h>
48184610Salfred#include <dev/usb2/core/usb2_mbuf.h>
49184610Salfred#include <dev/usb2/core/usb2_dev.h>
50184610Salfred
51184610Salfred/*
52184610Salfred * Download firmware to BCM2033.
53184610Salfred */
54184610Salfred
55184610Salfred#define	UBTBCMFW_CONFIG_NO	1	/* Config number */
56184610Salfred#define	UBTBCMFW_IFACE_IDX	0	/* Control interface */
57184610Salfred
58187866Semax#define	UBTBCMFW_BSIZE		1024
59187866Semax#define	UBTBCMFW_IFQ_MAXLEN	2
60187866Semax
61187259Sthompsaenum {
62187866Semax	UBTBCMFW_BULK_DT_WR = 0,
63187866Semax	UBTBCMFW_INTR_DT_RD,
64187866Semax	UBTBCMFW_N_TRANSFER,
65187259Sthompsa};
66187259Sthompsa
67184610Salfredstruct ubtbcmfw_softc {
68187866Semax	struct usb2_device	*sc_udev;
69187866Semax	struct mtx		sc_mtx;
70187866Semax	struct usb2_xfer	*sc_xfer[UBTBCMFW_N_TRANSFER];
71187866Semax	struct usb2_fifo_sc	sc_fifo;
72184610Salfred};
73184610Salfred
74187866Semax/*
75187866Semax * Prototypes
76187866Semax */
77184610Salfred
78187866Semaxstatic device_probe_t		ubtbcmfw_probe;
79187866Semaxstatic device_attach_t		ubtbcmfw_attach;
80187866Semaxstatic device_detach_t		ubtbcmfw_detach;
81184610Salfred
82187866Semaxstatic usb2_callback_t		ubtbcmfw_write_callback;
83187866Semaxstatic usb2_callback_t		ubtbcmfw_read_callback;
84184610Salfred
85187866Semaxstatic usb2_fifo_close_t	ubtbcmfw_close;
86187866Semaxstatic usb2_fifo_cmd_t		ubtbcmfw_start_read;
87187866Semaxstatic usb2_fifo_cmd_t		ubtbcmfw_start_write;
88187866Semaxstatic usb2_fifo_cmd_t		ubtbcmfw_stop_read;
89187866Semaxstatic usb2_fifo_cmd_t		ubtbcmfw_stop_write;
90187866Semaxstatic usb2_fifo_ioctl_t	ubtbcmfw_ioctl;
91187866Semaxstatic usb2_fifo_open_t		ubtbcmfw_open;
92184610Salfred
93187866Semaxstatic struct usb2_fifo_methods	ubtbcmfw_fifo_methods =
94187866Semax{
95187866Semax	.f_close =		&ubtbcmfw_close,
96187866Semax	.f_ioctl =		&ubtbcmfw_ioctl,
97187866Semax	.f_open =		&ubtbcmfw_open,
98187866Semax	.f_start_read =		&ubtbcmfw_start_read,
99187866Semax	.f_start_write =	&ubtbcmfw_start_write,
100187866Semax	.f_stop_read =		&ubtbcmfw_stop_read,
101187866Semax	.f_stop_write =		&ubtbcmfw_stop_write,
102187866Semax	.basename[0] =		"ubtbcmfw",
103187866Semax	.basename[1] =		"ubtbcmfw",
104187866Semax	.basename[2] =		"ubtbcmfw",
105187866Semax	.postfix[0] =		"",
106187866Semax	.postfix[1] =		".1",
107187866Semax	.postfix[2] =		".2",
108184610Salfred};
109184610Salfred
110187866Semax/*
111187866Semax * Device's config structure
112187866Semax */
113184610Salfred
114187866Semaxstatic const struct usb2_config	ubtbcmfw_config[UBTBCMFW_N_TRANSFER] =
115187866Semax{
116187259Sthompsa	[UBTBCMFW_BULK_DT_WR] = {
117187866Semax		.type =		UE_BULK,
118187866Semax		.endpoint =	0x02,	/* fixed */
119187866Semax		.direction =	UE_DIR_OUT,
120187866Semax		.if_index =	UBTBCMFW_IFACE_IDX,
121187866Semax		.mh.bufsize =	UBTBCMFW_BSIZE,
122187866Semax		.mh.flags =	{ .pipe_bof = 1, .force_short_xfer = 1,
123187866Semax				  .proxy_buffer = 1, },
124187866Semax		.mh.callback =	&ubtbcmfw_write_callback,
125184610Salfred	},
126184610Salfred
127187866Semax	[UBTBCMFW_INTR_DT_RD] = {
128187866Semax		.type =		UE_INTERRUPT,
129187866Semax		.endpoint =	0x01,	/* fixed */
130187866Semax		.direction =	UE_DIR_IN,
131187866Semax		.if_index =	UBTBCMFW_IFACE_IDX,
132187866Semax		.mh.bufsize =	UBTBCMFW_BSIZE,
133187866Semax		.mh.flags =	{ .pipe_bof = 1, .short_xfer_ok = 1,
134187866Semax				  .proxy_buffer = 1, },
135187866Semax		.mh.callback =	&ubtbcmfw_read_callback,
136184610Salfred	},
137184610Salfred};
138184610Salfred
139184610Salfred/*
140184610Salfred * Module
141184610Salfred */
142184610Salfred
143187866Semaxstatic devclass_t	ubtbcmfw_devclass;
144184610Salfred
145187866Semaxstatic device_method_t	ubtbcmfw_methods[] =
146187866Semax{
147184610Salfred	DEVMETHOD(device_probe, ubtbcmfw_probe),
148184610Salfred	DEVMETHOD(device_attach, ubtbcmfw_attach),
149184610Salfred	DEVMETHOD(device_detach, ubtbcmfw_detach),
150184610Salfred	{0, 0}
151184610Salfred};
152184610Salfred
153187866Semaxstatic driver_t		ubtbcmfw_driver =
154187866Semax{
155187866Semax	.name =		"ubtbcmfw",
156187866Semax	.methods =	ubtbcmfw_methods,
157187866Semax	.size =		sizeof(struct ubtbcmfw_softc),
158184610Salfred};
159184610Salfred
160184610SalfredDRIVER_MODULE(ubtbcmfw, ushub, ubtbcmfw_driver, ubtbcmfw_devclass, NULL, 0);
161184610SalfredMODULE_DEPEND(ubtbcmfw, usb2_bluetooth, 1, 1, 1);
162184610SalfredMODULE_DEPEND(ubtbcmfw, usb2_core, 1, 1, 1);
163184610Salfred
164184610Salfred/*
165184610Salfred * Probe for a USB Bluetooth device
166184610Salfred */
167184610Salfred
168184610Salfredstatic int
169184610Salfredubtbcmfw_probe(device_t dev)
170184610Salfred{
171187866Semax	const struct usb2_device_id	devs[] = {
172187866Semax	/* Broadcom BCM2033 devices only */
173187866Semax	{ USB_VPI(USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033, 0) },
174187866Semax	};
175184610Salfred
176187866Semax	struct usb2_attach_arg	*uaa = device_get_ivars(dev);
177187866Semax
178187866Semax	if (uaa->usb2_mode != USB_MODE_HOST)
179184610Salfred		return (ENXIO);
180187866Semax
181184610Salfred	if (uaa->info.bIfaceIndex != 0)
182184610Salfred		return (ENXIO);
183184610Salfred
184187866Semax	return (usb2_lookup_id_by_uaa(devs, sizeof(devs), uaa));
185187866Semax} /* ubtbcmfw_probe */
186184610Salfred
187184610Salfred/*
188184610Salfred * Attach the device
189184610Salfred */
190184610Salfred
191184610Salfredstatic int
192184610Salfredubtbcmfw_attach(device_t dev)
193184610Salfred{
194187866Semax	struct usb2_attach_arg	*uaa = device_get_ivars(dev);
195187866Semax	struct ubtbcmfw_softc	*sc = device_get_softc(dev);
196187866Semax	uint8_t			iface_index;
197187866Semax	int			error;
198184610Salfred
199184610Salfred	sc->sc_udev = uaa->device;
200184610Salfred
201184610Salfred	device_set_usb2_desc(dev);
202184610Salfred
203184610Salfred	mtx_init(&sc->sc_mtx, "ubtbcmfw lock", NULL, MTX_DEF | MTX_RECURSE);
204184610Salfred
205184610Salfred	iface_index = UBTBCMFW_IFACE_IDX;
206187866Semax	error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
207187866Semax				ubtbcmfw_config, UBTBCMFW_N_TRANSFER,
208187866Semax				sc, &sc->sc_mtx);
209187866Semax	if (error != 0) {
210187866Semax		device_printf(dev, "allocating USB transfers failed. %s\n",
211187866Semax			usb2_errstr(error));
212184610Salfred		goto detach;
213184610Salfred	}
214187866Semax
215187866Semax	/* Set interface permissions */
216184610Salfred	usb2_set_iface_perm(uaa->device, uaa->info.bIfaceIndex,
217187866Semax		UID_ROOT, GID_OPERATOR, 0644);
218184610Salfred
219187866Semax	error = usb2_fifo_attach(uaa->device, sc, &sc->sc_mtx,
220187866Semax			&ubtbcmfw_fifo_methods, &sc->sc_fifo,
221187866Semax			device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex);
222187866Semax	if (error != 0) {
223187866Semax		device_printf(dev, "could not attach fifo. %s\n",
224187866Semax			usb2_errstr(error));
225184610Salfred		goto detach;
226184610Salfred	}
227184610Salfred
228187866Semax	return (0);	/* success */
229187866Semax
230184610Salfreddetach:
231184610Salfred	ubtbcmfw_detach(dev);
232184610Salfred
233187866Semax	return (ENXIO);	/* failure */
234187866Semax} /* ubtbcmfw_attach */
235187866Semax
236184610Salfred/*
237184610Salfred * Detach the device
238184610Salfred */
239184610Salfred
240184610Salfredstatic int
241184610Salfredubtbcmfw_detach(device_t dev)
242184610Salfred{
243187866Semax	struct ubtbcmfw_softc	*sc = device_get_softc(dev);
244184610Salfred
245184610Salfred	usb2_fifo_detach(&sc->sc_fifo);
246184610Salfred
247187866Semax	usb2_transfer_unsetup(sc->sc_xfer, UBTBCMFW_N_TRANSFER);
248184610Salfred
249184610Salfred	mtx_destroy(&sc->sc_mtx);
250184610Salfred
251184610Salfred	return (0);
252187866Semax} /* ubtbcmfw_detach */
253184610Salfred
254187866Semax/*
255187866Semax * USB write callback
256187866Semax */
257187866Semax
258184610Salfredstatic void
259184610Salfredubtbcmfw_write_callback(struct usb2_xfer *xfer)
260184610Salfred{
261187866Semax	struct ubtbcmfw_softc	*sc = xfer->priv_sc;
262187866Semax	struct usb2_fifo	*f = sc->sc_fifo.fp[USB_FIFO_TX];
263187866Semax	uint32_t		actlen;
264184610Salfred
265184610Salfred	switch (USB_GET_STATE(xfer)) {
266187866Semax	case USB_ST_SETUP:
267184610Salfred	case USB_ST_TRANSFERRED:
268187866Semaxsetup_next:
269184610Salfred		if (usb2_fifo_get_data(f, xfer->frbuffers, 0,
270187866Semax				xfer->max_data_length, &actlen, 0)) {
271184610Salfred			xfer->frlengths[0] = actlen;
272184610Salfred			usb2_start_hardware(xfer);
273184610Salfred		}
274187866Semax		break;
275184610Salfred
276187866Semax	default: /* Error */
277184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
278184610Salfred			/* try to clear stall first */
279187866Semax			xfer->flags.stall_pipe = 1;
280187866Semax			goto setup_next;
281184610Salfred		}
282187866Semax		break;
283184610Salfred	}
284187866Semax} /* ubtbcmfw_write_callback */
285184610Salfred
286187866Semax/*
287187866Semax * USB read callback
288187866Semax */
289184610Salfred
290184610Salfredstatic void
291184610Salfredubtbcmfw_read_callback(struct usb2_xfer *xfer)
292184610Salfred{
293187866Semax	struct ubtbcmfw_softc	*sc = xfer->priv_sc;
294187866Semax	struct usb2_fifo	*fifo = sc->sc_fifo.fp[USB_FIFO_RX];
295184610Salfred
296184610Salfred	switch (USB_GET_STATE(xfer)) {
297184610Salfred	case USB_ST_TRANSFERRED:
298187866Semax		usb2_fifo_put_data(fifo, xfer->frbuffers, 0, xfer->actlen, 1);
299187866Semax		/* FALLTHROUGH */
300184610Salfred
301184610Salfred	case USB_ST_SETUP:
302187866Semaxsetup_next:
303187866Semax		if (usb2_fifo_put_bytes_max(fifo) > 0) {
304184610Salfred			xfer->frlengths[0] = xfer->max_data_length;
305184610Salfred			usb2_start_hardware(xfer);
306184610Salfred		}
307187866Semax		break;
308184610Salfred
309187866Semax	default: /* Error */
310184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
311184610Salfred			/* try to clear stall first */
312187866Semax			xfer->flags.stall_pipe = 1;
313187866Semax			goto setup_next;
314184610Salfred		}
315187866Semax		break;
316184610Salfred	}
317187866Semax} /* ubtbcmfw_read_callback */
318184610Salfred
319187866Semax/*
320187866Semax * Called when we about to start read()ing from the device
321187866Semax */
322184610Salfred
323184610Salfredstatic void
324184610Salfredubtbcmfw_start_read(struct usb2_fifo *fifo)
325184610Salfred{
326187866Semax	struct ubtbcmfw_softc	*sc = fifo->priv_sc0;
327184610Salfred
328187866Semax	usb2_transfer_start(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
329187866Semax} /* ubtbcmfw_start_read */
330184610Salfred
331187866Semax/*
332187866Semax * Called when we about to stop reading (i.e. closing fifo)
333187866Semax */
334187866Semax
335184610Salfredstatic void
336184610Salfredubtbcmfw_stop_read(struct usb2_fifo *fifo)
337184610Salfred{
338187866Semax	struct ubtbcmfw_softc	*sc = fifo->priv_sc0;
339184610Salfred
340187866Semax	usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
341187866Semax} /* ubtbcmfw_stop_read */
342184610Salfred
343187866Semax/*
344187866Semax * Called when we about to start write()ing to the device, poll()ing
345187866Semax * for write or flushing fifo
346187866Semax */
347187866Semax
348184610Salfredstatic void
349184610Salfredubtbcmfw_start_write(struct usb2_fifo *fifo)
350184610Salfred{
351187866Semax	struct ubtbcmfw_softc	*sc = fifo->priv_sc0;
352184610Salfred
353187259Sthompsa	usb2_transfer_start(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
354187866Semax} /* ubtbcmfw_start_write */
355184610Salfred
356187866Semax/*
357187866Semax * Called when we about to stop writing (i.e. closing fifo)
358187866Semax */
359187866Semax
360184610Salfredstatic void
361184610Salfredubtbcmfw_stop_write(struct usb2_fifo *fifo)
362184610Salfred{
363187866Semax	struct ubtbcmfw_softc	*sc = fifo->priv_sc0;
364184610Salfred
365187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
366187866Semax} /* ubtbcmfw_stop_write */
367184610Salfred
368187866Semax/*
369187866Semax * Called when fifo is open
370187866Semax */
371187866Semax
372184610Salfredstatic int
373184610Salfredubtbcmfw_open(struct usb2_fifo *fifo, int fflags, struct thread *td)
374184610Salfred{
375187866Semax	struct ubtbcmfw_softc	*sc = fifo->priv_sc0;
376187866Semax	struct usb2_xfer	*xfer;
377184610Salfred
378187866Semax	/*
379187866Semax	 * f_open fifo method can only be called with either FREAD
380187866Semax	 * or FWRITE flag set at one time.
381187866Semax	 */
382187866Semax
383187866Semax	if (fflags & FREAD)
384187866Semax		xfer = sc->sc_xfer[UBTBCMFW_INTR_DT_RD];
385187866Semax	else if (fflags & FWRITE)
386187866Semax		xfer = sc->sc_xfer[UBTBCMFW_BULK_DT_WR];
387187866Semax	else
388187994Salfred		return (EINVAL);	/* should not happen */
389187994Salfred
390187866Semax	if (usb2_fifo_alloc_buffer(fifo, xfer->max_data_length,
391187866Semax			UBTBCMFW_IFQ_MAXLEN) != 0)
392187866Semax		return (ENOMEM);
393187866Semax
394184610Salfred	return (0);
395187866Semax} /* ubtbcmfw_open */
396184610Salfred
397187866Semax/*
398187866Semax * Called when fifo is closed
399187866Semax */
400187866Semax
401184610Salfredstatic void
402184610Salfredubtbcmfw_close(struct usb2_fifo *fifo, int fflags, struct thread *td)
403184610Salfred{
404187866Semax	if (fflags & (FREAD | FWRITE))
405184610Salfred		usb2_fifo_free_buffer(fifo);
406187866Semax} /* ubtbcmfw_close */
407184610Salfred
408187866Semax/*
409187866Semax * Process ioctl() on USB device
410187866Semax */
411187866Semax
412184610Salfredstatic int
413184610Salfredubtbcmfw_ioctl(struct usb2_fifo *fifo, u_long cmd, void *data,
414184610Salfred    int fflags, struct thread *td)
415184610Salfred{
416187866Semax	struct ubtbcmfw_softc	*sc = fifo->priv_sc0;
417187866Semax	int			error = 0;
418184610Salfred
419184610Salfred	switch (cmd) {
420184610Salfred	case USB_GET_DEVICE_DESC:
421187866Semax		memcpy(data, usb2_get_device_descriptor(sc->sc_udev),
422187866Semax			sizeof(struct usb2_device_descriptor));
423184610Salfred		break;
424184610Salfred
425184610Salfred	default:
426184610Salfred		error = EINVAL;
427184610Salfred		break;
428184610Salfred	}
429187866Semax
430184610Salfred	return (error);
431187866Semax} /* ubtbcmfw_ioctl */
432