Various USB related patches

- Add support for mpc8xx USB device.
- Add support for Common Device Class - Abstract Control Model USB console.
- Add support for flow control in USB slave devices.
- Add support for switching between gserial and cdc_acm using environment.
- Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h
- Update usbcore slightly to ease host enumeration.
- Fix non-portable endian problems in usbdcore and usbdcore_ep0.
- Add AdderUSB_config as a defconfig to enable usage of the USB console
  by default with the Adder87x U-Boot port.
Patches by Bryan O'Donoghue <bodonoghue@codehermit.ie>, 29 May 2006
This commit is contained in:
Wolfgang Denk 2006-06-14 17:45:53 +02:00
parent 81d72d7e2e
commit 16c8d5e76a
15 changed files with 2473 additions and 356 deletions

View File

@ -2,6 +2,18 @@
Changes since U-Boot 1.1.4:
======================================================================
* Various USB related patches
- Add support for mpc8xx USB device.
- Add support for Common Device Class - Abstract Control Model USB console.
- Add support for flow control in USB slave devices.
- Add support for switching between gserial and cdc_acm using environment.
- Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h
- Update usbcore slightly to ease host enumeration.
- Fix non-portable endian problems in usbdcore and usbdcore_ep0.
- Add AdderUSB_config as a defconfig to enable usage of the USB console
by default with the Adder87x U-Boot port.
Patch by Bryan O'Donoghue <bodonoghue@codehermit.ie>, 29 May 2006
* Fix PCI to memory window size problems on PM82x boards
We use the "automatic" mode that was used for the MPC8266ADS and
MPC8272 boards. Eventually this should be used on all boards?]

View File

@ -58,7 +58,7 @@ ifeq ($(HOSTARCH),ppc)
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = powerpc-linux-
CROSS_COMPILE = ppc_8xx-
endif
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
@ -437,6 +437,9 @@ AdderII_config \
@echo "#define CONFIG_MPC852T" > include/config.h)
@./mkconfig -a Adder ppc mpc8xx adder
AdderUSB_config: unconfig
@./mkconfig -a AdderUSB ppc mpc8xx adder
ADS860_config \
FADS823_config \
FADS850SAR_config \

62
README
View File

@ -862,7 +862,69 @@ The following options need to be configured:
for differential drivers: 0x00001000
for single ended drivers: 0x00005000
- USB Device:
Define the below if you wish to use the USB console.
Once firmware is rebuilt from a serial console issue the
command "setenv stdin usbtty; setenv stdout usbtty" and
attach your usb cable. The Unix command "dmesg" should print
it has found a new device. The environment variable usbtty
can be set to gserial or cdc_acm to enable your device to
appear to a USB host as a Linux gserial device or a
Common Device Class Abstract Control Model serial device.
If you select usbtty = gserial you should be able to enumerate
a Linux host by
# modprobe usbserial vendor=0xVendorID product=0xProductID
else if using cdc_acm, simply setting the environment
variable usbtty to be cdc_acm should suffice. The following
might be defined in YourBoardName.h
CONFIG_USB_DEVICE
Define this to build a UDC device
CONFIG_USB_TTY
Define this to have a tty type of device available to
talk to the UDC device
CFG_CONSOLE_IS_IN_ENV
Define this if you want stdin, stdout &/or stderr to
be set to usbtty.
mpc8xx:
CFG_USB_EXTC_CLK 0xBLAH
Derive USB clock from external clock "blah"
- CFG_USB_EXTC_CLK 0x02
CFG_USB_BRG_CLK 0xBLAH
Derive USB clock from brgclk
- CFG_USB_BRG_CLK 0x04
If you have a USB-IF assigned VendorID then you may wish to
define your own vendor specific values either in BoardName.h
or directly in usbd_vendor_info.h. If you don't define
CONFIG_USBD_MANUFACTURER, CONFIG_USBD_PRODUCT_NAME,
CONFIG_USBD_VENDORID and CONFIG_USBD_PRODUCTID, then U-Boot
should pretend to be a Linux device to it's target host.
CONFIG_USBD_MANUFACTURER
Define this string as the name of your company for
- CONFIG_USBD_MANUFACTURER "my company"
CONFIG_USBD_PRODUCT_NAME
Define this string as the name of your product
- CONFIG_USBD_PRODUCT_NAME "acme usb device"
CONFIG_USBD_VENDORID
Define this as your assigned Vendor ID from the USB
Implementors Forum. This *must* be a genuine Vendor ID
to avoid polluting the USB namespace.
- CONFIG_USBD_VENDORID 0xFFFF
CONFIG_USBD_PRODUCTID
Define this as the unique Product ID
for your device
- CONFIG_USBD_PRODUCTID 0xFFFF
- MMC Support:
The MMC controller on the Intel PXA is supported. To
enable this define CONFIG_MMC. The MMC can be

View File

@ -48,7 +48,7 @@ OBJS = 3c589.o 5701rls.o ali512x.o \
ti_pci1410a.o tigon3.o tsec.o \
usb_ohci.o usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \
videomodes.o w83c553f.o \
ks8695eth.o
ks8695eth.o usbdcore_mpc8xx.o
all: $(LIB)

View File

