refactor urb, add ep & hport in urb to make hardware pipe more reusable

This commit is contained in:
sakumisu 2023-11-15 22:08:26 +08:00
parent c1435548e7
commit 5bbe2a97f2
26 changed files with 1072 additions and 1172 deletions

View File

@ -89,7 +89,7 @@ freq_found:
setup->wIndex = intf;
setup->wLength = 0;
ret = usbh_control_transfer(audio_class->hport->ep0, setup, NULL);
ret = usbh_control_transfer(audio_class->hport, setup, NULL);
if (ret < 0) {
return ret;
}
@ -103,7 +103,7 @@ freq_found:
setup->wLength = 3;
memcpy(g_audio_buf, &samp_freq, 3);
ret = usbh_control_transfer(audio_class->hport->ep0, setup, g_audio_buf);
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
if (ret < 0) {
return ret;
}
@ -112,10 +112,10 @@ freq_found:
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
if (ep_desc->bEndpointAddress & 0x80) {
audio_class->isoin_mps = mps * (mult + 1);
usbh_hport_activate_epx(&audio_class->isoin, audio_class->hport, ep_desc);
USBH_EP_INIT(audio_class->isoin, ep_desc);
} else {
audio_class->isoout_mps = mps * (mult + 1);
usbh_hport_activate_epx(&audio_class->isoout, audio_class->hport, ep_desc);
USBH_EP_INIT(audio_class->isoout, ep_desc);
}
USB_LOG_INFO("Open audio module :%s, altsetting: %u\r\n", name, altsetting);
@ -147,12 +147,10 @@ int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
if (audio_class->isoin) {
usbh_pipe_free(audio_class->isoin);
audio_class->isoin = NULL;
}
} else {
if (audio_class->isoout) {
usbh_pipe_free(audio_class->isoout);
audio_class->isoout = NULL;
}
}
@ -163,7 +161,7 @@ int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
setup->wIndex = intf;
setup->wLength = 0;
ret = usbh_control_transfer(audio_class->hport->ep0, setup, NULL);
ret = usbh_control_transfer(audio_class->hport, setup, NULL);
return ret;
}
@ -196,7 +194,7 @@ int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint
volume_hex = -0xDB00 / 100 * volume + 0xdb00;
memcpy(g_audio_buf, &volume_hex, 2);
ret = usbh_control_transfer(audio_class->hport->ep0, setup, NULL);
ret = usbh_control_transfer(audio_class->hport, setup, NULL);
return ret;
}
@ -226,7 +224,7 @@ int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_
setup->wLength = 1;
memcpy(g_audio_buf, &mute, 1);
ret = usbh_control_transfer(audio_class->hport->ep0, setup, g_audio_buf);
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
return ret;
}
@ -416,11 +414,9 @@ static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (audio_class) {
if (audio_class->isoin) {
usbh_pipe_free(audio_class->isoin);
}
if (audio_class->isoout) {
usbh_pipe_free(audio_class->isoout);
}
if (hport->config.intf[intf].devname[0] != '\0') {

View File

@ -40,11 +40,11 @@ struct usbh_audio_module {
struct usbh_audio {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *isoin; /* ISO IN endpoint */
struct usb_endpoint_descriptor *isoout; /* ISO OUT endpoint */
uint8_t ctrl_intf; /* interface number */
uint8_t minor;
usbh_pipe_t isoin; /* ISO IN endpoint */
usbh_pipe_t isoout; /* ISO OUT endpoint */
uint16_t isoin_mps;
uint16_t isoout_mps;
bool is_opened;

View File

@ -19,9 +19,9 @@ static struct usbd_endpoint cdc_ecm_ep_data[3];
#define CDC_ECM_MAX_PACKET_SIZE 64
#endif
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
volatile uint8_t *g_cdc_ecm_rx_data_buffer = NULL;
volatile uint32_t g_cdc_ecm_rx_data_length = 0;

View File

@ -50,7 +50,7 @@ int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_
memcpy((uint8_t *)&g_cdc_line_coding, line_coding, sizeof(struct cdc_line_coding));
return usbh_control_transfer(cdc_acm_class->hport->ep0, setup, (uint8_t *)&g_cdc_line_coding);
return usbh_control_transfer(cdc_acm_class->hport, setup, (uint8_t *)&g_cdc_line_coding);
}
int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding)
@ -64,7 +64,7 @@ int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_
setup->wIndex = cdc_acm_class->ctrl_intf;
setup->wLength = 7;
ret = usbh_control_transfer(cdc_acm_class->hport->ep0, setup, (uint8_t *)&g_cdc_line_coding);
ret = usbh_control_transfer(cdc_acm_class->hport, setup, (uint8_t *)&g_cdc_line_coding);
if (ret < 0) {
return ret;
}
@ -85,7 +85,7 @@ int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bo
cdc_acm_class->dtr = dtr;
cdc_acm_class->rts = rts;
return usbh_control_transfer(cdc_acm_class->hport->ep0, setup, NULL);
return usbh_control_transfer(cdc_acm_class->hport, setup, NULL);
}
static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
@ -124,15 +124,15 @@ static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
usbh_hport_activate_epx(&cdc_acm_class->intin, hport, ep_desc);
USBH_EP_INIT(cdc_acm_class->intin, ep_desc);
#endif
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
usbh_hport_activate_epx(&cdc_acm_class->bulkin, hport, ep_desc);
USBH_EP_INIT(cdc_acm_class->bulkin, ep_desc);
} else {
usbh_hport_activate_epx(&cdc_acm_class->bulkout, hport, ep_desc);
USBH_EP_INIT(cdc_acm_class->bulkout, ep_desc);
}
}
@ -152,13 +152,19 @@ static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (cdc_acm_class) {
if (cdc_acm_class->bulkin) {
usbh_pipe_free(cdc_acm_class->bulkin);
usbh_kill_urb(&cdc_acm_class->bulkin_urb);
}
if (cdc_acm_class->bulkout) {
usbh_pipe_free(cdc_acm_class->bulkout);
usbh_kill_urb(&cdc_acm_class->bulkout_urb);
}
#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
if (cdc_acm_class->intin) {
usbh_kill_urb(&cdc_acm_class->intin_urb);
}
#endif
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister CDC ACM Class:%s\r\n", hport->config.intf[intf].devname);
usbh_cdc_acm_stop(cdc_acm_class);
@ -170,6 +176,32 @@ static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
int usbh_cdc_acm_bulk_in_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &cdc_acm_class->bulkin_urb;
usbh_bulk_urb_fill(urb, cdc_acm_class->hport, cdc_acm_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
int usbh_cdc_acm_bulk_out_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &cdc_acm_class->bulkout_urb;
usbh_bulk_urb_fill(urb, cdc_acm_class->hport, cdc_acm_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
static int usbh_cdc_data_connect(struct usbh_hubport *hport, uint8_t intf)
{
return 0;

View File

@ -10,6 +10,12 @@
struct usbh_cdc_acm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint (optional) */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
struct usbh_urb intin_urb;
struct cdc_line_coding linecoding;
uint8_t ctrl_intf; /* Control interface number */
@ -17,11 +23,6 @@ struct usbh_cdc_acm {
bool dtr;
bool rts;
uint8_t minor;
usbh_pipe_t bulkin; /* Bulk IN endpoint */
usbh_pipe_t bulkout; /* Bulk OUT endpoint */
#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
usbh_pipe_t intin; /* Interrupt IN endpoint (optional) */
#endif
};
#ifdef __cplusplus
@ -32,6 +33,9 @@ int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_
int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding);
int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bool rts);
int usbh_cdc_acm_bulk_in_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_cdc_acm_bulk_out_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class);
void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class);

View File

