aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorproski <proski>2006-12-18 21:36:20 +0000
committerproski <proski>2006-12-18 21:36:20 +0000
commit224bc58990d90efe7a51c8550b45f9cee8d6493c (patch)
treefe91bca5cc629c92ec3e2d274043ed4f2a6dcecf
parent8a53ec0c7cc87121be0c98a9967dd1d0e7660dfd (diff)
Integrate at76_usbdfu.c into at76c503.c
at76_usbdfu.c was too small compared to at76c503.c, and there was no particular reason to keep it as a separate file. It's easier to deal with the changing kernel headers and the build system if the number of separate source files is kept to minimum.
-rw-r--r--Makefile4
-rw-r--r--at76_usbdfu.c319
-rw-r--r--at76c503.c284
3 files changed, 286 insertions, 321 deletions
diff --git a/Makefile b/Makefile
index 7e035c7..05f17c7 100644
--- a/Makefile
+++ b/Makefile
@@ -33,9 +33,9 @@ KERNELRELEASE = $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' \
obj-m = at76_usb.o
-at76_usb-objs = at76c503.o at76_usbdfu.o
+at76_usb-objs = at76c503.o
-SRCS = at76c503.c at76_usbdfu.c at76c503.h
+SRCS = at76c503.c at76c503.h
SPECFILE = at76c503a.spec
diff --git a/at76_usbdfu.c b/at76_usbdfu.c
deleted file mode 100644
index c0596fb..0000000
--- a/at76_usbdfu.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/* -*- linux-c -*- */
-/*
- * USB Device Firmware Upgrade (DFU) handler
- *
- * Copyright (c) 2003 Oliver Kurth
- * Copyright (c) 2004 Jörg Albert
- *
- * This file is part of the driver for WLAN USB devices based on the Atmel
- * AT76C503A/505/505A. See at76c503.h for details.
- *
- * 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.
- *
- * 2003_01_19 0.1:
- * - initial release
- *
- * TODO:
- * (someday)
- * - make a way for drivers to feed firmware data at download time (instead of
- * providing it all at once during register)
- * - procfs support for userland firmware downloaders
- * - Firmware upload (device-to-host) support
- */
-
-#ifndef AUTOCONF_INCLUDED
-#include <linux/config.h>
-#endif
-
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include "at76c503.h"
-
-/* DFU states */
-
-#define STATE_IDLE 0x00
-#define STATE_DETACH 0x01
-#define STATE_DFU_IDLE 0x02
-#define STATE_DFU_DOWNLOAD_SYNC 0x03
-#define STATE_DFU_DOWNLOAD_BUSY 0x04
-#define STATE_DFU_DOWNLOAD_IDLE 0x05
-#define STATE_DFU_MANIFEST_SYNC 0x06
-#define STATE_DFU_MANIFEST 0x07
-#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
-#define STATE_DFU_UPLOAD_IDLE 0x09
-#define STATE_DFU_ERROR 0x0a
-
-/* DFU commands */
-#define DFU_DETACH 0
-#define DFU_DNLOAD 1
-#define DFU_UPLOAD 2
-#define DFU_GETSTATUS 3
-#define DFU_CLRSTATUS 4
-#define DFU_GETSTATE 5
-#define DFU_ABORT 6
-
-struct dfu_status {
- unsigned char bStatus;
- unsigned char bwPollTimeout[3];
- unsigned char bState;
- unsigned char iString;
-} __attribute__ ((packed));
-
-
-/* driver independent download context */
-struct dfu_ctx {
- struct usb_device *udev;
- u8 dfu_state;
- struct dfu_status dfu_status;
- u8 *buf;
-};
-
-#define USB_SUCCESS(a) ((a) >= 0)
-
-#define DFU_PACKETSIZE 1024
-
-static
-int dfu_download_block(struct dfu_ctx *ctx, u8 *buffer,
- int bytes, int block)
-{
- int result;
- u8 *tmpbuf = ctx->buf;
- struct usb_device *udev = ctx->udev;
-
- dbg(DBG_DFU, "dfu_download_block(): buffer=%p, bytes=%d, block=%d", buffer, bytes, block);
-
- if(tmpbuf == NULL)
- return -ENOMEM;
-
- memcpy(tmpbuf, buffer, bytes);
-
- result = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
- DFU_DNLOAD,
- USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
- block, /* Value */
- 0, /* Index */
- tmpbuf, /* Buffer */
- bytes, /* Size */
- HZ);
- return result;
-}
-
-static
-int dfu_get_status(struct dfu_ctx *ctx, struct dfu_status *status)
-{
- int result;
- struct usb_device *udev = ctx->udev;
-
-// dbg(DBG_DFU, "dfu_get_status()");
-
- result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- DFU_GETSTATUS,
- USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
- 0, /* Value */
- 0, /* Index */
- status, /* Buffer */
- sizeof(struct dfu_status), /* Size */
- HZ);
-
- return result;
-}
-
-static
-u8 dfu_get_state(struct usb_device *udev, u8 *state)
-{
- int result;
-
-// dbg(DBG_DFU, "dfu_get_state()");
-
- result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- DFU_GETSTATE, /* Request */
- USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
- 0, /* Value */
- 0, /* Index */
- state, /* Buffer */
- 1, /* Size */
- HZ);
-
- return result;
-}
-
-static inline
-u32 __get_timeout(struct dfu_status *s)
-{
- unsigned long ret = 0;
-
- ret = (unsigned long) (s->bwPollTimeout[2] << 16);
- ret |= (unsigned long) (s->bwPollTimeout[1] << 8);
- ret |= (unsigned long) (s->bwPollTimeout[0]);
-
- return ret;
-}
-
-static
-struct dfu_ctx *dfu_alloc_ctx(struct usb_device *udev)
-{
- struct dfu_ctx *ctx;
-
- ctx = kmalloc(sizeof(struct dfu_ctx) + DFU_PACKETSIZE, GFP_KERNEL|GFP_DMA);
- if(ctx){
- ctx->udev = udev;
- ctx->buf = (u8 *)&(ctx[1]);
- }
- return ctx;
-}
-
-/* == PROC usbdfu_download ==
- if manifest_sync_timeout > 0 use this timeout (in msec) instead of the
- one reported by the device in state MANIFEST_SYNC */
-int usbdfu_download(struct usb_device *udev, u8 *dfu_buffer, u32 dfu_len,
- int manifest_sync_timeout)
-{
- struct dfu_ctx *ctx;
- struct dfu_status *dfu_stat_buf;
- int status = 0;
- int need_dfu_state = 1;
- int is_done = 0;
- u8 dfu_state = 0;
- u32 dfu_timeout = 0;
- int dfu_block_bytes = 0, dfu_bytes_left = dfu_len, dfu_buffer_offset = 0;
- int dfu_block_cnt = 0;
-
- dbg(DBG_DFU, "%s( %p, %u, %d)", __FUNCTION__, dfu_buffer,
- dfu_len, manifest_sync_timeout);
-
- if (dfu_len == 0) {
- err("FW Buffer length invalid!");
- return -EINVAL;
- }
-
- ctx = dfu_alloc_ctx(udev);
- if(ctx == NULL)
- return -ENOMEM;
-
- dfu_stat_buf = &ctx->dfu_status;
-
- do {
- if (need_dfu_state) {
- status = dfu_get_state(ctx->udev, &ctx->dfu_state);
- if (!USB_SUCCESS(status)) {
- err("DFU: Failed to get DFU state: %d", status);
- goto exit;
- }
- dfu_state = ctx->dfu_state;
- need_dfu_state = 0;
- }
-
- switch (dfu_state) {
- case STATE_DFU_DOWNLOAD_SYNC:
- dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
- status = dfu_get_status(ctx, dfu_stat_buf);
- if (USB_SUCCESS(status)) {
- dfu_state = dfu_stat_buf->bState;
- dfu_timeout = __get_timeout(dfu_stat_buf);
- need_dfu_state = 0;
- } else
- err("dfu_get_status failed with %d", status);
- break;
-
- case STATE_DFU_DOWNLOAD_BUSY:
- dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY");
- need_dfu_state = 1;
-
- if (dfu_timeout >= 0){
- dbg(DBG_DFU, "DFU: Resetting device");
- set_current_state( TASK_INTERRUPTIBLE );
- schedule_timeout(1+dfu_timeout*HZ/1000);
- }else
- dbg(DBG_DFU, "DFU: In progress");
-
- break;
-
- case STATE_DFU_DOWNLOAD_IDLE:
- dbg(DBG_DFU, "DOWNLOAD...");
- /* fall through */
- case STATE_DFU_IDLE:
- dbg(DBG_DFU, "DFU IDLE");
-
- if (dfu_bytes_left <= DFU_PACKETSIZE)
- dfu_block_bytes = dfu_bytes_left;
- else
- dfu_block_bytes = DFU_PACKETSIZE;
-
- dfu_bytes_left -= dfu_block_bytes;
- status = dfu_download_block(ctx,
- dfu_buffer +
- dfu_buffer_offset,
- dfu_block_bytes,
- dfu_block_cnt);
- dfu_buffer_offset += dfu_block_bytes;
- dfu_block_cnt++;
-
- if (!USB_SUCCESS(status))
- err("dfu_download_block failed with %d", status);
- need_dfu_state = 1;
- break;
-
- case STATE_DFU_MANIFEST_SYNC:
- dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");
-
- status = dfu_get_status(ctx, dfu_stat_buf);
-
- if (USB_SUCCESS(status)) {
- dfu_state = dfu_stat_buf->bState;
- dfu_timeout = __get_timeout(dfu_stat_buf);
- need_dfu_state = 0;
-
- /* override the timeout from the status response,
- needed for AT76C505A */
- if (manifest_sync_timeout > 0)
- dfu_timeout = manifest_sync_timeout;
-
- if (dfu_timeout >= 0){
- dbg(DBG_DFU, "DFU: Waiting for manifest phase");
-
- set_current_state( TASK_INTERRUPTIBLE );
- schedule_timeout((dfu_timeout*HZ+999)/1000);
- }else
- dbg(DBG_DFU, "DFU: In progress");
- }
- break;
-
- case STATE_DFU_MANIFEST:
- dbg(DBG_DFU, "STATE_DFU_MANIFEST");
- is_done = 1;
- break;
-
- case STATE_DFU_MANIFEST_WAIT_RESET:
- dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET");
-// usb_reset_device(udev);
- is_done = 1;
- break;
-
- case STATE_DFU_UPLOAD_IDLE:
- dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE");
- break;
-
- case STATE_DFU_ERROR:
- dbg(DBG_DFU, "STATE_DFU_ERROR");
-// usb_reset_device(udev);
- status = -EPIPE;
- break;
-
- default:
- dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
- status = -EINVAL;
- break;
- }
- } while (!is_done && USB_SUCCESS(status));
-
- exit:
- kfree(ctx);
- if (status < 0)
- return status;
- else
- return 0;
-}
-
diff --git a/at76c503.c b/at76c503.c
index 3172a60..e58c2f7 100644
--- a/at76c503.c
+++ b/at76c503.c
@@ -376,6 +376,290 @@ static void set_monitor_mode(struct at76c503 *dev, int use_prism);
/* second step of initialization (after fw download) */
static int init_new_device(struct at76c503 *dev);
+/* DFU states */
+#define STATE_IDLE 0x00
+#define STATE_DETACH 0x01
+#define STATE_DFU_IDLE 0x02
+#define STATE_DFU_DOWNLOAD_SYNC 0x03
+#define STATE_DFU_DOWNLOAD_BUSY 0x04
+#define STATE_DFU_DOWNLOAD_IDLE 0x05
+#define STATE_DFU_MANIFEST_SYNC 0x06
+#define STATE_DFU_MANIFEST 0x07
+#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
+#define STATE_DFU_UPLOAD_IDLE 0x09
+#define STATE_DFU_ERROR 0x0a
+
+/* DFU commands */
+#define DFU_DETACH 0
+#define DFU_DNLOAD 1
+#define DFU_UPLOAD 2
+#define DFU_GETSTATUS 3
+#define DFU_CLRSTATUS 4
+#define DFU_GETSTATE 5
+#define DFU_ABORT 6
+
+#define DFU_PACKETSIZE 1024
+
+#define USB_SUCCESS(a) ((a) >= 0)
+
+struct dfu_status {
+ unsigned char bStatus;
+ unsigned char bwPollTimeout[3];
+ unsigned char bState;
+ unsigned char iString;
+} __attribute__ ((packed));
+
+/* driver independent download context */
+struct dfu_ctx {
+ struct usb_device *udev;
+ u8 dfu_state;
+ struct dfu_status dfu_status;
+ u8 *buf;
+};
+
+
+static
+int dfu_download_block(struct dfu_ctx *ctx, u8 *buffer,
+ int bytes, int block)
+{
+ int result;
+ u8 *tmpbuf = ctx->buf;
+ struct usb_device *udev = ctx->udev;
+
+ dbg(DBG_DFU, "dfu_download_block(): buffer=%p, bytes=%d, block=%d", buffer, bytes, block);
+
+ if(tmpbuf == NULL)
+ return -ENOMEM;
+
+ memcpy(tmpbuf, buffer, bytes);
+
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+ DFU_DNLOAD,
+ USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
+ block, /* Value */
+ 0, /* Index */
+ tmpbuf, /* Buffer */
+ bytes, /* Size */
+ HZ);
+ return result;
+}
+
+static
+int dfu_get_status(struct dfu_ctx *ctx, struct dfu_status *status)
+{
+ int result;
+ struct usb_device *udev = ctx->udev;
+
+// dbg(DBG_DFU, "dfu_get_status()");
+
+ result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ DFU_GETSTATUS,
+ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ 0, /* Value */
+ 0, /* Index */
+ status, /* Buffer */
+ sizeof(struct dfu_status), /* Size */
+ HZ);
+
+ return result;
+}
+
+static
+u8 dfu_get_state(struct usb_device *udev, u8 *state)
+{
+ int result;
+
+// dbg(DBG_DFU, "dfu_get_state()");
+
+ result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ DFU_GETSTATE, /* Request */
+ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ 0, /* Value */
+ 0, /* Index */
+ state, /* Buffer */
+ 1, /* Size */
+ HZ);
+
+ return result;
+}
+
+static inline
+u32 __get_timeout(struct dfu_status *s)
+{
+ unsigned long ret = 0;
+
+ ret = (unsigned long) (s->bwPollTimeout[2] << 16);
+ ret |= (unsigned long) (s->bwPollTimeout[1] << 8);
+ ret |= (unsigned long) (s->bwPollTimeout[0]);
+
+ return ret;
+}
+
+static
+struct dfu_ctx *dfu_alloc_ctx(struct usb_device *udev)
+{
+ struct dfu_ctx *ctx;
+
+ ctx = kmalloc(sizeof(struct dfu_ctx) + DFU_PACKETSIZE, GFP_KERNEL|GFP_DMA);
+ if(ctx){
+ ctx->udev = udev;
+ ctx->buf = (u8 *)&(ctx[1]);
+ }
+ return ctx;
+}
+
+/* == PROC usbdfu_download ==
+ if manifest_sync_timeout > 0 use this timeout (in msec) instead of the
+ one reported by the device in state MANIFEST_SYNC */
+int usbdfu_download(struct usb_device *udev, u8 *dfu_buffer, u32 dfu_len,
+ int manifest_sync_timeout)
+{
+ struct dfu_ctx *ctx;
+ struct dfu_status *dfu_stat_buf;
+ int status = 0;
+ int need_dfu_state = 1;
+ int is_done = 0;
+ u8 dfu_state = 0;
+ u32 dfu_timeout = 0;
+ int dfu_block_bytes = 0, dfu_bytes_left = dfu_len, dfu_buffer_offset = 0;
+ int dfu_block_cnt = 0;
+
+ dbg(DBG_DFU, "%s( %p, %u, %d)", __FUNCTION__, dfu_buffer,
+ dfu_len, manifest_sync_timeout);
+
+ if (dfu_len == 0) {
+ err("FW Buffer length invalid!");
+ return -EINVAL;
+ }
+
+ ctx = dfu_alloc_ctx(udev);
+ if(ctx == NULL)
+ return -ENOMEM;
+
+ dfu_stat_buf = &ctx->dfu_status;
+
+ do {
+ if (need_dfu_state) {
+ status = dfu_get_state(ctx->udev, &ctx->dfu_state);
+ if (!USB_SUCCESS(status)) {
+ err("DFU: Failed to get DFU state: %d", status);
+ goto exit;
+ }
+ dfu_state = ctx->dfu_state;
+ need_dfu_state = 0;
+ }
+
+ switch (dfu_state) {
+ case STATE_DFU_DOWNLOAD_SYNC:
+ dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
+ status = dfu_get_status(ctx, dfu_stat_buf);
+ if (USB_SUCCESS(status)) {
+ dfu_state = dfu_stat_buf->bState;
+ dfu_timeout = __get_timeout(dfu_stat_buf);
+ need_dfu_state = 0;
+ } else
+ err("dfu_get_status failed with %d", status);
+ break;
+
+ case STATE_DFU_DOWNLOAD_BUSY:
+ dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY");
+ need_dfu_state = 1;
+
+ if (dfu_timeout >= 0){
+ dbg(DBG_DFU, "DFU: Resetting device");
+ set_current_state( TASK_INTERRUPTIBLE );
+ schedule_timeout(1+dfu_timeout*HZ/1000);
+ }else
+ dbg(DBG_DFU, "DFU: In progress");
+
+ break;
+
+ case STATE_DFU_DOWNLOAD_IDLE:
+ dbg(DBG_DFU, "DOWNLOAD...");
+ /* fall through */
+ case STATE_DFU_IDLE:
+ dbg(DBG_DFU, "DFU IDLE");
+
+ if (dfu_bytes_left <= DFU_PACKETSIZE)
+ dfu_block_bytes = dfu_bytes_left;
+ else
+ dfu_block_bytes = DFU_PACKETSIZE;
+
+ dfu_bytes_left -= dfu_block_bytes;
+ status = dfu_download_block(ctx,
+ dfu_buffer +
+ dfu_buffer_offset,
+ dfu_block_bytes,
+ dfu_block_cnt);
+ dfu_buffer_offset += dfu_block_bytes;
+ dfu_block_cnt++;
+
+ if (!USB_SUCCESS(status))
+ err("dfu_download_block failed with %d", status);
+ need_dfu_state = 1;
+ break;
+
+ case STATE_DFU_MANIFEST_SYNC:
+ dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");
+
+ status = dfu_get_status(ctx, dfu_stat_buf);
+
+ if (USB_SUCCESS(status)) {
+ dfu_state = dfu_stat_buf->bState;
+ dfu_timeout = __get_timeout(dfu_stat_buf);
+ need_dfu_state = 0;
+
+ /* override the timeout from the status response,
+ needed for AT76C505A */
+ if (manifest_sync_timeout > 0)
+ dfu_timeout = manifest_sync_timeout;
+
+ if (dfu_timeout >= 0){
+ dbg(DBG_DFU, "DFU: Waiting for manifest phase");
+
+ set_current_state( TASK_INTERRUPTIBLE );
+ schedule_timeout((dfu_timeout*HZ+999)/1000);
+ }else
+ dbg(DBG_DFU, "DFU: In progress");
+ }
+ break;
+
+ case STATE_DFU_MANIFEST:
+ dbg(DBG_DFU, "STATE_DFU_MANIFEST");
+ is_done = 1;
+ break;
+
+ case STATE_DFU_MANIFEST_WAIT_RESET:
+ dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET");
+// usb_reset_device(udev);
+ is_done = 1;
+ break;
+
+ case STATE_DFU_UPLOAD_IDLE:
+ dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE");
+ break;
+
+ case STATE_DFU_ERROR:
+ dbg(DBG_DFU, "STATE_DFU_ERROR");
+// usb_reset_device(udev);
+ status = -EPIPE;
+ break;
+
+ default:
+ dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
+ status = -EINVAL;
+ break;
+ }
+ } while (!is_done && USB_SUCCESS(status));
+
+ exit:
+ kfree(ctx);
+ if (status < 0)
+ return status;
+ else
+ return 0;
+}
+
/* some abbrev. for wireless events */
static inline void iwevent_scan_complete(struct net_device *dev)
{