@ -2,6 +2,9 @@
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
*
* (C) Copyright 2006
* Bryan O'Donoghue, deckard@CodeHermit.ie
*
* Based on
* linux/drivers/usbd/ep0.c
*
@ -39,11 +42,17 @@
* function driver. This may need to change.
*
* XXX
*
* As alluded to above, a simple callback cdc_recv_setup has been implemented
* in the usb_device data structure to facilicate passing
* Common Device Class packets to a function driver.
*
* XXX
*/
#include <common.h>
#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
#if defined(CONFIG_USB_DEVICE)
#include "usbdcore.h"
#if 0
@ -69,7 +78,7 @@ static int ep0_get_status (struct usb_device_instance *device,
char *cp;
urb->actual_length = 2;
cp = urb->buffer;
cp = (char*)urb->buffer;
cp[0] = cp[1] = 0;
switch (requesttype) {
@ -115,7 +124,7 @@ static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
*
* Copy configuration data to urb transfer buffer if there is room for it.
*/
static void copy_config (struct urb *urb, void *data, int max_length,
void copy_config (struct urb *urb, void *data, int max_length,
int max_buf)
{
int available;
@ -128,10 +137,7 @@ static void copy_config (struct urb *urb, void *data, int max_length,
dbg_ep0 (1, "data is NULL");
return;
}
if (!(length = *(unsigned char *) data)) {
dbg_ep0 (1, "length is zero");
return;
}
length = max_length;
if (length > max_length) {
dbg_ep0 (1, "length: %d >= max_length: %d", length,
@ -192,7 +198,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
/* setup tx urb */
urb->actual_length = 0;
cp = urb->buffer;
cp = (char*)urb->buffer;
dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
@ -200,7 +206,6 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
case USB_DESCRIPTOR_TYPE_DEVICE:
{
struct usb_device_descriptor *device_descriptor;
if (!
(device_descriptor =
usbd_device_device_descriptor (device, port))) {
@ -214,20 +219,16 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
/* correct the correct control endpoint 0 max packet size into the descriptor */
device_descriptor =
(struct usb_device_descriptor *) urb->buffer;
device_descriptor->bMaxPacketSize0 =
urb->device->bus->maxpacketsize;
}
/*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
break;
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
{
int bNumInterface;
struct usb_configuration_descriptor
*configuration_descriptor;
struct usb_device_descriptor *device_descriptor;
if (!
(device_descriptor =
usbd_device_device_descriptor (device, port))) {
@ -251,130 +252,35 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
index);
return -1;
}
dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
copy_config (urb, configuration_descriptor,
sizeof (struct
usb_configuration_descriptor),
cpu_to_le16(configuration_descriptor->wTotalLength),
max);
/* iterate across interfaces for specified configuration */
dbg_ep0 (0, "bNumInterfaces: %d",
configuration_descriptor->bNumInterfaces);
for (bNumInterface = 0;
bNumInterface <
configuration_descriptor->bNumInterfaces;
bNumInterface++) {
int bAlternateSetting;
struct usb_interface_instance
*interface_instance;
dbg_ep0 (3, "[%d] bNumInterfaces: %d",
bNumInterface,
configuration_descriptor->bNumInterfaces);
if (! (interface_instance = usbd_device_interface_instance (device,
port, index, bNumInterface)))
{
dbg_ep0 (3, "[%d] interface_instance NULL",
bNumInterface);
return -1;
}
/* iterate across interface alternates */
for (bAlternateSetting = 0;
bAlternateSetting < interface_instance->alternates;
bAlternateSetting++) {
/*int class; */
int bNumEndpoint;
struct usb_interface_descriptor *interface_descriptor;
struct usb_alternate_instance *alternate_instance;
dbg_ep0 (3, "[%d:%d] alternates: %d",
bNumInterface,
bAlternateSetting,
interface_instance->alternates);
if (! (alternate_instance = usbd_device_alternate_instance (device, port, index, bNumInterface, bAlternateSetting))) {
dbg_ep0 (3, "[%d] alternate_instance NULL",
bNumInterface);
return -1;
}
/* copy descriptor for this interface */
copy_config (urb, alternate_instance->interface_descriptor,
sizeof (struct usb_interface_descriptor),
max);
/*dbg_ep0(3, "[%d:%d] classes: %d endpoints: %d", bNumInterface, bAlternateSetting, */
/* alternate_instance->classes, alternate_instance->endpoints); */
/* iterate across classes for this alternate interface */
#if 0
for (class = 0;
class < alternate_instance->classes;
class++) {
struct usb_class_descriptor *class_descriptor;
/*dbg_ep0(3, "[%d:%d:%d] classes: %d", bNumInterface, bAlternateSetting, */
/* class, alternate_instance->classes); */
if (!(class_descriptor = usbd_device_class_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, class))) {
dbg_ep0 (3, "[%d] class NULL",
class);
return -1;
}
/* copy descriptor for this class */
copy_config (urb, class_descriptor,
sizeof (struct usb_class_descriptor),
max);
}
#endif
/* iterate across endpoints for this alternate interface */
interface_descriptor = alternate_instance->interface_descriptor;
for (bNumEndpoint = 0;
bNumEndpoint < alternate_instance->endpoints;
bNumEndpoint++) {
struct usb_endpoint_descriptor *endpoint_descriptor;
dbg_ep0 (3, "[%d:%d:%d] endpoint: %d",
bNumInterface,
bAlternateSetting,
bNumEndpoint,
interface_descriptor->
bNumEndpoints);
if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, bNumEndpoint))) {
dbg_ep0 (3, "[%d] endpoint NULL",
bNumEndpoint);
return -1;
}
/* copy descriptor for this endpoint */
copy_config (urb, endpoint_descriptor,
sizeof (struct usb_endpoint_descriptor),
max);
}
}
}
dbg_ep0 (3, "lengths: %d %d",
le16_to_cpu (configuration_descriptor->wTotalLength),
urb->actual_length);
}
break;
case USB_DESCRIPTOR_TYPE_STRING:
{
struct usb_string_descriptor *string_descriptor;
if (!(string_descriptor = usbd_get_string (index))) {
serial_printf("Invalid string index %d\n", index);
return -1;
}
/*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */
dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);
copy_config (urb, string_descriptor, string_descriptor->bLength, max);
}
break;
case USB_DESCRIPTOR_TYPE_INTERFACE:
serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
return -1;
case USB_DESCRIPTOR_TYPE_ENDPOINT:
serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
return -1;
case USB_DESCRIPTOR_TYPE_HID:
{
serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
return -1; /* unsupported at this time */
#if 0
int bNumInterface =
@ -403,6 +309,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
break;
case USB_DESCRIPTOR_TYPE_REPORT:
{
serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
return -1; /* unsupported at this time */
#if 0
int bNumInterface =
@ -434,12 +341,19 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
#endif
}
break;
case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
{
/* If a USB device supports both a full speed and low speed operation
* we must send a Device_Qualifier descriptor here
*/
return -1;
}
default:
return -1;
}
dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d",
dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
urb->buffer, urb->buffer_length, urb->actual_length,
device->bus->endpoint_array[0].tx_packetSize);
/*
@ -495,6 +409,12 @@ int ep0_recv_setup (struct urb *urb)
/* handle USB Standard Request (c.f. USB Spec table 9-2) */
if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
if(device->device_state <= STATE_CONFIGURED){
/* Attempt to handle a CDC specific request if we are
* in the configured state.
*/
return device->cdc_recv_setup(request,urb);
}
dbg_ep0 (1, "non standard request: %x",
request->bmRequestType & USB_REQ_TYPE_MASK);
return -1; /* Stall here */
@ -567,6 +487,7 @@ int ep0_recv_setup (struct urb *urb)
le16_to_cpu (request->wValue) & 0xff);
case USB_REQ_GET_CONFIGURATION:
serial_printf("get config %d\n", device->configuration);
return ep0_get_one (device, urb,
device->configuration);
@ -642,7 +563,6 @@ int ep0_recv_setup (struct urb *urb)
/*dbg_ep0(2, "address: %d %d %d", */
/* request->wValue, le16_to_cpu(request->wValue), device->address); */
serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");
return 0;
case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */
@ -653,9 +573,10 @@ int ep0_recv_setup (struct urb *urb)
/* c.f. 9.4.7 - the top half of wValue is reserved */
/* */
if ((device->configuration =
le16_to_cpu (request->wValue) & 0x7f) != 0) {
le16_to_cpu (request->wValue) & 0xFF80) != 0) {
/* c.f. 9.4.7 - zero is the default or addressed state, in our case this */
/* is the same is configuration zero */
serial_printf("error setting dev->config to zero!\n");
device->configuration = 0; /* TBR - ?????? */
}
/* reset interface and alternate settings */

1412
drivers/usbdcore_mpc8xx.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -645,7 +645,7 @@ static void omap1510_udc_state_changed (void)
static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
{
UDCDBG ("-> Entering device setup");
do {
const int setup_pktsize = 8;
unsigned char *datap =
@ -1517,4 +1517,31 @@ void udc_startup_events (struct usb_device_instance *device)
udc_enable (device);
}
/**
* udc_irq - do pseudo interrupts
*/
void udc_irq(void)
{
/* Loop while we have interrupts.
* If we don't do this, the input chain
* polling delay is likely to miss
* host requests.
*/
while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
/* Handle any new IRQs */
omap1510_udc_irq ();
omap1510_udc_noniso_irq ();
}
}
/* Flow control */
void udc_set_nak(int epid)
{
/* TODO: implement this functionality in omap1510 */
}
void udc_unset_nak (int epid)
{
/* TODO: implement this functionality in omap1510 */
}
#endif

View File

