c0b43a5ac2
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19165 a1c6a512-1295-4272-9138-f99709370657
1417 lines
32 KiB
C
1417 lines
32 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2008 by Maurus Cuelenaere
|
|
*
|
|
* 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 "string.h"
|
|
#include "system.h"
|
|
#include "usb_ch9.h"
|
|
#include "usb_drv.h"
|
|
#include "usb_core.h"
|
|
#include "usb-target.h"
|
|
#include "jz4740.h"
|
|
#include "thread.h"
|
|
|
|
#if 1
|
|
|
|
#define EP1_INTR_BIT 2
|
|
#define EP_FIFO_NOEMPTY 2
|
|
|
|
#define IS_CACHE(x) (x < 0xa0000000)
|
|
|
|
#define USB_EP0_IDLE 0
|
|
#define USB_EP0_RX 1
|
|
#define USB_EP0_TX 2
|
|
|
|
enum ep_type
|
|
{
|
|
ep_control, ep_bulk, ep_interrupt
|
|
};
|
|
|
|
struct usb_endpoint
|
|
{
|
|
void *buf;
|
|
unsigned int length;
|
|
void *ptr;
|
|
|
|
const enum ep_type type;
|
|
const bool use_dma;
|
|
const bool in;
|
|
|
|
const void *fifo_addr;
|
|
unsigned short fifo_size;
|
|
};
|
|
|
|
static unsigned char ep0_rx_buf[64];
|
|
static unsigned char ep0_tx_buf[64];
|
|
static unsigned char ep0state = USB_EP0_IDLE;
|
|
static struct usb_endpoint endpoints[] =
|
|
{
|
|
/* buf length ptr type use_dma in fifo_addr fifo_size */
|
|
{&ep0_rx_buf, 0, &ep0_rx_buf, ep_control, false, true, (void*)USB_FIFO_EP0, 64 },
|
|
{&ep0_tx_buf, 0, &ep0_tx_buf, ep_control, false, false, (void*)USB_FIFO_EP0, 64 },
|
|
{NULL, 0, NULL, ep_bulk, true, true, (void*)USB_FIFO_EP1, 512},
|
|
{NULL, 0, NULL, ep_bulk, true, false, (void*)USB_FIFO_EP1, 512},
|
|
{NULL, 0, NULL, ep_interrupt, false, true, (void*)USB_FIFO_EP2, 64 }
|
|
};
|
|
|
|
static inline void select_endpoint(int ep)
|
|
{
|
|
REG_USB_REG_INDEX = ep;
|
|
}
|
|
|
|
static void readFIFO(struct usb_endpoint *ep, unsigned int size)
|
|
{
|
|
unsigned int *d = (unsigned int *)ep->ptr;
|
|
unsigned int s;
|
|
s = (size + 3) >> 2;
|
|
while (s--)
|
|
*d++ = REG32(ep->fifo_addr);
|
|
}
|
|
|
|
static void writeFIFO(struct usb_endpoint *ep, unsigned int size)
|
|
{
|
|
unsigned int *d = (unsigned int *)ep->ptr;
|
|
unsigned char *c;
|
|
int s, q;
|
|
|
|
if (size > 0)
|
|
{
|
|
s = size >> 2;
|
|
while (s--)
|
|
REG32(ep->fifo_addr) = *d++;
|
|
|
|
q = size & 3;
|
|
if (q)
|
|
{
|
|
c = (unsigned char *)d;
|
|
while (q--)
|
|
REG8(ep->fifo_addr) = *c++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sendPKT(int ep_nr, const unsigned char* ptr, unsigned int size)
|
|
{
|
|
struct usb_endpoint *ep = &endpoints[ep_nr];
|
|
|
|
if (ep_nr != 0)
|
|
{
|
|
ep->buf = (void*)ptr;
|
|
ep->ptr = (void*)ptr;
|
|
ep->length = size;
|
|
select_endpoint(ep_nr);
|
|
if (size <= ep->fifo_size)
|
|
{
|
|
writeFIFO(ep, size);
|
|
REG_USB_REG_INCSR |= USB_INCSR_INPKTRDY;
|
|
ep->ptr = ep->buf + size;
|
|
}
|
|
else
|
|
{
|
|
writeFIFO(ep, ep->fifo_size);
|
|
REG_USB_REG_INCSR |= USB_INCSR_INPKTRDY;
|
|
ep->ptr += ep->fifo_size;
|
|
}
|
|
}
|
|
else /* EP0 */
|
|
{
|
|
ep->length = size;
|
|
ep->ptr = ep->buf;
|
|
memcpy(ep->buf, ptr, size);
|
|
ep0state = USB_EP0_TX;
|
|
}
|
|
}
|
|
|
|
static void getPKT(int ep_nr, const unsigned char *ptr, unsigned int size)
|
|
{
|
|
struct usb_endpoint *ep = &endpoints[ep_nr];
|
|
|
|
memcpy((void*)ptr, ep->ptr, size);
|
|
if (ep->length > size)
|
|
ep->length -= size;
|
|
else
|
|
{
|
|
size = ep->length;
|
|
ep->length = 0;
|
|
}
|
|
|
|
ep->ptr += size;
|
|
}
|
|
|
|
static void EP0_handler(void)
|
|
{
|
|
unsigned char csr0;
|
|
|
|
/* Read CSR0 */
|
|
select_endpoint(0);
|
|
csr0 = REG_USB_REG_CSR0;
|
|
|
|
/* Check for SentStall
|
|
if sentstall is set, clear the sentstall bit
|
|
*/
|
|
if (csr0 & USB_CSR0_SENTSTALL)
|
|
{
|
|
REG_USB_REG_CSR0 = csr0 & ~USB_CSR0_SENTSTALL;
|
|
ep0state = USB_EP0_IDLE;
|
|
return;
|
|
}
|
|
|
|
/* Check for SetupEnd */
|
|
if (csr0 & USB_CSR0_SETUPEND)
|
|
{
|
|
REG_USB_REG_CSR0 |= USB_CSR0_SVDSETUPEND;
|
|
ep0state = USB_EP0_IDLE;
|
|
return;
|
|
}
|
|
|
|
/* Call relevant routines for endpoint 0 state */
|
|
if (ep0state == USB_EP0_IDLE)
|
|
{
|
|
if (csr0 & USB_CSR0_OUTPKTRDY) /* There is data in the fifo */
|
|
{
|
|
readFIFO(&endpoints[0], 8);
|
|
REG_USB_REG_CSR0 |= USB_CSR0_SVDOUTPKTRDY; /* clear OUTRD bit */
|
|
usb_core_control_request((struct usb_ctrlrequest*)endpoints[0].buf);
|
|
}
|
|
endpoints[0].length = 0;
|
|
endpoints[0].ptr = endpoints[0].buf;
|
|
}
|
|
|
|
if (ep0state == USB_EP0_TX)
|
|
{
|
|
if ((&endpoints[1].ptr - &endpoints[1].buf) <= endpoints[1].fifo_size)
|
|
{
|
|
writeFIFO(&endpoints[1], (&endpoints[1].ptr - &endpoints[1].buf));
|
|
endpoints[1].ptr = &endpoints[1].buf + endpoints[1].length;
|
|
REG_USB_REG_CSR0 |= (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */
|
|
ep0state = USB_EP0_IDLE;
|
|
}
|
|
else
|
|
{
|
|
writeFIFO(&endpoints[1], endpoints[1].fifo_size);
|
|
REG_USB_REG_CSR0 |= USB_CSR0_INPKTRDY;
|
|
endpoints[1].ptr += endpoints[1].fifo_size;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void setup_endpoint(struct usb_endpoint *ep)
|
|
{
|
|
ep->ptr = ep->buf;
|
|
ep->length = 0;
|
|
|
|
if(ep->in)
|
|
{
|
|
if(ep->type == ep_bulk)
|
|
{
|
|
register int size;
|
|
|
|
if((REG_USB_REG_POWER & USB_POWER_HSMODE) == 0)
|
|
size = 64;
|
|
else
|
|
size = 512;
|
|
|
|
REG_USB_REG_INMAXP = size;
|
|
ep->fifo_size = size;
|
|
}
|
|
else
|
|
REG_USB_REG_INMAXP = ep->fifo_size;
|
|
|
|
REG_USB_REG_INCSR = 0x2048;
|
|
}
|
|
else
|
|
{
|
|
REG_USB_REG_OUTMAXP = ep->fifo_size;
|
|
REG_USB_REG_OUTCSR = 0x0090;
|
|
}
|
|
}
|
|
|
|
static void udc_reset(void)
|
|
{
|
|
register int i;
|
|
|
|
/* data init */
|
|
ep0state = USB_EP0_IDLE;
|
|
|
|
/* Disable interrupts */
|
|
REG_USB_REG_INTRINE = 0;
|
|
REG_USB_REG_INTROUTE = 0;
|
|
REG_USB_REG_INTRUSBE = 0;
|
|
|
|
REG_USB_REG_FADDR = 0;
|
|
REG_USB_REG_POWER = 0x60; /* High speed */
|
|
|
|
select_endpoint(0);
|
|
REG_USB_REG_CSR0 = 0xC0;
|
|
|
|
for(i=1; i<3; i++)
|
|
{
|
|
select_endpoint(i);
|
|
setup_endpoint(&endpoints[i]);
|
|
}
|
|
|
|
/* enable intr */
|
|
REG_USB_REG_INTRINE = 0x3;
|
|
REG_USB_REG_INTROUTE = 0x2;
|
|
REG_USB_REG_INTRUSBE = 0x4;
|
|
}
|
|
|
|
/* Interrupt handler */
|
|
void UDC(void)
|
|
{
|
|
/* Read interrupt registers */
|
|
unsigned char intrUSB = REG_USB_REG_INTRUSB & 0x07; /* Mask SOF */
|
|
unsigned short intrIn = REG_USB_REG_INTRIN;
|
|
unsigned short intrOut = REG_USB_REG_INTROUT;
|
|
unsigned char intrDMA = REG_USB_REG_INTR;
|
|
|
|
if(intrUSB == 0 && intrIn == 0 && intrOut == 0 && intrDMA == 0)
|
|
return;
|
|
|
|
/* EPIN & EPOUT are all handled in DMA */
|
|
if(intrIn & USB_INTR_EP0)
|
|
EP0_handler();
|
|
if(intrUSB & USB_INTR_RESET)
|
|
udc_reset();
|
|
if(intrUSB & USB_INTR_SUSPEND);
|
|
if(intrUSB & USB_INTR_RESUME);
|
|
if(intrDMA & USB_INTR_DMA_BULKIN)
|
|
{
|
|
usb_core_transfer_complete(((REG_USB_REG_CNTL1 >> 4) & 0xF) | USB_DIR_IN, USB_DIR_IN, 0, 0);
|
|
}
|
|
if(intrDMA & USB_INTR_DMA_BULKOUT)
|
|
{
|
|
usb_core_transfer_complete(((REG_USB_REG_CNTL2 >> 4) & 0xF) | USB_DIR_OUT, USB_DIR_OUT, 0, 0);
|
|
}
|
|
}
|
|
|
|
bool usb_drv_stalled(int endpoint, bool in)
|
|
{
|
|
select_endpoint(endpoint);
|
|
|
|
if(endpoint == 0)
|
|
return (REG_USB_REG_CSR0 & USB_CSR0_SENDSTALL) != 0;
|
|
else
|
|
{
|
|
if(in)
|
|
return (REG_USB_REG_INCSR & USB_INCSR_SENDSTALL) != 0;
|
|
else
|
|
return (REG_USB_REG_OUTCSR & USB_OUTCSR_SENDSTALL) != 0;
|
|
}
|
|
}
|
|
|
|
void usb_drv_stall(int endpoint, bool stall, bool in)
|
|
{
|
|
select_endpoint(endpoint);
|
|
|
|
if(endpoint == 0)
|
|
{
|
|
if(stall)
|
|
REG_USB_REG_CSR0 |= USB_CSR0_SENDSTALL;
|
|
else
|
|
REG_USB_REG_CSR0 &= ~USB_CSR0_SENDSTALL;
|
|
}
|
|
else
|
|
{
|
|
if(in)
|
|
{
|
|
if(stall)
|
|
REG_USB_REG_INCSR |= USB_INCSR_SENDSTALL;
|
|
else
|
|
REG_USB_REG_INCSR &= ~USB_INCSR_SENDSTALL;
|
|
}
|
|
else
|
|
{
|
|
if(stall)
|
|
REG_USB_REG_OUTCSR |= USB_OUTCSR_SENDSTALL;
|
|
else
|
|
REG_USB_REG_OUTCSR &= ~USB_OUTCSR_SENDSTALL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool usb_drv_connected(void)
|
|
{
|
|
return __gpio_get_pin(GPIO_UDC_DETE) == 1;
|
|
}
|
|
|
|
int usb_detect(void)
|
|
{
|
|
if(usb_drv_connected())
|
|
return USB_INSERTED;
|
|
else
|
|
return USB_EXTRACTED;
|
|
}
|
|
|
|
void usb_init_device(void)
|
|
{
|
|
usb_init_gpio();
|
|
}
|
|
|
|
void usb_enable(bool on)
|
|
{
|
|
if(on)
|
|
usb_core_init();
|
|
else
|
|
usb_core_exit();
|
|
}
|
|
|
|
void usb_drv_init(void)
|
|
{
|
|
/* Set this bit to allow the UDC entering low-power mode when
|
|
* there are no actions on the USB bus.
|
|
* UDC still works during this bit was set.
|
|
*/
|
|
//__cpm_stop_udc();
|
|
|
|
__cpm_start_udc();
|
|
|
|
/* Enable the USB PHY */
|
|
REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE;
|
|
|
|
/* Disable interrupts */
|
|
REG_USB_REG_INTRINE = 0;
|
|
REG_USB_REG_INTROUTE = 0;
|
|
REG_USB_REG_INTRUSBE = 0;
|
|
|
|
/* Enable interrupts */
|
|
REG_USB_REG_INTRINE |= USB_INTR_EP0;
|
|
REG_USB_REG_INTRUSBE |= USB_INTR_RESET;
|
|
|
|
/* Enable SUSPEND */
|
|
/* usb_setb(USB_REG_POWER, USB_POWER_SUSPENDM); */
|
|
|
|
/* Enable HS Mode */
|
|
REG_USB_REG_POWER |= USB_POWER_HSENAB;
|
|
|
|
/* Let host detect UDC:
|
|
* Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this
|
|
* transistor on and pull the USBDP pin HIGH.
|
|
*/
|
|
REG_USB_REG_POWER |= USB_POWER_SOFTCONN;
|
|
|
|
udc_reset();
|
|
}
|
|
|
|
void usb_drv_exit(void)
|
|
{
|
|
/* Disable interrupts */
|
|
REG_USB_REG_INTRINE = 0;
|
|
REG_USB_REG_INTROUTE = 0;
|
|
REG_USB_REG_INTRUSBE = 0;
|
|
|
|
/* Disable DMA */
|
|
REG_USB_REG_CNTL1 = 0;
|
|
REG_USB_REG_CNTL2 = 0;
|
|
|
|
/* Disconnect from usb */
|
|
REG_USB_REG_POWER &= ~USB_POWER_SOFTCONN;
|
|
|
|
/* Disable the USB PHY */
|
|
REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE;
|
|
|
|
__cpm_stop_udc();
|
|
}
|
|
|
|
void usb_drv_set_address(int address)
|
|
{
|
|
REG_USB_REG_FADDR = address;
|
|
}
|
|
|
|
int usb_drv_send(int endpoint, void* ptr, int length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int usb_drv_recv(int endpoint, void* ptr, int length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void usb_drv_set_test_mode(int mode)
|
|
{
|
|
|
|
}
|
|
|
|
int usb_drv_port_speed(void)
|
|
{
|
|
return ((REG_USB_REG_POWER & USB_POWER_HSMODE) != 0) ? 1 : 0;
|
|
}
|
|
|
|
void usb_drv_cancel_all_transfers(void)
|
|
{
|
|
int i;
|
|
for(i=0; i<5; i++)
|
|
{
|
|
endpoints[i].ptr = endpoints[i].buf;
|
|
endpoints[i].length = 0;
|
|
}
|
|
}
|
|
|
|
void usb_drv_release_endpoint(int ep)
|
|
{
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
//------------------------------------------
|
|
#ifndef u8
|
|
#define u8 unsigned char
|
|
#endif
|
|
|
|
#ifndef u16
|
|
#define u16 unsigned short
|
|
#endif
|
|
|
|
#ifndef u32
|
|
#define u32 unsigned int
|
|
#endif
|
|
|
|
#ifndef s8
|
|
#define s8 char
|
|
#endif
|
|
|
|
#ifndef s16
|
|
#define s16 short
|
|
#endif
|
|
|
|
#ifndef s32
|
|
#define s32 int
|
|
#endif
|
|
|
|
extern int usbdebug;
|
|
|
|
enum USB_ENDPOINT_TYPE
|
|
{
|
|
ENDPOINT_TYPE_CONTROL,
|
|
/* Typically used to configure a device when attached to the host.
|
|
* It may also be used for other device specific purposes, including
|
|
* control of other pipes on the device.
|
|
*/
|
|
ENDPOINT_TYPE_ISOCHRONOUS,
|
|
/* Typically used for applications which need guaranteed speed.
|
|
* Isochronous transfer is fast but with possible data loss. A typical
|
|
* use is audio data which requires a constant data rate.
|
|
*/
|
|
ENDPOINT_TYPE_BULK,
|
|
/* Typically used by devices that generate or consume data in relatively
|
|
* large and bursty quantities. Bulk transfer has wide dynamic latitude
|
|
* in transmission constraints. It can use all remaining available bandwidth,
|
|
* but with no guarantees on bandwidth or latency. Since the USB bus is
|
|
* normally not very busy, there is typically 90% or more of the bandwidth
|
|
* available for USB transfers.
|
|
*/
|
|
ENDPOINT_TYPE_INTERRUPT
|
|
/* Typically used by devices that need guaranteed quick responses
|
|
* (bounded latency).
|
|
*/
|
|
};
|
|
|
|
|
|
enum USB_STANDARD_REQUEST_CODE {
|
|
GET_STATUS,
|
|
CLEAR_FEATURE,
|
|
SET_FEATURE = 3,
|
|
SET_ADDRESS = 5,
|
|
GET_DESCRIPTOR,
|
|
SET_DESCRIPTOR,
|
|
GET_CONFIGURATION,
|
|
SET_CONFIGURATION,
|
|
GET_INTERFACE,
|
|
SET_INTERFACE,
|
|
SYNCH_FRAME
|
|
};
|
|
|
|
|
|
enum USB_DESCRIPTOR_TYPE {
|
|
DEVICE_DESCRIPTOR = 1,
|
|
CONFIGURATION_DESCRIPTOR,
|
|
STRING_DESCRIPTOR,
|
|
INTERFACE_DESCRIPTOR,
|
|
ENDPOINT_DESCRIPTOR,
|
|
DEVICE_QUALIFIER_DESCRIPTOR,
|
|
OTHER_SPEED_CONFIGURATION_DESCRIPTOR,
|
|
INTERFACE_POWER1_DESCRIPTOR
|
|
};
|
|
|
|
|
|
enum USB_FEATURE_SELECTOR {
|
|
ENDPOINT_HALT,
|
|
DEVICE_REMOTE_WAKEUP,
|
|
TEST_MODE
|
|
};
|
|
|
|
enum USB_CLASS_CODE {
|
|
CLASS_DEVICE,
|
|
CLASS_AUDIO,
|
|
CLASS_COMM_AND_CDC_CONTROL,
|
|
CLASS_HID,
|
|
CLASS_PHYSICAL = 0x05,
|
|
CLASS_STILL_IMAGING,
|
|
CLASS_PRINTER,
|
|
CLASS_MASS_STORAGE,
|
|
CLASS_HUB,
|
|
CLASS_CDC_DATA,
|
|
CLASS_SMART_CARD,
|
|
CLASS_CONTENT_SECURITY = 0x0d,
|
|
CLASS_VIDEO,
|
|
CLASS_DIAGNOSTIC_DEVICE = 0xdc,
|
|
CLASS_WIRELESS_CONTROLLER = 0xe0,
|
|
CLASS_MISCELLANEOUS = 0xef,
|
|
CLASS_APP_SPECIFIC = 0xfe,
|
|
CLASS_VENDOR_SPECIFIC = 0xff
|
|
};
|
|
|
|
|
|
typedef struct {
|
|
u8 bmRequestType;
|
|
u8 bRequest;
|
|
u16 wValue;
|
|
u16 wIndex;
|
|
u16 wLength;
|
|
} __attribute__ ((packed)) USB_DeviceRequest;
|
|
|
|
|
|
typedef struct {
|
|
u8 bLength;
|
|
u8 bDescriptorType;
|
|
u16 bcdUSB;
|
|
u8 bDeviceClass;
|
|
u8 bDeviceSubClass;
|
|
u8 bDeviceProtocol;
|
|
u8 bMaxPacketSize0;
|
|
u16 idVendor;
|
|
u16 idProduct;
|
|
u16 bcdDevice;
|
|
u8 iManufacturer;
|
|
u8 iProduct;
|
|
u8 iSerialNumber;
|
|
u8 bNumConfigurations;
|
|
} __attribute__ ((packed)) USB_DeviceDescriptor;
|
|
|
|
|
|
typedef struct {
|
|
u8 bLength;
|
|
u8 bDescriptorType;
|
|
u16 bcdUSB;
|
|
u8 bDeviceClass;
|
|
u8 bDeviceSubClass;
|
|
u8 bDeviceProtocol;
|
|
u8 bMaxPacketSize0;
|
|
u8 bNumConfigurations;
|
|
u8 bReserved;
|
|
} __attribute__ ((packed)) USB_DeviceQualifierDescriptor;
|
|
|
|
|
|
typedef struct {
|
|
u8 bLength;
|
|
u8 bDescriptorType;
|
|
u16 wTotalLength;
|
|
u8 bNumInterfaces;
|
|
u8 bConfigurationValue;
|
|
u8 iConfiguration;
|
|
u8 bmAttributes;
|
|
u8 MaxPower;
|
|
} __attribute__ ((packed)) USB_ConfigDescriptor;
|
|
|
|
|
|
typedef struct {
|
|
u8 bLength;
|
|
u8 bDescriptorType;
|
|
u16 wTotalLength;
|
|
u8 bNumInterfaces;
|
|
u8 bConfigurationValue;
|
|
u8 iConfiguration;
|
|
u8 bmAttributes;
|
|
u8 bMaxPower;
|
|
} __attribute__ ((packed)) USB_OtherSpeedConfigDescriptor;
|
|
|
|
|
|
typedef struct {
|
|
u8 bLength;
|
|
u8 bDescriptorType;
|
|
u8 bInterfaceNumber;
|
|
u8 bAlternateSetting;
|
|
u8 bNumEndpoints;
|
|
u8 bInterfaceClass;
|
|
u8 bInterfaceSubClass;
|
|
u8 bInterfaceProtocol;
|
|
u8 iInterface;
|
|
} __attribute__ ((packed)) USB_InterfaceDescriptor;
|
|
|
|
|
|
typedef struct {
|
|
u8 bLegth;
|
|
u8 bDescriptorType;
|
|
u8 bEndpointAddress;
|
|
u8 bmAttributes;
|
|
u16 wMaxPacketSize;
|
|
u8 bInterval;
|
|
} __attribute__ ((packed)) USB_EndPointDescriptor;
|
|
|
|
|
|
typedef struct {
|
|
u8 bLength;
|
|
u8 bDescriptorType;
|
|
u16 SomeDesriptor[1];
|
|
} __attribute__ ((packed)) USB_StringDescriptor;
|
|
//------------------------------------------
|
|
#define MAX_EP0_SIZE 64
|
|
#define MAX_EP1_SIZE 512
|
|
|
|
#define USB_HS 0
|
|
#define USB_FS 1
|
|
#define USB_LS 2
|
|
|
|
//definitions of EP0
|
|
#define USB_EP0_IDLE 0
|
|
#define USB_EP0_RX 1
|
|
#define USB_EP0_TX 2
|
|
/* Define maximum packet size for endpoint 0 */
|
|
#define M_EP0_MAXP 64
|
|
/* Endpoint 0 status structure */
|
|
|
|
static __inline__ void usb_setb(u32 port, u8 val)
|
|
{
|
|
volatile u8 *ioport = (volatile u8 *)(port);
|
|
*ioport = (*ioport) | val;
|
|
}
|
|
|
|
static __inline__ void usb_clearb(u32 port, u8 val)
|
|
{
|
|
volatile u8 *ioport = (volatile u8 *)(port);
|
|
*ioport = (*ioport) & ~val;
|
|
}
|
|
|
|
static __inline__ void usb_setw(u32 port, u16 val)
|
|
{
|
|
volatile u16 *ioport = (volatile u16 *)(port);
|
|
*ioport = (*ioport) | val;
|
|
}
|
|
|
|
static __inline__ void usb_clearw(u32 port, u16 val)
|
|
{
|
|
volatile u16 *ioport = (volatile u16 *)(port);
|
|
*ioport = (*ioport) & ~val;
|
|
}
|
|
//---------------------------------
|
|
#define BULK_OUT_BUF_SIZE 0x20000 //buffer size :
|
|
#define BULK_IN_BUF_SIZE 0x20000 // too
|
|
|
|
enum UDC_STATE
|
|
{
|
|
IDLE,
|
|
BULK_IN,
|
|
BULK_OUT
|
|
};
|
|
|
|
enum USB_JZ4740_REQUEST //add for USB_BOOT
|
|
{
|
|
VR_GET_CUP_INFO = 0,
|
|
VR_SET_DATA_ADDERSS,
|
|
VR_SET_DATA_LENGTH,
|
|
VR_FLUSH_CACHES,
|
|
VR_PROGRAM_START1,
|
|
VR_PROGRAM_START2,
|
|
VR_NOR_OPS,
|
|
VR_NAND_OPS,
|
|
VR_SDRAM_OPS,
|
|
VR_CONFIGRATION
|
|
};
|
|
|
|
enum NOR_OPS_TYPE
|
|
{
|
|
NOR_INIT = 0,
|
|
NOR_QUERY,
|
|
NOR_WRITE,
|
|
NOR_ERASE_CHIP,
|
|
NOR_ERASE_SECTOR
|
|
};
|
|
|
|
enum NOR_FLASH_TYPE
|
|
{
|
|
NOR_AM29 = 0,
|
|
NOR_SST28,
|
|
NOR_SST39x16,
|
|
NOR_SST39x8
|
|
};
|
|
|
|
enum NAND_OPS_TYPE
|
|
{
|
|
NAND_QUERY = 0,
|
|
NAND_INIT,
|
|
NAND_MARK_BAD,
|
|
NAND_READ_OOB,
|
|
NAND_READ_RAW,
|
|
NAND_ERASE,
|
|
NAND_READ,
|
|
NAND_PROGRAM,
|
|
NAND_READ_TO_RAM
|
|
};
|
|
|
|
enum SDRAM_OPS_TYPE
|
|
{
|
|
SDRAM_LOAD,
|
|
|
|
};
|
|
|
|
enum DATA_STRUCTURE_OB
|
|
{
|
|
DS_flash_info ,
|
|
DS_hand
|
|
};
|
|
|
|
|
|
/*typedef enum _USB_BOOT_STATUS
|
|
{
|
|
USB_NO_ERR =0 ,
|
|
GET_CPU_INFO_ERR,
|
|
SET_DATA_ADDRESS_ERR,
|
|
SET_DATA_LENGTH_ERR,
|
|
FLUSH_CAHCES_ERR,
|
|
PROGRAM_START1_ERR,
|
|
PROGRAM_START2_ERR,
|
|
NOR_OPS_ERR,
|
|
NAND_OPS_ERR,
|
|
NOR_FLASHTYPE_ERR,
|
|
OPS_NOTSUPPORT_ERR
|
|
}USB_BOOT_STATUS;*/
|
|
|
|
enum OPTION
|
|
{
|
|
OOB_ECC,
|
|
OOB_NO_ECC,
|
|
NO_OOB,
|
|
};
|
|
//-------------------------
|
|
static inline void jz_writeb(u32 address, u8 value)
|
|
{
|
|
*((volatile u8 *)address) = value;
|
|
}
|
|
|
|
static inline void jz_writew(u32 address, u16 value)
|
|
{
|
|
*((volatile u16 *)address) = value;
|
|
}
|
|
|
|
static inline void jz_writel(u32 address, u32 value)
|
|
{
|
|
*((volatile u32 *)address) = value;
|
|
}
|
|
|
|
static inline u8 jz_readb(u32 address)
|
|
{
|
|
return *((volatile u8 *)address);
|
|
}
|
|
|
|
static inline u16 jz_readw(u32 address)
|
|
{
|
|
return *((volatile u16 *)address);
|
|
}
|
|
|
|
static inline u32 jz_readl(u32 address)
|
|
{
|
|
return *((volatile u32 *)address);
|
|
}
|
|
//---------------------------
|
|
|
|
#define TXFIFOEP0 USB_FIFO_EP0
|
|
|
|
u8 *Bulk_in_buf;
|
|
u32 Bulk_out_buf[BULK_OUT_BUF_SIZE];
|
|
u32 Bulk_in_size,Bulk_in_finish,Bulk_out_size;
|
|
u16 handshake_PKT[4]={0,0,0,0};
|
|
u8 udc_state;
|
|
|
|
static u32 rx_buf[32];
|
|
static u32 tx_buf[32];
|
|
static u32 tx_size, rx_size, finished,fifo;
|
|
static u8 ep0state,USB_Version;
|
|
|
|
static u32 fifoaddr[] =
|
|
{
|
|
TXFIFOEP0, TXFIFOEP0+4 ,TXFIFOEP0+8
|
|
};
|
|
|
|
static u32 fifosize[] = {
|
|
MAX_EP0_SIZE, MAX_EP1_SIZE
|
|
};
|
|
|
|
static void udcReadFifo(u8 *ptr, int size)
|
|
{
|
|
u32 *d = (u32 *)ptr;
|
|
int s;
|
|
s = (size + 3) >> 2;
|
|
while (s--)
|
|
*d++ = REG32(fifo);
|
|
}
|
|
|
|
static void udcWriteFifo(u8 *ptr, int size)
|
|
{
|
|
u32 *d = (u32 *)ptr;
|
|
u8 *c;
|
|
int s, q;
|
|
|
|
if (size > 0) {
|
|
s = size >> 2;
|
|
while (s--)
|
|
REG32(fifo) = *d++;
|
|
q = size & 3;
|
|
if (q) {
|
|
c = (u8 *)d;
|
|
while (q--)
|
|
REG8(fifo) = *c++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HW_SendPKT(int ep, const u8 *buf, int size)
|
|
{
|
|
fifo = fifoaddr[ep];
|
|
|
|
if (ep!=0)
|
|
{
|
|
Bulk_in_size = size;
|
|
Bulk_in_finish = 0;
|
|
jz_writeb(USB_REG_INDEX, ep);
|
|
if (Bulk_in_size - Bulk_in_finish <= fifosize[ep])
|
|
{
|
|
udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish),
|
|
Bulk_in_size - Bulk_in_finish);
|
|
usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY);
|
|
Bulk_in_finish = Bulk_in_size;
|
|
}
|
|
else
|
|
{
|
|
udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish),
|
|
fifosize[ep]);
|
|
usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY);
|
|
Bulk_in_finish += fifosize[ep];
|
|
Bulk_in_buf = (u8*)buf;
|
|
}
|
|
}
|
|
else //EP0
|
|
{
|
|
tx_size = size;
|
|
finished = 0;
|
|
memcpy((void *)tx_buf, buf, size);
|
|
ep0state = USB_EP0_TX;
|
|
}
|
|
}
|
|
|
|
void HW_GetPKT(int ep, const u8 *buf, unsigned int size)
|
|
{
|
|
memcpy((void *)buf, (u8 *)rx_buf, size);
|
|
fifo = fifoaddr[ep];
|
|
if (rx_size > size)
|
|
rx_size -= size;
|
|
else
|
|
{
|
|
size = rx_size;
|
|
rx_size = 0;
|
|
}
|
|
memcpy((u8 *)rx_buf, (u8 *)((u32)rx_buf+size), rx_size);
|
|
}
|
|
|
|
void Enable_DMA(u8* buf, u32 length)
|
|
{
|
|
dma_cache_wback_inv((u32)buf, length);
|
|
jz_writeb(USB_REG_INDEX, 1);
|
|
usb_setw(USB_REG_INCSR, 0x9400);
|
|
usb_clearw(USB_REG_INTRINE, 0x2); //disable OUT intr
|
|
jz_writel(USB_REG_ADDR1, (u32)buf);
|
|
jz_writel(USB_REG_COUNT1, length);
|
|
jz_writel(USB_REG_CNTL1, 0x001f);
|
|
}
|
|
|
|
void Disable_DMA(void)
|
|
{
|
|
jz_writeb(USB_REG_INDEX, 1);
|
|
usb_clearw(USB_REG_INCSR, 0x9400);
|
|
usb_setw(USB_REG_INTRINE, 0x2); //Enable OUT intr
|
|
}
|
|
|
|
static USB_DeviceDescriptor devDesc =
|
|
{
|
|
sizeof(USB_DeviceDescriptor),
|
|
DEVICE_DESCRIPTOR, //1
|
|
0x0200, //Version 2.0
|
|
0xff, //Vendor spec class
|
|
0xff,
|
|
0xff,
|
|
64, /* Ep0 FIFO size */
|
|
0x601a, //vendor ID
|
|
0xDEAD, //Product ID
|
|
0xffff,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x01
|
|
};
|
|
|
|
#define CONFIG_DESCRIPTOR_LEN (sizeof(USB_ConfigDescriptor) + \
|
|
sizeof(USB_InterfaceDescriptor) + \
|
|
sizeof(USB_EndPointDescriptor) * 2)
|
|
|
|
static struct {
|
|
USB_ConfigDescriptor configuration_descriptor;
|
|
USB_InterfaceDescriptor interface_descritor;
|
|
USB_EndPointDescriptor endpoint_descriptor[2];
|
|
} __attribute__ ((packed)) confDesc = {
|
|
{
|
|
sizeof(USB_ConfigDescriptor),
|
|
CONFIGURATION_DESCRIPTOR,
|
|
CONFIG_DESCRIPTOR_LEN,
|
|
0x01,
|
|
0x01,
|
|
0x00,
|
|
0xc0, // Self Powered, no remote wakeup
|
|
0x64 // Maximum power consumption 2000 mA
|
|
},
|
|
{
|
|
sizeof(USB_InterfaceDescriptor),
|
|
INTERFACE_DESCRIPTOR,
|
|
0x00,
|
|
0x00,
|
|
0x02, /* ep number */
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0x00
|
|
},
|
|
{
|
|
{
|
|
sizeof(USB_EndPointDescriptor),
|
|
ENDPOINT_DESCRIPTOR,
|
|
(1 << 7) | 1,// endpoint 2 is IN endpoint
|
|
2, /* bulk */
|
|
512,
|
|
0
|
|
},
|
|
{
|
|
sizeof(USB_EndPointDescriptor),
|
|
ENDPOINT_DESCRIPTOR,
|
|
(0 << 7) | 1,// endpoint 5 is OUT endpoint
|
|
2, /* bulk */
|
|
512, /* OUT EP FIFO size */
|
|
0
|
|
}
|
|
}
|
|
};
|
|
|
|
void sendDevDescString(int size)
|
|
{
|
|
u16 str_ret[13] = {
|
|
0x031a,//0x1a=26 byte
|
|
0x0041,
|
|
0x0030,
|
|
0x0030,
|
|
0x0041,
|
|
0x0030,
|
|
0x0030,
|
|
0x0041,
|
|
0x0030,
|
|
0x0030,
|
|
0x0041,
|
|
0x0030,
|
|
0x0030
|
|
};
|
|
if(size >= 26)
|
|
size = 26;
|
|
str_ret[0] = (0x0300 | size);
|
|
HW_SendPKT(0, (u8 *)str_ret,size);
|
|
}
|
|
|
|
void sendDevDesc(int size)
|
|
{
|
|
switch (size) {
|
|
case 18:
|
|
HW_SendPKT(0, (u8 *)&devDesc, sizeof(devDesc));
|
|
break;
|
|
default:
|
|
HW_SendPKT(0, (u8 *)&devDesc, 8);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void sendConfDesc(int size)
|
|
{
|
|
switch (size) {
|
|
case 9:
|
|
HW_SendPKT(0, (u8 *)&confDesc, 9);
|
|
break;
|
|
case 8:
|
|
HW_SendPKT(0, (u8 *)&confDesc, 8);
|
|
break;
|
|
default:
|
|
HW_SendPKT(0, (u8 *)&confDesc, sizeof(confDesc));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EP0_init(u32 out, u32 out_size, u32 in, u32 in_size)
|
|
{
|
|
confDesc.endpoint_descriptor[0].bEndpointAddress = (1<<7) | in;
|
|
confDesc.endpoint_descriptor[0].wMaxPacketSize = in_size;
|
|
confDesc.endpoint_descriptor[1].bEndpointAddress = (0<<7) | out;
|
|
confDesc.endpoint_descriptor[1].wMaxPacketSize = out_size;
|
|
}
|
|
|
|
static void udc_reset(void)
|
|
{
|
|
//data init
|
|
ep0state = USB_EP0_IDLE;
|
|
Bulk_in_size = 0;
|
|
Bulk_in_finish = 0;
|
|
Bulk_out_size = 0;
|
|
udc_state = IDLE;
|
|
tx_size = 0;
|
|
rx_size = 0;
|
|
finished = 0;
|
|
/* Enable the USB PHY */
|
|
// REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE;
|
|
/* Disable interrupts */
|
|
jz_writew(USB_REG_INTRINE, 0);
|
|
jz_writew(USB_REG_INTROUTE, 0);
|
|
jz_writeb(USB_REG_INTRUSBE, 0);
|
|
jz_writeb(USB_REG_FADDR,0);
|
|
jz_writeb(USB_REG_POWER,0x60); //High speed
|
|
jz_writeb(USB_REG_INDEX,0);
|
|
jz_writeb(USB_REG_CSR0,0xc0);
|
|
jz_writeb(USB_REG_INDEX,1);
|
|
jz_writew(USB_REG_INMAXP,512);
|
|
jz_writew(USB_REG_INCSR,0x2048);
|
|
jz_writeb(USB_REG_INDEX,1);
|
|
jz_writew(USB_REG_OUTMAXP,512);
|
|
jz_writew(USB_REG_OUTCSR,0x0090);
|
|
jz_writew(USB_REG_INTRINE,0x3); //enable intr
|
|
jz_writew(USB_REG_INTROUTE,0x2);
|
|
jz_writeb(USB_REG_INTRUSBE,0x4);
|
|
|
|
if ((jz_readb(USB_REG_POWER)&0x10)==0)
|
|
{
|
|
jz_writeb(USB_REG_INDEX,1);
|
|
jz_writew(USB_REG_INMAXP,64);
|
|
jz_writew(USB_REG_INCSR,0x2048);
|
|
jz_writeb(USB_REG_INDEX,1);
|
|
jz_writew(USB_REG_OUTMAXP,64);
|
|
jz_writew(USB_REG_OUTCSR,0x0090);
|
|
USB_Version=USB_FS;
|
|
fifosize[1]=64;
|
|
EP0_init(1,64,1,64);
|
|
}
|
|
else
|
|
{
|
|
jz_writeb(USB_REG_INDEX,1);
|
|
jz_writew(USB_REG_INMAXP,512);
|
|
jz_writew(USB_REG_INCSR,0x2048);
|
|
jz_writeb(USB_REG_INDEX,1);
|
|
jz_writew(USB_REG_OUTMAXP,512);
|
|
jz_writew(USB_REG_OUTCSR,0x0090);
|
|
USB_Version=USB_HS;
|
|
fifosize[1]=512;
|
|
EP0_init(1,512,1,512);
|
|
}
|
|
|
|
}
|
|
|
|
void usbHandleStandDevReq(u8 *buf)
|
|
{
|
|
USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf;
|
|
switch (dreq->bRequest) {
|
|
case GET_DESCRIPTOR:
|
|
if (dreq->bmRequestType == 0x80) /* Dev2Host */
|
|
switch(dreq->wValue >> 8)
|
|
{
|
|
case DEVICE_DESCRIPTOR:
|
|
sendDevDesc(dreq->wLength);
|
|
break;
|
|
case CONFIGURATION_DESCRIPTOR:
|
|
sendConfDesc(dreq->wLength);
|
|
break;
|
|
case STRING_DESCRIPTOR:
|
|
if (dreq->wLength == 0x02)
|
|
HW_SendPKT(0, "\x04\x03", 2);
|
|
else
|
|
sendDevDescString(dreq->wLength);
|
|
//HW_SendPKT(0, "\x04\x03\x09\x04", 2);
|
|
break;
|
|
}
|
|
ep0state=USB_EP0_TX;
|
|
|
|
break;
|
|
case SET_ADDRESS:
|
|
jz_writeb(USB_REG_FADDR,dreq->wValue);
|
|
break;
|
|
case GET_STATUS:
|
|
switch (dreq->bmRequestType) {
|
|
case 80: /* device */
|
|
HW_SendPKT(0, "\x01\x00", 2);
|
|
break;
|
|
case 81: /* interface */
|
|
case 82: /* ep */
|
|
HW_SendPKT(0, "\x00\x00", 2);
|
|
break;
|
|
}
|
|
ep0state=USB_EP0_TX;
|
|
break;
|
|
case CLEAR_FEATURE:
|
|
case SET_CONFIGURATION:
|
|
case SET_INTERFACE:
|
|
case SET_FEATURE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
unsigned char nandbuffer[4096];
|
|
extern void jz_nand_read(int block, int page, unsigned char *buf);
|
|
|
|
void usbHandleVendorReq(u8 *buf)
|
|
{
|
|
USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf;
|
|
switch (dreq->bRequest)
|
|
{
|
|
case 0xB0:
|
|
memset(&nandbuffer, 0, 4096);
|
|
jz_nand_read(dreq->wValue, dreq->wIndex, nandbuffer);
|
|
//printf("Read block %d page %d", dreq->wValue, dreq->wIndex);
|
|
udc_state = IDLE;
|
|
break;
|
|
case 0xAB:
|
|
Enable_DMA(nandbuffer, 4096);
|
|
//HW_SendPKT(1, nandbuffer, 4096);
|
|
//printf("Send data");
|
|
//udc_state = BULK_OUT;
|
|
break;
|
|
case 0x12:
|
|
HW_SendPKT(0, "TEST", 4);
|
|
//printf("Send test");
|
|
udc_state = IDLE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Handshake_PKT(void)
|
|
{
|
|
if (udc_state!=IDLE)
|
|
{
|
|
HW_SendPKT(1,(u8 *)handshake_PKT,sizeof(handshake_PKT));
|
|
udc_state = IDLE;
|
|
}
|
|
}
|
|
|
|
void usbHandleDevReq(u8 *buf)
|
|
{
|
|
switch ((buf[0] & (3 << 5)) >> 5) {
|
|
case 0: /* Standard request */
|
|
usbHandleStandDevReq(buf);
|
|
break;
|
|
case 1: /* Class request */
|
|
break;
|
|
case 2: /* Vendor request */
|
|
usbHandleVendorReq(buf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EP0_Handler (void)
|
|
{
|
|
u8 byCSR0;
|
|
|
|
/* Read CSR0 */
|
|
jz_writeb(USB_REG_INDEX, 0);
|
|
byCSR0 = jz_readb(USB_REG_CSR0);
|
|
|
|
/* Check for SentStall
|
|
if sendstall is set ,clear the sendstall bit*/
|
|
if (byCSR0 & USB_CSR0_SENTSTALL)
|
|
{
|
|
jz_writeb(USB_REG_CSR0, (byCSR0 & ~USB_CSR0_SENDSTALL));
|
|
ep0state = USB_EP0_IDLE;
|
|
return;
|
|
}
|
|
|
|
/* Check for SetupEnd */
|
|
if (byCSR0 & USB_CSR0_SETUPEND)
|
|
{
|
|
jz_writeb(USB_REG_CSR0, (byCSR0 | USB_CSR0_SVDSETUPEND));
|
|
ep0state = USB_EP0_IDLE;
|
|
return;
|
|
}
|
|
/* Call relevant routines for endpoint 0 state */
|
|
if (ep0state == USB_EP0_IDLE)
|
|
{
|
|
if (byCSR0 & USB_CSR0_OUTPKTRDY) //There are datas in fifo
|
|
{
|
|
USB_DeviceRequest *dreq;
|
|
fifo=fifoaddr[0];
|
|
udcReadFifo((u8 *)rx_buf, sizeof(USB_DeviceRequest));
|
|
usb_setb(USB_REG_CSR0, 0x48);//clear OUTRD bit
|
|
dreq = (USB_DeviceRequest *)rx_buf;
|
|
usbHandleDevReq((u8 *)rx_buf);
|
|
}
|
|
rx_size = 0;
|
|
}
|
|
|
|
if (ep0state == USB_EP0_TX)
|
|
{
|
|
fifo=fifoaddr[0];
|
|
if (tx_size - finished <= 64)
|
|
{
|
|
udcWriteFifo((u8 *)((u32)tx_buf+finished),
|
|
tx_size - finished);
|
|
finished = tx_size;
|
|
usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY);
|
|
usb_setb(USB_REG_CSR0, USB_CSR0_DATAEND); //Set dataend!
|
|
ep0state=USB_EP0_IDLE;
|
|
} else
|
|
{
|
|
udcWriteFifo((u8 *)((u32)tx_buf+finished), 64);
|
|
usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY);
|
|
finished += 64;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void EPIN_Handler(u8 EP)
|
|
{
|
|
jz_writeb(USB_REG_INDEX, EP);
|
|
fifo = fifoaddr[EP];
|
|
|
|
if (Bulk_in_size-Bulk_in_finish==0)
|
|
{
|
|
Handshake_PKT();
|
|
return;
|
|
}
|
|
|
|
if (Bulk_in_size - Bulk_in_finish <= fifosize[EP])
|
|
{
|
|
udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish),
|
|
Bulk_in_size - Bulk_in_finish);
|
|
usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY);
|
|
Bulk_in_finish = Bulk_in_size;
|
|
}
|
|
else
|
|
{
|
|
udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish),
|
|
fifosize[EP]);
|
|
usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY);
|
|
Bulk_in_finish += fifosize[EP];
|
|
}
|
|
}
|
|
|
|
void EPOUT_Handler(u8 EP)
|
|
{
|
|
u32 size;
|
|
jz_writeb(USB_REG_INDEX, EP);
|
|
size = jz_readw(USB_REG_OUTCOUNT);
|
|
fifo = fifoaddr[EP];
|
|
udcReadFifo((u8 *)((u32)Bulk_out_buf+Bulk_out_size), size);
|
|
usb_clearb(USB_REG_OUTCSR,USB_OUTCSR_OUTPKTRDY);
|
|
Bulk_out_size += size;
|
|
}
|
|
|
|
void UDC(void)
|
|
{
|
|
u8 IntrUSB;
|
|
u16 IntrIn;
|
|
u16 IntrOut;
|
|
u16 IntrDMA;
|
|
/* Read interrupt registers */
|
|
IntrUSB = jz_readb(USB_REG_INTRUSB);
|
|
IntrIn = jz_readw(USB_REG_INTRIN);
|
|
IntrOut = jz_readw(USB_REG_INTROUT);
|
|
IntrDMA = jz_readb(USB_REG_INTR);
|
|
|
|
if ( IntrUSB == 0 && IntrIn == 0 && IntrOut == 0)
|
|
return;
|
|
|
|
if (IntrIn & 2)
|
|
{
|
|
EPIN_Handler(1);
|
|
}
|
|
if (IntrOut & 2)
|
|
{
|
|
EPOUT_Handler(1);
|
|
}
|
|
if (IntrUSB & USB_INTR_RESET)
|
|
{
|
|
udc_reset();
|
|
}
|
|
|
|
/* Check for endpoint 0 interrupt */
|
|
if (IntrIn & USB_INTR_EP0)
|
|
{
|
|
EP0_Handler();
|
|
}
|
|
|
|
if (IntrDMA & 0x1) //channel 1 :OUT
|
|
{
|
|
if (tx_size > 0 && tx_size % fifosize[1] != 0)
|
|
{
|
|
jz_writeb(USB_REG_INDEX, 1);
|
|
usb_clearb(USB_REG_INCSR, USB_INCSR_INPKTRDY);
|
|
}
|
|
Disable_DMA();
|
|
}
|
|
}
|
|
|
|
void __udc_start(void)
|
|
{
|
|
udc_reset();
|
|
|
|
ep0state = USB_EP0_IDLE;
|
|
Bulk_in_size = 0;
|
|
Bulk_in_finish = 0;
|
|
Bulk_out_size = 0;
|
|
udc_state = IDLE;
|
|
tx_size = 0;
|
|
rx_size = 0;
|
|
finished = 0;
|
|
|
|
if ((jz_readb(USB_REG_POWER)&0x10)==0)
|
|
{
|
|
USB_Version=USB_FS;
|
|
fifosize[1]=64;
|
|
EP0_init(1,64,1,64);
|
|
}
|
|
else
|
|
{
|
|
USB_Version=USB_HS;
|
|
fifosize[1]=512;
|
|
EP0_init(1,512,1,512);
|
|
}
|
|
|
|
USB_Version=USB_HS;
|
|
system_enable_irq(IRQ_UDC);
|
|
}
|
|
|
|
void usb_init_device(void)
|
|
{
|
|
REG_USB_REG_POWER &= ~USB_POWER_SOFTCONN;
|
|
REG_USB_REG_POWER |= USB_POWER_SOFTCONN;
|
|
__udc_start();
|
|
}
|
|
|
|
#endif
|