FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/ubtbcmfw.c
1 /* $NetBSD: ubtbcmfw.c,v 1.7 2003/12/01 01:09:24 atatat Exp $ */
2
3 /*
4 * Copyright (c) 2002 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@augustsson.net>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: ubtbcmfw.c,v 1.7 2003/12/01 01:09:24 atatat Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/conf.h>
47 #include <sys/namei.h>
48 #include <sys/vnode.h>
49 #include <sys/proc.h>
50 #include <sys/fcntl.h>
51 #include <sys/sysctl.h>
52
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usbdi.h>
55 #include <dev/usb/usbdi_util.h>
56 #include <dev/usb/usbdevs.h>
57
58 /*
59 * Download firmware to BCM2033.
60 */
61
62 #define CONFIG_NO 1
63 #define IFACE_IDX 0 /* Control interface */
64 /* Fixed endpoints */
65 #define INTR_IN_EP 0x81
66 #define BULK_OUT_EP 0x02
67
68 Static char ubtbcmfw_fwpath[128] = "/usr/libdata/firmware/bcm2033";
69
70 #define MINI_DRIVER "BCM2033-MD.hex"
71 #define FIRMWARE "BCM2033-FW.bin"
72
73 struct ubtbcmfw_softc {
74 USBBASEDEVICE sc_dev; /* base device */
75 };
76
77 Static int
78 ubtbcmfw_load_file(usbd_device_handle dev, usbd_pipe_handle out,
79 const char *filename);
80 Static usbd_status
81 ubtbcmfw_write(usbd_device_handle dev, usbd_pipe_handle out,
82 char *buf, uint count);
83 Static usbd_status
84 ubtbcmfw_read(usbd_device_handle dev, usbd_pipe_handle in,
85 char *buf, uint *count);
86
87 USB_DECLARE_DRIVER(ubtbcmfw);
88
89 USB_MATCH(ubtbcmfw)
90 {
91 USB_MATCH_START(ubtbcmfw, uaa);
92
93 if (uaa->iface != NULL)
94 return (UMATCH_NONE);
95
96 /* Match the boot device. */
97 if (uaa->vendor == USB_VENDOR_BROADCOM &&
98 uaa->product == USB_PRODUCT_BROADCOM_BCM2033NF)
99 return (UMATCH_VENDOR_PRODUCT);
100
101 return (UMATCH_NONE);
102 }
103
104 USB_ATTACH(ubtbcmfw)
105 {
106 USB_ATTACH_START(ubtbcmfw, sc, uaa);
107 usbd_device_handle dev = uaa->device;
108 usbd_interface_handle iface;
109 usbd_status err;
110 char devinfo[1024];
111 char name[256];
112 char buf[16];
113 usbd_pipe_handle intr_in_pipe;
114 usbd_pipe_handle bulk_out_pipe;
115 uint n;
116
117 usbd_devinfo(dev, 0, devinfo);
118 USB_ATTACH_SETUP;
119 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
120
121 err = usbd_set_config_no(dev, CONFIG_NO, 1);
122 if (err) {
123 printf("%s: setting config no failed\n",
124 USBDEVNAME(sc->sc_dev));
125 USB_ATTACH_ERROR_RETURN;
126 }
127 err = usbd_device2interface_handle(dev, IFACE_IDX, &iface);
128 if (err) {
129 printf("%s: getting interface handle failed\n",
130 USBDEVNAME(sc->sc_dev));
131 USB_ATTACH_ERROR_RETURN;
132 }
133
134 /* Will be used as a bulk pipe. */
135 err = usbd_open_pipe(iface, INTR_IN_EP, 0, &intr_in_pipe);
136 if (err) {
137 printf("%s: open bulk in failed\n", USBDEVNAME(sc->sc_dev));
138 USB_ATTACH_ERROR_RETURN;
139 }
140 err = usbd_open_pipe(iface, BULK_OUT_EP, 0, &bulk_out_pipe);
141 if (err) {
142 printf("%s: open bulk in failed\n", USBDEVNAME(sc->sc_dev));
143 USB_ATTACH_ERROR_RETURN;
144 }
145
146 printf("%s: downloading firmware\n", USBDEVNAME(sc->sc_dev));
147 snprintf(name, sizeof name, "%s/%s", ubtbcmfw_fwpath, MINI_DRIVER);
148 err = ubtbcmfw_load_file(dev, bulk_out_pipe, name);
149 if (err) {
150 printf("%s: loading mini-driver failed\n",
151 USBDEVNAME(sc->sc_dev));
152 USB_ATTACH_ERROR_RETURN;
153 }
154 usbd_delay_ms(dev, 1);
155 err = ubtbcmfw_write(dev, bulk_out_pipe, "#", 1);
156 if (err) {
157 printf("%s: write # failed\n", USBDEVNAME(sc->sc_dev));
158 USB_ATTACH_ERROR_RETURN;
159 }
160 buf[0] = 0;
161 n = 10;
162 err = ubtbcmfw_read(dev, intr_in_pipe, buf, &n);
163 if (err) {
164 printf("%s: read # failed\n", USBDEVNAME(sc->sc_dev));
165 USB_ATTACH_ERROR_RETURN;
166 }
167 if (buf[0] != '#') {
168 printf("%s: memory select failed\n", USBDEVNAME(sc->sc_dev));
169 USB_ATTACH_ERROR_RETURN;
170 }
171 snprintf(name, sizeof name, "%s/%s", ubtbcmfw_fwpath, FIRMWARE);
172 err = ubtbcmfw_load_file(dev, bulk_out_pipe, name);
173 if (err) {
174 printf("%s: loading firmware failed\n",
175 USBDEVNAME(sc->sc_dev));
176 USB_ATTACH_ERROR_RETURN;
177 }
178 n = 10;
179 err = ubtbcmfw_read(dev, intr_in_pipe, buf, &n);
180 if (err) {
181 printf("%s: read . failed\n", USBDEVNAME(sc->sc_dev));
182 USB_ATTACH_ERROR_RETURN;
183 }
184 if (buf[0] != '.') {
185 printf("%s: firmware load failed\n", USBDEVNAME(sc->sc_dev));
186 USB_ATTACH_ERROR_RETURN;
187 }
188
189 usbd_close_pipe(intr_in_pipe);
190 usbd_close_pipe(bulk_out_pipe);
191
192 printf("%s: firmware download complete\n",
193 USBDEVNAME(sc->sc_dev));
194 usbd_delay_ms(dev, 500);
195
196 USB_ATTACH_SUCCESS_RETURN;
197 }
198
199 USB_DETACH(ubtbcmfw)
200 {
201 /*USB_DETACH_START(ubtbcmfw, sc);*/
202
203 return (0);
204 }
205
206 int
207 ubtbcmfw_activate(device_ptr_t self, enum devact act)
208 {
209 return 0;
210 }
211
212 Static int
213 ubtbcmfw_load_file(usbd_device_handle dev, usbd_pipe_handle out,
214 const char *filename)
215 {
216 struct proc *p = curproc;
217 struct nameidata nd;
218 struct vnode *vp;
219 size_t resid, offs, size;
220 int error;
221 char buf[1024];
222 struct timeval delta;
223
224 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p);
225 /* Loop until we are well passed boot */
226 for (;;) {
227 error = vn_open(&nd, FREAD, 0);
228 if (!error)
229 break;
230 timersub(&boottime, &time, &delta);
231 if (delta.tv_sec > 60)
232 break;
233 printf("ubtbcmfw_load_file: waiting for firmware file\n");
234 if (tsleep(buf, PZERO, "ubtbcmfw", hz * 5) != EWOULDBLOCK)
235 break;
236 }
237 if (error)
238 return (error);
239 vp = nd.ni_vp;
240 VOP_UNLOCK(vp, 0);
241 if (nd.ni_vp->v_type != VREG) {
242 error = EACCES;
243 goto out;
244 }
245
246 for (offs = 0; ; offs += size) {
247 size = sizeof buf;
248 error = vn_rdwr(UIO_READ, vp, buf, size, offs, UIO_SYSSPACE,
249 IO_NODELOCKED | IO_SYNC, p->p_ucred, &resid, p);
250 size -= resid;
251 if (error || size == 0)
252 break;
253 if (ubtbcmfw_write(dev, out, buf, size)) {
254 error = EIO;
255 break;
256 }
257 }
258
259 out:
260 vn_close(vp, FREAD, p->p_ucred, p);
261 return error;
262 }
263
264 Static usbd_status
265 ubtbcmfw_write(usbd_device_handle dev, usbd_pipe_handle out,
266 char *buf, uint count)
267 {
268 usbd_xfer_handle xfer;
269 usbd_status err;
270 uint n;
271
272 xfer = usbd_alloc_xfer(dev);
273 if (xfer == NULL)
274 return (USBD_NOMEM);
275 n = count;
276 err = usbd_bulk_transfer(xfer, out, 0, USBD_DEFAULT_TIMEOUT,
277 buf, &n, "ubtfwr");
278 usbd_free_xfer(xfer);
279 return (err);
280 }
281
282 Static usbd_status
283 ubtbcmfw_read(usbd_device_handle dev, usbd_pipe_handle in,
284 char *buf, uint *count)
285 {
286 usbd_xfer_handle xfer;
287 usbd_status err;
288
289 xfer = usbd_alloc_xfer(dev);
290 if (xfer == NULL)
291 return (USBD_NOMEM);
292 err = usbd_bulk_transfer(xfer, in, USBD_SHORT_XFER_OK,
293 USBD_DEFAULT_TIMEOUT, buf, count, "ubtfrd");
294 usbd_free_xfer(xfer);
295 return (err);
296 }
Cache object: b6d224998214ac506ce3cf142a8d0d37
|