@ -1,6 +1,9 @@
/*
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
*
* (C) Copyright 2006
* Bryan O'Donoghue, bodonoghue@codehermit.ie
*
* 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
@ -25,19 +28,41 @@
#include <circbuf.h>
#include <devices.h>
#include "usbtty.h"
#include "usb_cdc_acm.h"
#include "usbdescriptors.h"
#include <config.h> /* If defined, override Linux identifiers with
* vendor specific ones */
#if 0
#define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
#define TTYDBG(fmt,args...)\
serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
#else
#define TTYDBG(fmt,args...) do{}while(0)
#endif
#if 0
#define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
#if 1
#define TTYERR(fmt,args...)\
serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\
__LINE__,##args)
#else
#define TTYERR(fmt,args...) do{}while(0)
#endif
/*
* Defines
*/
#define NUM_CONFIGS 1
#define MAX_INTERFACES 2
#define NUM_ENDPOINTS 3
#define ACM_TX_ENDPOINT 3
#define ACM_RX_ENDPOINT 2
#define GSERIAL_TX_ENDPOINT 2
#define GSERIAL_RX_ENDPOINT 1
#define NUM_ACM_INTERFACES 2
#define NUM_GSERIAL_INTERFACES 1
#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface"
#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface"
/*
* Buffers to hold input and output data
*/
@ -50,157 +75,336 @@ static circbuf_t usbtty_output;
* Instance variables
*/
static device_t usbttydev;
static struct usb_device_instance device_instance[1];
static struct usb_bus_instance bus_instance[1];
static struct usb_device_instance device_instance[1];
static struct usb_bus_instance bus_instance[1];
static struct usb_configuration_instance config_instance[NUM_CONFIGS];
static struct usb_interface_instance interface_instance[NUM_INTERFACES];
static struct usb_alternate_instance alternate_instance[NUM_INTERFACES];
static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */
/*
* Static allocation of urbs
*/
#define RECV_ENDPOINT 1
#define TX_ENDPOINT 2
static struct usb_interface_instance interface_instance[MAX_INTERFACES];
static struct usb_alternate_instance alternate_instance[MAX_INTERFACES];
/* one extra for control endpoint */
static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];
/*
* Global flag
*/
int usbtty_configured_flag = 0;
/*
* Serial number
*/
static char serial_number[16];
/*
* Descriptors
* Descriptors, Strings, Local variables.
*/
/* defined and used by usbdcore_ep0.c */
extern struct usb_string_descriptor **usb_strings;
/* Indicies, References */
static unsigned short rx_endpoint = 0;
static unsigned short tx_endpoint = 0;
static unsigned short interface_count = 0;
static struct usb_string_descriptor *usbtty_string_table[STR_COUNT];
/* USB Descriptor Strings */
static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};
static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];
static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];
static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)];
static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)];
static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)];
static struct usb_string_descriptor *usbtty_string_table[] = {
(struct usb_string_descriptor*)wstrLang,
(struct usb_string_descriptor*)wstrManufacturer,
(struct usb_string_descriptor*)wstrProduct,
(struct usb_string_descriptor*)wstrSerial,
(struct usb_string_descriptor*)wstrConfiguration,
(struct usb_string_descriptor*)wstrInterface
};
extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */
static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
/* Standard USB Data Structures */
static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES];
static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
static struct usb_configuration_descriptor *configuration_descriptor = 0;
static struct usb_device_descriptor device_descriptor = {
bLength: sizeof(struct usb_device_descriptor),
bDescriptorType: USB_DT_DEVICE,
bcdUSB: USB_BCD_VERSION,
bDeviceClass: USBTTY_DEVICE_CLASS,
bDeviceSubClass: USBTTY_DEVICE_SUBCLASS,
bDeviceProtocol: USBTTY_DEVICE_PROTOCOL,
bMaxPacketSize0: EP0_MAX_PACKET_SIZE,
idVendor: CONFIG_USBD_VENDORID,
idProduct: CONFIG_USBD_PRODUCTID,
bcdDevice: USBTTY_BCD_DEVICE,
iManufacturer: STR_MANUFACTURER,
iProduct: STR_PRODUCT,
iSerialNumber: STR_SERIAL,
bNumConfigurations: NUM_CONFIGS
};
static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = {
{
bLength: sizeof(struct usb_configuration_descriptor),
bDescriptorType: USB_DT_CONFIG,
wTotalLength: (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) +
(sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) +
(sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS),
bNumInterfaces: NUM_INTERFACES,
bConfigurationValue: 1,
iConfiguration: STR_CONFIG,
bmAttributes: BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED,
bMaxPower: USBTTY_MAXPOWER
},
.bLength = sizeof(struct usb_device_descriptor),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = cpu_to_le16(USB_BCD_VERSION),
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
.idVendor = cpu_to_le16(CONFIG_USBD_VENDORID),
.bcdDevice = cpu_to_le16(USBTTY_BCD_DEVICE),
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIAL,
.bNumConfigurations = NUM_CONFIGS
};
static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = {
{
bLength: sizeof(struct usb_interface_descriptor),
bDescriptorType: USB_DT_INTERFACE,
bInterfaceNumber: 0,
bAlternateSetting: 0,
bNumEndpoints: NUM_ENDPOINTS,
bInterfaceClass: USBTTY_INTERFACE_CLASS,
bInterfaceSubClass: USBTTY_INTERFACE_SUBCLASS,
bInterfaceProtocol: USBTTY_INTERFACE_PROTOCOL,
iInterface: STR_INTERFACE
},
/*
* Static CDC ACM specific descriptors
*/
struct acm_config_desc {
struct usb_configuration_descriptor configuration_desc;
/* Master Interface */
struct usb_interface_descriptor interface_desc;
struct usb_class_header_function_descriptor usb_class_header;
struct usb_class_call_management_descriptor usb_class_call_mgt;
struct usb_class_abstract_control_descriptor usb_class_acm;
struct usb_class_union_function_descriptor usb_class_union;
struct usb_endpoint_descriptor notification_endpoint;
/* Slave Interface */
struct usb_interface_descriptor data_class_interface;
struct usb_endpoint_descriptor
data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed));
} __attribute__((packed));
static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = {
{
.configuration_desc ={
.bLength =
sizeof(struct usb_configuration_descriptor),
.bDescriptorType = USB_DT_CONFIG,
.wTotalLength =
cpu_to_le16(sizeof(struct acm_config_desc)),
.bNumInterfaces = NUM_ACM_INTERFACES,
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG,
.bmAttributes =
BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
.bMaxPower = USBTTY_MAXPOWER
},
/* Interface 1 */
.interface_desc = {
.bLength = sizeof(struct usb_interface_descriptor),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 0x01,
.bInterfaceClass =
COMMUNICATIONS_INTERFACE_CLASS_CONTROL,
.bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS,
.bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL,
.iInterface = STR_CTRL_INTERFACE,
},
.usb_class_header = {
.bFunctionLength =
sizeof(struct usb_class_header_function_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_ST_HEADER,
.bcdCDC = cpu_to_le16(110),
},
.usb_class_call_mgt = {
.bFunctionLength =
sizeof(struct usb_class_call_management_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_ST_CMF,
.bmCapabilities = 0x00,
.bDataInterface = 0x01,
},
.usb_class_acm = {
.bFunctionLength =
sizeof(struct usb_class_abstract_control_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_ST_ACMF,
.bmCapabilities = 0x00,
},
.usb_class_union = {
.bFunctionLength =
sizeof(struct usb_class_union_function_descriptor),
.bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_ST_UF,
.bMasterInterface = 0x00,
.bSlaveInterface0 = 0x01,
},
.notification_endpoint = {
.bLength =
sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x01 | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize
= cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
.bInterval = 0xFF,
},
/* Interface 2 */
.data_class_interface = {
.bLength =
sizeof(struct usb_interface_descriptor),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0x01,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass =
COMMUNICATIONS_INTERFACE_CLASS_DATA,
.bInterfaceSubClass = DATA_INTERFACE_SUBCLASS_NONE,
.bInterfaceProtocol = DATA_INTERFACE_PROTOCOL_NONE,
.iInterface = STR_DATA_INTERFACE,
},
.data_endpoints = {
{
.bLength =
sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x02 | USB_DIR_OUT,
.bmAttributes =
USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize =
cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
.bInterval = 0xFF,
},
{
.bLength =
sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x03 | USB_DIR_IN,
.bmAttributes =
USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize =
cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
.bInterval = 0xFF,
},
},
},
};
static struct rs232_emu rs232_desc={
.dter = 115200,
.stop_bits = 0x00,
.parity = 0x00,
.data_bits = 0x08
};
static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = {
{
bLength: sizeof(struct usb_endpoint_descriptor),
bDescriptorType: USB_DT_ENDPOINT,
bEndpointAddress: CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT,
bmAttributes: USB_ENDPOINT_XFER_BULK,
wMaxPacketSize: CONFIG_USBD_SERIAL_OUT_PKTSIZE,
bInterval: 0
},
{
bLength: sizeof(struct usb_endpoint_descriptor),
bDescriptorType: USB_DT_ENDPOINT,
bEndpointAddress: CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN,
bmAttributes: USB_ENDPOINT_XFER_BULK,
wMaxPacketSize: CONFIG_USBD_SERIAL_IN_PKTSIZE,
bInterval: 0
},
{
bLength: sizeof(struct usb_endpoint_descriptor),
bDescriptorType: USB_DT_ENDPOINT,
bEndpointAddress: CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN,
bmAttributes: USB_ENDPOINT_XFER_INT,
wMaxPacketSize: CONFIG_USBD_SERIAL_INT_PKTSIZE,
bInterval: 0
},
};
static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = {
&(ep_descriptors[0]),
&(ep_descriptors[1]),
&(ep_descriptors[2]),
/*
* Static Generic Serial specific data
*/
struct gserial_config_desc {
struct usb_configuration_descriptor configuration_desc;
struct usb_interface_descriptor
interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed));
struct usb_endpoint_descriptor
data_endpoints[NUM_ENDPOINTS] __attribute__((packed));
} __attribute__((packed));
static struct gserial_config_desc
gserial_configuration_descriptors[NUM_CONFIGS] ={
{
.configuration_desc ={
.bLength = sizeof(struct usb_configuration_descriptor),
.bDescriptorType = USB_DT_CONFIG,
.wTotalLength =
cpu_to_le16(sizeof(struct gserial_config_desc)),
.bNumInterfaces = NUM_GSERIAL_INTERFACES,
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG,
.bmAttributes =
BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
.bMaxPower = USBTTY_MAXPOWER
},
.interface_desc = {
{
.bLength =
sizeof(struct usb_interface_descriptor),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = NUM_ENDPOINTS,
.bInterfaceClass =
COMMUNICATIONS_INTERFACE_CLASS_VENDOR,
.bInterfaceSubClass =
COMMUNICATIONS_NO_SUBCLASS,
.bInterfaceProtocol =
COMMUNICATIONS_NO_PROTOCOL,
.iInterface = STR_DATA_INTERFACE
},
},
.data_endpoints = {
{
.bLength =
sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x01 | USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize =
cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE),
.bInterval= 0xFF,
},
{
.bLength =
sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x02 | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize =
cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE),
.bInterval = 0xFF,
},
{
.bLength =
sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x03 | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize =
cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
.bInterval = 0xFF,
},
},
},
};
/*
* Static Function Prototypes
*/
static void usbtty_init_strings (void);
static void usbtty_init_instances (void);
static void usbtty_init_endpoints (void);
static void usbtty_init_terminal_type(short type);
static void usbtty_event_handler (struct usb_device_instance *device,
usb_device_event_t event, int data);
static int usbtty_cdc_setup(struct usb_device_request *request,
struct urb *urb);
static int usbtty_configured (void);
static int write_buffer (circbuf_t * buf);
static int fill_buffer (circbuf_t * buf);
void usbtty_poll (void);
/* utility function for converting char* to wide string used by USB */
static void str2wide (char *str, u16 * wide)
{
int i;
for (i = 0; i < strlen (str) && str[i]; i++)
wide[i] = (u16) str[i];
for (i = 0; i < strlen (str) && str[i]; i++){
#if defined(__LITTLE_ENDIAN__)
wide[i] = (u16) str[i];
#elif defined(__BIG_ENDIAN__)
wide[i] = ((u16)(str[i])<<8);
#else
#error "__LITTLE_ENDIAN__ or __BIG_ENDIAN__ undefined"
#endif
}
}
/*
* Prototypes
*/
static void usbtty_init_strings (void);
static void usbtty_init_instances (void);
static void usbtty_init_endpoints (void);
static void usbtty_event_handler (struct usb_device_instance *device,
usb_device_event_t event, int data);
static int usbtty_configured (void);
static int write_buffer (circbuf_t * buf);
static int fill_buffer (circbuf_t * buf);
void usbtty_poll (void);
static void pretend_interrupts (void);
/*
* Test whether a character is in the RX buffer
*/
int usbtty_tstc (void)
{
struct usb_endpoint_instance *endpoint =
&endpoint_instance[rx_endpoint];
/* If no input data exists, allow more RX to be accepted */
if(usbtty_input.size <= 0){
udc_unset_nak(endpoint->endpoint_address&0x03);
}
usbtty_poll ();
return (usbtty_input.size > 0);
}
@ -210,15 +414,21 @@ int usbtty_tstc (void)
* otherwise. When the function is succesfull, the character read is
* written into its argument c.
*/
int usbtty_getc (void)
{
char c;
struct usb_endpoint_instance *endpoint =
&endpoint_instance[rx_endpoint];
while (usbtty_input.size <= 0) {
udc_unset_nak(endpoint->endpoint_address&0x03);
usbtty_poll ();
}
buf_pop (&usbtty_input, &c, 1);
udc_set_nak(endpoint->endpoint_address&0x03);
return c;
}
@ -238,7 +448,6 @@ void usbtty_putc (const char c)
}
}
/* usbtty_puts() helper function for finding the next '\n' in a string */
static int next_nl_pos (const char *s)
{
@ -252,8 +461,9 @@ static int next_nl_pos (const char *s)
}
/*
* Output a string to the usb client port.
* Output a string to the usb client port - implementing flow control
*/
static void __usbtty_puts (const char *str, int len)
{
int maxlen = usbtty_output.totalsize;
@ -261,22 +471,19 @@ static void __usbtty_puts (const char *str, int len)
/* break str into chunks < buffer size, if needed */
while (len > 0) {
usbtty_poll ();
space = maxlen - usbtty_output.size;
/* Empty buffer here, if needed, to ensure space... */
if (space <= 0) {
if (space) {
write_buffer (&usbtty_output);
space = maxlen - usbtty_output.size;
if (space <= 0) {
space = len; /* allow old data to be overwritten. */
}
n = MIN (space, MIN (len, maxlen));
buf_push (&usbtty_output, str, n);
str += n;
len -= n;
}
n = MIN (space, MIN (len, maxlen));
buf_push (&usbtty_output, str, n);
str += n;
len -= n;
}
}
@ -313,8 +520,10 @@ int drv_usbtty_init (void)
{
int rc;
char * sn;
char * tt;
int snlen;
/* Ger seiral number */
if (!(sn = getenv("serial#"))) {
sn = "000000000000";
}
@ -327,6 +536,14 @@ int drv_usbtty_init (void)
memcpy (serial_number, sn, snlen);
serial_number[snlen] = '\0';
/* Decide on which type of UDC device to be.
*/
if(!(tt = getenv("usbtty"))) {
tt = "generic";
}
usbtty_init_terminal_type(strcmp(tt,"cdc_acm"));
/* prepare buffers... */
buf_init (&usbtty_input, USBTTY_BUFFER_SIZE);
buf_init (&usbtty_output, USBTTY_BUFFER_SIZE);
@ -337,7 +554,7 @@ int drv_usbtty_init (void)
usbtty_init_strings ();
usbtty_init_instances ();
udc_startup_events (device_instance); /* Enable our device, initialize udc pointers */
udc_startup_events (device_instance);/* Enable dev, init udc pointers */
udc_connect (); /* Enable pullup for host detection */
usbtty_init_endpoints ();
@ -362,34 +579,52 @@ static void usbtty_init_strings (void)
{
struct usb_string_descriptor *string;
usbtty_string_table[STR_LANG] =
(struct usb_string_descriptor*)wstrLang;
string = (struct usb_string_descriptor *) wstrManufacturer;
string->bLength = sizeof (wstrManufacturer);
string->bLength = sizeof(wstrManufacturer);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_MANUFACTURER, string->wData);
usbtty_string_table[STR_MANUFACTURER]=string;
string = (struct usb_string_descriptor *) wstrProduct;
string->bLength = sizeof (wstrProduct);
string->bLength = sizeof(wstrProduct);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData);
usbtty_string_table[STR_PRODUCT]=string;
string = (struct usb_string_descriptor *) wstrSerial;
string->bLength = 2 + 2*strlen(serial_number);
string->bLength = sizeof(serial_number);
string->bDescriptorType = USB_DT_STRING;
str2wide (serial_number, string->wData);
usbtty_string_table[STR_SERIAL]=string;
string = (struct usb_string_descriptor *) wstrConfiguration;
string->bLength = sizeof (wstrConfiguration);
string->bLength = sizeof(wstrConfiguration);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData);
usbtty_string_table[STR_CONFIG]=string;
string = (struct usb_string_descriptor *) wstrInterface;
string->bLength = sizeof (wstrInterface);
string = (struct usb_string_descriptor *) wstrDataInterface;
string->bLength = sizeof(wstrDataInterface);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_INTERFACE_STR, string->wData);
str2wide (CONFIG_USBD_DATA_INTERFACE_STR, string->wData);
usbtty_string_table[STR_DATA_INTERFACE]=string;
string = (struct usb_string_descriptor *) wstrCtrlInterface;
string->bLength = sizeof(wstrCtrlInterface);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_CTRL_INTERFACE_STR, string->wData);
usbtty_string_table[STR_CTRL_INTERFACE]=string;
/* Now, initialize the string table for ep0 handling */
usb_strings = usbtty_string_table;
}
}
static void usbtty_init_instances (void)
{
@ -400,6 +635,7 @@ static void usbtty_init_instances (void)
device_instance->device_state = STATE_INIT;
device_instance->device_descriptor = &device_descriptor;
device_instance->event = usbtty_event_handler;
device_instance->cdc_recv_setup = usbtty_cdc_setup;
device_instance->bus = bus_instance;
device_instance->configurations = NUM_CONFIGS;
device_instance->configuration_instance_array = config_instance;
@ -415,8 +651,8 @@ static void usbtty_init_instances (void)
/* configuration instance */
memset (config_instance, 0,
sizeof (struct usb_configuration_instance));
config_instance->interfaces = NUM_INTERFACES;
config_instance->configuration_descriptor = config_descriptors;
config_instance->interfaces = interface_count;
config_instance->configuration_descriptor = configuration_descriptor;
config_instance->interface_instance_array = interface_instance;
/* interface instance */
@ -447,17 +683,22 @@ static void usbtty_init_instances (void)
sizeof (struct usb_endpoint_instance));
endpoint_instance[i].endpoint_address =
ep_descriptors[i - 1].bEndpointAddress;
ep_descriptor_ptrs[i - 1]->bEndpointAddress;
endpoint_instance[i].rcv_attributes =
ep_descriptor_ptrs[i - 1]->bmAttributes;
endpoint_instance[i].rcv_packetSize =
ep_descriptors[i - 1].wMaxPacketSize;
endpoint_instance[i].rcv_attributes =
ep_descriptors[i - 1].bmAttributes;
le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
endpoint_instance[i].tx_attributes =
ep_descriptor_ptrs[i - 1]->bmAttributes;
endpoint_instance[i].tx_packetSize =
ep_descriptors[i - 1].wMaxPacketSize;
le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
endpoint_instance[i].tx_attributes =
ep_descriptors[i - 1].bmAttributes;
ep_descriptor_ptrs[i - 1]->bmAttributes;
urb_link_init (&endpoint_instance[i].rcv);
urb_link_init (&endpoint_instance[i].rdy);
@ -480,13 +721,79 @@ static void usbtty_init_endpoints (void)
int i;
bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
for (i = 0; i <= NUM_ENDPOINTS; i++) {
for (i = 1; i <= NUM_ENDPOINTS; i++) {
udc_setup_ep (device_instance, i, &endpoint_instance[i]);
}
}
/* usbtty_init_terminal_type
*
* Do some late binding for our device type.
*/
static void usbtty_init_terminal_type(short type)
{
switch(type){
/* CDC ACM */
case 0:
/* Assign endpoint descriptors */
ep_descriptor_ptrs[0] =
&acm_configuration_descriptors[0].notification_endpoint;
ep_descriptor_ptrs[1] =
&acm_configuration_descriptors[0].data_endpoints[0];
ep_descriptor_ptrs[2] =
&acm_configuration_descriptors[0].data_endpoints[1];
/*********************************************************************************/
/* Enumerate Device Descriptor */
device_descriptor.bDeviceClass =
COMMUNICATIONS_DEVICE_CLASS;
device_descriptor.idProduct =
cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM);
/* Assign endpoint indices */
tx_endpoint = ACM_TX_ENDPOINT;
rx_endpoint = ACM_RX_ENDPOINT;
/* Configuration Descriptor */
configuration_descriptor =
(struct usb_configuration_descriptor*)
&acm_configuration_descriptors;
/* Interface count */
interface_count = NUM_ACM_INTERFACES;
break;
/* BULK IN/OUT & Default */
case 1:
default:
/* Assign endpoint descriptors */
ep_descriptor_ptrs[0] =
&gserial_configuration_descriptors[0].data_endpoints[0];
ep_descriptor_ptrs[1] =
&gserial_configuration_descriptors[0].data_endpoints[1];
ep_descriptor_ptrs[2] =
&gserial_configuration_descriptors[0].data_endpoints[2];
/* Enumerate Device Descriptor */
device_descriptor.bDeviceClass = 0xFF;
device_descriptor.idProduct =
cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL);
/* Assign endpoint indices */
tx_endpoint = GSERIAL_TX_ENDPOINT;
rx_endpoint = GSERIAL_RX_ENDPOINT;
/* Configuration Descriptor */
configuration_descriptor =
(struct usb_configuration_descriptor*)
&gserial_configuration_descriptors;
/* Interface count */
interface_count = NUM_GSERIAL_INTERFACES;
break;
}
}
/******************************************************************************/
static struct urb *next_urb (struct usb_device_instance *device,
struct usb_endpoint_instance *endpoint)
@ -525,28 +832,40 @@ static int write_buffer (circbuf_t * buf)
if (!usbtty_configured ()) {
return 0;
}
struct usb_endpoint_instance *endpoint =
&endpoint_instance[tx_endpoint];
struct urb *current_urb = NULL;
current_urb = next_urb (device_instance, endpoint);
/* TX data still exists - send it now
*/
if(endpoint->sent < current_urb->actual_length){
if(udc_endpoint_write (endpoint)){
/* Write pre-empted by RX */
return -1;
}
}
if (buf->size) {
struct usb_endpoint_instance *endpoint =
&endpoint_instance[TX_ENDPOINT];
struct urb *current_urb = NULL;
char *dest;
int space_avail;
int popnum, popped;
int total = 0;
/* Break buffer into urb sized pieces, and link each to the endpoint */
/* Break buffer into urb sized pieces,
* and link each to the endpoint
*/
while (buf->size > 0) {
current_urb = next_urb (device_instance, endpoint);
if (!current_urb) {
TTYERR ("current_urb is NULL, buf->size %d\n",
buf->size);
return total;
}
dest = current_urb->buffer +
dest = (char*)current_urb->buffer +
current_urb->actual_length;
space_avail =
@ -562,14 +881,19 @@ static int write_buffer (circbuf_t * buf)
current_urb->actual_length += popped;
total += popped;
/* If endpoint->last == 0, then transfers have not started on this endpoint */
/* If endpoint->last == 0, then transfers have
* not started on this endpoint
*/
if (endpoint->last == 0) {
udc_endpoint_write (endpoint);
if(udc_endpoint_write (endpoint)){
/* Write pre-empted by RX */
return -1;
}
}
} /* end while */
}/* end while */
return total;
} /* end if tx_urb */
}
return 0;
}
@ -577,18 +901,22 @@ static int write_buffer (circbuf_t * buf)
static int fill_buffer (circbuf_t * buf)
{
struct usb_endpoint_instance *endpoint =
&endpoint_instance[RECV_ENDPOINT];
&endpoint_instance[rx_endpoint];
if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
unsigned int nb = endpoint->rcv_urb->actual_length;
unsigned int nb = 0;
char *src = (char *) endpoint->rcv_urb->buffer;
unsigned int rx_avail = buf->totalsize - buf->size;
buf_push (buf, src, nb);
endpoint->rcv_urb->actual_length = 0;
if(rx_avail >= endpoint->rcv_urb->actual_length){
nb = endpoint->rcv_urb->actual_length;
buf_push (buf, src, nb);
endpoint->rcv_urb->actual_length = 0;
}
return nb;
}
return 0;
}
@ -597,7 +925,7 @@ static int usbtty_configured (void)
return usbtty_configured_flag;
}
/*********************************************************************************/
/******************************************************************************/
static void usbtty_event_handler (struct usb_device_instance *device,
usb_device_event_t event, int data)
@ -619,8 +947,34 @@ static void usbtty_event_handler (struct usb_device_instance *device,
}
}
/*********************************************************************************/
/******************************************************************************/
int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb)
{
switch (request->bRequest){
case ACM_SET_CONTROL_LINE_STATE: /* Implies DTE ready */
break;
case ACM_SEND_ENCAPSULATED_COMMAND : /* Required */
break;
case ACM_SET_LINE_ENCODING : /* DTE stop/parity bits
* per character */
break;
case ACM_GET_ENCAPSULATED_RESPONSE : /* request response */
break;
case ACM_GET_LINE_ENCODING : /* request DTE rate,
* stop/parity bits */
memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc));
urb->actual_length = sizeof(rs232_desc);
break;
default:
return 1;
}
return 0;
}
/******************************************************************************/
/*
* Since interrupt handling has not yet been implemented, we use this function
@ -630,36 +984,29 @@ static void usbtty_event_handler (struct usb_device_instance *device,
void usbtty_poll (void)
{
/* New interrupts? */
pretend_interrupts ();
udc_irq();
/* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */
/* Write any output data to host buffer
* (do this before checking interrupts to avoid missing one)
*/
if (usbtty_configured ()) {
write_buffer (&usbtty_output);
}
/* New interrupts? */
pretend_interrupts ();
/* Check for new data from host.. (do this after checking interrupts to get latest data) */
udc_irq();
/* Check for new data from host..
* (do this after checking interrupts to get latest data)
*/
if (usbtty_configured ()) {
fill_buffer (&usbtty_input);
}
/* New interrupts? */
pretend_interrupts ();
udc_irq();
}
static void pretend_interrupts (void)
{
/* Loop while we have interrupts.
* If we don't do this, the input chain
* polling delay is likely to miss
* host requests.
*/
while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
/* Handle any new IRQs */
omap1510_udc_irq ();
omap1510_udc_noniso_irq ();
}
}
#endif

