diff --git a/firmware/export/logf.h b/firmware/export/logf.h index b57ae91..48cfae8 100644 --- a/firmware/export/logf.h +++ b/firmware/export/logf.h @@ -29,7 +29,7 @@ #ifndef __PCTOOL__ -#define MAX_LOGF_SIZE 16384 +#define MAX_LOGF_SIZE 163840 extern unsigned char logfbuffer[MAX_LOGF_SIZE]; extern int logfindex; diff --git a/firmware/export/rk27xx.h b/firmware/export/rk27xx.h index 3ca2bc0..0a56536 100644 --- a/firmware/export/rk27xx.h +++ b/firmware/export/rk27xx.h @@ -8,7 +8,8 @@ #define FLASH_BANK1 0x11000000 #define USB_NUM_ENDPOINTS 16 -#define USB_DEVBSS_ATTR +/* cache aligned */ +#define USB_DEVBSS_ATTR __attribute__((aligned(32))) /* Timers */ #define APB0_TIMER (ARM_BUS0_BASE + 0x00000000) @@ -731,6 +732,7 @@ #define RXVOIDINTEN (1<<5) #define RXERRINTEN (1<<6) #define RXACKINTEN (1<<7) +#define RXCFINTE (1<<12) /* bits 31:8 reserved for EP0 */ /* bits 31:14 reserved for others */ @@ -753,6 +755,7 @@ #define TXERRINTEN (1<<5) #define TXACKINTEN (1<<6) #define TXDMADNEN (1<<7) /* reserved for EP0 */ +#define TXCFINTE (1<<12) /* bits 31:8 reserved */ /* TXnBUF bits */ diff --git a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c index 810c793..4795e77 100644 --- a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c +++ b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c @@ -170,48 +170,112 @@ static void ctr_read(void) RX0DMACTLO = DMA_START; /* start DMA */ } -static void blk_write(int ep) +static void blk_write(int ep_num) { - int ep_num = EP_NUM(ep); - int max = usb_drv_port_speed() ? 512 : 64; - int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt; unsigned int timeout = current_tick + HZ/10; - + int max = usb_drv_port_speed() ? 512 : 64; + int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt; + while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */ { if(TIME_AFTER(current_tick, timeout)) break; } - + BIN_TXSTAT(ep_num) = xfer_size; /* size */ BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */ BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */ BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */ - + /* Decrement by max packet size is intentional. - * This way if we have final packet short one we will get negative len - * after transfer, which in turn indicates we *don't* need to send - * zero length packet. If the final packet is max sized packet we will - * get zero len after transfer which indicates we need to send - * zero length packet to signal host end of the transfer. - */ + * This way if we have final packet short one we will get negative len + * after transfer, which in turn indicates we *don't* need to send + * zero length packet. If the final packet is max sized packet we will + * get zero len after transfer which indicates we need to send + * zero length packet to signal host end of the transfer. + */ endpoints[ep_num].cnt -= max; endpoints[ep_num].buf += xfer_size; } -static void blk_read(int ep) +static void blk_write_int(int ep_num) { - int ep_num = EP_NUM(ep); - int xfer_size = BOUT_RXSTAT(ep_num) & 0xffff; - - /* clear NAK bit */ - BOUT_RXCON(ep_num) &= ~RXNAK; - - endpoints[ep_num].cnt -= xfer_size; - endpoints[ep_num].buf += xfer_size; - - BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; - BOUT_DMAOUTCTL(ep_num) = DMA_START; + uint32_t txstat = BIN_TXSTAT(ep_num); + struct endpoint_t *endp = &endpoints[ep_num]; + + if(txstat & TXCFINT) + { + logf("blk_write:cf(0x%x), %ld", ep_num, current_tick); + /* bit cleared by read */ + usb_drv_stall(ep_num, false, true); + } + + if (txstat & TXACK) /* check TxACK flag */ + { + if (endp->cnt >= 0) + { + logf("blk_write:ack(0x%x), %ld", ep_num, current_tick); + /* we still have data to send (or ZLP) */ + blk_write(ep_num); + } + else + { + logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_IN, 0, 0x%x), %ld", ep_num, endp->len, current_tick); + /* final ack received */ + usb_core_transfer_complete(ep_num, /* ep */ + USB_DIR_IN, /* dir */ + 0, /* status */ + endp->len); /* length */ + + /* release semaphore for blocking transfer */ + if (endp->block) + { + logf("udc_intr: ep=0x%x, semaphore_release(), %ld", ep_num, current_tick); + semaphore_release(&endp->complete); + } + } + } +} + +static void blk_read_int(int ep_num) +{ + uint32_t rxstat = BOUT_RXSTAT(ep_num); + int xfer_size = rxstat & 0xffff; + int max = usb_drv_port_speed() ? 512 : 64; + struct endpoint_t *endp = &endpoints[ep_num]; + + if(rxstat & RXCFINT) + { + logf("blk_read:cf(0x%x), %ld", ep_num, current_tick); + /* bit cleared by read */ + usb_drv_stall(ep_num, false, false); + } + + if((rxstat & RXACK) && endp->cnt > 0) + { + logf("blk_read:ack(0x%x,0x%x), %ld", ep_num, xfer_size, current_tick); + /* clear NAK bit */ + BOUT_RXCON(ep_num) &= ~RXNAK; + + endp->cnt -= xfer_size; + endp->buf += xfer_size; + + /* if the transfer was short or if the total count is zero, transfer is complete */ + if (endp->cnt == 0 || xfer_size < max) + { + logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_OUT, 0, 0x%x), %ld", ep_num, endp->len, current_tick); + usb_core_transfer_complete(ep_num, /* ep */ + USB_DIR_OUT, /* dir */ + 0, /* status */ + endp->len - endp->cnt); /* length */ + endp->cnt = 0; + } + else + { + BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endp->buf; + BOUT_DMAOUTCTL(ep_num) = DMA_START; + } + } } static void int_write(int ep) @@ -387,17 +451,20 @@ void INT_UDC(void) if (intsrc & CONN_INTR) /* usb connect */ { -// if (DEV_INFO & VBUS_STS) -// { + if (DEV_INFO & VBUS_STS) + { udc_phy_reset(); udelay(10000); udc_soft_connect(); udc_conn = 1; usb_status_event(USB_INSERTED); -// } -// else -// udc_conn = 0; + } + else + { + udc_conn = 0; + usb_status_event(USB_EXTRACTED); + } } /* TODO this needs rework */ @@ -414,60 +481,10 @@ void INT_UDC(void) { case USB_ENDPOINT_XFER_BULK: if (ep->dir == DIR_OUT) - { /* bulk out */ - rxstat = BOUT_RXSTAT(ep_num); - - /* TODO handle errors */ - if (rxstat & RXACK) /* RxACK */ - { - if (ep->cnt > 0) - { - logf("udc_intr: blk_read(0x%x), %ld", ep_num, current_tick); - blk_read(ep_num); - } - else - { - logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_OUT, 0, 0x%x), %ld", ep_num, ep->len, current_tick); - usb_core_transfer_complete(ep_num, /* ep */ - USB_DIR_OUT, /* dir */ - 0, /* status */ - ep->len); /* length */ - } - } - } + blk_read_int(ep_num); else - { - /* bulk in */ - txstat = BIN_TXSTAT(ep_num); - - /* TODO handle errors */ - if (txstat & TXACK) /* check TxACK flag */ - { - if (ep->cnt >= 0) - { - logf("udc_intr: blk_write(0x%x), %ld", ep_num, current_tick); - /* we still have data to send (or ZLP) */ - blk_write(ep_num); - } - else - { - logf("udc_intr: usb_core_transfer_complete(0x%x, USB_DIR_IN, 0, 0x%x), %ld", ep_num, ep->len, current_tick); - /* final ack received */ - usb_core_transfer_complete(ep_num, /* ep */ - USB_DIR_IN, /* dir */ - 0, /* status */ - ep->len); /* length */ - - /* release semaphore for blocking transfer */ - if (ep->block) - { - logf("udc_intr: ep=0x%x, semaphore_release(), %ld", ep_num, current_tick); - semaphore_release(&ep->complete); - } - } - } - } + blk_write_int(ep_num); break; case USB_ENDPOINT_XFER_INT: @@ -534,15 +551,15 @@ int usb_drv_request_endpoint(int type, int dir) if (ep_num%3 == 0) /* IIN 3, 6, 9, 12, 15 */ { - IIN_TXCON(ep_num) = (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */ + IIN_TXCON(ep_num) = (ep_num<<8)|TXEPEN|TXNAK|TXACKINTEN|TXCFINTE; } else if (ep_num%3 == 1) /* BOUT 1, 4, 7, 10, 13 */ { - BOUT_RXCON(ep_num) = (ep_num<<8)|RXEPEN|RXNAK; /* ep_num, NAK, enable */ + BOUT_RXCON(ep_num) = (ep_num<<8)|RXEPEN|RXNAK|RXACKINTEN|RXCFINTE; } else if (ep_num%3 == 2) /* BIN 2, 5, 8, 11, 14 */ { - BIN_TXCON(ep_num) = (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */ + BIN_TXCON(ep_num) = (ep_num<<8)|TXEPEN|TXNAK|TXACKINTEN|TXCFINTE; } /* enable interrupt from this endpoint */ @@ -586,6 +603,12 @@ static int _usb_drv_send(int endpoint, void *ptr, int length, bool block) struct endpoint_t *ep; int ep_num = EP_NUM(endpoint); + /* for send transfers, make sure the data is committed + * for recv, I don't know how to simply discard the cache so commit and + * pray that no-one will read it in between */ + //commit_discard_dcache_range(ptr, length); + commit_discard_idcache(); + logf("_usb_drv_send: endpt=0x%x, len=0x%x, block=%d", endpoint, length, block); if (ep_num == 0) ep = &ctrlep[DIR_IN]; @@ -602,7 +625,7 @@ static int _usb_drv_send(int endpoint, void *ptr, int length, bool block) switch (ep->type) { - case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_CONTROL: ctr_write(); break; @@ -724,6 +747,7 @@ bool usb_drv_stalled(int endpoint, bool in) void usb_drv_stall(int endpoint, bool stall, bool in) { int ep_num = EP_NUM(endpoint); + logf("usb_drv: %sstall EP%d %s", stall ? "": "un", ep_num, in ? "IN" : "OUT"); switch (endpoints[ep_num].type) { diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 8dc5969..0703036 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -686,6 +686,16 @@ static void usb_core_do_set_config(uint8_t config) #endif } +static void usb_core_do_clear_feature(int recip, int recip_nr, int feature) +{ + logf("usb_core: CLEAR FEATURE (%d,%d,%d)", recip, recip_nr, feature); + if(recip == USB_RECIP_ENDPOINT) + { + if(feature == USB_ENDPOINT_HALT) + usb_drv_stall(EP_NUM(recip_nr), false, EP_DIR(recip_nr)); + } +} + static void request_handler_device(struct usb_ctrlrequest* req) { switch(req->bRequest) { @@ -808,12 +818,11 @@ static void request_handler_endpoint_standard(struct usb_ctrlrequest* req) { switch (req->bRequest) { case USB_REQ_CLEAR_FEATURE: - if(req->wValue == USB_ENDPOINT_HALT) - usb_drv_stall(EP_NUM(req->wIndex), false, EP_DIR(req->wIndex)); - + usb_core_do_clear_feature(USB_RECIP_ENDPOINT, req->wIndex, req->wValue); usb_drv_send(EP_CONTROL, NULL, 0); break; case USB_REQ_SET_FEATURE: + logf("usb_core: SET FEATURE (%d)", req->wValue); if(req->wValue == USB_ENDPOINT_HALT) usb_drv_stall(EP_NUM(req->wIndex), true, EP_DIR(req->wIndex)); diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index dbcf4a2..d2b2a5e 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c @@ -753,6 +753,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) unsigned int block_size_mult = 1; if(letoh32(cbw->signature) != CBW_SIGNATURE) { + logf("ums: bad cbw signature (%x)", cbw->signature); usb_drv_stall(ep_in, true,true); usb_drv_stall(ep_out, true,false); return; @@ -1151,6 +1152,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) default: logf("scsi unknown cmd %x",cbw->command_block[0x0]); + usb_drv_stall(ep_in, true,true); send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; cur_sense_data.asc=ASC_INVALID_COMMAND;