avr-fw-modules/usb/src/usb_ll_endpoint.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;
};
};