summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2010-09-28 23:30:47 +0200
committerWolfgang Denk <wd@denx.de>2010-09-28 23:30:47 +0200
commit2e6e1772c0e34871769be4aef79748fe3e47d953 (patch)
tree00e4e19d7bccd2a1cd5753854ff4c2b8a26bebb0 /drivers
parent1e4e5ef0469050f014aee1204dae8a9ab6053e49 (diff)
parent3df61957938586c512c17e72d83551d190400981 (diff)
downloadblackbird-obmc-uboot-2e6e1772c0e34871769be4aef79748fe3e47d953.tar.gz
blackbird-obmc-uboot-2e6e1772c0e34871769be4aef79748fe3e47d953.zip
Merge branch 'next' of /home/wd/git/u-boot/next
Conflicts: include/ppc4xx.h Signed-off-by: Wolfgang Denk <wd@denx.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/omap24xx_i2c.c4
-rw-r--r--drivers/i2c/ppc4xx_i2c.c4
-rw-r--r--drivers/input/ps2ser.c109
-rw-r--r--drivers/mtd/cfi_flash.c32
-rw-r--r--drivers/mtd/cfi_mtd.c10
-rw-r--r--drivers/mtd/nand/ndfc.c2
-rw-r--r--drivers/net/4xx_enet.c9
-rw-r--r--drivers/pcmcia/mpc8xx_pcmcia.c29
-rw-r--r--drivers/pcmcia/tqm8xx_pcmcia.c42
-rw-r--r--drivers/serial/serial_netarm.c5
-rw-r--r--drivers/usb/gadget/Makefile6
-rw-r--r--drivers/usb/gadget/config.c119
-rw-r--r--drivers/usb/gadget/epautoconf.c305
-rw-r--r--drivers/usb/gadget/ether.c1976
-rw-r--r--drivers/usb/gadget/gadget_chips.h220
-rw-r--r--drivers/usb/gadget/usbstring.c140
-rw-r--r--drivers/usb/musb/musb_core.h2
-rw-r--r--drivers/video/cfb_console.c38
18 files changed, 2848 insertions, 204 deletions
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index a7c4e69a64..3febd1ff63 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -40,6 +40,7 @@ static unsigned int current_bus;
void i2c_init (int speed, int slaveadd)
{
+ DECLARE_GLOBAL_DATA_PTR;
int psc, fsscll, fssclh;
int hsscll = 0, hssclh = 0;
u32 scll, sclh;
@@ -139,7 +140,8 @@ void i2c_init (int speed, int slaveadd)
writew (0xFFFF, &i2c_base->stat);
writew (0, &i2c_base->cnt);
- bus_initialized[current_bus] = 1;
+ if (gd->flags & GD_FLG_RELOC)
+ bus_initialized[current_bus] = 1;
}
static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
diff --git a/drivers/i2c/ppc4xx_i2c.c b/drivers/i2c/ppc4xx_i2c.c
index e9548f1a68..c1cbe55bb9 100644
--- a/drivers/i2c/ppc4xx_i2c.c
+++ b/drivers/i2c/ppc4xx_i2c.c
@@ -27,8 +27,8 @@
*/
#include <common.h>
-#include <ppc4xx.h>
-#include <4xx_i2c.h>
+#include <asm/ppc4xx.h>
+#include <asm/ppc4xx-i2c.h>
#include <i2c.h>
#include <asm/io.h>
diff --git a/drivers/input/ps2ser.c b/drivers/input/ps2ser.c
index 8d0b6d6042..a655a16d75 100644
--- a/drivers/input/ps2ser.c
+++ b/drivers/input/ps2ser.c
@@ -46,8 +46,7 @@ DECLARE_GLOBAL_DATA_PTR;
#error CONFIG_PS2SERIAL must be in 1 ... 6
#endif
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
+#else
#if CONFIG_PS2SERIAL == 1
#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500)
@@ -57,17 +56,12 @@ DECLARE_GLOBAL_DATA_PTR;
#error CONFIG_PS2SERIAL must be in 1 ... 2
#endif
-#endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */
+#endif /* CONFIG_MPC5xxx / other */
static int ps2ser_getc_hw(void);
static void ps2ser_interrupt(void *dev_id);
extern struct serial_state rs_table[]; /* in serial.c */
-#if !defined(CONFIG_MPC5xxx) && !defined(CONFIG_MPC8540) && \
- !defined(CONFIG_MPC8541) && !defined(CONFIG_MPC8548) && \
- !defined(CONFIG_MPC8555)
-static struct serial_state *state;
-#endif
static u_char ps2buf[PS2BUF_SIZE];
static atomic_t ps2buf_cnt;
@@ -111,8 +105,8 @@ int ps2ser_init(void)
return (0);
}
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
+#else
+
int ps2ser_init(void)
{
NS16550_t com_port = (NS16550_t)COM_BASE;
@@ -128,76 +122,24 @@ int ps2ser_init(void)
return (0);
}
-#else /* !CONFIG_MPC5xxx && !CONFIG_MPC8540 / other */
-
-static inline unsigned int ps2ser_in(int offset)
-{
- return readb((unsigned long) state->iomem_base + offset);
-}
-
-static inline void ps2ser_out(int offset, int value)
-{
- writeb(value, (unsigned long) state->iomem_base + offset);
-}
-
-int ps2ser_init(void)
-{
- int quot;
- unsigned cval;
-
- state = rs_table + CONFIG_PS2SERIAL;
-
- quot = state->baud_base / PS2SER_BAUD;
- cval = 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */
-
- /* Set speed, enable interrupts, enable FIFO
- */
- ps2ser_out(UART_LCR, cval | UART_LCR_DLAB);
- ps2ser_out(UART_DLL, quot & 0xff);
- ps2ser_out(UART_DLM, quot >> 8);
- ps2ser_out(UART_LCR, cval);
- ps2ser_out(UART_IER, UART_IER_RDI);
- ps2ser_out(UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS);
- ps2ser_out(UART_FCR,
- UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-
- /* If we read 0xff from the LSR, there is no UART here
- */
- if (ps2ser_in(UART_LSR) == 0xff) {
- printf ("ps2ser.c: no UART found\n");
- return -1;
- }
-
- irq_install_handler(state->irq, ps2ser_interrupt, NULL);
-
- return 0;
-}
-#endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */
+#endif /* CONFIG_MPC5xxx / other */
void ps2ser_putc(int chr)
{
#ifdef CONFIG_MPC5xxx
volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
+#else
NS16550_t com_port = (NS16550_t)COM_BASE;
#endif
-#ifdef DEBUG
- printf(">>>> 0x%02x\n", chr);
-#endif
+ debug(">>>> 0x%02x\n", chr);
#ifdef CONFIG_MPC5xxx
while (!(psc->psc_status & PSC_SR_TXRDY));
psc->psc_buffer_8 = chr;
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
+#else
while ((com_port->lsr & UART_LSR_THRE) == 0);
com_port->thr = chr;
-#else
- while (!(ps2ser_in(UART_LSR) & UART_LSR_THRE));
-
- ps2ser_out(UART_TX, chr);
#endif
}
@@ -205,8 +147,7 @@ static int ps2ser_getc_hw(void)
{
#ifdef CONFIG_MPC5xxx
volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
+#else
NS16550_t com_port = (NS16550_t)COM_BASE;
#endif
int res = -1;
@@ -215,15 +156,10 @@ static int ps2ser_getc_hw(void)
if (psc->psc_status & PSC_SR_RXRDY) {
res = (psc->psc_buffer_8);
}
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
+#else
if (com_port->lsr & UART_LSR_DR) {
res = com_port->rbr;
}
-#else
- if (ps2ser_in(UART_LSR) & UART_LSR_DR) {
- res = (ps2ser_in(UART_RX));
- }
#endif
return res;
@@ -234,9 +170,7 @@ int ps2ser_getc(void)
volatile int chr;
int flags;
-#ifdef DEBUG
- printf("<< ");
-#endif
+ debug("<< ");
flags = disable_interrupts();
@@ -251,11 +185,10 @@ int ps2ser_getc(void)
}
while (chr < 0);
- if (flags) enable_interrupts();
+ if (flags)
+ enable_interrupts();
-#ifdef DEBUG
- printf("0x%02x\n", chr);
-#endif
+ debug("0x%02x\n", chr);
return chr;
}
@@ -275,8 +208,7 @@ static void ps2ser_interrupt(void *dev_id)
{
#ifdef CONFIG_MPC5xxx
volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
+#else
NS16550_t com_port = (NS16550_t)COM_BASE;
#endif
int chr;
@@ -286,11 +218,8 @@ static void ps2ser_interrupt(void *dev_id)
chr = ps2ser_getc_hw();
#ifdef CONFIG_MPC5xxx
status = psc->psc_status;
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
- status = com_port->lsr;
#else
- status = ps2ser_in(UART_IIR);
+ status = com_port->lsr;
#endif
if (chr < 0) continue;
@@ -303,13 +232,9 @@ static void ps2ser_interrupt(void *dev_id)
}
#ifdef CONFIG_MPC5xxx
} while (status & PSC_SR_RXRDY);
-#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
- defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
- } while (status & UART_LSR_DR);
#else
- } while (status & UART_IIR_RDI);
+ } while (status & UART_LSR_DR);
#endif
-
if (atomic_read(&ps2buf_cnt)) {
ps2mult_callback(atomic_read(&ps2buf_cnt));
}
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 44ebb9d06a..02dd27ffb1 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -62,20 +62,9 @@
* reading and writing ... (yes there is such a Hardware).
*/
-#ifndef CONFIG_SYS_FLASH_BANKS_LIST
-#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE }
-#endif
-
static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
static uint flash_verbose = 1;
-/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
-#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
-# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT
-#else
-# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS
-#endif
-
flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
/*
@@ -85,6 +74,17 @@ flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT
#endif
+#if defined(CONFIG_SYS_MAX_FLASH_BANKS_DETECT)
+int cfi_flash_num_flash_banks = CONFIG_SYS_MAX_FLASH_BANKS_DETECT;
+#endif
+
+static phys_addr_t __cfi_flash_bank_addr(int i)
+{
+ return ((phys_addr_t [])CONFIG_SYS_FLASH_BANKS_LIST)[i];
+}
+phys_addr_t cfi_flash_bank_addr(int i)
+ __attribute__((weak, alias("__cfi_flash_bank_addr")));
+
static void __flash_write8(u8 value, void *addr)
{
__raw_writeb(value, addr);
@@ -153,7 +153,7 @@ u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
flash_info_t *flash_get_info(ulong base)
{
int i;
- flash_info_t * info = 0;
+ flash_info_t *info = NULL;
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
info = & flash_info[i];
@@ -162,7 +162,7 @@ flash_info_t *flash_get_info(ulong base)
break;
}
- return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
+ return info;
}
#endif
@@ -2021,14 +2021,12 @@ unsigned long flash_init (void)
getenv_f("unlock", s, sizeof(s));
#endif
-#define BANK_BASE(i) (((phys_addr_t [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])
-
/* Init: no FLASHes known */
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
- if (!flash_detect_legacy (BANK_BASE(i), i))
- flash_get_size (BANK_BASE(i), i);
+ if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
+ flash_get_size(cfi_flash_bank_addr(i), i);
size += flash_info[i].size;
if (flash_info[i].flash_id == FLASH_UNKNOWN) {
#ifndef CONFIG_SYS_FLASH_QUIET_TEST
diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c
index 6a0cab3059..cbcc165c7e 100644
--- a/drivers/mtd/cfi_mtd.c
+++ b/drivers/mtd/cfi_mtd.c
@@ -30,15 +30,7 @@
#include <asm/errno.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/concat.h>
-
-/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */
-#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT
-# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT
-#else
-# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS
-#endif
-
-extern flash_info_t flash_info[];
+#include <mtd/cfi_flash.h>
static struct mtd_info cfi_mtd_info[CFI_MAX_FLASH_BANKS];
static char cfi_mtd_names[CFI_MAX_FLASH_BANKS][16];
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 0dd6789582..3ca13a979c 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -35,7 +35,7 @@
#include <linux/mtd/nand_ecc.h>
#include <asm/processor.h>
#include <asm/io.h>
-#include <ppc4xx.h>
+#include <asm/ppc4xx.h>
/*
* We need to store the info, which chip-select (CS) is used for the
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
index d9487ad732..45ff4f333b 100644
--- a/drivers/net/4xx_enet.c
+++ b/drivers/net/4xx_enet.c
@@ -87,9 +87,9 @@
#include <asm/cache.h>
#include <asm/mmu.h>
#include <commproc.h>
-#include <ppc4xx.h>
-#include <ppc4xx_enet.h>
-#include <405_mal.h>
+#include <asm/ppc4xx.h>
+#include <asm/ppc4xx-emac.h>
+#include <asm/ppc4xx-mal.h>
#include <miiphy.h>
#include <malloc.h>
@@ -1494,8 +1494,7 @@ get_speed:
/* set speed */
if (speed == _1000BASET) {
-#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
- defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
unsigned long pfc1;
mfsdr (SDR0_PFC1, pfc1);
diff --git a/drivers/pcmcia/mpc8xx_pcmcia.c b/drivers/pcmcia/mpc8xx_pcmcia.c
index 70305748c8..74a50f1c74 100644
--- a/drivers/pcmcia/mpc8xx_pcmcia.c
+++ b/drivers/pcmcia/mpc8xx_pcmcia.c
@@ -57,12 +57,6 @@ static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] =
/* -------------------------------------------------------------------- */
-#ifdef CONFIG_HMI10
-#define HMI10_FRAM_TIMING ( PCMCIA_SHT(2) \
- | PCMCIA_SST(2) \
- | PCMCIA_SL(4))
-#endif
-
#if defined(CONFIG_LWMON) || defined(CONFIG_NSCU)
#define CONFIG_SYS_PCMCIA_TIMING ( PCMCIA_SHT(9) \
| PCMCIA_SST(3) \
@@ -106,17 +100,6 @@ int pcmcia_on (void)
switch (i) {
#ifdef CONFIG_IDE_8xx_PCCARD
case 4:
-#ifdef CONFIG_HMI10
- { /* map FRAM area */
- win->or = ( PCMCIA_BSIZE_256K
- | PCMCIA_PPS_8
- | PCMCIA_PRS_ATTR
- | slotbit
- | PCMCIA_PV
- | HMI10_FRAM_TIMING );
- break;
- }
-#endif
case 0: { /* map attribute memory */
win->or = ( PCMCIA_BSIZE_64M
| PCMCIA_PPS_8
@@ -147,18 +130,6 @@ int pcmcia_on (void)
break;
}
#endif /* CONFIG_IDE_8xx_PCCARD */
-#ifdef CONFIG_HMI10
- case 3: { /* map I/O window for 4xUART data/ctrl */
- win->br += 0x40000;
- win->or = ( PCMCIA_BSIZE_256K
- | PCMCIA_PPS_8
- | PCMCIA_PRS_IO
- | slotbit
- | PCMCIA_PV
- | CONFIG_SYS_PCMCIA_TIMING );
- break;
- }
-#endif /* CONFIG_HMI10 */
default: /* set to not valid */
win->or = 0;
break;
diff --git a/drivers/pcmcia/tqm8xx_pcmcia.c b/drivers/pcmcia/tqm8xx_pcmcia.c
index 6ba8b5c01f..ca1a9fe151 100644
--- a/drivers/pcmcia/tqm8xx_pcmcia.c
+++ b/drivers/pcmcia/tqm8xx_pcmcia.c
@@ -36,39 +36,6 @@
#define power_on_5_0(slot) do {} while (0)
#define power_on_3_3(slot) do {} while (0)
-#elif defined(CONFIG_HMI10)
-
-static inline void power_config(int slot)
-{
- volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
- /*
- * Configure Port B pins for
- * 5 Volts Enable and 3 Volts enable
- */
- immap->im_cpm.cp_pbpar &= ~(0x00000300);
-}
-
-static inline void power_off(int slot)
-{
- volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
- /* remove all power */
- immap->im_cpm.cp_pbdat |= 0x00000300;
-}
-
-static inline void power_on_5_0(int slot)
-{
- volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
- immap->im_cpm.cp_pbdat &= ~(0x0000100);
- immap->im_cpm.cp_pbdir |= 0x00000300;
-}
-
-static inline void power_on_3_3(int slot)
-{
- volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
- immap->im_cpm.cp_pbdat &= ~(0x0000200);
- immap->im_cpm.cp_pbdir |= 0x00000300;
-}
-
#elif defined(CONFIG_VIRTLAB2)
#define power_config(slot) do {} while (0)
@@ -128,21 +95,12 @@ static inline void power_on_3_3(int slot)
#endif
-#ifdef CONFIG_HMI10
-static inline int check_card_is_absent(int slot)
-{
- volatile pcmconf8xx_t *pcmp =
- (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
- return pcmp->pcmc_pipr & (0x10000000 >> (slot << 4));
-}
-#else
static inline int check_card_is_absent(int slot)
{
volatile pcmconf8xx_t *pcmp =
(pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
return pcmp->pcmc_pipr & (0x18000000 >> (slot << 4));
}
-#endif
#ifdef NSCU_OE_INV
#define NSCU_GCRX_CXOE 0
diff --git a/drivers/serial/serial_netarm.c b/drivers/serial/serial_netarm.c
index 2eb5393404..d04790d270 100644
--- a/drivers/serial/serial_netarm.c
+++ b/drivers/serial/serial_netarm.c
@@ -51,13 +51,8 @@ DECLARE_GLOBAL_DATA_PTR;
}
-#ifndef CONFIG_UART1_CONSOLE
volatile netarm_serial_channel_t *serial_reg_ch1 = get_serial_channel(0);
volatile netarm_serial_channel_t *serial_reg_ch2 = get_serial_channel(1);
-#else
-volatile netarm_serial_channel_t *serial_reg_ch1 = get_serial_channel(1);
-volatile netarm_serial_channel_t *serial_reg_ch2 = get_serial_channel(0);
-#endif
extern void _netarm_led_FAIL1(void);
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 1d7362dc97..8e6b26e261 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -25,6 +25,11 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_gadget.a
+# new USB gadget layer dependencies
+ifdef CONFIG_USB_ETHER
+COBJS-y += ether.o epautoconf.o config.o usbstring.o
+else
+# Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE
ifdef CONFIG_USB_DEVICE
COBJS-y += core.o
COBJS-y += ep0.o
@@ -34,6 +39,7 @@ COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o
COBJS-$(CONFIG_PXA27X) += pxa27x_udc.o
COBJS-$(CONFIG_SPEARUDC) += spr_udc.o
endif
+endif
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
new file mode 100644
index 0000000000..cf22629b97
--- /dev/null
+++ b/drivers/usb/gadget/config.c
@@ -0,0 +1,119 @@
+/*
+ * usb/gadget/config.c -- simplify building config descriptors
+ *
+ * Copyright (C) 2003 David Brownell
+ *
+ * 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
+ *
+ * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and
+ * Remy Bohmer <linux@bohmer.net>
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <linux/list.h>
+#include <linux/string.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+
+/**
+ * usb_descriptor_fillbuf - fill buffer with descriptors
+ * @buf: Buffer to be filled
+ * @buflen: Size of buf
+ * @src: Array of descriptor pointers, terminated by null pointer.
+ *
+ * Copies descriptors into the buffer, returning the length or a
+ * negative error code if they can't all be copied. Useful when
+ * assembling descriptors for an associated set of interfaces used
+ * as part of configuring a composite device; or in other cases where
+ * sets of descriptors need to be marshaled.
+ */
+int
+usb_descriptor_fillbuf(void *buf, unsigned buflen,
+ const struct usb_descriptor_header **src)
+{
+ u8 *dest = buf;
+
+ if (!src)
+ return -EINVAL;
+
+ /* fill buffer from src[] until null descriptor ptr */
+ for (; NULL != *src; src++) {
+ unsigned len = (*src)->bLength;
+
+ if (len > buflen)
+ return -EINVAL;
+ memcpy(dest, *src, len);
+ buflen -= len;
+ dest += len;
+ }
+ return dest - (u8 *)buf;
+}
+
+
+/**
+ * usb_gadget_config_buf - builts a complete configuration descriptor
+ * @config: Header for the descriptor, including characteristics such
+ * as power requirements and number of interfaces.
+ * @desc: Null-terminated vector of pointers to the descriptors (interface,
+ * endpoint, etc) defining all functions in this device configuration.
+ * @buf: Buffer for the resulting configuration descriptor.
+ * @length: Length of buffer. If this is not big enough to hold the
+ * entire configuration descriptor, an error code will be returned.
+ *
+ * This copies descriptors into the response buffer, building a descriptor
+ * for that configuration. It returns the buffer length or a negative
+ * status code. The config.wTotalLength field is set to match the length
+ * of the result, but other descriptor fields (including power usage and
+ * interface count) must be set by the caller.
+ *
+ * Gadget drivers could use this when constructing a config descriptor
+ * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
+ * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
+ */
+int usb_gadget_config_buf(
+ const struct usb_config_descriptor *config,
+ void *buf,
+ unsigned length,
+ const struct usb_descriptor_header **desc
+)
+{
+ struct usb_config_descriptor *cp = buf;
+ int len;
+
+ /* config descriptor first */
+ if (length < USB_DT_CONFIG_SIZE || !desc)
+ return -EINVAL;
+ *cp = *config;
+
+ /* then interface/endpoint/class/vendor/... */
+ len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf,
+ length - USB_DT_CONFIG_SIZE, desc);
+ if (len < 0)
+ return len;
+ len += USB_DT_CONFIG_SIZE;
+ if (len > 0xffff)
+ return -EINVAL;
+
+ /* patch up the config descriptor */
+ cp->bLength = USB_DT_CONFIG_SIZE;
+ cp->bDescriptorType = USB_DT_CONFIG;
+ cp->wTotalLength = cpu_to_le16(len);
+ cp->bmAttributes |= USB_CONFIG_ATT_ONE;
+ return len;
+}
+
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
new file mode 100644
index 0000000000..7cf3c673dd
--- /dev/null
+++ b/drivers/usb/gadget/epautoconf.c
@@ -0,0 +1,305 @@
+/*
+ * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
+ *
+ * Copyright (C) 2004 David Brownell
+ *
+ * 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
+ *
+ * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and
+ * Remy Bohmer <linux@bohmer.net>
+ */
+
+#include <common.h>
+#include <linux/usb/ch9.h>
+#include <asm/errno.h>
+#include <linux/usb/gadget.h>
+#include "gadget_chips.h"
+
+#define isdigit(c) ('0' <= (c) && (c) <= '9')
+
+/* we must assign addresses for configurable endpoints (like net2280) */
+static unsigned epnum;
+
+/* #define MANY_ENDPOINTS */
+#ifdef MANY_ENDPOINTS
+/* more than 15 configurable endpoints */
+static unsigned in_epnum;
+#endif
+
+
+/*
+ * This should work with endpoints from controller drivers sharing the
+ * same endpoint naming convention. By example:
+ *
+ * - ep1, ep2, ... address is fixed, not direction or type
+ * - ep1in, ep2out, ... address and direction are fixed, not type
+ * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
+ * - ep1in-bulk, ep2out-iso, ... all three are fixed
+ * - ep-* ... no functionality restrictions
+ *
+ * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal.
+ * Less common restrictions are implied by gadget_is_*().
+ *
+ * NOTE: each endpoint is unidirectional, as specified by its USB
+ * descriptor; and isn't specific to a configuration or altsetting.
+ */
+static int ep_matches(
+ struct usb_gadget *gadget,
+ struct usb_ep *ep,
+ struct usb_endpoint_descriptor *desc
+)
+{
+ u8 type;
+ const char *tmp;
+ u16 max;
+
+ /* endpoint already claimed? */
+ if (NULL != ep->driver_data)
+ return 0;
+
+ /* only support ep0 for portable CONTROL traffic */
+ type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (USB_ENDPOINT_XFER_CONTROL == type)
+ return 0;
+
+ /* some other naming convention */
+ if ('e' != ep->name[0])
+ return 0;
+
+ /* type-restriction: "-iso", "-bulk", or "-int".
+ * direction-restriction: "in", "out".
+ */
+ if ('-' != ep->name[2]) {
+ tmp = strrchr(ep->name, '-');
+ if (tmp) {
+ switch (type) {
+ case USB_ENDPOINT_XFER_INT:
+ /* bulk endpoints handle interrupt transfers,
+ * except the toggle-quirky iso-synch kind
+ */
+ if ('s' == tmp[2]) /* == "-iso" */
+ return 0;
+ /* for now, avoid PXA "interrupt-in";
+ * it's documented as never using DATA1.
+ */
+ if (gadget_is_pxa(gadget)
+ && 'i' == tmp[1])
+ return 0;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ if ('b' != tmp[1]) /* != "-bulk" */
+ return 0;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if ('s' != tmp[2]) /* != "-iso" */
+ return 0;
+ }
+ } else {
+ tmp = ep->name + strlen(ep->name);
+ }
+
+ /* direction-restriction: "..in-..", "out-.." */
+ tmp--;
+ if (!isdigit(*tmp)) {
+ if (desc->bEndpointAddress & USB_DIR_IN) {
+ if ('n' != *tmp)
+ return 0;
+ } else {
+ if ('t' != *tmp)
+ return 0;
+ }
+ }
+ }
+
+ /* endpoint maxpacket size is an input parameter, except for bulk
+ * where it's an output parameter representing the full speed limit.
+ * the usb spec fixes high speed bulk maxpacket at 512 bytes.
+ */
+ max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
+ switch (type) {
+ case USB_ENDPOINT_XFER_INT:
+ /* INT: limit 64 bytes full speed, 1024 high speed */
+ if (!gadget->is_dualspeed && max > 64)
+ return 0;
+ /* FALLTHROUGH */
+
+ case USB_ENDPOINT_XFER_ISOC:
+ /* ISO: limit 1023 bytes full speed, 1024 high speed */
+ if (ep->maxpacket < max)
+ return 0;
+ if (!gadget->is_dualspeed && max > 1023)
+ return 0;
+
+ /* BOTH: "high bandwidth" works only at high speed */
+ if ((desc->wMaxPacketSize & __constant_cpu_to_le16(3<<11))) {
+ if (!gadget->is_dualspeed)
+ return 0;
+ /* configure your hardware with enough buffering!! */
+ }
+ break;
+ }
+
+ /* MATCH!! */
+
+ /* report address */
+ if (isdigit(ep->name[2])) {
+ u8 num = simple_strtoul(&ep->name[2], NULL, 10);
+ desc->bEndpointAddress |= num;
+#ifdef MANY_ENDPOINTS
+ } else if (desc->bEndpointAddress & USB_DIR_IN) {
+ if (++in_epnum > 15)
+ return 0;
+ desc->bEndpointAddress = USB_DIR_IN | in_epnum;
+#endif
+ } else {
+ if (++epnum > 15)
+ return 0;
+ desc->bEndpointAddress |= epnum;
+ }
+
+ /* report (variable) full speed bulk maxpacket */
+ if (USB_ENDPOINT_XFER_BULK == type) {
+ int size = ep->maxpacket;
+
+ /* min() doesn't work on bitfields with gcc-3.5 */
+ if (size > 64)
+ size = 64;
+ desc->wMaxPacketSize = cpu_to_le16(size);
+ }
+ return 1;
+}
+
+static struct usb_ep *
+find_ep(struct usb_gadget *gadget, const char *name)
+{
+ struct usb_ep *ep;
+
+ list_for_each_entry(ep, &gadget->ep_list, ep_list) {
+ if (0 == strcmp(ep->name, name))
+ return ep;
+ }
+ return NULL;
+}
+
+/**
+ * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ * initialized. For periodic transfers, the maximum packet
+ * size must also be initialized. This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers. The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware. This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed. To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+ struct usb_gadget *gadget,
+ struct usb_endpoint_descriptor *desc
+)
+{
+ struct usb_ep *ep;
+ u8 type;
+
+ type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ /* First, apply chip-specific "best usage" knowledge.
+ * This might make a good usb_gadget_ops hook ...
+ */
+ if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) {
+ /* ep-e, ep-f are PIO with only 64 byte fifos */
+ ep = find_ep(gadget, "ep-e");
+ if (ep && ep_matches(gadget, ep, desc))
+ return ep;
+ ep = find_ep(gadget, "ep-f");
+ if (ep && ep_matches(gadget, ep, desc))
+ return ep;
+
+ } else if (gadget_is_goku(gadget)) {
+ if (USB_ENDPOINT_XFER_INT == type) {
+ /* single buffering is enough */
+ ep = find_ep(gadget, "ep3-bulk");
+ if (ep && ep_matches(gadget, ep, desc))
+ return ep;
+ } else if (USB_ENDPOINT_XFER_BULK == type
+ && (USB_DIR_IN & desc->bEndpointAddress)) {
+ /* DMA may be available */
+ ep = find_ep(gadget, "ep2-bulk");
+ if (ep && ep_matches(gadget, ep, desc))
+ return ep;
+ }
+
+ } else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) {
+ /* single buffering is enough; maybe 8 byte fifo is too */
+ ep = find_ep(gadget, "ep3in-bulk");
+ if (ep && ep_matches(gadget, ep, desc))
+ return ep;
+
+ } else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) {
+ ep = find_ep(gadget, "ep1-bulk");
+ if (ep && ep_matches(gadget, ep, desc))
+ return ep;
+ }
+
+ /* Second, look at endpoints until an unclaimed one looks usable */
+ list_for_each_entry(ep, &gadget->ep_list, ep_list) {
+ if (ep_matches(gadget, ep, desc))
+ return ep;
+ }
+
+ /* Fail */
+ return NULL;
+}
+
+/**
+ * usb_ep_autoconfig_reset - reset endpoint autoconfig state
+ * @gadget: device for which autoconfig state will be reset
+ *
+ * Use this for devices where one configuration may need to assign
+ * endpoint resources very differently from the next one. It clears
+ * state such as ep->driver_data and the record of assigned endpoints
+ * used by usb_ep_autoconfig().
+ */
+void usb_ep_autoconfig_reset(struct usb_gadget *gadget)
+{
+ struct usb_ep *ep;
+
+ list_for_each_entry(ep, &gadget->ep_list, ep_list) {
+ ep->driver_data = NULL;
+ }
+#ifdef MANY_ENDPOINTS
+ in_epnum = 0;
+#endif
+ epnum = 0;
+}
+
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
new file mode 100644
index 0000000000..bc6480c78d
--- /dev/null
+++ b/drivers/usb/gadget/ether.c
@@ -0,0 +1,1976 @@
+/*
+ * ether.c -- Ethernet gadget driver, with CDC and non-CDC options
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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 <common.h>
+#include <asm/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/gadget.h>
+#include <net.h>
+#include <linux/ctype.h>
+
+#include "gadget_chips.h"
+
+#define USB_NET_NAME "usb0"
+
+#define atomic_read
+extern struct platform_data brd;
+#define spin_lock(x)
+#define spin_unlock(x)
+
+
+unsigned packet_received, packet_sent;
+
+#define DEV_CONFIG_CDC 1
+#define GFP_ATOMIC ((gfp_t) 0)
+#define GFP_KERNEL ((gfp_t) 0)
+
+/*
+ * Ethernet gadget driver -- with CDC and non-CDC options
+ * Builds on hardware support for a full duplex link.
+ *
+ * CDC Ethernet is the standard USB solution for sending Ethernet frames
+ * using USB. Real hardware tends to use the same framing protocol but look
+ * different for control features. This driver strongly prefers to use
+ * this USB-IF standard as its open-systems interoperability solution;
+ * most host side USB stacks (except from Microsoft) support it.
+ *
+ * This is sometimes called "CDC ECM" (Ethernet Control Model) to support
+ * TLA-soup. "CDC ACM" (Abstract Control Model) is for modems, and a new
+ * "CDC EEM" (Ethernet Emulation Model) is starting to spread.
+ *
+ * There's some hardware that can't talk CDC ECM. We make that hardware
+ * implement a "minimalist" vendor-agnostic CDC core: same framing, but
+ * link-level setup only requires activating the configuration. Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available. Linux supports it, but other host operating
+ * systems may not. (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs. So we do that, making it easier to use
+ * those MS-Windows drivers. Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all. (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
+ *
+ * A third option is also in use. Rather than CDC Ethernet, or something
+ * simpler, Microsoft pushes their own approach: RNDIS. The published
+ * RNDIS specs are ambiguous and appear to be incomplete, and are also
+ * needlessly complex. They borrow more from CDC ACM than CDC ECM.
+ */
+#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
+#define ETH_FCS_LEN 4 /* Octets in the FCS */
+
+#define DRIVER_DESC "Ethernet Gadget"
+/* Based on linux 2.6.27 version */
+#define DRIVER_VERSION "May Day 2005"
+
+static const char shortname[] = "ether";
+static const char driver_desc[] = DRIVER_DESC;
+
+#define RX_EXTRA 20 /* guard against rx overflows */
+
+/* CDC support the same host-chosen outgoing packet filters. */
+#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
+ |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+ |USB_CDC_PACKET_TYPE_PROMISCUOUS \
+ |USB_CDC_PACKET_TYPE_DIRECTED)
+
+#define USB_CONNECT_TIMEOUT (3 * CONFIG_SYS_HZ)
+
+/*-------------------------------------------------------------------------*/
+static struct eth_dev l_ethdev;
+static struct eth_device l_netdev;
+static struct usb_gadget_driver eth_driver;
+
+/*-------------------------------------------------------------------------*/
+
+/* "main" config is either CDC, or its simple subset */
+static inline int is_cdc(struct eth_dev *dev)
+{
+#if !defined(DEV_CONFIG_SUBSET)
+ return 1; /* only cdc possible */
+#elif !defined(DEV_CONFIG_CDC)
+ return 0; /* only subset possible */
+#else
+ return dev->cdc; /* depends on what hardware we found */
+#endif
+}
+
+#define subset_active(dev) (!is_cdc(dev))
+#define cdc_active(dev) (is_cdc(dev))
+
+#define DEFAULT_QLEN 2 /* double buffering by default */
+
+/* peak bulk transfer bits-per-second */
+#define HS_BPS (13 * 512 * 8 * 1000 * 8)
+#define FS_BPS (19 * 64 * 1 * 1000 * 8)
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+#define DEVSPEED USB_SPEED_HIGH
+
+#ifdef CONFIG_USB_ETH_QMULT
+#define qmult CONFIG_USB_ETH_QMULT
+#else
+#define qmult 5
+#endif
+
+/* for dual-speed hardware, use deeper queues at highspeed */
+#define qlen(gadget) \
+ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
+
+static inline int BITRATE(struct usb_gadget *g)
+{
+ return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
+}
+
+#else /* full speed (low speed doesn't do bulk) */
+
+#define qmult 1
+
+#define DEVSPEED USB_SPEED_FULL
+
+#define qlen(gadget) DEFAULT_QLEN
+
+static inline int BITRATE(struct usb_gadget *g)
+{
+ return FS_BPS;
+}
+#endif
+
+struct eth_dev {
+ struct usb_gadget *gadget;
+ struct usb_request *req; /* for control responses */
+ struct usb_request *stat_req; /* for cdc status */
+
+ u8 config;
+ struct usb_ep *in_ep, *out_ep, *status_ep;
+ const struct usb_endpoint_descriptor
+ *in, *out, *status;
+
+ struct usb_request *tx_req, *rx_req;
+
+ struct eth_device *net;
+ unsigned int tx_qlen;
+
+ unsigned zlp:1;
+ unsigned cdc:1;
+ unsigned suspended:1;
+ unsigned network_started:1;
+ u16 cdc_filter;
+ unsigned long todo;
+ int mtu;
+#define WORK_RX_MEMORY 0
+ u8 host_mac[ETH_ALEN];
+};
+
+/*
+ * This version autoconfigures as much as possible at run-time.
+ *
+ * It also ASSUMES a self-powered device, without remote wakeup,
+ * although remote wakeup support would make sense.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ * It's for devices with only CDC Ethernet configurations.
+ */
+#define CDC_VENDOR_NUM 0x0525 /* NetChip */
+#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
+
+/*
+ * For hardware that can't talk CDC, we use the same vendor ID that
+ * ARM Linux has used for ethernet-over-usb, both with sa1100 and
+ * with pxa250. We're protocol-compatible, if the host-side drivers
+ * use the endpoint descriptors. bcdDevice (version) is nonzero, so
+ * drivers that need to hard-wire endpoint numbers have a hook.
+ *
+ * The protocol is a minimal subset of CDC Ether, which works on any bulk
+ * hardware that's not deeply broken ... even on hardware that can't talk
+ * RNDIS (like SA-1100, with no interrupt endpoint, or anything that
+ * doesn't handle control-OUT).
+ */
+#define SIMPLE_VENDOR_NUM 0x049f
+#define SIMPLE_PRODUCT_NUM 0x505a
+
+/*
+ * Some systems will want different product identifers published in the
+ * device descriptor, either numbers or strings or both. These string
+ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+static ushort bcdDevice;
+#if defined(CONFIG_USBNET_MANUFACTURER)
+static char *iManufacturer = CONFIG_USBNET_MANUFACTURER;
+#else
+static char *iManufacturer = "U-boot";
+#endif
+static char *iProduct;
+static char *iSerialNumber;
+static char dev_addr[18];
+static char host_addr[18];
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB DRIVER HOOKUP (to the hardware driver, below us), mostly
+ * ep0 implementation: descriptors, config management, setup().
+ * also optional class-specific notification interrupt transfer.
+ */
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand. For now we do either full CDC, or
+ * our simple subset.
+ */
+
+#define STRING_MANUFACTURER 1
+#define STRING_PRODUCT 2
+#define STRING_ETHADDR 3
+#define STRING_DATA 4
+#define STRING_CONTROL 5
+#define STRING_CDC 7
+#define STRING_SUBSET 8
+#define STRING_SERIALNUMBER 10
+
+/* holds our biggest descriptor */
+#define USB_BUFSIZ 256
+
+/*
+ * This device advertises one configuration, eth_config,
+ * on hardware supporting at least two configs.
+ *
+ * FIXME define some higher-powered configurations to make it easier
+ * to recharge batteries ...
+ */
+
+#define DEV_CONFIG_VALUE 1 /* cdc or subset */
+
+static struct usb_device_descriptor
+device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+
+ .bDeviceClass = USB_CLASS_COMM,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+
+ .idVendor = __constant_cpu_to_le16(CDC_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(CDC_PRODUCT_NUM),
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .bNumConfigurations = 1,
+};
+
+static struct usb_otg_descriptor
+otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+
+ .bmAttributes = USB_OTG_SRP,
+};
+
+static struct usb_config_descriptor
+eth_config = {
+ .bLength = sizeof eth_config,
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* compute wTotalLength on the fly */
+ .bNumInterfaces = 2,
+ .bConfigurationValue = DEV_CONFIG_VALUE,
+ .iConfiguration = STRING_CDC,
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .bMaxPower = 1,
+};
+
+/*
+ * Compared to the simple CDC subset, the full CDC Ethernet model adds
+ * three class descriptors, two interface descriptors, optional status
+ * endpoint. Both have a "data" interface and two bulk endpoints.
+ * There are also differences in how control requests are handled.
+ */
+
+#ifdef DEV_CONFIG_CDC
+static struct usb_interface_descriptor
+control_intf = {
+ .bLength = sizeof control_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 0,
+ /* status endpoint is optional; this may be patched later */
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .iInterface = STRING_CONTROL,
+};
+#endif
+
+static const struct usb_cdc_header_desc header_desc = {
+ .bLength = sizeof header_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
+
+ .bcdCDC = __constant_cpu_to_le16(0x0110),
+};
+
+#if defined(DEV_CONFIG_CDC)
+
+static const struct usb_cdc_union_desc union_desc = {
+ .bLength = sizeof union_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_UNION_TYPE,
+
+ .bMasterInterface0 = 0, /* index of control interface */
+ .bSlaveInterface0 = 1, /* index of DATA interface */
+};
+
+#endif /* CDC */
+
+#ifndef DEV_CONFIG_CDC
+
+/*
+ * "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways: data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+ .bLength = sizeof mdlm_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_MDLM_TYPE,
+
+ .bcdVersion = __constant_cpu_to_le16(0x0100),
+ .bGUID = {
+ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+ },
+};
+
+/*
+ * since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct. All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+ 6,
+ USB_DT_CS_INTERFACE,
+ USB_CDC_MDLM_DETAIL_TYPE,
+
+ 0, /* "SAFE" */
+ 0, /* network control capabilities (none) */
+ 0, /* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
+
+static const struct usb_cdc_ether_desc ether_desc = {
+ .bLength = sizeof(ether_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
+
+ /* this descriptor actually adds value, surprise! */
+ .iMACAddress = STRING_ETHADDR,
+ .bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */
+ .wMaxSegmentSize = __constant_cpu_to_le16(ETH_FRAME_LEN),
+ .wNumberMCFilters = __constant_cpu_to_le16(0),
+ .bNumberPowerFilters = 0,
+};
+
+#if defined(DEV_CONFIG_CDC)
+
+/*
+ * include the status endpoint if we can, even where it's optional.
+ * use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
+ * packet, to simplify cancellation; and a big transfer interval, to
+ * waste less bandwidth.
+ *
+ * some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even
+ * if they ignore the connect/disconnect notifications that real aether
+ * can provide. more advanced cdc configurations might want to support
+ * encapsulated commands (vendor-specific, using control-OUT).
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
+#define STATUS_BYTECOUNT 16 /* 8 byte header + data */
+
+static struct usb_endpoint_descriptor
+fs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT),
+ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+#endif
+
+#ifdef DEV_CONFIG_CDC
+
+/* the default data interface has no endpoints ... */
+
+static const struct usb_interface_descriptor
+data_nop_intf = {
+ .bLength = sizeof data_nop_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+};
+
+/* ... but the "real" data interface has two bulk endpoints */
+
+static const struct usb_interface_descriptor
+data_intf = {
+ .bLength = sizeof data_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = STRING_DATA,
+};
+
+#endif
+
+#ifdef DEV_CONFIG_SUBSET
+
+/*
+ * "Simple" CDC-subset option is a simple vendor-neutral model that most
+ * full speed controllers can handle: one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
+ */
+
+static const struct usb_interface_descriptor
+subset_data_intf = {
+ .bLength = sizeof subset_data_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM,
+ .bInterfaceProtocol = 0,
+ .iInterface = STRING_DATA,
+};
+
+#endif /* SUBSET */
+
+static struct usb_endpoint_descriptor
+fs_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor
+fs_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static const struct usb_descriptor_header *fs_eth_function[11] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+#ifdef DEV_CONFIG_CDC
+ /* "cdc" mode descriptors */
+ (struct usb_descriptor_header *) &control_intf,
+ (struct usb_descriptor_header *) &header_desc,
+ (struct usb_descriptor_header *) &union_desc,
+ (struct usb_descriptor_header *) &ether_desc,
+ /* NOTE: status endpoint may need to be removed */
+ (struct usb_descriptor_header *) &fs_status_desc,
+ /* data interface, with altsetting */
+ (struct usb_descriptor_header *) &data_nop_intf,
+ (struct usb_descriptor_header *) &data_intf,
+ (struct usb_descriptor_header *) &fs_source_desc,
+ (struct usb_descriptor_header *) &fs_sink_desc,
+ NULL,
+#endif /* DEV_CONFIG_CDC */
+};
+
+static inline void fs_subset_descriptors(void)
+{
+#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
+ fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+ fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+ fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+ fs_eth_function[8] = NULL;
+#else
+ fs_eth_function[1] = NULL;
+#endif
+}
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ */
+
+#if defined(DEV_CONFIG_CDC)
+static struct usb_endpoint_descriptor
+hs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT),
+ .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+#endif /* DEV_CONFIG_CDC */
+
+static struct usb_endpoint_descriptor
+hs_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor
+hs_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+};
+
+static struct usb_qualifier_descriptor
+dev_qualifier = {
+ .bLength = sizeof dev_qualifier,
+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_COMM,
+
+ .bNumConfigurations = 1,
+};
+
+static const struct usb_descriptor_header *hs_eth_function[11] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+#ifdef DEV_CONFIG_CDC
+ /* "cdc" mode descriptors */
+ (struct usb_descriptor_header *) &control_intf,
+ (struct usb_descriptor_header *) &header_desc,
+ (struct usb_descriptor_header *) &union_desc,
+ (struct usb_descriptor_header *) &ether_desc,
+ /* NOTE: status endpoint may need to be removed */
+ (struct usb_descriptor_header *) &hs_status_desc,
+ /* data interface, with altsetting */
+ (struct usb_descriptor_header *) &data_nop_intf,
+ (struct usb_descriptor_header *) &data_intf,
+ (struct usb_descriptor_header *) &hs_source_desc,
+ (struct usb_descriptor_header *) &hs_sink_desc,
+ NULL,
+#endif /* DEV_CONFIG_CDC */
+};
+
+static inline void hs_subset_descriptors(void)
+{
+#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
+ hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
+ hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+ hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+ hs_eth_function[8] = NULL;
+#else
+ hs_eth_function[1] = NULL;
+#endif
+}
+
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* descriptors that are built on-demand */
+
+static char manufacturer[50];
+static char product_desc[40] = DRIVER_DESC;
+static char serial_number[20];
+
+/* address that the host will use ... usually assigned at random */
+static char ethaddr[2 * ETH_ALEN + 1];
+
+/* static strings, in UTF-8 */
+static struct usb_string strings[] = {
+ { STRING_MANUFACTURER, manufacturer, },
+ { STRING_PRODUCT, product_desc, },
+ { STRING_SERIALNUMBER, serial_number, },
+ { STRING_DATA, "Ethernet Data", },
+ { STRING_ETHADDR, ethaddr, },
+#ifdef DEV_CONFIG_CDC
+ { STRING_CDC, "CDC Ethernet", },
+ { STRING_CONTROL, "CDC Communications Control", },
+#endif
+#ifdef DEV_CONFIG_SUBSET
+ { STRING_SUBSET, "CDC Ethernet Subset", },
+#endif
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = strings,
+};
+
+/*============================================================================*/
+static u8 control_req[USB_BUFSIZ];
+static u8 status_req[STATUS_BYTECOUNT] __attribute__ ((aligned(4)));
+
+
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+ size_t ret = strlen(src);
+
+ if (size) {
+ size_t len = (ret >= size) ? size - 1 : ret;
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+ }
+ return ret;
+}
+
+/*============================================================================*/
+
+/*
+ * one config, two interfaces: control, data.
+ * complications: class descriptors, and an altsetting.
+ */
+static int
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
+{
+ int len;
+ const struct usb_config_descriptor *config;
+ const struct usb_descriptor_header **function;
+ int hs = 0;
+
+ if (gadget_is_dualspeed(g)) {
+ hs = (g->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
+#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
+
+ if (index >= device_desc.bNumConfigurations)
+ return -EINVAL;
+
+ config = &eth_config;
+ function = which_fn(eth);
+
+ /* for now, don't advertise srp-only devices */
+ if (!is_otg)
+ function++;
+
+ len = usb_gadget_config_buf(config, buf, USB_BUFSIZ, function);
+ if (len < 0)
+ return len;
+ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+ return len;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags);
+
+static int
+set_ether_config(struct eth_dev *dev, gfp_t gfp_flags)
+{
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+#if defined(DEV_CONFIG_CDC)
+ /* status endpoint used for (optionally) CDC */
+ if (!subset_active(dev) && dev->status_ep) {
+ dev->status = ep_desc(gadget, &hs_status_desc,
+ &fs_status_desc);
+ dev->status_ep->driver_data = dev;
+
+ result = usb_ep_enable(dev->status_ep, dev->status);
+ if (result != 0) {
+ debug("enable %s --> %d\n",
+ dev->status_ep->name, result);
+ goto done;
+ }
+ }
+#endif
+
+ dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+ dev->in_ep->driver_data = dev;
+
+ dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+ dev->out_ep->driver_data = dev;
+
+ /*
+ * With CDC, the host isn't allowed to use these two data
+ * endpoints in the default altsetting for the interface.
+ * so we don't activate them yet. Reset from SET_INTERFACE.
+ */
+ if (!cdc_active(dev)) {
+ result = usb_ep_enable(dev->in_ep, dev->in);
+ if (result != 0) {
+ debug("enable %s --> %d\n",
+ dev->in_ep->name, result);
+ goto done;
+ }
+
+ result = usb_ep_enable(dev->out_ep, dev->out);
+ if (result != 0) {
+ debug("enable %s --> %d\n",
+ dev->out_ep->name, result);
+ goto done;
+ }
+ }
+
+done:
+ if (result == 0)
+ result = alloc_requests(dev, qlen(gadget), gfp_flags);
+
+ /* on error, disable any endpoints */
+ if (result < 0) {
+ if (!subset_active(dev) && dev->status_ep)
+ (void) usb_ep_disable(dev->status_ep);
+ dev->status = NULL;
+ (void) usb_ep_disable(dev->in_ep);
+ (void) usb_ep_disable(dev->out_ep);
+ dev->in = NULL;
+ dev->out = NULL;
+ }
+
+ /* caller is responsible for cleanup on error */
+ return result;
+}
+
+static void eth_reset_config(struct eth_dev *dev)
+{
+ if (dev->config == 0)
+ return;
+
+ debug("%s\n", __func__);
+
+ /*
+ * disable endpoints, forcing (synchronous) completion of
+ * pending i/o. then free the requests.
+ */
+
+ if (dev->in) {
+ usb_ep_disable(dev->in_ep);
+ if (dev->tx_req) {
+ usb_ep_free_request(dev->in_ep, dev->tx_req);
+ dev->tx_req = NULL;
+ }
+ }
+ if (dev->out) {
+ usb_ep_disable(dev->out_ep);
+ if (dev->rx_req) {
+ usb_ep_free_request(dev->out_ep, dev->rx_req);
+ dev->rx_req = NULL;
+ }
+ }
+ if (dev->status)
+ usb_ep_disable(dev->status_ep);
+
+ dev->cdc_filter = 0;
+ dev->config = 0;
+}
+
+/*
+ * change our operational config. must agree with the code
+ * that returns config descriptors, and altsetting code.
+ */
+static int eth_set_config(struct eth_dev *dev, unsigned number,
+ gfp_t gfp_flags)
+{
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+ if (gadget_is_sa1100(gadget)
+ && dev->config
+ && dev->tx_qlen != 0) {
+ /* tx fifo is full, but we can't clear it...*/
+ error("can't change configurations");
+ return -ESPIPE;
+ }
+ eth_reset_config(dev);
+
+ switch (number) {
+ case DEV_CONFIG_VALUE:
+ result = set_ether_config(dev, gfp_flags);
+ break;
+ default:
+ result = -EINVAL;
+ /* FALL THROUGH */
+ case 0:
+ break;
+ }
+
+ if (result) {
+ if (number)
+ eth_reset_config(dev);
+ usb_gadget_vbus_draw(dev->gadget,
+ gadget_is_otg(dev->gadget) ? 8 : 100);
+ } else {
+ char *speed;
+ unsigned power;
+
+ power = 2 * eth_config.bMaxPower;
+ usb_gadget_vbus_draw(dev->gadget, power);
+
+ switch (gadget->speed) {
+ case USB_SPEED_FULL:
+ speed = "full"; break;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ case USB_SPEED_HIGH:
+ speed = "high"; break;
+#endif
+ default:
+ speed = "?"; break;
+ }
+
+ dev->config = number;
+ printf("%s speed config #%d: %d mA, %s, using %s\n",
+ speed, number, power, driver_desc,
+ (cdc_active(dev) ? "CDC Ethernet"
+ : "CDC Ethernet Subset"));
+ }
+ return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEV_CONFIG_CDC
+
+/*
+ * The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
+ * only to notify the host about link status changes (which we support) or
+ * report completion of some encapsulated command. Since
+ * we want this CDC Ethernet code to be vendor-neutral, we don't use that
+ * command mechanism; and only one status request is ever queued.
+ */
+static void eth_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct usb_cdc_notification *event = req->buf;
+ int value = req->status;
+ struct eth_dev *dev = ep->driver_data;
+
+ /* issue the second notification if host reads the first */
+ if (event->bNotificationType == USB_CDC_NOTIFY_NETWORK_CONNECTION
+ && value == 0) {
+ __le32 *data = req->buf + sizeof *event;
+
+ event->bmRequestType = 0xA1;
+ event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
+ event->wValue = __constant_cpu_to_le16(0);
+ event->wIndex = __constant_cpu_to_le16(1);
+ event->wLength = __constant_cpu_to_le16(8);
+
+ /* SPEED_CHANGE data is up/down speeds in bits/sec */
+ data[0] = data[1] = cpu_to_le32(BITRATE(dev->gadget));
+
+ req->length = STATUS_BYTECOUNT;
+ value = usb_ep_queue(ep, req, GFP_ATOMIC);
+ debug("send SPEED_CHANGE --> %d\n", value);
+ if (value == 0)
+ return;
+ } else if (value != -ECONNRESET) {
+ debug("event %02x --> %d\n",
+ event->bNotificationType, value);
+ if (event->bNotificationType ==
+ USB_CDC_NOTIFY_SPEED_CHANGE) {
+ l_ethdev.network_started = 1;
+ printf("USB network up!\n");
+ }
+ }
+ req->context = NULL;
+}
+
+static void issue_start_status(struct eth_dev *dev)
+{
+ struct usb_request *req = dev->stat_req;
+ struct usb_cdc_notification *event;
+ int value;
+
+ /*
+ * flush old status
+ *
+ * FIXME ugly idiom, maybe we'd be better with just
+ * a "cancel the whole queue" primitive since any
+ * unlink-one primitive has way too many error modes.
+ * here, we "know" toggle is already clear...
+ *
+ * FIXME iff req->context != null just dequeue it
+ */
+ usb_ep_disable(dev->status_ep);
+ usb_ep_enable(dev->status_ep, dev->status);
+
+ /*
+ * 3.8.1 says to issue first NETWORK_CONNECTION, then
+ * a SPEED_CHANGE. could be useful in some configs.
+ */
+ event = req->buf;
+ event->bmRequestType = 0xA1;
+ event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
+ event->wValue = __constant_cpu_to_le16(1); /* connected */
+ event->wIndex = __constant_cpu_to_le16(1);
+ event->wLength = 0;
+
+ req->length = sizeof *event;
+ req->complete = eth_status_complete;
+ req->context = dev;
+
+ value = usb_ep_queue(dev->status_ep, req, GFP_ATOMIC);
+ if (value < 0)
+ debug("status buf queue --> %d\n", value);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void eth_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ if (req->status || req->actual != req->length)
+ debug("setup complete --> %d, %d/%d\n",
+ req->status, req->actual, req->length);
+}
+
+/*
+ * The setup() callback implements all the ep0 functionality that's not
+ * handled lower down. CDC has a number of less-common features:
+ *
+ * - two interfaces: control, and ethernet data
+ * - Ethernet data interface has two altsettings: default, and active
+ * - class-specific descriptors for the control interface
+ * - class-specific control requests
+ */
+static int
+eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+ struct eth_dev *dev = get_gadget_data(gadget);
+ struct usb_request *req = dev->req;
+ int value = -EOPNOTSUPP;
+ u16 wIndex = le16_to_cpu(ctrl->wIndex);
+ u16 wValue = le16_to_cpu(ctrl->wValue);
+ u16 wLength = le16_to_cpu(ctrl->wLength);
+
+ /*
+ * descriptors just go into the pre-allocated ep0 buffer,
+ * while config change events may enable network traffic.
+ */
+
+ debug("%s\n", __func__);
+
+ req->complete = eth_setup_complete;
+ switch (ctrl->bRequest) {
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ switch (wValue >> 8) {
+
+ case USB_DT_DEVICE:
+ value = min(wLength, (u16) sizeof device_desc);
+ memcpy(req->buf, &device_desc, value);
+ break;
+ case USB_DT_DEVICE_QUALIFIER:
+ if (!gadget_is_dualspeed(gadget))
+ break;
+ value = min(wLength, (u16) sizeof dev_qualifier);
+ memcpy(req->buf, &dev_qualifier, value);
+ break;
+
+ case USB_DT_OTHER_SPEED_CONFIG:
+ if (!gadget_is_dualspeed(gadget))
+ break;
+ /* FALLTHROUGH */
+ case USB_DT_CONFIG:
+ value = config_buf(gadget, req->buf,
+ wValue >> 8,
+ wValue & 0xff,
+ gadget_is_otg(gadget));
+ if (value >= 0)
+ value = min(wLength, (u16) value);
+ break;
+
+ case USB_DT_STRING:
+ value = usb_gadget_get_string(&stringtab,
+ wValue & 0xff, req->buf);
+
+ if (value >= 0)
+ value = min(wLength, (u16) value);
+
+ break;
+ }
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (ctrl->bRequestType != 0)
+ break;
+ if (gadget->a_hnp_support)
+ debug("HNP available\n");
+ else if (gadget->a_alt_hnp_support)
+ debug("HNP needs a different root port\n");
+ value = eth_set_config(dev, wValue, GFP_ATOMIC);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ *(u8 *)req->buf = dev->config;
+ value = min(wLength, (u16) 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ if (ctrl->bRequestType != USB_RECIP_INTERFACE
+ || !dev->config
+ || wIndex > 1)
+ break;
+ if (!cdc_active(dev) && wIndex != 0)
+ break;
+
+ /*
+ * PXA hardware partially handles SET_INTERFACE;
+ * we need to kluge around that interference.
+ */
+ if (gadget_is_pxa(gadget)) {
+ value = eth_set_config(dev, DEV_CONFIG_VALUE,
+ GFP_ATOMIC);
+ goto done_set_intf;
+ }
+
+#ifdef DEV_CONFIG_CDC
+ switch (wIndex) {
+ case 0: /* control/master intf */
+ if (wValue != 0)
+ break;
+ if (dev->status) {
+ usb_ep_disable(dev->status_ep);
+ usb_ep_enable(dev->status_ep, dev->status);
+ }
+ value = 0;
+ break;
+ case 1: /* data intf */
+ if (wValue > 1)
+ break;
+ usb_ep_disable(dev->in_ep);
+ usb_ep_disable(dev->out_ep);
+
+ /*
+ * CDC requires the data transfers not be done from
+ * the default interface setting ... also, setting
+ * the non-default interface resets filters etc.
+ */
+ if (wValue == 1) {
+ if (!cdc_active(dev))
+ break;
+ usb_ep_enable(dev->in_ep, dev->in);
+ usb_ep_enable(dev->out_ep, dev->out);
+ dev->cdc_filter = DEFAULT_FILTER;
+ if (dev->status)
+ issue_start_status(dev);
+ }
+
+ value = 0;
+ break;
+ }
+#else
+ /*
+ * FIXME this is wrong, as is the assumption that
+ * all non-PXA hardware talks real CDC ...
+ */
+ debug("set_interface ignored!\n");
+#endif /* DEV_CONFIG_CDC */
+
+done_set_intf:
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+ || !dev->config
+ || wIndex > 1)
+ break;
+ if (!(cdc_active(dev)) && wIndex != 0)
+ break;
+
+ /* for CDC, iff carrier is on, data interface is active. */
+ if (wIndex != 1)
+ *(u8 *)req->buf = 0;
+ else {
+ /* *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; */
+ /* carrier always ok ...*/
+ *(u8 *)req->buf = 1 ;
+ }
+ value = min(wLength, (u16) 1);
+ break;
+
+#ifdef DEV_CONFIG_CDC
+ case USB_CDC_SET_ETHERNET_PACKET_FILTER:
+ /*
+ * see 6.2.30: no data, wIndex = interface,
+ * wValue = packet filter bitmap
+ */
+ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+ || !cdc_active(dev)
+ || wLength != 0
+ || wIndex > 1)
+ break;
+ debug("packet filter %02x\n", wValue);
+ dev->cdc_filter = wValue;
+ value = 0;
+ break;
+
+ /*
+ * and potentially:
+ * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+ * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
+ * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
+ * case USB_CDC_GET_ETHERNET_STATISTIC:
+ */
+
+#endif /* DEV_CONFIG_CDC */
+
+ default:
+ debug("unknown control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ wValue, wIndex, wLength);
+ }
+
+ /* respond with data transfer before status phase? */
+ if (value >= 0) {
+ debug("respond with data transfer before status phase\n");
+ req->length = value;
+ req->zero = value < wLength
+ && (value % gadget->ep0->maxpacket) == 0;
+ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ debug("ep_queue --> %d\n", value);
+ req->status = 0;
+ eth_setup_complete(gadget->ep0, req);
+ }
+ }
+
+ /* host either stalls (value < 0) or reports success */
+ return value;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req);
+
+static int rx_submit(struct eth_dev *dev, struct usb_request *req,
+ gfp_t gfp_flags)
+{
+ int retval = -ENOMEM;
+ size_t size;
+
+ /*
+ * Padding up to RX_EXTRA handles minor disagreements with host.
+ * Normally we use the USB "terminate on short read" convention;
+ * so allow up to (N*maxpacket), since that memory is normally
+ * already allocated. Some hardware doesn't deal well with short
+ * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
+ * byte off the end (to force hardware errors on overflow).
+ */
+
+ debug("%s\n", __func__);
+
+ size = (ETHER_HDR_SIZE + dev->mtu + RX_EXTRA);
+ size += dev->out_ep->maxpacket - 1;
+ size -= size % dev->out_ep->maxpacket;
+
+ /*
+ * Some platforms perform better when IP packets are aligned,
+ * but on at least one, checksumming fails otherwise.
+ */
+
+ req->buf = (u8 *) NetRxPackets[0];
+ req->length = size;
+ req->complete = rx_complete;
+
+ retval = usb_ep_queue(dev->out_ep, req, gfp_flags);
+
+ if (retval)
+ error("rx submit --> %d", retval);
+
+ return retval;
+}
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct eth_dev *dev = ep->driver_data;
+
+ debug("%s: status %d\n", __func__, req->status);
+
+ packet_received = 1;
+
+ if (req)
+ dev->rx_req = req;
+}
+
+static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags)
+{
+
+ dev->tx_req = usb_ep_alloc_request(dev->in_ep, 0);
+
+ if (!dev->tx_req)
+ goto fail;
+
+ dev->rx_req = usb_ep_alloc_request(dev->out_ep, 0);
+
+ if (!dev->rx_req)
+ goto fail;
+
+ return 0;
+
+fail:
+ error("can't alloc requests");
+ return -1;
+}
+
+static void tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ debug("%s: status %s\n", __func__, (req->status) ? "failed" : "ok");
+ packet_sent = 1;
+}
+
+static inline int eth_is_promisc(struct eth_dev *dev)
+{
+ /* no filters for the CDC subset; always promisc */
+ if (subset_active(dev))
+ return 1;
+ return dev->cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
+}
+
+#if 0
+static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
+{
+ struct eth_dev *dev = netdev_priv(net);
+ int length = skb->len;
+ int retval;
+ struct usb_request *req = NULL;
+ unsigned long flags;
+
+ /* apply outgoing CDC or RNDIS filters */
+ if (!eth_is_promisc (dev)) {
+ u8 *dest = skb->data;
+
+ if (is_multicast_ether_addr(dest)) {
+ u16 type;
+
+ /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
+ * SET_ETHERNET_MULTICAST_FILTERS requests
+ */
+ if (is_broadcast_ether_addr(dest))
+ type = USB_CDC_PACKET_TYPE_BROADCAST;
+ else
+ type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
+ if (!(dev->cdc_filter & type)) {
+ dev_kfree_skb_any (skb);
+ return 0;
+ }
+ }
+ /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
+ }
+
+ spin_lock_irqsave(&dev->req_lock, flags);
+ /*
+ * this freelist can be empty if an interrupt triggered disconnect()
+ * and reconfigured the gadget (shutting down this queue) after the
+ * network stack decided to xmit but before we got the spinlock.
+ */
+ if (list_empty(&dev->tx_reqs)) {
+ spin_unlock_irqrestore(&dev->req_lock, flags);
+ return 1;
+ }
+
+ req = container_of (dev->tx_reqs.next, struct usb_request, list);
+ list_del (&req->list);
+
+ /* temporarily stop TX queue when the freelist empties */
+ if (list_empty (&dev->tx_reqs))
+ netif_stop_queue (net);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
+
+ /* no buffer copies needed, unless the network stack did it
+ * or the hardware can't use skb buffers.
+ * or there's not enough space for any RNDIS headers we need
+ */
+ if (rndis_active(dev)) {
+ struct sk_buff *skb_rndis;
+
+ skb_rndis = skb_realloc_headroom (skb,
+ sizeof (struct rndis_packet_msg_type));
+ if (!skb_rndis)
+ goto drop;
+
+ dev_kfree_skb_any (skb);
+ skb = skb_rndis;
+ rndis_add_hdr (skb);
+ length = skb->len;
+ }
+ req->buf = skb->data;
+ req->context = skb;
+ req->complete = tx_complete;
+
+ /* use zlp framing on tx for strict CDC-Ether conformance,
+ * though any robust network rx path ignores extra padding.
+ * and some hardware doesn't like to write zlps.
+ */
+ req->zero = 1;
+ if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0)
+ length++;
+
+ req->length = length;
+
+ /* throttle highspeed IRQ rate back slightly */
+ if (gadget_is_dualspeed(dev->gadget))
+ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+ ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+ : 0;
+
+ retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+ switch (retval) {
+ default:
+ DEBUG (dev, "tx queue err %d\n", retval);
+ break;
+ case 0:
+ net->trans_start = jiffies;
+ atomic_inc (&dev->tx_qlen);
+ }
+
+ if (retval) {
+drop:
+ dev->stats.tx_dropped++;
+ dev_kfree_skb_any (skb);
+ spin_lock_irqsave(&dev->req_lock, flags);
+ if (list_empty (&dev->tx_reqs))
+ netif_start_queue (net);
+ list_add (&req->list, &dev->tx_reqs);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#endif
+
+static void eth_unbind(struct usb_gadget *gadget)
+{
+ struct eth_dev *dev = get_gadget_data(gadget);
+
+ debug("%s...\n", __func__);
+
+ /* we've already been disconnected ... no i/o is active */
+ if (dev->req) {
+ usb_ep_free_request(gadget->ep0, dev->req);
+ dev->req = NULL;
+ }
+ if (dev->stat_req) {
+ usb_ep_free_request(dev->status_ep, dev->stat_req);
+ dev->stat_req = NULL;
+ }
+
+ if (dev->tx_req) {
+ usb_ep_free_request(dev->in_ep, dev->tx_req);
+ dev->tx_req = NULL;
+ }
+
+ if (dev->rx_req) {
+ usb_ep_free_request(dev->out_ep, dev->rx_req);
+ dev->rx_req = NULL;
+ }
+
+/* unregister_netdev (dev->net);*/
+/* free_netdev(dev->net);*/
+
+ set_gadget_data(gadget, NULL);
+}
+
+static void eth_disconnect(struct usb_gadget *gadget)
+{
+ eth_reset_config(get_gadget_data(gadget));
+}
+
+static void eth_suspend(struct usb_gadget *gadget)
+{
+ /* Not used */
+}
+
+static void eth_resume(struct usb_gadget *gadget)
+{
+ /* Not used */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int is_eth_addr_valid(char *str)
+{
+ if (strlen(str) == 17) {
+ int i;
+ char *p, *q;
+ uchar ea[6];
+
+ /* see if it looks like an ethernet address */
+
+ p = str;
+
+ for (i = 0; i < 6; i++) {
+ char term = (i == 5 ? '\0' : ':');
+
+ ea[i] = simple_strtol(p, &q, 16);
+
+ if ((q - p) != 2 || *q++ != term)
+ break;
+
+ p = q;
+ }
+
+ if (i == 6) /* it looks ok */
+ return 1;
+ }
+ return 0;
+}
+
+static u8 nibble(unsigned char c)
+{
+ if (likely(isdigit(c)))
+ return c - '0';
+ c = toupper(c);
+ if (likely(isxdigit(c)))
+ return 10 + c - 'A';
+ return 0;
+}
+
+static int get_ether_addr(const char *str, u8 *dev_addr)
+{
+ if (str) {
+ unsigned i;
+
+ for (i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if ((*str == '.') || (*str == ':'))
+ str++;
+ num = nibble(*str++) << 4;
+ num |= (nibble(*str++));
+ dev_addr[i] = num;
+ }
+ if (is_valid_ether_addr(dev_addr))
+ return 0;
+ }
+ return 1;
+}
+
+static int eth_bind(struct usb_gadget *gadget)
+{
+ struct eth_dev *dev = &l_ethdev;
+ u8 cdc = 1, zlp = 1;
+ struct usb_ep *in_ep, *out_ep, *status_ep = NULL;
+ int gcnum;
+ u8 tmp[7];
+
+ /* these flags are only ever cleared; compiler take note */
+#ifndef DEV_CONFIG_CDC
+ cdc = 0;
+#endif
+ /*
+ * Because most host side USB stacks handle CDC Ethernet, that
+ * standard protocol is _strongly_ preferred for interop purposes.
+ * (By everyone except Microsoft.)
+ */
+ if (gadget_is_pxa(gadget)) {
+ /* pxa doesn't support altsettings */
+ cdc = 0;
+ } else if (gadget_is_musbhdrc(gadget)) {
+ /* reduce tx dma overhead by avoiding special cases */
+ zlp = 0;
+ } else if (gadget_is_sh(gadget)) {
+ /* sh doesn't support multiple interfaces or configs */
+ cdc = 0;
+ } else if (gadget_is_sa1100(gadget)) {
+ /* hardware can't write zlps */
+ zlp = 0;
+ /*
+ * sa1100 CAN do CDC, without status endpoint ... we use
+ * non-CDC to be compatible with ARM Linux-2.4 "usb-eth".
+ */
+ cdc = 0;
+ }
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+ device_desc.bcdDevice = cpu_to_le16(0x0300 + gcnum);
+ else {
+ /*
+ * can't assume CDC works. don't want to default to
+ * anything less functional on CDC-capable hardware,
+ * so we fail in this case.
+ */
+ error("controller '%s' not recognized",
+ gadget->name);
+ return -ENODEV;
+ }
+
+ /*
+ * CDC subset ... recognized by Linux since 2.4.10, but Windows
+ * drivers aren't widely available. (That may be improved by
+ * supporting one submode of the "SAFE" variant of MDLM.)
+ */
+ if (!cdc) {
+ device_desc.idVendor =
+ __constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
+ device_desc.idProduct =
+ __constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);
+ }
+
+ /* support optional vendor/distro customization */
+#if defined(CONFIG_USB_CDC_VENDOR_ID) && defined(CONFIG_USB_CDC_PRODUCT_ID)
+ device_desc.idVendor = cpu_to_le16(CONFIG_USB_CDC_VENDOR_ID);
+ device_desc.idProduct = cpu_to_le16(CONFIG_USB_CDC_PRODUCT_ID);
+#endif
+ if (bcdDevice)
+ device_desc.bcdDevice = cpu_to_le16(bcdDevice);
+ if (iManufacturer)
+ strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
+ if (iProduct)
+ strlcpy(product_desc, iProduct, sizeof product_desc);
+ if (iSerialNumber) {
+ device_desc.iSerialNumber = STRING_SERIALNUMBER,
+ strlcpy(serial_number, iSerialNumber, sizeof serial_number);
+ }
+
+ /* all we really need is bulk IN/OUT */
+ usb_ep_autoconfig_reset(gadget);
+ in_ep = usb_ep_autoconfig(gadget, &fs_source_desc);
+ if (!in_ep) {
+autoconf_fail:
+ error("can't autoconfigure on %s\n",
+ gadget->name);
+ return -ENODEV;
+ }
+ in_ep->driver_data = in_ep; /* claim */
+
+ out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
+ if (!out_ep)
+ goto autoconf_fail;
+ out_ep->driver_data = out_ep; /* claim */
+
+#if defined(DEV_CONFIG_CDC)
+ /*
+ * CDC Ethernet control interface doesn't require a status endpoint.
+ * Since some hosts expect one, try to allocate one anyway.
+ */
+ if (cdc) {
+ status_ep = usb_ep_autoconfig(gadget, &fs_status_desc);
+ if (status_ep) {
+ status_ep->driver_data = status_ep; /* claim */
+ } else if (cdc) {
+ control_intf.bNumEndpoints = 0;
+ /* FIXME remove endpoint from descriptor list */
+ }
+ }
+#endif
+
+ /* one config: cdc, else minimal subset */
+ if (!cdc) {
+ eth_config.bNumInterfaces = 1;
+ eth_config.iConfiguration = STRING_SUBSET;
+
+ /*
+ * use functions to set these up, in case we're built to work
+ * with multiple controllers and must override CDC Ethernet.
+ */
+ fs_subset_descriptors();
+ hs_subset_descriptors();
+ }
+
+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+ usb_gadget_set_selfpowered(gadget);
+
+ if (gadget_is_dualspeed(gadget)) {
+ if (!cdc)
+ dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+
+ /* assumes ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress =
+ fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress =
+ fs_sink_desc.bEndpointAddress;
+#if defined(DEV_CONFIG_CDC)
+ if (status_ep)
+ hs_status_desc.bEndpointAddress =
+ fs_status_desc.bEndpointAddress;
+#endif
+ }
+
+ if (gadget_is_otg(gadget)) {
+ otg_descriptor.bmAttributes |= USB_OTG_HNP,
+ eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ eth_config.bMaxPower = 4;
+ }
+
+ dev->net = &l_netdev;
+ strcpy(dev->net->name, USB_NET_NAME);
+
+ dev->cdc = cdc;
+ dev->zlp = zlp;
+
+ dev->in_ep = in_ep;
+ dev->out_ep = out_ep;
+ dev->status_ep = status_ep;
+
+ /*
+ * Module params for these addresses should come from ID proms.
+ * The host side address is used with CDC, and commonly
+ * ends up in a persistent config database. It's not clear if
+ * host side code for the SAFE thing cares -- its original BLAN
+ * thing didn't, Sharp never assigned those addresses on Zaurii.
+ */
+ get_ether_addr(dev_addr, dev->net->enetaddr);
+
+ memset(tmp, 0, sizeof(tmp));
+ memcpy(tmp, dev->net->enetaddr, sizeof(dev->net->enetaddr));
+
+ get_ether_addr(host_addr, dev->host_mac);
+
+ sprintf(ethaddr, "%02X%02X%02X%02X%02X%02X",
+ dev->host_mac[0], dev->host_mac[1],
+ dev->host_mac[2], dev->host_mac[3],
+ dev->host_mac[4], dev->host_mac[5]);
+
+ printf("using %s, OUT %s IN %s%s%s\n", gadget->name,
+ out_ep->name, in_ep->name,
+ status_ep ? " STATUS " : "",
+ status_ep ? status_ep->name : ""
+ );
+ printf("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->net->enetaddr[0], dev->net->enetaddr[1],
+ dev->net->enetaddr[2], dev->net->enetaddr[3],
+ dev->net->enetaddr[4], dev->net->enetaddr[5]);
+
+ if (cdc) {
+ printf("HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->host_mac[0], dev->host_mac[1],
+ dev->host_mac[2], dev->host_mac[3],
+ dev->host_mac[4], dev->host_mac[5]);
+ }
+
+ /*
+ * use PKTSIZE (or aligned... from u-boot) and set
+ * wMaxSegmentSize accordingly
+ */
+ dev->mtu = PKTSIZE_ALIGN; /* RNDIS does not like this, only 1514, TODO*/
+
+ /* preallocate control message data and buffer */
+ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+ if (!dev->req)
+ goto fail;
+ dev->req->buf = control_req;
+ dev->req->complete = eth_setup_complete;
+
+ /* ... and maybe likewise for status transfer */
+#if defined(DEV_CONFIG_CDC)
+ if (dev->status_ep) {
+ dev->stat_req = usb_ep_alloc_request(dev->status_ep,
+ GFP_KERNEL);
+ if (!dev->stat_req) {
+ usb_ep_free_request(dev->status_ep, dev->req);
+
+ goto fail;
+ }
+ dev->stat_req->buf = status_req;
+ dev->stat_req->context = NULL;
+ }
+#endif
+
+ /* finish hookup to lower layer ... */
+ dev->gadget = gadget;
+ set_gadget_data(gadget, dev);
+ gadget->ep0->driver_data = dev;
+
+ /*
+ * two kinds of host-initiated state changes:
+ * - iff DATA transfer is active, carrier is "on"
+ * - tx queueing enabled if open *and* carrier is "on"
+ */
+ return 0;
+
+fail:
+ error("%s failed", __func__);
+ eth_unbind(gadget);
+ return -ENOMEM;
+}
+
+static int usb_eth_init(struct eth_device *netdev, bd_t *bd)
+{
+ struct eth_dev *dev = &l_ethdev;
+ struct usb_gadget *gadget;
+ unsigned long ts;
+ unsigned long timeout = USB_CONNECT_TIMEOUT;
+
+ if (!netdev) {
+ error("received NULL ptr");
+ goto fail;
+ }
+
+ dev->network_started = 0;
+ dev->tx_req = NULL;
+ dev->rx_req = NULL;
+
+ packet_received = 0;
+ packet_sent = 0;
+
+ gadget = dev->gadget;
+ usb_gadget_connect(gadget);
+
+ if (getenv("cdc_connect_timeout"))
+ timeout = simple_strtoul(getenv("cdc_connect_timeout"),
+ NULL, 10) * CONFIG_SYS_HZ;
+ ts = get_timer(0);
+ while (!l_ethdev.network_started) {
+ /* Handle control-c and timeouts */
+ if (ctrlc() || (get_timer(ts) > timeout)) {
+ error("The remote end did not respond in time.");
+ goto fail;
+ }
+ usb_gadget_handle_interrupts();
+ }
+
+ rx_submit(dev, dev->rx_req, 0);
+ return 0;
+fail:
+ return -1;
+}
+
+static int usb_eth_send(struct eth_device *netdev,
+ volatile void *packet, int length)
+{
+ int retval;
+ struct usb_request *req = NULL;
+ struct eth_dev *dev = &l_ethdev;
+ unsigned long ts;
+ unsigned long timeout = USB_CONNECT_TIMEOUT;
+
+ debug("%s:...\n", __func__);
+
+ req = dev->tx_req;
+
+ req->buf = (void *)packet;
+ req->context = NULL;
+ req->complete = tx_complete;
+
+ /*
+ * use zlp framing on tx for strict CDC-Ether conformance,
+ * though any robust network rx path ignores extra padding.
+ * and some hardware doesn't like to write zlps.
+ */
+ req->zero = 1;
+ if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0)
+ length++;
+
+ req->length = length;
+#if 0
+ /* throttle highspeed IRQ rate back slightly */
+ if (gadget_is_dualspeed(dev->gadget))
+ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+ ? ((dev->tx_qlen % qmult) != 0) : 0;
+#endif
+ dev->tx_qlen = 1;
+ ts = get_timer(0);
+ packet_sent = 0;
+
+ retval = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
+
+ if (!retval)
+ debug("%s: packet queued\n", __func__);
+ while (!packet_sent) {
+ if (get_timer(ts) > timeout) {
+ printf("timeout sending packets to usb ethernet\n");
+ return -1;
+ }
+ usb_gadget_handle_interrupts();
+ }
+
+ return 0;
+}
+
+static int usb_eth_recv(struct eth_device *netdev)
+{
+ struct eth_dev *dev = &l_ethdev;
+
+ usb_gadget_handle_interrupts();
+
+ if (packet_received) {
+ debug("%s: packet received\n", __func__);
+ if (dev->rx_req) {
+ NetReceive(NetRxPackets[0], dev->rx_req->length);
+ packet_received = 0;
+
+ if (dev->rx_req)
+ rx_submit(dev, dev->rx_req, 0);
+ } else
+ error("dev->rx_req invalid");
+ }
+ return 0;
+}
+
+void usb_eth_halt(struct eth_device *netdev)
+{
+ struct eth_dev *dev = &l_ethdev;
+
+ if (!netdev) {
+ error("received NULL ptr");
+ return;
+ }
+
+ usb_gadget_disconnect(dev->gadget);
+}
+
+static struct usb_gadget_driver eth_driver = {
+ .speed = DEVSPEED,
+
+ .bind = eth_bind,
+ .unbind = eth_unbind,
+
+ .setup = eth_setup,
+ .disconnect = eth_disconnect,
+
+ .suspend = eth_suspend,
+ .resume = eth_resume,
+};
+
+int usb_eth_initialize(bd_t *bi)
+{
+ int status = 0;
+ struct eth_device *netdev = &l_netdev;
+
+ sprintf(netdev->name, "usb_ether");
+
+ netdev->init = usb_eth_init;
+ netdev->send = usb_eth_send;
+ netdev->recv = usb_eth_recv;
+ netdev->halt = usb_eth_halt;
+
+#ifdef CONFIG_MCAST_TFTP
+ #error not supported
+#endif
+ /* Configure default mac-addresses for the USB ethernet device */
+#ifdef CONFIG_USBNET_DEV_ADDR
+ strncpy(dev_addr, CONFIG_USBNET_DEV_ADDR, sizeof(dev_addr));
+#endif
+#ifdef CONFIG_USBNET_HOST_ADDR
+ strncpy(host_addr, CONFIG_USBNET_HOST_ADDR, sizeof(host_addr));
+#endif
+ /* Check if the user overruled the MAC addresses */
+ if (getenv("usbnet_devaddr"))
+ strncpy(dev_addr, getenv("usbnet_devaddr"),
+ sizeof(dev_addr));
+
+ if (getenv("usbnet_hostaddr"))
+ strncpy(host_addr, getenv("usbnet_hostaddr"),
+ sizeof(host_addr));
+
+ /* Make sure both strings are terminated */
+ dev_addr[sizeof(dev_addr)-1] = '\0';
+ host_addr[sizeof(host_addr)-1] = '\0';
+
+ if (!is_eth_addr_valid(dev_addr)) {
+ error("Need valid 'usbnet_devaddr' to be set");
+ status = -1;
+ }
+ if (!is_eth_addr_valid(host_addr)) {
+ error("Need valid 'usbnet_hostaddr' to be set");
+ status = -1;
+ }
+ if (status)
+ goto fail;
+
+ status = usb_gadget_register_driver(&eth_driver);
+ if (status < 0)
+ goto fail;
+
+ eth_register(netdev);
+ return 0;
+
+fail:
+ error("%s failed. error = %d", __func__, status);
+ return status;
+}
+
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
new file mode 100644
index 0000000000..9bb7e2e77a
--- /dev/null
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -0,0 +1,220 @@
+/*
+ * USB device controllers have lots of quirks. Use these macros in
+ * gadget drivers or other code that needs to deal with them, and which
+ * autoconfigures instead of using early binding to the hardware.
+ *
+ * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
+ * some config file that gets updated as new hardware is supported.
+ * (And avoiding all runtime comparisons in typical one-choice configs!)
+ *
+ * NOTE: some of these controller drivers may not be available yet.
+ * Some are available on 2.4 kernels; several are available, but not
+ * yet pushed in the 2.6 mainline tree.
+ *
+ * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and
+ * Remy Bohmer <linux@bohmer.net>
+ */
+#ifdef CONFIG_USB_GADGET_NET2280
+#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name))
+#else
+#define gadget_is_net2280(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name))
+#else
+#define gadget_is_amd5536udc(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_DUMMY_HCD
+#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name))
+#else
+#define gadget_is_dummy(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_PXA2XX
+#define gadget_is_pxa(g) (!strcmp("pxa2xx_udc", (g)->name))
+#else
+#define gadget_is_pxa(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_GOKU
+#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
+#else
+#define gadget_is_goku(g) 0
+#endif
+
+/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
+#ifdef CONFIG_USB_GADGET_SUPERH
+#define gadget_is_sh(g) (!strcmp("sh_udc", (g)->name))
+#else
+#define gadget_is_sh(g) 0
+#endif
+
+/* not yet stable on 2.6 (would help "original Zaurus") */
+#ifdef CONFIG_USB_GADGET_SA1100
+#define gadget_is_sa1100(g) (!strcmp("sa1100_udc", (g)->name))
+#else
+#define gadget_is_sa1100(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_LH7A40X
+#define gadget_is_lh7a40x(g) (!strcmp("lh7a40x_udc", (g)->name))
+#else
+#define gadget_is_lh7a40x(g) 0
+#endif
+
+/* handhelds.org tree (?) */
+#ifdef CONFIG_USB_GADGET_MQ11XX
+#define gadget_is_mq11xx(g) (!strcmp("mq11xx_udc", (g)->name))
+#else
+#define gadget_is_mq11xx(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_OMAP
+#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name))
+#else
+#define gadget_is_omap(g) 0
+#endif
+
+/* not yet ported 2.4 --> 2.6 */
+#ifdef CONFIG_USB_GADGET_N9604
+#define gadget_is_n9604(g) (!strcmp("n9604_udc", (g)->name))
+#else
+#define gadget_is_n9604(g) 0
+#endif
+
+/* various unstable versions available */
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name))
+#else
+#define gadget_is_pxa27x(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name))
+#else
+#define gadget_is_atmel_usba(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name))
+#else
+#define gadget_is_s3c2410(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_AT91
+#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name))
+#else
+#define gadget_is_at91(g) 0
+#endif
+
+/* status unclear */
+#ifdef CONFIG_USB_GADGET_IMX
+#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name))
+#else
+#define gadget_is_imx(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_FSL_USB2
+#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name))
+#else
+#define gadget_is_fsl_usb2(g) 0
+#endif
+
+/* Mentor high speed function controller */
+/* from Montavista kernel (?) */
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define gadget_is_musbhsfc(g) (!strcmp("musbhsfc_udc", (g)->name))
+#else
+#define gadget_is_musbhsfc(g) 0
+#endif
+
+/* Mentor high speed "dual role" controller, in peripheral role */
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+#define gadget_is_musbhdrc(g) (!strcmp("musb_hdrc", (g)->name))
+#else
+#define gadget_is_musbhdrc(g) 0
+#endif
+
+/* from Montavista kernel (?) */
+#ifdef CONFIG_USB_GADGET_MPC8272
+#define gadget_is_mpc8272(g) (!strcmp("mpc8272_udc", (g)->name))
+#else
+#define gadget_is_mpc8272(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_M66592
+#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name))
+#else
+#define gadget_is_m66592(g) 0
+#endif
+
+
+/*
+ * CONFIG_USB_GADGET_SX2
+ * CONFIG_USB_GADGET_AU1X00
+ * ...
+ */
+
+/**
+ * usb_gadget_controller_number - support bcdDevice id convention
+ * @gadget: the controller being driven
+ *
+ * Return a 2-digit BCD value associated with the peripheral controller,
+ * suitable for use as part of a bcdDevice value, or a negative error code.
+ *
+ * NOTE: this convention is purely optional, and has no meaning in terms of
+ * any USB specification. If you want to use a different convention in your
+ * gadget driver firmware -- maybe a more formal revision ID -- feel free.
+ *
+ * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
+ * to change their behavior accordingly. For example it might help avoiding
+ * some chip bug.
+ */
+static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+{
+ if (gadget_is_net2280(gadget))
+ return 0x01;
+ else if (gadget_is_dummy(gadget))
+ return 0x02;
+ else if (gadget_is_pxa(gadget))
+ return 0x03;
+ else if (gadget_is_sh(gadget))
+ return 0x04;
+ else if (gadget_is_sa1100(gadget))
+ return 0x05;
+ else if (gadget_is_goku(gadget))
+ return 0x06;
+ else if (gadget_is_mq11xx(gadget))
+ return 0x07;
+ else if (gadget_is_omap(gadget))
+ return 0x08;
+ else if (gadget_is_lh7a40x(gadget))
+ return 0x09;
+ else if (gadget_is_n9604(gadget))
+ return 0x10;
+ else if (gadget_is_pxa27x(gadget))
+ return 0x11;
+ else if (gadget_is_s3c2410(gadget))
+ return 0x12;
+ else if (gadget_is_at91(gadget))
+ return 0x13;
+ else if (gadget_is_imx(gadget))
+ return 0x14;
+ else if (gadget_is_musbhsfc(gadget))
+ return 0x15;
+ else if (gadget_is_musbhdrc(gadget))
+ return 0x16;
+ else if (gadget_is_mpc8272(gadget))
+ return 0x17;
+ else if (gadget_is_atmel_usba(gadget))
+ return 0x18;
+ else if (gadget_is_fsl_usb2(gadget))
+ return 0x19;
+ else if (gadget_is_amd5536udc(gadget))
+ return 0x20;
+ else if (gadget_is_m66592(gadget))
+ return 0x21;
+ return -ENOENT;
+}
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
new file mode 100644
index 0000000000..6e9d1bf0f2
--- /dev/null
+++ b/drivers/usb/gadget/usbstring.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and
+ * Remy Bohmer <linux@bohmer.net>
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/unaligned.h>
+
+
+static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
+{
+ int count = 0;
+ u8 c;
+ u16 uchar;
+
+ /*
+ * this insists on correct encodings, though not minimal ones.
+ * BUT it currently rejects legit 4-byte UTF-8 code points,
+ * which need surrogate pairs. (Unicode 3.1 can use them.)
+ */
+ while (len != 0 && (c = (u8) *s++) != 0) {
+ if ((c & 0x80)) {
+ /*
+ * 2-byte sequence:
+ * 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+ */
+ if ((c & 0xe0) == 0xc0) {
+ uchar = (c & 0x1f) << 6;
+
+ c = (u8) *s++;
+ if ((c & 0xc0) != 0x80)
+ goto fail;
+ c &= 0x3f;
+ uchar |= c;
+
+ /*
+ * 3-byte sequence (most CJKV characters):
+ * zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+ */
+ } else if ((c & 0xf0) == 0xe0) {
+ uchar = (c & 0x0f) << 12;
+
+ c = (u8) *s++;
+ if ((c & 0xc0) != 0x80)
+ goto fail;
+ c &= 0x3f;
+ uchar |= c << 6;
+
+ c = (u8) *s++;
+ if ((c & 0xc0) != 0x80)
+ goto fail;
+ c &= 0x3f;
+ uchar |= c;
+
+ /* no bogus surrogates */
+ if (0xd800 <= uchar && uchar <= 0xdfff)
+ goto fail;
+
+ /*
+ * 4-byte sequence (surrogate pairs, currently rare):
+ * 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+ * = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+ * (uuuuu = wwww + 1)
+ * FIXME accept the surrogate code points (only)
+ */
+ } else
+ goto fail;
+ } else
+ uchar = c;
+ put_unaligned_le16(uchar, cp++);
+ count++;
+ len--;
+ }
+ return count;
+fail:
+ return -1;
+}
+
+
+/**
+ * usb_gadget_get_string - fill out a string descriptor
+ * @table: of c strings encoded using UTF-8
+ * @id: string id, from low byte of wValue in get string descriptor
+ * @buf: at least 256 bytes
+ *
+ * Finds the UTF-8 string matching the ID, and converts it into a
+ * string descriptor in utf16-le.
+ * Returns length of descriptor (always even) or negative errno
+ *
+ * If your driver needs stings in multiple languages, you'll probably
+ * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
+ * using this routine after choosing which set of UTF-8 strings to use.
+ * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
+ * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
+ * characters (which are also widely used in C strings).
+ */
+int
+usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf)
+{
+ struct usb_string *s;
+ int len;
+
+ /* descriptor 0 has the language id */
+ if (id == 0) {
+ buf[0] = 4;
+ buf[1] = USB_DT_STRING;
+ buf[2] = (u8) table->language;
+ buf[3] = (u8) (table->language >> 8);
+ return 4;
+ }
+ for (s = table->strings; s && s->s; s++)
+ if (s->id == id)
+ break;
+
+ /* unrecognized: stall. */
+ if (!s || !s->s)
+ return -EINVAL;
+
+ /* string descriptors have length, tag, then UTF16-LE text */
+ len = min((size_t) 126, strlen(s->s));
+ memset(buf + 2, 0, 2 * len); /* zero all the bytes */
+ len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
+ if (len < 0)
+ return -EINVAL;
+ buf[0] = (len + 1) * 2;
+ buf[1] = USB_DT_STRING;
+ return buf[0];
+}
+
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 4771876445..8f73876f80 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -369,6 +369,8 @@ extern void read_fifo(u8 ep, u32 length, void *fifo_data);
# define readb(addr) (u8)bfin_read16(addr)
# undef writeb
# define writeb(b, addr) bfin_write16(addr, b)
+# undef MUSB_TXCSR_MODE /* not supported */
+# define MUSB_TXCSR_MODE 0
/*
* The USB PHY on current Blackfin processors is a UTMI+ level 2 PHY.
* However, it has no ULPI support - so there are no registers at all.
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 3d047f275c..dd849c2dc1 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -1118,8 +1118,44 @@ int video_display_bitmap (ulong bmp_image, int x, int y)
}
#endif
- /* We handle only 8bpp or 24 bpp bitmap */
+ /* We handle only 4, 8, or 24 bpp bitmaps */
switch (le16_to_cpu (bmp->header.bit_count)) {
+ case 4:
+ padded_line -= width / 2;
+ ycount = height;
+
+ switch (VIDEO_DATA_FORMAT) {
+ case GDF_32BIT_X888RGB:
+ while (ycount--) {
+ WATCHDOG_RESET ();
+ /*
+ * Don't assume that 'width' is an
+ * even number
+ */
+ for (xcount = 0; xcount < width; xcount++) {
+ uchar idx;
+
+ if (xcount & 1) {
+ idx = *bmap & 0xF;
+ bmap++;
+ } else
+ idx = *bmap >> 4;
+ cte = bmp->color_table[idx];
+ FILL_32BIT_X888RGB(cte.red, cte.green,
+ cte.blue);
+ }
+ bmap += padded_line;
+ fb -= (VIDEO_VISIBLE_COLS + width) *
+ VIDEO_PIXEL_SIZE;
+ }
+ break;
+ default:
+ puts("4bpp bitmap unsupported with current "
+ "video mode\n");
+ break;
+ }
+ break;
+
case 8:
padded_line -= width;
if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
OpenPOWER on IntegriCloud