View File

@ -2,6 +2,9 @@
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
*
* (C) Copyright 2006
* Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit
*
* 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
@ -21,44 +24,47 @@
#ifndef __USB_TTY_H__
#define __USB_TTY_H__
#include "usbdcore.h"
#if defined(CONFIG_PPC)
#include "usbdcore_mpc8xx.h"
#elif defined(CONFIG_ARM)
#include "usbdcore_omap1510.h"
#endif
#include <version_autogenerated.h>
#define NUM_CONFIGS 1
#define NUM_INTERFACES 1
#define NUM_ENDPOINTS 3
/* If no VendorID/ProductID is defined in config.h, pretend to be Linux
* DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */
#define CONFIG_USBD_VENDORID 0x0525 /* Linux/NetChip */
#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6 /* gserial */
#define CONFIG_USBD_PRODUCTID_CDCACM 0xa4a7 /* CDC ACM */
#define CONFIG_USBD_MANUFACTURER "Das U-Boot"
#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION
#define EP0_MAX_PACKET_SIZE 64
#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
#define CONFIG_USBD_INTERFACE_STR "Simple Serial Data Interface - Bulk Mode"
#define CONFIG_USBD_SERIAL_OUT_ENDPOINT 2
#define CONFIG_USBD_SERIAL_OUT_PKTSIZE 64
#define CONFIG_USBD_SERIAL_IN_ENDPOINT 1
#define CONFIG_USBD_SERIAL_IN_PKTSIZE 64
#define CONFIG_USBD_SERIAL_INT_ENDPOINT 5
#define CONFIG_USBD_SERIAL_INT_PKTSIZE 16
#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT
#define CONFIG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE
#define CONFIG_USBD_SERIAL_IN_ENDPOINT UDC_IN_ENDPOINT
#define CONFIG_USBD_SERIAL_IN_PKTSIZE UDC_IN_PACKET_SIZE
#define CONFIG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT
#define CONFIG_USBD_SERIAL_INT_PKTSIZE UDC_INT_PACKET_SIZE
#define CONFIG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_PACKET_SIZE
#define USBTTY_DEVICE_CLASS COMMUNICATIONS_DEVICE_CLASS
#define USBTTY_DEVICE_SUBCLASS COMMUNICATIONS_NO_SUBCLASS
#define USBTTY_DEVICE_PROTOCOL COMMUNICATIONS_NO_PROTOCOL
#define USBTTY_INTERFACE_CLASS 0xFF /* Vendor Specific */
#define USBTTY_INTERFACE_SUBCLASS 0x02
#define USBTTY_INTERFACE_PROTOCOL 0x01
#define USBTTY_BCD_DEVICE 0x00
#define USBTTY_MAXPOWER 0x00
#define USBTTY_BCD_DEVICE 0x0
#define USBTTY_MAXPOWER 0x0
#define STR_MANUFACTURER 1
#define STR_PRODUCT 2
#define STR_SERIAL 3
#define STR_CONFIG 4
#define STR_INTERFACE 5
#define STR_LANG 0x00
#define STR_MANUFACTURER 0x01
#define STR_PRODUCT 0x02
#define STR_SERIAL 0x03
#define STR_CONFIG 0x04
#define STR_DATA_INTERFACE 0x05
#define STR_CTRL_INTERFACE 0x06
#define STR_COUNT 0x07
#endif

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2006 CodeHermit.
* Bryan O'Donoghue <bodonoghue@codehermit.ie>
*
* Provides support for USB console on the Analogue & Micro Adder87x
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef __ADDERUSB__
#define __ADDERUSB__
/* Include the board port */
#include "Adder.h"
#define CONFIG_USB_DEVICE /* Include UDC driver */
#define CONFIG_USB_TTY /* Bind the TTY driver to UDC */
#define CFG_USB_EXTC_CLK 0x02 /* Oscillator on EXTC_CLK 2 */
#define CFG_USB_BRG_CLK 0x04 /* or use Baud rate generator 0x04 */
#define CFG_CONSOLE_IS_IN_ENV /* Console is in env */
/* If you have a USB-IF assigned VendorID then you may wish to define
* your own vendor specific values either in BoardName.h or directly in
* usbd_vendor_info.h
*/
/*
#define CONFIG_USBD_MANUFACTURER "CodeHermit.ie"
#define CONFIG_USBD_PRODUCT_NAME "Das U-Boot"
#define CONFIG_USBD_VENDORID 0xFFFF
#define CONFIG_USBD_PRODUCTID_GSERIAL 0xFFFF
#define CONFIG_USBD_PRODUCTID_CDCACM 0xFFFE
*/
#endif /* __ADDERUSB_H__ */

