summaryrefslogtreecommitdiffstats
path: root/usr.sbin/uathload
diff options
context:
space:
mode:
authorweongyo <weongyo@FreeBSD.org>2009-04-04 11:23:00 +0000
committerweongyo <weongyo@FreeBSD.org>2009-04-04 11:23:00 +0000
commit3503cf99e3ac0111488d2a57341ab1b1088e2436 (patch)
tree8b2fbce8a0fa2518727f2da53f24794b7e8c2bc7 /usr.sbin/uathload
parentc9498bd9af0d2f300a586f4f9f0e78ed8f34de0e (diff)
downloadFreeBSD-src-3503cf99e3ac0111488d2a57341ab1b1088e2436.zip
FreeBSD-src-3503cf99e3ac0111488d2a57341ab1b1088e2436.tar.gz
Add uath(4) wireless USB driver for Atheros AR5005UG and AR5005UX
chipsets. Reviewed by: sam
Diffstat (limited to 'usr.sbin/uathload')
-rw-r--r--usr.sbin/uathload/Makefile18
-rw-r--r--usr.sbin/uathload/uathload.c233
2 files changed, 251 insertions, 0 deletions
diff --git a/usr.sbin/uathload/Makefile b/usr.sbin/uathload/Makefile
new file mode 100644
index 0000000..ef29ecd
--- /dev/null
+++ b/usr.sbin/uathload/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+PROG= uathload
+NO_MAN=
+
+SRCS= uathload.c ar5523.bin
+
+WARNS?= 4
+
+CLEANFILES= ar5523.bin
+
+ar5523.bin: ${.CURDIR}/../../sys/contrib/dev/uath/ar5523.bin.uu
+ uudecode -p ${.CURDIR}/../../sys/contrib/dev/uath/ar5523.bin.uu > ${.TARGET}
+
+ar5523.o: ar5523.bin
+ ${LD} -b binary -d -warn-common -r -d -o ${.TARGET} ar5523.bin
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/uathload/uathload.c b/usr.sbin/uathload/uathload.c
new file mode 100644
index 0000000..64ae661
--- /dev/null
+++ b/usr.sbin/uathload/uathload.c
@@ -0,0 +1,233 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Atheros AR5523 USB Station Firmware downloader.
+ *
+ * uathload -d ugen-device [firmware-file]
+ *
+ * Intended to be called from devd on device discovery.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/endian.h>
+#include <sys/mman.h>
+
+#include <sys/ioctl.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_ioctl.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+/* all fields are big endian */
+struct uath_fwmsg {
+ uint32_t flags;
+#define UATH_WRITE_BLOCK (1 << 4)
+
+ uint32_t len;
+#define UATH_MAX_FWBLOCK_SIZE 2048
+
+ uint32_t total;
+ uint32_t remain;
+ uint32_t rxtotal;
+ uint32_t pad[123];
+} __packed;
+
+#define UATH_DATA_TIMEOUT 10000
+#define UATH_CMD_TIMEOUT 1000
+
+#define VERBOSE(_fmt, ...) do { \
+ if (verbose) { \
+ printf(_fmt, __VA_ARGS__); \
+ fflush(stdout); \
+ } \
+} while (0)
+
+extern uint8_t _binary_ar5523_bin_start;
+extern uint8_t _binary_ar5523_bin_end;
+
+static int
+getdevname(const char *devname, char *msgdev, char *datadev)
+{
+ char *bn, *dn;
+
+ dn = dirname(devname);
+ if (dn == NULL)
+ return (-1);
+ bn = basename(devname);
+ if (bn == NULL || strncmp(bn, "ugen", 4))
+ return (-1);
+ bn += 4;
+
+ /* NB: pipes are hardcoded */
+ snprintf(msgdev, 256, "%s/usb/%s.1", dn, bn);
+ snprintf(datadev, 256, "%s/usb/%s.2", dn, bn);
+ return (0);
+}
+
+static void
+usage(void)
+{
+ errx(-1, "usage: uathload [-v] -d devname [firmware]");
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *fwname, *devname;
+ char msgdev[256], datadev[256];
+ struct uath_fwmsg txmsg, rxmsg;
+ char *txdata;
+ struct stat sb;
+ int msg, data, fw, timeout, b, c;
+ int bufsize = 512, verbose = 0;
+ ssize_t len;
+
+ devname = NULL;
+ while ((c = getopt(argc, argv, "d:v")) != -1) {
+ switch (c) {
+ case 'd':
+ devname = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (devname == NULL)
+ errx(-1, "No device name; use -d to specify the ugen device");
+ if (argc > 1)
+ usage();
+
+ if (argc == 1) {
+ fwname = argv[0];
+ fw = open(fwname, O_RDONLY, 0);
+ if (fw < 0)
+ err(-1, "open(%s)", fwname);
+ if (fstat(fw, &sb) < 0)
+ err(-1, "fstat(%s)", fwname);
+ txdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fw, 0);
+ if (txdata == MAP_FAILED)
+ err(-1, "mmap(%s)", fwname);
+ len = sb.st_size;
+ } else {
+ fwname = "ar5523.bin (builtin)";
+ fw = -1;
+ txdata = &_binary_ar5523_bin_start;
+ len = &_binary_ar5523_bin_end - &_binary_ar5523_bin_start;
+ }
+ /* XXX verify device is an AR5005 part */
+ if (getdevname(devname, msgdev, datadev))
+ err(-1, "getdevname error");
+
+ msg = open(msgdev, O_RDWR, 0);
+ if (msg < 0)
+ err(-1, "open(%s)", msgdev);
+ timeout = UATH_DATA_TIMEOUT;
+ if (ioctl(msg, USB_SET_RX_TIMEOUT, &timeout) < 0)
+ err(-1, "%s: USB_SET_RX_TIMEOUT(%u)", msgdev, UATH_DATA_TIMEOUT);
+ if (ioctl(msg, USB_SET_RX_BUFFER_SIZE, &bufsize) < 0)
+ err(-1, "%s: USB_SET_RX_BUFFER_SIZE(%u)", msgdev, bufsize);
+
+ data = open(datadev, O_WRONLY, 0);
+ if (data < 0)
+ err(-1, "open(%s)", datadev);
+ timeout = UATH_DATA_TIMEOUT;
+ if (ioctl(data, USB_SET_TX_TIMEOUT, &timeout) < 0)
+ err(-1, "%s: USB_SET_TX_TIMEOUT(%u)", datadev,
+ UATH_DATA_TIMEOUT);
+
+ VERBOSE("Load firmware %s to %s\n", fwname, devname);
+
+ bzero(&txmsg, sizeof (struct uath_fwmsg));
+ txmsg.flags = htobe32(UATH_WRITE_BLOCK);
+ txmsg.total = htobe32(len);
+
+ b = 0;
+ while (len > 0) {
+ int mlen;
+
+ mlen = len;
+ if (mlen > UATH_MAX_FWBLOCK_SIZE)
+ mlen = UATH_MAX_FWBLOCK_SIZE;
+ txmsg.remain = htobe32(len - mlen);
+ txmsg.len = htobe32(mlen);
+
+ /* send firmware block meta-data */
+ VERBOSE("send block %2u: %zd bytes remaining", b, len - mlen);
+ if (write(msg, &txmsg, sizeof(txmsg)) != sizeof(txmsg)) {
+ VERBOSE("%s", "\n");
+ err(-1, "error sending msg (%s)", msgdev);
+ break;
+ }
+
+ /* send firmware block data */
+ VERBOSE("%s", "\n : data...");
+ if (write(data, txdata, mlen) != mlen) {
+ VERBOSE("%s", "\n");
+ err(-1, "error sending data (%s)", datadev);
+ break;
+ }
+
+ /* wait for ack from firmware */
+ VERBOSE("%s", "\n : wait for ack...");
+ bzero(&rxmsg, sizeof(rxmsg));
+ if (read(msg, &rxmsg, sizeof(rxmsg)) != sizeof(rxmsg)) {
+ VERBOSE("%s", "\n");
+ err(-1, "error reading msg (%s)", msgdev);
+ break;
+ }
+
+ VERBOSE("flags=0x%x total=%d\n",
+ be32toh(rxmsg.flags), be32toh(rxmsg.rxtotal));
+ len -= mlen;
+ txdata += mlen;
+ b++;
+ }
+ sleep(1);
+ close(fw);
+ close(msg);
+ close(data);
+ return 0;
+}
OpenPOWER on IntegriCloud