summaryrefslogtreecommitdiff
path: root/firmware/src/os
diff options
context:
space:
mode:
authorlaforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-09-20 11:44:10 +0000
committerlaforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-09-20 11:44:10 +0000
commit514b0f72f50b50b75ef855f008c888f29989d68e (patch)
tree4a48031e2d2e95512ae3dc868301b5314c317081 /firmware/src/os
parent20b657d7d20508b2a5fedf2e7a59a30e3d9a2fa4 (diff)
- Add OpenPICC register definition (and USB command handling)
- Add automatic generation of include/compile.h with svn revision and compiletime - Add openpcd_compile_version structure to obtain version via USB - Move LED commands into new CMD_CLS_GENERIC family - Update TODO - Add support for large (2048 byte) request contexts in addition to 64byte - Shrink req_ctx size by collapsing rx and tx buffer into one - move definition of DFU_API_LOCATION to header file - Implement large req_ctx aware USB transmit / refill routines - Implement TX refilling for IRQ Endpoint - Print version information at startup time - move some generic req_ctx processing into usb_handler.c - Some further work on DFU (still not finished) - Only use '-Os' for DFU, use '-O2' for application code git-svn-id: https://svn.openpcd.org:2342/trunk@208 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'firmware/src/os')
-rw-r--r--firmware/src/os/dbgu.c8
-rw-r--r--firmware/src/os/led.c21
-rw-r--r--firmware/src/os/main.c12
-rw-r--r--firmware/src/os/main.h1
-rw-r--r--firmware/src/os/pcd_enumerate.c93
-rw-r--r--firmware/src/os/pcd_enumerate.h7
-rw-r--r--firmware/src/os/pio_irq.c11
-rw-r--r--firmware/src/os/pwm.c7
-rw-r--r--firmware/src/os/req_ctx.c37
-rw-r--r--firmware/src/os/req_ctx.h16
-rw-r--r--firmware/src/os/usb_benchmark.c11
-rw-r--r--firmware/src/os/usb_handler.c42
-rw-r--r--firmware/src/os/usb_handler.h10
-rw-r--r--firmware/src/os/usbcmd_generic.c49
-rw-r--r--firmware/src/os/usbcmd_generic.h4
15 files changed, 234 insertions, 95 deletions
diff --git a/firmware/src/os/dbgu.c b/firmware/src/os/dbgu.c
index f7c62e3..eed5546 100644
--- a/firmware/src/os/dbgu.c
+++ b/firmware/src/os/dbgu.c
@@ -139,7 +139,13 @@ void AT91F_DBGU_Init(void)
DBGU_irq_handler);
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS);
- AT91F_DBGU_Printk
+ AT91F_DBGU_Printk("\n\r");
+ AT91F_DBGU_Printk(opcd_version.svnrev);
+ AT91F_DBGU_Printk(" ");
+ AT91F_DBGU_Printk(opcd_version.date);
+ AT91F_DBGU_Printk(" ");
+ AT91F_DBGU_Printk(opcd_version.by);
+ AT91F_DBGU_Printk("\n\r");
("\n\r-I- OpenPCD test mode\n\r 0) Set Pull-up 1) Clear Pull-up "
"2) Toggle LED1 3) Toggle LED2 4) Test RC632\n\r"
"5) Read RxWait 6) Write RxWait 7) Dump RC632 Regs\n\r");
diff --git a/firmware/src/os/led.c b/firmware/src/os/led.c
index 30353ac..96ffecc 100644
--- a/firmware/src/os/led.c
+++ b/firmware/src/os/led.c
@@ -73,31 +73,10 @@ int led_toggle(int led)
return !on;
}
-static int led_usb_rx(struct req_ctx *rctx)
-{
- struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0];
- int ret = 1;
-
- switch (poh->cmd) {
- case OPENPCD_CMD_SET_LED:
- DEBUGP("SET LED(%u,%u) ", poh->reg, poh->val);
- led_switch(poh->reg, poh->val);
- break;
- default:
- DEBUGP("UNKNOWN ");
- ret = -EINVAL;
- break;
- }
- req_ctx_put(rctx);
- return 1;
-}
-
void led_init(void)
{
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1);
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2);
led_switch(1, 0);
led_switch(2, 0);
-
- usb_hdlr_register(&led_usb_rx, OPENPCD_CMD_CLS_LED);
}
diff --git a/firmware/src/os/main.c b/firmware/src/os/main.c
index 3e05a7d..ce611bc 100644
--- a/firmware/src/os/main.c
+++ b/firmware/src/os/main.c
@@ -24,9 +24,18 @@
#include <os/led.h>
#include <os/main.h>
#include <os/power.h>
+#include <os/usbcmd_generic.h>
#include <os/pcd_enumerate.h>
#include "../openpcd.h"
+#include <compile.h>
+
+const struct openpcd_compile_version opcd_version = {
+ .svnrev = COMPILE_SVNREV,
+ .date = COMPILE_DATE,
+ .by = COMPILE_BY,
+};
+
int main(void)
{
/* initialize LED and debug unit */
@@ -34,10 +43,13 @@ int main(void)
AT91F_DBGU_Init();
AT91F_PIOA_CfgPMC();
+
/* call application specific init function */
_init_func();
/* initialize USB */
+ req_ctx_init();
+ usbcmd_gen_init();
udp_open();
// Enable User Reset and set its minimal assertion to 960 us
diff --git a/firmware/src/os/main.h b/firmware/src/os/main.h
index 1adc8f6..bd42341 100644
--- a/firmware/src/os/main.h
+++ b/firmware/src/os/main.h
@@ -5,4 +5,5 @@ extern void _init_func(void);
extern int _main_dbgu(char key);
extern void _main_func(void);
+extern const struct openpcd_compile_version opcd_version;
#endif
diff --git a/firmware/src/os/pcd_enumerate.c b/firmware/src/os/pcd_enumerate.c
index 1f35b06..e3443a8 100644
--- a/firmware/src/os/pcd_enumerate.c
+++ b/firmware/src/os/pcd_enumerate.c
@@ -52,7 +52,6 @@
#define AT91C_EP_INT 3
#ifdef CONFIG_DFU
-#define DFU_API_LOCATION ((const struct dfuapi *) 0x00100fd0)
static const struct dfuapi *dfu = DFU_API_LOCATION;
#define udp_init dfu->udp_init
#define udp_ep0_send_data dfu->ep0_send_data
@@ -167,32 +166,64 @@ void udp_unthrottle(void)
pUDP->UDP_IER = AT91C_UDP_EPINT1;
}
-int udp_refill_ep(int ep, struct req_ctx *rctx)
+int udp_refill_ep(int ep)
{
u_int16_t i;
AT91PS_UDP pUDP = upcd.pUdp;
+ struct req_ctx *rctx;
+ unsigned int start, end;
+ /* If we're not configured by the host yet, there is no point
+ * in trying to send data to it... */
if (!upcd.cur_config)
return -ENXIO;
- if (rctx->tx.tot_len > AT91C_EP_IN_SIZE) {
- DEBUGPCRF("TOO LARGE!!!!!!!!!!!!!!!!!!!!!!!!!!! (%d > %d)",
- rctx->tx.tot_len, AT91C_EP_IN_SIZE);
- return -EINVAL;
- }
-
+ /* If there are already two packets in transit, the DPR of
+ * the SAM7 UDC doesn't have space for more data */
if (atomic_read(&upcd.ep[ep].pkts_in_transit) == 2)
return -EBUSY;
-
+
+ /* If we have an incompletely-transmitted req_ctx (>EP size),
+ * we need to transmit the rest and finish the transaction */
+ if (upcd.ep[ep].incomplete.rctx) {
+ rctx = upcd.ep[ep].incomplete.rctx;
+ start = upcd.ep[ep].incomplete.bytes_sent;
+ } else {
+ unsigned int state, state_busy;
+ if (ep == 2) {
+ state = RCTX_STATE_UDP_EP2_PENDING;
+ state_busy = RCTX_STATE_UDP_EP2_BUSY;
+ } else {
+ state = RCTX_STATE_UDP_EP3_PENDING;
+ state_busy = RCTX_STATE_UDP_EP3_BUSY;
+ }
+
+ /* get pending rctx and start transmitting from zero */
+ rctx = req_ctx_find_get(0, state, state_busy);
+ if (!rctx)
+ return 0;
+ start = 0;
+ }
+
+ if (rctx->tot_len - start <= AT91C_EP_IN_SIZE)
+ end = rctx->tot_len;
+ else
+ end = AT91C_EP_IN_SIZE;
+
/* fill FIFO/DPR */
- for (i = 0; i < rctx->tx.tot_len; i++)
- pUDP->UDP_FDR[ep] = rctx->tx.data[i];
+ for (i = start; i < end; i++)
+ pUDP->UDP_FDR[ep] = rctx->data[i];
if (atomic_inc_return(&upcd.ep[ep].pkts_in_transit) == 1) {
/* not been transmitting before, start transmit */
pUDP->UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
}
+ /* Increment the number of bytes sent in the current large
+ * context, if any */
+ if (start != 0)
+ upcd.ep[ep].incomplete.bytes_sent += end-start;
+
/* return rctx to pool of free contexts */
req_ctx_put(rctx);
@@ -257,19 +288,21 @@ 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(RCTX_STATE_FREE,
- RCTX_STATE_UDP_RCV_BUSY);
+ struct req_ctx *rctx =
+ req_ctx_find_get(0, RCTX_STATE_FREE,
+ RCTX_STATE_UDP_RCV_BUSY);
if (rctx) {
- rctx->rx.tot_len = pkt_size;
+ rctx->tot_len = pkt_size;
while (pkt_size--)
- rctx->rx.data[pkt_recv++] = pUDP->UDP_FDR[1];
+ rctx->data[pkt_recv++] = pUDP->UDP_FDR[1];
pUDP->UDP_CSR[1] &= ~cur_rcv_bank;
if (cur_rcv_bank == AT91C_UDP_RX_DATA_BK0)
cur_rcv_bank = AT91C_UDP_RX_DATA_BK1;
else
cur_rcv_bank = AT91C_UDP_RX_DATA_BK0;
upcd.cur_rcv_bank = cur_rcv_bank;
+ DEBUGI("rctxdump(%s) ", hexdump(rctx->data, rctx->tot_len));
req_ctx_set_state(rctx, RCTX_STATE_UDP_RCV_DONE);
DEBUGI("RCTX=%u ", req_ctx_num(rctx));
} else {
@@ -283,8 +316,6 @@ static void udp_irq(void)
csr = pUDP->UDP_CSR[2];
DEBUGI("EP2INT(In, CSR=0x%08x) ", csr);
if (csr & AT91C_UDP_TXCOMP) {
- struct req_ctx *rctx;
-
DEBUGI("ACK_TX_COMP ");
/* acknowledge TX completion */
pUDP->UDP_CSR[2] &= ~AT91C_UDP_TXCOMP;
@@ -294,21 +325,24 @@ static void udp_irq(void)
if (atomic_dec_return(&upcd.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
- DEBUGI("NO_RCTX_pending ");
+ udp_refill_ep(2);
}
}
if (isr & AT91C_UDP_EPINT3) {
csr = pUDP->UDP_CSR[3];
DEBUGI("EP3INT(Interrupt, CSR=0x%08x) ", csr);
/* Transmit has completed, re-fill from pending rcts for EP3 */
- }
+ if (csr & AT91C_UDP_TXCOMP) {
+ pUDP->UDP_CSR[3] &= ~AT91C_UDP_TXCOMP;
+ while (pUDP->UDP_CSR[3] & AT91C_UDP_TXCOMP) ;
+ /* if we already have another packet in DPR, send it */
+ if (atomic_dec_return(&upcd.ep[3].pkts_in_transit) == 1)
+ pUDP->UDP_CSR[3] |= AT91C_UDP_TXPKTRDY;
+
+ udp_refill_ep(3);
+ }
+ }
if (isr & AT91C_UDP_RXSUSP) {
pUDP->UDP_ICR = AT91C_UDP_RXSUSP;
DEBUGI("RXSUSP ");
@@ -424,6 +458,7 @@ static void udp_ep0_handler(void)
pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP;
while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ;
+ DEBUGE("dfu_state = %u ", *dfu->dfu_state);
/* Handle supported standard device request Cf Table 9-3 in USB
* speciication Rev 1.1 */
switch ((bRequest << 8) | bmRequestType) {
@@ -465,6 +500,10 @@ static void udp_ep0_handler(void)
udp_ep0_send_stall();
break;
}
+ } else if (wValue == 0x2100) {
+ /* Return Function descriptor */
+ udp_ep0_send_data((const char *) &dfu->dfu_cfg_descriptor->func_dfu,
+ MIN(sizeof(dfu->dfu_cfg_descriptor->func_dfu), wLength));
#if 0
} else if (wValue == 0x400) {
/* Return Interface descriptor */
@@ -581,7 +620,7 @@ static void udp_ep0_handler(void)
pUDP->UDP_RSTEP &= ~AT91C_UDP_EP2;
/* free all currently transmitting contexts */
- while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_BUSY,
+ while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP2_BUSY,
RCTX_STATE_FREE)) {}
atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0);
}
@@ -593,7 +632,7 @@ static void udp_ep0_handler(void)
pUDP->UDP_RSTEP &= ~AT91C_UDP_EP3;
/* free all currently transmitting contexts */
- while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_BUSY,
+ while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP3_BUSY,
RCTX_STATE_FREE)) {}
atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0);
}
diff --git a/firmware/src/os/pcd_enumerate.h b/firmware/src/os/pcd_enumerate.h
index 813243e..3b95de7 100644
--- a/firmware/src/os/pcd_enumerate.h
+++ b/firmware/src/os/pcd_enumerate.h
@@ -10,13 +10,16 @@
struct req_ctx;
extern void udp_open(void);
-extern int udp_refill_ep(int ep, struct req_ctx *rctx);
+extern int udp_refill_ep(int ep);
extern void udp_unthrottle(void);
extern void udp_reset(void);
struct ep_ctx {
atomic_t pkts_in_transit;
- void *ctx;
+ struct {
+ struct req_ctx *rctx;
+ unsigned int bytes_sent;
+ } incomplete;
};
struct udp_pcd {
diff --git a/firmware/src/os/pio_irq.c b/firmware/src/os/pio_irq.c
index dfe818c..14f51c2 100644
--- a/firmware/src/os/pio_irq.c
+++ b/firmware/src/os/pio_irq.c
@@ -50,7 +50,7 @@ static void pio_irq_demux(void)
if (send_usb && !pirqs.usb_throttled) {
struct req_ctx *irq_rctx;
- irq_rctx = req_ctx_find_get(RCTX_STATE_FREE,
+ irq_rctx = req_ctx_find_get(0, RCTX_STATE_FREE,
RCTX_STATE_PIOIRQ_BUSY);
if (!irq_rctx) {
/* we cannot disable the interrupt, since we have
@@ -59,14 +59,14 @@ static void pio_irq_demux(void)
} else {
struct openpcd_hdr *opcdh;
u_int32_t *regmask;
- opcdh = (struct openpcd_hdr *) &irq_rctx->tx.data[0];
- regmask = (u_int32_t *) (&irq_rctx->tx.data[0] + sizeof(*opcdh));
+ opcdh = (struct openpcd_hdr *) irq_rctx->data;
+ regmask = (u_int32_t *) (irq_rctx->data + sizeof(*opcdh));
opcdh->cmd = OPENPCD_CMD_PIO_IRQ;
opcdh->reg = 0x00;
opcdh->flags = 0x00;
opcdh->val = 0x00;
- irq_rctx->tx.tot_len = sizeof(*opcdh) + sizeof(u_int32_t);
+ irq_rctx->tot_len = sizeof(*opcdh) + sizeof(u_int32_t);
req_ctx_set_state(irq_rctx, RCTX_STATE_UDP_EP3_PENDING);
}
}
@@ -116,8 +116,7 @@ void pio_irq_unregister(u_int32_t pio)
static int pio_irq_usb_in(struct req_ctx *rctx)
{
- struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0];
- struct openpcd_hdr *pih = (struct openpcd_hdr *) &rctx->tx.data[0];
+ struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data;
switch (poh->cmd) {
case OPENPCD_CMD_PIO_IRQ:
diff --git a/firmware/src/os/pwm.c b/firmware/src/os/pwm.c
index 5c52ee6..285f4e7 100644
--- a/firmware/src/os/pwm.c
+++ b/firmware/src/os/pwm.c
@@ -119,8 +119,7 @@ void pwm_duty_set_percent(int channel, u_int16_t duty)
static int pwm_usb_in(struct req_ctx *rctx)
{
- struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0];
- /* struct openpcd_hdr *pih = (struct openpcd_hdr *) &rctx->tx.data[0]; */
+ struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data;
u_int32_t *freq;
switch (poh->cmd) {
@@ -137,7 +136,7 @@ static int pwm_usb_in(struct req_ctx *rctx)
goto respond;
break;
case OPENPCD_CMD_PWM_FREQ_SET:
- if (rctx->rx.tot_len < sizeof(*poh)+4)
+ if (rctx->tot_len < sizeof(*poh)+4)
break;
freq = (unsigned char *) poh + sizeof(*poh);
pwm_freq_set(0, *freq);
@@ -153,7 +152,7 @@ static int pwm_usb_in(struct req_ctx *rctx)
return 0;
respond:
req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING);
- udp_refill_ep(2, rctx);
+ udp_refill_ep(2);
return 1;
}
diff --git a/firmware/src/os/req_ctx.c b/firmware/src/os/req_ctx.c
index d118aca..fef7258 100644
--- a/firmware/src/os/req_ctx.c
+++ b/firmware/src/os/req_ctx.c
@@ -28,14 +28,32 @@
/* FIXME: locking, FIFO order processing */
+#define RCTX_SIZE_LARGE 2048
+#define RCTX_SIZE_SMALL 64
+
+#define NUM_RCTX_SMALL 8
+#define NUM_RCTX_LARGE 3
+
+#define NUM_REQ_CTX (NUM_RCTX_SMALL+NUM_RCTX_LARGE)
+
+static u_int8_t rctx_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL];
+static u_int8_t rctx_data_large[NUM_RCTX_LARGE][RCTX_SIZE_LARGE];
+
static struct req_ctx req_ctx[NUM_REQ_CTX];
-struct req_ctx *req_ctx_find_get(unsigned long old_state, unsigned long new_state)
+struct req_ctx *req_ctx_find_get(int large,
+ unsigned long old_state,
+ unsigned long new_state)
{
unsigned long flags;
u_int8_t i;
+
+ if (large)
+ i = NUM_RCTX_SMALL;
+ else
+ i = 0;
- for (i = 0; i < NUM_REQ_CTX; i++) {
+ for (1; i < NUM_REQ_CTX; i++) {
local_irq_save(flags);
if (req_ctx[i].state == old_state) {
req_ctx[i].state = new_state;
@@ -67,3 +85,18 @@ void req_ctx_put(struct req_ctx *ctx)
{
req_ctx_set_state(ctx, RCTX_STATE_FREE);
}
+
+void req_ctx_init(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_RCTX_SMALL; i++) {
+ req_ctx[i].size = RCTX_SIZE_SMALL;
+ req_ctx[i].data = rctx_data[i];
+ }
+
+ for (i = 0; i < NUM_RCTX_LARGE; i++) {
+ req_ctx[i].size = RCTX_SIZE_LARGE;
+ req_ctx[NUM_RCTX_SMALL+i].data = rctx_data_large[i];
+ }
+}
diff --git a/firmware/src/os/req_ctx.h b/firmware/src/os/req_ctx.h
index 82a133f..b68fb66 100644
--- a/firmware/src/os/req_ctx.h
+++ b/firmware/src/os/req_ctx.h
@@ -9,18 +9,11 @@
#include <sys/types.h>
-struct req_buf {
- u_int16_t hdr_len;
- u_int16_t tot_len;
- u_int8_t data[64];
-};
-
struct req_ctx {
- u_int16_t seq; /* request sequence number */
- u_int16_t flags;
volatile u_int32_t state;
- struct req_buf rx;
- struct req_buf tx;
+ u_int16_t size;
+ u_int16_t tot_len;
+ u_int8_t *data;
};
#define RCTX_STATE_FREE 0x00
@@ -39,8 +32,7 @@ struct req_ctx {
#define RCTX_STATE_PIOIRQ_BUSY 0x80
-#define NUM_REQ_CTX 8
-extern struct req_ctx *req_ctx_find_get(unsigned long old_state, unsigned long new_state);
+extern struct req_ctx *req_ctx_find_get(int large, unsigned long old_state, unsigned long new_state);
extern struct req_ctx *req_ctx_find_busy(void);
extern void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state);
extern void req_ctx_put(struct req_ctx *ctx);
diff --git a/firmware/src/os/usb_benchmark.c b/firmware/src/os/usb_benchmark.c
index 1f890bf..bfc6b37 100644
--- a/firmware/src/os/usb_benchmark.c
+++ b/firmware/src/os/usb_benchmark.c
@@ -33,6 +33,8 @@ static void usbtest_tx_transfer(unsigned int num_pkts)
{
unsigned int i;
+#if 0
+#warning please reimplement refill userspecified rctx
for (i = 0; i < num_pkts; i++) {
/* send 16 packets of 64byte */
while (udp_refill_ep(2, &dummy_rctx) < 0)
@@ -41,11 +43,12 @@ static void usbtest_tx_transfer(unsigned int num_pkts)
/* send one packet of 0 byte */
while (udp_refill_ep(2, &empty_rctx) < 0)
;
+#endif
}
static int usbtest_rx(struct req_ctx *rctx)
{
- struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0];
+ struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data;
int i;
switch (poh->cmd) {
@@ -67,10 +70,10 @@ static int usbtest_rx(struct req_ctx *rctx)
void usbtest_init(void)
{
- dummy_rctx.tx.tot_len = 64;
- memset(dummy_rctx.tx.data, 0x23, 64);
+ dummy_rctx.tot_len = 64;
+ memset(dummy_rctx.data, 0x23, 64);
- empty_rctx.tx.tot_len = 0;
+ empty_rctx.tot_len = 0;
usb_hdlr_register(&usbtest_rx, OPENPCD_CMD_CLS_USBTEST);
}
diff --git a/firmware/src/os/usb_handler.c b/firmware/src/os/usb_handler.c
index 6c45e18..c3d4cfa 100644
--- a/firmware/src/os/usb_handler.c
+++ b/firmware/src/os/usb_handler.c
@@ -46,23 +46,33 @@ void usb_hdlr_unregister(u_int8_t class)
static int usb_in(struct req_ctx *rctx)
{
- struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0];
- struct openpcd_hdr *pih = (struct openpcd_hdr *) &rctx->tx.data[0];
+ struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data;
usb_cmd_fn *hdlr;
+ int ret;
DEBUGP("usb_in(cls=%d) ", OPENPCD_CMD_CLS(poh->cmd));
- if (rctx->rx.tot_len < sizeof(*poh))
+ if (rctx->tot_len < sizeof(*poh))
return -EINVAL;
- memcpy(pih, poh, sizeof(*poh));
- rctx->tx.tot_len = sizeof(*poh);
-
hdlr = cmd_hdlrs[OPENPCD_CMD_CLS(poh->cmd)];
- if (hdlr)
- return (hdlr)(rctx);
- else
- DEBUGPCR("no handler for this class\n");
+ if (!hdlr) {
+ DEBUGPCR("no handler for this class ");
+ ret = USB_ERR(USB_ERR_CMD_UNKNOWN);
+ } else
+ ret = (hdlr)(rctx);
+
+ if (ret & USB_RET_ERR) {
+ poh->val = ret & 0xff;
+ poh->flags = OPENPCD_FLAG_ERROR;
+ }
+ if (ret & USB_RET_RESPOND) {
+ req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING);
+ udp_refill_ep(2);
+ }
+
+ DEBUGPCR("");
+ return (ret & USB_RET_ERR) ? 1 : 0;
}
/* Process all pending request contexts that want to Tx on either
@@ -71,17 +81,17 @@ void usb_out_process(void)
{
struct req_ctx *rctx;
- while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_PENDING,
+ while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP3_PENDING,
RCTX_STATE_UDP_EP3_BUSY)) {
DEBUGPCRF("EP3_BUSY for ctx %u", req_ctx_num(rctx));
- if (udp_refill_ep(3, rctx) < 0)
+ if (udp_refill_ep(3) < 0)
req_ctx_set_state(rctx, RCTX_STATE_UDP_EP3_PENDING);
}
- while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_PENDING,
+ while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP2_PENDING,
RCTX_STATE_UDP_EP2_BUSY)) {
DEBUGPCRF("EP2_BUSY for ctx %u", req_ctx_num(rctx));
- if (udp_refill_ep(2, rctx) < 0)
+ if (udp_refill_ep(2) < 0)
req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING);
}
}
@@ -92,10 +102,10 @@ void usb_in_process(void)
{
struct req_ctx *rctx;
- while (rctx = req_ctx_find_get(RCTX_STATE_UDP_RCV_DONE,
+ while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_RCV_DONE,
RCTX_STATE_MAIN_PROCESSING)) {
DEBUGPCRF("found used ctx %u: len=%u",
- req_ctx_num(rctx), rctx->rx.tot_len);
+ req_ctx_num(rctx), rctx->tot_len);
usb_in(rctx);
}
udp_unthrottle();
diff --git a/firmware/src/os/usb_handler.h b/firmware/src/os/usb_handler.h
index 3efcc1f..9d5ad48 100644
--- a/firmware/src/os/usb_handler.h
+++ b/firmware/src/os/usb_handler.h
@@ -6,6 +6,16 @@
#define MAX_PAYLOAD_LEN (64 - sizeof(struct openpcd_hdr))
+#define USB_RET_RESPOND (1 << 8)
+#define USB_RET_ERR (2 << 8)
+#define USB_ERR(x) (USB_RET_RESPOND|USB_RET_ERR|(x & 0xff))
+
+enum usbapi_err {
+ USB_ERR_NONE,
+ USB_ERR_CMD_UNKNOWN,
+ USB_ERR_CMD_NOT_IMPL,
+};
+
typedef int usb_cmd_fn(struct req_ctx *rctx);
extern int usb_hdlr_register(usb_cmd_fn *hdlr, u_int8_t class);
diff --git a/firmware/src/os/usbcmd_generic.c b/firmware/src/os/usbcmd_generic.c
new file mode 100644
index 0000000..9dec14e
--- /dev/null
+++ b/firmware/src/os/usbcmd_generic.c
@@ -0,0 +1,49 @@
+/* Some generel USB API commands, common between OpenPCD and OpenPICC
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <openpcd.h>
+#include <os/req_ctx.h>
+#include <os/usb_handler.h>
+#include <os/led.h>
+#include <os/dbgu.h>
+#include <os/main.h>
+
+static int gen_usb_rx(struct req_ctx *rctx)
+{
+ struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data;
+ struct openpcd_compile_version *ver =
+ (struct openpcd_compile_version *) poh->data;
+ int ret = 1;
+
+ rctx->tot_len = sizeof(*poh);
+
+ switch (poh->cmd) {
+ case OPENPCD_CMD_GET_VERSION:
+ DEBUGP("GET_VERSION ");
+ memcpy(ver, &opcd_version, sizeof(*ver));
+ rctx->tot_len += sizeof(*ver);
+ poh->flags |= OPENPCD_FLAG_RESPOND;
+ break;
+ case OPENPCD_CMD_SET_LED:
+ DEBUGP("SET LED(%u,%u) ", poh->reg, poh->val);
+ led_switch(poh->reg, poh->val);
+ break;
+ default:
+ DEBUGP("UNKNOWN ");
+ return USB_ERR(USB_ERR_CMD_UNKNOWN);
+ break;
+ }
+
+ if (poh->flags & OPENPCD_FLAG_RESPOND)
+ return USB_RET_RESPOND;
+ return 0;
+}
+
+void usbcmd_gen_init(void)
+{
+ usb_hdlr_register(&gen_usb_rx, OPENPCD_CMD_CLS_GENERIC);
+}
+
diff --git a/firmware/src/os/usbcmd_generic.h b/firmware/src/os/usbcmd_generic.h
new file mode 100644
index 0000000..0a7b8b7
--- /dev/null
+++ b/firmware/src/os/usbcmd_generic.h
@@ -0,0 +1,4 @@
+#ifndef _USBAPI_GENERIC_H
+#define _USBAPI_GENERIC_H
+extern void usbcmd_gen_init(void);
+#endif
personal git repositories of Harald Welte. Your mileage may vary