From caaf3c0b97b59117cacd221ed4557b2fd351b5b3 Mon Sep 17 00:00:00 2001 From: Frank Gevaerts Date: Sun, 30 Nov 2008 15:43:15 +0000 Subject: Move tcc77x/usb-tcc77x.c to usb-tcc.c as it is more general than just tcc77x (even usb-tcc is too specific, but I don't know anything better) Add #if0ed USB defines to config-cowond2.h, so experimenting with USB is easy Add dummy set_serial_descriptor() implementation to usb_core.c. This one doesn't generate a unique serial, so it must never be used for non-testing purposes. When usaed, a compiler warning will be generated git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19273 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 10 +- firmware/export/config-cowond2.h | 8 + firmware/export/usb-tcc.h | 116 +++++ firmware/export/usb-tcc7xx.h | 116 ----- firmware/target/arm/tcc77x/usb-tcc77x.c | 799 -------------------------------- firmware/target/arm/usb-tcc.c | 799 ++++++++++++++++++++++++++++++++ firmware/usbstack/usb_core.c | 12 +- 7 files changed, 939 insertions(+), 921 deletions(-) create mode 100644 firmware/export/usb-tcc.h delete mode 100644 firmware/export/usb-tcc7xx.h delete mode 100644 firmware/target/arm/tcc77x/usb-tcc77x.c create mode 100644 firmware/target/arm/usb-tcc.c diff --git a/firmware/SOURCES b/firmware/SOURCES index 9b576d435a..d0862ba37b 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1013,7 +1013,7 @@ target/arm/tcc77x/kernel-tcc77x.c target/arm/tcc77x/powermgmt-tcc77x.c target/arm/tcc77x/system-tcc77x.c target/arm/tcc77x/timer-tcc77x.c -target/arm/tcc77x/usb-tcc77x.c +target/arm/usb-tcc.c target/arm/tcc77x/logikdax/button-logikdax.c target/arm/tcc77x/logikdax/power-logikdax.c #ifndef BOOTLOADER @@ -1034,7 +1034,7 @@ target/arm/tcc77x/kernel-tcc77x.c target/arm/tcc77x/powermgmt-tcc77x.c target/arm/tcc77x/system-tcc77x.c target/arm/tcc77x/timer-tcc77x.c -target/arm/tcc77x/usb-tcc77x.c +target/arm/usb-tcc.c target/arm/tcc77x/m200/button-m200.c target/arm/tcc77x/m200/power-m200.c #ifndef BOOTLOADER @@ -1055,7 +1055,7 @@ target/arm/tcc77x/c100/lcd-S6B33B2.c target/arm/tcc77x/powermgmt-tcc77x.c target/arm/tcc77x/system-tcc77x.c target/arm/tcc77x/timer-tcc77x.c -target/arm/tcc77x/usb-tcc77x.c +target/arm/usb-tcc.c target/arm/tcc77x/c100/button-c100.c target/arm/tcc77x/c100/power-c100.c #ifndef BOOTLOADER @@ -1110,7 +1110,7 @@ target/arm/tcc77x/kernel-tcc77x.c target/arm/tcc77x/timer-tcc77x.c target/arm/tcc77x/adc-tcc77x.c target/arm/tcc77x/powermgmt-tcc77x.c -target/arm/tcc77x/usb-tcc77x.c +target/arm/usb-tcc.c target/arm/tcc77x/iaudio7/lcd-iaudio7.c target/arm/tcc77x/iaudio7/power-iaudio7.c target/arm/tcc77x/iaudio7/button-iaudio7.c @@ -1135,8 +1135,8 @@ target/arm/tcc780x/cowond2/button-cowond2.c target/arm/tcc780x/cowond2/lcd-cowond2.c target/arm/tcc780x/cowond2/power-cowond2.c target/arm/tcc780x/cowond2/powermgmt-cowond2.c -target/arm/tcc780x/cowond2/usb-cowond2.c target/arm/tcc780x/cowond2/backlight-cowond2.c +target/arm/usb-tcc.c #ifndef BOOTLOADER target/arm/tcc780x/kernel-tcc780x.c target/arm/tcc780x/timer-tcc780x.c diff --git a/firmware/export/config-cowond2.h b/firmware/export/config-cowond2.h index c6e4555f18..edeb834ef7 100644 --- a/firmware/export/config-cowond2.h +++ b/firmware/export/config-cowond2.h @@ -8,6 +8,14 @@ #define MODEL_NAME "Cowon D2" +#if 0 +#define HAVE_USBSTACK +#define USE_ROCKBOX_USB +#define USB_VENDOR_ID 0x0e21 +#define USB_PRODUCT_ID 0x0800 +#endif + + /* Produce a dual-boot bootloader.bin for mktccboot */ #define TCCBOOT diff --git a/firmware/export/usb-tcc.h b/firmware/export/usb-tcc.h new file mode 100644 index 0000000000..787977312f --- /dev/null +++ b/firmware/export/usb-tcc.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 Vitja Makarov + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef USB_TCC7XX_H +#define USB_TCC7XX_H + +#define MMR_REG16(base, x) (*(volatile unsigned short *) ((base) + (x))) + +/* USB PHY registers */ +#define TCC7xx_USB_PHY_CFG MMR_REG16(USB_BASE, 0xc4) + #define TCC7xx_USB_PHY_CFG_XSEL (1<<13) /* FS/HS Transceiver enable */ + #define TCC7xx_USB_PHY_CFG_DWS (1<<6) /* Host mode */ + #define TCC7xx_USB_PHY_XO (1<<5) /* Enable XO_OUT */ + #define TCC7xx_USB_PHY_CKSEL_12 0 + #define TCC7xx_USB_PHY_CKSEL_24 1 + #define TCC7xx_USB_PHY_CKSEL_48 2 + +/* USB 2.0 device registers */ +#define TCC7xx_USB_INDEX MMR_REG16(USB_BASE, 0x00) /* Endpoint Index register */ +#define TCC7xx_USB_EPIF MMR_REG16(USB_BASE, 0x04) /* Endpoint interrupt flag register */ +#define TCC7xx_USB_EPIE MMR_REG16(USB_BASE, 0x08) /* Endpoint interrupt enable register */ +#define TCC7xx_USB_FUNC MMR_REG16(USB_BASE, 0x0c) /* Function address register */ +#define TCC7xx_USB_EP_DIR MMR_REG16(USB_BASE, 0x14) /* Endpoint direction register */ +#define TCC7xx_USB_TST MMR_REG16(USB_BASE, 0x14) /* Test registerregister */ +#define TCC7xx_USB_SYS_STAT MMR_REG16(USB_BASE, 0x1c) /* System status register */ + #define TCC7xx_USB_SYS_STAT_RESET (1<<0) /* Host forced reced */ + #define TCC7xx_USB_SYS_STAT_SUSPEND (1<<1) /* Host forced suspend */ + #define TCC7xx_USB_SYS_STAT_RESUME (1<<2) /* Host forced resume */ + #define TCC7xx_USB_SYS_STAT_HIGH (1<<4) /* High speed */ + #define TCC7xx_USB_SYS_STAT_SPD_END (1<<6) /* Speed detection end */ + #define TCC7xx_USB_SYS_STAT_VBON (1<<8) + #define TCC7xx_USB_SYS_STAT_VBOF (1<<9) + #define TCC7xx_USB_SYS_STAT_EOERR (1<<10) /* overrun error */ + #define TCC7xx_USB_SYS_STAT_DCERR (1<<11) /* Data CRC error */ + #define TCC7xx_USB_SYS_STAT_TCERR (1<<12) /* Token CRC error */ + #define TCC7xx_USB_SYS_STAT_BSERR (1<<13) /* Bit-stuff error */ + #define TCC7xx_USB_SYS_STAT_TMERR (1<<14) /* Timeout error */ + #define TCC7xx_USB_SYS_STAT_BAERR (1<<15) /* Byte align error */ + +#define TCC7xx_USB_SYS_STAT_ERRORS (TCC7xx_USB_SYS_STAT_EOERR | \ + TCC7xx_USB_SYS_STAT_DCERR | \ + TCC7xx_USB_SYS_STAT_TCERR | \ + TCC7xx_USB_SYS_STAT_BSERR | \ + TCC7xx_USB_SYS_STAT_TMERR | \ + TCC7xx_USB_SYS_STAT_BAERR) + +#define TCC7xx_USB_SYS_CTRL MMR_REG16(USB_BASE, 0x20) /* System control register */ + #define TCC7xx_USB_SYS_CTRL_RESET (1<<0) /* Reset enable */ + #define TCC7xx_USB_SYS_CTRL_SUSPEND (1<<1) /* Suspend enable */ + #define TCC7xx_USB_SYS_CTRL_RESUME (1<<2) /* Resume enable */ + #define TCC7xx_USB_SYS_CTRL_IPS (1<<4) /* Interrupt polarity */ + #define TCC7xx_USB_SYS_CTRL_RFRE (1<<5) /* Reverse read data enable */ + #define TCC7xx_USB_SYS_CTRL_SPDEN (1<<6) /* Speed detection interrupt enable */ + #define TCC7xx_USB_SYS_CTRL_BUS16 (1<<7) /* Select bus width 8/16 */ + #define TCC7xx_USB_SYS_CTRL_EIEN (1<<8) /* Error interrupt enable */ + #define TCC7xx_USB_SYS_CTRL_RWDE (1<<9) /* Reverse write data enable */ + #define TCC7xx_USB_SYS_CTRL_VBONE (1<<10) /* VBus On enable */ + #define TCC7xx_USB_SYS_CTRL_VBOFE (1<<11) /* VBus Off enable */ + #define TCC7xx_USB_SYS_CTRL_DUAL (1<<12) /* Dual interrupt enable*/ + #define TCC7xx_USB_SYS_CTRL_DMAZ (1<<14) /* DMA total count zero int */ + +#define TCC7xx_USB_EP0_STAT MMR_REG16(USB_BASE, 0x24) /* EP0 status register */ +#define TCC7xx_USB_EP0_CTRL MMR_REG16(USB_BASE, 0x28) /* EP0 control register */ + +#define TCC7xx_USB_EP0_BUF MMR_REG16(USB_BASE, 0x60) /* EP0 buffer register */ +#define TCC7xx_USB_EP1_BUF MMR_REG16(USB_BASE, 0x64) /* EP1 buffer register */ +#define TCC7xx_USB_EP2_BUF MMR_REG16(USB_BASE, 0x68) /* EP2 buffer register */ +#define TCC7xx_USB_EP3_BUF MMR_REG16(USB_BASE, 0x6c) /* EP3 buffer register */ + +/* Indexed registers, write endpoint number to TCC7xx_USB_INDEX */ +#define TCC7xx_USB_EP_STAT MMR_REG16(USB_BASE, 0x2c) /* EP status register */ + #define TCC7xx_USP_EP_STAT_RPS (1 << 0) /* Packet received */ + #define TCC7xx_USP_EP_STAT_TPS (1 << 1) /* Packet transmited */ + #define TCC7xx_USP_EP_STAT_LWO (1 << 4) /* Last word odd */ +#define TCC7xx_USB_EP_CTRL MMR_REG16(USB_BASE, 0x30) /* EP control register */ + #define TCC7xx_USB_EP_CTRL_TZLS (1 << 0) /* TX Zero Length Set */ + #define TCC7xx_USB_EP_CTRL_ESS (1 << 1) /* Endpoint Stall Set */ + #define TCC7xx_USB_EP_CTRL_CDP (1 << 2) /* Clear Data PID */ + #define TCC7xx_USB_EP_CTRL_TTE (1 << 5) /* TX Toggle Enable */ + #define TCC7xx_USB_EP_CTRL_FLUSH (1 << 6) /* Flush FIFO */ + #define TCC7xx_USB_EP_CTRL_DUEN (1 << 7) /* Dual FIFO Mode */ + #define TCC7xx_USB_EP_CTRL_IME (1 << 8) /* ISO Mode */ + #define TCC7xx_USB_EP_CTRL_OUTHD (1 << 11) /* OUT Packet Hold */ + #define TCC7xx_USB_EP_CTRL_INHLD (1 << 12) /* IN Packet Hold */ + +#define TCC7xx_USB_EP_BRCR MMR_REG16(USB_BASE, 0x34) /* EP byte read count register */ +#define TCC7xx_USB_EP_BWCR MMR_REG16(USB_BASE, 0x38) /* EP byte write count register */ +#define TCC7xx_USB_EP_MAXP MMR_REG16(USB_BASE, 0x3c) /* EP max packet register */ + +#define TCC7xx_USB_EP_DMA_CTRL MMR_REG16(USB_BASE, 0x40) /* EP DMA control register */ +#define TCC7xx_USB_EP_DMA_TCNTR MMR_REG16(USB_BASE, 0x44) /* EP DMA transfer counter register */ +#define TCC7xx_USB_EP_DMA_FCNTR MMR_REG16(USB_BASE, 0x48) /* EP DMA fifo counter register */ +#define TCC7xx_USB_EP_DMA_TTCNTR1 MMR_REG16(USB_BASE, 0x4c) /* EP DMA total trasfer counter1 register */ +#define TCC7xx_USB_EP_DMA_TTCNTR2 MMR_REG16(USB_BASE, 0x50) /* EP DMA total trasfer counter2 register */ +#define TCC7xx_USB_EP_DMA_ADDR1 MMR_REG16(USB_BASE, 0xa0) /* EP DMA MCU addr1 register */ +#define TCC7xx_USB_EP_DMA_ADDR2 MMR_REG16(USB_BASE, 0xa4) /* EP DMA MCU addr2 register */ +#define TCC7xx_USB_EP_DMA_STAT MMR_REG16(USB_BASE, 0xc0) /* EP DMA Transfer Status register */ +#define TCC7xx_USB_DELAY_CTRL MMR_REG16(USB_BASE, 0x80) /* Delay control register */ +#endif /* USB_TCC7XX_H */ diff --git a/firmware/export/usb-tcc7xx.h b/firmware/export/usb-tcc7xx.h deleted file mode 100644 index 787977312f..0000000000 --- a/firmware/export/usb-tcc7xx.h +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2008 Vitja Makarov - * - * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef USB_TCC7XX_H -#define USB_TCC7XX_H - -#define MMR_REG16(base, x) (*(volatile unsigned short *) ((base) + (x))) - -/* USB PHY registers */ -#define TCC7xx_USB_PHY_CFG MMR_REG16(USB_BASE, 0xc4) - #define TCC7xx_USB_PHY_CFG_XSEL (1<<13) /* FS/HS Transceiver enable */ - #define TCC7xx_USB_PHY_CFG_DWS (1<<6) /* Host mode */ - #define TCC7xx_USB_PHY_XO (1<<5) /* Enable XO_OUT */ - #define TCC7xx_USB_PHY_CKSEL_12 0 - #define TCC7xx_USB_PHY_CKSEL_24 1 - #define TCC7xx_USB_PHY_CKSEL_48 2 - -/* USB 2.0 device registers */ -#define TCC7xx_USB_INDEX MMR_REG16(USB_BASE, 0x00) /* Endpoint Index register */ -#define TCC7xx_USB_EPIF MMR_REG16(USB_BASE, 0x04) /* Endpoint interrupt flag register */ -#define TCC7xx_USB_EPIE MMR_REG16(USB_BASE, 0x08) /* Endpoint interrupt enable register */ -#define TCC7xx_USB_FUNC MMR_REG16(USB_BASE, 0x0c) /* Function address register */ -#define TCC7xx_USB_EP_DIR MMR_REG16(USB_BASE, 0x14) /* Endpoint direction register */ -#define TCC7xx_USB_TST MMR_REG16(USB_BASE, 0x14) /* Test registerregister */ -#define TCC7xx_USB_SYS_STAT MMR_REG16(USB_BASE, 0x1c) /* System status register */ - #define TCC7xx_USB_SYS_STAT_RESET (1<<0) /* Host forced reced */ - #define TCC7xx_USB_SYS_STAT_SUSPEND (1<<1) /* Host forced suspend */ - #define TCC7xx_USB_SYS_STAT_RESUME (1<<2) /* Host forced resume */ - #define TCC7xx_USB_SYS_STAT_HIGH (1<<4) /* High speed */ - #define TCC7xx_USB_SYS_STAT_SPD_END (1<<6) /* Speed detection end */ - #define TCC7xx_USB_SYS_STAT_VBON (1<<8) - #define TCC7xx_USB_SYS_STAT_VBOF (1<<9) - #define TCC7xx_USB_SYS_STAT_EOERR (1<<10) /* overrun error */ - #define TCC7xx_USB_SYS_STAT_DCERR (1<<11) /* Data CRC error */ - #define TCC7xx_USB_SYS_STAT_TCERR (1<<12) /* Token CRC error */ - #define TCC7xx_USB_SYS_STAT_BSERR (1<<13) /* Bit-stuff error */ - #define TCC7xx_USB_SYS_STAT_TMERR (1<<14) /* Timeout error */ - #define TCC7xx_USB_SYS_STAT_BAERR (1<<15) /* Byte align error */ - -#define TCC7xx_USB_SYS_STAT_ERRORS (TCC7xx_USB_SYS_STAT_EOERR | \ - TCC7xx_USB_SYS_STAT_DCERR | \ - TCC7xx_USB_SYS_STAT_TCERR | \ - TCC7xx_USB_SYS_STAT_BSERR | \ - TCC7xx_USB_SYS_STAT_TMERR | \ - TCC7xx_USB_SYS_STAT_BAERR) - -#define TCC7xx_USB_SYS_CTRL MMR_REG16(USB_BASE, 0x20) /* System control register */ - #define TCC7xx_USB_SYS_CTRL_RESET (1<<0) /* Reset enable */ - #define TCC7xx_USB_SYS_CTRL_SUSPEND (1<<1) /* Suspend enable */ - #define TCC7xx_USB_SYS_CTRL_RESUME (1<<2) /* Resume enable */ - #define TCC7xx_USB_SYS_CTRL_IPS (1<<4) /* Interrupt polarity */ - #define TCC7xx_USB_SYS_CTRL_RFRE (1<<5) /* Reverse read data enable */ - #define TCC7xx_USB_SYS_CTRL_SPDEN (1<<6) /* Speed detection interrupt enable */ - #define TCC7xx_USB_SYS_CTRL_BUS16 (1<<7) /* Select bus width 8/16 */ - #define TCC7xx_USB_SYS_CTRL_EIEN (1<<8) /* Error interrupt enable */ - #define TCC7xx_USB_SYS_CTRL_RWDE (1<<9) /* Reverse write data enable */ - #define TCC7xx_USB_SYS_CTRL_VBONE (1<<10) /* VBus On enable */ - #define TCC7xx_USB_SYS_CTRL_VBOFE (1<<11) /* VBus Off enable */ - #define TCC7xx_USB_SYS_CTRL_DUAL (1<<12) /* Dual interrupt enable*/ - #define TCC7xx_USB_SYS_CTRL_DMAZ (1<<14) /* DMA total count zero int */ - -#define TCC7xx_USB_EP0_STAT MMR_REG16(USB_BASE, 0x24) /* EP0 status register */ -#define TCC7xx_USB_EP0_CTRL MMR_REG16(USB_BASE, 0x28) /* EP0 control register */ - -#define TCC7xx_USB_EP0_BUF MMR_REG16(USB_BASE, 0x60) /* EP0 buffer register */ -#define TCC7xx_USB_EP1_BUF MMR_REG16(USB_BASE, 0x64) /* EP1 buffer register */ -#define TCC7xx_USB_EP2_BUF MMR_REG16(USB_BASE, 0x68) /* EP2 buffer register */ -#define TCC7xx_USB_EP3_BUF MMR_REG16(USB_BASE, 0x6c) /* EP3 buffer register */ - -/* Indexed registers, write endpoint number to TCC7xx_USB_INDEX */ -#define TCC7xx_USB_EP_STAT MMR_REG16(USB_BASE, 0x2c) /* EP status register */ - #define TCC7xx_USP_EP_STAT_RPS (1 << 0) /* Packet received */ - #define TCC7xx_USP_EP_STAT_TPS (1 << 1) /* Packet transmited */ - #define TCC7xx_USP_EP_STAT_LWO (1 << 4) /* Last word odd */ -#define TCC7xx_USB_EP_CTRL MMR_REG16(USB_BASE, 0x30) /* EP control register */ - #define TCC7xx_USB_EP_CTRL_TZLS (1 << 0) /* TX Zero Length Set */ - #define TCC7xx_USB_EP_CTRL_ESS (1 << 1) /* Endpoint Stall Set */ - #define TCC7xx_USB_EP_CTRL_CDP (1 << 2) /* Clear Data PID */ - #define TCC7xx_USB_EP_CTRL_TTE (1 << 5) /* TX Toggle Enable */ - #define TCC7xx_USB_EP_CTRL_FLUSH (1 << 6) /* Flush FIFO */ - #define TCC7xx_USB_EP_CTRL_DUEN (1 << 7) /* Dual FIFO Mode */ - #define TCC7xx_USB_EP_CTRL_IME (1 << 8) /* ISO Mode */ - #define TCC7xx_USB_EP_CTRL_OUTHD (1 << 11) /* OUT Packet Hold */ - #define TCC7xx_USB_EP_CTRL_INHLD (1 << 12) /* IN Packet Hold */ - -#define TCC7xx_USB_EP_BRCR MMR_REG16(USB_BASE, 0x34) /* EP byte read count register */ -#define TCC7xx_USB_EP_BWCR MMR_REG16(USB_BASE, 0x38) /* EP byte write count register */ -#define TCC7xx_USB_EP_MAXP MMR_REG16(USB_BASE, 0x3c) /* EP max packet register */ - -#define TCC7xx_USB_EP_DMA_CTRL MMR_REG16(USB_BASE, 0x40) /* EP DMA control register */ -#define TCC7xx_USB_EP_DMA_TCNTR MMR_REG16(USB_BASE, 0x44) /* EP DMA transfer counter register */ -#define TCC7xx_USB_EP_DMA_FCNTR MMR_REG16(USB_BASE, 0x48) /* EP DMA fifo counter register */ -#define TCC7xx_USB_EP_DMA_TTCNTR1 MMR_REG16(USB_BASE, 0x4c) /* EP DMA total trasfer counter1 register */ -#define TCC7xx_USB_EP_DMA_TTCNTR2 MMR_REG16(USB_BASE, 0x50) /* EP DMA total trasfer counter2 register */ -#define TCC7xx_USB_EP_DMA_ADDR1 MMR_REG16(USB_BASE, 0xa0) /* EP DMA MCU addr1 register */ -#define TCC7xx_USB_EP_DMA_ADDR2 MMR_REG16(USB_BASE, 0xa4) /* EP DMA MCU addr2 register */ -#define TCC7xx_USB_EP_DMA_STAT MMR_REG16(USB_BASE, 0xc0) /* EP DMA Transfer Status register */ -#define TCC7xx_USB_DELAY_CTRL MMR_REG16(USB_BASE, 0x80) /* Delay control register */ -#endif /* USB_TCC7XX_H */ diff --git a/firmware/target/arm/tcc77x/usb-tcc77x.c b/firmware/target/arm/tcc77x/usb-tcc77x.c deleted file mode 100644 index f5bb7c9ff2..0000000000 --- a/firmware/target/arm/tcc77x/usb-tcc77x.c +++ /dev/null @@ -1,799 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2008 by Vitja Makarov - * - * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "usb.h" - -#include "usb-tcc7xx.h" - -#include "cpu.h" -#include "system.h" -#include "kernel.h" -#include "panic.h" - -#ifdef HAVE_USBSTACK -#include "usb_ch9.h" -#include "usb_core.h" - -#define TCC7xx_USB_EPIF_IRQ_MASK 0xf - -static int dbg_level = 0x00; -static int global_ep_irq_mask = 0x1; -#define DEBUG(level, fmt, args...) do { if (dbg_level & (level)) printf(fmt, ## args); } while (0) - -#include - - -#include "sprintf.h" -#include "power.h" - -#ifndef BOOTLOADER -#define printf(...) do {} while (0) -#define panicf_my panicf -#else -int printf(const char *fmt, ...); -#define panicf_my(fmt, args...) { \ - int flags = disable_irq_save(); \ - printf("*** PANIC ***"); \ - printf(fmt, ## args); \ - printf("*** PANIC ***"); \ - while (usb_detect() == USB_INSERTED) \ - ; \ - power_off(); \ - while(1); \ - restore_irq(flags); \ -} -#endif - -struct tcc_ep { - unsigned char dir; /* endpoint direction */ - volatile uint16_t *ep; /* hw ep buffer */ - int id; /* Endpoint id */ - int mask; /* Endpoint bit mask */ - char *buf; /* user buffer to store data */ - int max_len; /* how match data will fit */ - int count; /* actual data count */ - bool busy; -} ; - -static struct tcc_ep tcc_endpoints[] = { - /* control */ - { - .dir = -1, - .ep = &TCC7xx_USB_EP0_BUF, - }, { /* bulk */ - .dir = -1, - .ep = &TCC7xx_USB_EP1_BUF, - }, { /* bulk */ - .dir = -1, - .ep = &TCC7xx_USB_EP2_BUF, - }, { /* interrupt */ - .dir = -1, - .ep = &TCC7xx_USB_EP3_BUF, - }, -} ; - -static bool usb_drv_write_ep(struct tcc_ep *ep); -static void usb_set_speed(int); - -int usb_drv_request_endpoint(int dir) -{ - int flags = disable_irq_save(); - size_t ep; - int ret = 0; - - if (dir == USB_DIR_IN) - ep = 1; - else - ep = 2; - - if (!tcc_endpoints[ep].busy) { - tcc_endpoints[ep].busy = true; - tcc_endpoints[ep].dir = dir; - ret = ep | dir; - } else { - ret = -1; - } - - restore_irq(flags); - return ret; -} - -void usb_drv_release_endpoint(int ep) -{ - int flags; - ep = ep & 0x7f; - - if (ep < 1 || ep > NUM_ENDPOINTS) - return ; - - flags = disable_irq_save(); - - tcc_endpoints[ep].busy = false; - tcc_endpoints[ep].dir = -1; - - restore_irq(flags); -} - -static void udelay(unsigned long msecs) -{ - /* TODO: implement me other way */ - msecs*=126; - while (msecs--) - asm("nop;"); -} - -static inline void pullup_on(void) -{ - TCC7xx_USB_PHY_CFG = 0x000c; -} - -static inline void pullup_off(void) -{ - TCC7xx_USB_PHY_CFG = 0x3e4c; -} - -#if 0 -static -char *dump_data(char *data, int count) -{ - static char buf[1024]; - char *dump = buf; - int i; - - for (i = 0; i < count; i++) - dump += snprintf(dump, sizeof(buf) - (dump - buf), "%02x", data[i]); - return buf; -} -#endif - -static -void handle_control(void) -{ - /* control are always 8 bytes len */ - static unsigned char ep_control[8]; - struct usb_ctrlrequest *req = - (struct usb_ctrlrequest *) ep_control; - unsigned short stat; - unsigned short count = 0; - int i; - int type; - - /* select control endpoint */ - TCC7xx_USB_INDEX = 0x00; - stat = TCC7xx_USB_EP0_STAT; - - if (stat & 0x10) { - DEBUG(2, "stall"); - TCC7xx_USB_EP0_STAT = 0x10; - } - - if (TCC7xx_USB_EP0_STAT & 0x01) { /* RX */ - uint16_t *ptr = (uint16_t *) ep_control; - - count = TCC7xx_USB_EP_BRCR; - - if (TCC7xx_USB_EP0_STAT & 0x2) - TCC7xx_USB_EP0_STAT = 0x02; - - if (count != 4) { /* bad control? */ - unsigned short dummy; - - while (count--) - dummy = TCC7xx_USB_EP0_BUF; - DEBUG(1, "WTF: count = %d", count); - } else { - /* simply read control packet */ - for (i = 0; i < count; i++) - ptr[i] = TCC7xx_USB_EP0_BUF; - } - - count *= 2; - TCC7xx_USB_EP0_STAT = 0x01; - DEBUG(1, "CTRL: len = %d %04x", count, stat); - } else if (TCC7xx_USB_EP0_STAT & 0x02) { /* TX */ - TCC7xx_USB_EP0_STAT = 0x02; - DEBUG(2, "TX Done\n"); - } else { - DEBUG(1, "stat: %04x", stat); - } - - TCC7xx_USB_EPIF = 1; - - if (0 == (stat & 0x1) || count != 8) - return ; -#if 1 /* TODO: remove me someday */ - { - int i; - uint16_t *ptr = (uint16_t *) ep_control; - for (i = 1; i < (count>>1); i++) { - if (ptr[i] != ptr[0]) - break; - } - if (i == (count>>1)) { - /*DEBUG(2, */panicf_my("sanity failed"); - return ; - } - } -#endif - type = req->bRequestType; - - /* TODO: don't pass some kinds of requests to upper level */ - switch (req->bRequest) { - case USB_REQ_CLEAR_FEATURE: - DEBUG(2, "USB_REQ_CLEAR_FEATURE"); - DEBUG(2, "...%04x %04x", req->wValue, req->wIndex); - break; - case USB_REQ_SET_ADDRESS: - //DEBUG(2, "USB_REQ_SET_ADDRESS, %d %d", req->wValue, TCC7xx_USB_FUNC); - /* seems we don't have to set it manually - TCC7xx_USB_FUNC = req->wValue; */ - break; - case USB_REQ_GET_DESCRIPTOR: - DEBUG(2, "gd, %02x %02x", req->wValue, req->wIndex); - break; - case USB_REQ_GET_CONFIGURATION: - DEBUG(2, "USB_REQ_GET_CONFIGURATION"); - break; - default: - DEBUG(2, "req: %02x %02d", req->bRequestType, req->bRequest); - } - - usb_core_control_request(req); -} - -static -void handle_ep_in(struct tcc_ep *tcc_ep, uint16_t stat) -{ - uint8_t *buf = tcc_ep->buf; - uint16_t *wbuf = (uint16_t *) buf; - int wcount; - int count; - int i; - - if (tcc_ep->dir != USB_DIR_OUT) { - panicf_my("ep%d: is input only", tcc_ep->id); - } - - wcount = TCC7xx_USB_EP_BRCR; - - DEBUG(2, "ep%d: %04x %04x", tcc_ep->id, stat, wcount); - - /* read data */ - count = wcount * 2; - if (stat & TCC7xx_USP_EP_STAT_LWO) { - count--; - wcount--; - } - - if (buf == NULL) - panicf_my("ep%d: Unexpected packet! %d %x", tcc_ep->id, count, TCC7xx_USB_EP_CTRL); - if (tcc_ep->max_len < count) - panicf_my("Too big packet: %d excepted %d %x", count, tcc_ep->max_len, TCC7xx_USB_EP_CTRL); - - for (i = 0; i < wcount; i++) - wbuf[i] = *tcc_ep->ep; - - if (count & 1) { /* lwo */ - uint16_t tmp = *tcc_ep->ep; - buf[count - 1] = tmp & 0xff; - } - - tcc_ep->buf = NULL; - - TCC7xx_USB_EP_STAT = TCC7xx_USB_EP_STAT; - TCC7xx_USB_EPIF = tcc_ep->mask; - TCC7xx_USB_EPIE &= ~tcc_ep->mask; /* TODO: use INGLD? */ - global_ep_irq_mask &= ~tcc_ep->mask; - - if (TCC7xx_USB_EP_STAT & 0x1) - panicf_my("One more packet?"); - - TCC7xx_USB_EP_CTRL |= TCC7xx_USB_EP_CTRL_OUTHD; - - usb_core_transfer_complete(tcc_ep->id, USB_DIR_OUT, 0, count); -} - -static -void handle_ep_out(struct tcc_ep *tcc_ep, uint16_t stat) -{ - bool done; - (void) stat; - - if (tcc_ep->dir != USB_DIR_IN) { - panicf_my("ep%d: is out only", tcc_ep->id); - } - -// if (tcc_ep->buf == NULL) { -// panicf_my("%s:%d", __FILE__, __LINE__); -// } - - done = usb_drv_write_ep(tcc_ep); - -// TCC7xx_USB_EP_STAT = 0x2; /* Clear TX stat */ - TCC7xx_USB_EPIF = tcc_ep->mask; - - if (done) { // tcc_ep->buf == NULL) { - TCC7xx_USB_EPIE &= ~tcc_ep->mask; - global_ep_irq_mask &= ~tcc_ep->mask; - -// usb_core_transfer_complete(tcc_ep->id, USB_DIR_IN, 0, tcc_ep->count); - } -} - -static -void handle_ep(unsigned short ep_irq) -{ - if (ep_irq & 0x1) { - handle_control(); - } - - if (ep_irq & 0xe) { - int endpoint; - - for (endpoint = 1; endpoint < 4; endpoint++) { - struct tcc_ep *tcc_ep = &tcc_endpoints[endpoint]; - uint16_t stat; - - if (0 == (ep_irq & (1 << endpoint))) - continue; - if (!tcc_ep->busy) - panicf_my("ep%d: wasn't requested", endpoint); - - TCC7xx_USB_INDEX = endpoint; - stat = TCC7xx_USB_EP_STAT; - - DEBUG(1, "ep%d: %04x", endpoint, stat); - - if (stat & 0x1) - handle_ep_in(tcc_ep, stat); - else if (stat & 0x2) - handle_ep_out(tcc_ep, stat); - else /* TODO: remove me? */ - panicf_my("Unhandled ep%d state: %x, %d", endpoint, TCC7xx_USB_EP_STAT, TCC7xx_USB_INDEX); - } - } -} - -static void usb_set_speed(int high_speed) -{ - TCC7xx_USB_EP_DIR = 0x0000; - - /* control endpoint */ - TCC7xx_USB_INDEX = 0; - TCC7xx_USB_EP0_CTRL = 0x0000; - TCC7xx_USB_EP_MAXP = 64; - TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP | TCC7xx_USB_EP_CTRL_FLUSH; - - /* ep1: bulk-in, to host */ - TCC7xx_USB_INDEX = 1; - TCC7xx_USB_EP_DIR |= (1 << 1); - TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; - - if (high_speed) - TCC7xx_USB_EP_MAXP = 512; - else - TCC7xx_USB_EP_MAXP = 64; - - TCC7xx_USB_EP_DMA_CTRL = 0x0; - - /* ep2: bulk-out, from host */ - TCC7xx_USB_INDEX = 2; - TCC7xx_USB_EP_DIR &= ~(1 << 2); - TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; - - if (high_speed) - TCC7xx_USB_EP_MAXP = 512; - else - TCC7xx_USB_EP_MAXP = 64; - - TCC7xx_USB_EP_DMA_CTRL = 0x0; - - /* ep3: interrupt in */ - TCC7xx_USB_INDEX = 3; - TCC7xx_USB_EP_DIR &= ~(1 << 3); - TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; - TCC7xx_USB_EP_MAXP = 64; - - TCC7xx_USB_EP_DMA_CTRL = 0x0; -} - -/* - Reset TCC7xx usb device - */ -static void usb_reset(void) -{ - pullup_on(); - - TCC7xx_USB_DELAY_CTRL |= 0x81; - - TCC7xx_USB_SYS_CTRL = 0xa000 | - TCC7xx_USB_SYS_CTRL_RESET | - TCC7xx_USB_SYS_CTRL_RFRE | - TCC7xx_USB_SYS_CTRL_SPDEN | - TCC7xx_USB_SYS_CTRL_VBONE | - TCC7xx_USB_SYS_CTRL_VBOFE; - - usb_set_speed(1); - pullup_on(); - - TCC7xx_USB_EPIF = TCC7xx_USB_EPIF_IRQ_MASK; - global_ep_irq_mask = 0x1; - TCC7xx_USB_EPIE = global_ep_irq_mask; - - usb_core_bus_reset(); -} - -/* IRQ handler */ -void USB_DEVICE(void) -{ - unsigned short sys_stat; - unsigned short ep_irq; - unsigned short index_save; - - sys_stat = TCC7xx_USB_SYS_STAT; - - if (sys_stat & TCC7xx_USB_SYS_STAT_RESET) { - TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_RESET; - usb_reset(); - TCC7xx_USB_SYS_CTRL |= TCC7xx_USB_SYS_CTRL_SUSPEND; - DEBUG(2, "reset"); - } - - if (sys_stat & TCC7xx_USB_SYS_STAT_RESUME) { - TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_RESUME; - usb_reset(); - TCC7xx_USB_SYS_CTRL |= TCC7xx_USB_SYS_CTRL_SUSPEND; - DEBUG(2, "resume"); - } - - if (sys_stat & TCC7xx_USB_SYS_STAT_SPD_END) { - usb_set_speed(1); - TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_SPD_END; - DEBUG(2, "spd end"); - } - - if (sys_stat & TCC7xx_USB_SYS_STAT_ERRORS) { - DEBUG(2, "errors: %4x", sys_stat & TCC7xx_USB_SYS_STAT_ERRORS); - TCC7xx_USB_SYS_STAT = sys_stat & TCC7xx_USB_SYS_STAT_ERRORS; - } - -// TCC7xx_USB_SYS_STAT = sys_stat; - - index_save = TCC7xx_USB_INDEX; - - ep_irq = TCC7xx_USB_EPIF & global_ep_irq_mask; - - while (ep_irq & TCC7xx_USB_EPIF_IRQ_MASK) { - handle_ep(ep_irq); - - /* is that really needed, btw not a problem for rockbox */ - udelay(50); - ep_irq = TCC7xx_USB_EPIF & global_ep_irq_mask; - } - - TCC7xx_USB_INDEX = index_save; -} - -void usb_drv_set_address(int address) -{ - DEBUG(2, "setting address %d %d", address, TCC7xx_USB_FUNC); -} - -int usb_drv_port_speed(void) -{ - return (TCC7xx_USB_SYS_STAT & 0x10) ? 1 : 0; -} - -static int usb_drv_write_packet(volatile unsigned short *buf, unsigned char *data, int len, int max) -{ - uint16_t *wbuf = (uint16_t *) data; - int count, i; - - len = MIN(len, max); - count = (len + 1) / 2; - - TCC7xx_USB_EP_BWCR = len; - - for (i = 0; i < count; i++) - *buf = *wbuf++; - - return len; -} - -static bool usb_drv_write_ep(struct tcc_ep *ep) -{ - int count; - - if (ep->max_len == 0) - return true; - - count = usb_drv_write_packet(ep->ep, ep->buf, ep->max_len, 512); - TCC7xx_USB_EP_STAT = 0x2; /* Clear TX stat */ - - ep->buf += count; - ep->count += count; - ep->max_len -= count; - - if (ep->max_len == 0) { - usb_core_transfer_complete(ep->id, USB_DIR_IN, 0, ep->count); - ep->buf = NULL; -// return true; - } - - return false; -} - -int usb_drv_send(int endpoint, void *ptr, int length) -{ - int flags = disable_irq_save(); - int rc = 0; - char *data = (unsigned char*) ptr;; - - DEBUG(2, "%s(%d,%d)" , __func__, endpoint, length); - - if (endpoint != 0) - panicf_my("%s(%d,%d)", __func__, endpoint, length); - - TCC7xx_USB_INDEX = 0; - while (length > 0) { - int ret; - - ret = usb_drv_write_packet(&TCC7xx_USB_EP0_BUF, data, length, 64); - length -= ret; - data += ret; - - while (0 == (TCC7xx_USB_EP0_STAT & 0x2)) - ; - TCC7xx_USB_EP0_STAT = 0x2; - } - - restore_irq(flags); - return rc; -} - - -int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) -{ - int flags; - int rc = 0, count = length; - char *data = (unsigned char*) ptr; - struct tcc_ep *ep = &tcc_endpoints[endpoint & 0x7f]; - - if (ep->dir != USB_DIR_IN || length == 0) - panicf_my("%s(%d,%d): Not supported", __func__, endpoint, length); - - DEBUG(2, "%s(%d,%d):", __func__, endpoint, length); - - flags = disable_irq_save(); - - if(ep->buf != NULL) { - panicf_my("%s: ep is already busy", __func__); - } - - ep->buf = data; - ep->max_len = length; - ep->count = count; - - TCC7xx_USB_INDEX = ep->id; -#if 1 - TCC7xx_USB_EP_STAT = 0x2; - /* TODO: use interrupts instead */ - while (!usb_drv_write_ep(ep)) { - while (0==(TCC7xx_USB_EP_STAT & 0x2)) - ; - } -#else - if (!usb_drv_write_ep(ep)) { - TCC7xx_USB_EPIE |= ep->mask; - global_ep_irq_mask |= ep->mask; - } -#endif - restore_irq(flags); - - DEBUG(2, "%s end", __func__); - - return rc; -} - -int usb_drv_recv(int endpoint, void* ptr, int length) -{ - volatile struct tcc_ep *tcc_ep = &tcc_endpoints[endpoint & 0x7f]; - int flags; - - if (length == 0) { - if (endpoint != 0) - panicf_my("%s(%d,%d) zero length?", __func__, endpoint, length); - return 0; - } - // TODO: check ep - if (tcc_ep->dir != USB_DIR_OUT) - panicf_my("%s(%d,%d)", __func__, endpoint, length); - - DEBUG(2, "%s(%d,%d)", __func__, endpoint, length); - - flags = disable_irq_save(); - - if (tcc_ep->buf) { - panicf_my("%s: overrun: %x %x", __func__, tcc_ep->buf, tcc_ep); - } - - tcc_ep->buf = ptr; - tcc_ep->max_len = length; - tcc_ep->count = 0; - - TCC7xx_USB_INDEX = tcc_ep->id; - - TCC7xx_USB_EP_CTRL &= ~TCC7xx_USB_EP_CTRL_OUTHD; - TCC7xx_USB_EPIE |= tcc_ep->mask; - global_ep_irq_mask |= tcc_ep->mask; - - restore_irq(flags); - - return 0; -} - -void usb_drv_cancel_all_transfers(void) -{ - int endpoint; - int flags; - - DEBUG(2, "%s", __func__); - - flags = disable_irq_save(); - for (endpoint = 0; endpoint < 4; endpoint++) { - if (tcc_endpoints[endpoint].buf) { -/* usb_core_transfer_complete(tcc_endpoints[endpoint].id, - tcc_endpoints[endpoint].dir, -1, 0); */ - tcc_endpoints[endpoint].buf = NULL; - } - } - - global_ep_irq_mask = 1; - TCC7xx_USB_EPIE = global_ep_irq_mask; - TCC7xx_USB_EPIF = TCC7xx_USB_EPIF_IRQ_MASK; - restore_irq(flags); -} - -void usb_drv_set_test_mode(int mode) -{ - panicf_my("%s(%d)", __func__, mode); -} - -bool usb_drv_stalled(int endpoint, bool in) -{ - panicf_my("%s(%d,%d)", __func__, endpoint, in); -} - -void usb_drv_stall(int endpoint, bool stall,bool in) -{ - printf("%s(%d,%d,%d)", __func__, endpoint, stall, in); -} - -void usb_drv_init(void) -{ - size_t i; - - DEBUG(2, "%s", __func__); - - for (i = 0; i < sizeof(tcc_endpoints)/sizeof(struct tcc_ep); i++) { - tcc_endpoints[i].id = i; - tcc_endpoints[i].mask = 1 << i; - tcc_endpoints[i].buf = NULL; - tcc_endpoints[i].busy = false; - tcc_endpoints[i].dir = -1; - } - - /* Enable USB clock */ - BCLKCTR |= DEV_USBD; - - /* switch USB to host and then reset */ - TCC7xx_USB_PHY_CFG = 0x3e4c; - SWRESET |= DEV_USBD; - udelay(50); - SWRESET &= ~DEV_USBD; - - usb_reset(); - - /* unmask irq */ - CREQ = USBD_IRQ_MASK; - IRQSEL |= USBD_IRQ_MASK; - TMODE &= ~USBD_IRQ_MASK; - IEN |= USBD_IRQ_MASK; -} - -void usb_drv_exit(void) -{ - TCC7xx_USB_EPIE = 0; - BCLKCTR &= ~DEV_USBD; - - SWRESET |= DEV_USBD; - udelay(50); - SWRESET &= ~DEV_USBD; - - pullup_off(); -} - -void usb_init_device(void) -{ -} - -void usb_enable(bool on) -{ - if (on) - usb_core_init(); - else - usb_core_exit(); -} - - -int usb_detect(void) -{ - /* TODO: not correct for all targets, we should poll VBUS - signal on USB bus. */ - if (charger_inserted()) - return USB_INSERTED; - return USB_EXTRACTED; -} - -#ifdef BOOTLOADER -#include "ata.h" -void usb_test(void) -{ - int rc; - - printf("ATA"); - rc = ata_init(); - - if(rc) { - panicf("ata_init failed"); - } - - usb_init(); - usb_start_monitoring(); - usb_acknowledge(SYS_USB_CONNECTED_ACK); - - while (1) { - sleep(HZ); -// usb_serial_send("Hello\r\n", 7); - } -} -#endif -#else -void usb_init_device(void) -{ - /* simply switch USB off for now */ - BCLKCTR |= DEV_USBD; - TCC7xx_USB_PHY_CFG = 0x3e4c; - BCLKCTR &= ~DEV_USBD; -} - -void usb_enable(bool on) -{ - (void)on; -} - -/* Always return false for now */ -int usb_detect(void) -{ - return USB_EXTRACTED; -} -#endif diff --git a/firmware/target/arm/usb-tcc.c b/firmware/target/arm/usb-tcc.c new file mode 100644 index 0000000000..345f6bed78 --- /dev/null +++ b/firmware/target/arm/usb-tcc.c @@ -0,0 +1,799 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Vitja Makarov + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "usb.h" + +#include "usb-tcc.h" + +#include "cpu.h" +#include "system.h" +#include "kernel.h" +#include "panic.h" + +#ifdef HAVE_USBSTACK +#include "usb_ch9.h" +#include "usb_core.h" + +#define TCC7xx_USB_EPIF_IRQ_MASK 0xf + +static int dbg_level = 0x00; +static int global_ep_irq_mask = 0x1; +#define DEBUG(level, fmt, args...) do { if (dbg_level & (level)) printf(fmt, ## args); } while (0) + +#include + + +#include "sprintf.h" +#include "power.h" + +#ifndef BOOTLOADER +#define printf(...) do {} while (0) +#define panicf_my panicf +#else +int printf(const char *fmt, ...); +#define panicf_my(fmt, args...) { \ + int flags = disable_irq_save(); \ + printf("*** PANIC ***"); \ + printf(fmt, ## args); \ + printf("*** PANIC ***"); \ + while (usb_detect() == USB_INSERTED) \ + ; \ + power_off(); \ + while(1); \ + restore_irq(flags); \ +} +#endif + +struct tcc_ep { + unsigned char dir; /* endpoint direction */ + volatile uint16_t *ep; /* hw ep buffer */ + int id; /* Endpoint id */ + int mask; /* Endpoint bit mask */ + char *buf; /* user buffer to store data */ + int max_len; /* how match data will fit */ + int count; /* actual data count */ + bool busy; +} ; + +static struct tcc_ep tcc_endpoints[] = { + /* control */ + { + .dir = -1, + .ep = &TCC7xx_USB_EP0_BUF, + }, { /* bulk */ + .dir = -1, + .ep = &TCC7xx_USB_EP1_BUF, + }, { /* bulk */ + .dir = -1, + .ep = &TCC7xx_USB_EP2_BUF, + }, { /* interrupt */ + .dir = -1, + .ep = &TCC7xx_USB_EP3_BUF, + }, +} ; + +static bool usb_drv_write_ep(struct tcc_ep *ep); +static void usb_set_speed(int); + +int usb_drv_request_endpoint(int dir) +{ + int flags = disable_irq_save(); + size_t ep; + int ret = 0; + + if (dir == USB_DIR_IN) + ep = 1; + else + ep = 2; + + if (!tcc_endpoints[ep].busy) { + tcc_endpoints[ep].busy = true; + tcc_endpoints[ep].dir = dir; + ret = ep | dir; + } else { + ret = -1; + } + + restore_irq(flags); + return ret; +} + +void usb_drv_release_endpoint(int ep) +{ + int flags; + ep = ep & 0x7f; + + if (ep < 1 || ep > NUM_ENDPOINTS) + return ; + + flags = disable_irq_save(); + + tcc_endpoints[ep].busy = false; + tcc_endpoints[ep].dir = -1; + + restore_irq(flags); +} + +static void udelay(unsigned long msecs) +{ + /* TODO: implement me other way */ + msecs*=126; + while (msecs--) + asm("nop;"); +} + +static inline void pullup_on(void) +{ + TCC7xx_USB_PHY_CFG = 0x000c; +} + +static inline void pullup_off(void) +{ + TCC7xx_USB_PHY_CFG = 0x3e4c; +} + +#if 0 +static +char *dump_data(char *data, int count) +{ + static char buf[1024]; + char *dump = buf; + int i; + + for (i = 0; i < count; i++) + dump += snprintf(dump, sizeof(buf) - (dump - buf), "%02x", data[i]); + return buf; +} +#endif + +static +void handle_control(void) +{ + /* control are always 8 bytes len */ + static unsigned char ep_control[8]; + struct usb_ctrlrequest *req = + (struct usb_ctrlrequest *) ep_control; + unsigned short stat; + unsigned short count = 0; + int i; + int type; + + /* select control endpoint */ + TCC7xx_USB_INDEX = 0x00; + stat = TCC7xx_USB_EP0_STAT; + + if (stat & 0x10) { + DEBUG(2, "stall"); + TCC7xx_USB_EP0_STAT = 0x10; + } + + if (TCC7xx_USB_EP0_STAT & 0x01) { /* RX */ + uint16_t *ptr = (uint16_t *) ep_control; + + count = TCC7xx_USB_EP_BRCR; + + if (TCC7xx_USB_EP0_STAT & 0x2) + TCC7xx_USB_EP0_STAT = 0x02; + + if (count != 4) { /* bad control? */ + unsigned short dummy; + + while (count--) + dummy = TCC7xx_USB_EP0_BUF; + DEBUG(1, "WTF: count = %d", count); + } else { + /* simply read control packet */ + for (i = 0; i < count; i++) + ptr[i] = TCC7xx_USB_EP0_BUF; + } + + count *= 2; + TCC7xx_USB_EP0_STAT = 0x01; + DEBUG(1, "CTRL: len = %d %04x", count, stat); + } else if (TCC7xx_USB_EP0_STAT & 0x02) { /* TX */ + TCC7xx_USB_EP0_STAT = 0x02; + DEBUG(2, "TX Done\n"); + } else { + DEBUG(1, "stat: %04x", stat); + } + + TCC7xx_USB_EPIF = 1; + + if (0 == (stat & 0x1) || count != 8) + return ; +#if 1 /* TODO: remove me someday */ + { + int i; + uint16_t *ptr = (uint16_t *) ep_control; + for (i = 1; i < (count>>1); i++) { + if (ptr[i] != ptr[0]) + break; + } + if (i == (count>>1)) { + /*DEBUG(2, */panicf_my("sanity failed"); + return ; + } + } +#endif + type = req->bRequestType; + + /* TODO: don't pass some kinds of requests to upper level */ + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + DEBUG(2, "USB_REQ_CLEAR_FEATURE"); + DEBUG(2, "...%04x %04x", req->wValue, req->wIndex); + break; + case USB_REQ_SET_ADDRESS: + //DEBUG(2, "USB_REQ_SET_ADDRESS, %d %d", req->wValue, TCC7xx_USB_FUNC); + /* seems we don't have to set it manually + TCC7xx_USB_FUNC = req->wValue; */ + break; + case USB_REQ_GET_DESCRIPTOR: + DEBUG(2, "gd, %02x %02x", req->wValue, req->wIndex); + break; + case USB_REQ_GET_CONFIGURATION: + DEBUG(2, "USB_REQ_GET_CONFIGURATION"); + break; + default: + DEBUG(2, "req: %02x %02d", req->bRequestType, req->bRequest); + } + + usb_core_control_request(req); +} + +static +void handle_ep_in(struct tcc_ep *tcc_ep, uint16_t stat) +{ + uint8_t *buf = tcc_ep->buf; + uint16_t *wbuf = (uint16_t *) buf; + int wcount; + int count; + int i; + + if (tcc_ep->dir != USB_DIR_OUT) { + panicf_my("ep%d: is input only", tcc_ep->id); + } + + wcount = TCC7xx_USB_EP_BRCR; + + DEBUG(2, "ep%d: %04x %04x", tcc_ep->id, stat, wcount); + + /* read data */ + count = wcount * 2; + if (stat & TCC7xx_USP_EP_STAT_LWO) { + count--; + wcount--; + } + + if (buf == NULL) + panicf_my("ep%d: Unexpected packet! %d %x", tcc_ep->id, count, TCC7xx_USB_EP_CTRL); + if (tcc_ep->max_len < count) + panicf_my("Too big packet: %d excepted %d %x", count, tcc_ep->max_len, TCC7xx_USB_EP_CTRL); + + for (i = 0; i < wcount; i++) + wbuf[i] = *tcc_ep->ep; + + if (count & 1) { /* lwo */ + uint16_t tmp = *tcc_ep->ep; + buf[count - 1] = tmp & 0xff; + } + + tcc_ep->buf = NULL; + + TCC7xx_USB_EP_STAT = TCC7xx_USB_EP_STAT; + TCC7xx_USB_EPIF = tcc_ep->mask; + TCC7xx_USB_EPIE &= ~tcc_ep->mask; /* TODO: use INGLD? */ + global_ep_irq_mask &= ~tcc_ep->mask; + + if (TCC7xx_USB_EP_STAT & 0x1) + panicf_my("One more packet?"); + + TCC7xx_USB_EP_CTRL |= TCC7xx_USB_EP_CTRL_OUTHD; + + usb_core_transfer_complete(tcc_ep->id, USB_DIR_OUT, 0, count); +} + +static +void handle_ep_out(struct tcc_ep *tcc_ep, uint16_t stat) +{ + bool done; + (void) stat; + + if (tcc_ep->dir != USB_DIR_IN) { + panicf_my("ep%d: is out only", tcc_ep->id); + } + +// if (tcc_ep->buf == NULL) { +// panicf_my("%s:%d", __FILE__, __LINE__); +// } + + done = usb_drv_write_ep(tcc_ep); + +// TCC7xx_USB_EP_STAT = 0x2; /* Clear TX stat */ + TCC7xx_USB_EPIF = tcc_ep->mask; + + if (done) { // tcc_ep->buf == NULL) { + TCC7xx_USB_EPIE &= ~tcc_ep->mask; + global_ep_irq_mask &= ~tcc_ep->mask; + +// usb_core_transfer_complete(tcc_ep->id, USB_DIR_IN, 0, tcc_ep->count); + } +} + +static +void handle_ep(unsigned short ep_irq) +{ + if (ep_irq & 0x1) { + handle_control(); + } + + if (ep_irq & 0xe) { + int endpoint; + + for (endpoint = 1; endpoint < 4; endpoint++) { + struct tcc_ep *tcc_ep = &tcc_endpoints[endpoint]; + uint16_t stat; + + if (0 == (ep_irq & (1 << endpoint))) + continue; + if (!tcc_ep->busy) + panicf_my("ep%d: wasn't requested", endpoint); + + TCC7xx_USB_INDEX = endpoint; + stat = TCC7xx_USB_EP_STAT; + + DEBUG(1, "ep%d: %04x", endpoint, stat); + + if (stat & 0x1) + handle_ep_in(tcc_ep, stat); + else if (stat & 0x2) + handle_ep_out(tcc_ep, stat); + else /* TODO: remove me? */ + panicf_my("Unhandled ep%d state: %x, %d", endpoint, TCC7xx_USB_EP_STAT, TCC7xx_USB_INDEX); + } + } +} + +static void usb_set_speed(int high_speed) +{ + TCC7xx_USB_EP_DIR = 0x0000; + + /* control endpoint */ + TCC7xx_USB_INDEX = 0; + TCC7xx_USB_EP0_CTRL = 0x0000; + TCC7xx_USB_EP_MAXP = 64; + TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP | TCC7xx_USB_EP_CTRL_FLUSH; + + /* ep1: bulk-in, to host */ + TCC7xx_USB_INDEX = 1; + TCC7xx_USB_EP_DIR |= (1 << 1); + TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; + + if (high_speed) + TCC7xx_USB_EP_MAXP = 512; + else + TCC7xx_USB_EP_MAXP = 64; + + TCC7xx_USB_EP_DMA_CTRL = 0x0; + + /* ep2: bulk-out, from host */ + TCC7xx_USB_INDEX = 2; + TCC7xx_USB_EP_DIR &= ~(1 << 2); + TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; + + if (high_speed) + TCC7xx_USB_EP_MAXP = 512; + else + TCC7xx_USB_EP_MAXP = 64; + + TCC7xx_USB_EP_DMA_CTRL = 0x0; + + /* ep3: interrupt in */ + TCC7xx_USB_INDEX = 3; + TCC7xx_USB_EP_DIR &= ~(1 << 3); + TCC7xx_USB_EP_CTRL = TCC7xx_USB_EP_CTRL_CDP; + TCC7xx_USB_EP_MAXP = 64; + + TCC7xx_USB_EP_DMA_CTRL = 0x0; +} + +/* + Reset TCC7xx usb device + */ +static void usb_reset(void) +{ + pullup_on(); + + TCC7xx_USB_DELAY_CTRL |= 0x81; + + TCC7xx_USB_SYS_CTRL = 0xa000 | + TCC7xx_USB_SYS_CTRL_RESET | + TCC7xx_USB_SYS_CTRL_RFRE | + TCC7xx_USB_SYS_CTRL_SPDEN | + TCC7xx_USB_SYS_CTRL_VBONE | + TCC7xx_USB_SYS_CTRL_VBOFE; + + usb_set_speed(1); + pullup_on(); + + TCC7xx_USB_EPIF = TCC7xx_USB_EPIF_IRQ_MASK; + global_ep_irq_mask = 0x1; + TCC7xx_USB_EPIE = global_ep_irq_mask; + + usb_core_bus_reset(); +} + +/* IRQ handler */ +void USB_DEVICE(void) +{ + unsigned short sys_stat; + unsigned short ep_irq; + unsigned short index_save; + + sys_stat = TCC7xx_USB_SYS_STAT; + + if (sys_stat & TCC7xx_USB_SYS_STAT_RESET) { + TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_RESET; + usb_reset(); + TCC7xx_USB_SYS_CTRL |= TCC7xx_USB_SYS_CTRL_SUSPEND; + DEBUG(2, "reset"); + } + + if (sys_stat & TCC7xx_USB_SYS_STAT_RESUME) { + TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_RESUME; + usb_reset(); + TCC7xx_USB_SYS_CTRL |= TCC7xx_USB_SYS_CTRL_SUSPEND; + DEBUG(2, "resume"); + } + + if (sys_stat & TCC7xx_USB_SYS_STAT_SPD_END) { + usb_set_speed(1); + TCC7xx_USB_SYS_STAT = TCC7xx_USB_SYS_STAT_SPD_END; + DEBUG(2, "spd end"); + } + + if (sys_stat & TCC7xx_USB_SYS_STAT_ERRORS) { + DEBUG(2, "errors: %4x", sys_stat & TCC7xx_USB_SYS_STAT_ERRORS); + TCC7xx_USB_SYS_STAT = sys_stat & TCC7xx_USB_SYS_STAT_ERRORS; + } + +// TCC7xx_USB_SYS_STAT = sys_stat; + + index_save = TCC7xx_USB_INDEX; + + ep_irq = TCC7xx_USB_EPIF & global_ep_irq_mask; + + while (ep_irq & TCC7xx_USB_EPIF_IRQ_MASK) { + handle_ep(ep_irq); + + /* is that really needed, btw not a problem for rockbox */ + udelay(50); + ep_irq = TCC7xx_USB_EPIF & global_ep_irq_mask; + } + + TCC7xx_USB_INDEX = index_save; +} + +void usb_drv_set_address(int address) +{ + DEBUG(2, "setting address %d %d", address, TCC7xx_USB_FUNC); +} + +int usb_drv_port_speed(void) +{ + return (TCC7xx_USB_SYS_STAT & 0x10) ? 1 : 0; +} + +static int usb_drv_write_packet(volatile unsigned short *buf, unsigned char *data, int len, int max) +{ + uint16_t *wbuf = (uint16_t *) data; + int count, i; + + len = MIN(len, max); + count = (len + 1) / 2; + + TCC7xx_USB_EP_BWCR = len; + + for (i = 0; i < count; i++) + *buf = *wbuf++; + + return len; +} + +static bool usb_drv_write_ep(struct tcc_ep *ep) +{ + int count; + + if (ep->max_len == 0) + return true; + + count = usb_drv_write_packet(ep->ep, ep->buf, ep->max_len, 512); + TCC7xx_USB_EP_STAT = 0x2; /* Clear TX stat */ + + ep->buf += count; + ep->count += count; + ep->max_len -= count; + + if (ep->max_len == 0) { + usb_core_transfer_complete(ep->id, USB_DIR_IN, 0, ep->count); + ep->buf = NULL; +// return true; + } + + return false; +} + +int usb_drv_send(int endpoint, void *ptr, int length) +{ + int flags = disable_irq_save(); + int rc = 0; + char *data = (unsigned char*) ptr;; + + DEBUG(2, "%s(%d,%d)" , __func__, endpoint, length); + + if (endpoint != 0) + panicf_my("%s(%d,%d)", __func__, endpoint, length); + + TCC7xx_USB_INDEX = 0; + while (length > 0) { + int ret; + + ret = usb_drv_write_packet(&TCC7xx_USB_EP0_BUF, data, length, 64); + length -= ret; + data += ret; + + while (0 == (TCC7xx_USB_EP0_STAT & 0x2)) + ; + TCC7xx_USB_EP0_STAT = 0x2; + } + + restore_irq(flags); + return rc; +} + + +int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) +{ + int flags; + int rc = 0, count = length; + char *data = (unsigned char*) ptr; + struct tcc_ep *ep = &tcc_endpoints[endpoint & 0x7f]; + + if (ep->dir != USB_DIR_IN || length == 0) + panicf_my("%s(%d,%d): Not supported", __func__, endpoint, length); + + DEBUG(2, "%s(%d,%d):", __func__, endpoint, length); + + flags = disable_irq_save(); + + if(ep->buf != NULL) { + panicf_my("%s: ep is already busy", __func__); + } + + ep->buf = data; + ep->max_len = length; + ep->count = count; + + TCC7xx_USB_INDEX = ep->id; +#if 1 + TCC7xx_USB_EP_STAT = 0x2; + /* TODO: use interrupts instead */ + while (!usb_drv_write_ep(ep)) { + while (0==(TCC7xx_USB_EP_STAT & 0x2)) + ; + } +#else + if (!usb_drv_write_ep(ep)) { + TCC7xx_USB_EPIE |= ep->mask; + global_ep_irq_mask |= ep->mask; + } +#endif + restore_irq(flags); + + DEBUG(2, "%s end", __func__); + + return rc; +} + +int usb_drv_recv(int endpoint, void* ptr, int length) +{ + volatile struct tcc_ep *tcc_ep = &tcc_endpoints[endpoint & 0x7f]; + int flags; + + if (length == 0) { + if (endpoint != 0) + panicf_my("%s(%d,%d) zero length?", __func__, endpoint, length); + return 0; + } + // TODO: check ep + if (tcc_ep->dir != USB_DIR_OUT) + panicf_my("%s(%d,%d)", __func__, endpoint, length); + + DEBUG(2, "%s(%d,%d)", __func__, endpoint, length); + + flags = disable_irq_save(); + + if (tcc_ep->buf) { + panicf_my("%s: overrun: %x %x", __func__, tcc_ep->buf, tcc_ep); + } + + tcc_ep->buf = ptr; + tcc_ep->max_len = length; + tcc_ep->count = 0; + + TCC7xx_USB_INDEX = tcc_ep->id; + + TCC7xx_USB_EP_CTRL &= ~TCC7xx_USB_EP_CTRL_OUTHD; + TCC7xx_USB_EPIE |= tcc_ep->mask; + global_ep_irq_mask |= tcc_ep->mask; + + restore_irq(flags); + + return 0; +} + +void usb_drv_cancel_all_transfers(void) +{ + int endpoint; + int flags; + + DEBUG(2, "%s", __func__); + + flags = disable_irq_save(); + for (endpoint = 0; endpoint < 4; endpoint++) { + if (tcc_endpoints[endpoint].buf) { +/* usb_core_transfer_complete(tcc_endpoints[endpoint].id, + tcc_endpoints[endpoint].dir, -1, 0); */ + tcc_endpoints[endpoint].buf = NULL; + } + } + + global_ep_irq_mask = 1; + TCC7xx_USB_EPIE = global_ep_irq_mask; + TCC7xx_USB_EPIF = TCC7xx_USB_EPIF_IRQ_MASK; + restore_irq(flags); +} + +void usb_drv_set_test_mode(int mode) +{ + panicf_my("%s(%d)", __func__, mode); +} + +bool usb_drv_stalled(int endpoint, bool in) +{ + panicf_my("%s(%d,%d)", __func__, endpoint, in); +} + +void usb_drv_stall(int endpoint, bool stall,bool in) +{ + printf("%s(%d,%d,%d)", __func__, endpoint, stall, in); +} + +void usb_drv_init(void) +{ + size_t i; + + DEBUG(2, "%s", __func__); + + for (i = 0; i < sizeof(tcc_endpoints)/sizeof(struct tcc_ep); i++) { + tcc_endpoints[i].id = i; + tcc_endpoints[i].mask = 1 << i; + tcc_endpoints[i].buf = NULL; + tcc_endpoints[i].busy = false; + tcc_endpoints[i].dir = -1; + } + + /* Enable USB clock */ + BCLKCTR |= DEV_USBD; + + /* switch USB to host and then reset */ + TCC7xx_USB_PHY_CFG = 0x3e4c; + SWRESET |= DEV_USBD; + udelay(50); + SWRESET &= ~DEV_USBD; + + usb_reset(); + + /* unmask irq */ + CREQ = USBD_IRQ_MASK; + IRQSEL |= USBD_IRQ_MASK; + TMODE &= ~USBD_IRQ_MASK; + IEN |= USBD_IRQ_MASK; +} + +void usb_drv_exit(void) +{ + TCC7xx_USB_EPIE = 0; + BCLKCTR &= ~DEV_USBD; + + SWRESET |= DEV_USBD; + udelay(50); + SWRESET &= ~DEV_USBD; + + pullup_off(); +} + +void usb_init_device(void) +{ +} + +void usb_enable(bool on) +{ + if (on) + usb_core_init(); + else + usb_core_exit(); +} + + +int usb_detect(void) +{ + /* TODO: not correct for all targets, we should poll VBUS + signal on USB bus. */ + if (charger_inserted()) + return USB_INSERTED; + return USB_EXTRACTED; +} + +#ifdef BOOTLOADER +#include "ata.h" +void usb_test(void) +{ + int rc; + + printf("ATA"); + rc = ata_init(); + + if(rc) { + panicf("ata_init failed"); + } + + usb_init(); + usb_start_monitoring(); + usb_acknowledge(SYS_USB_CONNECTED_ACK); + + while (1) { + sleep(HZ); +// usb_serial_send("Hello\r\n", 7); + } +} +#endif +#else +void usb_init_device(void) +{ + /* simply switch USB off for now */ + BCLKCTR |= DEV_USBD; + TCC7xx_USB_PHY_CFG = 0x3e4c; + BCLKCTR &= ~DEV_USBD; +} + +void usb_enable(bool on) +{ + (void)on; +} + +/* Always return false for now */ +int usb_detect(void) +{ + return USB_EXTRACTED; +} +#endif diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 6003c8d197..5f22d87c5e 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -314,7 +314,17 @@ static void set_serial_descriptor(void) usb_string_iSerial.bLength=68; } #else -#error No set_serial_descriptor() implementation for this target +#warning No proper set_serial_descriptor() implementation for this target +static void set_serial_descriptor(void) +{ + short* p = &usb_string_iSerial.wString[1]; + int i; + for (i = 0; i < 16; i++) { + *p++ = hex[(2*i)&0xF]; + *p++ = hex[(2*i+1)&0xF]; + } + usb_string_iSerial.bLength=68; +} #endif void usb_core_init(void) -- cgit v1.2.3