43
include/usb_cdc_acm.h Normal file
View File

@ -0,0 +1,43 @@
/*
* (C) Copyright 2006
* Bryan O'Donoghue, deckard@codehermit.ie, CodeHermit
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* ACM Control Requests */
#define ACM_SEND_ENCAPSULATED_COMMAND 0x00
#define ACM_GET_ENCAPSULATED_RESPONSE 0x01
#define ACM_SET_COMM_FEATURE 0x02
#define ACM_GET_COMM_FEATRUE 0x03
#define ACM_CLEAR_COMM_FEATURE 0x04
#define ACM_SET_LINE_ENCODING 0x20
#define ACM_GET_LINE_ENCODING 0x21
#define ACM_SET_CONTROL_LINE_STATE 0x22
#define ACM_SEND_BREAK 0x23
/* ACM Notification Codes */
#define ACM_NETWORK_CONNECTION 0x00
#define ACM_RESPONSE_AVAILABLE 0x01
#define ACM_SERIAL_STATE 0x20
/* Format of response expected by a ACM_GET_LINE_ENCODING request */
struct rs232_emu{
unsigned long dter;
unsigned char stop_bits;
unsigned char parity;
unsigned char data_bits;
}__attribute__((packed));

View File

@ -576,6 +576,9 @@ struct usb_device_instance {
void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data);
/* Do cdc device specific control requests */
int (*cdc_recv_setup)(struct usb_device_request *request, struct urb *urb);
/* bus interface */
struct usb_bus_instance *bus; /* which bus interface driver */

