From 3503cf99e3ac0111488d2a57341ab1b1088e2436 Mon Sep 17 00:00:00 2001 From: weongyo Date: Sat, 4 Apr 2009 11:23:00 +0000 Subject: Add uath(4) wireless USB driver for Atheros AR5005UG and AR5005UX chipsets. Reviewed by: sam --- usr.sbin/uathload/Makefile | 18 ++++ usr.sbin/uathload/uathload.c | 233 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 usr.sbin/uathload/Makefile create mode 100644 usr.sbin/uathload/uathload.c (limited to 'usr.sbin/uathload') 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 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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; +} -- cgit v1.1