diff options
| author | (no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-07-30 10:17:48 +0000 | 
|---|---|---|
| committer | (no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-07-30 10:17:48 +0000 | 
| commit | fa5c8c7c635a99453c8b6f7e0ff7e970285d83f5 (patch) | |
| tree | 85c0d2c0bb2bbbde065728e7f75ebec6f19263f1 | |
| parent | 628c6776c9a4736fdb434a597ccccf602ef90c39 (diff) | |
implement new request context and interrupt handling
git-svn-id: https://svn.openpcd.org:2342/trunk@61 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
| -rw-r--r-- | openpcd/firmware/src/pcd_enumerate.c | 111 | ||||
| -rw-r--r-- | openpcd/firmware/src/pcd_enumerate.h | 15 | 
2 files changed, 115 insertions, 11 deletions
| diff --git a/openpcd/firmware/src/pcd_enumerate.c b/openpcd/firmware/src/pcd_enumerate.c index 80926bc..dd0ba48 100644 --- a/openpcd/firmware/src/pcd_enumerate.c +++ b/openpcd/firmware/src/pcd_enumerate.c @@ -18,6 +18,7 @@  // 12. Apr. 2006: added modification found in the mikrocontroller.net gcc-Forum   //                additional line marked with /* +++ */ +#include <errno.h>  #include <sys/types.h>  #include <usb_ch9.h>  #include <lib_AT91SAM7.h> @@ -129,6 +130,44 @@ const struct _desc cfgDescriptor = {  static void udp_ep0_handler(void); +void udp_unthrottle(void) +{ +	AT91PS_UDP pUDP = pCDC.pUdp; +	pUDP->UDP_IER = AT91C_UDP_EPINT1; +} + +int udp_refill_ep(int ep, struct req_ctx *rctx) +{ +	u_int16_t i; +	AT91PS_UDP pUDP = pCDC.pUdp; + +	if (rctx->tx.tot_len > 64) { +		DEBUGPCRF("TOO LARGE!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); +		return -EINVAL; +	} + +	DEBUGP("refilling EP%u ", ep); + +	/* FIXME: state machine to handle two banks of FIFO memory, etc */ +	if (atomic_read(&pCDC.ep[ep].pkts_in_transit) >= 2) +		return -EBUSY; +		 +	/* fill FIFO/DPR */ +	for (i = 0; i < rctx->tx.tot_len; i++)  +		pUDP->UDP_FDR[ep] = rctx->tx.data[i]; + +	if (atomic_read(&pCDC.ep[ep].pkts_in_transit) == 0) { +		/* start transmit */ +		pUDP->UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY; +		atomic_inc(&pCDC.ep[ep].pkts_in_transit); +	} +	 +	/* return rctx to pool of free contexts */ +	req_ctx_put(rctx); + +	return 0; +} +  static void udp_irq(void)  {  	u_int32_t csr; @@ -174,7 +213,8 @@ static void udp_irq(void)  		if (csr & cur_rcv_bank) {  			u_int16_t pkt_recv = 0;  			u_int16_t pkt_size = csr >> 16; -			struct req_ctx *rctx = req_ctx_find_get(); +			struct req_ctx *rctx = req_ctx_find_get(RCTX_STATE_FREE, +								RCTX_STATE_UDP_RCV_BUSY);  			if (rctx) {  				rctx->rx.tot_len = pkt_size; @@ -190,32 +230,61 @@ static void udp_irq(void)  				DEBUGP(rctx->rx.data);  #endif  				pCDC.currentRcvBank = cur_rcv_bank; -			} else -				DEBUGP("NO RCTX AVAIL! "); +				req_ctx_set_state(rctx, RCTX_STATE_UDP_RCV_DONE); +				DEBUGP("RCTX=%u ", req_ctx_num(rctx)); +			} else { +				/* disable interrupts for now */ +				pUDP->UDP_IDR = AT91C_UDP_EPINT1; +				DEBUGP("NO_RCTX_AVAIL! "); +			}  		}  	}  	if (isr & AT91C_UDP_EPINT2) {  		csr = pUDP->UDP_CSR[2]; -		//pUDP->UDP_ICR = AT91C_UDP_EPINT2; -		DEBUGP("EP2INT(In) "); +		DEBUGP("EP2INT(In, CSR=0x%08x) ", csr); +		if (csr & AT91C_UDP_TXCOMP) { +			struct req_ctx *rctx; + +			DEBUGP("ACK_TX_COMP "); +			/* acknowledge TX completion */ +			pUDP->UDP_CSR[2] &= ~AT91C_UDP_TXCOMP; +			while (pUDP->UDP_CSR[2] & AT91C_UDP_TXCOMP) ; + +			/* if we already have another packet in DPR, send it */ +			if (atomic_dec_return(&pCDC.ep[2].pkts_in_transit) == 1) +				pUDP->UDP_CSR[2] |= AT91C_UDP_TXPKTRDY; + +			/* try to re-fill from pending rcts for EP2 */ +			rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_PENDING, +						RCTX_STATE_UDP_EP2_BUSY); +			if (rctx) +				udp_refill_ep(2, rctx); +			else +				DEBUGP("NO_RCTX_pending "); + +			/* FIXME: re-fill second packet into DPR */ +		}  	}  	if (isr & AT91C_UDP_EPINT3) {  		csr = pUDP->UDP_CSR[3]; -		//pUDP->UDP_ICR = AT91C_UDP_EPINT3; -		DEBUGP("EP3INT(Interrupt) "); +		DEBUGP("EP3INT(Interrupt, CSR=0x%08x) ", csr); +		/* Transmit has completed, re-fill from pending rcts for EP3 */  	}  	if (isr & AT91C_UDP_RXSUSP) {  		pUDP->UDP_ICR = AT91C_UDP_RXSUSP;  		DEBUGP("RXSUSP "); +		/* FIXME: implement suspend/resume */  	}  	if (isr & AT91C_UDP_RXRSM) {  		pUDP->UDP_ICR = AT91C_UDP_RXRSM;  		DEBUGP("RXRSM "); +		/* FIXME: implement suspend/resume */  	}  	if (isr & AT91C_UDP_EXTRSM) {  		pUDP->UDP_ICR = AT91C_UDP_EXTRSM;  		DEBUGP("EXTRSM "); +		/* FIXME: implement suspend/resume */  	}  	if (isr & AT91C_UDP_SOFINT) {  		pUDP->UDP_ICR = AT91C_UDP_SOFINT; @@ -224,6 +293,7 @@ static void udp_irq(void)  	if (isr & AT91C_UDP_WAKEUP) {  		pUDP->UDP_ICR = AT91C_UDP_WAKEUP;  		DEBUGP("WAKEUP "); +		/* FIXME: implement suspend/resume */  	}  	DEBUGP("END\r\n"); @@ -276,6 +346,7 @@ u_int8_t udp_is_configured(void)  	return pCdc->currentConfiguration;  } +  /* Send data through endpoint 2/3 */  u_int32_t AT91F_UDP_Write(u_int8_t irq, const unsigned char *pData, u_int32_t length)  { @@ -394,8 +465,21 @@ static void udp_ep0_handler(void)  	AT91PS_UDP pUDP = pCdc->pUdp;  	u_int8_t bmRequestType, bRequest;  	u_int16_t wValue, wIndex, wLength, wStatus; +	u_int32_t csr = pUDP->UDP_CSR[0]; + +	DEBUGP("CSR=0x%04x ", csr); -	if (!(pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) { +	if (csr & AT91C_UDP_STALLSENT) { +		DEBUGP("ACK_STALLSENT "); +		pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT; +	} + +	if (csr & AT91C_UDP_RX_DATA_BK0) { +		DEBUGP("ACK_BANK0 "); +		pUDP->UDP_CSR[0] = ~AT91C_UDP_RX_DATA_BK0; +	} + +	if (!(csr & AT91C_UDP_RXSETUP)) {  		DEBUGP("no setup packet ");  		return;  	} @@ -451,7 +535,7 @@ static void udp_ep0_handler(void)  		pUDP->UDP_CSR[3] =  		    (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;  		pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1| -				  0);//AT91C_UDP_EPINT2|AT91C_UDP_EPINT3); +				 AT91C_UDP_EPINT2|AT91C_UDP_EPINT3);  		break;  	case STD_GET_CONFIGURATION:  		DEBUGP("GET_CONFIG "); @@ -516,6 +600,7 @@ static void udp_ep0_handler(void)  		DEBUGP("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f);  		wIndex &= 0x0F;  		if ((wValue == 0) && wIndex && (wIndex <= 3)) { +			struct req_ctx *rctx;  			if (wIndex == 1) {  				pUDP->UDP_CSR[1] =  				    (AT91C_UDP_EPEDS | @@ -529,6 +614,10 @@ static void udp_ep0_handler(void)  				     AT91C_UDP_EPTYPE_BULK_IN);  				pUDP->UDP_RSTEP |= AT91C_UDP_EP2;  				pUDP->UDP_RSTEP &= ~AT91C_UDP_EP2; + +				/* free all currently transmitting contexts */ +				while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_BUSY, +							       RCTX_STATE_FREE)) {}  			}  			else if (wIndex == 3) {  				pUDP->UDP_CSR[3] = @@ -536,6 +625,10 @@ static void udp_ep0_handler(void)  				     AT91C_UDP_EPTYPE_INT_IN);  				pUDP->UDP_RSTEP |= AT91C_UDP_EP3;  				pUDP->UDP_RSTEP &= ~AT91C_UDP_EP3; + +				/* free all currently transmitting contexts */ +				while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_BUSY, +							       RCTX_STATE_FREE)) {}  			}  			udp_ep0_send_zlp(pUDP);  		} else diff --git a/openpcd/firmware/src/pcd_enumerate.h b/openpcd/firmware/src/pcd_enumerate.h index 31d8f28..d08ba65 100644 --- a/openpcd/firmware/src/pcd_enumerate.h +++ b/openpcd/firmware/src/pcd_enumerate.h @@ -17,6 +17,8 @@  #include <sys/types.h>  #include <AT91SAM7.h> +#include <asm/atomic.h> +#include "src/openpcd.h"  #define AT91C_EP_OUT 1  #define AT91C_EP_OUT_SIZE 0x40 @@ -24,6 +26,11 @@  #define AT91C_EP_IN_SIZE 0x40  #define AT91C_EP_INT  3 +struct ep_ctx { +	atomic_t pkts_in_transit; +	void *ctx; +}; +  typedef struct _AT91S_CDC  { @@ -31,14 +38,18 @@ typedef struct _AT91S_CDC  	unsigned char currentConfiguration;  	unsigned char currentConnection;  	unsigned int  currentRcvBank; -	void *ep_ctx[4]; +	struct ep_ctx ep[4];  } AT91S_CDC, *AT91PS_CDC;  //* external function description  extern void udp_init(void);  u_int8_t AT91F_UDP_IsConfigured(void); -u_int32_t AT91F_UDP_Write(u_int8_t irq, const unsigned char *pData, u_int32_t length); + +//u_int32_t AT91F_UDP_Write(u_int8_t irq, const unsigned char *pData, u_int32_t length); + +extern int udp_refill_ep(int ep, struct req_ctx *rctx); +extern void udp_unthrottle(void);  #endif // CDC_ENUMERATE_H | 