210
include/usbdcore_mpc8xx.h Normal file
View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2006 Bryan O'Donoghue, CodeHermit
* bodonoghue@codehermit.ie
*
*
* 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.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include <commproc.h>
/* Mode Register */
#define USMOD_EN 0x01
#define USMOD_HOST 0x02
#define USMOD_TEST 0x04
#define USMOD_SFTE 0x08
#define USMOD_RESUME 0x40
#define USMOD_LSS 0x80
/* Endpoint Registers */
#define USEP_RHS_NORM 0x00
#define USEP_RHS_IGNORE 0x01
#define USEP_RHS_NAK 0x02
#define USEP_RHS_STALL 0x03
#define USEP_THS_NORM 0x00
#define USEP_THS_IGNORE 0x04
#define USEP_THS_NAK 0x08
#define USEP_THS_STALL 0x0C
#define USEP_RTE 0x10
#define USEP_MF 0x20
#define USEP_TM_CONTROL 0x00
#define USEP_TM_INT 0x100
#define USEP_TM_BULK 0x200
#define USEP_TM_ISO 0x300
/* Command Register */
#define USCOM_EP0 0x00
#define USCOM_EP1 0x01
#define USCOM_EP2 0x02
#define USCOM_EP3 0x03
#define USCOM_FLUSH 0x40
#define USCOM_STR 0x80
/* Event Register */
#define USB_E_RXB 0x0001
#define USB_E_TXB 0x0002
#define USB_E_BSY 0x0004
#define USB_E_SOF 0x0008
#define USB_E_TXE1 0x0010
#define USB_E_TXE2 0x0020
#define USB_E_TXE3 0x0040
#define USB_E_TXE4 0x0080
#define USB_TX_ERRMASK (USB_E_TXE1|USB_E_TXE2|USB_E_TXE3|USB_E_TXE4)
#define USB_E_IDLE 0x0100
#define USB_E_RESET 0x0200
/* Mask Register */
#define USBS_IDLE 0x01
/* RX Buffer Descriptor */
#define RX_BD_OV 0x02
#define RX_BD_CR 0x04
#define RX_BD_AB 0x08
#define RX_BD_NO 0x10
#define RX_BD_PID_DATA0 0x00
#define RX_BD_PID_DATA1 0x40
#define RX_BD_PID_SETUP 0x80
#define RX_BD_F 0x400
#define RX_BD_L 0x800
#define RX_BD_I 0x1000
#define RX_BD_W 0x2000
#define RX_BD_E 0x8000
/* Useful masks */
#define RX_BD_PID_BITMASK (RX_BD_PID_DATA1 | RX_BD_PID_SETUP)
#define STALL_BITMASK (USEP_THS_STALL | USEP_RHS_STALL)
#define NAK_BITMASK (USEP_THS_NAK | USEP_RHS_NAK)
#define CBD_TX_BITMASK (TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_I | TX_BD_CNF)
/* TX Buffer Descriptor */
#define TX_BD_UN 0x02
#define TX_BD_TO 0x04
#define TX_BD_NO_PID 0x00
#define TX_BD_PID_DATA0 0x80
#define TX_BD_PID_DATA1 0xC0
#define TX_BD_CNF 0x200
#define TX_BD_TC 0x400
#define TX_BD_L 0x800
#define TX_BD_I 0x1000
#define TX_BD_W 0x2000
#define TX_BD_R 0x8000
/* Implementation specific defines */
#define EP_MIN_PACKET_SIZE 0x08
#define MAX_ENDPOINTS 0x04
#define FIFO_SIZE 0x10
#define EP_MAX_PKT FIFO_SIZE
#define TX_RING_SIZE 0x04
#define RX_RING_SIZE 0x06
#define USB_MAX_PKT 0x40
#define TOGGLE_TX_PID(x) x= ((~x)&0x40)|0x80
#define TOGGLE_RX_PID(x) x^= 0x40
#define EP_ATTACHED 0x01 /* Endpoint has a urb attached or not */
#define EP_SEND_ZLP 0x02 /* Send ZLP y/n ? */
#define PROFF_USB 0x00000000
#define CPM_USB_BASE 0x00000A00
/* UDC device defines */
#define EP0_MAX_PACKET_SIZE EP_MAX_PKT
#define UDC_OUT_ENDPOINT 0x02
#define UDC_OUT_PACKET_SIZE EP_MIN_PACKET_SIZE
#define UDC_IN_ENDPOINT 0x03
#define UDC_IN_PACKET_SIZE EP_MIN_PACKET_SIZE
#define UDC_INT_ENDPOINT 0x01
#define UDC_INT_PACKET_SIZE UDC_IN_PACKET_SIZE
#define UDC_BULK_PACKET_SIZE EP_MIN_PACKET_SIZE
struct mpc8xx_ep {
struct urb * urb;
unsigned char pid;
unsigned char sc;
volatile cbd_t * prx;
};
typedef struct mpc8xx_usb{
char usmod; /* Mode Register */
char usaddr; /* Slave Address Register */
char uscom; /* Command Register */
char res1; /* Reserved */
ushort usep[4];
ulong res2; /* Reserved */
ushort usber; /* Event Register */
ushort res3; /* Reserved */
ushort usbmr; /* Mask Register */
char res4; /* Reserved */
char usbs; /* Status Register */
char res5[8]; /* Reserved */
}usb_t;
typedef struct mpc8xx_parameter_ram{
ushort ep0ptr; /* Endpoint Pointer Register 0 */
ushort ep1ptr; /* Endpoint Pointer Register 1 */
ushort ep2ptr; /* Endpoint Pointer Register 2 */
ushort ep3ptr; /* Endpoint Pointer Register 3 */
uint rstate; /* Receive state */
uint rptr; /* Receive internal data pointer */
ushort frame_n; /* Frame number */
ushort rbcnt; /* Receive byte count */
uint rtemp; /* Receive temp cp use only */
uint rxusb; /* Rx Data Temp */
ushort rxuptr; /* Rx microcode return address temp */
}usb_pram_t;
typedef struct endpoint_parameter_block_pointer{
ushort rbase; /* RxBD base address */
ushort tbase; /* TxBD base address */
char rfcr; /* Rx Function code */
char tfcr; /* Tx Function code */
ushort mrblr; /* Maximum Receive Buffer Length */
ushort rbptr; /* RxBD pointer Next Buffer Descriptor */
ushort tbptr; /* TxBD pointer Next Buffer Descriptor */
ulong tstate; /* Transmit internal state */
ulong tptr; /* Transmit internal data pointer */
ushort tcrc; /* Transmit temp CRC */
ushort tbcnt; /* Transmit internal bye count */
ulong ttemp; /* Tx temp */
ushort txuptr; /* Tx microcode return address */
ushort res1; /* Reserved */
}usb_epb_t;
typedef enum mpc8xx_udc_state{
STATE_NOT_READY,
STATE_ERROR,
STATE_READY,
}mpc8xx_udc_state_t;
/* Declarations */
int udc_init(void);
void udc_irq(void);
int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
struct usb_endpoint_instance *endpoint);
void udc_connect(void);
void udc_disconnect(void);
void udc_enable(struct usb_device_instance *device);
void udc_disable(void);
void udc_startup_events(struct usb_device_instance *device);
/* Flow control */
void udc_set_nak(int epid);
void udc_unset_nak (int epid);

