1 /* $NetBSD: aubtfwl.c,v 1.10 2020/05/30 17:19:45 jakllsch Exp $ */
2 
3 /*
4  * Copyright (c) 2011 Jonathan A. Kollasch
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: aubtfwl.c,v 1.10 2020/05/30 17:19:45 jakllsch Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/kmem.h>
34 #include <dev/usb/usb.h>
35 #include <dev/usb/usbdevs.h>
36 #include <dev/usb/usbdi.h>
37 #include <dev/usb/usbdivar.h>
38 #include <dev/usb/usbdi_util.h>
39 #include <dev/firmload.h>
40 
41 #include <dev/usb/aubtfwlreg.h>
42 
43 #define AR3K_FIRMWARE_CHUNK_SIZE 4096
44 
45 static int aubtfwl_match(device_t, cfdata_t, void *);
46 static void aubtfwl_attach(device_t, device_t, void *);
47 static int aubtfwl_detach(device_t, int);
48 static void aubtfwl_attach_hook(device_t);
49 
50 struct aubtfwl_softc {
51           struct usbd_device *sc_udev;
52           int sc_flags;
53 #define AUBT_IS_AR3012                  1
54 };
55 
56 CFATTACH_DECL_NEW(aubtfwl, sizeof(struct aubtfwl_softc), aubtfwl_match, aubtfwl_attach, aubtfwl_detach, NULL);
57 
58 static const struct usb_devno ar3k_devs[] = {
59           { USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR3011 },
60 };
61 
62 static const struct usb_devno ar3k12_devs[] = {
63           { USB_VENDOR_FOXCONN, USB_PRODUCT_FOXCONN_AR3012 },
64 };
65 
66 static int
aubtfwl_match(device_t parent,cfdata_t match,void * aux)67 aubtfwl_match(device_t parent, cfdata_t match, void *aux)
68 {
69           const struct usb_attach_arg * const uaa = aux;
70 
71           if (usb_lookup(ar3k_devs, uaa->uaa_vendor, uaa->uaa_product))
72                     return UMATCH_VENDOR_PRODUCT;
73 
74           if (usb_lookup(ar3k12_devs, uaa->uaa_vendor, uaa->uaa_product)) {
75                     return (UGETW(uaa->uaa_device->ud_ddesc.bcdDevice) > 1)?
76                               UMATCH_NONE : UMATCH_VENDOR_PRODUCT;
77           }
78 
79           return UMATCH_NONE;
80 }
81 
82 static void
aubtfwl_attach(device_t parent,device_t self,void * aux)83 aubtfwl_attach(device_t parent, device_t self, void *aux)
84 {
85           const struct usb_attach_arg * const uaa = aux;
86           struct aubtfwl_softc * const sc = device_private(self);
87           aprint_naive("\n");
88           aprint_normal("\n");
89           sc->sc_udev = uaa->uaa_device;
90           sc->sc_flags = 0;
91 
92           if (usb_lookup(ar3k12_devs, uaa->uaa_vendor, uaa->uaa_product))
93                     sc->sc_flags |= AUBT_IS_AR3012;
94 
95           config_mountroot(self, aubtfwl_attach_hook);
96 }
97 
98 static int
aubtfwl_detach(device_t self,int flags)99 aubtfwl_detach(device_t self, int flags)
100 {
101           struct aubtfwl_softc * const sc = device_private(self);
102 
103           usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, self);
104 
105           return 0;
106 }
107 
108 /* Returns 0 if firmware was correctly loaded */
109 static int
aubtfwl_firmware_load(device_t self,const char * name)110 aubtfwl_firmware_load(device_t self, const char *name) {
111           struct aubtfwl_softc * const sc = device_private(self);
112           struct usbd_interface *iface;
113           struct usbd_pipe *pipe;
114           struct usbd_xfer *xfer;
115           void *buf;
116           usb_device_request_t req;
117           int error = 0;
118           firmware_handle_t fwh;
119           size_t fws;
120           size_t fwo = 0;
121           uint32_t n;
122 
123           memset(&req, 0, sizeof(req));
124 
125           error = firmware_open("ubt", name, &fwh);
126           if (error != 0) {
127                     aprint_error_dev(self, "'%s' open fail %d\n", name, error);
128                     return error;
129           }
130           fws = firmware_get_size(fwh);
131 
132           error = usbd_set_config_no(sc->sc_udev, 1, 0);
133           if (error != 0) {
134                     aprint_error_dev(self, "failed to set configuration"
135                         ", err=%s\n", usbd_errstr(error));
136                     goto out_firmware;
137           }
138 
139           error = usbd_device2interface_handle(sc->sc_udev, 0, &iface);
140           if (error) {
141                     aprint_error_dev(self, "failed to get interface, %s\n",
142                        usbd_errstr(error));
143                     goto out_firmware;
144           }
145 
146           error = usbd_open_pipe(iface, UE_DIR_OUT|2, USBD_EXCLUSIVE_USE, &pipe);
147           if (error) {
148                     aprint_error_dev(self, "failed to open pipe, %s\n",
149                        usbd_errstr(error));
150                     goto out_firmware;
151           }
152 
153           error = usbd_create_xfer(pipe, AR3K_FIRMWARE_CHUNK_SIZE, 0, 0, &xfer);
154           if (error) {
155                     aprint_verbose_dev(self, "cannot create xfer(%d)\n",
156                         error);
157                     goto out_pipe;
158           }
159           buf = usbd_get_buffer(xfer);
160 
161           error = firmware_read(fwh, fwo, buf, AR3K_FIRMWARE_HEADER_SIZE);
162           if (error != 0) {
163                     aprint_error_dev(self, "firmware_read failed %d\n", error);
164                     goto out_xfer;
165           }
166 
167           req.bRequest = AR3K_SEND_FIRMWARE;
168           req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
169           USETW(req.wValue, 0);
170           USETW(req.wIndex, 0);
171           USETW(req.wLength, AR3K_FIRMWARE_HEADER_SIZE);
172 
173           aprint_verbose_dev(self, "beginning firmware load\n");
174 
175           error = usbd_do_request(sc->sc_udev, &req, buf);
176           if (error != 0) {
177                     aprint_error_dev(self, "%s\n", usbd_errstr(error));
178                     return error;
179           }
180           fwo = AR3K_FIRMWARE_HEADER_SIZE;
181 
182           while (fwo < fws) {
183                     n = uimin(AR3K_FIRMWARE_CHUNK_SIZE, fws - fwo);
184                     error = firmware_read(fwh, fwo, buf, n);
185                     if (error != 0) {
186                               break;
187                     }
188                     error = usbd_bulk_transfer(xfer, pipe, 0, USBD_DEFAULT_TIMEOUT,
189                         buf, &n);
190                     if (error != USBD_NORMAL_COMPLETION) {
191                               aprint_error_dev(self, "xfer failed, %s\n",
192                                  usbd_errstr(error));
193                               break;
194                     }
195                     fwo += n;
196           }
197 
198           if (error == 0)
199                     aprint_verbose_dev(self, "firmware load complete\n");
200 
201 out_xfer:
202           usbd_destroy_xfer(xfer);
203 out_pipe:
204           usbd_close_pipe(pipe);
205 out_firmware:
206           firmware_close(fwh);
207 
208           return !!error;
209 }
210 
211 static int
aubtfwl_get_state(struct aubtfwl_softc * sc,uint8_t * state)212 aubtfwl_get_state(struct aubtfwl_softc *sc, uint8_t *state) {
213           usb_device_request_t req;
214           int error = 0;
215 
216           memset(&req, 0, sizeof(req));
217 
218           req.bRequest = AR3K_GET_STATE;
219           req.bmRequestType = UT_READ_VENDOR_DEVICE;
220           USETW(req.wValue, 0);
221           USETW(req.wIndex, 0);
222           USETW(req.wLength, sizeof(*state));
223 
224           error = usbd_do_request(sc->sc_udev, &req, state);
225 
226           return error;
227 }
228 
229 static int
aubtfwl_get_version(struct aubtfwl_softc * sc,struct ar3k_version * ver)230 aubtfwl_get_version(struct aubtfwl_softc *sc, struct ar3k_version *ver) {
231           usb_device_request_t req;
232           int error = 0;
233 
234           memset(&req, 0, sizeof(req));
235 
236           req.bRequest = AR3K_GET_VERSION;
237           req.bmRequestType = UT_READ_VENDOR_DEVICE;
238           USETW(req.wValue, 0);
239           USETW(req.wIndex, 0);
240           USETW(req.wLength, sizeof(*ver));
241 
242           error = usbd_do_request(sc->sc_udev, &req, ver);
243 
244 #if BYTE_ORDER == BIG_ENDIAN
245           if (error == USBD_NORMAL_COMPLETION) {
246                     ver->rom = bswap32(ver->rom);
247                     ver->build = bswap32(ver->build);
248                     ver->ram = bswap32(ver->ram);
249           }
250 #endif
251           return error;
252 }
253 
254 static int
aubtfwl_send_command(struct aubtfwl_softc * sc,uByte cmd)255 aubtfwl_send_command(struct aubtfwl_softc *sc, uByte cmd) {
256           usb_device_request_t req;
257           int error = 0;
258 
259           memset(&req, 0, sizeof(req));
260 
261           req.bRequest = cmd;
262           req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
263           USETW(req.wValue, 0);
264           USETW(req.wIndex, 0);
265           USETW(req.wLength, 0);
266 
267           error = usbd_do_request(sc->sc_udev, &req, NULL);
268 
269           return error;
270 }
271 
272 static void
aubtfwl_attach_hook(device_t self)273 aubtfwl_attach_hook(device_t self)
274 {
275           struct aubtfwl_softc * const sc = device_private(self);
276           char *fw_name;
277           struct ar3k_version ver;
278           uint8_t state;
279           int clock = 0;
280           int error = 0;
281 
282           if (sc->sc_flags & AUBT_IS_AR3012) {
283                     error = aubtfwl_get_version(sc, &ver);
284                     if (!error)
285                               error = aubtfwl_get_state(sc, &state);
286 
287                     if (error) {
288                               aprint_error_dev(self,
289                                         "couldn't get version or state\n");
290                               return;
291                     }
292 
293                     aprint_verbose_dev(self, "state is 0x%02x\n", state);
294 
295                     if (!(state & AR3K_STATE_IS_PATCHED)) {
296                               fw_name = kmem_asprintf("ar3k/AthrBT_0x%08x.dfu",
297                                   ver.rom);
298                               error = aubtfwl_firmware_load(self, fw_name);
299                               kmem_strfree(fw_name);
300 
301                               if (error)
302                                         return;
303                     }
304 
305                     switch (ver.clock) {
306                     case AR3K_CLOCK_19M:
307                               clock = 19;
308                               break;
309                     case AR3K_CLOCK_26M:
310                               clock = 26;
311                               break;
312                     case AR3K_CLOCK_40M:
313                               clock = 40;
314                               break;
315                     }
316 
317                     fw_name = kmem_asprintf("ar3k/ramps_0x%08x_%d.dfu",
318                         ver.rom, clock);
319                     aubtfwl_firmware_load(self, fw_name);
320                     kmem_strfree(fw_name);
321 
322                     if ((state & AR3K_STATE_MODE_MASK) != AR3K_STATE_MODE_NORMAL) {
323                               error = aubtfwl_send_command(sc, AR3K_SET_NORMAL_MODE);
324                               if (error) {
325                                         aprint_error_dev(self,
326                                                   "couldn't set normal mode: %s",
327                                                   usbd_errstr(error));
328                                         return;
329                               }
330                     }
331 
332                     /* Apparently some devices will fail this, so ignore result */
333                     (void) aubtfwl_send_command(sc, AR3K_SWITCH_VID_PID);
334           } else {
335                     aubtfwl_firmware_load(self, "ath3k-1.fw");
336           }
337 
338           return;
339 }
340