diff options
Diffstat (limited to 'carl9170fw/tools/carlu/src/usb.c')
-rw-r--r-- | carl9170fw/tools/carlu/src/usb.c | 793 |
1 files changed, 0 insertions, 793 deletions
diff --git a/carl9170fw/tools/carlu/src/usb.c b/carl9170fw/tools/carlu/src/usb.c deleted file mode 100644 index ebc19a9..0000000 --- a/carl9170fw/tools/carlu/src/usb.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * carlu - userspace testing utility for ar9170 devices - * - * USB back-end driver - * - * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <stdbool.h> -#include <stdlib.h> -#include <errno.h> -#include <stdlib.h> -#include "libusb.h" - -#include "carlu.h" -#include "usb.h" -#include "debug.h" -#include "list.h" -#include "cmd.h" - -#define ADD_DEV(_vid, _pid, _vs, _ps) { \ - .idVendor = _vid, \ - .idProduct = _pid, \ - .vendor_name = _vs, \ - .product_name = _ps \ -} - -static const struct { - uint16_t idVendor; - uint16_t idProduct; - char *vendor_name; - char *product_name; -} dev_list[] = { - ADD_DEV(0x0cf3, 0x9170, "Atheros", "9170"), - ADD_DEV(0x0cf3, 0x1001, "Atheros", "TG121N"), - ADD_DEV(0x0cf3, 0x1002, "TP-Link", "TL-WN821N v2"), - ADD_DEV(0xcace, 0x0300, "Cace", "Airpcap NX"), - ADD_DEV(0x07d1, 0x3c10, "D-Link", "DWA 160 A1"), - ADD_DEV(0x07d1, 0x3a09, "D-Link", "DWA 160 A2"), - ADD_DEV(0x0846, 0x9010, "Netgear", "WNDA3100"), - ADD_DEV(0x0846, 0x9001, "Netgear", "WN111 v2"), - ADD_DEV(0x0ace, 0x1221, "Zydas", "ZD1221"), - ADD_DEV(0x0586, 0x3417, "ZyXEL", "NWD271N"), - ADD_DEV(0x0cde, 0x0023, "Z-Com", "UB81 BG"), - ADD_DEV(0x0cde, 0x0026, "Z-Com", "UB82 ABG"), - ADD_DEV(0x0cde, 0x0027, "Sphairon", "Homelink 1202"), - ADD_DEV(0x083a, 0xf522, "Arcadyan", "WN7512"), - ADD_DEV(0x2019, 0x5304, "Planex", "GWUS300"), - ADD_DEV(0x04bb, 0x093f, "IO-Data", "WNGDNUS2"), - ADD_DEV(0x057C, 0x8401, "AVM", "FRITZ!WLAN USB Stick N"), - ADD_DEV(0x057C, 0x8402, "AVM", "FRITZ!WLAN USB Stick N 2.4"), -}; - -static libusb_context *usb_ctx; -static LIST_HEAD(active_dev_list); - -static int carlusb_event_thread(void *_ar) -{ - struct carlu *ar = (void *)_ar; - dbg("event thread active and polling.\n"); - - while (!ar->stop_event_polling) - libusb_handle_events(ar->ctx); - - dbg("==> event thread desixed.\n"); - return 0; -} - -static int carlusb_is_ar9170(struct libusb_device_descriptor *desc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - if ((desc->idVendor == dev_list[i].idVendor) && - (desc->idProduct == dev_list[i].idProduct)) { - dbg("== found device \"%s %s\" [0x%04x:0x%04x]\n", - dev_list[i].vendor_name, dev_list[i].product_name, - desc->idVendor, desc->idProduct); - - return i; - } - } - - return -1; -} - -static bool carlusb_is_dev(struct carlu *iter, - struct libusb_device *dev) -{ - libusb_device *list_dev; - - if (!iter->dev) - return false; - - list_dev = libusb_get_device(iter->dev); - - if (libusb_get_bus_number(list_dev) == libusb_get_bus_number(dev) && - libusb_get_device_address(list_dev) == libusb_get_device_address(dev)) - return true; - - return false; -} - -int carlusb_show_devinfo(struct carlu *ar) -{ - struct libusb_device_descriptor desc; - libusb_device *dev; - int err; - - dev = libusb_get_device(ar->dev); - - err = libusb_get_device_descriptor(dev, &desc); - if (err) - return err; - - info("USB Device Information:\n"); - info("\tUSB VendorID:%.4x(%s), ProductID:%.4x(%s)\n", - dev_list[ar->idx].idVendor, dev_list[ar->idx].vendor_name, - dev_list[ar->idx].idProduct, dev_list[ar->idx].product_name); - info("\tBus:%d Address:%d\n", libusb_get_bus_number(dev), - libusb_get_device_address(dev)); - - return 0; -} - -static int carlusb_get_dev(struct carlu *ar, bool reset) -{ - struct carlu *iter; - libusb_device_handle *dev; - libusb_device **list; - int ret, err, i, idx = -1; - - ret = libusb_get_device_list(usb_ctx, &list); - if (ret < 0) { - err("usb device enum failed (%d)\n", ret); - return ret; - } - - for (i = 0; i < ret; i++) { - struct libusb_device_descriptor desc; - - memset(&desc, 0, sizeof(desc)); - err = libusb_get_device_descriptor(list[i], &desc); - if (err != 0) - continue; - - idx = carlusb_is_ar9170(&desc); - if (idx < 0) - continue; - - list_for_each_entry(iter, &active_dev_list, dev_list) { - if (carlusb_is_dev(iter, list[i])) { - err = -EALREADY; - break; - } - } - - if (err) - continue; - - err = libusb_open(list[i], &dev); - if (err != 0) { - err("failed to open device (%d)\n", err); - continue; - } - - err = libusb_kernel_driver_active(dev, 0); - switch (err) { - case 0: - break; - default: - err("failed to aquire exculusive access (%d).\n", err); - goto skip; - } - - if (reset) { - err = libusb_reset_device(dev); - if (err != 0) { - err("failed to reset device (%d)\n", err); - goto skip; - } - } - - err = libusb_claim_interface(dev, 0); - if (err == 0) { - dbg(">device is now under our control.\n"); - break; - } else { - err("failed to claim device (%d)\n", err); - goto skip; - } - -skip: - libusb_close(dev); - } - - if (i != ret) { - ar->idx = idx; - ar->ctx = usb_ctx; - ar->dev = dev; - list_add_tail(&ar->dev_list, &active_dev_list); - ret = 0; - } else { - ret = -ENODEV; - } - - libusb_free_device_list(list, 1); - return ret; -} - -static void carlusb_tx_cb(struct carlu *ar, - struct frame *frame) -{ - if (ar->tx_cb) - ar->tx_cb(ar, frame); - - ar->tx_octets += frame->len; - - carlu_free_frame(ar, frame); -} - -static void carlusb_zap_queues(struct carlu *ar) -{ - struct frame *frame; - - BUG_ON(SDL_mutexP(ar->tx_queue_lock) != 0); - while (!list_empty(&ar->tx_queue)) { - frame = list_first_entry(&ar->tx_queue, struct frame, dcb.list); - list_del(&frame->dcb.list); - carlusb_tx_cb(ar, frame); - } - SDL_mutexV(ar->tx_queue_lock); -} - -static void carlusb_free_driver(struct carlu *ar) -{ - if (!IS_ERR_OR_NULL(ar)) { - if (ar->event_pipe[0] > -1) - close(ar->event_pipe[0]); - - if (ar->event_pipe[1] > -1) - close(ar->event_pipe[1]); - - carlusb_zap_queues(ar); - carlfw_release(ar->fw); - ar->fw = NULL; - - if (ar->dev) { - libusb_release_interface(ar->dev, 0); - libusb_close(ar->dev); - ar->dev = NULL; - } - carlu_free_driver(ar); - } -} - -static int carlusb_init(struct carlu *ar) -{ - init_list_head(&ar->tx_queue); - ar->tx_queue_lock = SDL_CreateMutex(); - ar->event_pipe[0] = ar->event_pipe[1] = -1; - - return 0; -} - -static struct carlu *carlusb_open(void) -{ - struct carlu *tmp; - int err; - - tmp = carlu_alloc_driver(sizeof(*tmp)); - if (tmp == NULL) - return NULL; - - err = carlusb_init(tmp); - if (err < 0) - goto err_out; - - err = carlusb_get_dev(tmp, true); - if (err < 0) - goto err_out; - - return tmp; - -err_out: - carlusb_free_driver(tmp); - return ERR_PTR(err); -} - -static void carlusb_cancel_rings(struct carlu *ar) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ar->rx_ring); i++) - libusb_cancel_transfer(ar->rx_ring[i]); - - libusb_cancel_transfer(ar->rx_interrupt); -} - -static void carlusb_free_rings(struct carlu *ar) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ar->rx_ring); i++) - libusb_free_transfer(ar->rx_ring[i]); - - libusb_free_transfer(ar->rx_interrupt); -} - -static void carlusb_destroy(struct carlu *ar) -{ - int event_thread_status; - - dbg("==>release device.\n"); - - ar->stop_event_polling = true; - - carlusb_cancel_rings(ar); - - SDL_WaitThread(ar->event_thread, &event_thread_status); - - carlusb_free_rings(ar); - list_del(&ar->dev_list); -} - -static void carlusb_tx_bulk_cb(struct libusb_transfer *transfer); - -static void carlusb_tx_pending(struct carlu *ar) -{ - struct frame *frame; - struct libusb_transfer *urb; - int err; - - BUG_ON(SDL_mutexP(ar->tx_queue_lock) != 0); - if (ar->tx_queue_len >= (AR9170_TX_MAX_ACTIVE_URBS) || - list_empty(&ar->tx_queue)) - goto out; - - ar->tx_queue_len++; - - urb = libusb_alloc_transfer(0); - if (urb == NULL) - goto out; - - frame = list_first_entry(&ar->tx_queue, struct frame, dcb.list); - list_del(&frame->dcb.list); - - if (ar->tx_stream) { - struct ar9170_stream *tx_stream; - - tx_stream = frame_push(frame, sizeof(*tx_stream)); - tx_stream->length = cpu_to_le16(frame->len); - tx_stream->tag = cpu_to_le16(0x697e); - } - - libusb_fill_bulk_transfer(urb, ar->dev, AR9170_EP_TX, (unsigned char *) - frame->data, frame->len, carlusb_tx_bulk_cb, (void *)frame, 0); - - /* FIXME: ZERO_PACKET support! */ - urb->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; -/* urb->flags |= LIBUSB_TRANSFER_ZERO_PACKET; */ - frame->dev = (void *) ar; - frame_get(frame); - - err = libusb_submit_transfer(urb); - if (err != 0) { - err("->usb bulk tx submit failed (%d).\n", err); - libusb_free_transfer(urb); - } - -out: - SDL_mutexV(ar->tx_queue_lock); - return; -} - -void carlusb_tx(struct carlu *ar, struct frame *frame) -{ - BUG_ON(SDL_mutexP(ar->tx_queue_lock) != 0); - - list_add_tail(&frame->dcb.list, &ar->tx_queue); - SDL_mutexV(ar->tx_queue_lock); - - carlusb_tx_pending(ar); -} - -static void carlusb_tx_bulk_cb(struct libusb_transfer *transfer) -{ - struct frame *frame = (void *) transfer->user_data; - struct carlu *ar = (void *) frame->dev; - - BUG_ON(SDL_mutexP(ar->tx_queue_lock) != 0); - ar->tx_queue_len--; - SDL_mutexV(ar->tx_queue_lock); - - if (ar->tx_stream) - frame_pull(frame, 4); - - carlusb_tx_cb(ar, frame); - carlusb_tx_pending(ar); -} - -static void carlusb_rx_interrupt_cb(struct libusb_transfer *transfer) -{ - struct carlu *ar = (void *) transfer->user_data; - int err; - - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - carlu_handle_command(ar, transfer->buffer, transfer->actual_length); - break; - - case LIBUSB_TRANSFER_CANCELLED: - return; - - default: - err("==>rx_irq urb died (%d)\n", transfer->status); - break; - } - - err = libusb_submit_transfer(transfer); - if (err != 0) - err("==>rx_irq urb resubmit failed (%d)\n", err); -} - -static void carlusb_rx_bulk_cb(struct libusb_transfer *transfer) -{ - struct frame *frame = (void *) transfer->user_data; - struct carlu *ar = (void *) frame->dev; - int err; - - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - frame_put(frame, transfer->actual_length); - - carlu_rx(ar, frame); - - frame_trim(frame, 0); - break; - - case LIBUSB_TRANSFER_CANCELLED: - return; - - default: - err("==>rx_bulk urb died (%d)\n", transfer->status); - break; - } - - err = libusb_submit_transfer(transfer); - if (err != 0) - err("->rx_bulk urb resubmit failed (%d)\n", err); -} - -static int carlusb_initialize_rxirq(struct carlu *ar) -{ - int err; - - ar->rx_interrupt = libusb_alloc_transfer(0); - if (ar->rx_interrupt == NULL) { - err("==>cannot alloc rx interrupt urb\n"); - return -1; - } - - libusb_fill_interrupt_transfer(ar->rx_interrupt, ar->dev, AR9170_EP_IRQ, - (unsigned char *)&ar->irq_buf, sizeof(ar->irq_buf), - carlusb_rx_interrupt_cb, (void *) ar, 0); - - err = libusb_submit_transfer(ar->rx_interrupt); - if (err != 0) { - err("==>failed to submit rx interrupt (%d)\n", err); - return err; - } - - dbg("rx interrupt is now operational.\n"); - return 0; -} - -static int carlusb_initialize_rxrings(struct carlu *ar) -{ - struct frame *tmp; - unsigned int i; - int err; - - for (i = 0; i < ARRAY_SIZE(ar->rx_ring); i++) { - tmp = frame_alloc(ar->rx_max); - if (tmp == NULL) - return -ENOMEM; - - tmp->dev = (void *) ar; - - ar->rx_ring[i] = libusb_alloc_transfer(0); - if (ar->rx_ring[i] == NULL) { - frame_free(tmp); - return -ENOMEM; - } - - libusb_fill_bulk_transfer(ar->rx_ring[i], ar->dev, - AR9170_EP_RX, (unsigned char *)tmp->data, - ar->rx_max, carlusb_rx_bulk_cb, (void *)tmp, 0); - - err = libusb_submit_transfer(ar->rx_ring[i]); - if (err != 0) { - err("==>failed to submit rx buld urb (%d)\n", err); - return EXIT_FAILURE; - } - } - - dbg("rx ring is now ready to receive.\n"); - return 0; -} - -static int carlusb_load_firmware(struct carlu *ar) -{ - int ret = 0; - - dbg("loading firmware...\n"); - - ar->fw = carlfw_load(CARL9170_FIRMWARE_FILE); - if (IS_ERR_OR_NULL(ar->fw)) - return PTR_ERR(ar->fw); - - ret = carlu_fw_check(ar); - if (ret) - return ret; - - ret = carlusb_fw_check(ar); - if (ret) - return ret; - - return 0; -} - -static int carlusb_upload_firmware(struct carlu *ar, bool boot) -{ - uint32_t addr = 0x200000; - size_t len; - void *buf; - int ret = 0; - - dbg("initiating firmware image upload procedure.\n"); - - buf = carlfw_get_fw(ar->fw, &len); - if (IS_ERR_OR_NULL(buf)) - return PTR_ERR(buf); - - if (ar->miniboot_size) { - dbg("Miniboot firmware size:%d\n", ar->miniboot_size); - len -= ar->miniboot_size; - buf += ar->miniboot_size; - } - - while (len) { - int blocklen = len > 4096 ? 4096 : len; - - ret = libusb_control_transfer(ar->dev, 0x40, 0x30, addr >> 8, 0, buf, blocklen, 1000); - if (ret != blocklen && ret != LIBUSB_ERROR_TIMEOUT) { - err("==>firmware upload failed (%d)\n", ret); - return -EXIT_FAILURE; - } - - dbg("uploaded %d bytes to start address 0x%04x.\n", blocklen, addr); - - buf += blocklen; - addr += blocklen; - len -= blocklen; - } - - if (boot) { - ret = libusb_control_transfer(ar->dev, 0x40, 0x31, 0, 0, NULL, 0, 5000); - if (ret < 0) { - err("unable to boot firmware (%d)\n", ret); - return -EXIT_FAILURE; - } - - /* give the firmware some time to reset & reboot */ - SDL_Delay(100); - - /* - * since the device did a full usb reset, - * we have to get a new "dev". - */ - libusb_release_interface(ar->dev, 0); - libusb_close(ar->dev); - ar->dev = NULL; - list_del(&ar->dev_list); - - ret = carlusb_get_dev(ar, false); - } - - return 0; -} - -int carlusb_cmd_async(struct carlu *ar, struct carl9170_cmd *cmd, - const bool free_buf) -{ - struct libusb_transfer *urb; - int ret, send; - - if (cmd->hdr.len > (CARL9170_MAX_CMD_LEN - 4)) { - err("|-> too much payload\n"); - ret = -EINVAL; - goto out; - } - - if (cmd->hdr.len % 4) { - err("|-> invalid command length\n"); - ret = -EINVAL; - goto out; - } - - ret = libusb_interrupt_transfer(ar->dev, AR9170_EP_CMD, (void *) cmd, cmd->hdr.len + 4, &send, 32); - if (ret != 0) { - err("OID:0x%.2x failed due to (%d) (%d).\n", cmd->hdr.cmd, ret, send); - print_hex_dump_bytes(ERROR, "CMD:", cmd, cmd->hdr.len); - } - -out: - if (free_buf) - free((void *)cmd); - - return ret; -} - -int carlusb_cmd(struct carlu *ar, uint8_t oid, - uint8_t *cmd, size_t clen, - uint8_t *rsp, size_t rlen) -{ - int ret, send; - - if (clen > (CARL9170_MAX_CMD_LEN - 4)) { - err("|-> OID:0x%.2x has too much payload (%d octs)\n", oid, (int)clen); - return -EINVAL; - } - - ret = SDL_mutexP(ar->resp_lock); - if (ret != 0) { - err("failed to acquire resp_lock.\n"); - print_hex_dump_bytes(ERROR, "CMD:", ar->cmd.buf, clen); - return -1; - } - - ar->cmd.cmd.hdr.len = clen; - ar->cmd.cmd.hdr.cmd = oid; - /* buf[2] & buf[3] are padding */ - if (clen && cmd != (uint8_t *)(&ar->cmd.cmd.data)) - memcpy(&ar->cmd.cmd.data, cmd, clen); - - ar->resp_buf = (uint8_t *)rsp; - ar->resp_len = rlen; - - ret = carlusb_cmd_async(ar, &ar->cmd.cmd, false); - if (ret != 0) { - err("OID:0x%.2x failed due to (%d) (%d).\n", oid, ret, send); - print_hex_dump_bytes(ERROR, "CMD:", ar->cmd.buf, clen); - SDL_mutexV(ar->resp_lock); - return ret; - } - - ret = SDL_CondWaitTimeout(ar->resp_pend, ar->resp_lock, 100); - if (ret != 0) { - err("|-> OID:0x%.2x timed out %d.\n", oid, ret); - ar->resp_buf = NULL; - ar->resp_len = 0; - ret = -ETIMEDOUT; - } - - SDL_mutexV(ar->resp_lock); - return ret; -} - -struct carlu *carlusb_probe(void) -{ - struct carlu *ar; - int ret = -ENOMEM; - - ar = carlusb_open(); - if (IS_ERR_OR_NULL(ar)) { - if (IS_ERR(ar)) - ret = PTR_ERR(ar); - goto err_out; - } - - ret = carlusb_show_devinfo(ar); - if (ret) - goto err_out; - - ret = carlusb_load_firmware(ar); - if (ret) - goto err_out; - - ret = pipe(ar->event_pipe); - if (ret) - goto err_out; - - ar->stop_event_polling = false; - ar->event_thread = SDL_CreateThread(carlusb_event_thread, ar); - - ret = carlusb_upload_firmware(ar, true); - if (ret) - goto err_kill; - - ret = carlusb_initialize_rxirq(ar); - if (ret) - goto err_kill; - - ret = carlusb_initialize_rxrings(ar); - if (ret) - goto err_kill; - - ret = carlu_cmd_echo(ar, 0x44110dee); - if (ret) { - err("echo test failed...\n"); - goto err_kill; - } - - info("firmware is active and running.\n"); - - carlu_fw_info(ar); - - return ar; - -err_kill: - carlusb_destroy(ar); - -err_out: - carlusb_free_driver(ar); - err("usb device rendezvous failed (%d).\n", ret); - return ERR_PTR(ret); -} - -void carlusb_close(struct carlu *ar) -{ - carlu_cmd_reboot(ar); - - carlusb_destroy(ar); - carlusb_free_driver(ar); -} - -int carlusb_print_known_devices(void) -{ - unsigned int i; - - debug_level = INFO; - - info("==> dumping known device list <==\n"); - for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - info("Vendor:\"%-9s\" Product:\"%-26s\" => USBID:[0x%04x:0x%04x]\n", - dev_list[i].vendor_name, dev_list[i].product_name, - dev_list[i].idVendor, dev_list[i].idProduct); - } - info("==> end of device list <==\n"); - - return EXIT_SUCCESS; -} - -int usb_init(void) -{ - int ret; - - ret = libusb_init(&usb_ctx); - if (ret != 0) { - err("failed to initialize usb subsystem (%d)\n", ret); - return ret; - } - - /* like a silent chatterbox! */ - libusb_set_debug(usb_ctx, 2); - - return 0; -} - -void usb_exit(void) -{ - libusb_exit(usb_ctx); -} |