View File

@ -161,10 +161,20 @@
#define UDC_VBUS_CTRL (1 << 19)
#define UDC_VBUS_MODE (1 << 18)
/* OMAP Endpoint parameters */
#define EP0_MAX_PACKET_SIZE 64
#define UDC_OUT_ENDPOINT 2
#define UDC_OUT_PACKET_SIZE 64
#define UDC_IN_ENDPOINT 1
#define UDC_IN_PACKET_SIZE 64
#define UDC_INT_ENDPOINT 5
#define UDC_INT_PKTSIZE 16
#define UDC_BULK_PKTSIZE 16
void omap1510_udc_irq(void);
void omap1510_udc_noniso_irq(void);
void udc_irq (void);
/* Flow control */
void udc_set_nak(int epid);
void udc_unset_nak (int epid);
/* Higher level functions for abstracting away from specific device */
void udc_endpoint_write(struct usb_endpoint_instance *endpoint);

View File

@ -92,33 +92,42 @@
#define COMMUNICATIONS_DEVICE_CLASS 0x02
/* c.f. CDC 4.2 Table 15 */
#define COMMUNICATIONS_INTERFACE_CLASS 0x02
#define COMMUNICATIONS_INTERFACE_CLASS_CONTROL 0x02
#define COMMUNICATIONS_INTERFACE_CLASS_DATA 0x0A
#define COMMUNICATIONS_INTERFACE_CLASS_VENDOR 0x0FF
/* c.f. CDC 4.3 Table 16 */
#define COMMUNICATIONS_NO_SUBCLASS 0x00
#define COMMUNICATIONS_NO_SUBCLASS 0x00
#define COMMUNICATIONS_DLCM_SUBCLASS 0x01
#define COMMUNICATIONS_ACM_SUBCLASS 0x02
#define COMMUNICATIONS_TCM_SUBCLASS 0x03
#define COMMUNICATIONS_ACM_SUBCLASS 0x02
#define COMMUNICATIONS_TCM_SUBCLASS 0x03
#define COMMUNICATIONS_MCCM_SUBCLASS 0x04
#define COMMUNICATIONS_CCM_SUBCLASS 0x05
#define COMMUNICATIONS_CCM_SUBCLASS 0x05
#define COMMUNICATIONS_ENCM_SUBCLASS 0x06
#define COMMUNICATIONS_ANCM_SUBCLASS 0x07
/* c.f. WMCD 5.1 */
#define COMMUNICATIONS_WHCM_SUBCLASS 0x08
#define COMMUNICATIONS_DMM_SUBCLASS 0x09
#define COMMUNICATIONS_DMM_SUBCLASS 0x09
#define COMMUNICATIONS_MDLM_SUBCLASS 0x0a
#define COMMUNICATIONS_OBEX_SUBCLASS 0x0b
/* c.f. CDC 4.6 Table 18 */
/* c.f. CDC 4.4 Table 17 */
#define COMMUNICATIONS_NO_PROTOCOL 0x00
#define COMMUNICATIONS_V25TER_PROTOCOL 0x01 /*Common AT Hayes compatible*/
/* c.f. CDC 4.5 Table 18 */
#define DATA_INTERFACE_CLASS 0x0a
/* c.f. CDC 4.6 No Table */
#define DATA_INTERFACE_SUBCLASS_NONE 0x00 /* No subclass pertinent */
/* c.f. CDC 4.7 Table 19 */
#define COMMUNICATIONS_NO_PROTOCOL 0x00
#define DATA_INTERFACE_PROTOCOL_NONE 0x00 /* No class protcol required */
/* c.f. CDC 5.2.3 Table 24 */
#define CS_INTERFACE 0x24
#define CS_INTERFACE 0x24
#define CS_ENDPOINT 0x25
/*
@ -128,7 +137,7 @@
* c.f. WMCD 5.3 Table 5.3
*/
#define USB_ST_HEADER 0x00
#define USB_ST_HEADER 0x00
#define USB_ST_CMF 0x01
#define USB_ST_ACMF 0x02
#define USB_ST_DLMF 0x03
@ -137,18 +146,18 @@
#define USB_ST_UF 0x06
#define USB_ST_CSF 0x07
#define USB_ST_TOMF 0x08
#define USB_ST_USBTF 0x09
#define USB_ST_USBTF 0x09
#define USB_ST_NCT 0x0a
#define USB_ST_PUF 0x0b
#define USB_ST_EUF 0x0c
#define USB_ST_MCMF 0x0d
#define USB_ST_CCMF 0x0e
#define USB_ST_ENF 0x0f
#define USB_ST_ATMNF 0x10
#define USB_ST_ATMNF 0x10
#define USB_ST_WHCM 0x11
#define USB_ST_MDLM 0x12
#define USB_ST_MDLMD 0x13
#define USB_ST_MDLMD 0x13
#define USB_ST_DMM 0x14
#define USB_ST_OBEX 0x15
#define USB_ST_CS 0x16
@ -312,7 +321,8 @@ struct usb_class_union_function_descriptor {
u8 bDescriptorType;
u8 bDescriptorSubtype; /* 0x06 */
u8 bMasterInterface;
u8 bSlaveInterface0[0];
//u8 bSlaveInterface0[0];
u8 bSlaveInterface0;
} __attribute__ ((packed));
struct usb_class_country_selection_descriptor {