]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/uathload/uathload.c
Update to zstd 1.3.2
[FreeBSD/FreeBSD.git] / usr.sbin / uathload / uathload.c
1 /*-
2  * Copyright (c) 2006 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  *
29  * $FreeBSD$
30  */
31
32 /*
33  * Atheros AR5523 USB Station Firmware downloader.
34  *
35  *    uathload -d ugen-device [firmware-file]
36  *
37  * Intended to be called from devd on device discovery.
38  */
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/endian.h>
42 #include <sys/mman.h>
43
44 #include <sys/ioctl.h>
45 #include <dev/usb/usb.h>
46 #include <dev/usb/usb_ioctl.h>
47
48 #include <err.h>
49 #include <fcntl.h>
50 #include <libgen.h>
51 #include <paths.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <strings.h>
56 #include <unistd.h>
57
58 /* all fields are big endian */
59 struct uath_fwmsg {
60         uint32_t        flags;
61 #define UATH_WRITE_BLOCK        (1 << 4)
62
63         uint32_t        len;
64 #define UATH_MAX_FWBLOCK_SIZE   2048
65
66         uint32_t        total;
67         uint32_t        remain;
68         uint32_t        rxtotal;
69         uint32_t        pad[123];
70 } __packed;
71
72 #define UATH_DATA_TIMEOUT       10000
73 #define UATH_CMD_TIMEOUT        1000
74
75 #define VERBOSE(_fmt, ...) do {                 \
76         if (verbose) {                          \
77                 printf(_fmt, __VA_ARGS__);      \
78                 fflush(stdout);                 \
79         }                                       \
80 } while (0)
81
82 extern  uint8_t _binary_ar5523_bin_start;
83 extern  uint8_t _binary_ar5523_bin_end;
84
85 static int
86 getdevname(const char *udevname, char *msgdev, char *datadev)
87 {
88         char *bn, *bnbuf, *dn, *dnbuf;
89
90         dnbuf = strdup(udevname);
91         if (dnbuf == NULL)
92                 return (-1);
93         dn = dirname(dnbuf);
94         bnbuf = strdup(udevname);
95         if (bnbuf == NULL) {
96                 free(dnbuf);
97                 return (-1);
98         }
99         bn = basename(bnbuf);
100         if (strncmp(bn, "ugen", 4) != 0) {
101                 free(dnbuf);
102                 free(bnbuf);
103                 return (-1);
104         }
105         bn += 4;
106
107         /* NB: pipes are hardcoded */
108         snprintf(msgdev, 256, "%s/usb/%s.1", dn, bn);
109         snprintf(datadev, 256, "%s/usb/%s.2", dn, bn);
110         free(dnbuf);
111         free(bnbuf);
112         return (0);
113 }
114
115 static void
116 usage(void)
117 {
118         errx(-1, "usage: uathload [-v] -d devname [firmware]");
119 }
120
121 int
122 main(int argc, char *argv[])
123 {
124         const char *fwname, *udevname;
125         char msgdev[256], datadev[256];
126         struct uath_fwmsg txmsg, rxmsg;
127         char *txdata;
128         struct stat sb;
129         int msg, data, fw, timeout, b, c;
130         int bufsize = 512, verbose = 0;
131         ssize_t len;
132
133         udevname = NULL;
134         while ((c = getopt(argc, argv, "d:v")) != -1) {
135                 switch (c) {
136                 case 'd':
137                         udevname = optarg;
138                         break;
139                 case 'v':
140                         verbose = 1;
141                         break;
142                 default:
143                         usage();
144                         /*NOTREACHED*/
145                 }
146         }
147         argc -= optind;
148         argv += optind;
149
150         if (udevname == NULL)
151                 errx(-1, "No device name; use -d to specify the ugen device");
152         if (argc > 1)
153                 usage();
154
155         if (argc == 1)
156                 fwname = argv[0];
157         else
158                 fwname = _PATH_FIRMWARE "/ar5523.bin";
159         fw = open(fwname, O_RDONLY, 0);
160         if (fw < 0)
161                 err(-1, "open(%s)", fwname);
162         if (fstat(fw, &sb) < 0)
163                 err(-1, "fstat(%s)", fwname);
164         txdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fw, 0);
165         if (txdata == MAP_FAILED)
166                 err(-1, "mmap(%s)", fwname);
167         len = sb.st_size;
168         /* XXX verify device is an AR5005 part */
169         if (getdevname(udevname, msgdev, datadev))
170                 err(-1, "getdevname error");
171
172         msg = open(msgdev, O_RDWR, 0);
173         if (msg < 0)
174                 err(-1, "open(%s)", msgdev);
175         timeout = UATH_DATA_TIMEOUT;
176         if (ioctl(msg, USB_SET_RX_TIMEOUT, &timeout) < 0)
177                 err(-1, "%s: USB_SET_RX_TIMEOUT(%u)", msgdev, UATH_DATA_TIMEOUT);
178         if (ioctl(msg, USB_SET_RX_BUFFER_SIZE, &bufsize) < 0)
179                 err(-1, "%s: USB_SET_RX_BUFFER_SIZE(%u)", msgdev, bufsize);
180
181         data = open(datadev, O_WRONLY, 0);
182         if (data < 0)
183                 err(-1, "open(%s)", datadev);
184         timeout = UATH_DATA_TIMEOUT;
185         if (ioctl(data, USB_SET_TX_TIMEOUT, &timeout) < 0)
186                 err(-1, "%s: USB_SET_TX_TIMEOUT(%u)", datadev,
187                     UATH_DATA_TIMEOUT);
188
189         VERBOSE("Load firmware %s to %s\n", fwname, udevname);
190
191         bzero(&txmsg, sizeof (struct uath_fwmsg));
192         txmsg.flags = htobe32(UATH_WRITE_BLOCK);
193         txmsg.total = htobe32(len);
194
195         b = 0;
196         while (len > 0) {
197                 int mlen;
198
199                 mlen = len;
200                 if (mlen > UATH_MAX_FWBLOCK_SIZE)
201                         mlen = UATH_MAX_FWBLOCK_SIZE;
202                 txmsg.remain = htobe32(len - mlen);
203                 txmsg.len = htobe32(mlen);
204
205                 /* send firmware block meta-data */
206                 VERBOSE("send block %2u: %zd bytes remaining", b, len - mlen);
207                 if (write(msg, &txmsg, sizeof(txmsg)) != sizeof(txmsg)) {
208                         VERBOSE("%s", "\n");
209                         err(-1, "error sending msg (%s)", msgdev);
210                         break;
211                 }
212
213                 /* send firmware block data */
214                 VERBOSE("%s", "\n             : data...");
215                 if (write(data, txdata, mlen) != mlen) {
216                         VERBOSE("%s", "\n");
217                         err(-1, "error sending data (%s)", datadev);
218                         break;
219                 }
220
221                 /* wait for ack from firmware */
222                 VERBOSE("%s", "\n             : wait for ack...");
223                 bzero(&rxmsg, sizeof(rxmsg));
224                 if (read(msg, &rxmsg, sizeof(rxmsg)) != sizeof(rxmsg)) {
225                         VERBOSE("%s", "\n");
226                         err(-1, "error reading msg (%s)", msgdev);
227                         break;
228                 }
229
230                 VERBOSE("flags=0x%x total=%d\n",
231                     be32toh(rxmsg.flags), be32toh(rxmsg.rxtotal));
232                 len -= mlen;
233                 txdata += mlen;
234                 b++;
235         }
236         sleep(1);
237         close(fw);
238         close(msg);
239         close(data);
240         return 0;
241 }