@ -20,9 +20,9 @@
#define CONFIG_USBHOST_CDC_ECM_PKT_FILTER 0x000C
#define CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE 1514U
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[16];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[16];
static struct usbh_cdc_ecm g_cdc_ecm_class;
@ -36,21 +36,25 @@ static int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class
setup->wIndex = cdc_ecm_class->ctrl_intf;
setup->wLength = 0;
return usbh_control_transfer(cdc_ecm_class->hport->ep0, setup, NULL);
return usbh_control_transfer(cdc_ecm_class->hport, setup, NULL);
}
int usbh_cdc_ecm_get_notification(struct usbh_cdc_ecm *cdc_ecm_class)
{
int ret;
usbh_int_urb_fill(&cdc_ecm_class->intin_urb, cdc_ecm_class->intin, g_cdc_ecm_inttx_buffer, 16, USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_int_urb_fill(&cdc_ecm_class->intin_urb, cdc_ecm_class->hport, cdc_ecm_class->intin, g_cdc_ecm_inttx_buffer, 16, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&cdc_ecm_class->intin_urb);
if (ret < 0) {
return ret;
}
if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION) {
cdc_ecm_class->connect_status = g_cdc_ecm_inttx_buffer[2];
if (g_cdc_ecm_inttx_buffer[2] == CDC_ECM_NET_CONNECTED) {
cdc_ecm_class->connect_status = true;
} else {
cdc_ecm_class->connect_status = false;
}
} else if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE) {
memcpy(cdc_ecm_class->speed, &g_cdc_ecm_inttx_buffer[8], 8);
}
@ -69,6 +73,8 @@ static int usbh_cdc_ecm_connect(struct usbh_hubport *hport, uint8_t intf)
struct usbh_cdc_ecm *cdc_ecm_class = &g_cdc_ecm_class;
memset(cdc_ecm_class, 0, sizeof(struct usbh_cdc_ecm));
cdc_ecm_class->hport = hport;
cdc_ecm_class->ctrl_intf = intf;
cdc_ecm_class->data_intf = intf + 1;
@ -105,7 +111,7 @@ get_mac:
return -1;
}
memset(mac_buffer, 0, 8);
memset(mac_buffer, 0, 12);
ret = usbh_get_string_desc(cdc_ecm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
if (ret < 0) {
return ret;
@ -137,7 +143,7 @@ get_mac:
/* enable int ep */
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
usbh_hport_activate_epx(&cdc_ecm_class->intin, hport, ep_desc);
USBH_EP_INIT(cdc_ecm_class->intin, ep_desc);
if (hport->config.intf[intf + 1].altsetting_num > 1) {
altsetting = hport->config.intf[intf + 1].altsetting_num - 1;
@ -146,9 +152,9 @@ get_mac:
ep_desc = &hport->config.intf[intf + 1].altsetting[altsetting].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
usbh_hport_activate_epx(&cdc_ecm_class->bulkin, hport, ep_desc);
USBH_EP_INIT(cdc_ecm_class->bulkin, ep_desc);
} else {
usbh_hport_activate_epx(&cdc_ecm_class->bulkout, hport, ep_desc);
USBH_EP_INIT(cdc_ecm_class->bulkout, ep_desc);
}
}
@ -159,9 +165,9 @@ get_mac:
ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
usbh_hport_activate_epx(&cdc_ecm_class->bulkin, hport, ep_desc);
USBH_EP_INIT(cdc_ecm_class->bulkin, ep_desc);
} else {
usbh_hport_activate_epx(&cdc_ecm_class->bulkout, hport, ep_desc);
USBH_EP_INIT(cdc_ecm_class->bulkout, ep_desc);
}
}
}
@ -194,15 +200,15 @@ static int usbh_cdc_ecm_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (cdc_ecm_class) {
if (cdc_ecm_class->bulkin) {
usbh_pipe_free(cdc_ecm_class->bulkin);
usbh_kill_urb(&cdc_ecm_class->bulkin_urb);
}
if (cdc_ecm_class->bulkout) {
usbh_pipe_free(cdc_ecm_class->bulkout);
usbh_kill_urb(&cdc_ecm_class->bulkout_urb);
}
if (cdc_ecm_class->intin) {
usbh_pipe_free(cdc_ecm_class->intin);
usbh_kill_urb(&cdc_ecm_class->intin_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
@ -223,30 +229,25 @@ static void usbh_cdc_ecm_rx_thread(void *argument)
err_t err;
struct pbuf *p;
struct netif *netif = (struct netif *)argument;
uint16_t ep_mps;
// clang-format off
find_class:
// clang-format on
g_cdc_ecm_class.connect_status = false;
while (usbh_find_class_instance("/dev/cdc_ether") == NULL) {
usb_osal_msleep(1000);
}
while (g_cdc_ecm_class.connect_status == CDC_ECM_NET_DISCONNECTED) {
while (g_cdc_ecm_class.connect_status == false) {
ret = usbh_cdc_ecm_get_notification(&g_cdc_ecm_class);
if (ret < 0) {
goto find_class;
}
}
if (g_cdc_ecm_class.hport->speed == USB_SPEED_FULL) {
ep_mps = 64;
} else {
ep_mps = 512;
}
g_cdc_ecm_rx_length = 0;
while (1) {
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.bulkin, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_length], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkin, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_length], USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize), USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ecm_class.bulkin_urb);
if (ret < 0) {
goto find_class;
@ -254,13 +255,14 @@ find_class:
g_cdc_ecm_rx_length += g_cdc_ecm_class.bulkin_urb.actual_length;
if (g_cdc_ecm_rx_length % ep_mps) {
if (g_cdc_ecm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize)) {
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_length);
p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_length, PBUF_POOL);
if (p != NULL) {
memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
g_cdc_ecm_rx_length = 0;
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
@ -280,7 +282,7 @@ err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
struct pbuf *q;
uint8_t *buffer = g_cdc_ecm_tx_buffer;
if (g_cdc_ecm_class.connect_status == CDC_ECM_NET_DISCONNECTED) {
if (g_cdc_ecm_class.connect_status == false) {
return ERR_BUF;
}
@ -291,7 +293,7 @@ err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
USB_LOG_DBG("txlen:%d\r\n", p->tot_len);
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, p->tot_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, p->tot_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
if (ret < 0) {
return ERR_BUF;

View File

@ -13,20 +13,21 @@
struct usbh_cdc_ecm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* Interrupt IN endpoint */
struct usbh_urb bulkout_urb; /* Bulk out endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN endpoint */
struct usbh_urb intin_urb; /* Interrupt IN endpoint */
uint8_t ctrl_intf; /* Control interface number */
uint8_t data_intf; /* Data interface number */
uint8_t minor;
uint8_t mac[6];
uint32_t max_segment_size;
uint8_t connect_status;
bool connect_status;
uint16_t max_segment_size;
uint32_t speed[2];
usbh_pipe_t bulkin; /* Bulk IN endpoint */
usbh_pipe_t bulkout; /* Bulk OUT endpoint */
usbh_pipe_t intin; /* Interrupt IN endpoint */
struct usbh_urb bulkout_urb;
struct usbh_urb bulkin_urb;
struct usbh_urb intin_urb;
ip_addr_t ipaddr;
ip_addr_t netmask;

View File

@ -49,7 +49,7 @@ static int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *b
setup->wIndex = hid_class->intf;
setup->wLength = 128;
ret = usbh_control_transfer(hid_class->hport->ep0, setup, g_hid_buf);
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf);
if (ret < 0) {
return ret;
}
@ -67,7 +67,7 @@ int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t dur
setup->wIndex = hid_class->intf;
setup->wLength = 0;
return usbh_control_transfer(hid_class->hport->ep0, setup, NULL);
return usbh_control_transfer(hid_class->hport, setup, NULL);
}
int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
@ -81,7 +81,7 @@ int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
setup->wIndex = hid_class->intf;
setup->wLength = 1;
ret = usbh_control_transfer(hid_class->hport->ep0, setup, g_hid_buf);
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf);
if (ret < 0) {
return ret;
}
@ -99,7 +99,7 @@ int usbh_hid_set_protocol(struct usbh_hid *hid_class, uint8_t protocol)
setup->wIndex = 0;
setup->wLength = 0;
return usbh_control_transfer(hid_class->hport->ep0, setup, NULL);
return usbh_control_transfer(hid_class->hport, setup, NULL);
}
int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
@ -137,9 +137,9 @@ int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
usbh_hport_activate_epx(&hid_class->intin, hport, ep_desc);
USBH_EP_INIT(hid_class->intin, ep_desc);
} else {
usbh_hport_activate_epx(&hid_class->intout, hport, ep_desc);
USBH_EP_INIT(hid_class->intout, ep_desc);
}
}
@ -159,11 +159,11 @@ int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (hid_class) {
if (hid_class->intin) {
usbh_pipe_free(hid_class->intin);
usbh_kill_urb(&hid_class->intin_urb);
}
if (hid_class->intout) {
usbh_pipe_free(hid_class->intout);
usbh_kill_urb(&hid_class->intout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {

View File

@ -10,12 +10,14 @@
struct usbh_hid {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint */
struct usb_endpoint_descriptor *intout; /* INTR OUT endpoint */
struct usbh_urb intin_urb; /* INTR IN urb */
struct usbh_urb intout_urb; /* INTR OUT urb */
uint8_t report_desc[128];
uint8_t intf; /* interface number */
uint8_t minor;
usbh_pipe_t intin; /* INTR IN endpoint */
usbh_pipe_t intout; /* INTR OUT endpoint */
};
#ifdef __cplusplus

View File

@ -5,14 +5,14 @@
*/
#include "usbh_hub.h"
#define DEV_FORMAT "/dev/hub%d"
#define DEV_FORMAT "/dev/hub%d"
#define HUB_DEBOUNCE_TIMEOUT 1500
#define HUB_DEBOUNCE_STEP 25
#define HUB_DEBOUNCE_STABLE 100
#define DELAY_TIME_AFTER_RESET 200
#define EXTHUB_FIRST_INDEX 2
#define EXTHUB_FIRST_INDEX 2
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[32];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_intbuf[CONFIG_USBHOST_MAX_EXTHUBS + 1][CONFIG_USB_ALIGN_SIZE];
@ -24,10 +24,8 @@ usb_osal_mq_t hub_mq;
struct usbh_hub roothub;
extern int usbh_hport_activate_ep0(struct usbh_hubport *hport);
extern int usbh_hport_deactivate_ep0(struct usbh_hubport *hport);
extern int usbh_free_devaddr(struct usbh_hubport *hport);
extern int usbh_enumerate(struct usbh_hubport *hport);
static void usbh_hub_thread_wakeup(struct usbh_hub *hub);
static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
@ -101,7 +99,7 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
setup->wIndex = 0;
setup->wLength = USB_SIZEOF_HUB_DESC;
ret = usbh_control_transfer(hub->parent->ep0, setup, g_hub_buf);
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf);
if (ret < 0) {
return ret;
}
@ -122,7 +120,7 @@ static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
setup->wIndex = 0;
setup->wLength = 2;
ret = usbh_control_transfer(hub->parent->ep0, setup, g_hub_buf);
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf);
if (ret < 0) {
return ret;
}
@ -145,7 +143,7 @@ static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct h
setup->wIndex = port;
setup->wLength = 4;
ret = usbh_control_transfer(hub->parent->ep0, setup, g_hub_buf);
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf);
if (ret < 0) {
return ret;
}
@ -165,7 +163,7 @@ static int _usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t fea
setup->wIndex = port;
setup->wLength = 0;
return usbh_control_transfer(hub->parent->ep0, setup, NULL);
return usbh_control_transfer(hub->parent, setup, NULL);
}
static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
@ -180,7 +178,7 @@ static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t f
setup->wIndex = port;
setup->wLength = 0;
return usbh_control_transfer(hub->parent->ep0, setup, NULL);
return usbh_control_transfer(hub->parent, setup, NULL);
}
static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
@ -195,7 +193,7 @@ static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
setup->wIndex = 0;
setup->wLength = 0;
return usbh_control_transfer(hub->parent->ep0, setup, NULL);
return usbh_control_transfer(hub->parent, setup, NULL);
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
@ -294,13 +292,31 @@ static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
}
}
static void usbh_hub_thread_wakeup(struct usbh_hub *hub)
{
usb_osal_mq_send(hub_mq, (uintptr_t)hub);
}
static void usbh_hubport_release(struct usbh_hubport *child)
{
if (child->connected) {
child->connected = false;
usbh_free_devaddr(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(child, i);
}
}
child->config.config_desc.bNumInterfaces = 0;
}
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
static void hub_int_complete_callback(void *arg, int nbytes)
{
struct usbh_hub *hub = (struct usbh_hub *)arg;
if (nbytes > 0)
{
if (nbytes > 0) {
usbh_hub_thread_wakeup(hub);
}
}
@ -336,7 +352,7 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
usbh_hport_activate_epx(&hub->intin, hport, ep_desc);
USBH_EP_INIT(hub->intin, ep_desc);
} else {
return -1;
}
@ -376,7 +392,7 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname);
hub->int_buffer = g_hub_intbuf[hub->index - 1];
usbh_int_urb_fill(&hub->intin_urb, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
usbh_int_urb_fill(&hub->intin_urb, hub->parent, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
usbh_submit_urb(&hub->intin_urb);
return 0;
}
@ -390,19 +406,12 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (hub) {
if (hub->intin) {
usbh_pipe_free(hub->intin);
usbh_kill_urb(&hub->intin_urb);
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
child = &hub->child[port];
usbh_hport_deactivate_ep0(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(child, i);
}
}
child->config.config_desc.bNumInterfaces = 0;
usbh_hubport_release(child);
child->parent = NULL;
}
@ -417,27 +426,10 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
}
#endif
static void usbh_hubport_release(struct usbh_hubport *child)
{
if (child->connected) {
child->connected = false;
usbh_hport_deactivate_ep0(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(child, i);
}
}
child->config.config_desc.bNumInterfaces = 0;
}
}
static void usbh_hubport_enumerate_thread(void *argument)
{
struct usbh_hubport *child = (struct usbh_hubport *)argument;
/* Configure EP0 with the default maximum packet size */
usbh_hport_activate_ep0(child);
if (usbh_enumerate(child) < 0) {
/** release child sources */
usbh_hubport_release(child);
@ -662,11 +654,6 @@ static void usbh_roothub_register(void)
usbh_hub_register(&roothub);
}
static void usbh_hub_thread_wakeup(struct usbh_hub *hub)
{
usb_osal_mq_send(hub_mq, (uintptr_t)hub);
}
void usbh_roothub_thread_wakeup(uint8_t port)
{
roothub.int_buffer = g_hub_intbuf[roothub.index - 1];

View File

@ -50,7 +50,7 @@ static int usbh_msc_get_maxlun(struct usbh_msc *msc_class, uint8_t *buffer)
setup->wIndex = msc_class->intf;
setup->wLength = 1;
return usbh_control_transfer(msc_class->hport->ep0, setup, buffer);
return usbh_control_transfer(msc_class->hport, setup, buffer);
}
static void usbh_msc_cbw_dump(struct CBW *cbw)
@ -87,9 +87,8 @@ static inline int usbh_msc_bulk_in_transfer(struct usbh_msc *msc_class, uint8_t
{
int ret;
struct usbh_urb *urb = &msc_class->bulkin_urb;
memset(urb, 0, sizeof(struct usbh_urb));
usbh_bulk_urb_fill(urb, msc_class->bulkin, buffer, buflen, timeout, NULL, NULL);
usbh_bulk_urb_fill(urb, msc_class->hport, msc_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
@ -101,9 +100,8 @@ static inline int usbh_msc_bulk_out_transfer(struct usbh_msc *msc_class, uint8_t
{
int ret;
struct usbh_urb *urb = &msc_class->bulkout_urb;
memset(urb, 0, sizeof(struct usbh_urb));
usbh_bulk_urb_fill(urb, msc_class->bulkout, buffer, buflen, timeout, NULL, NULL);
usbh_bulk_urb_fill(urb, msc_class->hport, msc_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
@ -111,7 +109,7 @@ static inline int usbh_msc_bulk_out_transfer(struct usbh_msc *msc_class, uint8_t
return ret;
}
int usbh_bulk_cbw_csw_xfer(struct usbh_msc *msc_class, struct CBW *cbw, struct CSW *csw, uint8_t *buffer)
static int usbh_bulk_cbw_csw_xfer(struct usbh_msc *msc_class, struct CBW *cbw, struct CSW *csw, uint8_t *buffer)
{
int nbytes;
@ -236,55 +234,7 @@ static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, g_msc_buf);
}
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
{
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
cbw->dDataLength = (msc_class->blocksize * nsectors);
cbw->bCBLength = SCSICMD_WRITE10_SIZEOF;
cbw->CB[0] = SCSI_CMD_WRITE10;
SET_BE32(&cbw->CB[2], start_sector);
SET_BE16(&cbw->CB[7], nsectors);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
}
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
{
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
cbw->dDataLength = (msc_class->blocksize * nsectors);
cbw->bmFlags = 0x80;
cbw->bCBLength = SCSICMD_READ10_SIZEOF;
cbw->CB[0] = SCSI_CMD_READ10;
SET_BE32(&cbw->CB[2], start_sector);
SET_BE16(&cbw->CB[7], nsectors);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
}
void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config)
{
if (config) {
g_msc_modeswitch_config = config;
} else {
g_msc_modeswitch_config = NULL;
}
}
void usbh_msc_modeswitch(struct usbh_msc *msc_class, const uint8_t *message)
static inline void usbh_msc_modeswitch(struct usbh_msc *msc_class, const uint8_t *message)
{
struct CBW *cbw;
@ -323,9 +273,9 @@ static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
usbh_hport_activate_epx(&msc_class->bulkin, hport, ep_desc);
USBH_EP_INIT(msc_class->bulkin, ep_desc);
} else {
usbh_hport_activate_epx(&msc_class->bulkout, hport, ep_desc);
USBH_EP_INIT(msc_class->bulkout, ep_desc);
}
}
@ -390,11 +340,11 @@ static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (msc_class) {
if (msc_class->bulkin) {
usbh_pipe_free(msc_class->bulkin);
usbh_kill_urb(&msc_class->bulkin_urb);
}
if (msc_class->bulkout) {
usbh_pipe_free(msc_class->bulkout);
usbh_kill_urb(&msc_class->bulkout_urb);
}
if (hport->config.intf[intf].devname[0] != '\0') {
@ -408,6 +358,55 @@ static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
{
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
cbw->dDataLength = (msc_class->blocksize * nsectors);
cbw->bCBLength = SCSICMD_WRITE10_SIZEOF;
cbw->CB[0] = SCSI_CMD_WRITE10;
SET_BE32(&cbw->CB[2], start_sector);
SET_BE16(&cbw->CB[7], nsectors);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
}
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
{
struct CBW *cbw;
/* Construct the CBW */
cbw = (struct CBW *)g_msc_buf;
memset(cbw, 0, USB_SIZEOF_MSC_CBW);
cbw->dSignature = MSC_CBW_Signature;
cbw->dDataLength = (msc_class->blocksize * nsectors);
cbw->bmFlags = 0x80;
cbw->bCBLength = SCSICMD_READ10_SIZEOF;
cbw->CB[0] = SCSI_CMD_READ10;
SET_BE32(&cbw->CB[2], start_sector);
SET_BE16(&cbw->CB[7], nsectors);
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
}
void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config)
{
if (config) {
g_msc_modeswitch_config = config;
} else {
g_msc_modeswitch_config = NULL;
}
}
__WEAK void usbh_msc_run(struct usbh_msc *msc_class)
{
}

View File

@ -11,15 +11,15 @@
struct usbh_msc {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN urb */
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
uint8_t intf; /* Data interface number */
uint8_t sdchar;
usbh_pipe_t bulkin; /* Bulk IN endpoint */
usbh_pipe_t bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN urb */
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
uint32_t blocknum; /* Number of blocks on the USB mass storage device */
uint16_t blocksize; /* Block size of USB mass storage device */
uint32_t blocknum; /* Number of blocks on the USB mass storage device */
uint16_t blocksize; /* Block size of USB mass storage device */
};
struct usbh_msc_modeswitch_config {

View File

@ -67,7 +67,7 @@ int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf
retry = 0;
while (1) {
ret = usbh_control_transfer(video_class->hport->ep0, setup, g_video_buf);
ret = usbh_control_transfer(video_class->hport, setup, g_video_buf);
if (ret > 0) {
break;
}
@ -98,7 +98,7 @@ int usbh_video_set(struct usbh_video *video_class, uint8_t request, uint8_t intf
memcpy(g_video_buf, buf, len);
ret = usbh_control_transfer(video_class->hport->ep0, setup, g_video_buf);
ret = usbh_control_transfer(video_class->hport, setup, g_video_buf);
usb_osal_msleep(50);
return ret;
}
@ -233,7 +233,7 @@ int usbh_video_open(struct usbh_video *video_class,
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport->ep0, setup, NULL);
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
goto errout;
}
@ -243,10 +243,10 @@ int usbh_video_open(struct usbh_video *video_class,
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
if (ep_desc->bEndpointAddress & 0x80) {
video_class->isoin_mps = mps * (mult + 1);
usbh_hport_activate_epx(&video_class->isoin, video_class->hport, ep_desc);
USBH_EP_INIT(video_class->isoin, ep_desc);
} else {
video_class->isoout_mps = mps * (mult + 1);
usbh_hport_activate_epx(&video_class->isoout, video_class->hport, ep_desc);
USBH_EP_INIT(video_class->isoout, ep_desc);
}
USB_LOG_INFO("Open video and select formatidx:%u, frameidx:%u, altsetting:%u\r\n", formatidx, frameidx, altsetting);
@ -269,12 +269,10 @@ int usbh_video_close(struct usbh_video *video_class)
video_class->is_opened = false;
if (video_class->isoin) {
usbh_pipe_free(video_class->isoin);
video_class->isoin = NULL;
}
if (video_class->isoout) {
usbh_pipe_free(video_class->isoout);
video_class->isoout = NULL;
}
@ -284,7 +282,7 @@ int usbh_video_close(struct usbh_video *video_class)
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport->ep0, setup, NULL);
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
return ret;
}
@ -455,11 +453,9 @@ static int usbh_video_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (video_class) {
if (video_class->isoin) {
usbh_pipe_free(video_class->isoin);
}
if (video_class->isoout) {
usbh_pipe_free(video_class->isoout);
}
if (hport->config.intf[intf].devname[0] != '\0') {

View File

@ -32,12 +32,12 @@ struct usbh_videostreaming {
struct usbh_video {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *isoin; /* ISO IN endpoint */
struct usb_endpoint_descriptor *isoout; /* ISO OUT endpoint */
uint8_t ctrl_intf; /* interface number */
uint8_t data_intf; /* interface number */
uint8_t minor;
usbh_pipe_t isoin; /* ISO IN endpoint */
usbh_pipe_t isoout; /* ISO OUT endpoint */
struct video_probe_and_commit_controls probe;
struct video_probe_and_commit_controls commit;
uint16_t isoin_mps;

View File

@ -45,8 +45,8 @@ struct usbd_rndis_priv {
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + 44];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + 44];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + 44];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + 44];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t rndis_encapsulated_resp_buffer[CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t NOTIFY_RESPONSE_AVAILABLE[8];

View File

@ -11,8 +11,33 @@
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[4096];
#define CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE 1514
#define CONFIG_USBHOST_RNDIS_ETH_MSG_SIZE (CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE + 44)
/* eth rx size must be a multiple of 512 or 64 */
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE];
// static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_inttx_buffer[16];
static struct usbh_rndis g_rndis_class;
static int usbh_rndis_get_notification(struct usbh_rndis *rndis_class)
{
// int ret;
// struct usbh_urb *urb = &rndis_class->intin_urb;
// usbh_int_urb_fill(urb, rndis_class->hport, rndis_class->intin, g_rndis_inttx_buffer, rndis_class->intin->wMaxPacketSize, USB_OSAL_WAITING_FOREVER, NULL, NULL);
// ret = usbh_submit_urb(urb);
// if (ret == 0) {
// ret = urb->actual_length;
// }
// return ret;
return 0;
}
static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
{
struct usb_setup_packet *setup = rndis_class->hport->setup;
@ -35,13 +60,13 @@ static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
setup->wIndex = 0;
setup->wLength = sizeof(rndis_initialize_msg_t);
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("rndis_initialize_msg_t send error, ret: %d\r\n", ret);
return ret;
}
//ret = usbh_ep_intr_transfer()
usbh_rndis_get_notification(rndis_class);
resp = (rndis_initialize_cmplt_t *)g_rndis_buf;
@ -51,7 +76,7 @@ static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("rndis_initialize_cmplt_t recv error, ret: %d\r\n", ret);
return ret;
@ -83,13 +108,13 @@ int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid,
setup->wIndex = 0;
setup->wLength = query_len + sizeof(rndis_query_msg_t);
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
}
//ret = usbh_ep_intr_transfer()
usbh_rndis_get_notification(rndis_class);
resp = (rndis_query_cmplt_t *)g_rndis_buf;
@ -99,7 +124,7 @@ int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid,
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
@ -135,13 +160,13 @@ static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t
setup->wIndex = 0;
setup->wLength = info_len + sizeof(rndis_set_msg_t);
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
}
//ret = usbh_ep_intr_transfer(rndis_class->hport->intin,buf,len,500);
usbh_rndis_get_notification(rndis_class);
resp = (rndis_set_cmplt_t *)g_rndis_buf;
@ -151,7 +176,7 @@ static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
@ -160,32 +185,22 @@ static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t
return ret;
}
int usbh_rndis_bulk_out_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
static int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
{
int ret;
struct usbh_urb *urb = &rndis_class->bulkout_urb;
memset(urb, 0, sizeof(struct usbh_urb));
uint8_t data[32];
uint32_t data_len;
usbh_bulk_urb_fill(urb, rndis_class->bulkout, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
if (ret < 0) {
return ret;
}
return ret;
}
int usbh_rndis_bulk_in_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
{
int ret;
struct usbh_urb *urb = &rndis_class->bulkin_urb;
memset(urb, 0, sizeof(struct usbh_urb));
usbh_bulk_urb_fill(urb, rndis_class->bulkin, buffer, buflen, timeout, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
rndis_class->link_status = true;
} else {
rndis_class->link_status = false;
}
return ret;
return 0;
}
int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
@ -207,13 +222,13 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
setup->wIndex = 0;
setup->wLength = sizeof(rndis_keepalive_msg_t);
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("keepalive send error, ret: %d\r\n", ret);
return ret;
}
//ret = usbh_ep_intr_transfer(rndis_class->hport->intin,buf,len,500);
usbh_rndis_get_notification(rndis_class);
resp = (rndis_keepalive_cmplt_t *)g_rndis_buf;
@ -223,7 +238,7 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("keepalive recv error, ret: %d\r\n", ret);
return ret;
@ -254,17 +269,16 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
hport->config.intf[intf].priv = rndis_class;
hport->config.intf[intf + 1].priv = NULL;
#ifdef CONFIG_USBHOST_RNDIS_NOTIFY
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
usbh_hport_activate_epx(&rndis_class->intin, hport, ep_desc);
#endif
// ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
// USBH_EP_INIT(rndis_class->intin, ep_desc);
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
usbh_hport_activate_epx(&rndis_class->bulkin, hport, ep_desc);
USBH_EP_INIT(rndis_class->bulkin, ep_desc);
} else {
usbh_hport_activate_epx(&rndis_class->bulkout, hport, ep_desc);
USBH_EP_INIT(rndis_class->bulkout, ep_desc);
}
}
@ -360,6 +374,14 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
}
USB_LOG_INFO("rndis set OID_802_3_MULTICAST_LIST success\r\n");
USB_LOG_INFO("rndis MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
rndis_class->mac[0],
rndis_class->mac[1],
rndis_class->mac[2],
rndis_class->mac[3],
rndis_class->mac[4],
rndis_class->mac[5]);
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
@ -378,13 +400,17 @@ static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
if (rndis_class) {
if (rndis_class->bulkin) {
usbh_pipe_free(rndis_class->bulkin);
usbh_kill_urb(&rndis_class->bulkin_urb);
}
if (rndis_class->bulkout) {
usbh_pipe_free(rndis_class->bulkout);
usbh_kill_urb(&rndis_class->bulkout_urb);
}
// if (rndis_class->intin) {
// usbh_kill_urb(&rndis_class->intin_urb);
// }
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
usbh_rndis_stop(rndis_class);
@ -396,6 +422,123 @@ static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
static void usbh_rndis_rx_thread(void *argument)
{
uint32_t g_rndis_rx_length;
uint32_t pmg_offset;
uint32_t payload_offset;
int ret;
err_t err;
struct pbuf *p, *q;
rndis_data_packet_t *pmsg;
rndis_data_packet_t temp;
struct netif *netif = (struct netif *)argument;
// clang-format off
find_class:
// clang-format on
g_rndis_class.link_status = false;
while (usbh_find_class_instance("/dev/rndis") == NULL) {
usb_osal_msleep(1000);
}
while (g_rndis_class.link_status == false) {
ret = usbh_rndis_get_connect_status(&g_rndis_class);
if (ret < 0) {
goto find_class;
}
}
while (1) {
g_rndis_rx_length = 0;
usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, g_rndis_rx_buffer, CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rndis_class.bulkin_urb);
if (ret < 0) {
goto find_class;
}
g_rndis_rx_length = g_rndis_class.bulkin_urb.actual_length;
pmg_offset = 0;
while (g_rndis_rx_length > 0) {
USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_length);
pmsg = (rndis_data_packet_t *)(g_rndis_rx_buffer + pmg_offset);
/* Not word-aligned case */
if (pmg_offset & 0x3) {
memcpy(&temp, pmsg, sizeof(rndis_data_packet_t));
pmsg = &temp;
}
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, PBUF_POOL);
if (p != NULL) {
payload_offset = 0;
for (q = p; q != NULL; q = q->next) {
void *src = (void *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset + payload_offset);
memcpy(q->payload, src, q->len);
payload_offset += q->len;
}
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
}
pmg_offset += pmsg->MessageLength;
g_rndis_rx_length -= pmsg->MessageLength;
} else {
USB_LOG_ERR("No memory to alloc pbuf for rndis rx\r\n");
}
}
}
}
}
err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p)
{
int ret;
struct pbuf *q;
uint8_t *buffer;
rndis_data_packet_t *hdr;
if (g_rndis_class.link_status == false) {
return ERR_BUF;
}
hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
memset(hdr, 0, sizeof(rndis_data_packet_t));
hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
hdr->MessageLength = sizeof(rndis_data_packet_t) + p->tot_len;
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
hdr->DataLength = p->tot_len;
buffer = (uint8_t *)(g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
/* send */
if ((hdr->MessageLength & 0x1FF) == 0) {
/* pad a dummy. */
hdr->MessageLength += 1;
}
USB_LOG_DBG("txlen:%d\r\n", hdr->MessageLength);
usbh_bulk_urb_fill(&g_rndis_class.bulkout_urb, g_rndis_class.hport, g_rndis_class.bulkout, g_rndis_tx_buffer, hdr->MessageLength, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rndis_class.bulkout_urb);
if (ret < 0) {
return ERR_BUF;
}
return ERR_OK;
}
void usbh_rndis_lwip_thread_init(struct netif *netif)
{
usb_osal_thread_create("usbh_rndis_rx", 2560, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rndis_rx_thread, netif);
}
__WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
{
}

View File

@ -8,36 +8,45 @@
#include "usb_cdc.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
struct usbh_rndis {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* INTR endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN urb */
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
struct usbh_urb intin_urb; /* INTR IN urb */
uint8_t ctrl_intf; /* Control interface number */
uint8_t data_intf; /* Data interface number */
uint8_t minor;
usbh_pipe_t bulkin; /* Bulk IN endpoint */
usbh_pipe_t bulkout; /* Bulk OUT endpoint */
usbh_pipe_t intin; /* Notify endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN urb */
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
uint32_t request_id;
uint32_t link_speed;
bool link_status;
uint8_t mac[6];
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_rndis_bulk_out_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_rndis_bulk_in_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
int usbh_rndis_keepalive(struct usbh_rndis *rndis_class);
void usbh_rndis_run(struct usbh_rndis *rndis_class);
void usbh_rndis_stop(struct usbh_rndis *rndis_class);
err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p);
void usbh_rndis_lwip_thread_init(struct netif *netif);
#ifdef __cplusplus
}
#endif

