/* Name: usbdrv.c
* Project: AVR USB driver
* Author: Christian Starkjohann
* Creation Date: 2004-12-29
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: Proprietary, free under certain conditions. See Documentation.
* This Revision: $Id: usbdrv.c 205 2006-06-23 19:01:45Z cs $
*/
//#include <avr/io.h>
//#include <avr/pgmspace.h>
#include <iarcompat.h>
#include "usbdrv.h"
#define DBG2(prefix, data, len)
#define DBG1(prefix, data, len)
/*
General Description:
This module implements the C-part of the USB driver. See usbdrv.h for a
documentation of the entire driver.
*/
#ifndef IAR_SECTION
#define IAR_SECTION(arg)
#define __no_init
#endif
/* The macro IAR_SECTION is a hack to allow IAR-cc compatibility. On gcc, it
* is defined to nothing. __no_init is required on IAR.
*/
/* ------------------------------------------------------------------------- */
/* raw USB registers / interface to assembler code: */
/* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */
__no_init uchar usbRxBuf[2][USB_BUFSIZE] __attribute__ ((section (USB_BUFFER_SECTION))) IAR_SECTION(USB_BUFFER_SECTION);///* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */
uchar usbNewDeviceAddr; /* device ID which should be set after status phase */
uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */
uchar usbInputBuf; /* ptr to raw buffer used for receiving */
uchar usbAppBuf; /* ptr to raw buffer passed to app for processing */
volatile schar usbRxLen; /* = 0; number of bytes in usbAppBuf; 0 means free */
uchar usbCurrentTok; /* last token received, if more than 1 rx endpoint: MSb=endpoint */
uchar usbRxToken; /* token for data we received; if more than 1 rx endpoint: MSb=endpoint */
uchar usbMsgLen = 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */
volatile schar usbTxLen = -1; /* number of bytes to transmit with next IN token */
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen == -1 */
#if USB_CFG_HAVE_INTRIN_ENDPOINT
volatile schar usbTxLen1 = -1; /* TX count for endpoint 1 */
uchar usbTxBuf1[USB_BUFSIZE];/* TX data for endpoint 1 */
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
volatile schar usbTxLen3 = -1; /* TX count for endpoint 1 */
uchar usbTxBuf3[USB_BUFSIZE];/* TX data for endpoint 1 */
#endif
#endif
uchar usbAckBuf[1] = {USBPID_ACK}; /* transmit buffer for ack tokens */
uchar usbNakBuf[1] = {USBPID_NAK}; /* transmit buffer for nak tokens */
/* USB status registers / not shared with asm code */
uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */
static uchar usbMsgFlags; /* flag values see below */
static uchar usbIsReset; /* = 0; USB bus is in reset phase */
#define USB_FLG_TX_PACKET (1<<0)
/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */
#define USB_FLG_MSGPTR_IS_ROM (1<<6)
#define USB_FLG_USE_DEFAULT_RW (1<<7)
/*
optimizing hints:
- do not post/pre inc/dec integer values in operations
- assign value of PRG_RDB() to register variables and don't use side effects in arg
- use narrow scope for variables which should be in X/Y/Z register
- assign char sized expressions to variables to force 8 bit arithmetics
*/
/* ------------------------------------------------------------------------- */
static PROGMEM char usbDescrDevice[] = { /* USB device descriptor */
18, /* sizeof(usbDescrDevice): length of descriptor in bytes */
USBDESCR_DEVICE, /* descriptor type */
0x01, 0x01, /* USB version supported */
USB_CFG_DEVICE_CLASS,
USB_CFG_DEVICE_SUBCLASS,
0, /* protocol */
8, /* max packet size */
USB_CFG_VENDOR_ID, /* 2 bytes */
USB_CFG_DEVICE_ID, /* 2 bytes */
USB_CFG_DEVICE_VERSION, /* 2 bytes */
#if USB_CFG_VENDOR_NAME_LEN
1, /* manufacturer string index */
#else
0, /* manufacturer string index */
#endif
#if USB_CFG_DEVICE_NAME_LEN
2, /* product string index */
#else
0, /* product string index */
#endif
#if USB_CFG_SERIAL_NUMBER_LENGTH
3, /* serial number string index */
#else
0, /* serial number string index */
#endif
1, /* number of configurations */
};
#if !USB_CFG_EXTERNAL_CONFIG_DESCRIPTOR_LENGH
#define USB_CFG_EXTERNAL_CONFIG_DESCRIPTOR_LENGH sizeof(usbDescrConfig)
static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
9, /* sizeof(usbDescrConfig): length of descriptor in bytes */
USBDESCR_CONFIG, /* descriptor type */
(18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
+ 9
#endif
), 0, /* total length of data returned (including inlined descriptors) */
1, /* number of interfaces in this configuration */
1, /* index of this configuration */
0, /* configuration name string index */
#if USB_CFG_IS_SELF_POWERED
USBATTR_SELFPOWER, /* attributes */
#else
USBATTR_BUSPOWER, /* attributes */
#endif
USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */
/* interface descriptor follows inline: */
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
USBDESCR_INTERFACE, /* descriptor type */
0, /* index of this interface */
0, /* alternate setting for this interface */
USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */
USB_CFG_INTERFACE_CLASS,
USB_CFG_INTERFACE_SUBCLASS,
USB_CFG_INTERFACE_PROTOCOL,
0, /* string index for interface */
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* HID descriptor */
9, /* sizeof(usbDescrHID): length of descriptor in bytes */
USBDESCR_HID, /* descriptor type: HID */
0x01, 0x01, /* BCD representation of HID version */
0x00, /* target country code */
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
0x22, /* descriptor type: report */
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
0x81, /* IN endpoint number 1 */
0x03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
#endif
};
#endif /* USB_CFG_EXTERNAL_CONFIG_DESCRIPTOR_LENGH */
static PROGMEM char usbDescrString0[] = { /* language descriptor */
4, /* sizeof(usbDescrString0): length of descriptor in bytes */
3, /* descriptor type */
0x09, 0x04, /* language index (0x0409 = US-English) */
};
#if USB_CFG_VENDOR_NAME_LEN
static PROGMEM int usbDescrString1[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
USB_CFG_VENDOR_NAME
};
#endif
#if USB_CFG_DEVICE_NAME_LEN
static PROGMEM int usbDescrString2[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
USB_CFG_DEVICE_NAME
};
#endif
/* We don't use prog_int or prog_int16_t for compatibility with various libc
* versions. Here's an other compatibility hack:
*/
#ifndef PRG_RDB
#define PRG_RDB(addr) pgm_read_byte(addr)
#endif
typedef union{
unsigned word;
uchar *ptr;
uchar bytes[2];
}converter_t;
/* We use this union to do type conversions. This is better optimized th