as3525v2-usb: all control operations are working, there is a problem with UMS: the IN transfer to respond to inquiry does not start, resulting in not lun being detected

- implement request_endpoint
- setup nextep chain for in endpoints
- remove useless dcache operation on IN transfer completion
- fix transfers to use correct max packet size

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28028 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Amaury Pouly 2010-09-07 20:44:26 +00:00
parent 025112fc7b
commit f20d11c718

View file

@ -31,7 +31,7 @@
#include "panic.h" #include "panic.h"
#include "mmu-arm.h" #include "mmu-arm.h"
#include "system.h" #include "system.h"
#define LOGF_ENABLE //#define LOGF_ENABLE
#include "logf.h" #include "logf.h"
#include "usb-drv-as3525v2.h" #include "usb-drv-as3525v2.h"
#include "usb_core.h" #include "usb_core.h"
@ -312,6 +312,12 @@ static void reset_endpoints(void)
/* 64 bytes packet size, active endpoint */ /* 64 bytes packet size, active endpoint */
DOEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep | DEPCTL_snak; DOEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep | DEPCTL_snak;
DIEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep | DEPCTL_snak; DIEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep | DEPCTL_snak;
/* Setup next chain for IN eps */
FOR_EACH_IN_EP_AND_EP0(i, ep)
{
int next_ep = __in_ep_list_ep0[(i + 1) % (NUM_IN_EP + 1)];
DIEPCTL(ep) = (DIEPCTL(ep) & ~bitm(DEPCTL, nextep)) | (next_ep << DEPCTL_nextep_bitp);
}
} }
static void cancel_all_transfers(bool cancel_ep0) static void cancel_all_transfers(bool cancel_ep0)
@ -472,7 +478,6 @@ static void handle_ep_int(int ep, bool dir_in)
panicf("usb-drv: ahb error on EP%d IN", ep); panicf("usb-drv: ahb error on EP%d IN", ep);
if(DIEPINT(ep) & DIEPINT_xfercompl) if(DIEPINT(ep) & DIEPINT_xfercompl)
{ {
logf("usb-drv: xfer complete on EP%d IN", ep);
if(endpoint->busy) if(endpoint->busy)
{ {
endpoint->busy = false; endpoint->busy = false;
@ -482,7 +487,6 @@ static void handle_ep_int(int ep, bool dir_in)
logf("len=%d reg=%ld xfer=%d", endpoint->len, logf("len=%d reg=%ld xfer=%d", endpoint->len,
(DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits), (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits),
transfered); transfered);
invalidate_dcache_range(endpoint->buffer, transfered);
/* handle EP0 state if necessary, /* handle EP0 state if necessary,
* this is a ack if length is 0 */ * this is a ack if length is 0 */
if(ep == 0) if(ep == 0)
@ -550,7 +554,10 @@ static void handle_ep_int(int ep, bool dir_in)
/* handle set address */ /* handle set address */
if(ep0_setup_pkt.bRequestType == USB_TYPE_STANDARD && if(ep0_setup_pkt.bRequestType == USB_TYPE_STANDARD &&
ep0_setup_pkt.bRequest == USB_REQ_SET_ADDRESS) ep0_setup_pkt.bRequest == USB_REQ_SET_ADDRESS)
usb_drv_set_address(ep0_setup_pkt.wValue); {
/* Set address now */
DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt.wValue << DCFG_devadr_bitp);
}
usb_core_control_request(&ep0_setup_pkt); usb_core_control_request(&ep0_setup_pkt);
} }
} }
@ -657,17 +664,62 @@ int usb_drv_port_speed(void)
} }
} }
static unsigned long usb_drv_mps_by_type(int type)
{
bool hs = usb_drv_port_speed();
switch(type)
{
case USB_ENDPOINT_XFER_CONTROL: return 64;
case USB_ENDPOINT_XFER_BULK: return hs ? 512 : 64;
case USB_ENDPOINT_XFER_INT: return hs ? 1024 : 64;
case USB_ENDPOINT_XFER_ISOC: return hs ? 1024 : 1023;
default: return 0;
}
}
int usb_drv_request_endpoint(int type, int dir) int usb_drv_request_endpoint(int type, int dir)
{ {
(void) type; int i, ep, ret = -1;
(void) dir;
logf("usb-drv: request endpoint (type=%d,dir=%s)", type, dir == USB_DIR_IN ? "IN" : "OUT"); logf("usb-drv: request endpoint (type=%d,dir=%s)", type, dir == USB_DIR_IN ? "IN" : "OUT");
if(dir == USB_DIR_IN)
FOR_EACH_IN_EP(i, ep)
{
if(endpoints[ep][DIR_IN].active)
continue;
endpoints[ep][DIR_IN].active = true;
ret = ep | dir;
break;
}
else
FOR_EACH_OUT_EP(i, ep)
{
if(endpoints[ep][DIR_OUT].active)
continue;
endpoints[ep][DIR_OUT].active = true;
ret = ep | dir;
break;
}
if(ret == -1)
{
logf("usb-drv: request failed");
return -1; return -1;
} }
unsigned long data = DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp)
| (usb_drv_mps_by_type(type) << DEPCTL_mps_bitp);
unsigned long mask = ~(bitm(DEPCTL, eptype) | bitm(DEPCTL, mps));
if(dir == USB_DIR_IN) DIEPCTL(ep) = (DIEPCTL(ep) & mask) | data;
else DOEPCTL(ep) = (DOEPCTL(ep) & mask) | data;
return ret;
}
void usb_drv_release_endpoint(int ep) void usb_drv_release_endpoint(int ep)
{ {
//logf("usb-drv: release EP%d %s", EP_NUM(ep), EP_DIR(ep) == DIR_IN ? "IN" : "OUT"); logf("usb-drv: release EP%d %s", EP_NUM(ep), EP_DIR(ep) == DIR_IN ? "IN" : "OUT");
endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false;
} }
@ -679,8 +731,11 @@ void usb_drv_cancel_all_transfers()
static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocking) static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocking)
{ {
ep = EP_NUM(ep); ep = EP_NUM(ep);
logf("usb-drv: xfer EP%d, len=%d, dir_in=%d, blocking=%d", ep, if(ep != 0)
{
_logf("usb-drv: xfer EP%d, len=%d, dir_in=%d, blocking=%d", ep,
len, dir_in, blocking); len, dir_in, blocking);
}
volatile unsigned long *epctl = dir_in ? &DIEPCTL(ep) : &DOEPCTL(ep); volatile unsigned long *epctl = dir_in ? &DIEPCTL(ep) : &DOEPCTL(ep);
volatile unsigned long *eptsiz = dir_in ? &DIEPTSIZ(ep) : &DOEPTSIZ(ep); volatile unsigned long *eptsiz = dir_in ? &DIEPTSIZ(ep) : &DOEPTSIZ(ep);
@ -690,20 +745,21 @@ static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocki
#define DEPTSIZ *eptsiz #define DEPTSIZ *eptsiz
#define DEPDMA *epdma #define DEPDMA *epdma
if(DEPCTL & DEPCTL_stall)
{
logf("usb-drv: cannot receive/send on a stalled endpoint");
return -1;
}
if(endpoint->busy) if(endpoint->busy)
logf("usb-drv: EP%d %s is already busy", ep, dir_in ? "IN" : "OUT"); _logf("usb-drv: EP%d %s is already busy", ep, dir_in ? "IN" : "OUT");
endpoint->busy = true; endpoint->busy = true;
endpoint->len = len; endpoint->len = len;
endpoint->wait = blocking; endpoint->wait = blocking;
endpoint->status = true;
int mps = 64; DEPCTL &= ~DEPCTL_stall;
DEPCTL |= DEPCTL_usbactep;
if(ep != 0)
_logf("usb-drv: depctl=%lx", DEPCTL);
int mps = usb_drv_mps_by_type(extract(DEPCTL, eptype));
int nb_packets = (len + mps - 1) / mps; int nb_packets = (len + mps - 1) / mps;
if(len == 0) if(len == 0)
@ -713,14 +769,17 @@ static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocki
} }
else else
{ {
clean_dcache_range(ptr, len);
DEPDMA = (unsigned long)AS3525_PHYSICAL_ADDR(ptr); DEPDMA = (unsigned long)AS3525_PHYSICAL_ADDR(ptr);
DEPTSIZ = (nb_packets << DEPTSIZ_pkcnt_bitp) | len; DEPTSIZ = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
clean_dcache_range(ptr, len);
} }
logf("pkt=%d dma=%lx", nb_packets, DEPDMA); logf("pkt=%d dma=%lx", nb_packets, DEPDMA);
DEPCTL |= DEPCTL_epena | DEPCTL_cnak | DEPCTL_usbactep; DEPCTL |= DEPCTL_epena | DEPCTL_cnak;
if(ep != 0)
_logf("usb-drv: depctl=%lx", DEPCTL);
if(blocking) if(blocking)
wakeup_wait(&endpoint->complete, TIMEOUT_BLOCK); wakeup_wait(&endpoint->complete, TIMEOUT_BLOCK);
@ -751,31 +810,33 @@ int usb_drv_send_nonblocking(int ep, void *ptr, int len)
void usb_drv_set_test_mode(int mode) void usb_drv_set_test_mode(int mode)
{ {
(void) mode; /* there is a perfect matching between usb test mode code
* and the register field value */
DCTL = (DCTL & ~bitm(DCTL, tstctl)) | (mode << DCTL_tstctl_bitp);
} }
void usb_drv_set_address(int address) void usb_drv_set_address(int address)
{ {
/* ignore it if addres is already set */ (void) address;
if(extract(DCFG, devadr) == 0)
{
logf("usb-drv: set address %x", address);
DCFG = (DCFG & ~bitm(DCFG, devadr)) | (address << DCFG_devadr_bitp);
}
} }
void usb_drv_stall(int ep, bool stall, bool in) void usb_drv_stall(int ep, bool stall, bool in)
{ {
(void) ep;
(void) stall;
(void) in;
logf("usb-drv: %sstall EP%d %s", stall ? "" : "un", ep, in ? "IN" : "OUT"); logf("usb-drv: %sstall EP%d %s", stall ? "" : "un", ep, in ? "IN" : "OUT");
if(in)
{
if(stall) DIEPCTL(ep) |= DEPCTL_stall;
else DIEPCTL(ep) &= ~DEPCTL_stall;
}
else
{
if(stall) DOEPCTL(ep) |= DEPCTL_stall;
else DOEPCTL(ep) &= ~DEPCTL_stall;
}
} }
bool usb_drv_stalled(int ep, bool in) bool usb_drv_stalled(int ep, bool in)
{ {
(void) ep; return (in ? DIEPCTL(ep) : DOEPCTL(ep)) & DEPCTL_stall ? true : false;
(void) in;
return true;
} }