View File

@ -221,6 +221,7 @@
#define USB_ENDPOINT_TYPE_BULK (2 << USB_ENDPOINT_TYPE_SHIFT)
#define USB_ENDPOINT_TYPE_INTERRUPT (3 << USB_ENDPOINT_TYPE_SHIFT)
#define USB_ENDPOINT_TYPE_MASK (3 << USB_ENDPOINT_TYPE_SHIFT)
#define USB_GET_ENDPOINT_TYPE(x) ((x & USB_ENDPOINT_TYPE_MASK) >> USB_ENDPOINT_TYPE_SHIFT)
#define USB_ENDPOINT_SYNC_SHIFT 2
#define USB_ENDPOINT_SYNC_NO_SYNCHRONIZATION (0 << USB_ENDPOINT_SYNC_SHIFT)
@ -245,6 +246,8 @@
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_ONE (1 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_TWO (2 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK (3 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
#define USB_GET_MAXPACKETSIZE(x) ((x & USB_MAXPACKETSIZE_MASK) >> USB_MAXPACKETSIZE_SHIFT)
#define USB_GET_MULT(x) ((x & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
/* bDevCapabilityType in Device Capability Descriptor */
#define USB_DEVICE_CAPABILITY_WIRELESS_USB 1

View File

@ -13,21 +13,6 @@ extern "C" {
#endif
typedef void (*usbh_complete_callback_t)(void *arg, int nbytes);
typedef void *usbh_pipe_t;
/**
* @brief USB Endpoint Configuration.
*
* Structure containing the USB endpoint configuration.
*/
struct usbh_endpoint_cfg {
struct usbh_hubport *hport;
uint8_t ep_addr; /* Endpoint addr with direction */
uint8_t ep_type; /* Endpoint type */
uint16_t ep_mps; /* Endpoint max packet size */
uint8_t ep_interval; /* Endpoint interval */
uint8_t mult; /* Endpoint additional transcation */
};
/**
* @brief USB Iso Configuration.
@ -47,7 +32,10 @@ struct usbh_iso_frame_packet {
* Structure containing the USB Urb configuration.
*/
struct usbh_urb {
usbh_pipe_t pipe;
void *hcpriv;
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *ep;
uint8_t data_toggle;
struct usb_setup_packet *setup;
uint8_t *transfer_buffer;
uint32_t transfer_buffer_length;
@ -88,34 +76,6 @@ uint16_t usbh_get_frame_number(void);
*/
int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf);
/**
* @brief reconfig endpoint pipe.
*
* @param pipe A memory allocated for pipe.
* @param dev_addr device address.
* @param ep_mps endpoint max packet size.
* @param mult endpoint additional transcation
* @return On success will return 0, and others indicate fail.
*/
int usbh_ep_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t ep_mps, uint8_t mult);
/**
* @brief Allocate pipe for endpoint
*
* @param pipe A memory location provided by the caller in which to save the allocated pipe.
* @param ep_cfg Describes the endpoint info to be allocated.
* @return On success will return 0, and others indicate fail.
*/
int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg);
/**
* @brief Free a pipe in which saves endpoint info.
*
* @param pipe A memory location provided by the caller in which to free the allocated endpoint info.
* @return On success will return 0, and others indicate fail.
*/
int usbh_pipe_free(usbh_pipe_t pipe);
/**
* @brief Submit a usb transfer request to an endpoint.
*

View File

@ -64,7 +64,7 @@ static int usbh_allocate_devaddr(struct usbh_devaddr_map *devgen)
}
}
static int usbh_free_devaddr(struct usbh_devaddr_map *devgen, uint8_t devaddr)
static int __usbh_free_devaddr(struct usbh_devaddr_map *devgen, uint8_t devaddr)
{
int index;
int bitno;
@ -340,57 +340,18 @@ static int usbh_get_default_mps(int speed)
}
}
int usbh_hport_activate_ep0(struct usbh_hubport *hport)
{
struct usbh_endpoint_cfg ep0_cfg = { 0 };
ep0_cfg.ep_addr = 0x00;
ep0_cfg.ep_interval = 0x00;
ep0_cfg.ep_mps = usbh_get_default_mps(hport->speed);
ep0_cfg.ep_type = USB_ENDPOINT_TYPE_CONTROL;
ep0_cfg.hport = hport;
usbh_pipe_alloc(&hport->ep0, &ep0_cfg);
return 0;
}
int usbh_hport_deactivate_ep0(struct usbh_hubport *hport)
int usbh_free_devaddr(struct usbh_hubport *hport)
{
#ifndef CONFIG_USBHOST_XHCI
if (hport->dev_addr > 0) {
usbh_free_devaddr(&g_usbh_bus.devgen, hport->dev_addr);
__usbh_free_devaddr(&g_usbh_bus.devgen, hport->dev_addr);
}
#endif
if (hport->ep0) {
usbh_pipe_free(hport->ep0);
}
hport->ep0 = NULL;
hport->dev_addr = 0;
return 0;
}
int usbh_hport_activate_epx(usbh_pipe_t *pipe, struct usbh_hubport *hport, struct usb_endpoint_descriptor *ep_desc)
{
struct usbh_endpoint_cfg ep_cfg = { 0 };
ep_cfg.ep_addr = ep_desc->bEndpointAddress;
ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
ep_cfg.ep_mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
ep_cfg.ep_interval = ep_desc->bInterval;
ep_cfg.mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
ep_cfg.hport = hport;
USB_LOG_INFO("Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
ep_cfg.ep_addr,
ep_desc->bmAttributes,
ep_cfg.ep_mps,
ep_cfg.ep_interval,
ep_cfg.mult);
return usbh_pipe_alloc(pipe, &ep_cfg);
}
int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *output)
{
struct usb_setup_packet *setup = hport->setup;
@ -408,7 +369,7 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out
setup->wIndex = 0x0409;
setup->wLength = 255;
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
if (ret < 0) {
return ret;
}
@ -436,7 +397,7 @@ int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsett
setup->wIndex = altsetting;
setup->wLength = 0;
return usbh_control_transfer(hport->ep0, setup, NULL);
return usbh_control_transfer(hport, setup, NULL);
}
int usbh_enumerate(struct usbh_hubport *hport)
@ -444,12 +405,25 @@ int usbh_enumerate(struct usbh_hubport *hport)
struct usb_interface_descriptor *intf_desc;
struct usb_setup_packet *setup;
struct usb_device_descriptor *dev_desc;
struct usb_endpoint_descriptor *ep;
int dev_addr;
uint16_t ep_mps;
int ret;
hport->setup = &g_setup[hport->parent->index - 1][hport->port - 1];
setup = hport->setup;
ep = &hport->ep0;
/* Config EP0 mps from speed */
ep->bEndpointAddress = 0x00;
ep->bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT;
ep->bmAttributes = USB_ENDPOINT_TYPE_CONTROL;
ep->wMaxPacketSize = usbh_get_default_mps(hport->speed);
ep->bInterval = 0;
ep->bLength = 7;
/* Configure EP0 with zero address */
hport->dev_addr = 0;
/* Read the first 8 bytes of the device descriptor */
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
@ -458,7 +432,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = 8;
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
if (ret < 0) {
USB_LOG_ERR("Failed to get device descriptor,errorcode:%d\r\n", ret);
goto errout;
@ -479,7 +453,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
dev_desc->bDeviceProtocol, ep_mps);
/* Reconfigure EP0 with the correct maximum packet size */
usbh_ep_pipe_reconfigure(hport->ep0, 0, ep_mps, 0);
ep->wMaxPacketSize = ep_mps;
#ifdef CONFIG_USBHOST_XHCI
extern int usbh_get_xhci_devaddr(usbh_pipe_t * pipe);
@ -506,7 +480,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = 0;
ret = usbh_control_transfer(hport->ep0, setup, NULL);
ret = usbh_control_transfer(hport, setup, NULL);
if (ret < 0) {
USB_LOG_ERR("Failed to set devaddr,errorcode:%d\r\n", ret);
goto errout;
@ -515,12 +489,9 @@ int usbh_enumerate(struct usbh_hubport *hport)
/* Wait device set address completely */
usb_osal_msleep(2);
/* Assign the function address to the port */
/*Reconfigure EP0 with the correct address */
hport->dev_addr = dev_addr;
/* And reconfigure EP0 with the correct address */
usbh_ep_pipe_reconfigure(hport->ep0, dev_addr, ep_mps, 0);
/* Read the full device descriptor */
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
@ -528,7 +499,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = USB_SIZEOF_DEVICE_DESC;
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
if (ret < 0) {
USB_LOG_ERR("Failed to get full device descriptor,errorcode:%d\r\n", ret);
goto errout;
@ -547,7 +518,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = USB_SIZEOF_CONFIG_DESC;
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
if (ret < 0) {
USB_LOG_ERR("Failed to get config descriptor,errorcode:%d\r\n", ret);
goto errout;
@ -564,7 +535,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = wTotalLength;
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
if (ret < 0) {
USB_LOG_ERR("Failed to get full config descriptor,errorcode:%d\r\n", ret);
goto errout;
@ -623,7 +594,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wIndex = 0;
setup->wLength = 0;
ret = usbh_control_transfer(hport->ep0, setup, NULL);
ret = usbh_control_transfer(hport, setup, NULL);
if (ret < 0) {
USB_LOG_ERR("Failed to set configuration,errorcode:%d\r\n", ret);
goto errout;
@ -670,27 +641,6 @@ errout:
return ret;
}
void *usbh_find_class_instance(const char *devname)
{
struct usbh_hubport *hport;
usb_slist_t *hub_list;
usb_slist_for_each(hub_list, &hub_class_head)
{
struct usbh_hub *hub = usb_slist_entry(hub_list, struct usbh_hub, list);
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
hport = &hub->child[port];
if (hport->connected) {
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if ((strncmp(hport->config.intf[itf].devname, devname, CONFIG_USBHOST_DEV_NAMELEN) == 0) && hport->config.intf[itf].priv)
return hport->config.intf[itf].priv;
}
}
}
}
return NULL;
}
int usbh_initialize(void)
{
memset(&g_usbh_bus, 0, sizeof(struct usbh_bus));
@ -717,7 +667,7 @@ int usbh_initialize(void)
return 0;
}
int usbh_control_transfer(usbh_pipe_t pipe, struct usb_setup_packet *setup, uint8_t *buffer)
int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *setup, uint8_t *buffer)
{
struct usbh_urb *urb;
int ret;
@ -725,7 +675,7 @@ int usbh_control_transfer(usbh_pipe_t pipe, struct usb_setup_packet *setup, uint
urb = usb_malloc(sizeof(struct usbh_urb));
memset(urb, 0, sizeof(struct usbh_urb));
usbh_control_urb_fill(urb, pipe, setup, buffer, setup->wLength, CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT, NULL, NULL);
usbh_control_urb_fill(urb, hport, setup, buffer, setup->wLength, CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
@ -735,6 +685,27 @@ int usbh_control_transfer(usbh_pipe_t pipe, struct usb_setup_packet *setup, uint
return ret;
}
void *usbh_find_class_instance(const char *devname)
{
struct usbh_hubport *hport;
usb_slist_t *hub_list;
usb_slist_for_each(hub_list, &hub_class_head)
{
struct usbh_hub *hub = usb_slist_entry(hub_list, struct usbh_hub, list);
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
hport = &hub->child[port];
if (hport->connected) {
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if ((strncmp(hport->config.intf[itf].devname, devname, CONFIG_USBHOST_DEV_NAMELEN) == 0) && hport->config.intf[itf].priv)
return hport->config.intf[itf].priv;
}
}
}
}
return NULL;
}
int lsusb(int argc, char **argv)
{
usb_slist_t *i;

View File

@ -32,8 +32,8 @@ extern "C" {
#define USB_CLASS_MATCH_INTF_SUBCLASS 0x0008
#define USB_CLASS_MATCH_INTF_PROTOCOL 0x0010
#define CLASS_CONNECT(hport, i) ((hport)->config.intf[i].class_driver->connect(hport, i))
#define CLASS_DISCONNECT(hport, i) ((hport)->config.intf[i].class_driver->disconnect(hport, i))
#define CLASS_CONNECT(hport, i) ((hport)->config.intf[i].class_driver->connect(hport, i))
#define CLASS_DISCONNECT(hport, i) ((hport)->config.intf[i].class_driver->disconnect(hport, i))
#ifdef __ARMCC_VERSION /* ARM C Compiler */
#define CLASS_INFO_DEFINE __attribute__((section("usbh_class_info"))) __USED __ALIGNED(1)
@ -44,57 +44,16 @@ extern "C" {
#define CLASS_INFO_DEFINE __attribute__((section("usbh_class_info"))) __USED __ALIGNED(1)
#endif
static inline void usbh_control_urb_fill(struct usbh_urb *urb,
usbh_pipe_t pipe,
struct usb_setup_packet *setup,
uint8_t *transfer_buffer,
uint32_t transfer_buffer_length,
uint32_t timeout,
usbh_complete_callback_t complete,
void *arg)
{
urb->pipe = pipe;
urb->setup = setup;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = transfer_buffer_length;
urb->timeout = timeout;
urb->complete = complete;
urb->arg = arg;
}
static inline void usbh_bulk_urb_fill(struct usbh_urb *urb,
usbh_pipe_t pipe,
uint8_t *transfer_buffer,
uint32_t transfer_buffer_length,
uint32_t timeout,
usbh_complete_callback_t complete,
void *arg)
{
urb->pipe = pipe;
urb->setup = NULL;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = transfer_buffer_length;
urb->timeout = timeout;
urb->complete = complete;
urb->arg = arg;
}
static inline void usbh_int_urb_fill(struct usbh_urb *urb,
usbh_pipe_t pipe,
uint8_t *transfer_buffer,
uint32_t transfer_buffer_length,
uint32_t timeout,
usbh_complete_callback_t complete,
void *arg)
{
urb->pipe = pipe;
urb->setup = NULL;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = transfer_buffer_length;
urb->timeout = timeout;
urb->complete = complete;
urb->arg = arg;
}
#define USBH_EP_INIT(ep, ep_desc) \
do { \
ep = ep_desc; \
USB_LOG_INFO("Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n", \
ep_desc->bEndpointAddress, \
USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes), \
USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize), \
ep_desc->bInterval, \
USB_GET_MULT(ep_desc->bmAttributes)); \
} while (0)
struct usbh_class_info {
uint8_t match_flags; /* Used for product specific matches; range is inclusive */
@ -140,7 +99,7 @@ struct usbh_hubport {
uint8_t port; /* Hub port index */
uint8_t dev_addr; /* device address */
uint8_t speed; /* device speed */
usbh_pipe_t ep0; /* control ep pipe info */
struct usb_endpoint_descriptor ep0;
struct usb_device_descriptor device_desc;
struct usbh_configuration config;
const char *iManufacturer;
@ -161,7 +120,7 @@ struct usbh_hub {
bool is_roothub;
uint8_t index;
uint8_t hub_addr;
usbh_pipe_t intin;
struct usb_endpoint_descriptor *intin;
uint8_t *int_buffer;
struct usbh_urb intin_urb;
struct usb_hub_descriptor hub_desc;
@ -169,17 +128,62 @@ struct usbh_hub {
struct usbh_hubport *parent;
};
/**
* @brief Activates an endpoint for a USB host pipe on a specific hub port.
*
* This function is responsible for activating the specified endpoint
* described by the given endpoint descriptor on the USB host pipe.
* @param pipe Pointer to the USB host pipe structure.
* @param hport Pointer to the USB hub port structure.
* @param ep_desc Pointer to the USB endpoint descriptor.
* @return On success will return 0, and others indicate fail.
*/
int usbh_hport_activate_epx(usbh_pipe_t *pipe, struct usbh_hubport *hport, struct usb_endpoint_descriptor *ep_desc);
static inline void usbh_control_urb_fill(struct usbh_urb *urb,
struct usbh_hubport *hport,
struct usb_setup_packet *setup,
uint8_t *transfer_buffer,
uint32_t transfer_buffer_length,
uint32_t timeout,
usbh_complete_callback_t complete,
void *arg)
{
urb->hport = hport;
urb->ep = &hport->ep0;
urb->setup = setup;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = transfer_buffer_length;
urb->timeout = timeout;
urb->complete = complete;
urb->arg = arg;
}
static inline void usbh_bulk_urb_fill(struct usbh_urb *urb,
struct usbh_hubport *hport,
struct usb_endpoint_descriptor *ep,
uint8_t *transfer_buffer,
uint32_t transfer_buffer_length,
uint32_t timeout,
usbh_complete_callback_t complete,
void *arg)
{
urb->hport = hport;
urb->ep = ep;
urb->setup = NULL;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = transfer_buffer_length;
urb->timeout = timeout;
urb->complete = complete;
urb->arg = arg;
}
static inline void usbh_int_urb_fill(struct usbh_urb *urb,
struct usbh_hubport *hport,
struct usb_endpoint_descriptor *ep,
uint8_t *transfer_buffer,
uint32_t transfer_buffer_length,
uint32_t timeout,
usbh_complete_callback_t complete,
void *arg)
{
urb->hport = hport;
urb->ep = ep;
urb->setup = NULL;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = transfer_buffer_length;
urb->timeout = timeout;
urb->complete = complete;
urb->arg = arg;
}
/**
* @brief Submit an control transfer to an endpoint.
@ -191,7 +195,7 @@ int usbh_hport_activate_epx(usbh_pipe_t *pipe, struct usbh_hubport *hport, struc
* @param buffer buffer used for sending the request and for returning any responses.
* @return On success will return 0, and others indicate fail.
*/
int usbh_control_transfer(usbh_pipe_t pipe, struct usb_setup_packet *setup, uint8_t *buffer);
int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *setup, uint8_t *buffer);
/**
* @brief Retrieves a USB string descriptor from a specific hub port.

View File

@ -12,13 +12,11 @@
#define TEST_USBH_AUDIO 0
#define TEST_USBH_VIDEO 0
#define TEST_USBH_CDC_ECM 0
#define TEST_USBH_RNDIS 0
#if TEST_USBH_CDC_ACM
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t cdc_buffer[512];
struct usbh_urb cdc_bulkin_urb;
struct usbh_urb cdc_bulkout_urb;
void usbh_cdc_acm_callback(void *arg, int nbytes)
{
//struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)arg;
@ -48,31 +46,19 @@ find_class:
}
memset(cdc_buffer, 0, 512);
usbh_bulk_urb_fill(&cdc_bulkin_urb, cdc_acm_class->bulkin, cdc_buffer, 64, 3000, NULL, NULL);
ret = usbh_submit_urb(&cdc_bulkin_urb);
if (ret < 0) {
USB_LOG_RAW("bulk in error,ret:%d\r\n", ret);
} else {
USB_LOG_RAW("recv over:%d\r\n", cdc_bulkin_urb.actual_length);
for (size_t i = 0; i < cdc_bulkin_urb.actual_length; i++) {
USB_LOG_RAW("0x%02x ", cdc_buffer[i]);
}
}
USB_LOG_RAW("\r\n");
const uint8_t data1[10] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x08, 0x14 };
memcpy(cdc_buffer, data1, 8);
usbh_bulk_urb_fill(&cdc_bulkout_urb, cdc_acm_class->bulkout, cdc_buffer, 8, 3000, NULL, NULL);
ret = usbh_submit_urb(&cdc_bulkout_urb);
memcpy(cdc_buffer, data1, 10);
usbh_bulk_urb_fill(&cdc_acm_class->bulkout_urb, cdc_acm_class->hport, cdc_acm_class->bulkout, cdc_buffer, 10, 3000, NULL, NULL);
ret = usbh_submit_urb(&cdc_acm_class->bulkout_urb);
if (ret < 0) {
USB_LOG_RAW("bulk out error,ret:%d\r\n", ret);
} else {
USB_LOG_RAW("send over:%d\r\n", cdc_bulkout_urb.actual_length);
USB_LOG_RAW("send over:%d\r\n", cdc_acm_class->bulkout_urb.actual_length);
}
usbh_bulk_urb_fill(&cdc_bulkin_urb, cdc_acm_class->bulkin, cdc_buffer, 64, 3000, usbh_cdc_acm_callback, cdc_acm_class);
ret = usbh_submit_urb(&cdc_bulkin_urb);
usbh_bulk_urb_fill(&cdc_acm_class->bulkin_urb, cdc_acm_class->hport, cdc_acm_class->bulkin, cdc_buffer, cdc_acm_class->bulkin->wMaxPacketSize, 3000, usbh_cdc_acm_callback, cdc_acm_class);
ret = usbh_submit_urb(&cdc_acm_class->bulkin_urb);
if (ret < 0) {
USB_LOG_RAW("bulk in error,ret:%d\r\n", ret);
} else {
@ -92,18 +78,16 @@ find_class:
#if TEST_USBH_HID
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t hid_buffer[128];
struct usbh_urb hid_intin_urb;
void usbh_hid_callback(void *arg, int nbytes)
{
//struct usbh_hid *hid_class = (struct usbh_hid *)arg;
struct usbh_hid *hid_class = (struct usbh_hid *)arg;
if (nbytes > 0) {
for (size_t i = 0; i < nbytes; i++) {
USB_LOG_RAW("0x%02x ", hid_buffer[i]);
}
USB_LOG_RAW("nbytes:%d\r\n", nbytes);
usbh_submit_urb(&hid_intin_urb);
usbh_submit_urb(&hid_class->intin_urb);
}
}
@ -122,8 +106,8 @@ find_class:
usb_osal_msleep(1500);
continue;
}
usbh_int_urb_fill(&hid_intin_urb, hid_class->intin, hid_buffer, 8, 0, usbh_hid_callback, hid_class);
ret = usbh_submit_urb(&hid_intin_urb);
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_buffer, hid_class->intin->wMaxPacketSize, 0, usbh_hid_callback, hid_class);
ret = usbh_submit_urb(&hid_class->intin_urb);
if (ret < 0) {
usb_osal_msleep(1500);
goto find_class;
@ -441,6 +425,98 @@ void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
}
#endif
#if TEST_USBH_RNDIS
#include "usbh_rndis.h"
#include "netif/etharp.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
#include "lwip/tcpip.h"
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"
struct netif g_rndis_netif;
TimerHandle_t timer_handle;
static void rndis_dev_keepalive_timeout(TimerHandle_t xTimer)
{
struct usbh_rndis *rndis_class = (struct usbh_rndis *)pvTimerGetTimerID(xTimer);
usbh_rndis_keepalive(rndis_class);
}
void timer_init(struct usbh_rndis *rndis_class)
{
timer_handle = xTimerCreate((const char *)NULL, (TickType_t)3000, (UBaseType_t)pdTRUE, (void *const)rndis_class, (TimerCallbackFunction_t)rndis_dev_keepalive_timeout);
if (NULL != timer_handle) {
xTimerStart(timer_handle, 0);
} else {
printf("timer creation failed!.\n");
for (;;) {
;
}
}
}
static err_t usbh_rndis_if_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
netif->state = NULL;
netif->name[0] = 'E';
netif->name[1] = 'X';
netif->output = etharp_output;
netif->linkoutput = usbh_rndis_linkoutput;
return ERR_OK;
}
void usbh_rndis_run(struct usbh_rndis *rndis_class)
{
struct netif *netif = &g_rndis_netif;
netif->hwaddr_len = 6;
memcpy(netif->hwaddr, rndis_class->mac, 6);
IP4_ADDR(&rndis_class->ipaddr, 0, 0, 0, 0);
IP4_ADDR(&rndis_class->netmask, 0, 0, 0, 0);
IP4_ADDR(&rndis_class->gateway, 0, 0, 0, 0);
netif = netif_add(netif, &rndis_class->ipaddr, &rndis_class->netmask, &rndis_class->gateway, NULL, usbh_rndis_if_init, tcpip_input);
netif_set_default(netif);
while (!netif_is_up(netif)) {
}
timer_init(rndis_class);
#if LWIP_DHCP
dhcp_start(netif);
#endif
}
void usbh_rndis_stop(struct usbh_rndis *rndis_class)
{
struct netif *netif = &g_rndis_netif;
#if LWIP_DHCP
dhcp_stop(netif);
dhcp_cleanup(netif);
#endif
netif_set_down(netif);
netif_remove(netif);
xTimerStop(timer_handle, 0);
xTimerDelete(timer_handle, 0);
}
#endif
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
{
}
@ -500,10 +576,14 @@ void usbh_class_test(void)
#error "if you want to use iso, please contact with me"
usb_osal_thread_create("usbh_video", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_video_thread, NULL);
#endif
#if TEST_USBH_CDC_ECM
#if TEST_USBH_CDC_ECM || TEST_USBH_RNDIS
/* Initialize the LwIP stack */
tcpip_init(NULL, NULL);
#endif
#if TEST_USBH_CDC_ECM
usbh_cdc_ecm_lwip_thread_init(&g_cdc_ecm_netif);
#endif
#if TEST_USBH_RNDIS
usbh_rndis_lwip_thread_init(&g_rndis_netif);
#endif
}

View File

@ -30,24 +30,13 @@
#define USB_OTG_HC(i) ((USB_OTG_HostChannelTypeDef *)(USB_BASE + USB_OTG_HOST_CHANNEL_BASE + ((i)*USB_OTG_HOST_CHANNEL_SIZE)))
#define USB_OTG_FIFO(i) *(__IO uint32_t *)(USB_BASE + USB_OTG_FIFO_BASE + ((i)*USB_OTG_FIFO_SIZE))
struct dwc2_pipe {
uint8_t dev_addr;
uint8_t ep_addr;
uint8_t ep_type;
uint8_t ep_interval;
uint8_t speed;
uint16_t ep_mps;
uint8_t data_pid;
uint8_t chidx;
volatile uint8_t ep0_state;
struct dwc2_chan {
uint8_t ep0_state;
uint16_t num_packets;
uint32_t xferlen;
uint8_t chidx;
bool inuse;
uint32_t xfrd;
int errorcode;
volatile bool waiter;
usb_osal_sem_t waitsem;
struct usbh_hubport *hport;
struct usbh_urb *urb;
uint32_t iso_frame_idx;
};
@ -56,7 +45,7 @@ struct dwc2_hcd {
volatile bool port_csc;
volatile bool port_pec;
volatile bool port_occ;
struct dwc2_pipe pipe_pool[CONFIG_USBHOST_PIPE_NUM];
struct dwc2_chan chan_pool[CONFIG_USBHOST_PIPE_NUM];
} g_dwc2_hcd;
#define DWC2_EP0_STATE_SETUP 0
@ -173,7 +162,7 @@ static inline void dwc2_drivebus(uint8_t state)
}
}
static void dwc2_pipe_init(uint8_t ch_num, uint8_t devaddr, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps, uint8_t speed)
static void dwc2_chan_init(uint8_t ch_num, uint8_t devaddr, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps, uint8_t speed)
{
uint32_t regval;
@ -236,7 +225,7 @@ static void dwc2_pipe_init(uint8_t ch_num, uint8_t devaddr, uint8_t ep_addr, uin
}
/* For IN channel HCTSIZ.XferSize is expected to be an integer multiple of ep_mps size.*/
static inline void dwc2_pipe_transfer(uint8_t ch_num, uint8_t ep_addr, uint32_t *buf, uint32_t size, uint8_t num_packets, uint8_t pid)
static inline void dwc2_chan_transfer(uint8_t ch_num, uint8_t ep_addr, uint32_t *buf, uint32_t size, uint8_t num_packets, uint8_t pid)
{
__IO uint32_t tmpreg;
uint8_t is_oddframe;
@ -361,13 +350,13 @@ static inline uint32_t dwc2_get_glb_intstatus(void)
return tmpreg;
}
static int dwc2_pipe_alloc(void)
static int dwc2_chan_alloc(void)
{
int chidx;
for (chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) {
if (!g_dwc2_hcd.pipe_pool[chidx].inuse) {
g_dwc2_hcd.pipe_pool[chidx].inuse = true;
if (!g_dwc2_hcd.chan_pool[chidx].inuse) {
g_dwc2_hcd.chan_pool[chidx].inuse = true;
return chidx;
}
}
@ -375,9 +364,9 @@ static int dwc2_pipe_alloc(void)
return -1;
}
static void dwc2_pipe_free(struct dwc2_pipe *pipe)
static void dwc2_chan_free(struct dwc2_chan *chan)
{
pipe->inuse = false;
chan->inuse = false;
}
static uint8_t dwc2_calculate_packet_num(uint32_t input_size, uint8_t ep_addr, uint16_t ep_mps, uint32_t *output_size)
@ -403,46 +392,60 @@ static uint8_t dwc2_calculate_packet_num(uint32_t input_size, uint8_t ep_addr, u
return num_packets;
}
static void dwc2_control_pipe_init(struct dwc2_pipe *chan, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
static void dwc2_control_urb_init(uint8_t chidx, struct usbh_urb *urb, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
{
struct dwc2_chan *chan;
chan = &g_dwc2_hcd.chan_pool[chidx];
if (chan->ep0_state == DWC2_EP0_STATE_SETUP) /* fill setup */
{
chan->num_packets = dwc2_calculate_packet_num(8, 0x00, chan->ep_mps, &chan->xferlen);
dwc2_pipe_init(chan->chidx, chan->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, chan->ep_mps, chan->speed);
dwc2_pipe_transfer(chan->chidx, 0x00, (uint32_t *)setup, chan->xferlen, chan->num_packets, HC_PID_SETUP);
chan->num_packets = dwc2_calculate_packet_num(8, 0x00, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(chidx, urb->hport->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(chidx, 0x00, (uint32_t *)setup, chan->xferlen, chan->num_packets, HC_PID_SETUP);
} else if (chan->ep0_state == DWC2_EP0_STATE_INDATA) /* fill in data */
{
chan->num_packets = dwc2_calculate_packet_num(setup->wLength, 0x80, chan->ep_mps, &chan->xferlen);
dwc2_pipe_init(chan->chidx, chan->dev_addr, 0x80, USB_ENDPOINT_TYPE_CONTROL, chan->ep_mps, chan->speed);
dwc2_pipe_transfer(chan->chidx, 0x80, (uint32_t *)buffer, chan->xferlen, chan->num_packets, HC_PID_DATA1);
chan->num_packets = dwc2_calculate_packet_num(setup->wLength, 0x80, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(chidx, urb->hport->dev_addr, 0x80, USB_ENDPOINT_TYPE_CONTROL, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(chidx, 0x80, (uint32_t *)buffer, chan->xferlen, chan->num_packets, HC_PID_DATA1);
} else if (chan->ep0_state == DWC2_EP0_STATE_OUTDATA) /* fill out data */
{
chan->num_packets = dwc2_calculate_packet_num(setup->wLength, 0x00, chan->ep_mps, &chan->xferlen);
dwc2_pipe_init(chan->chidx, chan->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, chan->ep_mps, chan->speed);
dwc2_pipe_transfer(chan->chidx, 0x00, (uint32_t *)buffer, chan->xferlen, chan->num_packets, HC_PID_DATA1);
chan->num_packets = dwc2_calculate_packet_num(setup->wLength, 0x00, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(chidx, urb->hport->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(chidx, 0x00, (uint32_t *)buffer, chan->xferlen, chan->num_packets, HC_PID_DATA1);
} else if (chan->ep0_state == DWC2_EP0_STATE_INSTATUS) /* fill in status */
{
chan->num_packets = dwc2_calculate_packet_num(0, 0x80, chan->ep_mps, &chan->xferlen);
dwc2_pipe_init(chan->chidx, chan->dev_addr, 0x80, USB_ENDPOINT_TYPE_CONTROL, chan->ep_mps, chan->speed);
dwc2_pipe_transfer(chan->chidx, 0x80, NULL, chan->xferlen, chan->num_packets, HC_PID_DATA1);
chan->num_packets = dwc2_calculate_packet_num(0, 0x80, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(chidx, urb->hport->dev_addr, 0x80, USB_ENDPOINT_TYPE_CONTROL, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(chidx, 0x80, NULL, chan->xferlen, chan->num_packets, HC_PID_DATA1);
} else if (chan->ep0_state == DWC2_EP0_STATE_OUTSTATUS) /* fill out status */
{
chan->num_packets = dwc2_calculate_packet_num(0, 0x00, chan->ep_mps, &chan->xferlen);
dwc2_pipe_init(chan->chidx, chan->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, chan->ep_mps, chan->speed);
dwc2_pipe_transfer(chan->chidx, 0x00, NULL, chan->xferlen, chan->num_packets, HC_PID_DATA1);
chan->num_packets = dwc2_calculate_packet_num(0, 0x00, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(chidx, urb->hport->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(chidx, 0x00, NULL, chan->xferlen, chan->num_packets, HC_PID_DATA1);
}
}
static void dwc2_bulk_intr_pipe_init(struct dwc2_pipe *chan, uint8_t *buffer, uint32_t buflen)
static void dwc2_bulk_intr_urb_init(uint8_t chidx, struct usbh_urb *urb, uint8_t *buffer, uint32_t buflen)
{
chan->num_packets = dwc2_calculate_packet_num(buflen, chan->ep_addr, chan->ep_mps, &chan->xferlen);
dwc2_pipe_transfer(chan->chidx, chan->ep_addr, (uint32_t *)buffer, chan->xferlen, chan->num_packets, chan->data_pid);
struct dwc2_chan *chan;
chan = &g_dwc2_hcd.chan_pool[chidx];
chan->num_packets = dwc2_calculate_packet_num(buflen, urb->ep->bEndpointAddress, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(chidx, urb->hport->dev_addr, urb->ep->bEndpointAddress, USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes), USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(chidx, urb->ep->bEndpointAddress, (uint32_t *)buffer, chan->xferlen, chan->num_packets, urb->data_toggle);
}
static void dwc2_iso_pipe_init(struct dwc2_pipe *chan, struct usbh_iso_frame_packet *iso_packet)
static void dwc2_iso_urb_init(uint8_t chidx, struct usbh_urb *urb, struct usbh_iso_frame_packet *iso_packet)
{
chan->num_packets = dwc2_calculate_packet_num(iso_packet->transfer_buffer_length, chan->ep_addr, chan->ep_mps, &chan->xferlen);
dwc2_pipe_transfer(chan->chidx, chan->ep_addr, (uint32_t *)iso_packet->transfer_buffer, chan->xferlen, chan->num_packets, HC_PID_DATA0);
struct dwc2_chan *chan;
chan = &g_dwc2_hcd.chan_pool[chidx];
chan->num_packets = dwc2_calculate_packet_num(iso_packet->transfer_buffer_length, urb->ep->bEndpointAddress, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(chidx, urb->hport->dev_addr, urb->ep->bEndpointAddress, USB_ENDPOINT_TYPE_ISOCHRONOUS, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(chidx, urb->ep->bEndpointAddress, (uint32_t *)iso_packet->transfer_buffer, chan->xferlen, chan->num_packets, HC_PID_DATA0);
}
__WEAK void usb_hc_low_level_init(void)
@ -456,7 +459,7 @@ int usb_hc_init(void)
memset(&g_dwc2_hcd, 0, sizeof(struct dwc2_hcd));
for (uint8_t chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) {
g_dwc2_hcd.pipe_pool[chidx].waitsem = usb_osal_sem_create(0);
g_dwc2_hcd.chan_pool[chidx].waitsem = usb_osal_sem_create(0);
}
usb_hc_low_level_init();
@ -681,137 +684,58 @@ int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf)
return 0;
}
int usbh_ep_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t ep_mps, uint8_t mult)
{
struct dwc2_pipe *chan;
chan = (struct dwc2_pipe *)pipe;
chan->dev_addr = dev_addr;
chan->ep_mps = ep_mps;
return 0;
}
int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg)
{
struct dwc2_pipe *chan;
int chidx;
usb_osal_sem_t waitsem;
chidx = dwc2_pipe_alloc();
if (chidx == -1) {
return -ENOMEM;
}
chan = &g_dwc2_hcd.pipe_pool[chidx];
/* store variables */
waitsem = chan->waitsem;
memset(chan, 0, sizeof(struct dwc2_pipe));
chan->chidx = chidx;
chan->ep_addr = ep_cfg->ep_addr;
chan->ep_type = ep_cfg->ep_type;
chan->ep_mps = ep_cfg->ep_mps;
chan->ep_interval = ep_cfg->ep_interval;
chan->speed = ep_cfg->hport->speed;
chan->dev_addr = ep_cfg->hport->dev_addr;
chan->hport = ep_cfg->hport;
if (ep_cfg->ep_type == USB_ENDPOINT_TYPE_CONTROL) {
chan->data_pid = HC_PID_DATA1;
} else {
dwc2_pipe_init(chidx, chan->dev_addr, ep_cfg->ep_addr, ep_cfg->ep_type, ep_cfg->ep_mps, chan->speed);
chan->data_pid = HC_PID_DATA0;
}
if (chan->speed == USB_SPEED_HIGH) {
chan->ep_interval = (1 << (chan->ep_interval - 1));
}
/* restore variables */
chan->inuse = true;
chan->waitsem = waitsem;
*pipe = (usbh_pipe_t)chan;
return 0;
}
int usbh_pipe_free(usbh_pipe_t pipe)
{
struct dwc2_pipe *chan;
struct usbh_urb *urb;
chan = (struct dwc2_pipe *)pipe;
if (!chan) {
return -EINVAL;
}
urb = chan->urb;
if (urb) {
usbh_kill_urb(urb);
}
dwc2_pipe_free(chan);
return 0;
}
int usbh_submit_urb(struct usbh_urb *urb)
{
struct dwc2_pipe *pipe;
struct dwc2_chan *chan;
size_t flags;
int ret = 0;
int chidx;
if (!urb || !urb->pipe) {
if (!urb || !urb->hport || !urb->ep) {
return -EINVAL;
}
pipe = urb->pipe;
/* dma addr must be aligned 4 bytes */
if ((((uint32_t)urb->setup) & 0x03) || (((uint32_t)urb->transfer_buffer) & 0x03)) {
return -EINVAL;
}
if (!(USB_OTG_HPRT & USB_OTG_HPRT_PCSTS) || !pipe->hport->connected) {
if (!(USB_OTG_HPRT & USB_OTG_HPRT_PCSTS) || !urb->hport->connected) {
return -ENODEV;
}
if (pipe->urb) {
if (urb->errorcode == -EBUSY) {
return -EBUSY;
}
flags = usb_osal_enter_critical_section();
pipe->waiter = false;
pipe->xfrd = 0;
pipe->urb = urb;
pipe->errorcode = -EBUSY;
chidx = dwc2_chan_alloc();
if (chidx == -1) {
usb_osal_leave_critical_section(flags);
return -ENOMEM;
}
chan = &g_dwc2_hcd.chan_pool[chidx];
chan->chidx = chidx;
chan->urb = urb;
urb->hcpriv = chan;
urb->errorcode = -EBUSY;
urb->actual_length = 0;
if (urb->timeout > 0) {
pipe->waiter = true;
}
usb_osal_leave_critical_section(flags);
switch (pipe->ep_type) {
switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
case USB_ENDPOINT_TYPE_CONTROL:
pipe->ep0_state = DWC2_EP0_STATE_SETUP;
dwc2_control_pipe_init(pipe, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
chan->ep0_state = DWC2_EP0_STATE_SETUP;
dwc2_control_urb_init(chidx, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
break;
case USB_ENDPOINT_TYPE_BULK:
case USB_ENDPOINT_TYPE_INTERRUPT:
dwc2_bulk_intr_pipe_init(pipe, urb->transfer_buffer, urb->transfer_buffer_length);
dwc2_bulk_intr_urb_init(chidx, urb, urb->transfer_buffer, urb->transfer_buffer_length);
break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
pipe->iso_frame_idx = 0;
dwc2_iso_pipe_init(pipe, &urb->iso_packet[pipe->iso_frame_idx]);
break;
default:
break;
@ -819,41 +743,44 @@ int usbh_submit_urb(struct usbh_urb *urb)
if (urb->timeout > 0) {
/* wait until timeout or sem give */
ret = usb_osal_sem_take(pipe->waitsem, urb->timeout);
ret = usb_osal_sem_take(chan->waitsem, urb->timeout);
if (ret < 0) {
goto errout_timeout;
}
urb->timeout = 0;
ret = urb->errorcode;
}
return ret;
errout_timeout:
pipe->waiter = false;
usbh_kill_urb(urb);
return ret;
}
int usbh_kill_urb(struct usbh_urb *urb)
{
struct dwc2_pipe *pipe;
struct dwc2_chan *chan;
size_t flags;
pipe = urb->pipe;
if (!urb || !pipe) {
if (!urb || !urb->hcpriv) {
return -EINVAL;
}
flags = usb_osal_enter_critical_section();
dwc2_halt(pipe->chidx);
CLEAR_HC_INT(pipe->chidx, USB_OTG_HCINT_CHH);
pipe->urb = NULL;
chan = (struct dwc2_chan *)urb->hcpriv;
if (pipe->waiter) {
pipe->waiter = false;
dwc2_halt(chan->chidx);
CLEAR_HC_INT(chan->chidx, USB_OTG_HCINT_CHH);
chan->urb = NULL;
urb->hcpriv = NULL;
dwc2_chan_free(chan);
if (urb->timeout) {
urb->timeout = 0;
urb->errorcode = -ESHUTDOWN;
usb_osal_sem_give(pipe->waitsem);
usb_osal_sem_give(chan->waitsem);
}
usb_osal_leave_critical_section(flags);
@ -861,16 +788,19 @@ int usbh_kill_urb(struct usbh_urb *urb)
return 0;
}
static inline void dwc2_pipe_waitup(struct dwc2_pipe *pipe)
static inline void dwc2_urb_waitup(struct usbh_urb *urb)
{
struct usbh_urb *urb;
struct dwc2_chan *chan;
urb = pipe->urb;
pipe->urb = NULL;
chan = (struct dwc2_chan *)urb->hcpriv;
chan->urb = NULL;
urb->hcpriv = NULL;
if (pipe->waiter) {
pipe->waiter = false;
usb_osal_sem_give(pipe->waitsem);
dwc2_chan_free(chan);
if (urb->timeout) {
urb->timeout = 0;
usb_osal_sem_give(chan->waitsem);
}
if (urb->complete) {
@ -885,214 +815,191 @@ static inline void dwc2_pipe_waitup(struct dwc2_pipe *pipe)
static void dwc2_inchan_irq_handler(uint8_t ch_num)
{
uint32_t chan_intstatus;
struct dwc2_pipe *chan;
struct dwc2_chan *chan;
struct usbh_urb *urb;
chan_intstatus = (USB_OTG_HC(ch_num)->HCINT) & (USB_OTG_HC((uint32_t)ch_num)->HCINTMSK);
chan = &g_dwc2_hcd.pipe_pool[ch_num];
chan = &g_dwc2_hcd.chan_pool[ch_num];
urb = chan->urb;
//printf("s1:%08x\r\n", chan_intstatus);
if ((chan_intstatus & USB_OTG_HCINT_XFRC) == USB_OTG_HCINT_XFRC) {
chan->errorcode = 0;
urb->errorcode = 0;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_XFRC);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_AHBERR) == USB_OTG_HCINT_AHBERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_AHBERR);
} else if ((chan_intstatus & USB_OTG_HCINT_STALL) == USB_OTG_HCINT_STALL) {
chan->errorcode = -EPERM;
urb->errorcode = -EPERM;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_STALL);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_NAK) == USB_OTG_HCINT_NAK) {
chan->errorcode = -EAGAIN;
urb->errorcode = -EAGAIN;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_ACK) == USB_OTG_HCINT_ACK) {
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_ACK);
} else if ((chan_intstatus & USB_OTG_HCINT_NYET) == USB_OTG_HCINT_NYET) {
chan->errorcode = -EAGAIN;
urb->errorcode = -EAGAIN;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NYET);
} else if ((chan_intstatus & USB_OTG_HCINT_TXERR) == USB_OTG_HCINT_TXERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_TXERR);
} else if ((chan_intstatus & USB_OTG_HCINT_BBERR) == USB_OTG_HCINT_BBERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_BBERR);
} else if ((chan_intstatus & USB_OTG_HCINT_FRMOR) == USB_OTG_HCINT_FRMOR) {
chan->errorcode = -EPIPE;
urb->errorcode = -EPIPE;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_FRMOR);
} else if ((chan_intstatus & USB_OTG_HCINT_DTERR) == USB_OTG_HCINT_DTERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_DTERR);
} else if ((chan_intstatus & USB_OTG_HCINT_CHH) == USB_OTG_HCINT_CHH) {
USB_MASK_HALT_HC_INT(ch_num);
if (urb == NULL) {
goto chhout;
}
urb->errorcode = chan->errorcode;
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_CHH);
if (urb->errorcode == 0) {
uint32_t count = chan->xferlen - (USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_XFRSIZ); /* how many size has received */
uint32_t has_used_packets = chan->num_packets - ((USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_DIEPTSIZ_PKTCNT) >> 19); /* how many packets have used */
chan->xfrd += count;
urb->actual_length += count;
if ((has_used_packets % 2) == 1) /* toggle in odd numbers */
{
if (chan->data_pid == HC_PID_DATA0) {
chan->data_pid = HC_PID_DATA1;
if (urb->data_toggle == HC_PID_DATA0) {
urb->data_toggle = HC_PID_DATA1;
} else {
chan->data_pid = HC_PID_DATA0;
urb->data_toggle = HC_PID_DATA0;
}
}
if (chan->ep_type == 0x00) {
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
if (chan->ep0_state == DWC2_EP0_STATE_INDATA) {
chan->ep0_state = DWC2_EP0_STATE_OUTSTATUS;
dwc2_control_pipe_init(chan, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
dwc2_control_urb_init(ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if (chan->ep0_state == DWC2_EP0_STATE_INSTATUS) {
chan->ep0_state = DWC2_EP0_STATE_SETUP;
urb->actual_length = chan->xfrd;
dwc2_pipe_waitup(chan);
}
} else if (chan->ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
urb->iso_packet[chan->iso_frame_idx].actual_length = chan->xfrd;
urb->iso_packet[chan->iso_frame_idx].errorcode = urb->errorcode;
chan->iso_frame_idx++;
if (chan->iso_frame_idx == urb->num_of_iso_packets) {
dwc2_pipe_waitup(chan);
} else {
dwc2_iso_pipe_init(chan, &urb->iso_packet[chan->iso_frame_idx]);
dwc2_urb_waitup(urb);
}
} else if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
} else {
urb->actual_length = chan->xfrd;
dwc2_pipe_waitup(chan);
dwc2_urb_waitup(urb);
}
} else if (urb->errorcode == -EAGAIN) {
/* re-activate the channel */
if (chan->ep_type == 0x00) {
dwc2_control_pipe_init(chan, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if ((chan->ep_type == 0x03) || (chan->ep_type == 0x02)) {
dwc2_bulk_intr_pipe_init(chan, urb->transfer_buffer, urb->transfer_buffer_length);
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
dwc2_control_urb_init(ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if ((USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_BULK) || (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT)) {
dwc2_bulk_intr_urb_init(ch_num, urb, urb->transfer_buffer, urb->transfer_buffer_length);
} else {
}
} else {
dwc2_pipe_waitup(chan);
dwc2_urb_waitup(urb);
}
chhout:
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_CHH);
}
}
static void dwc2_outchan_irq_handler(uint8_t ch_num)
{
uint32_t chan_intstatus;
struct dwc2_pipe *chan;
struct dwc2_chan *chan;
struct usbh_urb *urb;
uint16_t buflen;
chan_intstatus = (USB_OTG_HC(ch_num)->HCINT) & (USB_OTG_HC((uint32_t)ch_num)->HCINTMSK);
chan = &g_dwc2_hcd.pipe_pool[ch_num];
chan = &g_dwc2_hcd.chan_pool[ch_num];
urb = chan->urb;
//printf("s2:%08x\r\n", chan_intstatus);
if ((chan_intstatus & USB_OTG_HCINT_XFRC) == USB_OTG_HCINT_XFRC) {
chan->errorcode = 0;
urb->errorcode = 0;
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_XFRC);
dwc2_halt(ch_num);
USB_UNMASK_HALT_HC_INT(ch_num);
} else if ((chan_intstatus & USB_OTG_HCINT_AHBERR) == USB_OTG_HCINT_AHBERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_AHBERR);
} else if ((chan_intstatus & USB_OTG_HCINT_STALL) == USB_OTG_HCINT_STALL) {
chan->errorcode = -EPERM;
urb->errorcode = -EPERM;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_STALL);
} else if ((chan_intstatus & USB_OTG_HCINT_NAK) == USB_OTG_HCINT_NAK) {
chan->errorcode = -EAGAIN;
urb->errorcode = -EAGAIN;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_ACK) == USB_OTG_HCINT_ACK) {
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_ACK);
} else if ((chan_intstatus & USB_OTG_HCINT_NYET) == USB_OTG_HCINT_NYET) {
chan->errorcode = -EAGAIN;
urb->errorcode = -EAGAIN;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NYET);
} else if ((chan_intstatus & USB_OTG_HCINT_TXERR) == USB_OTG_HCINT_TXERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_TXERR);
} else if ((chan_intstatus & USB_OTG_HCINT_BBERR) == USB_OTG_HCINT_BBERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_BBERR);
} else if ((chan_intstatus & USB_OTG_HCINT_FRMOR) == USB_OTG_HCINT_FRMOR) {
chan->errorcode = -EPIPE;
urb->errorcode = -EPIPE;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_FRMOR);
} else if ((chan_intstatus & USB_OTG_HCINT_DTERR) == USB_OTG_HCINT_DTERR) {
chan->errorcode = -EIO;
urb->errorcode = -EIO;
USB_UNMASK_HALT_HC_INT(ch_num);
dwc2_halt(ch_num);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_DTERR);
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_NAK);
} else if ((chan_intstatus & USB_OTG_HCINT_CHH) == USB_OTG_HCINT_CHH) {
USB_MASK_HALT_HC_INT(ch_num);
if (urb == NULL) {
goto chhout;
}
urb->errorcode = chan->errorcode;
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_CHH);
if (urb->errorcode == 0) {
uint32_t count = USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_XFRSIZ; /* how many size has sent */
uint32_t has_used_packets = chan->num_packets - ((USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_DIEPTSIZ_PKTCNT) >> 19); /* how many packets have used */
chan->xfrd += count;
urb->actual_length += count;
if (has_used_packets % 2) /* toggle in odd numbers */
{
if (chan->data_pid == HC_PID_DATA0) {
chan->data_pid = HC_PID_DATA1;
if (urb->data_toggle == HC_PID_DATA0) {
urb->data_toggle = HC_PID_DATA1;
} else {
chan->data_pid = HC_PID_DATA0;
urb->data_toggle = HC_PID_DATA0;
}
}
if (chan->ep_type == 0x00) {
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
if (chan->ep0_state == DWC2_EP0_STATE_SETUP) {
if (urb->setup->wLength) {
if (urb->setup->bmRequestType & 0x80) {
@ -1103,42 +1010,29 @@ static void dwc2_outchan_irq_handler(uint8_t ch_num)
} else {
chan->ep0_state = DWC2_EP0_STATE_INSTATUS;
}
dwc2_control_pipe_init(chan, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
dwc2_control_urb_init(ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if (chan->ep0_state == DWC2_EP0_STATE_OUTDATA) {
chan->ep0_state = DWC2_EP0_STATE_INSTATUS;
dwc2_control_pipe_init(chan, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
dwc2_control_urb_init(ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if (chan->ep0_state == DWC2_EP0_STATE_OUTSTATUS) {
chan->ep0_state = DWC2_EP0_STATE_SETUP;
urb->actual_length = chan->xfrd;
dwc2_pipe_waitup(chan);
}
} else if (chan->ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
urb->iso_packet[chan->iso_frame_idx].actual_length = chan->xfrd;
urb->iso_packet[chan->iso_frame_idx].errorcode = urb->errorcode;
chan->iso_frame_idx++;
if (chan->iso_frame_idx == urb->num_of_iso_packets) {
dwc2_pipe_waitup(chan);
} else {
dwc2_iso_pipe_init(chan, &urb->iso_packet[chan->iso_frame_idx]);
dwc2_urb_waitup(urb);
}
} else if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
} else {
urb->actual_length = chan->xfrd;
dwc2_pipe_waitup(chan);
dwc2_urb_waitup(urb);
}
} else if (urb->errorcode == -EAGAIN) {
/* re-activate the channel */
if (chan->ep_type == 0x00) {
dwc2_control_pipe_init(chan, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if ((chan->ep_type == 0x03) || (chan->ep_type == 0x02)) {
dwc2_bulk_intr_pipe_init(chan, urb->transfer_buffer, urb->transfer_buffer_length);
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
dwc2_control_urb_init(ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if ((USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_BULK) || (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT)) {
dwc2_bulk_intr_urb_init(ch_num, urb, urb->transfer_buffer, urb->transfer_buffer_length);
} else {
}
} else {
dwc2_pipe_waitup(chan);
dwc2_urb_waitup(urb);
}
chhout:
CLEAR_HC_INT(ch_num, USB_OTG_HCINT_CHH);
}
}

View File

@ -33,34 +33,12 @@
extern uint8_t usbh_get_port_speed(const uint8_t port);
struct ehci_qh_hw;
struct ehci_itd_hw;
struct ehci_pipe {
uint8_t dev_addr;
uint8_t ep_addr;
uint8_t ep_type;
uint8_t ep_interval;
uint8_t speed;
uint8_t mult;
uint16_t ep_mps;
bool toggle;
bool inuse;
uint32_t xfrd;
bool waiter;
usb_osal_sem_t waitsem;
struct usbh_hubport *hport;
struct usbh_urb *urb;
uint8_t mf_unmask;
uint8_t mf_valid;
uint8_t iso_packet_idx;
uint8_t remain_itd_num;
};
struct ehci_qh_hw {
struct ehci_qh hw;
uint32_t first_qtd;
struct usbh_urb *urb;
uint8_t remove_in_iaad;
usb_osal_sem_t waitsem;
} __attribute__((aligned(32)));
struct ehci_qtd_hw {
@ -72,8 +50,10 @@ struct ehci_qtd_hw {
struct ehci_itd_hw {
struct ehci_itd hw;
struct usbh_urb *urb;
struct ehci_pipe *pipe;
uint16_t start_frame;
uint8_t mf_unmask;
uint8_t mf_valid;
uint32_t pkt_idx[8];
usb_slist_t list;
} __attribute__((aligned(32)));
@ -81,14 +61,13 @@ struct ehci_hcd {
bool ehci_qh_used[CONFIG_USB_EHCI_QH_NUM];
bool ehci_qtd_used[CONFIG_USB_EHCI_QTD_NUM];
bool ehci_itd_used[CONFIG_USB_EHCI_ITD_NUM];
struct ehci_pipe pipe_pool[CONFIG_USB_EHCI_QH_NUM];
};
extern struct ehci_hcd g_ehci_hcd;
extern uint32_t g_framelist[];
int ehci_iso_pipe_init(struct ehci_pipe *pipe, struct usbh_urb *urb);
int ehci_iso_urb_init(struct usbh_urb *urb);
void ehci_remove_itd_urb(struct usbh_urb *urb);
void ehci_scan_isochronous_list(void);
#endif
#endif

View File

@ -27,6 +27,7 @@ USB_NOCACHE_RAM_SECTION uint32_t g_framelist[CONFIG_USB_EHCI_FRAME_LIST_SIZE] __
static struct ehci_qh_hw *ehci_qh_alloc(void)
{
struct ehci_qh_hw *qh;
usb_osal_sem_t waitsem;
size_t flags;
for (uint32_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) {
@ -36,10 +37,12 @@ static struct ehci_qh_hw *ehci_qh_alloc(void)
usb_osal_leave_critical_section(flags);
qh = &ehci_qh_pool[i];
waitsem = qh->waitsem;
memset(qh, 0, sizeof(struct ehci_qh_hw));
qh->hw.hlp = QTD_LIST_END;
qh->hw.overlay.next_qtd = QTD_LIST_END;
qh->hw.overlay.alt_next_qtd = QTD_LIST_END;
qh->waitsem = waitsem;
return qh;
}
}
@ -100,24 +103,6 @@ static void ehci_qtd_free(struct ehci_qtd_hw *qtd)
}
}
static struct ehci_pipe *ehci_pipe_alloc(void)
{
int pipe;
for (pipe = 0; pipe < CONFIG_USB_EHCI_QH_NUM; pipe++) {
if (!g_ehci_hcd.pipe_pool[pipe].inuse) {
g_ehci_hcd.pipe_pool[pipe].inuse = true;
return &g_ehci_hcd.pipe_pool[pipe];
}
}
return NULL;
}
static void ehci_pipe_free(struct ehci_pipe *pipe)
{
pipe->inuse = false;
}
static inline void ehci_qh_add_head(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
{
n->hw.hlp = head->hw.hlp;
@ -312,7 +297,7 @@ static void ehci_qtd_fill(struct ehci_qtd_hw *qtd, uint32_t bufaddr, size_t bufl
qtd->total_len = buflen;
}
static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
static struct ehci_qh_hw *ehci_control_urb_init(struct usbh_urb *urb, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
{
struct ehci_qh_hw *qh = NULL;
struct ehci_qtd_hw *qtd_setup = NULL;
@ -344,15 +329,15 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
}
ehci_qh_fill(qh,
pipe->dev_addr,
pipe->ep_addr,
pipe->ep_type,
pipe->ep_mps,
urb->hport->dev_addr,
urb->ep->bEndpointAddress,
USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes),
USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize),
0,
pipe->ep_interval,
pipe->hport->speed,
pipe->hport->parent->hub_addr,
pipe->hport->port);
0,
urb->hport->speed,
urb->hport->parent->hub_addr,
urb->hport->port);
/* fill setup qtd */
token = QTD_TOKEN_STATUS_ACTIVE |
@ -361,7 +346,7 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
((uint32_t)8 << QTD_TOKEN_NBYTES_SHIFT);
ehci_qtd_fill(qtd_setup, (uintptr_t)setup, 8, token);
qtd_setup->urb = pipe->urb;
qtd_setup->urb = urb;
/* fill data qtd */
if (setup->wLength > 0) {
@ -377,7 +362,7 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
((uint32_t)buflen << QTD_TOKEN_NBYTES_SHIFT);
ehci_qtd_fill(qtd_data, (uintptr_t)buffer, buflen, token);
qtd_data->urb = pipe->urb;
qtd_data->urb = urb;
qtd_setup->hw.next_qtd = EHCI_PTR2ADDR(qtd_data);
qtd_data->hw.next_qtd = EHCI_PTR2ADDR(qtd_status);
} else {
@ -397,7 +382,7 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
((uint32_t)0 << QTD_TOKEN_NBYTES_SHIFT);
ehci_qtd_fill(qtd_status, 0, 0, token);
qtd_status->urb = pipe->urb;
qtd_status->urb = urb;
qtd_status->hw.next_qtd = QTD_LIST_END;
/* update qh first qtd */
@ -409,7 +394,8 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
flags = usb_osal_enter_critical_section();
qh->urb = pipe->urb;
qh->urb = urb;
urb->hcpriv = qh;
/* add qh into async list */
ehci_qh_add_head(&g_async_qh_head, qh);
@ -419,7 +405,7 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
return qh;
}
static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *buffer, uint32_t buflen)
static struct ehci_qh_hw *ehci_bulk_urb_init(struct usbh_urb *urb, uint8_t *buffer, uint32_t buflen)
{
struct ehci_qh_hw *qh = NULL;
struct ehci_qtd_hw *qtd = NULL;
@ -447,15 +433,15 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
}
ehci_qh_fill(qh,
pipe->dev_addr,
pipe->ep_addr,
pipe->ep_type,
pipe->ep_mps,
urb->hport->dev_addr,
urb->ep->bEndpointAddress,
USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes),
USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize),
0,
pipe->ep_interval,
pipe->hport->speed,
pipe->hport->parent->hub_addr,
pipe->hport->port);
0,
urb->hport->speed,
urb->hport->parent->hub_addr,
urb->hport->port);
while (buflen >= 0) {
qtd = ehci_qtd_alloc();
@ -468,7 +454,7 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
buflen = 0;
}
if (pipe->ep_addr & 0x80) {
if (urb->ep->bEndpointAddress & 0x80) {
token = QTD_TOKEN_PID_IN;
} else {
token = QTD_TOKEN_PID_OUT;
@ -483,7 +469,7 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
}
ehci_qtd_fill(qtd, (uintptr_t)buffer, xfer_len, token);
qtd->urb = pipe->urb;
qtd->urb = urb;
qtd->hw.next_qtd = QTD_LIST_END;
buffer += xfer_len;
@ -504,7 +490,7 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
qh->hw.overlay.next_qtd = EHCI_PTR2ADDR(first_qtd);
/* update data toggle */
if (pipe->toggle) {
if (urb->data_toggle) {
qh->hw.overlay.token = QTD_TOKEN_TOGGLE;
} else {
qh->hw.overlay.token = 0;
@ -515,7 +501,8 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
flags = usb_osal_enter_critical_section();
qh->urb = pipe->urb;
qh->urb = urb;
urb->hcpriv = qh;
/* add qh into async list */
ehci_qh_add_head(&g_async_qh_head, qh);
@ -525,7 +512,7 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
return qh;
}
static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *buffer, uint32_t buflen)
static struct ehci_qh_hw *ehci_intr_urb_init(struct usbh_urb *urb, uint8_t *buffer, uint32_t buflen)
{
struct ehci_qh_hw *qh = NULL;
struct ehci_qtd_hw *qtd = NULL;
@ -553,15 +540,15 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
}
ehci_qh_fill(qh,
pipe->dev_addr,
pipe->ep_addr,
pipe->ep_type,
pipe->ep_mps,
pipe->mult + 1,
pipe->ep_interval,
pipe->hport->speed,
pipe->hport->parent->hub_addr,
pipe->hport->port);
urb->hport->dev_addr,
urb->ep->bEndpointAddress,
USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes),
USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize),
USB_GET_MULT(urb->ep->wMaxPacketSize) + 1,
urb->ep->bInterval,
urb->hport->speed,
urb->hport->parent->hub_addr,
urb->hport->port);
while (buflen >= 0) {
qtd = ehci_qtd_alloc();
@ -574,7 +561,7 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
buflen = 0;
}
if (pipe->ep_addr & 0x80) {
if (urb->ep->bEndpointAddress & 0x80) {
token = QTD_TOKEN_PID_IN;
} else {
token = QTD_TOKEN_PID_OUT;
@ -589,7 +576,7 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
}
ehci_qtd_fill(qtd, (uintptr_t)buffer, xfer_len, token);
qtd->urb = pipe->urb;
qtd->urb = urb;
qtd->hw.next_qtd = QTD_LIST_END;
buffer += xfer_len;
@ -610,7 +597,7 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
qh->hw.overlay.next_qtd = EHCI_PTR2ADDR(first_qtd);
/* update data toggle */
if (pipe->toggle) {
if (urb->data_toggle) {
qh->hw.overlay.token = QTD_TOKEN_TOGGLE;
} else {
qh->hw.overlay.token = 0;
@ -621,12 +608,13 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
flags = usb_osal_enter_critical_section();
qh->urb = pipe->urb;
qh->urb = urb;
urb->hcpriv = qh;
/* add qh into periodic list */
if (pipe->speed == USB_SPEED_HIGH) {
ehci_qh_add_head(ehci_get_periodic_qhead(pipe->ep_interval), qh);
if (urb->hport->speed == USB_SPEED_HIGH) {
ehci_qh_add_head(ehci_get_periodic_qhead(urb->ep->bInterval), qh);
} else {
ehci_qh_add_head(ehci_get_periodic_qhead(pipe->ep_interval * 8), qh);
ehci_qh_add_head(ehci_get_periodic_qhead(urb->ep->bInterval * 8), qh);
}
EHCI_HCOR->usbcmd |= EHCI_USBCMD_PSEN;
@ -635,16 +623,20 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
return qh;
}
void ehci_pipe_waitup(struct ehci_pipe *pipe)
static void ehci_urb_waitup(struct usbh_urb *urb)
{
struct usbh_urb *urb;
struct ehci_qh_hw *qh;
urb = pipe->urb;
pipe->urb = NULL;
qh = (struct ehci_qh_hw *)urb->hcpriv;
qh->urb = NULL;
urb->hcpriv = NULL;
if (pipe->waiter) {
pipe->waiter = false;
usb_osal_sem_give(pipe->waitsem);
qh->remove_in_iaad = 0;
ehci_qh_free(qh);
if (urb->timeout) {
urb->timeout = 0;
usb_osal_sem_give(qh->waitsem);
}
if (urb->complete) {
@ -676,7 +668,6 @@ static void ehci_qh_scan_qtds(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
static void ehci_check_qh(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
{
struct usbh_urb *urb;
struct ehci_pipe *pipe;
struct ehci_qtd_hw *qtd;
uint32_t token;
@ -688,31 +679,30 @@ static void ehci_check_qh(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
}
urb = qh->urb;
pipe = urb->pipe;
if ((token & QTD_TOKEN_STATUS_ERRORS) == 0) {
qtd = EHCI_ADDR2QTD(qh->first_qtd);
qtd = EHCI_ADDR2QTD(qh->first_qtd);
while (qtd) {
if (qtd->hw.token & QTD_TOKEN_STATUS_ACTIVE) {
return;
}
qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd);
}
while (qtd) {
if ((qtd->hw.token & QTD_TOKEN_STATUS_ACTIVE) == QTD_TOKEN_STATUS_ACTIVE) {
return;
}
qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd);
}
if (token & QTD_TOKEN_TOGGLE) {
pipe->toggle = true;
urb->data_toggle = true;
} else {
pipe->toggle = false;
urb->data_toggle = false;
}
urb->errorcode = 0;
} else {
if (token & QTD_TOKEN_STATUS_BABBLE) {
urb->errorcode = -EPERM;
pipe->toggle = 0;
urb->data_toggle = 0;
} else if (token & QTD_TOKEN_STATUS_HALTED) {
urb->errorcode = -EPERM;
pipe->toggle = 0;
urb->data_toggle = 0;
} else if (token & (QTD_TOKEN_STATUS_DBERR | QTD_TOKEN_STATUS_XACTERR)) {
urb->errorcode = -EIO;
}
@ -720,10 +710,8 @@ static void ehci_check_qh(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
ehci_qh_scan_qtds(qhead, qh);
if (pipe->ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
qh->remove_in_iaad = 0;
ehci_qh_free(qh);
ehci_pipe_waitup(pipe);
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
ehci_urb_waitup(urb);
} else {
qh->remove_in_iaad = 1;
@ -806,10 +794,8 @@ int usb_hc_init(void)
}
for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) {
struct ehci_pipe *pipe;
pipe = &g_ehci_hcd.pipe_pool[index];
pipe->waitsem = usb_osal_sem_create(0);
qh = &ehci_qh_pool[index];
qh->waitsem = usb_osal_sem_create(0);
}
memset(&g_async_qh_head, 0, sizeof(struct ehci_qh_hw));
@ -1068,144 +1054,57 @@ int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf)
return 0;
}
int usbh_ep_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t ep_mps, uint8_t mult)
{
struct ehci_pipe *ppipe = (struct ehci_pipe *)pipe;
ppipe->dev_addr = dev_addr;
ppipe->ep_mps = ep_mps;
ppipe->mult = mult;
return 0;
}
int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg)
{
struct ehci_pipe *ppipe;
usb_osal_sem_t waitsem;
ppipe = ehci_pipe_alloc();
if (ppipe == NULL) {
return -ENOMEM;
}
/* store variables */
waitsem = ppipe->waitsem;
memset(ppipe, 0, sizeof(struct ehci_pipe));
ppipe->ep_addr = ep_cfg->ep_addr;
ppipe->ep_type = ep_cfg->ep_type;
ppipe->ep_mps = ep_cfg->ep_mps;
ppipe->ep_interval = ep_cfg->ep_interval;
ppipe->mult = ep_cfg->mult;
ppipe->speed = ep_cfg->hport->speed;
ppipe->dev_addr = ep_cfg->hport->dev_addr;
ppipe->hport = ep_cfg->hport;
#ifdef CONFIG_USB_EHCI_ISO
if ((ppipe->speed == USB_SPEED_HIGH) && (ppipe->ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS)) {
if (ep_cfg->ep_interval == 0x01) { /* transfer interval 1 mf */
ppipe->mf_unmask = 0xff;
ppipe->mf_valid = 8;
} else if (ep_cfg->ep_interval == 0x02) { /* transfer interval 2 mf */
ppipe->mf_unmask = 0x55;
ppipe->mf_valid = 4;
} else if (ep_cfg->ep_interval == 0x03) { /* transfer interval 4 mf */
ppipe->mf_unmask = 0x44;
ppipe->mf_valid = 2;
} else if (ep_cfg->ep_interval == 0x04) { /* transfer interval 8 mf */
ppipe->mf_unmask = 0x01;
ppipe->mf_valid = 1;
}
}
#endif
/* restore variable */
ppipe->inuse = true;
ppipe->waitsem = waitsem;
*pipe = (usbh_pipe_t)ppipe;
return 0;
}
int usbh_pipe_free(usbh_pipe_t pipe)
{
struct usbh_urb *urb;
struct ehci_pipe *ppipe;
ppipe = (struct ehci_pipe *)pipe;
if (!ppipe) {
return -EINVAL;
}
urb = ppipe->urb;
if (urb) {
usbh_kill_urb(urb);
}
ehci_pipe_free(ppipe);
return 0;
}
int usbh_submit_urb(struct usbh_urb *urb)
{
struct ehci_pipe *pipe;
struct ehci_qh_hw *qh = NULL;
size_t flags;
int ret = 0;
if (!urb || !urb->pipe) {
if (!urb || !urb->hport || !urb->ep) {
return -EINVAL;
}
pipe = urb->pipe;
if (!pipe->inuse /*|| !(EHCI_HCOR->portsc[pipe->hport->port-1] & EHCI_PORTSC_CCS)*/ || !pipe->hport->connected) {
if (!urb->hport->connected) {
return -ENODEV;
}
if (pipe->urb && (pipe->ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS)) {
if ((urb->errorcode == -EBUSY) && (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) != USB_ENDPOINT_TYPE_ISOCHRONOUS)) {
return -EBUSY;
}
flags = usb_osal_enter_critical_section();
pipe->waiter = false;
pipe->xfrd = 0;
pipe->urb = urb;
urb->hcpriv = NULL;
urb->errorcode = -EBUSY;
urb->actual_length = 0;
if (urb->timeout > 0) {
pipe->waiter = true;
}
usb_osal_leave_critical_section(flags);
switch (pipe->ep_type) {
switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
case USB_ENDPOINT_TYPE_CONTROL:
qh = ehci_control_pipe_init(pipe, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
qh = ehci_control_urb_init(urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
if (qh == NULL) {
return -ENOMEM;
}
urb->hcpriv = qh;
break;
case USB_ENDPOINT_TYPE_BULK:
qh = ehci_bulk_pipe_init(pipe, urb->transfer_buffer, urb->transfer_buffer_length);
qh = ehci_bulk_urb_init(urb, urb->transfer_buffer, urb->transfer_buffer_length);
if (qh == NULL) {
return -ENOMEM;
}
urb->hcpriv = qh;
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
qh = ehci_intr_pipe_init(pipe, urb->transfer_buffer, urb->transfer_buffer_length);
qh = ehci_intr_urb_init(urb, urb->transfer_buffer, urb->transfer_buffer_length);
if (qh == NULL) {
return -ENOMEM;
}
urb->hcpriv = qh;
break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
#ifdef CONFIG_USB_EHCI_ISO
ehci_iso_pipe_init(pipe, urb);
ret = ehci_iso_urb_init(urb);
#endif
break;
default:
@ -1214,34 +1113,26 @@ int usbh_submit_urb(struct usbh_urb *urb)
if (urb->timeout > 0) {
/* wait until timeout or sem give */
ret = usb_osal_sem_take(pipe->waitsem, urb->timeout);
ret = usb_osal_sem_take(qh->waitsem, urb->timeout);
if (ret < 0) {
goto errout_timeout;
}
urb->timeout = 0;
ret = urb->errorcode;
}
return ret;
errout_timeout:
/* Timeout will run here */
pipe->waiter = false;
usbh_kill_urb(urb);
return ret;
}
int usbh_kill_urb(struct usbh_urb *urb)
{
struct ehci_pipe *pipe;
struct ehci_qh_hw *qh = NULL;
struct ehci_qh_hw *qh;
size_t flags;
if (!urb) {
return -EINVAL;
}
pipe = urb->pipe;
if (!pipe) {
if (!urb || !urb->hcpriv) {
return -EINVAL;
}
@ -1249,7 +1140,7 @@ int usbh_kill_urb(struct usbh_urb *urb)
EHCI_HCOR->usbcmd &= ~(EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN);
if ((pipe->ep_type == USB_ENDPOINT_TYPE_CONTROL) || (pipe->ep_type == USB_ENDPOINT_TYPE_BULK)) {
if ((USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) || (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_BULK)) {
qh = EHCI_ADDR2QH(g_async_qh_head.hw.hlp);
while ((qh != &g_async_qh_head) && qh) {
if (qh->urb == urb) {
@ -1257,14 +1148,14 @@ int usbh_kill_urb(struct usbh_urb *urb)
}
qh = EHCI_ADDR2QH(qh->hw.hlp);
}
} else if (pipe->ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
} else if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
qh = EHCI_ADDR2QH(g_periodic_qh_head[EHCI_PERIOIDIC_QH_NUM - 1].hw.hlp);
while (qh) {
if (qh->urb == urb) {
if (pipe->speed == USB_SPEED_HIGH) {
ehci_kill_qh(ehci_get_periodic_qhead(pipe->ep_interval), qh);
if (urb->hport->speed == USB_SPEED_HIGH) {
ehci_kill_qh(ehci_get_periodic_qhead(urb->ep->bInterval), qh);
} else {
ehci_kill_qh(ehci_get_periodic_qhead(pipe->ep_interval * 8), qh);
ehci_kill_qh(ehci_get_periodic_qhead(urb->ep->bInterval * 8), qh);
}
}
qh = EHCI_ADDR2QH(qh->hw.hlp);
@ -1277,12 +1168,14 @@ int usbh_kill_urb(struct usbh_urb *urb)
EHCI_HCOR->usbcmd |= (EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN);
pipe->urb = NULL;
qh = (struct ehci_qh_hw *)urb->hcpriv;
urb->hcpriv = NULL;
qh->urb = NULL;
if (pipe->waiter) {
pipe->waiter = false;
if (urb->timeout) {
urb->timeout = 0;
urb->errorcode = -ESHUTDOWN;
usb_osal_sem_give(pipe->waitsem);
usb_osal_sem_give(qh->waitsem);
}
usb_osal_leave_critical_section(flags);
@ -1306,16 +1199,14 @@ static void ehci_scan_async_list(void)
static void ehci_scan_periodic_list(void)
{
struct ehci_qh_hw *qh;
struct ehci_pipe *pipe;
qh = EHCI_ADDR2QH(g_periodic_qh_head[EHCI_PERIOIDIC_QH_NUM - 1].hw.hlp);
while (qh) {
if (qh->urb && qh->urb->pipe) {
pipe = (struct ehci_pipe *)qh->urb->pipe;
if (pipe->speed == USB_SPEED_HIGH) {
ehci_check_qh(ehci_get_periodic_qhead(pipe->ep_interval), qh);
if (qh->urb) {
if (qh->urb->hport->speed == USB_SPEED_HIGH) {
ehci_check_qh(ehci_get_periodic_qhead(qh->urb->ep->bInterval), qh);
} else {
ehci_check_qh(ehci_get_periodic_qhead(pipe->ep_interval * 8), qh);
ehci_check_qh(ehci_get_periodic_qhead(qh->urb->ep->bInterval * 8), qh);
}
}
qh = EHCI_ADDR2QH(qh->hw.hlp);
@ -1372,16 +1263,7 @@ void USBH_IRQHandler(void)
for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) {
struct ehci_qh_hw *qh = &ehci_qh_pool[index];
if (g_ehci_hcd.ehci_qh_used[index] && qh->remove_in_iaad) {
struct usbh_urb *urb;
struct ehci_pipe *pipe;
urb = qh->urb;
pipe = urb->pipe;
qh->remove_in_iaad = 0;
ehci_qh_free(qh);
ehci_pipe_waitup(pipe);
ehci_urb_waitup(qh->urb);
}
}
}

View File

@ -151,17 +151,10 @@ typedef enum {
} ep0_state_t;
struct musb_pipe {
uint8_t dev_addr;
uint8_t ep_addr;
uint8_t ep_type;
uint8_t ep_interval;
uint8_t speed;
uint16_t ep_mps;
uint8_t chidx;
bool inuse;
uint32_t xfrd;
volatile bool waiter;
usb_osal_sem_t waitsem;
struct usbh_hubport *hport;
struct usbh_urb *urb;
};
@ -169,7 +162,7 @@ struct musb_hcd {
volatile bool port_csc;
volatile bool port_pec;
volatile bool port_pe;
struct musb_pipe pipe_pool[CONFIG_USBHOST_PIPE_NUM][2]; /* Support Bidirectional ep */
struct musb_pipe pipe_pool[CONFIG_USBHOST_PIPE_NUM];
} g_musb_hcd;
static volatile uint8_t usb_ep0_state = USB_EP0_STATE_SETUP;
@ -265,88 +258,115 @@ static void musb_read_packet(uint8_t ep_idx, uint8_t *buffer, uint16_t len)
}
}
void musb_control_pipe_init(struct musb_pipe *pipe, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
void musb_control_urb_init(uint8_t chidx, struct usbh_urb *urb, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
{
uint8_t old_ep_index;
uint8_t speed;
old_ep_index = musb_get_active_ep();
musb_set_active_ep(0);
musb_set_active_ep(chidx);
HWREGB(USB_TXADDR_BASE(0)) = pipe->dev_addr;
HWREGB(USB_BASE + MUSB_IND_TXTYPE_OFFSET) = pipe->speed;
HWREGB(USB_TXHUBADDR_BASE(0)) = 0;
HWREGB(USB_TXHUBPORT_BASE(0)) = 0;
if (urb->hport->speed == USB_SPEED_HIGH) {
speed = USB_TYPE0_SPEED_HIGH;
} else if (urb->hport->speed == USB_SPEED_FULL) {
speed = USB_TYPE0_SPEED_FULL;
} else if (urb->hport->speed == USB_SPEED_LOW) {
speed = USB_TYPE0_SPEED_LOW;
}
musb_write_packet(0, (uint8_t *)setup, 8);
HWREGB(USB_TXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_BASE + MUSB_IND_TXTYPE_OFFSET) = speed;
HWREGB(USB_TXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(chidx)) = 0;
musb_write_packet(chidx, (uint8_t *)setup, 8);
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
musb_set_active_ep(old_ep_index);
}
void musb_bulk_pipe_init(struct musb_pipe *pipe, uint8_t *buffer, uint32_t buflen)
void musb_bulk_urb_init(uint8_t chidx, struct usbh_urb *urb, uint8_t *buffer, uint32_t buflen)
{
uint8_t ep_idx;
uint8_t old_ep_index;
uint8_t speed;
ep_idx = pipe->ep_addr & 0x7f;
old_ep_index = musb_get_active_ep();
musb_set_active_ep(ep_idx);
musb_set_active_ep(chidx);
if (pipe->ep_addr & 0x80) {
HWREGB(USB_RXADDR_BASE(ep_idx)) = pipe->dev_addr;
HWREGB(USB_BASE + MUSB_IND_RXTYPE_OFFSET) = ep_idx | pipe->speed | USB_TXTYPE1_PROTO_BULK;
if (urb->hport->speed == USB_SPEED_HIGH) {
speed = USB_TXTYPE1_SPEED_HIGH;
} else if (urb->hport->speed == USB_SPEED_FULL) {
speed = USB_TXTYPE1_SPEED_FULL;
} else if (urb->hport->speed == USB_SPEED_LOW) {
speed = USB_TXTYPE1_SPEED_LOW;
}
if (urb->ep->bEndpointAddress & 0x80) {
HWREGB(USB_RXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_BASE + MUSB_IND_RXTYPE_OFFSET) = chidx | speed | USB_TXTYPE1_PROTO_BULK;
HWREGB(USB_BASE + MUSB_IND_RXINTERVAL_OFFSET) = 0;
HWREGB(USB_RXHUBADDR_BASE(ep_idx)) = 0;
HWREGB(USB_RXHUBPORT_BASE(ep_idx)) = 0;
HWREGB(USB_RXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_RXHUBPORT_BASE(chidx)) = 0;
HWREGB(USB_BASE + MUSB_IND_TXCSRH_OFFSET) &= ~USB_TXCSRH1_MODE;
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) = USB_RXCSRL1_REQPKT;
} else {
HWREGB(USB_TXADDR_BASE(ep_idx)) = pipe->dev_addr;
HWREGB(USB_BASE + MUSB_IND_TXTYPE_OFFSET) = ep_idx | pipe->speed | USB_TXTYPE1_PROTO_BULK;
HWREGB(USB_BASE + MUSB_IND_TXINTERVAL_OFFSET) = 0;
HWREGB(USB_TXHUBADDR_BASE(ep_idx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(ep_idx)) = 0;
if (buflen > pipe->ep_mps) {
buflen = pipe->ep_mps;
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) |= (1 << chidx);
} else {
HWREGB(USB_TXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_BASE + MUSB_IND_TXTYPE_OFFSET) = chidx | speed | USB_TXTYPE1_PROTO_BULK;
HWREGB(USB_BASE + MUSB_IND_TXINTERVAL_OFFSET) = 0;
HWREGB(USB_TXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(chidx)) = 0;
if (buflen > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
buflen = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
}
musb_write_packet(ep_idx, buffer, buflen);
musb_write_packet(chidx, buffer, buflen);
HWREGB(USB_BASE + MUSB_IND_TXCSRH_OFFSET) &= ~USB_TXCSRH1_MODE;
HWREGB(USB_BASE + MUSB_IND_TXCSRH_OFFSET) |= USB_TXCSRH1_MODE;
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_TXCSRL1_TXRDY;
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= (1 << chidx);
}
musb_set_active_ep(old_ep_index);
}
void musb_intr_pipe_init(struct musb_pipe *pipe, uint8_t *buffer, uint32_t buflen)
void musb_intr_urb_init(uint8_t chidx, struct usbh_urb *urb, uint8_t *buffer, uint32_t buflen)
{
uint8_t ep_idx;
uint8_t old_ep_index;
uint8_t speed;
ep_idx = pipe->ep_addr & 0x7f;
old_ep_index = musb_get_active_ep();
musb_set_active_ep(ep_idx);
musb_set_active_ep(chidx);
if (pipe->ep_addr & 0x80) {
HWREGB(USB_RXADDR_BASE(ep_idx)) = pipe->dev_addr;
HWREGB(USB_BASE + MUSB_IND_RXTYPE_OFFSET) = ep_idx | pipe->speed | USB_TXTYPE1_PROTO_INT;
HWREGB(USB_BASE + MUSB_IND_RXINTERVAL_OFFSET) = pipe->ep_interval;
HWREGB(USB_RXHUBADDR_BASE(ep_idx)) = 0;
HWREGB(USB_RXHUBPORT_BASE(ep_idx)) = 0;
if (urb->hport->speed == USB_SPEED_HIGH) {
speed = USB_TXTYPE1_SPEED_HIGH;
} else if (urb->hport->speed == USB_SPEED_FULL) {
speed = USB_TXTYPE1_SPEED_FULL;
} else if (urb->hport->speed == USB_SPEED_LOW) {
speed = USB_TXTYPE1_SPEED_LOW;
}
if (urb->ep->bEndpointAddress & 0x80) {
HWREGB(USB_RXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_BASE + MUSB_IND_RXTYPE_OFFSET) = chidx | speed | USB_TXTYPE1_PROTO_INT;
HWREGB(USB_BASE + MUSB_IND_RXINTERVAL_OFFSET) = urb->ep->bInterval;
HWREGB(USB_RXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_RXHUBPORT_BASE(chidx)) = 0;
HWREGB(USB_BASE + MUSB_IND_TXCSRH_OFFSET) &= ~USB_TXCSRH1_MODE;
HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) = USB_RXCSRL1_REQPKT;
} else {
HWREGB(USB_TXADDR_BASE(ep_idx)) = pipe->dev_addr;
HWREGB(USB_BASE + MUSB_IND_TXTYPE_OFFSET) = ep_idx | pipe->speed | USB_TXTYPE1_PROTO_INT;
HWREGB(USB_BASE + MUSB_IND_TXINTERVAL_OFFSET) = pipe->ep_interval;
HWREGB(USB_TXHUBADDR_BASE(ep_idx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(ep_idx)) = 0;
HWREGB(USB_TXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_BASE + MUSB_IND_TXTYPE_OFFSET) = chidx | speed | USB_TXTYPE1_PROTO_INT;
HWREGB(USB_BASE + MUSB_IND_TXINTERVAL_OFFSET) = urb->ep->bInterval;
HWREGB(USB_TXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(chidx)) = 0;
if (buflen > pipe->ep_mps) {
buflen = pipe->ep_mps;
if (buflen > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
buflen = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
}
musb_write_packet(ep_idx, buffer, buflen);
musb_write_packet(chidx, buffer, buflen);
HWREGB(USB_BASE + MUSB_IND_TXCSRH_OFFSET) &= ~USB_TXCSRH1_MODE;
HWREGB(USB_BASE + MUSB_IND_TXCSRH_OFFSET) |= USB_TXCSRH1_MODE;
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_TXCSRL1_TXRDY;
@ -379,6 +399,25 @@ static uint8_t usbh_get_port_speed(const uint8_t port)
return speed;
}
static int musb_pipe_alloc(void)
{
int chidx;
for (chidx = 1; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) {
if (!g_musb_hcd.pipe_pool[chidx].inuse) {
g_musb_hcd.pipe_pool[chidx].inuse = true;
return chidx;
}
}
return -1;
}
static void musb_pipe_free(struct musb_pipe *pipe)
{
pipe->inuse = false;
}
__WEAK void usb_hc_low_level_init(void)
{
}
@ -391,8 +430,7 @@ int usb_hc_init(void)
memset(&g_musb_hcd, 0, sizeof(struct musb_hcd));
for (uint8_t i = 0; i < CONFIG_USBHOST_PIPE_NUM; i++) {
g_musb_hcd.pipe_pool[i][0].waitsem = usb_osal_sem_create(0);
g_musb_hcd.pipe_pool[i][1].waitsem = usb_osal_sem_create(0);
g_musb_hcd.pipe_pool[i].waitsem = usb_osal_sem_create(0);
}
usb_hc_low_level_init();
@ -551,150 +589,53 @@ int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf)
return 0;
}
int usbh_ep_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t ep_mps, uint8_t mult)
{
struct musb_pipe *ppipe = (struct musb_pipe *)pipe;
ppipe->dev_addr = dev_addr;
ppipe->ep_mps = ep_mps;
return 0;
}
int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg)
{
struct musb_pipe *ppipe;
uint8_t old_ep_index;
uint8_t ep_idx;
usb_osal_sem_t waitsem;
ep_idx = ep_cfg->ep_addr & 0x7f;
if (ep_idx > CONIFG_USB_MUSB_PIPE_NUM) {
return -ENOMEM;
}
old_ep_index = musb_get_active_ep();
musb_set_active_ep(ep_idx);
if (ep_cfg->ep_addr & 0x80) {
ppipe = &g_musb_hcd.pipe_pool[ep_idx][1];
} else {
ppipe = &g_musb_hcd.pipe_pool[ep_idx][0];
}
/* store variables */
waitsem = ppipe->waitsem;
memset(ppipe, 0, sizeof(struct musb_pipe));
ppipe->ep_addr = ep_cfg->ep_addr;
ppipe->ep_type = ep_cfg->ep_type;
ppipe->ep_mps = ep_cfg->ep_mps;
ppipe->ep_interval = ep_cfg->ep_interval;
ppipe->speed = ep_cfg->hport->speed;
ppipe->dev_addr = ep_cfg->hport->dev_addr;
ppipe->hport = ep_cfg->hport;
if (ep_cfg->ep_type == USB_ENDPOINT_TYPE_CONTROL) {
if (ppipe->speed == USB_SPEED_HIGH) {
ppipe->speed = USB_TYPE0_SPEED_HIGH;
} else if (ppipe->speed == USB_SPEED_FULL) {
ppipe->speed = USB_TYPE0_SPEED_FULL;
} else if (ppipe->speed == USB_SPEED_LOW) {
ppipe->speed = USB_TYPE0_SPEED_LOW;
}
} else {
if (ppipe->speed == USB_SPEED_HIGH) {
ppipe->speed = USB_TXTYPE1_SPEED_HIGH;
} else if (ppipe->speed == USB_SPEED_FULL) {
ppipe->speed = USB_TXTYPE1_SPEED_FULL;
} else if (ppipe->speed == USB_SPEED_LOW) {
ppipe->speed = USB_TXTYPE1_SPEED_LOW;
}
if (ppipe->ep_addr & 0x80) {
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) |= (1 << ep_idx);
} else {
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= (1 << ep_idx);
}
}
/* restore variable */
ppipe->inuse = true;
ppipe->waitsem = waitsem;
musb_set_active_ep(old_ep_index);
*pipe = (usbh_pipe_t)ppipe;
return 0;
}
int usbh_pipe_free(usbh_pipe_t pipe)
{
struct musb_pipe *ppipe;
struct usbh_urb *urb;
ppipe = (struct musb_pipe *)pipe;
if (!ppipe) {
return -EINVAL;
}
urb = ppipe->urb;
if (urb) {
usbh_kill_urb(urb);
}
return 0;
}
int usbh_submit_urb(struct usbh_urb *urb)
{
struct musb_pipe *pipe;
int chidx;
size_t flags;
int ret = 0;
if (!urb) {
if (!urb || !urb->hport || !urb->ep) {
return -EINVAL;
}
pipe = urb->pipe;
if (!pipe) {
return -EINVAL;
}
if (!pipe->hport->connected) {
if (!urb->hport->connected) {
return -ENODEV;
}
if (pipe->urb) {
if (urb->errorcode == -EBUSY) {
return -EBUSY;
}
flags = usb_osal_enter_critical_section();
pipe->waiter = false;
pipe->xfrd = 0;
chidx = musb_pipe_alloc();
if (chidx == -1) {
usb_osal_leave_critical_section(flags);
return -ENOMEM;
}
pipe = &g_musb_hcd.pipe_pool[chidx];
pipe->chidx = chidx;
pipe->urb = urb;
urb->hcpriv = pipe;
urb->errorcode = -EBUSY;
urb->actual_length = 0;
if (urb->timeout > 0) {
pipe->waiter = true;
}
usb_osal_leave_critical_section(flags);
switch (pipe->ep_type) {
switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
case USB_ENDPOINT_TYPE_CONTROL:
usb_ep0_state = USB_EP0_STATE_SETUP;
musb_control_pipe_init(pipe, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
musb_control_urb_init(0, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
break;
case USB_ENDPOINT_TYPE_BULK:
musb_bulk_pipe_init(pipe, urb->transfer_buffer, urb->transfer_buffer_length);
musb_bulk_urb_init(chidx, urb, urb->transfer_buffer, urb->transfer_buffer_length);
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
musb_intr_pipe_init(pipe, urb->transfer_buffer, urb->transfer_buffer_length);
musb_intr_urb_init(chidx, urb, urb->transfer_buffer, urb->transfer_buffer_length);
break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
break;
@ -707,12 +648,11 @@ int usbh_submit_urb(struct usbh_urb *urb)
if (ret < 0) {
goto errout_timeout;
}
urb->timeout = 0;
ret = urb->errorcode;
}
return ret;
errout_timeout:
pipe->waiter = false;
usbh_kill_urb(urb);
return ret;
}
@ -720,31 +660,42 @@ errout_timeout:
int usbh_kill_urb(struct usbh_urb *urb)
{
struct musb_pipe *pipe;
size_t flags;
pipe = urb->pipe;
if (!urb || !pipe) {
if (!urb || !urb->hcpriv) {
return -EINVAL;
}
if (pipe->waiter) {
pipe->waiter = false;
flags = usb_osal_enter_critical_section();
pipe = (struct musb_pipe *)urb->hcpriv;
urb->hcpriv = NULL;
pipe->urb = NULL;
musb_pipe_free(pipe);
if (urb->timeout) {
urb->timeout = 0;
urb->errorcode = -ESHUTDOWN;
usb_osal_sem_give(pipe->waitsem);
}
usb_osal_leave_critical_section(flags);
return 0;
}
static inline void musb_pipe_waitup(struct musb_pipe *pipe)
static void musb_urb_waitup(struct usbh_urb *urb)
{
struct usbh_urb *urb;
struct musb_pipe *pipe;
urb = pipe->urb;
pipe = (struct musb_pipe *)urb->hcpriv;
pipe->urb = NULL;
urb->hcpriv = NULL;
if (pipe->waiter) {
pipe->waiter = false;
musb_pipe_free(pipe);
if (urb->timeout) {
urb->timeout = 0;
usb_osal_sem_give(pipe->waitsem);
}
@ -764,7 +715,7 @@ void handle_ep0(void)
struct usbh_urb *urb;
uint32_t size;
pipe = (struct musb_pipe *)&g_musb_hcd.pipe_pool[0][0];
pipe = (struct musb_pipe *)&g_musb_hcd.pipe_pool[0];
urb = pipe->urb;
if (urb == NULL) {
return;
@ -776,7 +727,7 @@ void handle_ep0(void)
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALLED;
usb_ep0_state = USB_EP0_STATE_SETUP;
urb->errorcode = -EPERM;
musb_pipe_waitup(pipe);
musb_urb_waitup(urb);
return;
}
if (ep0_status & USB_CSRL0_ERROR) {
@ -784,14 +735,14 @@ void handle_ep0(void)
musb_fifo_flush(0);
usb_ep0_state = USB_EP0_STATE_SETUP;
urb->errorcode = -EIO;
musb_pipe_waitup(pipe);
musb_urb_waitup(urb);
return;
}
if (ep0_status & USB_CSRL0_STALL) {
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALL;
usb_ep0_state = USB_EP0_STATE_SETUP;
urb->errorcode = -EPERM;
musb_pipe_waitup(pipe);
musb_urb_waitup(urb);
return;
}
@ -805,8 +756,8 @@ void handle_ep0(void)
} else {
usb_ep0_state = USB_EP0_STATE_OUT_DATA;
size = urb->transfer_buffer_length;
if (size > pipe->ep_mps) {
size = pipe->ep_mps;
if (size > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
size = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
}
musb_write_packet(0, urb->transfer_buffer, size);
@ -824,8 +775,8 @@ void handle_ep0(void)
case USB_EP0_STATE_IN_DATA:
if (ep0_status & USB_CSRL0_RXRDY) {
size = urb->transfer_buffer_length;
if (size > pipe->ep_mps) {
size = pipe->ep_mps;
if (size > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
size = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
}
size = MIN(size, HWREGH(USB_BASE + MUSB_IND_RXCOUNT_OFFSET));
@ -835,7 +786,7 @@ void handle_ep0(void)
urb->transfer_buffer_length -= size;
urb->actual_length += size;
if ((size < pipe->ep_mps) || (urb->transfer_buffer_length == 0)) {
if ((size < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) || (urb->transfer_buffer_length == 0)) {
usb_ep0_state = USB_EP0_STATE_OUT_STATUS;
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_TXRDY | USB_CSRL0_STATUS);
} else {
@ -846,8 +797,8 @@ void handle_ep0(void)
case USB_EP0_STATE_OUT_DATA:
if (urb->transfer_buffer_length > 0) {
size = urb->transfer_buffer_length;
if (size > pipe->ep_mps) {
size = pipe->ep_mps;
if (size > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
size = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
}
musb_write_packet(0, urb->transfer_buffer, size);
@ -863,13 +814,13 @@ void handle_ep0(void)
break;
case USB_EP0_STATE_OUT_STATUS:
urb->errorcode = 0;
musb_pipe_waitup(pipe);
musb_urb_waitup(urb);
break;
case USB_EP0_STATE_IN_STATUS:
if (ep0_status & (USB_CSRL0_RXRDY | USB_CSRL0_STATUS)) {
HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~(USB_CSRL0_RXRDY | USB_CSRL0_STATUS);
urb->errorcode = 0;
musb_pipe_waitup(pipe);
musb_urb_waitup(urb);
}
break;
}
@ -939,7 +890,7 @@ void USBH_IRQHandler(void)
if (txis & (1 << ep_idx)) {
HWREGH(USB_BASE + MUSB_TXIS_OFFSET) = (1 << ep_idx);
pipe = &g_musb_hcd.pipe_pool[ep_idx][0];
pipe = &g_musb_hcd.pipe_pool[ep_idx];
urb = pipe->urb;
musb_set_active_ep(ep_idx);
@ -960,8 +911,8 @@ void USBH_IRQHandler(void)
} else {
uint32_t size = urb->transfer_buffer_length;
if (size > pipe->ep_mps) {
size = pipe->ep_mps;
if (size > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
size = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
}
urb->transfer_buffer += size;
@ -984,7 +935,7 @@ void USBH_IRQHandler(void)
if (rxis & (1 << ep_idx)) {
HWREGH(USB_BASE + MUSB_RXIS_OFFSET) = (1 << ep_idx); // clear isr flag
pipe = &g_musb_hcd.pipe_pool[ep_idx][1];
pipe = &g_musb_hcd.pipe_pool[ep_idx];
urb = pipe->urb;
musb_set_active_ep(ep_idx);
@ -1005,8 +956,8 @@ void USBH_IRQHandler(void)
goto pipe_wait;
} else if (ep_csrl_status & USB_RXCSRL1_RXRDY) {
uint32_t size = urb->transfer_buffer_length;
if (size > pipe->ep_mps) {
size = pipe->ep_mps;
if (size > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
size = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
}
size = MIN(size, HWREGH(USB_BASE + MUSB_IND_RXCOUNT_OFFSET));
@ -1018,7 +969,7 @@ void USBH_IRQHandler(void)
urb->transfer_buffer_length -= size;
urb->actual_length += size;
if ((size < pipe->ep_mps) || (urb->transfer_buffer_length == 0)) {
if ((size < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) || (urb->transfer_buffer_length == 0)) {
urb->errorcode = 0;
goto pipe_wait;
} else {
@ -1030,6 +981,11 @@ void USBH_IRQHandler(void)
musb_set_active_ep(old_ep_idx);
return;
pipe_wait:
if (urb->ep->bEndpointAddress & 0x80) {
HWREGH(USB_BASE + MUSB_RXIE_OFFSET) |= (1 << pipe->chidx);
} else {
HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= (1 << pipe->chidx);
}
musb_set_active_ep(old_ep_idx);
musb_pipe_waitup(pipe);
musb_urb_waitup(urb);
}