URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [hal/] [arm/] [sa11x0/] [ipaq/] [v2_0/] [src/] [atmel_support.c] - Rev 1765
Compare with Previous | Blame | View Log
//========================================================================== // // atmel_support.c // // SA1110/iPAQ - Atmel micro-controller support routines // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. // at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas // Date: 2001-02-27 // Description: Simple Atmel support //####DESCRIPTIONEND#### #include <pkgconf/system.h> #include <pkgconf/hal.h> #ifdef CYGPKG_REDBOOT #include <redboot.h> #endif #include <cyg/infra/diag.h> #include <cyg/hal/hal_if.h> // Virtual vector functions #include <cyg/hal/hal_io.h> // IO macros #include <cyg/hal/hal_arch.h> // Register state info #include <cyg/hal/hal_intr.h> // HAL interrupt macros #include <cyg/hal/hal_sa11x0.h> // Board definitions #include <cyg/hal/ipaq.h> #include <cyg/hal/hal_cache.h> #ifdef CYGPKG_IO // Need to export interrupt driven interfaces #include <cyg/hal/drv_api.h> #define ATMEL_INT CYGNUM_HAL_INTERRUPT_UART1 static cyg_interrupt atmel_interrupt; static cyg_handle_t atmel_interrupt_handle; #endif #include <cyg/hal/atmel_support.h> // Interfaces, commands externC void *memcpy(void *, const void *, size_t); struct sa11x0_serial { volatile cyg_uint32 utcr0; volatile cyg_uint32 utcr1; volatile cyg_uint32 utcr2; volatile cyg_uint32 utcr3; volatile cyg_uint32 pad0010; volatile cyg_uint32 utdr; volatile cyg_uint32 pad0018; volatile cyg_uint32 utsr0; volatile cyg_uint32 utsr1; }; #define ATMEL_PUTQ_SIZE 32 unsigned char atmel_putq[ATMEL_PUTQ_SIZE]; int atmel_putq_put, atmel_putq_get; bool atmel_use_ints; void atmel_putc(unsigned char c) { atmel_putq[atmel_putq_put++] = c; if (atmel_putq_put == ATMEL_PUTQ_SIZE) { atmel_putq_put = 0; } } static atmel_handler *handlers[NUM_ATMEL_CMDS]; static void null_handler(atmel_pkt *pkt) { diag_printf("Atmel - packet ignored: %x\n", pkt->data[0]); diag_dump_buf(pkt->data, 16); } // // Register a handler for a particular packet type // void atmel_register(int cmd, atmel_handler *fun) { handlers[cmd] = fun; } // // This routine is called to process an input character from the // Atmel micro-controller. Since command packets are multiple // characters, this routine has to keep state for the packet. Once // a complete packet is received, the appropriate handler function // will be called (if the checksum matches) // static void atmel_in(unsigned char ch) { static atmel_pkt pkt; static unsigned char cksum; static bool sof = false; if (!sof) { // Wait for start of packet (SOF) if (ch != SOF) { return; // Just ignore out of order characters } sof = true; pkt.size = 0; return; } if (pkt.size == 0) { // First byte of packet - command+length; pkt.len = (ch & 0x0F) + 1; cksum = 0; } pkt.data[pkt.size++] = ch; if (pkt.size > pkt.len) { // End of packet data if (cksum == ch) { (*handlers[pkt.data[0] >> 4])(&pkt); } sof = false; } else { cksum += ch; } } // // This [internal] routine is used to handle data from the Atmel micro-controller // static void atmel_poll(void) { volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE; unsigned char ch; while ((base->utsr1 & SA11X0_UART_RX_FIFO_NOT_EMPTY) != 0) { ch = (char)base->utdr; atmel_in(ch); } } // // This [internal] routine is used to send data to the Atmel micro-controller // static void atmel_flush(void) { volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE; #ifdef CYGPKG_IO cyg_drv_isr_lock(); #endif while (atmel_putq_get != atmel_putq_put) { if ((base->utsr1 & SA11X0_UART_TX_FIFO_NOT_FULL) == 0) { // Wait forever if in non-interrupt mode if (atmel_use_ints) { break; } } else { base->utdr = atmel_putq[atmel_putq_get++]; if (atmel_putq_get == ATMEL_PUTQ_SIZE) { atmel_putq_get = 0; } } } #ifdef CYGPKG_IO cyg_drv_isr_unlock(); #endif } #ifdef CYGPKG_IO // Low level interrupt handler (ISR) static cyg_uint32 atmel_ISR(cyg_vector_t vector, cyg_addrword_t data) { cyg_drv_interrupt_mask(vector); cyg_drv_interrupt_acknowledge(vector); return CYG_ISR_CALL_DSR; // Cause DSR to be run } // High level interrupt handler (DSR) static void atmel_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) { volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE; unsigned int stat0 = base->utsr0; if (stat0 & SA11X0_UART_TX_SERVICE_REQUEST) { atmel_flush(); } if (stat0 & (SA11X0_UART_RX_SERVICE_REQUEST|SA11X0_UART_RX_IDLE)) { atmel_poll(); base->utsr0 = SA11X0_UART_RX_IDLE; // Need to clear this manually } cyg_drv_interrupt_unmask(vector); } // // Connect/disconnect interrupt processing // void atmel_interrupt_mode(bool enable) { volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE; if (enable) { // Enable the receiver (with interrupts) and the transmitter. base->utcr3 = SA11X0_UART_RX_ENABLED | SA11X0_UART_TX_ENABLED | SA11X0_UART_RX_FIFO_INT_ENABLED; cyg_drv_interrupt_unmask(ATMEL_INT); } else { cyg_drv_interrupt_mask(ATMEL_INT); } atmel_use_ints = enable; } #endif // // Set up the Atmel micro-controller environment // void atmel_init(void) { volatile struct sa11x0_serial *base = (volatile struct sa11x0_serial *)SA11X0_UART1_BASE; cyg_uint32 brd; int i; static bool _init = false; if (_init) return; // Disable Receiver and Transmitter (clears FIFOs) base->utcr3 = SA11X0_UART_RX_DISABLED | SA11X0_UART_TX_DISABLED; // Clear sticky (writable) status bits. base->utsr0 = SA11X0_UART_RX_IDLE | SA11X0_UART_RX_BEGIN_OF_BREAK | SA11X0_UART_RX_END_OF_BREAK; // Set UART to 8N1 (8 data bits, no partity, 1 stop bit) base->utcr0 = SA11X0_UART_PARITY_DISABLED | SA11X0_UART_STOP_BITS_1 | SA11X0_UART_DATA_BITS_8; // Set the desired baud rate. brd = SA11X0_UART_BAUD_RATE_DIVISOR(115200); base->utcr1 = (brd >> 8) & SA11X0_UART_H_BAUD_RATE_DIVISOR_MASK; base->utcr2 = brd & SA11X0_UART_L_BAUD_RATE_DIVISOR_MASK; // Enable the receiver and the transmitter. base->utcr3 = SA11X0_UART_RX_ENABLED | SA11X0_UART_TX_ENABLED; // Set up character queues atmel_putq_put = atmel_putq_get = 0; atmel_use_ints = false; // Set up handlers for (i = 0; i < NUM_ATMEL_CMDS; i++) { atmel_register(i, null_handler); } #ifdef CYGPKG_IO cyg_drv_interrupt_create(ATMEL_INT, 99, // Priority - unused (cyg_addrword_t)base, // Data item passed to interrupt handler atmel_ISR, atmel_DSR, &atmel_interrupt_handle, &atmel_interrupt); cyg_drv_interrupt_attach(atmel_interrupt_handle); #endif _init = true; } static void atmel_pkt_send(atmel_pkt *pkt) { int i; for (i = 0; i < pkt->len; i++) { atmel_putc(pkt->data[i]); } atmel_flush(); } bool atmel_send(int cmd, unsigned char *data, int len) { atmel_pkt pkt; unsigned char cksum, *dp; int i; dp = pkt.data; *dp++ = SOF; *dp++ = cksum = (cmd << 4) | len; for (i = 0; i < len; i++) { *dp++ = data[i]; cksum += data[i]; } *dp = cksum; pkt.len = len + 3; atmel_pkt_send(&pkt); return true; } #define MAX_TS_EVENTS 32 static struct ts_event ts_event_list[MAX_TS_EVENTS]; static int num_ts_events = 0; static int ts_event_get, ts_event_put; static void ts_event_handler(atmel_pkt *pkt) { unsigned char *buf = pkt->data; static bool up = true; static int down_count = 0; struct ts_event *tse; if (num_ts_events == MAX_TS_EVENTS) { return; } if ((buf[0] & 0x0F) == 0) { // Stylus up up = true; down_count = 0; tse = &ts_event_list[ts_event_put++]; if (ts_event_put == MAX_TS_EVENTS) { ts_event_put = 0; } num_ts_events++; tse->x = (buf[1] << 8) | buf[2]; tse->y = (buf[3] << 8) | buf[4]; tse->up = up; } else { up = false; if (down_count++ == 0) { // First 'down' event } else { } { tse = &ts_event_list[ts_event_put++]; if (ts_event_put == MAX_TS_EVENTS) { ts_event_put = 0; } num_ts_events++; tse->x = (buf[1] << 8) | buf[2]; tse->y = (buf[3] << 8) | buf[4]; tse->up = up; } } } bool ts_get_event(struct ts_event *tse) { static bool _init = false; if (!_init) { atmel_register(ATMEL_CMD_TOUCH, ts_event_handler); atmel_register(ATMEL_CMD_UNKNOWN, ts_event_handler); _init = true; } if (num_ts_events == 0) { atmel_poll(); } if (num_ts_events) { num_ts_events--; memcpy(tse, &ts_event_list[ts_event_get++], sizeof(*tse)); if (ts_event_get == MAX_TS_EVENTS) { ts_event_get = 0; } return true; } else { return false; } } #define MAX_KEY_EVENTS 8 static struct key_event key_event_list[MAX_KEY_EVENTS]; static int num_key_events = 0; static int key_event_get, key_event_put; static void kbd_event_handler(atmel_pkt *pkt) { unsigned char *buf = pkt->data; struct key_event *ke; if (num_key_events == MAX_KEY_EVENTS) { return; } // printf("Keybd = %x\n", buf[1]); ke = &key_event_list[key_event_put++]; if (key_event_put == MAX_KEY_EVENTS) { key_event_put = 0; } ke->button_info = buf[1]; num_key_events++; } bool key_get_event(struct key_event *ke) { static bool _init = false; if (!_init) { atmel_register(ATMEL_CMD_KEYBD, kbd_event_handler); _init = true; } if (num_key_events == 0) { atmel_poll(); } if (num_key_events) { num_key_events--; memcpy(ke, &key_event_list[key_event_get++], sizeof(*ke)); if (key_event_get == MAX_KEY_EVENTS) { key_event_get = 0; } return true; } else { return false; } } #ifdef CYGPKG_REDBOOT void atmel_check(bool is_idle) { } RedBoot_idle(atmel_check, RedBoot_BEFORE_NETIO); #endif