272 lines
5.9 KiB
C
272 lines
5.9 KiB
C
#include <usb/usb.h>
|
|
#include <avr/io.h>
|
|
|
|
#include <sys/trace.h>
|
|
|
|
int avr_usb_ep_size[] = {
|
|
8,
|
|
16,
|
|
32,
|
|
64,
|
|
128,
|
|
256,
|
|
512,
|
|
0
|
|
};
|
|
|
|
int usb_ll_ep_find_size_index(int minSize){
|
|
int n;
|
|
for (n=0;n<7;n++){
|
|
if (avr_usb_ep_size[n] >= minSize){
|
|
return n;
|
|
};
|
|
};
|
|
// In Case no useful size available, we try a fall back of 32bytes
|
|
return 0x02;
|
|
};
|
|
|
|
/**
|
|
* @brief select endpoint to be handled by the usb_ll_endpoint_X functions
|
|
* @param endpoint Number of endpoint
|
|
* @return 0 on Success
|
|
*/
|
|
int usb_ll_endpoint_select(uint8_t endpoint){
|
|
UENUM = endpoint;
|
|
return 0;
|
|
};
|
|
|
|
/**
|
|
* @brief read up to <len> bytes from endpoint fifo
|
|
* usb_ll_endpoint_select(..) must have been called before
|
|
* @param buffer Pointer to buffer to write data to
|
|
* @param len maximum buffer size
|
|
* @return number of bytes that have been read from hardware
|
|
*/
|
|
int usb_ll_endpoint_read(uint8_t *buffer,int len){
|
|
int p = 0;
|
|
|
|
while (UEBCX && (p < len)){
|
|
buffer[p++] = UEDATX;
|
|
};
|
|
|
|
return p;
|
|
};
|
|
|
|
/**
|
|
* @brief write up to <len> bytes to endpoint fifo
|
|
* usb_ll_endpoint_select(..) must have been called before
|
|
* @param buffer Pointer to buffer to read data from
|
|
* @param len buffer size
|
|
* @return number of bytes that have been written to hardware
|
|
*/
|
|
int usb_ll_endpoint_write(uint8_t *buffer,int len){
|
|
int p = 0;
|
|
int epsize = avr_usb_ep_size[ (UECFG1X>>EPSIZE0)&0x07 ];
|
|
|
|
while ((p < len) && (UEBCX < epsize) ){
|
|
UEDATX = buffer[p++];
|
|
};
|
|
|
|
return p;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void usb_irq_endpoint_txin(uint8_t endpoint)
|
|
{
|
|
uint8_t ep_type;
|
|
usb_ll_endpoint_select( endpoint );
|
|
ep_type = (UECFG0X >> EPTYPE0) & 0x03;
|
|
|
|
if ( (endpoint == 0) && (usb_device._addr_setup)){
|
|
if (usb_device.endpoints[ endpoint ].buffer){
|
|
usb_device.endpoints[ endpoint ].buffer = NULL;
|
|
} else {
|
|
//UDADDR = usb_device._addr_setup;
|
|
UDADDR |= _BV(ADDEN);
|
|
usb_device._addr_setup = 0;
|
|
usb_device.state.Address = 1;
|
|
};
|
|
|
|
} else if (usb_device.endpoints[ endpoint ].buffer){
|
|
int nSend = usb_device.endpoints[ endpoint ].blen - usb_device.endpoints[ endpoint ].bpos;
|
|
|
|
int nSent = usb_ll_endpoint_write(
|
|
&(usb_device.endpoints[ endpoint ].buffer[ usb_device.endpoints[ endpoint ].bpos ]),
|
|
nSend);
|
|
|
|
usb_device.endpoints[ endpoint ].bpos += nSent;
|
|
} else {
|
|
if (ep_type == USB_EP_CONTROL){
|
|
usb_ll_clear_irq( USB_IRQ_TXIN );
|
|
usb_ll_disable_irq( USB_IRQ_TXIN );
|
|
usb_ll_disable_irq( USB_IRQ_RXOUT );
|
|
} else {
|
|
usb_ll_disable_irq( USB_IRQ_TXIN );
|
|
};
|
|
return;
|
|
};
|
|
|
|
switch (ep_type){
|
|
case USB_EP_CONTROL:
|
|
usb_ll_clear_irq( USB_IRQ_TXIN );
|
|
break;
|
|
case USB_EP_INTERRUPT:
|
|
case USB_EP_BULK:
|
|
case USB_EP_ISOCHRONOUS:
|
|
if (UEBCX){
|
|
usb_ll_clear_irq( USB_IRQ_TXIN );
|
|
UEINTX &= ~_BV(FIFOCON);
|
|
} else {
|
|
usb_ll_disable_irq( USB_IRQ_TXIN );
|
|
};
|
|
break;
|
|
};
|
|
};
|
|
|
|
void usb_irq_endpoint_rxout(uint8_t endpoint)
|
|
{
|
|
uint8_t ep_type;
|
|
usb_ll_endpoint_select( endpoint );
|
|
ep_type = (UECFG0X >> EPTYPE0) & 0x03;
|
|
|
|
if ((ep_type == USB_EP_CONTROL)&&((usb_device.endpoints[ endpoint ].request->bmRequestType & 0x80)) ){
|
|
|
|
usb_device.endpoints[ endpoint ].buffer = NULL;
|
|
|
|
} else if (usb_device.endpoints[ endpoint ].buffer){
|
|
int nToRead = usb_device.endpoints[ endpoint ].blen - usb_device.endpoints[ endpoint ].bpos;
|
|
|
|
int nRead = usb_ll_endpoint_read(
|
|
&(usb_device.endpoints[ endpoint ].buffer[ usb_device.endpoints[ endpoint ].bpos ]),
|
|
nToRead);
|
|
|
|
usb_device.endpoints[ endpoint ].bpos += nRead;
|
|
} else {
|
|
usb_ll_disable_irq( USB_IRQ_RXOUT );
|
|
return;
|
|
};
|
|
|
|
switch (ep_type){
|
|
case USB_EP_CONTROL:
|
|
usb_ll_clear_irq( USB_IRQ_RXOUT );
|
|
break;
|
|
case USB_EP_INTERRUPT:
|
|
case USB_EP_BULK:
|
|
case USB_EP_ISOCHRONOUS:
|
|
if (!UEBCX){
|
|
usb_ll_clear_irq( USB_IRQ_RXOUT );
|
|
UEINTX &= ~_BV(FIFOCON);
|
|
} else {
|
|
usb_ll_disable_irq( USB_IRQ_RXOUT );
|
|
};
|
|
break;
|
|
};
|
|
};
|
|
|
|
void usb_irq_endpoint_nakin(uint8_t endpoint){
|
|
uint8_t ep_type;
|
|
usb_ll_endpoint_select( endpoint );
|
|
ep_type = (UECFG0X >> EPTYPE0) & 0x03;
|
|
|
|
if (ep_type == USB_EP_CONTROL){
|
|
if (!(usb_device.endpoints[ endpoint ].request->bmRequestType & 0x80 )) {
|
|
usb_ll_clear_irq( USB_IRQ_TXIN );
|
|
usb_ll_disable_irq( USB_IRQ_RXOUT );
|
|
};
|
|
};
|
|
usb_ll_clear_irq( USB_IRQ_NAKIN );
|
|
};
|
|
|
|
void usb_irq_endpoint_setup (uint8_t endpoint){
|
|
usb_ll_endpoint_t* ep = &(usb_device.endpoints[endpoint]);
|
|
int n;
|
|
|
|
if (ep && ep->request){
|
|
n = usb_ll_endpoint_read( (uint8_t*)ep->request, sizeof( usb_device_request_t ) );
|
|
|
|
if (n == sizeof( usb_device_request_t )){
|
|
|
|
if (usb_ll_setup_request( endpoint, ep->request ) < 0){
|
|
avr_usb_endpoint_stall_request();
|
|
};
|
|
};
|
|
};
|
|
|
|
usb_ll_clear_irq( USB_IRQ_SETUP );
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void usb_ll_endpoint_disable(int endpoint){
|
|
if (endpoint >= MAX_ENDPOINTS)
|
|
return;
|
|
|
|
usb_ll_endpoint_select(endpoint);
|
|
|
|
UEIENX = 0;
|
|
|
|
UECONX &= ~_BV(EPEN);
|
|
UECFG0X = 0x00;
|
|
UECFG1X = 0x00;
|
|
|
|
if (usb_device.endpoints[endpoint].request){
|
|
usb_ll_disable_irq( USB_IRQ_SETUP );
|
|
free(usb_device.endpoints[endpoint].request);
|
|
};
|
|
|
|
usb_device.endpoints[endpoint].cb_setup = NULL;
|
|
|
|
usb_endpoint_unset_buffer( endpoint );
|
|
usb_device.endpoints[endpoint].desc = NULL;
|
|
};
|
|
|
|
void usb_ll_endpoint_enable (struct usb_standard_endpoint_descriptor* descriptor){
|
|
int nEP;
|
|
|
|
if (!descriptor)
|
|
return;
|
|
|
|
nEP = descriptor->bEndpointAddress & 0x07;
|
|
|
|
if (nEP > MAX_ENDPOINTS)
|
|
return;
|
|
|
|
usb_ll_endpoint_select(nEP);
|
|
|
|
UECONX &= ~_BV(EPEN);
|
|
UECONX |= _BV(EPEN);
|
|
|
|
UERST |= _BV(nEP);
|
|
UERST &= ~_BV(nEP);
|
|
|
|
UEIENX = 0;
|
|
|
|
usb_device.endpoints[nEP].desc = descriptor;
|
|
|
|
UECFG0X = ((descriptor->bEndpointAddress & 0x80) ? 0x01 : 0x00) |
|
|
((descriptor->bmAttributes & 0x03) << EPTYPE0);
|
|
|
|
UECFG1X = (usb_ll_ep_find_size_index( descriptor->wMaxPacketSize ) << 4);
|
|
UECFG1X |= _BV(ALLOC);
|
|
|
|
if ((UECFG0X & (_BV(EPTYPE1)|_BV(EPTYPE0))) == 0){
|
|
usb_device.endpoints[nEP].request = malloc( sizeof(usb_device_request_t ) );
|
|
usb_ll_enable_irq( USB_IRQ_SETUP );
|
|
} else {
|
|
|
|
};
|
|
|
|
if (UESTA0X & _BV(CFGOK)){
|
|
return;
|
|
} else {
|
|
return;
|
|
};
|
|
};
|