From: ppisa Date: Fri, 30 Jan 2009 18:47:04 +0000 (+0100) Subject: Merge branch 'master' into can-usb1 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/a35b5224bbdfbd7147e1cf715c2931a2d740f592?hp=2e85655fb38062be1ac12541077db4d178122f94 Merge branch 'master' into can-usb1 --- diff --git a/build-embedded.sh b/build-embedded.sh new file mode 100755 index 0000000..09e10cc --- /dev/null +++ b/build-embedded.sh @@ -0,0 +1,41 @@ +SOURCE_DIRS="embedded/app embedded/arch embedded/board embedded/libs4c" +OMK_RULES_DIR=omk/rules/sysless +BUILD_DIR=embedded-build/can-usb1 +OMK_CONFIG=embedded/board/arm/ul_usb1/config/config.usbcan + +SOURCE_PATHS+=" $SOURCE_DIRS" +SOURCE_PATHS+=" $(echo $OMK_RULES_DIR/*)" + +TOP_RELATIVE="$( echo "$BUILD_DIR" | sed -n -e 's#[^/]*/[^/]*#../#pg' ).." + +echo "SOURCE_PATHS=$SOURCE_PATHS" +echo "TOP_RELATIVE=$TOP_RELATIVE" + +mkdir -p "$BUILD_DIR" || exit 1 + +for i in $SOURCE_PATHS ; do + b="$(basename $i)" + if [ ! -e "$BUILD_DIR/$b" ] ; then + echo "$BUILD_DIR : ln -s $TOP_RELATIVE/$i $b" + ( cd "$BUILD_DIR" && ln -s "$TOP_RELATIVE/$i" "$b" ) || exit 1 + fi +done + +for i in $SOURCE_DIRS ; do + b="$(basename $i)" + if ! grep -s "\<$b\>" "$BUILD_DIR/Makefile.omk" ; then + echo "SUBDIRS += $b" >>"$BUILD_DIR/Makefile.omk" || exit 1 + fi +done + +if [ ! -e "$BUILD_DIR/Makefile" ] ; then + cp omk/Makefile "$BUILD_DIR/Makefile" +fi + +if [ ! -e "$BUILD_DIR/config.omk" ] ; then + ( cd "$BUILD_DIR" && ln -s "$TOP_RELATIVE/$OMK_CONFIG" config.omk ) +fi + +( cd "$BUILD_DIR" && make default-config ) || exit 1 + +( cd "$BUILD_DIR" && make ) || exit 1 diff --git a/embedded/Makefile b/embedded/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/Makefile.omk b/embedded/Makefile.omk new file mode 100644 index 0000000..c0f9113 --- /dev/null +++ b/embedded/Makefile.omk @@ -0,0 +1,6 @@ +# -*- makefile -*- + +SUBDIRS = app arch board libs4c + +-include $(SOURCES_DIR)/Makefile.omk-additional + diff --git a/embedded/README.txt b/embedded/README.txt new file mode 100644 index 0000000..52b1e62 --- /dev/null +++ b/embedded/README.txt @@ -0,0 +1,93 @@ +uLan embedded source tree v 0.5 +=============================== + +This is highly experimental code, look for latest +version on the project related pages + + http://ulan.sourceforge.net/ + http://sourceforge.net/projects/ulan + http://cmp.felk.cvut.cz/~pisa#ulan + +To build code you need to have SDCC 2.5.3-CVS. +The snapshot past Sep 3 2005 are OK. +The GNU make program 3.81beta3 or better is required. +The full build has been tested on Linux based hosts only +for now. The uLan protocol code has been successfully build +by Keil compiler under Windows in the past. + +The archive has to be unpacked with symbolic links +for now. We are thinking about rearrangement +of the code to make it more portable and drop +link requirements. + +The MCS51 is only port provided in this version. + +To build do + + cd ul_embedded-x.y/mcs51 + make defaul-config + make + +You should find resulting binaries in the "_compiled/bin" +directory. The board and application is selected by used +"config.omk" file. Example files can be found in the "configs" +directory. + +The next boards and applications are supported + +Device: MCS51 TI MSC-1210 + Board: ULAD-21 - AD converter and uLan2USB converter + Applications: + config.mscboot-ulad21 - uLan enabled remote boot-loader and boot-block + config.u2u-ulad21 - uLan to USB converter + + Board: HISC - Home Information System Controller + config.mscboot-hisc - boot block for distributed HISC system + config.blinder - blinder controller + config.kswtimer - kettle switch timer + +Device: MCS51 Atmel AT89C51RD2 + config.u2u-ps1 - AT89C51RD2 based uLan2USB converter + + +The procedure to write boot-block into ULAD-21 MSC1210 based board +requires next steps + + FLASHMSC_TTY=/dev/ttyS1 + flashmsc -d $FLASHMSC_TTY -E 0x807f + flashmsc -d $FLASHMSC_TTY -E 0x7fff + flashmsc -d $FLASHMSC_TTY -X 18432000 ulad21-hcr.hex + flashmsc -d $FLASHMSC_TTY -X 18432000 ulad21-boot.hex + +The "flashmsc" sources can be found at page + http://cmp.felk.cvut.cz/~pisa/#mcuutils + +To replace application in the converter or other uLan node +over uLan communication protocol, next steps are required + + echo Reset application if running + ul_sendhex -g 0 -m 0 + echo Waiting to target to go into boot block + echo If application blocks, reset device at this time + echo to activate boot block now + ul_sendhex -o 0 -m 0 + echo Found devices + ul_sendhex -p 64 + echo Erasing flash + ul_sendhex -m 62 -t 5 -e -s 0x2000 -l 0x6000 + sleep 2 + echo Loading application + ul_sendhex -m 62 -t 5 application.hex + +Look for uLan driver for host side (Linux, Windows, DOS) +uLan protocol driver. The uLan2USB converter requires +at least version ul_drv-0.7 release. + +The code authors + + (C) Copyright 1996-2005 by Pavel Pisa + http://cmp.felk.cvut.cz/~pisa + (C) Copyright 1996-2005 PiKRON Ltd. + http://www.pikron.com + (C) Copyright 2002-2005 Petr Smolik + diff --git a/embedded/app/Makefile b/embedded/app/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/app/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/app/Makefile.omk b/embedded/app/Makefile.omk new file mode 100644 index 0000000..fd0ecae --- /dev/null +++ b/embedded/app/Makefile.omk @@ -0,0 +1,4 @@ +# -*- makefile -*- + +SUBDIRS = usbcan + diff --git a/embedded/app/usbcan/Makefile b/embedded/app/usbcan/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/app/usbcan/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/app/usbcan/Makefile.omk b/embedded/app/usbcan/Makefile.omk new file mode 100644 index 0000000..7f3e648 --- /dev/null +++ b/embedded/app/usbcan/Makefile.omk @@ -0,0 +1,32 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_APP_USBCAN=n + +ifeq ($(CONFIG_APP_USBCAN),y) + +#ULAN_ID=usbtest + +#default_CONFIG += CONFIG_ULOI_LT=x +#default_CONFIG += CONFIG_ULAN_DY=x +default_CONFIG += MACH=$(MACH) +#default_CONFIG += ULAN_ID=$(ULAN_ID) +default_CONFIG += CONFIG_MISC_VECT=x + +LOCAL_CONFIG_H = local_config.h + +INCLUDES += -I. + +#include_HEADERS = ul_idstr.h + +bin_PROGRAMS = usbcan +usbcan_SOURCES = main.c can.c can_queue.c sja1000p.c can_quesysless.c devcommon.c setup.c ul_usb1.c finish.c usb_vend.c + +#usbtest_SOURCES += ul_idstr.c +#lib_LOADLIBES = bspbase ul_drv lpciap keyval lpciap_kvpb mach_hal uldy +lib_LOADLIBES = bspbase usbbase usbmore lpcusb mach_hal +usbcan_MOREOBJS = $(USER_LIB_DIR)/system_stub.o $(USER_LIB_DIR)/ivt.o +nobase_include_HEADERS = usb/usb_defs.h + +link_VARIANTS = app boot + +endif #CONFIG_ULBOOT diff --git a/embedded/app/usbcan/can.c b/embedded/app/usbcan/can.c new file mode 100644 index 0000000..fc94599 --- /dev/null +++ b/embedded/app/usbcan/can.c @@ -0,0 +1,152 @@ +/** +can.c + +Routines for sending and receiving messages for configuration and/or +communication over CAN network using a SJA1000 transceiver. +For use in UL_USB1 module, it runs in Intel mode. +See documentation for details. + +*/ + + +#include "can/can.h" + +inline void can_data_pins_dir_output(void) +{ + IO1DIR|=P1_SJA1000_DATA_PINS; // Port as output to send data +} + +inline void can_data_pins_dir_input(void) +{ + IO1DIR&=~P1_SJA1000_DATA_PINS; // Sets port as input +} + +inline void can_data_pins_set_value(uint8_t data) +{ + uint32_t val = __val2mfld(P1_SJA1000_DATA_PINS,data); + /* + * Clear only that pins, which need that, lower transition + * frequency and eliminate spikes + */ + IO1CLR= val ^ P1_SJA1000_DATA_PINS; + IO1SET= val; +} + +inline uint8_t can_data_pins_get_value(void) +{ + return __mfld2val(P1_SJA1000_DATA_PINS,IO1PIN); +} + + +void can_comm_init() +{ + //CANMSG("Start can_comm_init\n"); + IO1DIR |= P1_OUT_PORT_CS_PIN|P1_SJA1000_RST_PIN; + // Due to change in design there is CS_PIN connected with ALE_PIN and ALE_PIN connection to LPC is interrupted + // We don't use ALE_PIN + //IO0DIR|=P0_SJA1000_ALE_PIN|P0_SJA1000_CS_PIN|P0_SJA1000_RD_PIN|P0_SJA1000_WR_PIN; + IO0DIR|=P0_SJA1000_CS_PIN|P0_SJA1000_RD_PIN|P0_SJA1000_WR_PIN; + IO0DIR&=~(P0_SJA1000_INT_PIN); + + SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN); + CLR_OUT_PIN(IO1,P1_SJA1000_RST_PIN); + SJA1000_INIT_DELAY(); + SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN); + // Due to change in design there is CS_PIN connected with ALE_PIN and ALE_PIN connection to LPC is interrupted + // CLR_OUT_PIN(IO0,P0_SJA1000_ALE_PIN); + SET_OUT_PIN(IO1,P1_SJA1000_RST_PIN); + SJA1000_INIT_DELAY(); +} + +void can_write(uint8_t data, uint8_t address) +{ + can_data_pins_dir_output(); + // Set memory address + can_data_pins_set_value(address); + // Init + SET_OUT_PIN(IO0,P0_SJA1000_RD_PIN); // Stays high on write + SET_OUT_PIN(IO0,P0_SJA1000_WR_PIN); // Stays high on address write + SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN); // Sets output buffers to third state + //SJA1000_DELAY(); + //SET_OUT_PIN(IO0,P0_SJA1000_ALE_PIN); // Start command + + //SJA1000_DELAY(); + //CLR_OUT_PIN(IO0,P0_SJA1000_ALE_PIN); // Makes address active + CLR_OUT_PIN(IO0,P0_SJA1000_CS_PIN); + //SJA1000_DELAY(); + + // Setting data + can_data_pins_set_value(data); + + CLR_OUT_PIN(IO0,P0_SJA1000_WR_PIN); + CLR_OUT_PIN(IO0,P0_SJA1000_WR_PIN); + //SJA1000_DELAY(); + SET_OUT_PIN(IO0,P0_SJA1000_WR_PIN); // Data should be accepted by now + SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN); + //SJA1000_DELAY(); +} + +uint8_t can_read(const uint8_t address) +{ + uint8_t data; + + can_data_pins_dir_output(); + // Set memory address + can_data_pins_set_value(address); + // Init + SET_OUT_PIN(IO0,P0_SJA1000_WR_PIN); // Stays high on read + SET_OUT_PIN(IO0,P0_SJA1000_RD_PIN); // Stays high while entering address + SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN); + //SJA1000_DELAY(); + //SET_OUT_PIN(IO0,P0_SJA1000_ALE_PIN); + + //SJA1000_DELAY(); + //CLR_OUT_PIN(IO0,P0_SJA1000_ALE_PIN); + CLR_OUT_PIN(IO0,P0_SJA1000_CS_PIN); + + // Get data + + can_data_pins_dir_input(); + CLR_OUT_PIN(IO0,P0_SJA1000_RD_PIN); + CLR_OUT_PIN(IO0,P0_SJA1000_RD_PIN); + //SJA1000_DELAY(); + data = can_data_pins_get_value(); + SET_OUT_PIN(IO0,P0_SJA1000_RD_PIN); + SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN); + //SJA1000_DELAY(); + + return data; +} + +int can_init(){ + uint8_t data=0,count=0; + do { + can_comm_init(); + data = can_read(SJAMOD); + if (count++ > 50) + return -1; + } while (!(data&sjaMOD_RM)); + + data=sjaCDR_CLKOUT_DIV1|sjaCDR_CLK_OFF|sjaCDR_CBP|sjaCDR_PELICAN; + can_write(data, SJACDR); + + // Single acceptance filter, reset mode + data=sjaMOD_AFM|sjaMOD_RM; + can_write(data, SJAMOD); + + // Enabling all interrupt sources + data=sjaENABLE_INTERRUPTS; + can_write(data, SJAIER); + + // Accept all messages + data=0xFF; + can_write(data, SJAAMR0); + can_write(data, SJAAMR0+1); + can_write(data, SJAAMR0+2); + can_write(data, SJAAMR0+3); + + data=sjaCMR_CDO; + can_write(data, SJACMR); + + return 0; +} diff --git a/embedded/app/usbcan/can/can.h b/embedded/app/usbcan/can/can.h new file mode 100644 index 0000000..ea863f6 --- /dev/null +++ b/embedded/app/usbcan/can/can.h @@ -0,0 +1,71 @@ +#ifndef SJA1000_CAN_H +#define SJA1000_CAN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "main.h" +#include "sja1000p.h" +/* can.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + + /* + Delay for synchronization with peripheral (SJA1000) + */ + #define SJA1000_CLK (24000000) /* XTAL frequency */ + #define SJA1000_PRESC (2) /* embedded prescaler */ + #define SJA1000_CCLK (SJA1000_CLK/SJA1000_PRESC) /* SJA core frequency */ + #define SJA1000_SCLK (PCLK/SJA1000_CCLK) /* Clock count to synchronize with LPC */ + + #define SJA1000_DELAY(void) \ + ({ \ + volatile int delay; \ + for (delay=0;delayfifo_flags) +#define canque_fifo_set_fl(fifo,fifo_fl) \ + set_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags) +#define canque_fifo_clear_fl(fifo,fifo_fl) \ + clear_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags) +#define canque_fifo_test_and_set_fl(fifo,fifo_fl) \ + test_and_set_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags) +#define canque_fifo_test_and_clear_fl(fifo,fifo_fl) \ + test_and_clear_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags) + + +/** + * canque_fifo_get_inslot - allocate slot for the input of one CAN message + * @fifo: pointer to the FIFO structure + * @slotp: pointer to location to store pointer to the allocated slot. + * @cmd: optional command associated with allocated slot. + * + * Return Value: The function returns negative value if there is no + * free slot in the FIFO queue. + */ +static inline +int canque_fifo_get_inslot(struct canque_fifo_t *fifo, struct canque_slot_t **slotp, int cmd) +{ + can_spin_irqflags_t flags; + struct canque_slot_t *slot; + can_spin_lock_irqsave(&fifo->fifo_lock, flags); + /* get the first free slot slot from flist */ + if(!(slot=fifo->flist)) { + canque_fifo_set_fl(fifo,OVERRUN); + canque_fifo_set_fl(fifo,FULL); + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + *slotp=NULL; + return -1; + } + /* adjust free slot list */ + if(!(fifo->flist=slot->next)) + canque_fifo_set_fl(fifo,FULL); + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + *slotp=slot; + slot->slot_flags=cmd&CAN_SLOTF_CMD; + return 1; +} + +/** + * canque_fifo_put_inslot - releases slot to further processing + * @fifo: pointer to the FIFO structure + * @slot: pointer to the slot previously acquired by canque_fifo_get_inslot(). + * + * Return Value: The nonzero return value indicates, that the queue was empty + * before call to the function. The caller should wake-up output side of the queue. + */ +static inline +int canque_fifo_put_inslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot) +{ + int ret; + can_spin_irqflags_t flags; + slot->next=NULL; + can_spin_lock_irqsave(&fifo->fifo_lock, flags); + if(*fifo->tail) can_printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n"); + *fifo->tail=slot; + fifo->tail=&slot->next; + ret=0; + if(canque_fifo_test_and_clear_fl(fifo,EMPTY)) + ret=CAN_FIFOF_EMPTY; /* Fifo has been empty before put */ + if(canque_fifo_test_and_clear_fl(fifo,INACTIVE)) + ret=CAN_FIFOF_INACTIVE; /* Fifo has been empty before put */ + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + return ret; +} + +/** + * canque_fifo_abort_inslot - release and abort slot + * @fifo: pointer to the FIFO structure + * @slot: pointer to the slot previously acquired by canque_fifo_get_inslot(). + * + * Return Value: The nonzero value indicates, that fifo was full + */ +static inline +int canque_fifo_abort_inslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot) +{ + int ret=0; + can_spin_irqflags_t flags; + can_spin_lock_irqsave(&fifo->fifo_lock, flags); + slot->next=fifo->flist; + fifo->flist=slot; + if(canque_fifo_test_and_clear_fl(fifo,FULL)) + ret=CAN_FIFOF_FULL; + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + return ret; +} + +/** + * canque_fifo_test_outslot - test and get ready slot from the FIFO + * @fifo: pointer to the FIFO structure + * @slotp: pointer to location to store pointer to the oldest slot from the FIFO. + * + * Return Value: The negative value indicates, that queue is empty. + * The positive or zero value represents command stored into slot by + * the call to the function canque_fifo_get_inslot(). + * The successfully acquired FIFO output slot has to be released by + * the call canque_fifo_free_outslot() or canque_fifo_again_outslot(). + */ +static inline +int canque_fifo_test_outslot(struct canque_fifo_t *fifo, struct canque_slot_t **slotp) +{ + can_spin_irqflags_t flags; + int cmd; + struct canque_slot_t *slot; + can_spin_lock_irqsave(&fifo->fifo_lock, flags); + if(!(slot=fifo->head)){; + canque_fifo_set_fl(fifo,EMPTY); + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + *slotp=NULL; + return -1; + } + if(!(fifo->head=slot->next)) + fifo->tail=&fifo->head; + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + + *slotp=slot; + cmd=slot->slot_flags; + return cmd&CAN_SLOTF_CMD; +} + + +/** + * canque_fifo_free_outslot - free processed FIFO slot + * @fifo: pointer to the FIFO structure + * @slot: pointer to the slot previously acquired by canque_fifo_test_outslot(). + * + * Return Value: The returned value informs about FIFO state change. + * The mask %CAN_FIFOF_FULL indicates, that the FIFO was full before + * the function call. The mask %CAN_FIFOF_EMPTY informs, that last ready slot + * has been processed. + */ +static inline +int canque_fifo_free_outslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot) +{ + int ret=0; + can_spin_irqflags_t flags; + can_spin_lock_irqsave(&fifo->fifo_lock, flags); + slot->next=fifo->flist; + fifo->flist=slot; + if(canque_fifo_test_and_clear_fl(fifo,FULL)) + ret=CAN_FIFOF_FULL; + if(!(fifo->head)){ + canque_fifo_set_fl(fifo,EMPTY); + ret|=CAN_FIFOF_EMPTY; + } + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + return ret; +} + +/** + * canque_fifo_again_outslot - interrupt and postpone processing of the slot + * @fifo: pointer to the FIFO structure + * @slot: pointer to the slot previously acquired by canque_fifo_test_outslot(). + * + * Return Value: The function cannot fail.. + */ +static inline +int canque_fifo_again_outslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot) +{ + can_spin_irqflags_t flags; + can_spin_lock_irqsave(&fifo->fifo_lock, flags); + if(!(slot->next=fifo->head)) + fifo->tail=&slot->next; + fifo->head=slot; + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + return 1; +} + +int canque_fifo_flush_slots(struct canque_fifo_t *fifo); + +int canque_fifo_init_slots(struct canque_fifo_t *fifo); + +#define CANQUEUE_PRIO_NR 3 + +/* Forward declarations for external types */ +struct msgobj_t; +struct canchip_t; + +/** + * struct canque_edge_t - CAN message delivery subsystem graph edge + * @fifo: place where primitive @struct canque_fifo_t FIFO is located. + * @filtid: the possible CAN message identifiers filter. + * @filtmask: the filter mask, the comparison considers only + * @filtid bits corresponding to set bits in the @filtmask field. + * @inpeers: the lists of all peers FIFOs connected by their + * input side (@inends) to the same terminal (@struct canque_ends_t). + * @outpeers: the lists of all peers FIFOs connected by their + * output side (@outends) to the same terminal (@struct canque_ends_t). + * @activepeers: the lists of peers FIFOs connected by their + * output side (@outends) to the same terminal (@struct canque_ends_t) + * with same priority and active state. + * @inends: the pointer to the FIFO input side terminal (@struct canque_ends_t). + * @outends: the pointer to the FIFO output side terminal (@struct canque_ends_t). + * @edge_used: the atomic usage counter, mainly used for safe destruction of the edge. + * @edge_prio: the assigned queue priority from the range 0 to %CANQUEUE_PRIO_NR-1 + * @edge_num: edge sequential number intended for debugging purposes only + * @pending_peers: edges with pending delayed events (RTL->Linux calls) + * @pending_inops: bitmask of pending operations + * @pending_outops: bitmask of pending operations + * + * This structure represents one direction connection from messages source + * (@inends) to message consumer (@outends) fifo ends hub. The edge contains + * &struct canque_fifo_t for message fifo implementation. + */ +struct canque_edge_t { + struct canque_fifo_t fifo; + unsigned long filtid; + unsigned long filtmask; + struct list_head inpeers; + struct list_head outpeers; + struct list_head activepeers; + struct canque_ends_t *inends; + struct canque_ends_t *outends; + atomic_t edge_used; + int edge_prio; + int edge_num; + #ifdef CAN_WITH_RTL + struct list_head pending_peers; + unsigned long pending_inops; + unsigned long pending_outops; + #endif /*CAN_WITH_RTL*/ +}; + +/** + * struct canque_ends_t - CAN message delivery subsystem graph vertex (FIFO ends) + * @ends_flags: this field holds flags describing state of the ENDS structure. + * @active: the array of the lists of active edges directed to the ends structure + * with ready messages. The array is indexed by the edges priorities. + * @idle: the list of the edges directed to the ends structure with empty FIFOs. + * @inlist: the list of outgoing edges input sides. + * @outlist: the list of all incoming edges output sides. Each of there edges + * is listed on one of @active or @idle lists. + * @ends_lock: the lock synchronizing operations between threads accessing + * same ends structure. + * @notify: pointer to notify procedure. The next state changes are notified. + * %CANQUEUE_NOTIFY_EMPTY (out->in call) - all slots are processed by FIFO out side. + * %CANQUEUE_NOTIFY_SPACE (out->in call) - full state negated => there is space for new message. + * %CANQUEUE_NOTIFY_PROC (in->out call) - empty state negated => out side is requested to process slots. + * %CANQUEUE_NOTIFY_NOUSR (both) - notify, that the last user has released the edge usage + * called with some lock to prevent edge disappear. + * %CANQUEUE_NOTIFY_DEAD (both) - edge is in progress of deletion. + * %CANQUEUE_NOTIFY_ATACH (both) - new edge has been attached to end. + * %CANQUEUE_NOTIFY_FILTCH (out->in call) - edge filter rules changed + * %CANQUEUE_NOTIFY_ERROR (out->in call) - error in messages processing. + * @context: space to store ends user specific information + * @endinfo: space to store some other ends usage specific informations + * mainly for waking-up by the notify calls. + * @dead_peers: used to chain ends wanting for postponed destruction + * + * Structure represents place to connect edges to for CAN communication entity. + * The zero, one or more incoming and outgoing edges can be connected to + * this structure. + */ +struct canque_ends_t { + unsigned long ends_flags; + struct list_head active[CANQUEUE_PRIO_NR]; + struct list_head idle; + struct list_head inlist; + struct list_head outlist; + can_spinlock_t ends_lock; /* can_spin_lock_irqsave / can_spin_unlock_irqrestore */ + void (*notify)(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what); + void *context; + union { + struct { + wait_queue_head_t readq; + wait_queue_head_t writeq; + wait_queue_head_t emptyq; + #ifdef CAN_ENABLE_KERN_FASYNC + struct fasync_struct *fasync; + #endif /*CAN_ENABLE_KERN_FASYNC*/ + } fileinfo; + #ifdef CAN_WITH_RTL + struct { + rtl_spinlock_t rtl_lock; + rtl_wait_t rtl_readq; + atomic_t rtl_readq_age; + rtl_wait_t rtl_writeq; + atomic_t rtl_writeq_age; + rtl_wait_t rtl_emptyq; + atomic_t rtl_emptyq_age; + unsigned long pend_flags; + } rtlinfo; + #endif /*CAN_WITH_RTL*/ + struct { + struct msgobj_t *msgobj; + struct canchip_t *chip; + #ifndef CAN_WITH_RTL + wait_queue_head_t daemonq; + #else /*CAN_WITH_RTL*/ + pthread_t worker_thread; + #endif /*CAN_WITH_RTL*/ + } chipinfo; + } endinfo; + struct list_head dead_peers; +}; + +#define CANQUEUE_NOTIFY_EMPTY 1 /* out -> in - all slots are processed by FIFO out side */ +#define CANQUEUE_NOTIFY_SPACE 2 /* out -> in - full state negated => there is space for new message */ +#define CANQUEUE_NOTIFY_PROC 3 /* in -> out - empty state negated => out side is requested to process slots */ +#define CANQUEUE_NOTIFY_NOUSR 4 /* called with some lock to prevent edge disappear */ +#define CANQUEUE_NOTIFY_DEAD 5 /* */ +#define CANQUEUE_NOTIFY_DEAD_WANTED 6 /* */ +#define CANQUEUE_NOTIFY_ATTACH 7 /* */ +#define CANQUEUE_NOTIFY_FILTCH 8 /* filter changed */ +#define CANQUEUE_NOTIFY_ERROR 0x10000 /* error notifiers */ +#define CANQUEUE_NOTIFY_ERRTX_PREP 0x11001 /* tx preparation error */ +#define CANQUEUE_NOTIFY_ERRTX_SEND 0x11002 /* tx send error */ +#define CANQUEUE_NOTIFY_ERRTX_BUS 0x11003 /* tx bus error */ + +#define CAN_ENDSF_DEAD (1<<0) +#define CAN_ENDSF_MEM_RTL (1<<1) + +/** + * canque_notify_inends - request to send notification to the input ends + * @qedge: pointer to the edge structure + * @what: notification type + */ +static inline +void canque_notify_inends(struct canque_edge_t *qedge, int what) +{ + if(qedge->inends) + if(qedge->inends->notify) + qedge->inends->notify(qedge->inends,qedge,what); +} + +/** + * canque_notify_outends - request to send notification to the output ends + * @qedge: pointer to the edge structure + * @what: notification type + */ +static inline +void canque_notify_outends(struct canque_edge_t *qedge, int what) +{ + if(qedge->outends) + if(qedge->outends->notify) + qedge->outends->notify(qedge->outends,qedge,what); +} + +/** + * canque_notify_bothends - request to send notification to the both ends + * @qedge: pointer to the edge structure + * @what: notification type + */ +static inline +void canque_notify_bothends(struct canque_edge_t *qedge, int what) +{ + canque_notify_inends(qedge, what); + canque_notify_outends(qedge, what); +} + +/** + * canque_activate_edge - mark output end of the edge as active + * @qedge: pointer to the edge structure + * @inends: input side of the edge + * + * Function call moves output side of the edge from idle onto active edges + * list. This function has to be called with edge reference count held. + * that is same as for most of other edge functions. + */ +static inline +void canque_activate_edge(struct canque_ends_t *inends, struct canque_edge_t *qedge) +{ + can_spin_irqflags_t flags; + struct canque_ends_t *outends; + if(qedge->edge_prio>=CANQUEUE_PRIO_NR) + qedge->edge_prio=CANQUEUE_PRIO_NR-1; + if((outends=qedge->outends)){ + can_spin_lock_irqsave(&outends->ends_lock, flags); + can_spin_lock(&qedge->fifo.fifo_lock); + if(!canque_fifo_test_fl(&qedge->fifo,EMPTY)){ + list_del(&qedge->activepeers); + list_add_tail(&qedge->activepeers,&outends->active[qedge->edge_prio]); + } + can_spin_unlock(&qedge->fifo.fifo_lock); + can_spin_unlock_irqrestore(&outends->ends_lock, flags); + } +} + +/** + * canque_filtid2internal - converts message ID and filter flags into internal format + * @id: CAN message 11 or 29 bit identifier + * @filtflags: CAN message flags + * + * This function maps message ID and %MSG_RTR, %MSG_EXT and %MSG_LOCAL into one 32 bit number + */ +static inline +unsigned int canque_filtid2internal(unsigned long id, int filtflags) +{ + filtflags &= MSG_RTR|MSG_EXT|MSG_LOCAL; + filtflags += filtflags&MSG_RTR; + return (id&MSG_ID_MASK) | (filtflags<<28); +} + +int canque_get_inslot(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd); + +int canque_get_inslot4id(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp, + int cmd, unsigned long id, int prio); + +int canque_put_inslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot); + +int canque_abort_inslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot); + +int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg); + +int canque_test_outslot(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp); + +int canque_free_outslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot); + +int canque_again_outslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot); + +int canque_set_filt(struct canque_edge_t *qedge, + unsigned long filtid, unsigned long filtmask, int flags); + +int canque_flush(struct canque_edge_t *qedge); + +int canqueue_disconnect_edge(struct canque_edge_t *qedge); + +int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends); + +int canqueue_ends_init_gen(struct canque_ends_t *qends); + +void canqueue_block_inlist(struct canque_ends_t *qends); + +void canqueue_block_outlist(struct canque_ends_t *qends); + +int canqueue_ends_kill_inlist(struct canque_ends_t *qends, int send_rest); + +int canqueue_ends_kill_outlist(struct canque_ends_t *qends); + +int canqueue_ends_filt_conjuction(struct canque_ends_t *qends, struct canfilt_t *filt); + +int canqueue_ends_flush_inlist(struct canque_ends_t *qends); + +int canqueue_ends_flush_outlist(struct canque_ends_t *qends); + +/* edge reference and traversal functions */ + +void canque_edge_do_dead(struct canque_edge_t *edge); + +/** + * canque_edge_incref - increments edge reference count + * @edge: pointer to the edge structure + */ +static inline +void canque_edge_incref(struct canque_edge_t *edge) +{ + atomic_inc(&edge->edge_used); +} + +static inline +can_spin_irqflags_t canque_edge_lock_both_ends(struct canque_ends_t *inends, struct canque_ends_t *outends) +{ + can_spin_irqflags_t flags; + if(inendsends_lock, flags); + can_spin_lock(&outends->ends_lock); + }else{ + can_spin_lock_irqsave(&outends->ends_lock, flags); + if(outends!=inends) can_spin_lock(&inends->ends_lock); + } + return flags; +} + +static inline +void canque_edge_unlock_both_ends(struct canque_ends_t *inends, struct canque_ends_t *outends, can_spin_irqflags_t flags) +{ + if(outends!=inends) can_spin_unlock(&outends->ends_lock); + can_spin_unlock_irqrestore(&inends->ends_lock, flags); +} + +/* Non-inlined version of edge reference decrement */ +void __canque_edge_decref(struct canque_edge_t *edge); + +static inline +void __canque_edge_decref_body(struct canque_edge_t *edge) +{ + can_spin_irqflags_t flags; + int dead_fl=0; + struct canque_ends_t *inends=edge->inends; + struct canque_ends_t *outends=edge->outends; + + flags=canque_edge_lock_both_ends(inends, outends); + if(atomic_dec_and_test(&edge->edge_used)) { + dead_fl=!canque_fifo_test_and_set_fl(&edge->fifo,DEAD); + /* Because of former evolution of edge references + management notify of CANQUEUE_NOTIFY_NOUSR could + be moved to canque_edge_do_dead :-) */ + } + canque_edge_unlock_both_ends(inends, outends, flags); + if(dead_fl) canque_edge_do_dead(edge); +} + +#ifndef CAN_HAVE_ARCH_CMPXCHG +/** + * canque_edge_decref - decrements edge reference count + * @edge: pointer to the edge structure + * + * This function has to be called without lock held for both ends of edge. + * If reference count drops to 0, function canque_edge_do_dead() + * is called. + */ +static inline +void canque_edge_decref(struct canque_edge_t *edge) +{ + __canque_edge_decref_body(edge); +} +#else +static inline +void canque_edge_decref(struct canque_edge_t *edge) +{ + int x, y; + + x = atomic_read(&edge->edge_used); + do{ + if(x<=1) + return __canque_edge_decref(edge); + y=x; + /* This code strongly depends on the definition of atomic_t !!!! */ + /* x=cmpxchg(&edge->edge_used, x, x-1); */ + /* Next alternative could be more portable */ + x=__cmpxchg(&edge->edge_used, x, x-1, sizeof(atomic_t)); + /* If even this does not help, comment out CAN_HAVE_ARCH_CMPXCHG in can_sysdep.h */ + } while(x!=y); +} +#endif + +static inline +struct canque_edge_t *canque_first_inedge(struct canque_ends_t *qends) +{ + can_spin_irqflags_t flags; + struct list_head *entry; + struct canque_edge_t *edge; + + can_spin_lock_irqsave(&qends->ends_lock, flags); + entry=qends->inlist.next; + skip_dead: + if(entry != &qends->inlist) { + edge=list_entry(entry,struct canque_edge_t,inpeers); + if(canque_fifo_test_fl(&edge->fifo,DEAD)) { + entry=entry->next; + goto skip_dead; + } + canque_edge_incref(edge); + } else { + edge=NULL; + } + can_spin_unlock_irqrestore(&qends->ends_lock, flags); + return edge; +} + + +static inline +struct canque_edge_t *canque_next_inedge(struct canque_ends_t *qends, struct canque_edge_t *edge) +{ + can_spin_irqflags_t flags; + struct list_head *entry; + struct canque_edge_t *next; + + can_spin_lock_irqsave(&qends->ends_lock, flags); + entry=edge->inpeers.next; + skip_dead: + if(entry != &qends->inlist) { + next=list_entry(entry,struct canque_edge_t,inpeers); + if(canque_fifo_test_fl(&edge->fifo,DEAD)) { + entry=entry->next; + goto skip_dead; + } + canque_edge_incref(next); + } else { + next=NULL; + } + can_spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(edge); + return next; +} + +#define canque_for_each_inedge(qends, edge) \ + for(edge=canque_first_inedge(qends);edge;edge=canque_next_inedge(qends, edge)) + +static inline +struct canque_edge_t *canque_first_outedge(struct canque_ends_t *qends) +{ + can_spin_irqflags_t flags; + struct list_head *entry; + struct canque_edge_t *edge; + + can_spin_lock_irqsave(&qends->ends_lock, flags); + entry=qends->outlist.next; + skip_dead: + if(entry != &qends->outlist) { + edge=list_entry(entry,struct canque_edge_t,outpeers); + if(canque_fifo_test_fl(&edge->fifo,DEAD)) { + entry=entry->next; + goto skip_dead; + } + canque_edge_incref(edge); + } else { + edge=NULL; + } + can_spin_unlock_irqrestore(&qends->ends_lock, flags); + return edge; +} + + +static inline +struct canque_edge_t *canque_next_outedge(struct canque_ends_t *qends, struct canque_edge_t *edge) +{ + can_spin_irqflags_t flags; + struct list_head *entry; + struct canque_edge_t *next; + + can_spin_lock_irqsave(&qends->ends_lock, flags); + entry=edge->outpeers.next; + skip_dead: + if(entry != &qends->outlist) { + next=list_entry(entry,struct canque_edge_t,outpeers); + if(canque_fifo_test_fl(&edge->fifo,DEAD)) { + entry=entry->next; + goto skip_dead; + } + canque_edge_incref(next); + } else { + next=NULL; + } + can_spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(edge); + return next; +} + +#define canque_for_each_outedge(qends, edge) \ + for(edge=canque_first_outedge(qends);edge;edge=canque_next_outedge(qends, edge)) + +/* Linux kernel specific functions */ + +int canque_fifo_init_kern(struct canque_fifo_t *fifo, int slotsnr); + +int canque_fifo_done_kern(struct canque_fifo_t *fifo); + +struct canque_edge_t *canque_new_edge_kern(int slotsnr); + +int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp, + int cmd, unsigned long id, int prio); + +int canque_get_outslot_wait_kern(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp); + +int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge); + +int canqueue_ends_init_kern(struct canque_ends_t *qends); + +int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync); + +void canqueue_ends_dispose_postpone(struct canque_ends_t *qends); + +void canqueue_kern_initialize(void); + +#ifdef CAN_WITH_RTL + +extern struct tasklet_struct canque_dead_tl; /*publication required only for RTL*/ + +/* RT-Linux specific functions and variables */ + +extern int canqueue_rtl_irq; + +extern unsigned long canqueue_rtl2lin_pend; + +#define CAN_RTL2LIN_PEND_DEAD_b 0 + +void canqueue_rtl_initialize(void); +void canqueue_rtl_done(void); + +int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends, + struct canque_edge_t *qedge, int what); + +struct canque_edge_t *canque_new_edge_rtl(int slotsnr); + +void canque_dispose_edge_rtl(struct canque_edge_t *qedge); + +int canque_get_inslot4id_wait_rtl(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp, + int cmd, unsigned long id, int prio); + +int canque_get_outslot_wait_rtl(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp); + +int canque_sync_wait_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge); + +void canque_ends_free_rtl(struct canque_ends_t *qends); + +int canqueue_ends_init_rtl(struct canque_ends_t *qends); + +int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync); + +#else /*CAN_WITH_RTL*/ + +static inline int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends, + struct canque_edge_t *qedge, int what) { return 0; } + +#endif /*CAN_WITH_RTL*/ + + +#endif /*_CAN_QUEUE_H*/ diff --git a/embedded/app/usbcan/can/can_sysdep.h b/embedded/app/usbcan/can/can_sysdep.h new file mode 100644 index 0000000..5a3b86c --- /dev/null +++ b/embedded/app/usbcan/can/can_sysdep.h @@ -0,0 +1,226 @@ +/* can_sysdep.h - hides differences between individual Linux kernel + * versions and RT extensions + * Linux CAN-bus device driver. + * Written by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#ifndef _CAN_SYSDEP_H +#define _CAN_SYSDEP_H + +#ifdef CAN_WITH_RTL +#include +#include +#include +#include +#include +#include +#endif /*CAN_WITH_RTL*/ + +/*#define __NO_VERSION__*/ +/*#include */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "lincan_config.h" + +/*optional features*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) +#define CAN_ENABLE_KERN_FASYNC +#ifdef CONFIG_PCI +#define CAN_ENABLE_PCI_SUPPORT +#endif +#ifdef CONFIG_OC_LINCANVME +#define CAN_ENABLE_VME_SUPPORT +#endif +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#include +#else +#include +#endif + +#ifdef CAN_ENABLE_PCI_SUPPORT +#include "linux/pci.h" +#endif /*CAN_ENABLE_PCI_SUPPORT*/ + +/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2 + kernels need next definitions too */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */ + #define wait_queue_head_t struct wait_queue * + #define wait_queue_t struct wait_queue + #define init_waitqueue_head(queue_head) (*queue_head=NULL) + #define init_waitqueue_entry(qentry,qtask) \ + (qentry->next=NULL,qentry->task=qtask) + #define DECLARE_WAIT_QUEUE_HEAD(name) \ + struct wait_queue * name=NULL + #define DECLARE_WAITQUEUE(wait, current) \ + struct wait_queue wait = { current, NULL } + #define init_MUTEX(sem) (*sem=MUTEX) + #define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#endif /* 2.2.19 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) && !defined(DECLARE_TASKLET) + #define tasklet_struct tq_struct + #define DECLARE_TASKLET(_name, _func, _data) \ + struct tq_struct _name = { sync: 0, routine: _func, data: (void*)_data } + + /* void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); */ + #define tasklet_init(_tasklet, _func, _data) \ + do{ \ + /* (_tasklet)->next=NULL; */ \ + /* Above not needed for 2.2.x and buggy for 2.4.x */ \ + (_tasklet)->sync=0; \ + (_tasklet)->routine=_func; \ + (_tasklet)->data=(void*)_data; \ + }while(0) + + /* void tasklet_schedule(struct tasklet_struct *t) */ + #define tasklet_schedule(_tasklet) \ + do{ \ + queue_task(_tasklet,&tq_immediate); \ + mark_bh(IMMEDIATE_BH); \ + }while(0) + + /* void tasklet_kill(struct tasklet_struct *t); */ + #define tasklet_kill(_tasklet) \ + synchronize_irq() + +#endif /* 2.4.0 */ + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + +#define MINOR_NR \ + (MINOR(file->f_dentry->d_inode->i_rdev)) + +#else /* Linux kernel < 2.5.7 or >= 2.6.0 */ + +#define MINOR_NR \ + (minor(file->f_dentry->d_inode->i_rdev)) + +#endif /* Linux kernel < 2.5.7 or >= 2.6.0 */ + +#ifndef CAN_WITH_RTL +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL)) + typedef void can_irqreturn_t; + #define CAN_IRQ_NONE + #define CAN_IRQ_HANDLED + #define CAN_IRQ_RETVAL(x) +#else /* <=2.5.67 */ + typedef irqreturn_t can_irqreturn_t; + #define CAN_IRQ_NONE IRQ_NONE + #define CAN_IRQ_HANDLED IRQ_HANDLED + #define CAN_IRQ_RETVAL IRQ_RETVAL +#endif /* <=2.5.67 */ +#else /*CAN_WITH_RTL*/ + typedef int can_irqreturn_t; + #define CAN_IRQ_NONE 0 + #define CAN_IRQ_HANDLED 1 + #define CAN_IRQ_RETVAL(x) ((x) != 0) +#endif /*CAN_WITH_RTL*/ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33)) + #define can_synchronize_irq(irqnum) synchronize_irq() +#else /* >=2.5.33 */ + #define can_synchronize_irq synchronize_irq +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) + #define del_timer_sync del_timer +#endif /* <2.4.0 */ + +#ifdef __HAVE_ARCH_CMPXCHG + #define CAN_HAVE_ARCH_CMPXCHG +#endif + +#ifndef CAN_WITH_RTL +/* Standard LINUX kernel */ + +#define can_spinlock_t spinlock_t +#define can_spin_irqflags_t unsigned long +#define can_spin_lock spin_lock +#define can_spin_unlock spin_unlock +#define can_spin_lock_irqsave spin_lock_irqsave +#define can_spin_unlock_irqrestore spin_unlock_irqrestore +#define can_spin_lock_init spin_lock_init + +#ifndef DEFINE_SPINLOCK +#define CAN_DEFINE_SPINLOCK(x) can_spinlock_t x = SPIN_LOCK_UNLOCKED +#else /*DEFINE_SPINLOCK*/ +#define CAN_DEFINE_SPINLOCK DEFINE_SPINLOCK +#endif /*DEFINE_SPINLOCK*/ + +#if defined(CONFIG_PREEMPT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +#define can_preempt_disable preempt_disable +#define can_preempt_enable preempt_enable +#else /*CONFIG_PREEMPT*/ +#define can_preempt_disable() do { } while (0) +#define can_preempt_enable() do { } while (0) +#endif /*CONFIG_PREEMPT*/ + +#define can_enable_irq enable_irq +#define can_disable_irq disable_irq + +#define can_printk printk + +/* CAN message timestamp source, it is called from interrupt context */ +#define can_gettimeofday do_gettimeofday + +#else /*CAN_WITH_RTL*/ + +#define can_spinlock_t rtl_spinlock_t +#define can_spin_irqflags_t rtl_irqstate_t +#define can_spin_lock rtl_spin_lock +#define can_spin_unlock rtl_spin_unlock +#define can_spin_lock_irqsave rtl_spin_lock_irqsave +#define can_spin_unlock_irqrestore rtl_spin_unlock_irqrestore +#define can_spin_lock_init rtl_spin_lock_init + +#define CAN_DEFINE_SPINLOCK(x) can_spinlock_t x = SPIN_LOCK_UNLOCKED + +#define can_preempt_disable() do { } while (0) +#define can_preempt_enable() do { } while (0) + +#define can_enable_irq rtl_hard_enable_irq +#define can_disable_irq rtl_hard_disable_irq + +#define can_printk rtl_printf + +/* + * terrible hack to test rtl_file private_data concept, ugh !!! + * this would result in crash on architectures, where + * sizeof(int) < sizeof(void *) + */ +#define can_set_rtl_file_private_data(fptr, p) do{ fptr->f_minor=(long)(p); } while(0) +#define can_get_rtl_file_private_data(fptr) ((void*)((fptr)->f_minor)) + +extern can_spinlock_t can_irq_manipulation_lock; + +/* CAN message timestamp source, it is called from interrupt context */ +#define can_gettimeofday(ptr) do {\ + struct timespec temp_timespec;\ + clock_gettime(CLOCK_REALTIME,&temp_timespec);\ + ptr->tv_usec=temp_timespec.tv_nsec/1000;\ + ptr->tv_sec=temp_timespec.tv_sec;\ + } while(0) + +#endif /*CAN_WITH_RTL*/ + +#endif /*_CAN_SYSDEP_H*/ diff --git a/embedded/app/usbcan/can/can_sysless.h b/embedded/app/usbcan/can/can_sysless.h new file mode 100644 index 0000000..af3d703 --- /dev/null +++ b/embedded/app/usbcan/can/can_sysless.h @@ -0,0 +1,537 @@ +/* can_sysdep.h - hides differences between individual Linux kernel + * versions and RT extensions + * Linux CAN-bus device driver. + * Written by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#ifndef _CAN_SYSDEP_H +#define _CAN_SYSDEP_H + +#ifdef CAN_WITH_RTL +#include +#include +#include +#include +#include +#include +#endif /*CAN_WITH_RTL*/ + +#include +#include + +// typedef unsigned long atomic_t; +typedef struct { volatile int counter; } atomic_t; + +#define mb() __memory_barrier() + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +/*#define __NO_VERSION__*/ +/*#include */ + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// +// #include +// #include +// #include +// #include + +// #include "lincan_config.h" + +/*optional features*/ +// #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) +// #define CAN_ENABLE_KERN_FASYNC +// #ifdef CONFIG_PCI +// #define CAN_ENABLE_PCI_SUPPORT +// #endif +// #ifdef CONFIG_OC_LINCANVME +// #define CAN_ENABLE_VME_SUPPORT +// #endif +// #endif + +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +// #include +// #else +// #include +// #endif + +// #ifdef CAN_ENABLE_PCI_SUPPORT +// #include "linux/pci.h" +// #endif /*CAN_ENABLE_PCI_SUPPORT*/ + +/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2 + kernels need next definitions too */ +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */ + #define wait_queue_head_t struct wait_queue * + #define wait_queue_t struct wait_queue + #define init_waitqueue_head(queue_head) (*queue_head=NULL) + #define init_waitqueue_entry(qentry,qtask) \ + (qentry->next=NULL,qentry->task=qtask) + #define DECLARE_WAIT_QUEUE_HEAD(name) \ + struct wait_queue * name=NULL + #define DECLARE_WAITQUEUE(wait, current) \ + struct wait_queue wait = { current, NULL } +// #define init_MUTEX(sem) (*sem=MUTEX) +// #define DECLARE_MUTEX(name) struct semaphore name=MUTEX +// #endif /* 2.2.19 */ + +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) && !defined(DECLARE_TASKLET) +// #define tasklet_struct tq_struct +/* #define DECLARE_TASKLET(_name, _func, _data) \ + struct tq_struct _name = { sync: 0, routine: _func, data: (void*)_data }*/ +// +// /* void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); */ +/* #define tasklet_init(_tasklet, _func, _data) \ + do{ \ + (_tasklet)->sync=0; \ + (_tasklet)->routine=_func; \ + (_tasklet)->data=(void*)_data; \ + }while(0)*/ +// +// /* void tasklet_schedule(struct tasklet_struct *t) */ +/* #define tasklet_schedule(_tasklet) \ + do{ \ + queue_task(_tasklet,&tq_immediate); \ + mark_bh(IMMEDIATE_BH); \ + }while(0)*/ +// +// /* void tasklet_kill(struct tasklet_struct *t); */ +/* #define tasklet_kill(_tasklet) \ + synchronize_irq()*/ +// +// #endif /* 2.4.0 */ + + +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + +#define MINOR_NR \ + (MINOR(file->f_dentry->d_inode->i_rdev)) + +// #else /* Linux kernel < 2.5.7 or >= 2.6.0 */ +// +/*#define MINOR_NR \ + (minor(file->f_dentry->d_inode->i_rdev))*/ +// +// #endif /* Linux kernel < 2.5.7 or >= 2.6.0 */ + +// #ifndef CAN_WITH_RTL +// #if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL)) + typedef void can_irqreturn_t; + #define CAN_IRQ_NONE + #define CAN_IRQ_HANDLED + #define CAN_IRQ_RETVAL(x) +// #else /* <=2.5.67 */ +// typedef irqreturn_t can_irqreturn_t; +// #define CAN_IRQ_NONE IRQ_NONE +// #define CAN_IRQ_HANDLED IRQ_HANDLED +// #define CAN_IRQ_RETVAL IRQ_RETVAL +// #endif /* <=2.5.67 */ +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +/* #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \ + int irq_number, void *dev_id, struct pt_regs *regs*/ +// #else /* < 2.6.19 */ + #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \ + int irq_number, void *dev_id +// #endif /* < 2.6.19 */ +// #else /*CAN_WITH_RTL*/ +// typedef int can_irqreturn_t; +// #define CAN_IRQ_NONE 0 +// #define CAN_IRQ_HANDLED 1 +// #define CAN_IRQ_RETVAL(x) ((x) != 0) +/* #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \ + int irq_number, void *dev_id, struct pt_regs *regs*/ +// #endif /*CAN_WITH_RTL*/ + +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33)) +// #define can_synchronize_irq(irqnum) synchronize_irq() +// #else /* >=2.5.33 */ + #define can_synchronize_irq synchronize_irq +// #endif + +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +// #define del_timer_sync del_timer +// #endif /* <2.4.0 */ + +// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) + typedef unsigned long can_ioptr_t; + #define can_ioptr2ulong(ioaddr) ((unsigned long)(ioaddr)) + #define can_ulong2ioptr(addr) ((unsigned long)(addr)) + #define can_inb(ioaddr) inb(ioaddr) + #define can_outb(data,ioaddr) outb(data,ioaddr) + #define can_inw(ioaddr) inb(ioaddr) + #define can_outw(data,ioaddr) outb(data,ioaddr) + #define can_inl(ioaddr) inb(ioaddr) + #define can_outl(data,ioaddr) outb(data,ioaddr) +// #else /* >=2.6.9 */ +// typedef void __iomem * can_ioptr_t; +// #define can_ioptr2ulong(ioaddr) ((unsigned long __force)(ioaddr)) +// #define can_ulong2ioptr(addr) ((can_ioptr_t)(addr)) +// #define can_inb(ioaddr) inb(can_ioptr2ulong(ioaddr)) +// #define can_outb(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr)) +// #define can_inw(ioaddr) inb(can_ioptr2ulong(ioaddr)) +// #define can_outw(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr)) +// #define can_inl(ioaddr) inb(can_ioptr2ulong(ioaddr)) +// #define can_outl(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr)) +// #endif + +#define can_readb readb +#define can_writeb writeb +#define can_readw readw +#define can_writew writew +#define can_readl readl +#define can_writel writel + +#define can_ioport2ioptr can_ulong2ioptr + +#ifdef __HAVE_ARCH_CMPXCHG + #define CAN_HAVE_ARCH_CMPXCHG +#endif + +// #ifndef CAN_WITH_RTL +/* Standard LINUX kernel */ + +#define can_spinlock_t long +#define can_spin_irqflags_t unsigned long +#define can_spin_lock(lock) cli() +#define can_spin_unlock(lock) sti() +#define can_spin_lock_irqsave(lock,flags) save_and_cli(flags) +#define can_spin_unlock_irqrestore(lock,flags) restore_flags(flags) +#define can_spin_lock_init can_splck_init + +#define CAN_DEFINE_SPINLOCK(x) can_spinlock_t x = 0 + +static inline +void can_splck_init(can_spinlock_t *x) +{ + *x=0; +} + +// #if !defined(CONFIG_PREEMPT_RT) && ( defined(CONFIG_PREEMPT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ) +// #define can_preempt_disable preempt_disable +// #define can_preempt_enable preempt_enable +// #else /*CONFIG_PREEMPT*/ +#define can_preempt_disable() do { } while (0) +#define can_preempt_enable() do { } while (0) +// #endif /*CONFIG_PREEMPT*/ + +// #define can_enable_irq sti() +// #define can_disable_irq cli() +#define can_enable_irq(var) (var=1) +#define can_disable_irq(var) (var=0) + +#define can_printk printf +#define KERN_CRIT +#define KERN_ERR + +/// LINUX src: include/asm-arm/bitops.h + +#define set_bit ____atomic_set_bit +#define clear_bit ____atomic_clear_bit +#define change_bit ____atomic_change_bit +#define test_and_set_bit ____atomic_test_and_set_bit +#define test_and_clear_bit ____atomic_test_and_clear_bit +#define test_and_change_bit ____atomic_test_and_change_bit +#define raw_local_irq_save(flags) save_and_cli(flags); +#define raw_local_irq_restore(flags) restore_flags(flags); +/* + * These functions are the basis of our bit ops. + * + * First, the atomic bitops. These use native endian. + */ +static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + *p |= mask; + raw_local_irq_restore(flags); +} + +static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + *p &= ~mask; + raw_local_irq_restore(flags); +} + +static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + *p ^= mask; + raw_local_irq_restore(flags); +} + +static inline int +____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + res = *p; + *p = res | mask; + raw_local_irq_restore(flags); + + return res & mask; +} + +static inline int +____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + res = *p; + *p = res & ~mask; + raw_local_irq_restore(flags); + + return res & mask; +} + +static inline int +____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + res = *p; + *p = res ^ mask; + raw_local_irq_restore(flags); + + return res & mask; +} + +/// LINUX src: include/asm-arm/atomic.h + +#define atomic_read(v) ((v)->counter) + +#define atomic_set(v,i) (((v)->counter) = (i)) + +static inline int atomic_add_return(int i, atomic_t *v) +{ + unsigned long flags; + int val; + + raw_local_irq_save(flags); + val = v->counter; + v->counter = val += i; + raw_local_irq_restore(flags); + + return val; +} + +static inline int atomic_sub_return(int i, atomic_t *v) +{ + unsigned long flags; + int val; + + raw_local_irq_save(flags); + val = v->counter; + v->counter = val -= i; + raw_local_irq_restore(flags); + + return val; +} + +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + int ret; + unsigned long flags; + + raw_local_irq_save(flags); + ret = v->counter; + if (ret == old) + v->counter = new; + raw_local_irq_restore(flags); + + return ret; +} + +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +static inline int atomic_add_unless(atomic_t *v, int a, int u) +{ + int c, old; + + c = atomic_read(v); + while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c) + c = old; + return c != u; +} +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + +#define atomic_add(i, v) (void) atomic_add_return(i, v) +#define atomic_inc(v) (void) atomic_add_return(1, v) +#define atomic_sub(i, v) (void) atomic_sub_return(i, v) +#define atomic_dec(v) (void) atomic_sub_return(1, v) + +#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) +#define atomic_inc_return(v) (atomic_add_return(1, v)) +#define atomic_dec_return(v) (atomic_sub_return(1, v)) +#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) + +#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) + +/* Atomic operations are already serializing on ARM */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +/// LINUX src: include/linux/interrupt.h + +#define ATOMIC_INIT(i) { (i) } + +/* Tasklets --- multithreaded analogue of BHs. + + Main feature differing them of generic softirqs: tasklet + is running only on one CPU simultaneously. + + Main feature differing them of BHs: different tasklets + may be run simultaneously on different CPUs. + + Properties: + * If tasklet_schedule() is called, then tasklet is guaranteed + to be executed on some cpu at least once after this. + * If the tasklet is already scheduled, but its excecution is still not + started, it will be executed only once. + * If this tasklet is already running on another CPU (or schedule is called + from tasklet itself), it is rescheduled for later. + * Tasklet is strictly serialized wrt itself, but not + wrt another tasklets. If client needs some intertask synchronization, + he makes it with spinlocks. + */ + +struct tasklet_struct +{ + struct tasklet_struct *next; + unsigned long state; + atomic_t count; + void (*func)(unsigned long); + unsigned long data; +}; + +#define DECLARE_TASKLET(name, func, data) \ +struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } + +#define DECLARE_TASKLET_DISABLED(name, func, data) \ +struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data } + +/* CAN message timestamp source, it is called from interrupt context */ +//#define can_gettimeofday do_gettimeofday + +/// from linux/timer.h + +struct tvec_t_base_s; + +struct timer_list { + struct list_head entry; + unsigned long expires; + + void (*function)(unsigned long); + unsigned long data; + + struct tvec_t_base_s *base; +#ifdef CONFIG_TIMER_STATS + void *start_site; + char start_comm[16]; + int start_pid; +#endif +}; + +static inline void udelay(long time) +{ + volatile long ticks=(time * CCLK) / 2000000; + do{ + ticks--; + } + while(ticks>0); +} + +// #else /*CAN_WITH_RTL*/ +// +// #define can_spinlock_t long +// #define can_spin_irqflags_t unsigned long +// #define can_spin_lock save_and_cli +// #define can_spin_unlock restore_flags +// #define can_spin_lock_irqsave save_and_cli +// #define can_spin_unlock_irqrestore restore_flags +// #define can_spin_lock_init can_splck_init +// +// #define CAN_DEFINE_SPINLOCK(x) can_spinlock_t x = 0 +// +// #define can_preempt_disable() do { } while (0) +// #define can_preempt_enable() do { } while (0) +// +// #define can_enable_irq sti +// #define can_disable_irq cli +// +// #define can_printk rtl_printf +// +// /* +// * terrible hack to test rtl_file private_data concept, ugh !!! +// * this would result in crash on architectures, where +// * sizeof(int) < sizeof(void *) +// */ +// #define can_set_rtl_file_private_data(fptr, p) do{ fptr->f_minor=(long)(p); } while(0) +// #define can_get_rtl_file_private_data(fptr) ((void*)((fptr)->f_minor)) +// +// extern can_spinlock_t can_irq_manipulation_lock; +// +// /* CAN message timestamp source, it is called from interrupt context */ +/*#define can_gettimeofday(ptr) do {\ + struct timespec temp_timespec;\ + clock_gettime(CLOCK_REALTIME,&temp_timespec);\ + ptr->tv_usec=temp_timespec.tv_nsec/1000;\ + ptr->tv_sec=temp_timespec.tv_sec;\ + } while(0)*/ +// +// #endif /*CAN_WITH_RTL*/ + +#endif /*_CAN_SYSDEP_H*/ diff --git a/embedded/app/usbcan/can/canmsg.h b/embedded/app/usbcan/can/canmsg.h new file mode 100644 index 0000000..779f68c --- /dev/null +++ b/embedded/app/usbcan/can/canmsg.h @@ -0,0 +1,136 @@ +/* canmsg.h - common kernel-space and user-space CAN message structure + * Linux CAN-bus device driver. + * Written by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#ifndef _CANMSG_T_H +#define _CANMSG_T_H + +#ifdef __KERNEL__ + +#include +#include + +#else /* __KERNEL__ */ + +#include +#include + +#endif /* __KERNEL__ */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * CAN_MSG_VERSION_2 enables new canmsg_t layout compatible with + * can4linux project from http://www.port.de/ + * + */ +#define CAN_MSG_VERSION_2 + +/* Number of data bytes in one CAN message */ +#define CAN_MSG_LENGTH 8 + +#ifdef CAN_MSG_VERSION_2 + +typedef struct timeval canmsg_tstamp_t ; + +typedef unsigned long canmsg_id_t; + +/** + * struct canmsg_t - structure representing CAN message + * @flags: message flags + * %MSG_RTR .. message is Remote Transmission Request, + * %MSG_EXT .. message with extended ID, + * %MSG_OVR .. indication of queue overflow condition, + * %MSG_LOCAL .. message originates from this node. + * @cob: communication object number (not used) + * @id: ID of CAN message + * @timestamp: not used + * @length: length of used data + * @data: data bytes buffer + * + * Header: canmsg.h + */ +struct canmsg_t { + int flags; + int cob; + canmsg_id_t id; + canmsg_tstamp_t timestamp; + unsigned short length; + unsigned char data[CAN_MSG_LENGTH]; +}; + +#else /*CAN_MSG_VERSION_2*/ +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif +/* Old, deprecated version of canmsg_t structure */ +struct canmsg_t { + short flags; + int cob; + canmsg_id_t id; + unsigned long timestamp; + unsigned int length; + unsigned char data[CAN_MSG_LENGTH]; +} PACKED; +#endif /*CAN_MSG_VERSION_2*/ + +typedef struct canmsg_t canmsg_t; + +/** + * struct canfilt_t - structure for acceptance filter setup + * @flags: message flags + * %MSG_RTR .. message is Remote Transmission Request, + * %MSG_EXT .. message with extended ID, + * %MSG_OVR .. indication of queue overflow condition, + * %MSG_LOCAL .. message originates from this node. + * there are corresponding mask bits + * %MSG_RTR_MASK, %MSG_EXT_MASK, %MSG_LOCAL_MASK. + * %MSG_PROCESSLOCAL enables local messages processing in the + * combination with global setting + * @queid: CAN queue identification in the case of the multiple + * queues per one user (open instance) + * @cob: communication object number (not used) + * @id: selected required value of cared ID id bits + * @mask: select bits significand for the comparation; + * 1 .. take care about corresponding ID bit, 0 .. don't care + * + * Header: canmsg.h + */ +struct canfilt_t { + int flags; + int queid; + int cob; + canmsg_id_t id; + canmsg_id_t mask; +}; + +typedef struct canfilt_t canfilt_t; + +/* Definitions to use for canmsg_t and canfilt_t flags */ +#define MSG_RTR (1<<0) +#define MSG_OVR (1<<1) +#define MSG_EXT (1<<2) +#define MSG_LOCAL (1<<3) +/* If you change above lines, check canque_filtid2internal function */ + +/* Additional definitions used for canfilt_t only */ +#define MSG_FILT_MASK_SHIFT 8 +#define MSG_RTR_MASK (MSG_RTR<obj_flags) +#define can_msgobj_set_fl(obj,obj_fl) \ + set_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags) +#define can_msgobj_clear_fl(obj,obj_fl) \ + clear_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags) +#define can_msgobj_test_and_set_fl(obj,obj_fl) \ + test_and_set_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags) +#define can_msgobj_test_and_clear_fl(obj,obj_fl) \ + test_and_clear_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags) + + +/* These flags can be used for the canchip_t structure flags data entry */ +#define CHIP_ATTACHED (1<<0) /* chip is attached to HW, release_chip() has to be called */ +#define CHIP_CONFIGURED (1<<1) /* chip is configured and prepared for communication */ +#define CHIP_SEGMENTED (1<<2) /* segmented access, ex: i82527 with 16 byte window*/ +#define CHIP_IRQ_SETUP (1<<3) /* IRQ handler has been set */ +#define CHIP_IRQ_PCI (1<<4) /* chip is on PCI board and uses PCI interrupt */ +#define CHIP_IRQ_VME (1<<5) /* interrupt is VME bus and requires VME bridge */ +#define CHIP_IRQ_CUSTOM (1<<6) /* custom interrupt provided by board or chip code */ +#define CHIP_IRQ_FAST (1<<7) /* interrupt handler only schedules postponed processing */ + +#define CHIP_MAX_IRQLOOP 1000 + +/* System independent defines of IRQ handled state */ +#define CANCHIP_IRQ_NONE 0 +#define CANCHIP_IRQ_HANDLED 1 +#define CANCHIP_IRQ_ACCEPTED 2 +#define CANCHIP_IRQ_STUCK 3 + +/* These flags can be used for the candevices_t structure flags data entry */ +#define CANDEV_PROGRAMMABLE_IRQ (1<<0) +#define CANDEV_IO_RESERVED (1<<1) + +/* Next flags are specific for struct canuser_t applications connection */ +#define CANUSER_RTL_CLIENT (1<<0) +#define CANUSER_RTL_MEM (1<<1) +#define CANUSER_DIRECT (1<<2) + + +enum timing_BTR1 { + MAX_TSEG1 = 15, + MAX_TSEG2 = 7 +}; + +/* Flags for baud_rate function */ +#define BTR1_SAM (1<<1) + +#endif diff --git a/embedded/app/usbcan/can/devcommon.h b/embedded/app/usbcan/can/devcommon.h new file mode 100644 index 0000000..837ffb6 --- /dev/null +++ b/embedded/app/usbcan/can/devcommon.h @@ -0,0 +1,15 @@ +/* devcommon.h - common device code + * Linux CAN-bus device driver. + * New CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "./canmsg.h" +#include "./can_sysdep.h" +#include "./constants.h" +#include "./can_queue.h" + +int canqueue_ends_init_chip(struct canque_ends_t *qends, struct canchip_t *chip, struct msgobj_t *obj); +int canqueue_ends_done_chip(struct canque_ends_t *qends); diff --git a/embedded/app/usbcan/can/errno-base.h b/embedded/app/usbcan/can/errno-base.h new file mode 100755 index 0000000..6511597 --- /dev/null +++ b/embedded/app/usbcan/can/errno-base.h @@ -0,0 +1,39 @@ +#ifndef _ASM_GENERIC_ERRNO_BASE_H +#define _ASM_GENERIC_ERRNO_BASE_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +#endif diff --git a/embedded/app/usbcan/can/errno.h b/embedded/app/usbcan/can/errno.h new file mode 100755 index 0000000..6edbe36 --- /dev/null +++ b/embedded/app/usbcan/can/errno.h @@ -0,0 +1,109 @@ +#ifndef _ASM_GENERIC_ERRNO_H +#define _ASM_GENERIC_ERRNO_H + +#include "./errno-base.h" + +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ +#define ECANCELED 125 /* Operation Canceled */ +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ + +/* for robust mutexes */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ + +#endif diff --git a/embedded/app/usbcan/can/finish.h b/embedded/app/usbcan/can/finish.h new file mode 100644 index 0000000..87df046 --- /dev/null +++ b/embedded/app/usbcan/can/finish.h @@ -0,0 +1,13 @@ +/* finish.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +void msgobj_done(struct msgobj_t *obj); +void canchip_done(struct canchip_t *chip); +void candevice_done(struct candevice_t *candev); +void canhardware_done(struct canhardware_t *candev); diff --git a/embedded/app/usbcan/can/i82527.h b/embedded/app/usbcan/can/i82527.h new file mode 100644 index 0000000..1747396 --- /dev/null +++ b/embedded/app/usbcan/can/i82527.h @@ -0,0 +1,177 @@ +/* i82527.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +int i82527_enable_configuration(struct canchip_t *chip); +int i82527_disable_configuration(struct canchip_t *chip); +int i82527_chip_config(struct canchip_t *chip); +int i82527_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, + int sampl_pt, int flags); +int i82527_standard_mask(struct canchip_t *chip, unsigned short code, + unsigned short mask); +int i82527_extended_mask(struct canchip_t *chip, unsigned long code, + unsigned long mask); +int i82527_message15_mask(struct canchip_t *chip, unsigned long code, + unsigned long mask); +int i82527_clear_objects(struct canchip_t *chip); +int i82527_config_irqs(struct canchip_t *chip, short irqs); +int i82527_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj); +int i82527_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); +int i82527_send_msg(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); +int i82527_remote_request(struct canchip_t *chip, struct msgobj_t *obj); +int i82527_set_btregs(struct canchip_t *chip, unsigned short btr0, + unsigned short btr1); +int i82527_start_chip(struct canchip_t *chip); +int i82527_stop_chip(struct canchip_t *chip); +int i82527_check_tx_stat(struct canchip_t *chip); +int i82527_irq_handler(int irq, struct canchip_t *chip); +int i82527_fill_chipspecops(struct canchip_t *chip); + + +#define MSG_OFFSET(object) ((object)*0x10) + +#define iCTL 0x00 // Control Register +#define iSTAT 0x01 // Status Register +#define iCPU 0x02 // CPU Interface Register +#define iHSR 0x04 // High Speed Read +#define iSGM0 0x06 // Standard Global Mask byte 0 +#define iSGM1 0x07 +#define iEGM0 0x08 // Extended Global Mask byte 0 +#define iEGM1 0x09 +#define iEGM2 0x0a +#define iEGM3 0x0b +#define i15M0 0x0c // Message 15 Mask byte 0 +#define i15M1 0x0d +#define i15M2 0x0e +#define i15M3 0x0f +#define iCLK 0x1f // Clock Out Register +#define iBUS 0x2f // Bus Configuration Register +#define iBT0 0x3f // Bit Timing Register byte 0 +#define iBT1 0x4f +#define iIRQ 0x5f // Interrupt Register +#define iP1C 0x9f // Port 1 Register +#define iP2C 0xaf // Port 2 Register +#define iP1I 0xbf // Port 1 Data In Register +#define iP2I 0xcf // Port 2 Data In Register +#define iP1O 0xdf // Port 1 Data Out Register +#define iP2O 0xef // Port 2 Data Out Register +#define iSRA 0xff // Serial Reset Address + +#define iMSGCTL0 0x00 /* First Control register */ +#define iMSGCTL1 0x01 /* Second Control register */ +#define iMSGID0 0x02 /* First Byte of Message ID */ +#define iMSGID1 0x03 +#define iMSGID2 0x04 +#define iMSGID3 0x05 +#define iMSGCFG 0x06 /* Message Configuration */ +#define iMSGDAT0 0x07 /* First Data Byte */ +#define iMSGDAT1 0x08 +#define iMSGDAT2 0x09 +#define iMSGDAT3 0x0a +#define iMSGDAT4 0x0b +#define iMSGDAT5 0x0c +#define iMSGDAT6 0x0d +#define iMSGDAT7 0x0e + +/* Control Register (0x00) */ +enum i82527_iCTL { + iCTL_INI = 1, // Initialization + iCTL_IE = 1<<1, // Interrupt Enable + iCTL_SIE = 1<<2, // Status Interrupt Enable + iCTL_EIE = 1<<3, // Error Interrupt Enable + iCTL_CCE = 1<<6 // Change Configuration Enable +}; + +/* Status Register (0x01) */ +enum i82527_iSTAT { + iSTAT_TXOK = 1<<3, // Transmit Message Successfully + iSTAT_RXOK = 1<<4, // Receive Message Successfully + iSTAT_WAKE = 1<<5, // Wake Up Status + iSTAT_WARN = 1<<6, // Warning Status + iSTAT_BOFF = 1<<7 // Bus Off Status +}; + +/* CPU Interface Register (0x02) */ +enum i82527_iCPU { + iCPU_CEN = 1, // Clock Out Enable + iCPU_MUX = 1<<2, // Multiplex + iCPU_SLP = 1<<3, // Sleep + iCPU_PWD = 1<<4, // Power Down Mode + iCPU_DMC = 1<<5, // Divide Memory Clock + iCPU_DSC = 1<<6, // Divide System Clock + iCPU_RST = 1<<7 // Hardware Reset Status +}; + +/* Clock Out Register (0x1f) */ +enum i82527_iCLK { + iCLK_CD0 = 1, // Clock Divider bit 0 + iCLK_CD1 = 1<<1, + iCLK_CD2 = 1<<2, + iCLK_CD3 = 1<<3, + iCLK_SL0 = 1<<4, // Slew Rate bit 0 + iCLK_SL1 = 1<<5 +}; + +/* Bus Configuration Register (0x2f) */ +enum i82527_iBUS { + iBUS_DR0 = 1, // Disconnect RX0 Input + iBUS_DR1 = 1<<1, // Disconnect RX1 Input + iBUS_DT1 = 1<<3, // Disconnect TX1 Output + iBUS_POL = 1<<5, // Polarity + iBUS_CBY = 1<<6 // Comparator Bypass +}; + +#define RESET 1 // Bit Pair Reset Status +#define SET 2 // Bit Pair Set Status +#define UNCHANGED 3 // Bit Pair Unchanged + +/* Message Control Register 0 (Base Address + 0x0) */ +enum i82527_iMSGCTL0 { + INTPD_SET = SET, // Interrupt pending + INTPD_RES = RESET, // No Interrupt pending + INTPD_UNC = UNCHANGED, + RXIE_SET = SET<<2, // Receive Interrupt Enable + RXIE_RES = RESET<<2, // Receive Interrupt Disable + RXIE_UNC = UNCHANGED<<2, + TXIE_SET = SET<<4, // Transmit Interrupt Enable + TXIE_RES = RESET<<4, // Transmit Interrupt Disable + TXIE_UNC = UNCHANGED<<4, + MVAL_SET = SET<<6, // Message Valid + MVAL_RES = RESET<<6, // Message Invalid + MVAL_UNC = UNCHANGED<<6 +}; + +/* Message Control Register 1 (Base Address + 0x01) */ +enum i82527_iMSGCTL1 { + NEWD_SET = SET, // New Data + NEWD_RES = RESET, // No New Data + NEWD_UNC = UNCHANGED, + MLST_SET = SET<<2, // Message Lost + MLST_RES = RESET<<2, // No Message Lost + MLST_UNC = UNCHANGED<<2, + CPUU_SET = SET<<2, // CPU Updating + CPUU_RES = RESET<<2, // No CPU Updating + CPUU_UNC = UNCHANGED<<2, + TXRQ_SET = SET<<4, // Transmission Request + TXRQ_RES = RESET<<4, // No Transmission Request + TXRQ_UNC = UNCHANGED<<4, + RMPD_SET = SET<<6, // Remote Request Pending + RMPD_RES = RESET<<6, // No Remote Request Pending + RMPD_UNC = UNCHANGED<<6 +}; + +/* Message Configuration Register (Base Address + 0x06) */ +enum i82527_iMSGCFG { + MCFG_XTD = 1<<2, // Extended Identifier + MCFG_DIR = 1<<3 // Direction is Transmit +}; + +void i82527_seg_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address); +unsigned i82527_seg_read_reg(const struct canchip_t *chip, unsigned address); diff --git a/embedded/app/usbcan/can/main.h b/embedded/app/usbcan/can/main.h new file mode 100644 index 0000000..23c8ab3 --- /dev/null +++ b/embedded/app/usbcan/can/main.h @@ -0,0 +1,523 @@ +/* main.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#ifndef MAIN_H +#define MAIN_H + +#include + +#include "./can.h" +#include "./constants.h" +#include "./ul_listbase.h" +#include "./can_sysless.h" +#include "./can_queue.h" +#include "./errno.h" + +#ifdef CAN_DEBUG + #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "USBCAN(debug): " fmt,\ + ##args) +#else + #define DEBUGMSG(fmt,args...) +#endif + +#define CANMSG(fmt,args...) can_printk(KERN_ERR "USBCAN: " fmt,##args) + + +extern can_spinlock_t canuser_manipulation_lock; + +/** + * struct canhardware_t - structure representing pointers to all CAN boards + * @nr_boards: number of present boards + * @rtr_queue: RTR - remote transmission request queue (expect some changes there) + * @rtr_lock: locking for RTR queue + * @candevice: array of pointers to CAN devices/boards + */ +struct canhardware_t { + int nr_boards; + struct rtr_id *rtr_queue; + can_spinlock_t rtr_lock; + struct candevice_t *candevice[MAX_HW_CARDS]; +}; + +/** + * struct candevice_t - CAN device/board structure + * @hwname: text string with board type + * @candev_idx: board index in canhardware_t.candevice[] + * @io_addr: IO/physical MEM address + * @res_addr: optional reset register port + * @dev_base_addr: CPU translated IO/virtual MEM address + * @flags: board flags: %PROGRAMMABLE_IRQ .. interrupt number + * can be programmed into board + * @nr_all_chips: number of chips present on the board + * @nr_82527_chips: number of Intel 8257 chips + * @nr_sja1000_chips: number of Philips SJA100 chips + * @chip: array of pointers to the chip structures + * @hwspecops: pointer to board specific operations + * @hosthardware_p: pointer to the root hardware structure + * @sysdevptr: union reserved for pointer to bus specific + * device structure (case @pcidev is used for PCI devices) + * + * The structure represent configuration and state of associated board. + * The driver infrastructure prepares this structure and calls + * board type specific board_register() function. The board support provided + * register function fills right function pointers in @hwspecops structure. + * Then driver setup calls functions init_hw_data(), init_chip_data(), + * init_chip_data(), init_obj_data() and program_irq(). Function init_hw_data() + * and init_chip_data() have to specify number and types of connected chips + * or objects respectively. + * The use of @nr_all_chips is preferred over use of fields @nr_82527_chips + * and @nr_sja1000_chips in the board non-specific functions. + * The @io_addr and @dev_base_addr is filled from module parameters + * to the same value. The request_io function can fix-up @dev_base_addr + * field if virtual address is different than bus address. + */ +struct candevice_t { + char *hwname; /* text board type */ + int candev_idx; /* board index in canhardware_t.candevice[] */ + unsigned long io_addr; /* IO/physical MEM address */ + unsigned long res_addr; /* optional reset register port */ + unsigned long dev_base_addr; /* CPU translated IO/virtual MEM address */ + unsigned int flags; + int nr_all_chips; + int nr_82527_chips; + int nr_sja1000_chips; + can_spinlock_t device_lock; + struct canchip_t *chip[MAX_HW_CHIPS]; + + struct hwspecops_t *hwspecops; + + struct canhardware_t *hosthardware_p; + + union { + void *anydev; + #ifdef CAN_ENABLE_PCI_SUPPORT + struct pci_dev *pcidev; + #endif /*CAN_ENABLE_PCI_SUPPORT*/ + } sysdevptr; + +}; + +/** + * struct canchip_t - CAN chip state and type information + * @chip_type: text string describing chip type + * @chip_idx: index of the chip in candevice_t.chip[] array + * @chip_irq: chip interrupt number if any + * @chip_base_addr: chip base address in the CPU IO or virtual memory space + * @flags: chip flags: %CHIP_CONFIGURED .. chip is configured, + * %CHIP_SEGMENTED .. access to the chip is segmented (mainly for i82527 chips) + * @clock: chip base clock frequency in Hz + * @baudrate: selected chip baudrate in Hz + * @write_register: write chip register function copy + * @read_register: read chip register function copy + * @chip_data: pointer for optional chip specific data extension + * @sja_cdr_reg: SJA specific register - + * holds hardware specific options for the Clock Divider + * register. Options defined in the sja1000.h file: + * %CDR_CLKOUT_MASK, %CDR_CLK_OFF, %CDR_RXINPEN, %CDR_CBP, %CDR_PELICAN + * @sja_ocr_reg: SJA specific register - + * hold hardware specific options for the Output Control + * register. Options defined in the sja1000.h file: + * %OCR_MODE_BIPHASE, %OCR_MODE_TEST, %OCR_MODE_NORMAL, %OCR_MODE_CLOCK, + * %OCR_TX0_LH, %OCR_TX1_ZZ. + * @int_cpu_reg: Intel specific register - + * holds hardware specific options for the CPU Interface + * register. Options defined in the i82527.h file: + * %iCPU_CEN, %iCPU_MUX, %iCPU_SLP, %iCPU_PWD, %iCPU_DMC, %iCPU_DSC, %iCPU_RST. + * @int_clk_reg: Intel specific register - + * holds hardware specific options for the Clock Out + * register. Options defined in the i82527.h file: + * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1. + * @int_bus_reg: Intel specific register - + * holds hardware specific options for the Bus Configuration + * register. Options defined in the i82527.h file: + * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY. + * @msgobj: array of pointers to individual communication objects + * @chipspecops: pointer to the set of chip specific object filled by init_chip_data() function + * @hostdevice: pointer to chip hosting board + * @max_objects: maximal number of communication objects connected to this chip + * @chip_lock: reserved for synchronization of the chip supporting routines + * (not used in the current driver version) + * @worker_thread: chip worker thread ID (RT-Linux specific field) + * @pend_flags: holds information about pending interrupt and tx_wake() operations + * (RT-Linux specific field). Masks values: + * %MSGOBJ_TX_REQUEST .. some of the message objects requires tx_wake() call, + * %MSGOBJ_IRQ_REQUEST .. chip interrupt processing required + * %MSGOBJ_WORKER_WAKE .. marks, that worker thread should be waked + * for some of above reasons + * + * The fields @write_register and @read_register are copied from + * corresponding fields from @hwspecops structure + * (chip->hostdevice->hwspecops->write_register and + * chip->hostdevice->hwspecops->read_register) + * to speedup can_write_reg() and can_read_reg() functions. + */ +struct canchip_t { + char *chip_type; + int chip_idx; /* chip index in candevice_t.chip[] */ + int chip_irq; + unsigned long chip_base_addr; + unsigned int flags; + long clock; /* Chip clock in Hz */ + long baudrate; + + void (*write_register)(unsigned data,unsigned long address); + unsigned (*read_register)(unsigned long address); + + void *chip_data; + + unsigned short sja_cdr_reg; /* sja1000 only! */ + unsigned short sja_ocr_reg; /* sja1000 only! */ + unsigned short int_cpu_reg; /* intel 82527 only! */ + unsigned short int_clk_reg; /* intel 82527 only! */ + unsigned short int_bus_reg; /* intel 82527 only! */ + + struct msgobj_t *msgobj[MAX_MSGOBJS]; + + struct chipspecops_t *chipspecops; + + struct candevice_t *hostdevice; + + int max_objects; /* 1 for sja1000, 15 for i82527 */ + + can_spinlock_t chip_lock; + + #ifdef CAN_WITH_RTL + pthread_t worker_thread; + unsigned long pend_flags; + #endif /*CAN_WITH_RTL*/ +}; + +/** + * struct msgobj_t - structure holding communication object state + * @obj_base_addr: + * @minor: associated device minor number + * @object: object number in canchip_t structure +1 + * @flags: message object flags + * @ret: field holding status of the last Tx operation + * @qends: pointer to message object corresponding ends structure + * @tx_qedge: edge corresponding to transmitted message + * @tx_slot: slot holding transmitted message, slot is taken from + * canque_test_outslot() call and is freed by canque_free_outslot() + * or rescheduled canque_again_outslot() + * @tx_retry_cnt: transmission attempt counter + * @tx_timeout: can be used by chip driver to check for the transmission timeout + * @rx_msg: temporary storage to hold received messages before + * calling to canque_filter_msg2edges() + * @hostchip: pointer to the &canchip_t structure this object belongs to + * @obj_used: counter of users (associated file structures for Linux + * userspace clients) of this object + * @obj_users: list of user structures of type &canuser_t. + * @obj_flags: message object specific flags. Masks values: + * %MSGOBJ_TX_REQUEST .. the message object requests TX activation + * %MSGOBJ_TX_LOCK .. some IRQ routine or callback on some CPU + * is running inside TX activation processing code + * @rx_preconfig_id: place to store RX message identifier for some chip types + * that reuse same object for TX + */ +struct msgobj_t { + unsigned long obj_base_addr; + unsigned int minor; /* associated device minor number */ + unsigned int object; /* object number in canchip_t +1 for debug printk */ + unsigned long obj_flags; + int ret; + + struct canque_ends_t *qends; + + struct canque_edge_t *tx_qedge; + struct canque_slot_t *tx_slot; + int tx_retry_cnt; + struct timer_list tx_timeout; + + struct canmsg_t rx_msg; + + struct canchip_t *hostchip; + + unsigned long rx_preconfig_id; + + atomic_t obj_used; + struct list_head obj_users; +}; + +#define CAN_USER_MAGIC 0x05402033 + +/** + * struct canuser_t - structure holding CAN user/client state + * @flags: used to distinguish Linux/RT-Linux type + * @peers: for connection into list of object users + * @qends: pointer to the ends structure corresponding for this user + * @msgobj: communication object the user is connected to + * @rx_edge0: default receive queue for filter IOCTL + * @userinfo: stores user context specific information. + * The field @fileinfo.file holds pointer to open device file state structure + * for the Linux user-space client applications + * @magic: magic number to check consistency when pointer is retrieved + * from file private field + */ +struct canuser_t { + unsigned long flags; + struct list_head peers; + struct canque_ends_t *qends; + struct msgobj_t *msgobj; + struct canque_edge_t *rx_edge0; /* simplifies IOCTL */ + union { + struct { + struct file *file; /* back ptr to file */ + } fileinfo; + #ifdef CAN_WITH_RTL + struct { + struct rtl_file *file; + } rtlinfo; + #endif /*CAN_WITH_RTL*/ + } userinfo; + int magic; +}; + +/** + * struct hwspecops_t - hardware/board specific operations + * @request_io: reserve io or memory range for can board + * @release_io: free reserved io memory range + * @reset: hardware reset routine + * @init_hw_data: called to initialize &candevice_t structure, mainly + * @res_add, @nr_all_chips, @nr_82527_chips, @nr_sja1000_chips + * and @flags fields + * @init_chip_data: called initialize each &canchip_t structure, mainly + * @chip_type, @chip_base_addr, @clock and chip specific registers. + * It is responsible to setup &canchip_t->@chipspecops functions + * for non-standard chip types (type other than "i82527", "sja1000" or "sja1000p") + * @init_obj_data: called initialize each &msgobj_t structure, + * mainly @obj_base_addr field. + * @program_irq: program interrupt generation hardware of the board + * if flag %PROGRAMMABLE_IRQ is present for specified device/board + * @write_register: low level write register routine + * @read_register: low level read register routine + */ +struct hwspecops_t { + int (*request_io)(struct candevice_t *candev); + int (*release_io)(struct candevice_t *candev); + int (*reset)(struct candevice_t *candev); + int (*init_hw_data)(struct candevice_t *candev); + int (*init_chip_data)(struct candevice_t *candev, int chipnr); + int (*init_obj_data)(struct canchip_t *chip, int objnr); + int (*program_irq)(struct candevice_t *candev); + void (*write_register)(unsigned data,unsigned long address); + unsigned (*read_register)(unsigned long address); +}; + +/** + * struct chipspecops_t - can controller chip specific operations + * @chip_config: CAN chip configuration + * @baud_rate: set communication parameters + * @standard_mask: setup of mask for message filtering + * @extended_mask: setup of extended mask for message filtering + * @message15_mask: set mask of i82527 message object 15 + * @clear_objects: clears state of all message object residing in chip + * @config_irqs: tunes chip hardware interrupt delivery + * @pre_read_config: prepares message object for message reception + * @pre_write_config: prepares message object for message transmission + * @send_msg: initiate message transmission + * @remote_request: configures message object and asks for RTR message + * @check_tx_stat: checks state of transmission engine + * @wakeup_tx: wakeup TX processing + * @filtch_rq: optional routine for propagation of outgoing edges filters to HW + * @enable_configuration: enable chip configuration mode + * @disable_configuration: disable chip configuration mode + * @set_btregs: configures bitrate registers + * @attach_to_chip: attaches to the chip, setups registers and possibly state informations + * @release_chip: called before chip structure removal if %CHIP_ATTACHED is set + * @start_chip: starts chip message processing + * @stop_chip: stops chip message processing + * @irq_handler: interrupt service routine + * @irq_accept: optional fast irq accept routine responsible for blocking further interrupts + */ +struct chipspecops_t { + int (*chip_config)(struct canchip_t *chip); + int (*baud_rate)(struct canchip_t *chip, int rate, int clock, int sjw, + int sampl_pt, int flags); + int (*standard_mask)(struct canchip_t *chip, unsigned short code, + unsigned short mask); + int (*extended_mask)(struct canchip_t *chip, unsigned long code, + unsigned long mask); + int (*message15_mask)(struct canchip_t *chip, unsigned long code, + unsigned long mask); + int (*clear_objects)(struct canchip_t *chip); + int (*config_irqs)(struct canchip_t *chip, short irqs); + int (*pre_read_config)(struct canchip_t *chip, struct msgobj_t *obj); + int (*pre_write_config)(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); + int (*send_msg)(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); + int (*remote_request)(struct canchip_t *chip, struct msgobj_t *obj); + int (*check_tx_stat)(struct canchip_t *chip); + int (*wakeup_tx)(struct canchip_t *chip, struct msgobj_t *obj); + int (*filtch_rq)(struct canchip_t *chip, struct msgobj_t *obj); + int (*enable_configuration)(struct canchip_t *chip); + int (*disable_configuration)(struct canchip_t *chip); + int (*set_btregs)(struct canchip_t *chip, unsigned short btr0, + unsigned short btr1); + int (*attach_to_chip)(struct canchip_t *chip); + int (*release_chip)(struct canchip_t *chip); + int (*start_chip)(struct canchip_t *chip); + int (*stop_chip)(struct canchip_t *chip); + int (*irq_handler)(int irq, struct canchip_t *chip); + int (*irq_accept)(int irq, struct canchip_t *chip); +}; + +struct mem_addr { + void *address; + struct mem_addr *next; + size_t size; +}; + +/* Structure for the RTR queue */ +struct rtr_id { + unsigned long id; + struct canmsg_t *rtr_message; + wait_queue_head_t rtr_wq; + struct rtr_id *next; +}; + +extern int major; +extern int minor[MAX_TOT_CHIPS]; +extern int extended; +extern int baudrate[MAX_TOT_CHIPS]; +extern char *hw[MAX_HW_CARDS]; +extern int irq[MAX_IRQ]; +extern unsigned long io[MAX_HW_CARDS]; +extern int processlocal; + +extern struct canhardware_t *hardware_p; +//extern struct canchip_t *chips_p[MAX_TOT_CHIPS]; +struct canchip_t *chips_p[MAX_TOT_CHIPS]; +extern struct msgobj_t *objects_p[MAX_TOT_MSGOBJS]; + +extern struct mem_addr *mem_head; + + +#if defined(CONFIG_OC_LINCAN_PORTIO_ONLY) +extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address) +{ + outb(data, chip->chip_base_addr+address); +} +extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address) +{ + return inb(chip->chip_base_addr+address); +} +extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj, + unsigned char data, unsigned address) +{ + outb(data, obj->obj_base_addr+address); +} +extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj, + unsigned address) +{ + return inb(obj->obj_base_addr+address); +} + +#elif defined(CONFIG_OC_LINCAN_MEMIO_ONLY) +extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address) +{ + writeb(data, chip->chip_base_addr+address); +} +extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address) +{ + return readb(chip->chip_base_addr+address); +} +extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj, + unsigned char data, unsigned address) +{ + writeb(data, obj->obj_base_addr+address); +} +extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj, + unsigned address) +{ + return readb(obj->obj_base_addr+address); +} + +#else /*CONFIG_OC_LINCAN_DYNAMICIO*/ +#ifndef CONFIG_OC_LINCAN_DYNAMICIO +#define CONFIG_OC_LINCAN_DYNAMICIO +#endif + +/* Inline function to write to the hardware registers. The argument address is + * relative to the memory map of the chip and not the absolute memory address. + */ +extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address) +{ + unsigned long address_to_write; + address_to_write = chip->chip_base_addr+address; + chip->write_register(data, address_to_write); +} + +extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address) +{ + unsigned long address_to_read; + address_to_read = chip->chip_base_addr+address; + return chip->read_register(address_to_read); +} + +extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj, + unsigned char data, unsigned address) +{ + unsigned long address_to_write; + address_to_write = obj->obj_base_addr+address; + chip->write_register(data, address_to_write); +} + +extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj, + unsigned address) +{ + unsigned long address_to_read; + address_to_read = obj->obj_base_addr+address; + return chip->read_register(address_to_read); +} + +#endif /*CONFIG_OC_LINCAN_DYNAMICIO*/ + +int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base); +int can_request_io_region(unsigned long start, unsigned long n, const char *name); +void can_release_io_region(unsigned long start, unsigned long n); +int can_request_mem_region(unsigned long start, unsigned long n, const char *name); +void can_release_mem_region(unsigned long start, unsigned long n); + +struct boardtype_t { + const char *boardtype; + int (*board_register)(struct hwspecops_t *hwspecops); + int irqnum; +}; + +const struct boardtype_t* boardtype_find(const char *str); + +int can_check_dev_taken(void *anydev); + +#if defined(can_gettimeofday) && defined(CAN_MSG_VERSION_2) && 1 +static inline +void can_filltimestamp(canmsg_tstamp_t *ptimestamp) +{ + can_gettimeofday(ptimestamp); +} +#else /* No timestamp support, set field to zero */ +static inline +void can_filltimestamp(canmsg_tstamp_t *ptimestamp) +{ + #ifdef CAN_MSG_VERSION_2 + ptimestamp->tv_sec = 0; + ptimestamp->tv_usec = 0; + #else /* CAN_MSG_VERSION_2 */ + *ptimestamp = 0; + #endif /* CAN_MSG_VERSION_2 */ + +} +#endif /* End of timestamp source selection */ + +#ifdef CAN_WITH_RTL +extern int can_rtl_priority; +#endif /*CAN_WITH_RTL*/ + +#endif /* MAIN_H */ + diff --git a/embedded/app/usbcan/can/modparms.h b/embedded/app/usbcan/can/modparms.h new file mode 100644 index 0000000..6691931 --- /dev/null +++ b/embedded/app/usbcan/can/modparms.h @@ -0,0 +1,10 @@ +/* mod_parms.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +int parse_mod_parms(void); diff --git a/embedded/app/usbcan/can/setup.h b/embedded/app/usbcan/can/setup.h new file mode 100644 index 0000000..d35a8b1 --- /dev/null +++ b/embedded/app/usbcan/can/setup.h @@ -0,0 +1,16 @@ +/* setup.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +int init_hw_struct(void); +int list_hw(void); +void *can_checked_malloc(size_t size); +int can_checked_free(void *address_p); +int can_del_mem_list(void); +int can_chip_setup_irq(struct canchip_t *chip); +void can_chip_free_irq(struct canchip_t *chip); diff --git a/embedded/app/usbcan/can/sja1000p.h b/embedded/app/usbcan/can/sja1000p.h new file mode 100644 index 0000000..fe81a9c --- /dev/null +++ b/embedded/app/usbcan/can/sja1000p.h @@ -0,0 +1,205 @@ +/* sja1000p.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Added by T.Motylewski@bfad.de + * See app. note an97076.pdf from Philips Semiconductors + * and SJA1000 data sheet + * PELICAN mode + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#ifndef SJA1000P_H +#define SJA1000P_H + +int sja1000p_chip_config(struct canchip_t *chip); +int sja1000p_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask); +int sja1000p_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, + int sampl_pt, int flags); +int sja1000p_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj); +int sja1000p_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); +int sja1000p_send_msg(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); +int sja1000p_fill_chipspecops(struct canchip_t *chip); +int sja1000p_irq_handler(int irq, struct canchip_t *chip); + + +/* PeliCAN mode */ +enum SJA1000_PeliCAN_regs { + SJAMOD = 0x00, +/// Command register + SJACMR = 0x01, +/// Status register + SJASR = 0x02, +/// Interrupt register + SJAIR = 0x03, +/// Interrupt Enable + SJAIER = 0x04, +/// Bus Timing register 0 + SJABTR0 = 0x06, +/// Bus Timing register 1 + SJABTR1 = 0x07, +/// Output Control register + SJAOCR = 0x08, +/// Arbitration Lost Capture + SJAALC = 0x0b, +/// Error Code Capture + SJAECC = 0x0c, +/// Error Warning Limit + SJAEWLR = 0x0d, +/// RX Error Counter + SJARXERR = 0x0e, +/// TX Error Counter + SJATXERR0 = 0x0e, + SJATXERR1 = 0x0f, +/// Rx Message Counter (number of msgs. in RX FIFO + SJARMC = 0x1d, +/// Rx Buffer Start Addr. (address of current MSG) + SJARBSA = 0x1e, +/// Transmit Buffer (write) Receive Buffer (read) Frame Information + SJAFRM = 0x10, +/// ID bytes (11 bits in 0 and 1 or 16 bits in 0,1 and 13 bits in 2,3 (extended)) + SJAID0 = 0x11, SJAID1 = 0x12, +/// ID cont. for extended frames + SJAID2 = 0x13, SJAID3 = 0x14, +/// Data start standard frame + SJADATS = 0x13, +/// Data start extended frame + SJADATE = 0x15, +/// Acceptance Code (4 bytes) in RESET mode + SJAACR0 = 0x10, +/// Acceptance Mask (4 bytes) in RESET mode + SJAAMR0 = 0x14, +/// 4 bytes + SJA_PeliCAN_AC_LEN = 4, +/// Clock Divider + SJACDR = 0x1f +}; + +/** Mode Register 0x00 */ +enum sja1000_PeliCAN_MOD { + sjaMOD_SM = 1<<4, // Sleep Mode (writable only in OPERATING mode) + sjaMOD_AFM= 1<<3, // Acceptance Filter Mode (writable only in RESET) + sjaMOD_STM= 1<<2, // Self Test Mode (writable only in RESET) + sjaMOD_LOM= 1<<1, // Listen Only Mode (writable only in RESET) + sjaMOD_RM = 1 // Reset Mode +}; + +/** Command Register 0x01 */ +enum sja1000_PeliCAN_CMR { + sjaCMR_SRR= 1<<4, // Self Reception Request (GoToSleep in BASIC mode) + sjaCMR_CDO= 1<<3, // Clear Data Overrun + sjaCMR_RRB= 1<<2, // Release Receive Buffer + sjaCMR_AT = 1<<1, // Abort Transmission + sjaCMR_TR = 1 }; // Transmission Request + +/** Status Register 0x02 */ +enum sja1000_SR { + sjaSR_BS = 1<<7, // Bus Status + sjaSR_ES = 1<<6, // Error Status + sjaSR_TS = 1<<5, // Transmit Status + sjaSR_RS = 1<<4, // Receive Status + sjaSR_TCS = 1<<3, // Transmission Complete Status + sjaSR_TBS = 1<<2, // Transmit Buffer Status + sjaSR_DOS = 1<<1, // Data Overrun Status + sjaSR_RBS = 1 }; // Receive Buffer Status + +/** Interrupt Enable Register 0x04 */ +enum sja1000_PeliCAN_IER { + sjaIER_BEIE= 1<<7, // Bus Error Interrupt Enable + sjaIER_ALIE= 1<<6, // Arbitration Lost Interrupt Enable + sjaIER_EPIE= 1<<5, // Error Passive Interrupt Enable + sjaIER_WUIE= 1<<4, // Wake-Up Interrupt Enable + sjaIER_DOIE= 1<<3, // Data Overrun Interrupt Enable + sjaIER_EIE = 1<<2, // Error Warning Interrupt Enable + sjaIER_TIE = 1<<1, // Transmit Interrupt Enable + sjaIER_RIE = 1, // Receive Interrupt Enable + sjaENABLE_INTERRUPTS = sjaIER_BEIE|sjaIER_EPIE|sjaIER_DOIE|sjaIER_EIE|sjaIER_TIE|sjaIER_RIE, + sjaDISABLE_INTERRUPTS = 0 +// WARNING: the chip automatically enters RESET (bus off) mode when + // error counter > 255 +}; + +/** Arbitration Lost Capture Register 0x0b. + * Counting starts from 0 (bit1 of ID). Bits 5-7 reserved*/ +enum sja1000_PeliCAN_ALC { + sjaALC_SRTR = 0x0b,// Arbitration lost in bit SRTR + sjaALC_IDE = 0x1c, // Arbitration lost in bit IDE + sjaALC_RTR = 0x1f, // Arbitration lost in RTR +}; + +/** Error Code Capture Register 0x0c*/ +enum sja1000_PeliCAN_ECC { + sjaECC_ERCC1 = 1<<7, + sjaECC_ERCC0 = 1<<6, + sjaECC_BIT = 0, + sjaECC_FORM = sjaECC_ERCC0, + sjaECC_STUFF = sjaECC_ERCC1, + sjaECC_OTHER = sjaECC_ERCC0 | sjaECC_ERCC1, + sjaECC_DIR = 1<<5, // 1 == RX, 0 == TX + sjaECC_SEG_M = (1<<5) -1 // Segment mask, see page 37 of SJA1000 Data Sheet +}; + +/** Frame format information 0x10 */ +enum sja1000_PeliCAN_FRM { + sjaFRM_FF = 1<<7, // Frame Format 1 == extended, 0 == standard + sjaFRM_RTR = 1<<6, // Remote request + sjaFRM_DLC_M = (1<<4)-1 // Length Mask +}; + + +/** Interrupt (status) Register 0x03 */ +enum sja1000_PeliCAN_IR { + sjaIR_BEI = 1<<7, // Bus Error Interrupt + sjaIR_ALI = 1<<6, // Arbitration Lost Interrupt + sjaIR_EPI = 1<<5, // Error Passive Interrupt (entered error passive state or error active state) + sjaIR_WUI = 1<<4, // Wake-Up Interrupt + sjaIR_DOI = 1<<3, // Data Overrun Interrupt + sjaIR_EI = 1<<2, // Error Interrupt + sjaIR_TI = 1<<1, // Transmit Interrupt + sjaIR_RI = 1 // Receive Interrupt +}; + +/** Bus Timing 1 Register 0x07 */ +enum sja1000_BTR1 { + sjaMAX_TSEG1 = 15, + sjaMAX_TSEG2 = 7 +}; + +/** Output Control Register 0x08 */ +enum sja1000_OCR { + sjaOCR_MODE_BIPHASE = 0, + sjaOCR_MODE_TEST = 1, + sjaOCR_MODE_NORMAL = 2, + sjaOCR_MODE_CLOCK = 3, +/// TX0 push-pull not inverted + sjaOCR_TX0_LH = 0x18, +/// TX1 floating (off) + sjaOCR_TX1_ZZ = 0 +}; + +/** Clock Divider register 0x1f */ +enum sja1000_CDR { + sjaCDR_PELICAN = 1<<7, +/// bypass input comparator + sjaCDR_CBP = 1<<6, +/// switch TX1 to generate RX INT + sjaCDR_RXINPEN = 1<<5, + sjaCDR_CLK_OFF = 1<<3, +/// f_out = f_osc/(2*(CDR[2:0]+1)) or f_osc if CDR[2:0]==7 + sjaCDR_CLKOUT_DIV1 = 7, + sjaCDR_CLKOUT_DIV2 = 0, + sjaCDR_CLKOUT_DIV4 = 1, + sjaCDR_CLKOUT_DIV6 = 2, + sjaCDR_CLKOUT_DIV8 = 3, + sjaCDR_CLKOUT_DIV10 = 4, + sjaCDR_CLKOUT_DIV12 = 5, + sjaCDR_CLKOUT_DIV14 = 6, + sjaCDR_CLKOUT_MASK = 7 +}; + +/** flags for sja1000_baud_rate */ +#define BTR1_SAM (1<<1) + +#endif /* SJA1000P_H */ diff --git a/embedded/app/usbcan/can/ul_listbase.h b/embedded/app/usbcan/can/ul_listbase.h new file mode 100644 index 0000000..2d4fece --- /dev/null +++ b/embedded/app/usbcan/can/ul_listbase.h @@ -0,0 +1,287 @@ +#ifndef _UL_LISTBASE_H +#define _UL_LISTBASE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __KERNEL__ + +#define LIST_POISON1 ((void *) 0) +#define LIST_POISON2 ((void *) 0) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *where = head->next; + + first->prev = head; + head->next = first; + + last->next = where; + where->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#else /*__KERNEL__*/ + +#include + +#endif /*__KERNEL__*/ + +#ifdef __cplusplus +} /* extern "C"*/ +#endif + +#endif /* _UL_LISTBASE_H */ diff --git a/embedded/app/usbcan/can/ul_usb1.h b/embedded/app/usbcan/can/ul_usb1.h new file mode 100644 index 0000000..385f4e3 --- /dev/null +++ b/embedded/app/usbcan/can/ul_usb1.h @@ -0,0 +1,26 @@ +#ifndef UL_USB1_H +#define UL_USB1_H + +/* ul_usb1.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +struct ul_usb1_chip_data +{ + int flags; +}; + +#define UL_USB1_CHIP_MASK_SET (1<<0) +#define UL_USB1_CHIP_BAUD_SET (1<<1) + +int ul_usb1_init(void); +void ul_usb1_exit(void); + +extern int ul_usb1_register(struct hwspecops_t *hwspecops); + +#endif /* UL_USB1_H */ diff --git a/embedded/app/usbcan/can_quesysless.c b/embedded/app/usbcan/can_quesysless.c new file mode 100644 index 0000000..f11f90d --- /dev/null +++ b/embedded/app/usbcan/can_quesysless.c @@ -0,0 +1,518 @@ +/* can_quesysless.c - CAN message queues functions for the Linux kernel + * Linux CAN-bus device driver. + * New CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "./can/can.h" +#include "./can/can_sysdep.h" +#include "./can/can_queue.h" + +// #define CAN_DEBUG + +extern atomic_t edge_num_cnt; + +#ifdef CAN_DEBUG + #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_quesysless (debug): " fmt,\ + ##args) + +#else + #define DEBUGQUE(fmt,args...) +#endif + +#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_quesysless: " fmt,\ + ##args) + + +/* + * Modifies Tx message processing + * 0 .. local message processing disabled + * 1 .. local messages disabled by default but can be enabled by canque_set_filt + * 2 .. local messages enabled by default, can be disabled by canque_set_filt + */ +extern int processlocal; + +void canque_dead_func(unsigned long data); + +/* Support for dead ends structures left after client close */ +can_spinlock_t canque_dead_func_lock; +LIST_HEAD(canque_dead_ends); +/* retrieved by list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers) */ +LIST_HEAD(canque_dead_edges); +/* retrieved by list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers) */ +// DECLARE_TASKLET(canque_dead_tl, canque_dead_func, 0); +/* activated by tasklet_schedule(&canque_dead_tl) */ + + +static inline +struct canque_edge_t *canque_dead_edges_cut_first(void) +{ + can_spin_irqflags_t flags; + struct canque_edge_t *edge; + can_spin_lock_irqsave(&canque_dead_func_lock, flags); + if(list_empty(&canque_dead_edges)) + edge=NULL; + else{ + edge=list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers); + list_del(&edge->inpeers); + } + can_spin_unlock_irqrestore(&canque_dead_func_lock, flags); + return edge; +} + +void canque_dead_func(unsigned long data) +{ + can_spin_irqflags_t flags; + struct canque_edge_t *qedge; + struct canque_ends_t *qends; + struct list_head *entry; + + while((qedge=canque_dead_edges_cut_first())){ + DEBUGQUE("edge %d disposed\n",qedge->edge_num); + #ifdef CAN_WITH_RTL + if(canque_fifo_test_fl(&qedge->fifo,RTL_MEM)){ + canque_dispose_edge_rtl(qedge); + continue; + } + #endif /*CAN_WITH_RTL*/ + canque_fifo_done_kern(&qedge->fifo); + free(qedge); + } + + can_spin_lock_irqsave(&canque_dead_func_lock, flags); + entry=canque_dead_ends.next; + while(entry!=&canque_dead_ends){ + qends=list_entry(entry,struct canque_ends_t,dead_peers); + entry=entry->next; + if(!list_empty(&qends->inlist)) + continue; + if(!list_empty(&qends->outlist)) + continue; + can_spin_lock_irqsave(&canque_dead_func_lock, flags); + list_del(&qends->dead_peers); + can_spin_unlock_irqrestore(&canque_dead_func_lock,flags); + DEBUGQUE("ends structure disposed\n"); + #ifdef CAN_WITH_RTL + if(qends->ends_flags&CAN_ENDSF_MEM_RTL){ + canque_ends_free_rtl(qends); + continue; + } + #endif /*CAN_WITH_RTL*/ + free(qends); + } + can_spin_unlock_irqrestore(&canque_dead_func_lock,flags); +} + +// static inline void canque_dead_tasklet_schedule(void) +// { +// #ifdef CAN_WITH_RTL +// if(!rtl_rt_system_is_idle()){ +// set_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend); +// rtl_global_pend_irq (canqueue_rtl_irq); +// return; +// } +// #endif /*CAN_WITH_RTL*/ +// +// tasklet_schedule(&canque_dead_tl); +// } + + +void canque_edge_do_dead(struct canque_edge_t *edge) +{ + can_spin_irqflags_t flags; + + canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); + #ifdef CAN_WITH_RTL + /* The problem of the above call is, that in RT-Linux to Linux notify + case is edge scheduled for delayed notify delivery, this needs + to be reflected there */ + if(atomic_read(&edge->edge_used)>0){ + can_spin_lock_irqsave(&edge->inends->ends_lock, flags); + can_spin_lock(&edge->outends->ends_lock); + if(atomic_read(&edge->edge_used)>0){ + /* left edge to live for a while, banshee comes again in a while */ + canque_fifo_clear_fl(&edge->fifo,DEAD); + can_spin_unlock(&edge->outends->ends_lock); + can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags); + can_printk(KERN_ERR "can_quertl (debug): canque_edge_do_dead postponed\n"); + return; + } + can_spin_unlock(&edge->outends->ends_lock); + can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags); + } + #endif /*CAN_WITH_RTL*/ + + if(canqueue_disconnect_edge(edge)<0){ + ERRMSGQUE("canque_edge_do_dead: canqueue_disconnect_edge failed !!!\n"); + return; + } + + can_spin_lock_irqsave(&canque_dead_func_lock, flags); + list_add(&edge->inpeers,&canque_dead_edges); + can_spin_unlock_irqrestore(&canque_dead_func_lock, flags); +// canque_dead_tasklet_schedule(); + canque_dead_func(0); +} + + + +/*if(qends->ends_flags & CAN_ENDSF_DEAD){ + can_spin_lock_irqsave(&canque_dead_func_lock, flags); + list_del(&qends->dead_peers); + list_add(&qends->dead_peers,&canque_dead_ends); + can_spin_unlock_irqrestore(&canque_dead_func_lock, flags); + tasklet_schedule(&canque_dead_tl); +}*/ + + +/** + * canqueue_notify_kern - notification callback handler for Linux userspace clients + * @qends: pointer to the callback side ends structure + * @qedge: edge which invoked notification + * @what: notification type + * + * The notification event is handled directly by call of this function except case, + * when called from RT-Linux context in mixed mode Linux/RT-Linux compilation. + * It is not possible to directly call Linux kernel synchronization primitives + * in such case. The notification request is postponed and signaled by @pending_inops flags + * by call canqueue_rtl2lin_check_and_pend() function. + * The edge reference count is increased until until all pending notifications are processed. + */ +void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what) +{ + DEBUGQUE("canqueue_notify_kern for edge %d, use %d and event %d\n", + qedge->edge_num,(int)atomic_read(&qedge->edge_used),what); + + /* delay event delivery for RT-Linux -> kernel notifications */ + if(canqueue_rtl2lin_check_and_pend(qends,qedge,what)){ + DEBUGQUE("canqueue_notify_kern postponed\n"); + return; + } + + switch(what){ + case CANQUEUE_NOTIFY_EMPTY: +// wake_up(&qends->endinfo.fileinfo.emptyq); + if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY)) + canque_edge_decref(qedge); + break; + case CANQUEUE_NOTIFY_SPACE: +// wake_up(&qends->endinfo.fileinfo.writeq); + #ifdef CAN_ENABLE_KERN_FASYNC + /* Asynchronous I/O processing */ + kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_OUT); + #endif /*CAN_ENABLE_KERN_FASYNC*/ + break; + case CANQUEUE_NOTIFY_PROC: +// wake_up(&qends->endinfo.fileinfo.readq); + #ifdef CAN_ENABLE_KERN_FASYNC + /* Asynchronous I/O processing */ + kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_IN); + #endif /*CAN_ENABLE_KERN_FASYNC*/ + break; + case CANQUEUE_NOTIFY_NOUSR: +// wake_up(&qends->endinfo.fileinfo.readq); +// wake_up(&qends->endinfo.fileinfo.writeq); +// wake_up(&qends->endinfo.fileinfo.emptyq); + break; + case CANQUEUE_NOTIFY_DEAD_WANTED: + case CANQUEUE_NOTIFY_DEAD: + if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY)) + canque_edge_decref(qedge); + break; + case CANQUEUE_NOTIFY_ATTACH: + break; + } +} + +/** + * canqueue_ends_init_kern - Linux userspace clients specific ends initialization + * @qends: pointer to the callback side ends structure + */ +int canqueue_ends_init_kern(struct canque_ends_t *qends) +{ + canqueue_ends_init_gen(qends); + qends->context=NULL; + init_waitqueue_head(&qends->endinfo.fileinfo.readq); + init_waitqueue_head(&qends->endinfo.fileinfo.writeq); + init_waitqueue_head(&qends->endinfo.fileinfo.emptyq); + #ifdef CAN_ENABLE_KERN_FASYNC + qends->endinfo.fileinfo.fasync=NULL; + #endif /*CAN_ENABLE_KERN_FASYNC*/ + + qends->notify=canqueue_notify_kern; + DEBUGQUE("canqueue_ends_init_kern\n"); + return 0; +} + + +/** + * canque_get_inslot4id_wait_kern - find or wait for best outgoing edge and slot for given ID + * @qends: ends structure belonging to calling communication object + * @qedgep: place to store pointer to found edge + * @slotp: place to store pointer to allocated slot + * @cmd: command type for slot + * @id: communication ID of message to send into edge + * @prio: optional priority of message + * + * Same as canque_get_inslot4id(), except, that it waits for free slot + * in case, that queue is full. Function is specific for Linux userspace clients. + * Return Value: If there is no usable edge negative value is returned. + */ +// int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends, +// struct canque_edge_t **qedgep, struct canque_slot_t **slotp, +// int cmd, unsigned long id, int prio) +// { +// int ret=-1; +// DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio); +// wait_event_interruptible((qends->endinfo.fileinfo.writeq), +// (ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1); +// return ret; +// } + +/** + * canque_get_outslot_wait_kern - receive or wait for ready slot for given ends + * @qends: ends structure belonging to calling communication object + * @qedgep: place to store pointer to found edge + * @slotp: place to store pointer to received slot + * + * The same as canque_test_outslot(), except it waits in the case, that there is + * no ready slot for given ends. Function is specific for Linux userspace clients. + * Return Value: Negative value informs, that there is no ready output + * slot for given ends. Positive value is equal to the command + * slot has been allocated by the input side. + */ +// int canque_get_outslot_wait_kern(struct canque_ends_t *qends, +// struct canque_edge_t **qedgep, struct canque_slot_t **slotp) +// { +// int ret=-1; +// DEBUGQUE("canque_get_outslot_wait_kern\n"); +// wait_event_interruptible((qends->endinfo.fileinfo.readq), +// (ret=canque_test_outslot(qends,qedgep,slotp))!=-1); +// return ret; +// } + +/** + * canque_sync_wait_kern - wait for all slots processing + * @qends: ends structure belonging to calling communication object + * @qedge: pointer to edge + * + * Functions waits for ends transition into empty state. + * Return Value: Positive value indicates, that edge empty state has been reached. + * Negative or zero value informs about interrupted wait or other problem. + */ +// int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge) +// { +// int ret=-1; +// DEBUGQUE("canque_sync_wait_kern\n"); +// wait_event_interruptible((qends->endinfo.fileinfo.emptyq), +// (ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0)); +// return ret; +// } + + +/** + * canque_fifo_init_kern - initialize one CAN FIFO + * @fifo: pointer to the FIFO structure + * @slotsnr: number of requested slots + * + * Return Value: The negative value indicates, that there is no memory + * to allocate space for the requested number of the slots. + */ +int canque_fifo_init_kern(struct canque_fifo_t *fifo, int slotsnr) +{ + int size; + if(!slotsnr) slotsnr=MAX_BUF_LENGTH; + size=sizeof(struct canque_slot_t)*slotsnr; + fifo->entry=malloc(size); + if(!fifo->entry) return -1; + fifo->slotsnr=slotsnr; + return canque_fifo_init_slots(fifo); +} + +/** + * canque_fifo_done_kern - frees slots allocated for CAN FIFO + * @fifo: pointer to the FIFO structure + */ +int canque_fifo_done_kern(struct canque_fifo_t *fifo) +{ + if(fifo->entry) + free(fifo->entry); + fifo->entry=NULL; + return 1; +} + + +/** + * canque_new_edge_kern - allocate new edge structure in the Linux kernel context + * @slotsnr: required number of slots in the newly allocated edge structure + * + * Return Value: Returns pointer to allocated slot structure or %NULL if + * there is not enough memory to process operation. + */ +struct canque_edge_t *canque_new_edge_kern(int slotsnr) +{ + struct canque_edge_t *qedge; + qedge = (struct canque_edge_t *)malloc(sizeof(struct canque_edge_t)); + if(qedge == NULL) return NULL; + + memset(qedge,0,sizeof(struct canque_edge_t)); + can_spin_lock_init(&qedge->fifo.fifo_lock); + if(canque_fifo_init_kern(&qedge->fifo, slotsnr)<0){ + free(qedge); + DEBUGQUE("canque_new_edge_kern failed\n"); + return NULL; + } + atomic_set(&qedge->edge_used,1); + qedge->filtid = 0; + qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0); + qedge->edge_prio = 0; + #ifdef CAN_DEBUG + /* not exactly clean, but enough for debugging */ + atomic_inc(&edge_num_cnt); + qedge->edge_num=atomic_read(&edge_num_cnt); + #endif /* CAN_DEBUG */ + DEBUGQUE("canque_new_edge_kern %d\n",qedge->edge_num); + return qedge; +} + +#ifdef USE_SYNC_DISCONNECT_EDGE_KERN + +/*not included in doc + * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait + * @qends: ends structure belonging to calling communication object + * @qedge: pointer to edge + * + * Same as canqueue_disconnect_edge(), but tries to wait for state with zero + * use counter. + * Return Value: Negative value means, that edge is used and cannot + * be disconnected yet. Operation has to be delayed. + */ +int canqueue_disconnect_edge_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge) +{ + canque_fifo_set_fl(&qedge->fifo,BLOCK); + DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num); + if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){ + canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD); + + if(atomic_read(&qedge->edge_used)>0) + atomic_dec(&qedge->edge_used); + + DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num); + wait_event((qends->endinfo.fileinfo.emptyq), + (canqueue_disconnect_edge(qedge)>=0)); + + /*set_current_state(TASK_UNINTERRUPTIBLE);*/ + /*schedule_timeout(HZ);*/ + return 0; + } else { + DEBUGQUE("canqueue_disconnect_edge_kern cannot set DEAD\n"); + return -1; + } +} + + +int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list) +{ + struct canque_edge_t *edge; + can_spin_irqflags_t flags; + for(;;){ + can_spin_lock_irqsave(&qends->ends_lock,flags); + if(list_empty(list)){ + can_spin_unlock_irqrestore(&qends->ends_lock,flags); + return 0; + } + if(list == &qends->inlist) + edge=list_entry(list->next,struct canque_edge_t,inpeers); + else + edge=list_entry(list->next,struct canque_edge_t,outpeers); + atomic_inc(&edge->edge_used); + can_spin_unlock_irqrestore(&qends->ends_lock,flags); + if(canqueue_disconnect_edge_kern(qends, edge)>=0) { + /* Free edge memory */ + canque_fifo_done_kern(&edge->fifo); + free(edge); + }else{ + canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED); + canque_edge_decref(edge); + DEBUGQUE("canqueue_disconnect_list_kern in troubles\n"); + DEBUGQUE("the edge %d has usage count %d and flags %ld\n",edge->edge_num,atomic_read(&edge->edge_used),edge->fifo.fifo_flags); + return -1; + } + } +} + +#endif /*USE_SYNC_DISCONNECT_EDGE_KERN*/ + + +// int canqueue_ends_sync_all_kern(struct canque_ends_t *qends) +// { +// struct canque_edge_t *qedge; +// +// canque_for_each_inedge(qends, qedge){ +// DEBUGQUE("canque_sync_wait_kern called for edge %d\n",qedge->edge_num); +// canque_sync_wait_kern(qends, qedge); +// } +// return 0; +// } + + +void canqueue_ends_dispose_postpone(struct canque_ends_t *qends) +{ + can_spin_irqflags_t flags; + + can_spin_lock_irqsave(&canque_dead_func_lock, flags); + qends->ends_flags |= CAN_ENDSF_DEAD; + list_add(&qends->dead_peers,&canque_dead_ends); + can_spin_unlock_irqrestore(&canque_dead_func_lock, flags); + canque_dead_func(0); +// canque_dead_tasklet_schedule(); +} + + +/** + * canqueue_ends_dispose_kern - finalizing of the ends structure for Linux kernel clients + * @qends: pointer to ends structure + * @sync: flag indicating, that user wants to wait for processing of all remaining + * messages + * + * Return Value: Function should be designed such way to not fail. + */ +// int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync) +// { +// int delayed; +// +// DEBUGQUE("canqueue_ends_dispose_kern\n"); +// canqueue_block_inlist(qends); +// canqueue_block_outlist(qends); +// +// /*Wait for sending of all pending messages in the output FIFOs*/ +// if(sync) +// canqueue_ends_sync_all_kern(qends); +// +// /* Finish or kill all outgoing edges listed in inends */ +// delayed=canqueue_ends_kill_inlist(qends, 1); +// /* Kill all incoming edges listed in outends */ +// delayed|=canqueue_ends_kill_outlist(qends); +// +// // wake_up(&qends->endinfo.fileinfo.readq); +// // wake_up(&qends->endinfo.fileinfo.writeq); +// // wake_up(&qends->endinfo.fileinfo.emptyq); +// +// if(delayed){ +// canqueue_ends_dispose_postpone(qends); +// +// DEBUGQUE("canqueue_ends_dispose_kern delayed\n"); +// return 1; +// } +// +// free(qends); +// DEBUGQUE("canqueue_ends_dispose_kern finished\n"); +// return 0; +// } + +void canqueue_kern_initialize() +{ + can_spin_lock_init(&canque_dead_func_lock); +} diff --git a/embedded/app/usbcan/can_queue.c b/embedded/app/usbcan/can_queue.c new file mode 100644 index 0000000..9815fd0 --- /dev/null +++ b/embedded/app/usbcan/can_queue.c @@ -0,0 +1,750 @@ +/* can_queue.c - CAN message queues + * Linux CAN-bus device driver. + * New CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "./can/can.h" +#include "./can/can_sysdep.h" +#include "./can/can_queue.h" + +/* + * Modifies Tx message processing + * 0 .. local message processing disabled + * 1 .. local messages disabled by default but can be enabled by canque_set_filt + * 2 .. local messages enabled by default, can be disabled by canque_set_filt + */ +extern int processlocal; + +atomic_t edge_num_cnt; + +// #define CAN_DEBUG +#undef CAN_DEBUG + +#ifdef CAN_DEBUG + #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\ + ##args) + +#else + #define DEBUGQUE(fmt,args...) +#endif + +#define CANQUE_ROUNDROB 1 + + +/** + * canque_fifo_flush_slots - free all ready slots from the FIFO + * @fifo: pointer to the FIFO structure + * + * The caller should be prepared to handle situations, when some + * slots are held by input or output side slots processing. + * These slots cannot be flushed or their processing interrupted. + * + * Return Value: The nonzero value indicates, that queue has not been + * empty before the function call. + */ +int canque_fifo_flush_slots(struct canque_fifo_t *fifo) +{ + int ret; + can_spin_irqflags_t flags; + struct canque_slot_t *slot; + can_spin_lock_irqsave(&fifo->fifo_lock, flags); + slot=fifo->head; + if(slot){ + *fifo->tail=fifo->flist; + fifo->flist=slot; + fifo->head=NULL; + fifo->tail=&fifo->head; + } + canque_fifo_clear_fl(fifo,FULL); + ret=canque_fifo_test_and_set_fl(fifo,EMPTY)?0:1; + can_spin_unlock_irqrestore(&fifo->fifo_lock, flags); + return ret; +} + + +/** + * canque_fifo_init_slots - initializes slot chain of one CAN FIFO + * @fifo: pointer to the FIFO structure + * + * Return Value: The negative value indicates, that there is no memory + * to allocate space for the requested number of the slots. + */ +int canque_fifo_init_slots(struct canque_fifo_t *fifo) +{ + struct canque_slot_t *slot; + int slotsnr=fifo->slotsnr; + if(!fifo->entry || !slotsnr) return -1; + slot=fifo->entry; + fifo->flist=slot; + while(--slotsnr){ + slot->next=slot+1; + slot++; + } + slot->next=NULL; + fifo->head=NULL; + fifo->tail=&fifo->head; + canque_fifo_set_fl(fifo,EMPTY); + return 1; +} + +/* atomic_dec_and_test(&qedge->edge_used); + void atomic_inc(&qedge->edge_used); + list_add_tail(struct list_head *new, struct list_head *head) + list_for_each(edge,qends->inlist); + list_entry(ptr, type, member) +*/ + +void __canque_edge_decref(struct canque_edge_t *edge) +{ + __canque_edge_decref_body(edge); +} + +/** + * canque_get_inslot - finds one outgoing edge and allocates slot from it + * @qends: ends structure belonging to calling communication object + * @qedgep: place to store pointer to found edge + * @slotp: place to store pointer to allocated slot + * @cmd: command type for slot + * + * Function looks for the first non-blocked outgoing edge in @qends structure + * and tries to allocate slot from it. + * Return Value: If there is no usable edge or there is no free slot in edge + * negative value is returned. + */ +int canque_get_inslot(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd) +{ + int ret=-2; + struct canque_edge_t *edge; + + edge=canque_first_inedge(qends); + if(edge){ + if(!canque_fifo_test_fl(&edge->fifo,BLOCK)){ + ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd); + if(ret>0){ + *qedgep=edge; + DEBUGQUE("canque_get_inslot cmd=%d found edge %d\n",cmd,edge->edge_num); + return ret; + + } + } + canque_edge_decref(edge); + } + *qedgep=NULL; + DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd); + return ret; +} + +/** + * canque_get_inslot4id - finds best outgoing edge and slot for given ID + * @qends: ends structure belonging to calling communication object + * @qedgep: place to store pointer to found edge + * @slotp: place to store pointer to allocated slot + * @cmd: command type for slot + * @id: communication ID of message to send into edge + * @prio: optional priority of message + * + * Function looks for the non-blocked outgoing edge accepting messages + * with given ID. If edge is found, slot is allocated from that edge. + * The edges with non-zero mask are preferred over edges open to all messages. + * If more edges with mask accepts given message ID, the edge with + * highest priority below or equal to required priority is selected. + * Return Value: If there is no usable edge or there is no free slot in edge + * negative value is returned. + */ +int canque_get_inslot4id(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp, + int cmd, unsigned long id, int prio) +{ + int ret=-2; + struct canque_edge_t *edge, *bestedge=NULL; + + canque_for_each_inedge(qends, edge){ + if(canque_fifo_test_fl(&edge->fifo,BLOCK)) + continue; + if((id^edge->filtid)&edge->filtmask) + continue; + if(bestedge){ + if(bestedge->filtmask){ + if (!edge->filtmask) continue; + } else { + if(edge->filtmask){ + canque_edge_decref(bestedge); + bestedge=edge; + canque_edge_incref(bestedge); + continue; + } + } + if(bestedge->edge_prioedge_prio){ + if(edge->edge_prio>prio) continue; + } else { + if(bestedge->edge_prio<=prio) continue; + } + canque_edge_decref(bestedge); + } + bestedge=edge; + canque_edge_incref(bestedge); + } + if((edge=bestedge)!=NULL){ + ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd); + if(ret>0){ + *qedgep=edge; + DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d found edge %d\n",cmd,id,prio,edge->edge_num); + return ret; + } + canque_edge_decref(bestedge); + } + *qedgep=NULL; + DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio); + return ret; +} + + +/** + * canque_put_inslot - schedules filled slot for processing + * @qends: ends structure belonging to calling communication object + * @qedge: edge slot belong to + * @slot: pointer to the prepared slot + * + * Puts slot previously acquired by canque_get_inslot() or canque_get_inslot4id() + * function call into FIFO queue and activates edge processing if needed. + * Return Value: Positive value informs, that activation of output end + * has been necessary + */ +int canque_put_inslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + ret=canque_fifo_put_inslot(&qedge->fifo,slot); + if(ret) { + canque_activate_edge(qends,qedge); + canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC); + } + canque_edge_decref(qedge); + DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +/** + * canque_abort_inslot - aborts preparation of the message in the slot + * @qends: ends structure belonging to calling communication object + * @qedge: edge slot belong to + * @slot: pointer to the previously allocated slot + * + * Frees slot previously acquired by canque_get_inslot() or canque_get_inslot4id() + * function call. Used when message copying into slot fails. + * Return Value: Positive value informs, that queue full state has been negated. + */ +int canque_abort_inslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + ret=canque_fifo_abort_inslot(&qedge->fifo,slot); + if(ret) { + canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE); + } + canque_edge_decref(qedge); + DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +/** + * canque_filter_msg2edges - sends message into all edges which accept its ID + * @qends: ends structure belonging to calling communication object + * @msg: pointer to CAN message + * + * Sends message to all outgoing edges connected to the given ends, which accepts + * message communication ID. + * Return Value: Returns number of edges message has been send to + */ +int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg) +{ + int destnr=0; + int ret; + unsigned long msgid; + struct canque_edge_t *edge; + struct canque_slot_t *slot; + + DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n", + msg->id, msg->flags); + msgid = canque_filtid2internal(msg->id, msg->flags); + + canque_for_each_inedge(qends, edge) { + if(canque_fifo_test_fl(&edge->fifo,BLOCK)) + continue; + if((msgid^edge->filtid)&edge->filtmask) + continue; + ret=canque_fifo_get_inslot(&edge->fifo, &slot, 0); + if(ret>0){ + slot->msg=*msg; + destnr++; + ret=canque_fifo_put_inslot(&edge->fifo,slot); + if(ret) { + canque_activate_edge(qends,edge); + canque_notify_outends(edge,CANQUEUE_NOTIFY_PROC); + } + + } + } + DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr); + return destnr; +} + +/** + * canque_test_outslot - test and retrieve ready slot for given ends + * @qends: ends structure belonging to calling communication object + * @qedgep: place to store pointer to found edge + * @slotp: place to store pointer to received slot + * + * Function takes highest priority active incoming edge and retrieves + * oldest ready slot from it. + * Return Value: Negative value informs, that there is no ready output + * slot for given ends. Positive value is equal to the command + * slot has been allocated by the input side. + */ +int canque_test_outslot(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp) +{ + can_spin_irqflags_t flags; + int prio; + struct canque_edge_t *edge; + int ret; + + can_spin_lock_irqsave(&qends->ends_lock, flags); + for(prio=CANQUEUE_PRIO_NR;--prio>=0;){ + while(!list_empty(&qends->active[prio])){ + edge=list_entry(qends->active[prio].next,struct canque_edge_t,activepeers); + if(!canque_fifo_test_fl(&edge->fifo,DEAD)) { + /* The first test on unlocked FIFO */ + if(canque_fifo_test_fl(&edge->fifo,EMPTY)) { + can_spin_lock(&edge->fifo.fifo_lock); + /* Test has to be repeated to ensure that EMPTY + state has not been nagated when locking FIFO */ + if(canque_fifo_test_fl(&edge->fifo,EMPTY)) { + canque_fifo_set_fl(&edge->fifo,INACTIVE); + list_del(&edge->activepeers); + list_add(&edge->activepeers,&qends->idle); + can_spin_unlock(&edge->fifo.fifo_lock); + continue; + } + can_spin_unlock(&edge->fifo.fifo_lock); + } + canque_edge_incref(edge); + can_spin_unlock_irqrestore(&qends->ends_lock, flags); + *qedgep=edge; + DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num); + ret=canque_fifo_test_outslot(&edge->fifo, slotp); + if(ret>=0) + return ret; + + canque_edge_decref(edge); + can_spin_lock_irqsave(&qends->ends_lock, flags); + } else { + can_spin_lock(&edge->fifo.fifo_lock); + canque_fifo_set_fl(&edge->fifo,INACTIVE); + list_del(&edge->activepeers); + list_add(&edge->activepeers,&qends->idle); + can_spin_unlock(&edge->fifo.fifo_lock); + } + } + } + can_spin_unlock_irqrestore(&qends->ends_lock, flags); + *qedgep=NULL; +// DEBUGQUE("canque_test_outslot no ready slot\n"); + return -1; +} + +/** + * canque_free_outslot - frees processed output slot + * @qends: ends structure belonging to calling communication object + * @qedge: edge slot belong to + * @slot: pointer to the processed slot + * + * Function releases processed slot previously acquired by canque_test_outslot() + * function call. + * Return Value: Return value informs if input side has been notified + * to know about change of edge state + */ +int canque_free_outslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + can_spin_irqflags_t flags; + ret=canque_fifo_free_outslot(&qedge->fifo, slot); + if(ret&CAN_FIFOF_EMPTY){ + canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY); + } + if(ret&CAN_FIFOF_FULL) + canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE); + can_spin_lock_irqsave(&qends->ends_lock, flags); + if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB ){ + can_spin_lock(&qedge->fifo.fifo_lock); + if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){ + canque_fifo_set_fl(&qedge->fifo,INACTIVE); + list_del(&qedge->activepeers); + list_add(&qedge->activepeers,&qends->idle); + } else{ + list_del(&qedge->activepeers); + list_add_tail(&qedge->activepeers,&qends->active[qedge->edge_prio]); + } + can_spin_unlock(&qedge->fifo.fifo_lock); + } + can_spin_unlock_irqrestore(&qends->ends_lock, flags); + canque_edge_decref(qedge); + DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +/** + * canque_again_outslot - reschedule output slot to process it again later + * @qends: ends structure belonging to calling communication object + * @qedge: edge slot belong to + * @slot: pointer to the slot for re-processing + * + * Function reschedules slot previously acquired by canque_test_outslot() + * function call for second time processing. + * Return Value: Function cannot fail. + */ +int canque_again_outslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + ret=canque_fifo_again_outslot(&qedge->fifo, slot); + canque_edge_decref(qedge); + DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +/** + * canque_set_filt - sets filter for specified edge + * @qedge: pointer to the edge + * @filtid: ID to set for the edge + * @filtmask: mask used for ID match check + * @filtflags: required filer flags + * + * Return Value: Negative value is returned if edge is in the process of delete. + */ +int canque_set_filt(struct canque_edge_t *qedge, + unsigned long filtid, unsigned long filtmask, int filtflags) +{ + int ret; + can_spin_irqflags_t flags; + + can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags); + + if(!(filtflags&MSG_PROCESSLOCAL) && (processlocal<2)) + filtflags |= MSG_LOCAL_MASK; + + qedge->filtid=canque_filtid2internal(filtid, filtflags); + qedge->filtmask=canque_filtid2internal(filtmask, filtflags>>MSG_FILT_MASK_SHIFT); + + if(canque_fifo_test_fl(&qedge->fifo,DEAD)) ret=-1; + else ret=canque_fifo_test_and_set_fl(&qedge->fifo,BLOCK)?1:0; + + can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags); + if(ret>=0){ + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH); + } + can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags); + if(!ret) canque_fifo_clear_fl(&qedge->fifo,BLOCK); + can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags); + + DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n", + qedge->edge_num,filtid,filtmask,filtflags,ret); + return ret; +} + +/** + * canque_flush - fluesh all ready slots in the edge + * @qedge: pointer to the edge + * + * Tries to flush all allocated slots from the edge, but there could + * exist some slots associated to edge which are processed by input + * or output side and cannot be flushed at this moment. + * Return Value: The nonzero value indicates, that queue has not been + * empty before the function call. + */ +int canque_flush(struct canque_edge_t *qedge) +{ + int ret; + can_spin_irqflags_t flags; + + ret=canque_fifo_flush_slots(&qedge->fifo); + if(ret){ + canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY); + canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE); + can_spin_lock_irqsave(&qedge->outends->ends_lock, flags); + can_spin_lock(&qedge->fifo.fifo_lock); + if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){ + list_del(&qedge->activepeers); + list_add(&qedge->activepeers,&qedge->outends->idle); + } + can_spin_unlock(&qedge->fifo.fifo_lock); + can_spin_unlock_irqrestore(&qedge->outends->ends_lock, flags); + } + DEBUGQUE("canque_flush for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +/** + * canqueue_ends_init_gen - subsystem independent routine to initialize ends state + * @qends: pointer to the ends structure + * + * Return Value: Cannot fail. + */ +int canqueue_ends_init_gen(struct canque_ends_t *qends) +{ + int i; + qends->ends_flags=0; + for(i=CANQUEUE_PRIO_NR;--i>=0;){ + INIT_LIST_HEAD(&qends->active[i]); + } + INIT_LIST_HEAD(&qends->idle); + INIT_LIST_HEAD(&qends->inlist); + INIT_LIST_HEAD(&qends->outlist); + can_spin_lock_init(&qends->ends_lock); + return 0; +} + + +/** + * canqueue_connect_edge - connect edge between two communication entities + * @qedge: pointer to edge + * @inends: pointer to ends the input of the edge should be connected to + * @outends: pointer to ends the output of the edge should be connected to + * + * Return Value: Negative value informs about failed operation. + */ +int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends) +{ + can_spin_irqflags_t flags; + if(qedge == NULL) return -1; + DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num); + canque_edge_incref(qedge); + flags=canque_edge_lock_both_ends(inends, outends); + can_spin_lock(&qedge->fifo.fifo_lock); + qedge->inends=inends; + list_add(&qedge->inpeers,&inends->inlist); + qedge->outends=outends; + list_add(&qedge->outpeers,&outends->outlist); + list_add(&qedge->activepeers,&outends->idle); + can_spin_unlock(&qedge->fifo.fifo_lock); + canque_edge_unlock_both_ends(inends, outends, flags); + canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATTACH); + + if(canque_fifo_test_and_set_fl(&qedge->fifo, READY)) + canque_edge_decref(qedge); + return 0; +} + +/** + * canqueue_disconnect_edge - disconnect edge from communicating entities + * @qedge: pointer to edge + * + * Return Value: Negative value means, that edge is used by somebody + * other and cannot be disconnected. Operation has to be delayed. + */ +int canqueue_disconnect_edge(struct canque_edge_t *qedge) +{ + int ret; + can_spin_irqflags_t flags; + struct canque_ends_t *inends, *outends; + + inends=qedge->inends; + outends=qedge->outends; + + if(inends && outends) { + flags=canque_edge_lock_both_ends(inends, outends); + } else { + DEBUGQUE("canqueue_disconnect_edge called with not fully connected edge"); + if(inends) can_spin_lock_irqsave(&inends->ends_lock,flags); + if(outends) can_spin_lock(&outends->ends_lock); + flags=0; + } + + can_spin_lock(&qedge->fifo.fifo_lock); + if(atomic_read(&qedge->edge_used)==0) { + if(qedge->outends){ + list_del(&qedge->activepeers); + mb(); /* memory barrier for list_empty use in canque_dead_func */ + list_del(&qedge->outpeers); + qedge->outends=NULL; + } + if(qedge->inends){ + list_del(&qedge->inpeers); + qedge->inends=NULL; + } + ret=1; + } else ret=-1; + can_spin_unlock(&qedge->fifo.fifo_lock); + + if(inends && outends) { + canque_edge_unlock_both_ends(inends, outends, flags); + } else { + if(outends) can_spin_unlock(&outends->ends_lock); + if(inends) can_spin_unlock_irqrestore(&inends->ends_lock,flags); + } + + DEBUGQUE("canqueue_disconnect_edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + + +/** + * canqueue_block_inlist - block slot allocation of all outgoing edges of specified ends + * @qends: pointer to ends structure + */ +void canqueue_block_inlist(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_inedge(qends, edge) { + canque_fifo_set_fl(&edge->fifo,BLOCK); + } +} + + +/** + * canqueue_block_outlist - block slot allocation of all incoming edges of specified ends + * @qends: pointer to ends structure + */ +void canqueue_block_outlist(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_outedge(qends, edge) { + canque_fifo_set_fl(&edge->fifo,BLOCK); + } +} + + +/** + * canqueue_ends_kill_inlist - sends request to die to all outgoing edges + * @qends: pointer to ends structure + * @send_rest: select, whether already allocated slots should be processed + * by FIFO output side + * + * Return Value: Non-zero value means, that not all edges could be immediately + * disconnected and that ends structure memory release has to be delayed + */ +int canqueue_ends_kill_inlist(struct canque_ends_t *qends, int send_rest) +{ + struct canque_edge_t *edge; + + canque_for_each_inedge(qends, edge){ + canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED); + if(send_rest){ + canque_edge_incref(edge); + if(!canque_fifo_test_and_set_fl(&edge->fifo, FREEONEMPTY)){ + if(!canque_fifo_test_fl(&edge->fifo, EMPTY)) + continue; + if(!canque_fifo_test_and_clear_fl(&edge->fifo, FREEONEMPTY)) + continue; + } + canque_edge_decref(edge); + } + } + return list_empty(&qends->inlist)?0:1; +} + + +/** + * canqueue_ends_kill_outlist - sends request to die to all incoming edges + * @qends: pointer to ends structure + * + * Return Value: Non-zero value means, that not all edges could be immediately + * disconnected and that ends structure memory release has to be delayed + */ +int canqueue_ends_kill_outlist(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_outedge(qends, edge){ + canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED); + } + return list_empty(&qends->outlist)?0:1; +} + + +/** + * canqueue_ends_filt_conjuction - computes conjunction of incoming edges filters filters + * @qends: pointer to ends structure + * @filt: pointer the filter structure filled by computed filters conjunction + * + * Return Value: Number of incoming edges + */ +int canqueue_ends_filt_conjuction(struct canque_ends_t *qends, struct canfilt_t *filt) +{ + struct canque_edge_t *edge; + int cnt=0; + unsigned long filtid=0; + unsigned long filtmask=~0; + unsigned long local_only=canque_filtid2internal(0,MSG_LOCAL); + + canque_for_each_inedge(qends, edge){ + /* skip edges processing only local messages */ + if(edge->filtid & edge->filtmask & local_only) + continue; + + if(!cnt++) + filtid = edge->filtid; + else + filtmask &= ~(filtid ^ edge->filtid); + + filtmask &= edge->filtmask; + } + + filt->id = filtid & MSG_ID_MASK; + filt->mask = filtmask & MSG_ID_MASK; + filtid >>= 28; + filtmask >>= 28; + filt->flags = filtid & MSG_EXT; + if(filtmask & (MSG_EXT)) + filt->flags |= MSG_EXT_MASK; + if(filtid & (MSG_RTR<<1)) + filt->flags |= MSG_RTR<<1; + if(filtmask & (MSG_RTR<<1)) + filt->flags |= MSG_RTR_MASK; + return cnt; +} + + +/** + * canqueue_ends_flush_inlist - flushes all messages in incoming edges + * @qends: pointer to ends structure + * + * Return Value: Negative value informs about unsuccessful result + */ +int canqueue_ends_flush_inlist(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_inedge(qends, edge){ + canque_flush(edge); + } + return 0; +} + + +/** + * canqueue_ends_flush_outlist - flushes all messages in outgoing edges + * @qends: pointer to ends structure + * + * Return Value: Negative value informs about unsuccessful result + */ +int canqueue_ends_flush_outlist(struct canque_ends_t *qends) +{ + struct canque_edge_t *edge; + + canque_for_each_outedge(qends, edge){ + canque_flush(edge); + } + return 0; +} + + + + diff --git a/embedded/app/usbcan/devcommon.c b/embedded/app/usbcan/devcommon.c new file mode 100644 index 0000000..eada97b --- /dev/null +++ b/embedded/app/usbcan/devcommon.c @@ -0,0 +1,131 @@ +/* devcommon.c - common device code + * Linux CAN-bus device driver. + * New CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "./can/can.h" +#include "./can/can_sysdep.h" +#include "./can/can_queue.h" +#include "./can/main.h" +#include "./can/devcommon.h" + +#ifdef CAN_WITH_RTL +static inline +void canqueue_wake_chip_worker(struct canque_ends_t *qends, struct canchip_t *chip, struct msgobj_t *obj) +{ + if(qends->endinfo.chipinfo.worker_thread){ + can_msgobj_set_fl(obj,WORKER_WAKE); + pthread_kill(qends->endinfo.chipinfo.worker_thread,RTL_SIGNAL_WAKEUP); + rtl_schedule(); + } else { + set_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags); + if(chip->worker_thread) { + set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags); + pthread_kill(chip->worker_thread,RTL_SIGNAL_WAKEUP); + rtl_schedule(); + } + } +} + +#endif /*CAN_WITH_RTL*/ + + +/** + * canqueue_notify_chip - notification callback handler for CAN chips ends of queues + * @qends: pointer to the callback side ends structure + * @qedge: edge which invoked notification + * @what: notification type + * + * This function has to deal with more possible cases. It can be called from + * the kernel or interrupt context for Linux only compilation of driver. + * The function can be called from kernel context or RT-Linux thread context + * for mixed mode Linux/RT-Linux compilation. + */ +void canqueue_notify_chip(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what) +{ + struct canchip_t *chip=qends->endinfo.chipinfo.chip; + struct msgobj_t *obj=qends->endinfo.chipinfo.msgobj; + + DEBUGMSG("canqueue_notify_chip for edge %d and event %d\n",qedge->edge_num,what); + switch(what){ + /*case CANQUEUE_NOTIFY_EMPTY:*/ + /*case CANQUEUE_NOTIFY_SPACE:*/ + /*case CANQUEUE_NOTIFY_NOUSR: + wake_up(&qends->endinfo.chipinfo.daemonq); + break;*/ + case CANQUEUE_NOTIFY_PROC: + #ifndef CAN_WITH_RTL + /*wake_up(&qends->endinfo.chipinfo.daemonq);*/ + chip->chipspecops->wakeup_tx(chip, obj); + #else /*CAN_WITH_RTL*/ + can_msgobj_set_fl(obj,TX_REQUEST); + canqueue_wake_chip_worker(qends, chip, obj); + #endif /*CAN_WITH_RTL*/ + break; + case CANQUEUE_NOTIFY_DEAD_WANTED: + case CANQUEUE_NOTIFY_DEAD: + if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY)) + canque_edge_decref(qedge); + break; + case CANQUEUE_NOTIFY_ATTACH: + break; + case CANQUEUE_NOTIFY_FILTCH: + if(!chip->chipspecops->filtch_rq) + break; + #ifndef CAN_WITH_RTL + chip->chipspecops->filtch_rq(chip, obj); + #else /*CAN_WITH_RTL*/ + can_msgobj_set_fl(obj,FILTCH_REQUEST); + canqueue_wake_chip_worker(qends, chip, obj); + #endif /*CAN_WITH_RTL*/ + + break; + } +} + + +/** + * canqueue_ends_init_chip - CAN chip specific ends initialization + * @qends: pointer to the ends structure + * @chip: pointer to the corresponding CAN chip structure + * @obj: pointer to the corresponding message object structure + */ +int canqueue_ends_init_chip(struct canque_ends_t *qends, struct canchip_t *chip, struct msgobj_t *obj) +{ + int ret; + ret=canqueue_ends_init_gen(qends); + if(ret<0) return ret; + + qends->context=NULL; + #ifndef CAN_WITH_RTL + init_waitqueue_head(&qends->endinfo.chipinfo.daemonq); + #endif /*CAN_WITH_RTL*/ + qends->endinfo.chipinfo.chip=chip; + qends->endinfo.chipinfo.msgobj=obj; + qends->notify=canqueue_notify_chip; + + DEBUGMSG("canqueue_ends_init_chip\n"); + return 0; +} + + +/** + * canqueue_ends_done_chip - finalizing of the ends structure for CAN chips + * @qends: pointer to ends structure + * + * Return Value: Function should be designed such way to not fail. + */ +int canqueue_ends_done_chip(struct canque_ends_t *qends) +{ + int delayed; + + /* Finish or kill all outgoing edges listed in inends */ + delayed=canqueue_ends_kill_inlist(qends, 1); + /* Kill all incoming edges listed in outends */ + delayed|=canqueue_ends_kill_outlist(qends); + + return delayed; +} diff --git a/embedded/app/usbcan/finish.c b/embedded/app/usbcan/finish.c new file mode 100644 index 0000000..fad2c05 --- /dev/null +++ b/embedded/app/usbcan/finish.c @@ -0,0 +1,136 @@ +/* finish.c - finalization of the driver operation + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "./can/can.h" +#include "./can/can_sysless.h" +#include "./can/main.h" +#include "./can/devcommon.h" +#include "./can/finish.h" +#include "./can/setup.h" + + +/** + * msgobj_done - destroys one CAN message object + * @obj: pointer to CAN message object structure + */ +void msgobj_done(struct msgobj_t *obj) +{ + int delayed=0; + if(obj->qends) { + delayed=canqueue_ends_done_chip(obj->qends); + if(delayed < 0) + CANMSG("msgobj_done: problem with chip queue ends\n"); + } + + if((obj->hostchip) && (obj->object>0)) { + if(obj->hostchip->msgobj[obj->object-1] == obj) + obj->hostchip->msgobj[obj->object-1]=NULL; + else + CANMSG("msgobj_done: not registered in the canchip_t\n"); + obj->hostchip=NULL; + } + + if((obj->minor>=0)) { + if(objects_p[obj->minor] == obj) + objects_p[obj->minor] = NULL; + else + CANMSG("msgobj_done: not registered as minor\n"); + } + +// del_timer_sync(&obj->tx_timeout); + + if(obj->qends) { + /*delayed free could be required there in the future, + actual use patter cannot generate such situation*/ + if(!delayed) { + free(obj->qends); + } + } + obj->qends=NULL; +} + + +/** + * canchip_done - destroys one CAN chip representation + * @chip: pointer to CAN chip structure + */ +void canchip_done(struct canchip_t *chip) +{ + + int i; + struct msgobj_t *obj; + + if(chip->flags & CHIP_ATTACHED) + chip->chipspecops->release_chip(chip); + + if((chip->hostdevice) && (chip->chip_idx>=0)) { + if(chip->hostdevice->chip[chip->chip_idx] == chip) + chip->hostdevice->chip[chip->chip_idx] = NULL; + else + CANMSG("canchip_done: not registered in hostdevice\n"); + } + +// Not using interrupts +// can_chip_free_irq(chip); + +// can_synchronize_irq(chip->chip_irq); + + for(i=0; imax_objects; i++){ + if((obj=chip->msgobj[i])==NULL) + continue; + msgobj_done(obj); + free(obj); + } + + free(chip->chipspecops); + chip->chipspecops=NULL; + +} + +/** + * candevice_done - destroys representation of one CAN device/board + * @candev: pointer to CAN device/board structure + */ +void candevice_done(struct candevice_t *candev) +{ + int i; + struct canchip_t *chip; + + for(i=0; inr_all_chips; i++){ + if((chip=candev->chip[i])==NULL) + continue; + canchip_done(chip); + free(chip); + + } + if(candev->flags & CANDEV_IO_RESERVED) { + candev->hwspecops->release_io(candev); + candev->flags &= ~CANDEV_IO_RESERVED; + } + free(candev->hwspecops); + candev->hwspecops=NULL; +} + +/** + * candevice_done - destroys representation of all CAN devices/boards + * @canhw: pointer to the root of all CAN hardware representation + */ +void canhardware_done(struct canhardware_t *canhw) +{ + int i; + struct candevice_t *candev; + + for(i=0; inr_boards; i++){ + if((candev=canhw->candevice[i])==NULL) + continue; + candevice_done(candev); + free(candev); + } + +} diff --git a/embedded/app/usbcan/main.c b/embedded/app/usbcan/main.c new file mode 100644 index 0000000..0aff221 --- /dev/null +++ b/embedded/app/usbcan/main.c @@ -0,0 +1,464 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if __BYTE_ORDER == __BIG_ENDIAN + #include +#endif + +#include "./can/can.h" +#include "./can/sja1000p.h" +#include "./can/main.h" + +// #include "./can/can_sysdep.h" +#include "./can/modparms.h" +#include "./can/devcommon.h" + +#include "./can/ul_usb1.h" +//#include "./can/setup.h" + +#include "./usb/usb_defs.h" +#include "./usb/usb_vend.h" + +#define MASK_EP1RX 0x01 +#define MASK_EP1TX 0x02 + +#define CAN_OP_MASK 0x80 +#define CAN_OP_READ 0x80 +#define CAN_OP_WRITE 0x00 + +#ifdef USB_MAX_PACKET + #undef USB_MAX_PACKET + #define USB_MAX_PACKET 16 +#endif +/*********************************************************************** + * Note: + * Comparing to LinCAN, there is no need to sleep for processes + * because the degree of filling of fifo from the client side + * is solved in main cycle (no new messages are accepted when full) + * and on the server side by speed of USB interface. FIFO in edge + * from SJA chip to USB interface should never be filled. + ***********************************************************************/ + +/*********************************************************************** + * Note: + * Code is wittingly complex in order to ease future changes in hardware + * configuration and to make it as much similar as the code of LinCAN + ***********************************************************************/ + +LT_TIMER_DEC(lt_10msec) +LT_TIMER_IMP(lt_10msec) +LT_TIMER_DEC(lt_100msec) +LT_TIMER_IMP(lt_100msec) +LT_TIMER_DEC(lt_2sec) +LT_TIMER_IMP(lt_2sec) + +typedef void (*FNC)(); //function ptr + +/*********************************************************************** + * global variables + ***********************************************************************/ + + +usb_device_t usb_device; + +usb_ep_t eps[NUM_ENDPOINTS]; +unsigned char ep1_rx_buff[USB_MAX_PACKET]; +unsigned char ep1_tx_buff[USB_MAX_PACKET]; +uint8_t timer_str,timer_rx_off,timer_tx_off,timer_configured; +volatile uint8_t bootloader_run; + +uint8_t vendor_ret; + +int processlocal; + +int baudrate[MAX_TOT_CHIPS]; +struct canhardware_t canhardware; +struct canhardware_t *hardware_p=&canhardware; +struct canchip_t *chips_p[MAX_TOT_CHIPS]; +struct msgobj_t *objects_p[MAX_TOT_MSGOBJS]; + +struct canuser_t *canuser; + +extern int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate); +extern int register_chip_struct(struct canchip_t *chip, int minorbase); +extern int register_obj_struct(struct msgobj_t *obj, int minorbase); + +/*********************************************************************** + * IF SOMETHING BAD HAPPENED + ***********************************************************************/ + +int sys_err(){ + unsigned char i=0; + + while(1) { + if (lt_100msec_expired(100)) { + i++; + if (i&1) { + SET_OUT_PIN(LED_PORT,LED_ERR); + } else { + CLR_OUT_PIN(LED_PORT,LED_ERR); + } + #ifdef WATCHDOG_ENABLED + watchdog_feed(); + #endif /* WATCHDOG_ENABLED */ + } + } +} + +/*********************************************************************** + * Routine for visible LED blinking (on USB transmission) + ***********************************************************************/ + +void timer_10ms(void) +{ + if (timer_tx_off!=0) timer_tx_off--; + else SET_OUT_PIN(LED_PORT,LED1_BIT); + if (timer_rx_off!=0) timer_rx_off--; + else SET_OUT_PIN(LED_PORT,LED2_BIT); +/* if (timer_configured!=0) timer_configured--; + else { + timer_configured=20; + CLR_OUT_PIN(LED_PORT,LED1_BIT); + CLR_OUT_PIN(LED_PORT,LED2_BIT); + timer_rx_off=timer_tx_off=5; + }*/ +} + +/*********************************************************************** + * Main routine + ***********************************************************************/ + +int main(void) +{ + struct candevice_t *candev; + struct canchip_t *chip=NULL; + struct msgobj_t *obj; + struct canque_ends_t *qends; + struct canque_edge_t *edge,*qedge; + struct canque_slot_t *slot; + struct canmsg_t canmsg; + can_spin_irqflags_t iflags; + + int chipnr,bd; + int i,size,m=0; + + CANMSG("Starting USBCAN module firmware...\n"); + +// volatile int i=0; + bootloader_run=0; + /***********************************/ + lt_10msec_init(); + lt_100msec_init(); + lt_2sec_init(); + + SET_OUT_PIN(LED_PORT,LED_ERR); + CLR_OUT_PIN(LED_PORT,LED_GP); + + if (USB_MAX_PACKET<16){ + CANMSG("Maximum packet size less than 16B (is %dB)\n",USB_MAX_PACKET); + sys_err(); + } + + /*********************************************************************** + * CAN device initialization - device side (adapted from LinCAN setup.c) + ***********************************************************************/ + + can_init(); + + DEBUGMSG("Initiating CAN device initialization\n"); + baudrate[0]=1000; + + canqueue_kern_initialize(); + + hardware_p->nr_boards=1; + + candev=(struct candevice_t *)malloc(sizeof(struct candevice_t)); + if (!candev){ + CANMSG("No space left in memory\n"); + sys_err(); + } + memset(candev, 0, sizeof(struct candevice_t)); + + hardware_p->candevice[0]=candev; + candev->candev_idx=0; + candev->io_addr=0; + candev->dev_base_addr=0; + + candev->hwspecops=(struct hwspecops_t *)malloc(sizeof(struct hwspecops_t)); + if (!candev->hwspecops){ + CANMSG("No space left in memory\n"); + sys_err(); + } + memset(candev->hwspecops, 0, sizeof(struct hwspecops_t)); + + ul_usb1_register(candev->hwspecops); + + bd=baudrate[0]; + if (candev->hwspecops->init_hw_data(candev)){ + CANMSG("HW data could not be initialized\n"); + sys_err(); + } + /* Alocate and initialize the chip structures */ + for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) { +/* if(chipnrnr_all_chips; chipnr++) { + struct canchip_t *chip=candev->chip[chipnr]; + int objnr; + + register_chip_struct(chip, m); + + for (objnr=0; objnrmax_objects; objnr++) { + register_obj_struct(chip->msgobj[objnr], m); + if(m>=0) m++; + } + } + if (candev->hwspecops->request_io(candev)) + sys_err(); + candev->flags|=CANDEV_IO_RESERVED; + if (candev->hwspecops->reset(candev)) + sys_err(); + for(chipnr=0; chipnrnr_all_chips; chipnr++) { + if((chip=candev->chip[chipnr])==NULL) + continue; + + if(chip->chipspecops->attach_to_chip(chip)<0) { +// CANMSG("Initial attach to the chip HW failed\n"); + sys_err(); + } + + chip->flags |= CHIP_ATTACHED; + +// Interrupts from chip are served in main cycle +/* if(can_chip_setup_irq(chip)<0) { +// CANMSG("Error to setup chip IRQ\n"); + sys_err(); + }*/ + } + + if (candev->flags & CANDEV_PROGRAMMABLE_IRQ) + if (candev->hwspecops->program_irq(candev)){ +// CANMSG("Error to program board interrupt\n"); + sys_err(); + } + + /*********************************************************************** + * CAN device initialization - client side (adapted from LinCAN open.c) + ***********************************************************************/ + + chip=candev->chip[0]; + obj=chip->msgobj[0]; + atomic_inc(&obj->obj_used); + can_msgobj_set_fl(obj,OPENED); + + if (chip->flags & CHIP_CONFIGURED) + DEBUGMSG("Device is already configured.\n"); + else { + if (chip->chipspecops->chip_config(chip)) + CANMSG("Error configuring chip.\n"); + else + chip->flags |= CHIP_CONFIGURED; + + if (chip->chipspecops->pre_read_config(chip,obj)<0) + CANMSG("Error initializing chip for receiving\n"); + + } /* End of chip configuration */ + + canuser = (struct canuser_t *)malloc(sizeof(struct canuser_t)); + if(canuser == NULL) sys_err(); + canuser->flags=0; +// canuser->userinfo.fileinfo.file = file; + canuser->msgobj = obj; +// canuser->magic = CAN_USER_MAGIC; +// file->private_data = canuser; + + qends = (struct canque_ends_t *)malloc(sizeof(struct canque_ends_t)); + if(qends == NULL) sys_err(); + canqueue_ends_init_kern(qends); + canuser->qends = qends; + + /*required to synchronize with RT-Linux context*/ + can_spin_lock_irqsave(&canuser_manipulation_lock, iflags); + list_add(&canuser->peers, &obj->obj_users); + can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags); + + if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH), + canuser->qends, obj->qends)<0) sys_err(); + + if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_kern(MAX_BUF_LENGTH), + obj->qends, canuser->qends)<0) sys_err(); + /*FIXME: more generic model should be used there*/ + canque_edge_decref(canuser->rx_edge0); + canque_edge_decref(edge); + + + /*********************************************************************** + * USB Init + ***********************************************************************/ + + memset( &usb_device, 0, sizeof( usb_device)); + usb_device.id = 1; + usb_device.devdes_table = &usb_devdes_table; + usb_device.init = usb_lpc_init; + usb_debug_set_level(DEBUG_LEVEL_NONE); + usb_device.cntep = NUM_ENDPOINTS; + usb_device.ep = eps; + + eps[0].max_packet_size = USB_MAX_PACKET; + eps[1].max_packet_size = USB_MAX_PACKET; + eps[0].epnum = 0x01; + eps[1].epnum = 0x81; + eps[0].event_mask = 0x04; + eps[1].event_mask = 0x08; + eps[0].udev = &usb_device; + eps[1].udev = &usb_device; + + usb_device.vendor_fnc=usbcan_vendor; + + usb_init(&usb_device); + usb_connect(&usb_device); + usb_device.ep_events |= MASK_EP1TX; + + /*********************************************************************** + * Start + ***********************************************************************/ + + timer_rx_off=timer_tx_off=timer_str=timer_configured=0; + while (1) { + + usb_check_events(&usb_device); + usb_control_response(&usb_device); + + if (!(IO0PIN&P0_SJA1000_INT_PIN)) //INT PIN is inverted + chip->chipspecops->irq_handler(0,chip); + + if (usb_device.ep_events & MASK_EP1RX) { //EP1RX - data waiting to receive + if (canque_get_inslot(qends, &qedge, &slot, 0)>=0){ //Free slot obtained + size=usb_udev_read_endpoint(&eps[0],ep1_rx_buff,16); + if (size==16){ + uint16_t msgflags; + uint32_t msgid; + canmsg.cob=0; + canmsg.length=*(uint8_t *)(ep1_rx_buff+1); + if (canmsg.length > CAN_MSG_LENGTH) + canmsg.length=CAN_MSG_LENGTH; + msgflags=*(uint16_t *)(ep1_rx_buff+2); + msgid=*(uint32_t *)(ep1_rx_buff+4); + #if __BYTE_ORDER == __BIG_ENDIAN + msgflags = bswap_16( msgflags); + msgid = bswap_32( msgid); + #endif + canmsg.flags=msgflags; + canmsg.id=msgid; + + for (i=0;i2047 */ + if (canmsg.id & ~0x7ffl & MSG_ID_MASK ) canmsg.flags |= MSG_EXT; + /* has been dependent on "extended" option */ + slot->msg=canmsg; + canque_put_inslot(qends, qedge, slot); + } + else + canque_abort_inslot(qends,qedge,slot); + timer_rx_off=50; //rosviceni diody pri prijmu + CLR_OUT_PIN(LED_PORT,LED2_BIT); + usb_device.ep_events &= ~MASK_EP1RX; + } + + +/* if (size==2){ + uint8_t val; + if ((data[0]&CAN_OP_MASK)==CAN_OP_READ){ // Get data from CAN device and return to caller + val = can_read(data[0] & ~CAN_OP_MASK); + *(data+1)=val; + usb_udev_write_endpoint(&eps[1],(unsigned char *)data,size); + timer_rx_off=50; //rosviceni diody pri prijmu + CLR_OUT_PIN(LED_PORT,LED2_BIT); + usb_can_send=0; + } + if ((data[0]&CAN_OP_MASK)==CAN_OP_WRITE){ // Save data to CAN device + can_write(data[1], data[0] & ~CAN_OP_MASK); + timer_tx_off=50; //rozsviceni diod pri vysilani + CLR_OUT_PIN(LED_PORT,LED1_BIT); + } + }*/ + } + + if(usb_device.ep_events & MASK_EP1TX){ //EP1TX - data transmitted + if(canque_test_outslot(qends, &qedge, &slot)>=0){ + DEBUGMSG("CAN message ready to send over usb\n"); + uint16_t msgflags; + uint32_t msgid; + + *(uint8_t *)(ep1_tx_buff)=0; + *(uint8_t *)(ep1_tx_buff+1)=slot->msg.length; + + msgflags=slot->msg.flags; + msgid=slot->msg.id; + #if __BYTE_ORDER == __BIG_ENDIAN + msgflags = bswap_16( msgflags); + msgid = bswap_32( msgid); + #endif + + *(uint16_t *)(ep1_tx_buff+2)=msgflags; + *(uint32_t *)(ep1_tx_buff+4)=msgid; + for (i=0;imsg.length;i++){ + *(uint8_t *)(ep1_tx_buff+8+i)=slot->msg.data[i]; + } + for (;idev_base_addr; + candev->dev_base_addr=new_base; + for(i=0;inr_all_chips;i++){ + candev->chip[i]->chip_base_addr += offs; + for(j=0;jchip[i]->max_objects;j++) + candev->chip[i]->msgobj[j]->obj_base_addr += offs; + } + return 0; +} + +/** + * can_check_dev_taken - checks if bus device description is already taken by driver + * @anydev: pointer to bus specific Linux device description + * + * Returns: Returns 1 if device is already used by LinCAN driver, 0 otherwise. + */ +int can_check_dev_taken(void *anydev) +{ + int board_nr; + struct candevice_t *candev; + void *boarddev; + + for (board_nr=hardware_p->nr_boards; board_nr--; ) { + if((candev=hardware_p->candevice[board_nr])==NULL) + continue; + boarddev=candev->sysdevptr.anydev; + if(boarddev == anydev) + return 1; + } + + return 0; +} + + +/** + * register_obj_struct - registers message object into global array + * @obj: the initialized message object being registered + * @minorbase: wanted minor number, if (-1) automatically selected + * + * Return Value: returns negative number in the case of fail + */ +int register_obj_struct(struct msgobj_t *obj, int minorbase) +{ + static int next_minor=0; + int i; + + if(minorbase>=0) + next_minor=minorbase; + if(next_minor>=MAX_TOT_MSGOBJS) + next_minor=0; + i=next_minor; + do{ + if(objects_p[i]==NULL){ + objects_p[i]=obj; + obj->minor=i; + next_minor=i+1; + return 0; + } + if(++i >= MAX_TOT_MSGOBJS) i=0; + }while(i!=next_minor); + obj->minor=-1; + return -1; +} + + +/** + * register_chip_struct - registers chip into global array + * @chip: the initialized chip structure being registered + * @minorbase: wanted minor number base, if (-1) automatically selected + * + * Return Value: returns negative number in the case of fail + */ +int register_chip_struct(struct canchip_t *chip, int minorbase) +{ + static int next_chip_slot=0; + int i; + + if(next_chip_slot>=MAX_TOT_CHIPS) + next_chip_slot=0; + i=next_chip_slot; + do{ + if(chips_p[i]==NULL){ + chips_p[i]=chip; + + next_chip_slot=i+1; + return 0; + } + if(++i >= MAX_TOT_CHIPS) i=0; + }while(i!=next_chip_slot); + return -1; +} + + + +/** + * init_hw_struct - initializes driver hardware description structures + * + * The function init_hw_struct() is used to initialize the hardware structure. + * + * Return Value: returns negative number in the case of fail + */ +// int init_hw_struct(void) +// { +// int i=0; +// int irq_param_idx=0; +// int chan_param_idx=0; +// +// hardware_p->nr_boards=0; +// while ( (hw[i] != NULL) & (i < MAX_HW_CARDS) ) { +// hardware_p->nr_boards++; +// +// if (init_device_struct(i, &chan_param_idx, &irq_param_idx)) { +// CANMSG("Error initializing candevice_t structures.\n"); +// return -ENODEV; +// } +// i++; +// } +// +// return 0; +// } + +/** + * init_device_struct - initializes single CAN device/board + * @card: index into @hardware_p HW description + * @chan_param_idx_p: pointer to the index into arrays of the CAN channel parameters + * @irq_param_idx_p: pointer to the index into arrays of the per CAN channel IRQ parameters + * + * The function builds representation of the one board from parameters provided + * in the module parameters arrays: + * @hw[card] .. hardware type, + * @io[card] .. base IO address, + * @baudrate[chan_param_idx] .. per channel baudrate, + * @minor[chan_param_idx] .. optional specification of requested channel minor base, + * @irq[irq_param_idx] .. one or more board/chips IRQ parameters. + * The indexes are advanced after consumed parameters if the registration is successful. + * + * The hardware specific operations of the device/board are initialized by call to + * init_hwspecops() function. Then board data are initialized by board specific + * init_hw_data() function. Then chips and objects representation is build by + * init_chip_struct() function. If all above steps are successful, chips and + * message objects are registered into global arrays. + * + * Return Value: returns negative number in the case of fail + */ +// int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p) +// { +// struct candevice_t *candev; +// int ret; +// int irqnum; +// int chipnr; +// long bd; +// int irqsig=-1; +// +// candev=(struct candevice_t *)malloc(sizeof(struct candevice_t)); +// if (candev==NULL) +// return -ENOMEM; +// +// memset(candev, 0, sizeof(struct candevice_t)); +// +// hardware_p->candevice[card]=candev; +// candev->candev_idx=card; +// +// candev=candev; +// +// candev->hwname=hw[card]; +// candev->io_addr=io[card]; +// candev->dev_base_addr=io[card]; +// +// candev->hwspecops=(struct hwspecops_t *)malloc(sizeof(struct hwspecops_t)); +// if (candev->hwspecops==NULL) +// goto error_nomem; +// +// memset(candev->hwspecops, 0, sizeof(struct hwspecops_t)); +// +// if (init_hwspecops(candev, &irqnum)) +// goto error_nodev; +// +// if (candev->hwspecops->init_hw_data(candev)) +// goto error_nodev; +// +// /* Alocate and initialize the chip structures */ +// for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) { +// +// if(chipnrnr_all_chips; chipnr++) { +// int m=minor[*chan_param_idx_p+chipnr]; +// struct canchip_t *chip=candev->chip[chipnr]; +// int objnr; +// +// register_chip_struct(chip, m); +// +// for (objnr=0; objnrmax_objects; objnr++) { +// register_obj_struct(chip->msgobj[objnr], m); +// if(m>=0) m++; +// } +// } +// +// *irq_param_idx_p += irqnum; +// *chan_param_idx_p += candev->nr_all_chips; +// +// return 0; +// +// error_nodev: +// ret=-ENODEV; +// error_chip: +// candevice_done(candev); +// goto error_both; +// +// error_nomem: +// ret=-ENOMEM; +// +// error_both: +// hardware_p->candevice[card]=NULL; +// free(candev); +// return ret; +// +// } + +/** + * init_chip_struct - initializes one CAN chip structure + * @candev: pointer to the corresponding CAN device/board + * @chipnr: index of the chip in the corresponding device/board structure + * @irq: chip IRQ number or (-1) if not appropriate + * @baudrate: baudrate in the units of 1Bd + * + * Chip structure is allocated and chip specific operations are filled by + * call to board specific init_chip_data() which calls chip specific + * fill_chipspecops(). The message objects are generated by + * calls to init_obj_struct() function. + * + * Return Value: returns negative number in the case of fail + */ +int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate) +{ + struct canchip_t *chip; + int objnr; + int ret; + + candev->chip[chipnr]=(struct canchip_t *)malloc(sizeof(struct canchip_t)); + if ((chip=candev->chip[chipnr])==NULL) + return -ENOMEM; + + memset(chip, 0, sizeof(struct canchip_t)); + + chip->write_register=candev->hwspecops->write_register; + chip->read_register=candev->hwspecops->read_register; + + chip->chipspecops=malloc(sizeof(struct chipspecops_t)); + if (chip->chipspecops==NULL) + return -ENOMEM; + memset(chip->chipspecops,0,sizeof(struct chipspecops_t)); + + chip->chip_idx=chipnr; + chip->hostdevice=candev; + chip->chip_irq=irq; + chip->baudrate=baudrate; + chip->flags=0x0; + + if(candev->hwspecops->init_chip_data(candev,chipnr)<0) + return -ENODEV; + + for (objnr=0; objnrmax_objects; objnr++) { + ret=init_obj_struct(candev, chip, objnr); + if(ret<0) return ret; + } + + return 0; +} + + +/** + * init_obj_struct - initializes one CAN message object structure + * @candev: pointer to the corresponding CAN device/board + * @hostchip: pointer to the chip containing this object + * @objnr: index of the builded object in the chip structure + * + * The function initializes message object structure and allocates and initializes + * CAN queue chip ends structure. + * + * Return Value: returns negative number in the case of fail + */ +int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int objnr) +{ + struct canque_ends_t *qends; + struct msgobj_t *obj; + int ret; + + obj=(struct msgobj_t *)malloc(sizeof(struct msgobj_t)); + hostchip->msgobj[objnr]=obj; + if (obj == NULL) + return -ENOMEM; + + memset(obj, 0, sizeof(struct msgobj_t)); + obj->minor=-1; + + atomic_set(&obj->obj_used,0); + INIT_LIST_HEAD(&obj->obj_users); +// init_timer(&obj->tx_timeout); + + qends = (struct canque_ends_t *)malloc(sizeof(struct canque_ends_t)); + if(qends == NULL) return -ENOMEM; + memset(qends, 0, sizeof(struct canque_ends_t)); + obj->hostchip=hostchip; + obj->object=objnr+1; + obj->qends=qends; + obj->tx_qedge=NULL; + obj->tx_slot=NULL; + obj->obj_flags = 0x0; + + ret=canqueue_ends_init_chip(qends, hostchip, obj); + if(ret<0) return ret; + + ret=candev->hwspecops->init_obj_data(hostchip,objnr); + if(ret<0) return ret; + + return 0; +} + + +/** + * init_hwspecops - finds and initializes board/device specific operations + * @candev: pointer to the corresponding CAN device/board + * @irqnum_p: optional pointer to the number of interrupts required by board + * + * The function searches board @hwname in the list of supported boards types. + * The board type specific board_register() function is used to initialize + * @hwspecops operations. + * + * Return Value: returns negative number in the case of fail + */ +// int init_hwspecops(struct candevice_t *candev, int *irqnum_p) +// { +// const struct boardtype_t *brp; +// +// brp = boardtype_find(candev->hwname); +// +// if(!brp) { +// CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",candev->hwname); +// return -EINVAL; +// } +// +// if(irqnum_p) +// *irqnum_p=brp->irqnum; +// brp->board_register(candev->hwspecops); +// +// return 0; +// } diff --git a/embedded/app/usbcan/sja1000p.c b/embedded/app/usbcan/sja1000p.c new file mode 100644 index 0000000..8a527ff --- /dev/null +++ b/embedded/app/usbcan/sja1000p.c @@ -0,0 +1,911 @@ +/* sja1000.c + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Changed for PeliCan mode SJA1000 by Tomasz Motylewski (BFAD GmbH) + * T.Motylewski@bfad.de + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "./can/can.h" +#include "./can/can_sysdep.h" +#include "./can/main.h" +#include "./can/sja1000p.h" + +#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS + +static const char *sja1000_ecc_errc_str[]={ + "bit error", + "form error", + "stuff error", + "other type of error" +}; + +static const char *sja1000_ecc_seg_str[]={ + "?0?", + "?1?", + "ID.28 to ID.21", + "start of frame", + "bit SRTR", + "bit IDE", + "ID.20 to ID.18", + "ID.17 to ID.13", + "CRC sequence", + "reserved bit 0", + "data field", + "data length code", + "bit RTR", + "reserved bit 1", + "ID.4 to ID.0", + "ID.12 to ID.5", + "?16?" + "active error flag", + "intermission", + "tolerate dominant bits", + "?20?", + "?21?", + "passive error flag", + "error delimiter", + "CRC delimiter", + "acknowledge slot", + "end of frame", + "acknowledge delimiter", + "overload flag", + "?29?", + "?30?", + "?31?" +}; + +#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/ + +static int sja1000_report_error_limit_counter; + +static void sja1000_report_error(struct canchip_t *chip, + unsigned sr, unsigned ir, unsigned ecc) +{ + if(sja1000_report_error_limit_counter>=100) + return; + + CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n", + sr, ir, ecc); + + sja1000_report_error_limit_counter+=10; + + if(sja1000_report_error_limit_counter>=100){ + sja1000_report_error_limit_counter+=10; + CANMSG("Error: too many errors, reporting disabled\n"); + return; + } + +#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS + CANMSG("SR: BS=%c ES=%c TS=%c RS=%c TCS=%c TBS=%c DOS=%c RBS=%c\n", + sr&sjaSR_BS?'1':'0',sr&sjaSR_ES?'1':'0', + sr&sjaSR_TS?'1':'0',sr&sjaSR_RS?'1':'0', + sr&sjaSR_TCS?'1':'0',sr&sjaSR_TBS?'1':'0', + sr&sjaSR_DOS?'1':'0',sr&sjaSR_RBS?'1':'0'); + CANMSG("IR: BEI=%c ALI=%c EPI=%c WUI=%c DOI=%c EI=%c TI=%c RI=%c\n", + sr&sjaIR_BEI?'1':'0',sr&sjaIR_ALI?'1':'0', + sr&sjaIR_EPI?'1':'0',sr&sjaIR_WUI?'1':'0', + sr&sjaIR_DOI?'1':'0',sr&sjaIR_EI?'1':'0', + sr&sjaIR_TI?'1':'0',sr&sjaIR_RI?'1':'0'); + if((sr&sjaIR_EI) || 1){ + CANMSG("EI: %s %s %s\n", + sja1000_ecc_errc_str[(ecc&(sjaECC_ERCC1|sjaECC_ERCC0))/sjaECC_ERCC0], + ecc&sjaECC_DIR?"RX":"TX", + sja1000_ecc_seg_str[ecc&sjaECC_SEG_M] + ); + } +#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/ +} + + +/** + * sja1000p_enable_configuration - enable chip configuration mode + * @chip: pointer to chip state structure + */ +int sja1000p_enable_configuration(struct canchip_t *chip) +{ + int i=0; + enum sja1000_PeliCAN_MOD flags; + + can_disable_irq(chip->chip_irq); + + flags=can_read_reg(chip,SJAMOD); + + while ((!(flags & sjaMOD_RM)) && (i<=10)) { + can_write_reg(chip, sjaMOD_RM, SJAMOD); +// TODO: configurable sjaMOD_AFM (32/16 bit acceptance filter) +// config sjaMOD_LOM (listen only) + udelay(100); + i++; + flags=can_read_reg(chip, SJAMOD); + } + if (i>=10) { + CANMSG("Reset error\n"); + can_enable_irq(chip->chip_irq); + return -ENODEV; + } + + return 0; +} + +/** + * sja1000p_disable_configuration - disable chip configuration mode + * @chip: pointer to chip state structure + */ +int sja1000p_disable_configuration(struct canchip_t *chip) +{ + int i=0; + enum sja1000_PeliCAN_MOD flags; + + flags=can_read_reg(chip,SJAMOD); + + while ( (flags & sjaMOD_RM) && (i<=50) ) { +// could be as long as 11*128 bit times after buss-off + can_write_reg(chip, 0, SJAMOD); +// TODO: configurable sjaMOD_AFM (32/16 bit acceptance filter) +// config sjaMOD_LOM (listen only) + udelay(100); + i++; + flags=can_read_reg(chip, SJAMOD); + } + if (i>=10) { + CANMSG("Error leaving reset status\n"); + return -ENODEV; + } + + can_enable_irq(chip->chip_irq); + + return 0; +} + +/** + * sja1000p_chip_config: - can chip configuration + * @chip: pointer to chip state structure + * + * This function configures chip and prepares it for message + * transmission and reception. The function resets chip, + * resets mask for acceptance of all messages by call to + * sja1000p_extended_mask() function and then + * computes and sets baudrate with use of function sja1000p_baud_rate(). + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_chip_config(struct canchip_t *chip) +{ + int i; + unsigned char n, r; + + if (sja1000p_enable_configuration(chip)) + return -ENODEV; + + /* Set mode, clock out, comparator */ + can_write_reg(chip,sjaCDR_PELICAN|chip->sja_cdr_reg,SJACDR); + + /* Ensure, that interrupts are disabled even on the chip level now */ + can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER); + + /* Set driver output configuration */ + can_write_reg(chip,chip->sja_ocr_reg,SJAOCR); + + /* Simple check for chip presence */ + for (i=0, n=0x5a; i<8; i++, n+=0xf) { + can_write_reg(chip,n,SJAACR0+i); + } + for (i=0, n=0x5a; i<8; i++, n+=0xf) { + r = n^can_read_reg(chip,SJAACR0+i); + if (r) { + CANMSG("sja1000p_chip_config: chip connection broken," + " readback differ 0x%02x\n", r); + return -ENODEV; + } + } + + + if (sja1000p_extended_mask(chip,0x00000000, 0xffffffff)) + return -ENODEV; + + if (!chip->baudrate) + chip->baudrate=1000000; + if (sja1000p_baud_rate(chip,chip->baudrate,chip->clock,0,75,0)) + return -ENODEV; + + /* Enable hardware interrupts */ + can_write_reg(chip, sjaENABLE_INTERRUPTS, SJAIER); + + sja1000p_disable_configuration(chip); + + return 0; +} + +/** + * sja1000p_extended_mask: - setup of extended mask for message filtering + * @chip: pointer to chip state structure + * @code: can message acceptance code + * @mask: can message acceptance mask + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask) +{ + int i; + + if (sja1000p_enable_configuration(chip)) + return -ENODEV; + +// LSB to +3, MSB to +0 + for(i=SJA_PeliCAN_AC_LEN; --i>=0;) { + can_write_reg(chip,code&0xff,SJAACR0+i); + can_write_reg(chip,mask&0xff,SJAAMR0+i); + code >>= 8; + mask >>= 8; + } + + DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code); + DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask); + + sja1000p_disable_configuration(chip); + + return 0; +} + +/** + * sja1000p_baud_rate: - set communication parameters. + * @chip: pointer to chip state structure + * @rate: baud rate in Hz + * @clock: frequency of sja1000 clock in Hz (ISA osc is 14318000) + * @sjw: synchronization jump width (0-3) prescaled clock cycles + * @sampl_pt: sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio + * @flags: fields %BTR1_SAM, %OCMODE, %OCPOL, %OCTP, %OCTN, %CLK_OFF, %CBP + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, + int sampl_pt, int flags) +{ + int best_error = 1000000000, error; + int best_tseg=0, best_brp=0, best_rate=0, brp=0; + int tseg=0, tseg1=0, tseg2=0; + + if (sja1000p_enable_configuration(chip)) + return -ENODEV; + + clock /=2; + + /* tseg even = round down, odd = round up */ + for (tseg=(0+0+2)*2; tseg<=(sjaMAX_TSEG2+sjaMAX_TSEG1+2)*2+1; tseg++) { + brp = clock/((1+tseg/2)*rate)+tseg%2; + if (brp == 0 || brp > 64) + continue; + error = rate - clock/(brp*(1+tseg/2)); + if (error < 0) + error = -error; + if (error <= best_error) { + best_error = error; + best_tseg = tseg/2; + best_brp = brp-1; + best_rate = clock/(brp*(1+tseg/2)); + } + } + if (best_error && (rate/best_error < 10)) { + CANMSG("baud rate %d is not possible with %d Hz clock\n", + rate, 2*clock); + CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n", + best_rate, best_brp, best_tseg, tseg1, tseg2); + return -EINVAL; + } + tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100; + if (tseg2 < 0) + tseg2 = 0; + if (tseg2 > sjaMAX_TSEG2) + tseg2 = sjaMAX_TSEG2; + tseg1 = best_tseg-tseg2-2; + if (tseg1>sjaMAX_TSEG1) { + tseg1 = sjaMAX_TSEG1; + tseg2 = best_tseg-tseg1-2; + } + + DEBUGMSG("Setting %d bps.\n", best_rate); + DEBUGMSG("brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n", + best_brp, best_tseg, tseg1, tseg2, + (100*(best_tseg-tseg2)/(best_tseg+1))); + + + can_write_reg(chip, sjw<<6 | best_brp, SJABTR0); + can_write_reg(chip, ((flags & BTR1_SAM) != 0)<<7 | (tseg2<<4) + | tseg1, SJABTR1); + + sja1000p_disable_configuration(chip); + + return 0; +} + +/** + * sja1000p_read: - reads and distributes one or more received messages + * @chip: pointer to chip state structure + * @obj: pinter to CAN message queue information + * + * File: src/sja1000p.c + */ +void sja1000p_read(struct canchip_t *chip, struct msgobj_t *obj) { + int i, flags, len, datastart; + do { + flags = can_read_reg(chip,SJAFRM); + if(flags&sjaFRM_FF) { + obj->rx_msg.id = + (can_read_reg(chip,SJAID0)<<21) + + (can_read_reg(chip,SJAID1)<<13) + + (can_read_reg(chip,SJAID2)<<5) + + (can_read_reg(chip,SJAID3)>>3); + datastart = SJADATE; + } else { + obj->rx_msg.id = + (can_read_reg(chip,SJAID0)<<3) + + (can_read_reg(chip,SJAID1)>>5); + datastart = SJADATS; + } + obj->rx_msg.flags = + ((flags & sjaFRM_RTR) ? MSG_RTR : 0) | + ((flags & sjaFRM_FF) ? MSG_EXT : 0); + len = flags & sjaFRM_DLC_M; + obj->rx_msg.length = len; + if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; + for(i=0; i< len; i++) { + obj->rx_msg.data[i]=can_read_reg(chip,datastart+i); + } + + /* fill CAN message timestamp */ + can_filltimestamp(&obj->rx_msg.timestamp); + + canque_filter_msg2edges(obj->qends, &obj->rx_msg); + + can_write_reg(chip, sjaCMR_RRB, SJACMR); + + } while (can_read_reg(chip, SJASR) & sjaSR_RBS); +} + +/** + * sja1000p_pre_read_config: - prepares message object for message reception + * @chip: pointer to chip state structure + * @obj: pointer to message object state structure + * + * Return Value: negative value reports error. + * Positive value indicates immediate reception of message. + * File: src/sja1000p.c + */ +int sja1000p_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj) +{ + int status; + status=can_read_reg(chip,SJASR); + + if(status & sjaSR_BS) { + /* Try to recover from error condition */ + DEBUGMSG("sja1000p_pre_read_config bus-off recover 0x%x\n",status); + sja1000p_enable_configuration(chip); + can_write_reg(chip, 0, SJARXERR); + can_write_reg(chip, 0, SJATXERR1); + can_read_reg(chip, SJAECC); + sja1000p_disable_configuration(chip); + } + + if (!(status&sjaSR_RBS)) { + return 0; + } + + can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER); //disable interrupts for a moment + sja1000p_read(chip, obj); + can_write_reg(chip, sjaENABLE_INTERRUPTS, SJAIER); //enable interrupts + return 1; +} + +#define MAX_TRANSMIT_WAIT_LOOPS 10 +/** + * sja1000p_pre_write_config: - prepares message object for message transmission + * @chip: pointer to chip state structure + * @obj: pointer to message object state structure + * @msg: pointer to CAN message + * + * This function prepares selected message object for future initiation + * of message transmission by sja1000p_send_msg() function. + * The CAN message data and message ID are transfered from @msg slot + * into chip buffer in this function. + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg) +{ + int i=0; + unsigned int id; + int status; + int len; + + /* Wait until Transmit Buffer Status is released */ + while ( !((status=can_read_reg(chip, SJASR)) & sjaSR_TBS) && + i++length; + if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; + /* len &= sjaFRM_DLC_M; ensured by above condition already */ + can_write_reg(chip, ((msg->flags&MSG_EXT)?sjaFRM_FF:0) | + ((msg->flags & MSG_RTR) ? sjaFRM_RTR : 0) | len, SJAFRM); + if(msg->flags&MSG_EXT) { + id=msg->id<<3; + can_write_reg(chip, id & 0xff, SJAID3); + id >>= 8; + can_write_reg(chip, id & 0xff, SJAID2); + id >>= 8; + can_write_reg(chip, id & 0xff, SJAID1); + id >>= 8; + can_write_reg(chip, id, SJAID0); + for(i=0; i < len; i++) { + can_write_reg(chip, msg->data[i], SJADATE+i); + } + } else { + id=msg->id<<5; + can_write_reg(chip, (id >> 8) & 0xff, SJAID0); + can_write_reg(chip, id & 0xff, SJAID1); + for(i=0; i < len; i++) { + can_write_reg(chip, msg->data[i], SJADATS+i); + } + } + return 0; +} + +/** + * sja1000p_send_msg: - initiate message transmission + * @chip: pointer to chip state structure + * @obj: pointer to message object state structure + * @msg: pointer to CAN message + * + * This function is called after sja1000p_pre_write_config() function, + * which prepares data in chip buffer. + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_send_msg(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg) +{ + can_write_reg(chip, sjaCMR_TR, SJACMR); + + return 0; +} + +/** + * sja1000p_check_tx_stat: - checks state of transmission engine + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * Positive return value indicates transmission under way status. + * Zero value indicates finishing of all issued transmission requests. + * File: src/sja1000p.c + */ +int sja1000p_check_tx_stat(struct canchip_t *chip) +{ + if (can_read_reg(chip,SJASR) & sjaSR_TCS) + return 0; + else + return 1; +} + +/** + * sja1000p_set_btregs: - configures bitrate registers + * @chip: pointer to chip state structure + * @btr0: bitrate register 0 + * @btr1: bitrate register 1 + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_set_btregs(struct canchip_t *chip, unsigned short btr0, + unsigned short btr1) +{ + if (sja1000p_enable_configuration(chip)) + return -ENODEV; + + can_write_reg(chip, btr0, SJABTR0); + can_write_reg(chip, btr1, SJABTR1); + + sja1000p_disable_configuration(chip); + + return 0; +} + +/** + * sja1000p_start_chip: - starts chip message processing + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_start_chip(struct canchip_t *chip) +{ + enum sja1000_PeliCAN_MOD flags; + + flags = can_read_reg(chip, SJAMOD) & (sjaMOD_LOM|sjaMOD_STM|sjaMOD_AFM|sjaMOD_SM); + can_write_reg(chip, flags, SJAMOD); + + sja1000_report_error_limit_counter=0; + + return 0; +} + +/** + * sja1000p_stop_chip: - stops chip message processing + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_stop_chip(struct canchip_t *chip) +{ + enum sja1000_PeliCAN_MOD flags; + + flags = can_read_reg(chip, SJAMOD) & (sjaMOD_LOM|sjaMOD_STM|sjaMOD_AFM|sjaMOD_SM); + can_write_reg(chip, flags|sjaMOD_RM, SJAMOD); + + return 0; +} + +/** + * sja1000p_attach_to_chip: - attaches to the chip, setups registers and state + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_attach_to_chip(struct canchip_t *chip) +{ + return 0; +} + +/** + * sja1000p_release_chip: - called before chip structure removal if %CHIP_ATTACHED is set + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_release_chip(struct canchip_t *chip) +{ + sja1000p_stop_chip(chip); + can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER); + + return 0; +} + +/** + * sja1000p_remote_request: - configures message object and asks for RTR message + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_remote_request(struct canchip_t *chip, struct msgobj_t *obj) +{ + CANMSG("sja1000p_remote_request not implemented\n"); + return -ENOSYS; +} + +/** + * sja1000p_standard_mask: - setup of mask for message filtering + * @chip: pointer to chip state structure + * @code: can message acceptance code + * @mask: can message acceptance mask + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_standard_mask(struct canchip_t *chip, unsigned short code, + unsigned short mask) +{ + CANMSG("sja1000p_standard_mask not implemented\n"); + return -ENOSYS; +} + +/** + * sja1000p_clear_objects: - clears state of all message object residing in chip + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_clear_objects(struct canchip_t *chip) +{ + CANMSG("sja1000p_clear_objects not implemented\n"); + return -ENOSYS; +} + +/** + * sja1000p_config_irqs: - tunes chip hardware interrupt delivery + * @chip: pointer to chip state structure + * @irqs: requested chip IRQ configuration + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_config_irqs(struct canchip_t *chip, short irqs) +{ + CANMSG("sja1000p_config_irqs not implemented\n"); + return -ENOSYS; +} + +/** + * sja1000p_irq_write_handler: - part of ISR code responsible for transmit events + * @chip: pointer to chip state structure + * @obj: pointer to attached queue description + * + * The main purpose of this function is to read message from attached queues + * and transfer message contents into CAN controller chip. + * This subroutine is called by + * sja1000p_irq_write_handler() for transmit events. + * File: src/sja1000p.c + */ +void sja1000p_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj) +{ + int cmd; + + if(obj->tx_slot){ + /* Do local transmitted message distribution if enabled */ + if (processlocal){ + /* fill CAN message timestamp */ + can_filltimestamp(&obj->tx_slot->msg.timestamp); + + obj->tx_slot->msg.flags |= MSG_LOCAL; + canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg); + } + /* Free transmitted slot */ + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + } + + can_msgobj_clear_fl(obj,TX_PENDING); + cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot); + if(cmd<0) + return; + can_msgobj_set_fl(obj,TX_PENDING); + + if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) { + obj->ret = -1; + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP); + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + return; + } + if (chip->chipspecops->send_msg(chip, obj, &obj->tx_slot->msg)) { + obj->ret = -1; + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND); + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + return; + } + +} + +#define MAX_RETR 10 + +/** + * sja1000p_irq_handler: - interrupt service routine + * @irq: interrupt vector number, this value is system specific + * @chip: pointer to chip state structure + * + * Interrupt handler is activated when state of CAN controller chip changes, + * there is message to be read or there is more space for new messages or + * error occurs. The receive events results in reading of the message from + * CAN controller chip and distribution of message through attached + * message queues. + * File: src/sja1000p.c + */ +int sja1000p_irq_handler(int irq, struct canchip_t *chip) +{ + int irq_register, status, error_code; + struct msgobj_t *obj=chip->msgobj[0]; + int loop_cnt=CHIP_MAX_IRQLOOP; + + irq_register=can_read_reg(chip,SJAIR); +// DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); +// DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n", +// can_read_reg(chip,SJASR)); + + if ((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) == 0) + return CANCHIP_IRQ_NONE; + + if(!(chip->flags&CHIP_CONFIGURED)) { + CANMSG("sja1000p_irq_handler: called for non-configured device, irq_register 0x%02x\n", irq_register); + return CANCHIP_IRQ_NONE; + } + + status=can_read_reg(chip,SJASR); + + do { + + if(!loop_cnt--) { + CANMSG("sja1000p_irq_handler IRQ %d stuck\n",irq); + return CANCHIP_IRQ_STUCK; + } + + /* (irq_register & sjaIR_RI) */ + /* old variant using SJAIR, collides with intended use with irq_accept */ + if (status & sjaSR_RBS) { + DEBUGMSG("sja1000_irq_handler: RI or RBS\n"); + sja1000p_read(chip,obj); + obj->ret = 0; + } + + /* (irq_register & sjaIR_TI) */ + /* old variant using SJAIR, collides with intended use with irq_accept */ + if (((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING))|| + (can_msgobj_test_fl(obj,TX_REQUEST))) { + DEBUGMSG("sja1000_irq_handler: TI or TX_PENDING and TBS\n"); + obj->ret = 0; + can_msgobj_set_fl(obj,TX_REQUEST); + while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ + can_msgobj_clear_fl(obj,TX_REQUEST); + + if (can_read_reg(chip, SJASR) & sjaSR_TBS) + sja1000p_irq_write_handler(chip, obj); + + can_msgobj_clear_fl(obj,TX_LOCK); + if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + DEBUGMSG("TX looping in sja1000_irq_handler\n"); + } + } + if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) { + // Some error happened + error_code=can_read_reg(chip,SJAECC); + sja1000_report_error(chip, status, irq_register, error_code); +// FIXME: chip should be brought to usable state. Transmission cancelled if in progress. +// Reset flag set to 0 if chip is already off the bus. Full state report + obj->ret=-1; + + if(error_code == 0xd9) { + obj->ret= -ENXIO; + /* no such device or address - no ACK received */ + } + if(obj->tx_retry_cnt++>MAX_RETR) { + can_write_reg(chip, sjaCMR_AT, SJACMR); // cancel any transmition + obj->tx_retry_cnt = 0; + } + if(status&sjaSR_BS) { + CANMSG("bus-off, resetting sja1000p\n"); + can_write_reg(chip, 0, SJAMOD); + } + + if(obj->tx_slot){ + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); + /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL;*/ + } + + } else { + if(sja1000_report_error_limit_counter) + sja1000_report_error_limit_counter--; + obj->tx_retry_cnt=0; + } + + irq_register=can_read_reg(chip,SJAIR); + + status=can_read_reg(chip,SJASR); + + if(((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) || + (irq_register & sjaIR_TI)) + can_msgobj_set_fl(obj,TX_REQUEST); + + } while((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_RI)) || + (can_msgobj_test_fl(obj,TX_REQUEST) && !can_msgobj_test_fl(obj,TX_LOCK)) || + (status & sjaSR_RBS)); + + return CANCHIP_IRQ_HANDLED; +} + +/** + * sja1000p_wakeup_tx: - wakeups TX processing + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Function is responsible for initiating message transmition. + * It is responsible for clearing of object TX_REQUEST flag + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj) +{ + + can_preempt_disable(); + + can_msgobj_set_fl(obj,TX_PENDING); + can_msgobj_set_fl(obj,TX_REQUEST); + while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ + can_msgobj_clear_fl(obj,TX_REQUEST); + + if (can_read_reg(chip, SJASR) & sjaSR_TBS){ + obj->tx_retry_cnt=0; + sja1000p_irq_write_handler(chip, obj); + } + + can_msgobj_clear_fl(obj,TX_LOCK); + if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + DEBUGMSG("TX looping in sja1000p_wakeup_tx\n"); + } + + can_preempt_enable(); + return 0; +} + +int sja1000p_register(struct chipspecops_t *chipspecops) +{ + CANMSG("initializing sja1000p chip operations\n"); + chipspecops->chip_config=sja1000p_chip_config; + chipspecops->baud_rate=sja1000p_baud_rate; + chipspecops->standard_mask=sja1000p_standard_mask; + chipspecops->extended_mask=sja1000p_extended_mask; + chipspecops->message15_mask=sja1000p_extended_mask; + chipspecops->clear_objects=sja1000p_clear_objects; + chipspecops->config_irqs=sja1000p_config_irqs; + chipspecops->pre_read_config=sja1000p_pre_read_config; + chipspecops->pre_write_config=sja1000p_pre_write_config; + chipspecops->send_msg=sja1000p_send_msg; + chipspecops->check_tx_stat=sja1000p_check_tx_stat; + chipspecops->wakeup_tx=sja1000p_wakeup_tx; + chipspecops->remote_request=sja1000p_remote_request; + chipspecops->enable_configuration=sja1000p_enable_configuration; + chipspecops->disable_configuration=sja1000p_disable_configuration; + chipspecops->attach_to_chip=sja1000p_attach_to_chip; + chipspecops->release_chip=sja1000p_release_chip; + chipspecops->set_btregs=sja1000p_set_btregs; + chipspecops->start_chip=sja1000p_start_chip; + chipspecops->stop_chip=sja1000p_stop_chip; + chipspecops->irq_handler=sja1000p_irq_handler; + chipspecops->irq_accept=NULL; + return 0; +} + +/** + * sja1000p_fill_chipspecops - fills chip specific operations + * @chip: pointer to chip representation structure + * + * The function fills chip specific operations for sja1000 (PeliCAN) chip. + * + * Return Value: returns negative number in the case of fail + */ +int sja1000p_fill_chipspecops(struct canchip_t *chip) +{ + chip->chip_type="sja1000p"; + chip->max_objects=1; + sja1000p_register(chip->chipspecops); + return 0; +} diff --git a/embedded/app/usbcan/ul_usb1.c b/embedded/app/usbcan/ul_usb1.c new file mode 100644 index 0000000..9e0e709 --- /dev/null +++ b/embedded/app/usbcan/ul_usb1.c @@ -0,0 +1,539 @@ +/* ul_usb1.c + * Linux CAN-bus device driver. + * Written by Jan Kriz email:johen@post.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + * + * Based on + * USB Skeleton driver - 2.2 + * + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * + * This program 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, version 2. + * + * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c + * but has been rewritten to be easier to read and use. + * + */ + +#include "./can/can.h" +#include "./can/can_sysdep.h" +#include "./can/main.h" +#include "./can/devcommon.h" +#include "./can/setup.h" +// #include "./can/finish.h" +#include "./can/i82527.h" +//#include "../include/sja1000.h" +#include "./can/sja1000p.h" + +#include "./can/errno.h" + +#include "./can/ul_usb1.h" + +/* Get a minor range for your devices from the usb maintainer */ +#define USB_SKEL_MINOR_BASE 192 + +#define CAN_OP_MASK 0x80 +#define CAN_OP_READ 0x80 +#define CAN_OP_WRITE 0x00 + + + /* our private defines. if this grows any larger, use your own .h file */ +#define MAX_TRANSFER (PAGE_SIZE - 512) +/* MAX_TRANSFER is chosen so that the VM is not stressed by + allocations > PAGE_SIZE and the number of packets in a page + is an integer 512 is the largest possible packet on EHCI */ +#define WRITES_IN_FLIGHT 8 +/* arbitrarily chosen */ + +/* Define these values to match your devices */ +#define USB_SKEL_VENDOR_ID 0xDEAD +#define USB_SKEL_PRODUCT_ID 0x1001 + +/* table of devices that work with this driver */ +// static struct usb_device_id ul_usb1_table [] = { +// { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, +// { } /* Terminating entry */ +// }; +// MODULE_DEVICE_TABLE(usb, ul_usb1_table); + +// extern struct file_operations can_fops; + +// struct ul_usb1_combo { +// struct usb_ul_usb1 * dev; +// struct urb * urb; +// }; + +/* + * IO_RANGE is the io-memory range that gets reserved, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + */ +#define IO_RANGE 0x100 + +/** ul_usb1_request_io + * ul_usb1_request_io: - reserve io or memory range for can board + * @candev: pointer to candevice/board which asks for io. Field @io_addr + * of @candev is used in most cases to define start of the range + * + * The function ul_usb1_request_io() is used to reserve the io-memory. If your + * hardware uses a dedicated memory range as hardware control registers you + * will have to add the code to reserve this memory as well. + * %IO_RANGE is the io-memory range that gets reserved, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/ul_usb1.c + */ +int ul_usb1_request_io(struct candevice_t *candev) +{ +// ((struct usb_ul_usb1*)candev->sysdevptr.anydev)->candev=candev; + return 0; +} + +/** ul_usb1_release_io + * ul_usb1_release_io - free reserved io memory range + * @candev: pointer to candevice/board which releases io + * + * The function ul_usb1_release_io() is used to free reserved io-memory. + * In case you have reserved more io memory, don't forget to free it here. + * IO_RANGE is the io-memory range that gets released, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function always returns zero + * File: src/ul_usb1.c + */ +int ul_usb1_release_io(struct candevice_t *candev) +{ +/* struct usb_ul_usb1 *dev; + if (candev->sysdevptr.anydev){ + dev=(struct usb_ul_usb1*) candev->sysdevptr.anydev; + usb_put_dev(dev->udev); + usb_kill_urb(dev->irq); + usb_free_urb(dev->irq); + kfree(dev->bulk_in_buffer); + kfree(dev->int_in_buffer); + if (dev->candev){ + dev->candev->sysdevptr.anydev=NULL; + //cleanup_usbdev(dev->candev); + } + kfree(dev); + }*/ + return 0; +} + +/** ul_usb1_reset + * ul_usb1_reset - hardware reset routine + * @candev: Pointer to candevice/board structure + * + * The function ul_usb1_reset() is used to give a hardware reset. This is + * rather hardware specific so I haven't included example code. Don't forget to + * check the reset status of the chip before returning. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/ul_usb1.c + */ +int ul_usb1_reset(struct candevice_t *candev) +{ + return 0; +} + +#define RESET_ADDR 0x0 +#define NR_82527 0 +#define NR_SJA1000 1 + +/** ul_usb1_init_hw_data + * ul_usb1_init_hw_data - Initialize hardware cards + * @candev: Pointer to candevice/board structure + * + * The function ul_usb1_init_hw_data() is used to initialize the hardware + * structure containing information about the installed CAN-board. + * %RESET_ADDR represents the io-address of the hardware reset register. + * %NR_82527 represents the number of Intel 82527 chips on the board. + * %NR_SJA1000 represents the number of Philips sja1000 chips on the board. + * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that + * the hardware uses programmable interrupts. + * Return Value: The function always returns zero + * File: src/ul_usb1.c + */ +int ul_usb1_init_hw_data(struct candevice_t *candev) +{ + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=NR_SJA1000; + candev->nr_all_chips=NR_82527+NR_SJA1000; + candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0; + + return 0; +} + +/** ul_usb1_init_chip_data + * ul_usb1_init_chip_data - Initialize chips + * @candev: Pointer to candevice/board structure + * @chipnr: Number of the CAN chip on the hardware card + * + * The function ul_usb1_init_chip_data() is used to initialize the hardware + * structure containing information about the CAN chips. + * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or + * "sja1000". + * The @chip_base_addr entry represents the start of the 'official' memory map + * of the installed chip. It's likely that this is the same as the @io_addr + * argument supplied at module loading time. + * The @clock entry holds the chip clock value in Hz. + * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider + * register. Options defined in the %sja1000.h file: + * %sjaCDR_CLKOUT_MASK, %sjaCDR_CLK_OFF, %sjaCDR_RXINPEN, %sjaCDR_CBP, %sjaCDR_PELICAN + * The entry @sja_ocr_reg holds hardware specific options for the Output Control + * register. Options defined in the %sja1000.h file: + * %sjaOCR_MODE_BIPHASE, %sjaOCR_MODE_TEST, %sjaOCR_MODE_NORMAL, %sjaOCR_MODE_CLOCK, + * %sjaOCR_TX0_LH, %sjaOCR_TX1_ZZ. + * The entry @int_clk_reg holds hardware specific options for the Clock Out + * register. Options defined in the %i82527.h file: + * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1. + * The entry @int_bus_reg holds hardware specific options for the Bus + * Configuration register. Options defined in the %i82527.h file: + * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY. + * The entry @int_cpu_reg holds hardware specific options for the cpu interface + * register. Options defined in the %i82527.h file: + * %iCPU_CEN, %iCPU_MUX, %iCPU_SLP, %iCPU_PWD, %iCPU_DMC, %iCPU_DSC, %iCPU_RST. + * Return Value: The function always returns zero + * File: src/ul_usb1.c + */ +int ul_usb1_init_chip_data(struct candevice_t *candev, int chipnr) +{ + /*i82527_fill_chipspecops(candev->chip[chipnr]);*/ + /*sja1000_fill_chipspecops(candev->chip[chipnr]);*/ + sja1000p_fill_chipspecops(candev->chip[chipnr]); + + candev->chip[chipnr]->flags|= CHIP_IRQ_CUSTOM; + + candev->chip[chipnr]->chip_base_addr=0; + candev->chip[chipnr]->clock = 24000000; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | + sjaOCR_TX0_LH; + + candev->chip[chipnr]->chip_data=(void *)malloc(sizeof(struct ul_usb1_chip_data)); + if (candev->chip[chipnr]->chip_data==NULL) + return -ENOMEM; + return 0; +} + +/** ul_usb1_init_obj_data + * ul_usb1_init_obj_data - Initialize message buffers + * @chip: Pointer to chip specific structure + * @objnr: Number of the message buffer + * + * The function ul_usb1_init_obj_data() is used to initialize the hardware + * structure containing information about the different message objects on the + * CAN chip. In case of the sja1000 there's only one message object but on the + * i82527 chip there are 15. + * The code below is for a i82527 chip and initializes the object base addresses + * The entry @obj_base_addr represents the first memory address of the message + * object. In case of the sja1000 @obj_base_addr is taken the same as the chips + * base address. + * Unless the hardware uses a segmented memory map, flags can be set zero. + * Return Value: The function always returns zero + * File: src/ul_usb1.c + */ +int ul_usb1_init_obj_data(struct canchip_t *chip, int objnr) +{ + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10; + + return 0; +} + +/** ul_usb1_program_irq + * ul_usb1_program_irq - program interrupts + * @candev: Pointer to candevice/board structure + * + * The function ul_usb1_program_irq() is used for hardware that uses + * programmable interrupts. If your hardware doesn't use programmable interrupts + * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and + * leave this function unedited. Again this function is hardware specific so + * there's no example code. + * Return value: The function returns zero on success or %-ENODEV on failure + * File: src/ul_usb1.c + */ +int ul_usb1_program_irq(struct candevice_t *candev) +{ + return 0; +} + +/** ul_usb1_write_register + * ul_usb1_write_register - Low level write register routine + * @data: data to be written + * @address: memory address to write to + * + * The function ul_usb1_write_register() is used to write to hardware registers + * on the CAN chip. You should only have to edit this function if your hardware + * uses some specific write process. + * Return Value: The function does not return a value + * File: src/ul_usb1.c + */ +void ul_usb1_write_register(unsigned data, unsigned long address) +{ + can_write(data, address & 0xFF); +} + +/** ul_usb1_read_register + * ul_usb1_read_register - Low level read register routine + * @address: memory address to read from + * + * The function ul_usb1_read_register() is used to read from hardware registers + * on the CAN chip. You should only have to edit this function if your hardware + * uses some specific read process. + * Return Value: The function returns the value stored in @address + * File: src/ul_usb1.c + */ +unsigned ul_usb1_read_register(unsigned long address) +{ + uint8_t data; + data = can_read(address & 0xFF); + return data; +} + +/* !!! Don't change this function !!! */ +int ul_usb1_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = ul_usb1_request_io; + hwspecops->release_io = ul_usb1_release_io; + hwspecops->reset = ul_usb1_reset; + hwspecops->init_hw_data = ul_usb1_init_hw_data; + hwspecops->init_chip_data = ul_usb1_init_chip_data; + hwspecops->init_obj_data = ul_usb1_init_obj_data; + hwspecops->write_register = ul_usb1_write_register; + hwspecops->read_register = ul_usb1_read_register; + hwspecops->program_irq = ul_usb1_program_irq; + return 0; +} + + + + +/* --------------------------------------------------------------------------------------------------- */ + + +// static void ul_usb1_irq(struct urb *urb) +// { +// struct usb_ul_usb1 *dev = urb->context; +// struct ul_usb1_combo devc; +// int retval; +// +// CANMSG("Interrupt poll\n"); +// +// switch (urb->status) { +// case 0: +// /* success */ +// break; +// case -ECONNRESET: +// case -ENOENT: +// case -ESHUTDOWN: +// /* this urb is terminated, clean up */ +// CANMSG("%s - urb shutting down with status: %d\n", __FUNCTION__, urb->status); +// return; +// default: +// CANMSG("%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status); +// goto exit; +// } +// +// devc.dev = dev; +// devc.urb = urb; +// +// dev->candev->chip[0]->chipspecops->irq_handler(0,dev->candev->chip[0]); +// CANMSG("Interrupt caught\n"); +// +// exit: +// retval = usb_submit_urb (urb, GFP_ATOMIC); +// if (retval) +// CANMSG("%s - usb_submit_urb failed with result %d\n", +// __FUNCTION__, retval); +// } + +// static void ul_usb1_delete(struct usb_ul_usb1 *dev) +// { +// usb_put_dev(dev->udev); +// usb_kill_urb(dev->irq); +// usb_free_urb(dev->irq); +// kfree(dev->bulk_in_buffer); +// kfree(dev->int_in_buffer); +// if (dev->candev){ +// dev->candev->sysdevptr.anydev=NULL; +// cleanup_usbdev(dev->candev); +// } +// kfree(dev); +// } + +// static int ul_usb1_probe(struct usb_interface *interface, const struct usb_device_id *id) +// { +// struct usb_ul_usb1 *dev; +// struct usb_host_interface *iface_desc; +// struct usb_endpoint_descriptor *endpoint; +// struct candevice_t *candev; +// size_t buffer_size; +// int i; +// int retval = -ENOMEM; +// +// /* allocate memory for our device state and initialize it */ +// dev = kzalloc(sizeof(*dev), GFP_KERNEL); +// if (!dev) { +// err("Out of memory"); +// goto error; +// } +// sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); +// mutex_init(&dev->io_mutex); +// spin_lock_init(&dev->err_lock); +// init_usb_anchor(&dev->submitted); +// +// // dev->udev = usb_get_dev(interface_to_usbdev(interface)); +// dev->udev = interface_to_usbdev(interface); +// dev->interface = interface; +// +// /* set up the endpoint information */ +// /* use only the first bulk-in and bulk-out endpoints */ +// iface_desc = interface->cur_altsetting; +// for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { +// endpoint = &iface_desc->endpoint[i].desc; +// +// if (!dev->bulk_in_endpointAddr && +// usb_endpoint_is_bulk_in(endpoint)) { +// /* we found a bulk in endpoint */ +// buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); +// dev->bulk_in_size = buffer_size; +// dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; +// dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); +// if (!dev->bulk_in_buffer) { +// err("Could not allocate bulk_in_buffer"); +// goto error; +// } +// } +// +// if (!dev->bulk_out_endpointAddr && +// usb_endpoint_is_bulk_out(endpoint)) { +// /* we found a bulk out endpoint */ +// dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; +// } +// +// if (!dev->int_in_endpointAddr && +// usb_endpoint_is_int_in(endpoint)) { +// /* we found an interrupt in endpoint */ +// buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); +// dev->int_in_size = buffer_size; +// dev->int_in_endpointAddr = endpoint->bEndpointAddress; +// dev->int_in_buffer = kmalloc(buffer_size, GFP_KERNEL); +// dev->int_in_interval = endpoint->bInterval; +// if (!dev->int_in_buffer) { +// err("Could not allocate int_in_buffer"); +// goto error; +// } +// } +// } +// if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr && dev->int_in_endpointAddr)) { +// err("Could not find all bulk-in, bulk-out and interrupt endpoints"); +// goto error; +// } +// +// /* save our data pointer in this interface device */ +// usb_set_intfdata(interface, dev); +// +// if (main_init_done==1) +// register_usbdev("ul_usb1",(void *) dev); +// else { +// mutex_lock(&usbdev_reg_mutex); +// if (main_init_done==1) +// register_usbdev("ul_usb1",(void *) dev); +// else { +// for (i=0;ihwname,"ul_usb1"); +// usbregq[i]->anydev=(void *) dev; +// break; +// } +// } +// if (i==MAX_HW_CARDS){ +// CANMSG("No free space to register new card"); +// mutex_unlock(&usbdev_reg_mutex); +// goto error; +// } +// } +// mutex_unlock(&usbdev_reg_mutex); +// } +// +// dev->irq = usb_alloc_urb(0, GFP_KERNEL); +// if (!dev->irq){ +// CANMSG("Error allocating usb urb\n"); +// goto error; +// } +// dev->irq->dev = dev->udev; +// usb_fill_int_urb(dev->irq, dev->udev, +// usb_rcvintpipe(dev->udev, dev->int_in_endpointAddr), +// dev->int_in_buffer, dev->int_in_size, +// ul_usb1_irq, dev, dev->int_in_interval); +// /* usb_fill_bulk_urb(dev->irq, dev->udev, +// usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), +// dev->int_in_buffer, dev->int_in_size, +// ul_usb1_irq, dev);*/ +// +// /* dev->irq->transfer_dma = wacom->data_dma; +// dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;*/ +// retval=usb_submit_urb(dev->irq, GFP_KERNEL); +// if (retval){ +// CANMSG("INT URB %d\n",retval); +// return -EIO; +// }else +// CANMSG("INT URB SUCCCESS\n"); +// +// /* let the user know what node this device is now attached to */ +// info("USB Skeleton device now attached"); +// return 0; +// +// error: +// ul_usb1_delete(dev); +// return retval; +// } + +// static void ul_usb1_disconnect(struct usb_interface *interface) +// { +// struct usb_ul_usb1 *dev; +// int minor = interface->minor; +// +// dev = usb_get_intfdata(interface); +// usb_set_intfdata(interface, NULL); +// +// /* prevent more I/O from starting */ +// mutex_lock(&dev->io_mutex); +// dev->interface = NULL; +// mutex_unlock(&dev->io_mutex); +// +// //usb_kill_anchored_urbs(&dev->submitted); +// +// ul_usb1_delete(dev); +// +// info("USB Skeleton now disconnected"); +// } + +// static struct usb_driver ul_usb1_driver = { +// .name = "ul_usb1-can", +// .id_table = ul_usb1_table, +// .probe = ul_usb1_probe, +// .disconnect = ul_usb1_disconnect, +// .id_table = ul_usb1_table, +// }; + +// int ul_usb1_init(void){ +// return usb_register(&ul_usb1_driver); +// } +// +// void ul_usb1_exit(void){ +// usb_deregister(&ul_usb1_driver); +// } diff --git a/embedded/app/usbcan/usb/usb_defs.h b/embedded/app/usbcan/usb/usb_defs.h new file mode 100644 index 0000000..adb531c --- /dev/null +++ b/embedded/app/usbcan/usb/usb_defs.h @@ -0,0 +1,321 @@ + +#ifndef USB_DEFS_MODULE + #define USB_DEFS_MODULE + + #include +// #include + #include + #include + #include + + #include + #if __BYTE_ORDER == __BIG_ENDIAN + #include + #define SWAP(x) ((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF)) + #else /*__LITTLE_ENDIAN*/ + #define SWAP(x) (x) + #endif + + #ifndef CODE + #define CODE + #endif + + #ifdef USB_MAX_PACKET + #undef USB_MAX_PACKET + #endif + #define USB_MAX_PACKET 16 + +/*****************************************************/ +/*** Static data structures for device descriptors ***/ +/*****************************************************/ +#ifndef USB_VENDOR_ID + #define USB_VENDOR_ID 0x1669 /* PiKRON.com registered number */ +#endif +#ifndef USB_PRODUCT_ID + #define USB_PRODUCT_ID 0x1011 /* test code for ULAD21 */ +#endif + #define USB_RELEASE_VER 0x0010 + +/*** Class codes for device description ***/ + #define USB_CLASS_CODE 0xFF + #define USB_SUBCLASS_CODE 0x00 + #define USB_PROTOCOL_CODE 0x00 + + + #define NUM_ENDPOINTS 2 + #define CONFIG_DESCRIPTOR_LENGTH sizeof( USB_CONFIGURATION_DESCRIPTOR) \ + + sizeof( USB_INTERFACE_DESCRIPTOR) \ + + ( NUM_ENDPOINTS * sizeof( USB_ENDPOINT_DESCRIPTOR)) + +/*** Device descriptor ***/ + CODE const USB_DEVICE_DESCRIPTOR DeviceDescription = { + sizeof( USB_DEVICE_DESCRIPTOR), + USB_DESCRIPTOR_TYPE_DEVICE, + SWAP( 0x0100), + USB_CLASS_CODE, + USB_SUBCLASS_CODE, + USB_PROTOCOL_CODE, + USB_MAX_PACKET0, + SWAP( USB_VENDOR_ID), + SWAP( USB_PRODUCT_ID), + SWAP( USB_RELEASE_VER), + 1, /* manufacturer string ID */ + 2, /* product string ID */ + 3, /* serial number string ID */ + 1 + }; + +/*** All In Configuration 0 ***/ + CODE const struct { + USB_CONFIGURATION_DESCRIPTOR configuration; + USB_INTERFACE_DESCRIPTOR interface; + USB_ENDPOINT_DESCRIPTOR endpoint_tx; + USB_ENDPOINT_DESCRIPTOR endpoint_rx; + } ConfigDescription = { + /*** Configuration descriptor ***/ + { + sizeof( USB_CONFIGURATION_DESCRIPTOR), + USB_DESCRIPTOR_TYPE_CONFIGURATION, + SWAP( CONFIG_DESCRIPTOR_LENGTH), + 1, /* cnt of interfaces */ + 1, /* this configuration ID */ + 4, /* config.name string ID*/ + 0x80, /* cfg, in spec is, taha bit 7 must be set to one -> 0xe0 , orig 0x60*/ + 0x32 /* device power current from host 100mA */ + }, + /*** Interface Descriptor ***/ + { + sizeof( USB_INTERFACE_DESCRIPTOR), + USB_DESCRIPTOR_TYPE_INTERFACE, + 0, /* index of this interface for SetInterface request */ + 0, /* ID alternate interface */ + NUM_ENDPOINTS, + USB_CLASS_CODE, + USB_SUBCLASS_CODE, + USB_PROTOCOL_CODE, + 5 + }, + /*** Endpoint 1 - Tx,Bulk ***/ + { + sizeof( USB_ENDPOINT_DESCRIPTOR), + USB_DESCRIPTOR_TYPE_ENDPOINT, + 0x01, + USB_ENDPOINT_TYPE_BULK, + SWAP( USB_MAX_PACKET), + 0 + }, + /*** Endpoint 1 - Rx,Bulk ***/ + { + sizeof( USB_ENDPOINT_DESCRIPTOR), + USB_DESCRIPTOR_TYPE_ENDPOINT, + 0x81, + USB_ENDPOINT_TYPE_BULK, + SWAP( USB_MAX_PACKET), + 0 + } + }; + /*** Strings - in unicode ***/ + CODE const char Str0Desc[] = { /* supported languages of strings */ + 4, 0x03, /* 2+2*N , N is count of supported languages */ + 0x09,0x04 /* english 0x0409 */ + }; + + CODE const char Str1Desc[] = { /* 1 = manufacturer */ + 44,0x03, + 'K',0, + 'r',0, + 'i',0, + 'z',0, + ',',0, + 'B',0, + 'a',0, + 'r',0, + 't',0, + 'o',0, + 's',0, + 'i',0, + 'n',0, + 's',0, + 'k',0, + 'i',0, + ',',0, + 'P',0, + 'i',0, + 's',0, + 'a',0 + }; + + CODE const char Str2Desc[] = { /* 2 = product */ + 42, 0x03, + 'C',0, + 'A',0, + 'N',0, + ' ',0, + 't',0, + 'o',0, + ' ',0, + 'U',0, + 'S',0, + 'B',0, + ' ',0, + 'c',0, + 'o',0, + 'n',0, + 'v',0, + 'e',0, + 'r',0, + 't',0, + 'o',0, + 'r',0 + }; + + + CODE const char Str3Desc[] = { /* 3 = version */ + 26, 0x03, + '1',0, + '.',0, + '1',0, + ' ',0, + '0',0, + '8',0, + '-',0, + '1',0, + '1',0, + '-',0, + '2',0, + '3',0 + }; + CODE const char Str4Desc[] = { /* 4 = configuration */ + 34, 0x03, + 'C',0, + 'o',0, + 'n',0, + 'f',0, + 'i',0, + 'g',0, + 'u',0, + 'r',0, + 'a',0, + 't',0, + 'i',0, + 'o',0, + 'n',0, + ' ',0, + '#',0, + '1',0 + }; + CODE const char Str5Desc[] = { /* 5 = interface */ + 38,0x03, + 'I',0, + 'n',0, + 't',0, + 'e',0, + 'r',0, + 'f',0, + 'a',0, + 'c',0, + 'e',0, + ' ',0, + '#',0, + '0',0, + ' ',0, + '-',0, + ' ',0, + 'C',0, + 'A',0, + 'N',0 + }; + + CODE const char Str6Desc[] = { /* EP1 OUT descriptor */ + 48,0x03, + 'E',0, + 'P',0, + '1',0, + 'O',0, + 'U',0, + 'T',0, + '-',0, + 's',0, + 'e',0, + 'n',0, + 'd',0, + ' ',0, + 'C',0, + 'A',0, + 'N',0, + ' ',0, + 'm',0, + 'e',0, + 's',0, + 's',0, + 'a',0, + 'g',0, + 'e',0 + }; + + CODE const char Str7Desc[] = { /* EP1 IN descriptor */ + 52,0x03, + 'E',0, + 'P',0, + '1',0, + 'I',0, + 'N',0, + '-',0, + 'r',0, + 'e',0, + 'c',0, + 'e',0, + 'i',0, + 'v',0, + 'e',0, + ' ',0, + 'C',0, + 'A',0, + 'N',0, + ' ',0, + 'm',0, + 'e',0, + 's',0, + 's',0, + 'a',0, + 'g',0, + 'e',0 + }; + + /* all strings in pointers array */ + CODE const PUSB_STRING_DESCRIPTOR StringDescriptors[] = { + (PUSB_STRING_DESCRIPTOR) Str0Desc, + (PUSB_STRING_DESCRIPTOR) Str1Desc, + (PUSB_STRING_DESCRIPTOR) Str2Desc, + (PUSB_STRING_DESCRIPTOR) Str3Desc, + (PUSB_STRING_DESCRIPTOR) Str4Desc, + (PUSB_STRING_DESCRIPTOR) Str5Desc, + (PUSB_STRING_DESCRIPTOR) Str6Desc, + (PUSB_STRING_DESCRIPTOR) Str7Desc, + }; + + #define CNT_STRINGS (sizeof(StringDescriptors)/sizeof(StringDescriptors[0])) + + CODE const USB_DEVICE_CONFIGURATION_ENTRY usb_devdes_configurations[] = { + { + .pConfigDescription = &ConfigDescription.configuration, + .iConfigTotalLength = CONFIG_DESCRIPTOR_LENGTH + } + }; + + CODE const USB_INTERFACE_DESCRIPTOR *usb_devdes_interfaces[] = { + &ConfigDescription.interface + }; + + CODE const USB_DEVICE_DESCRIPTORS_TABLE usb_devdes_table = { + .pDeviceDescription = &DeviceDescription, + .pConfigurations = usb_devdes_configurations, + .pInterfaceDescriptors = usb_devdes_interfaces, + .pStrings = StringDescriptors, + .iNumStrings = CNT_STRINGS, + .bNumEndpoints = NUM_ENDPOINTS, + .bNumConfigurations = 1, + .bNumInterfaces = 1 + }; + +#endif /* USB_DEFS_MODULE */ diff --git a/embedded/app/usbcan/usb/usb_vend.h b/embedded/app/usbcan/usb/usb_vend.h new file mode 100644 index 0000000..30835d0 --- /dev/null +++ b/embedded/app/usbcan/usb/usb_vend.h @@ -0,0 +1,19 @@ +#ifndef USBCAN_VENDOR +#define USBCAN_VENDOR + +#include + +#define USBCAN_VENDOR_BAUD_RATE_SET (1) +#define USBCAN_VENDOR_BAUD_RATE_STATUS (2) +#define USBCAN_VENDOR_SET_BTREGS (3) +#define USBCAN_VENDOR_CHECK_TX_STAT (4) +#define USBCAN_VENDOR_START_CHIP (5) +#define USBCAN_VENDOR_STOP_CHIP (6) +#define USBCAN_VENDOR_EXT_MASK_SET (7) +#define USBCAN_VENDOR_EXT_MASK_STATUS (8) + +int usbcan_vendor(usb_device_t *udev); + +int set_ext_mask_complete_fnc(struct usb_ep_t *ep, int status); + +#endif /* USBCAN_VENDOR */ diff --git a/embedded/app/usbcan/usb_vend.c b/embedded/app/usbcan/usb_vend.c new file mode 100644 index 0000000..29cd74b --- /dev/null +++ b/embedded/app/usbcan/usb_vend.c @@ -0,0 +1,181 @@ +// #define CAN_DEBUG + +#include +#include +#include +#include "./can/can.h" +#include "./can/can_sysless.h" +#include "./can/main.h" +#include "./can/devcommon.h" +#include "./usb/usb_vend.h" +#include "./can/ul_usb1.h" +#include +#if __BYTE_ORDER == __BIG_ENDIAN + #include +#endif + +extern struct canuser_t *canuser; +extern uint8_t vendor_ret; + +int set_ext_mask_complete_fnc(struct usb_ep_t *ep, int status){ + int dest_chip; + + unsigned long code; + unsigned long mask; + + struct ul_usb1_chip_data *chip_data=NULL; + + usb_device_t *udev=ep->udev; + unsigned char *data=ep->ptr - ep->actual; + + if (udev->request.bRequest==USBCAN_VENDOR_EXT_MASK_SET){ + dest_chip=(udev->request.wIndex); + if ((dest_chip>=MAX_TOT_CHIPS)||(dest_chip<0)) + goto error; + if (!chips_p[dest_chip]) + goto error; + if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL) + goto nodata; + + mask=*(uint32_t *)(data); + code=*(uint32_t *)(data+4); + #if __BYTE_ORDER == __BIG_ENDIAN + mask = bswap_32( mask); + code = bswap_32( code); + #endif + + + if (chips_p[dest_chip]->chipspecops->extended_mask(chips_p[dest_chip], code, mask)<0) + goto error; + chip_data->flags |= UL_USB1_CHIP_MASK_SET; + } + return 0; +error: + chip_data->flags &= ~UL_USB1_CHIP_MASK_SET; +nodata: + return -1; +} + +int set_baud_rate_complete_fnc(struct usb_ep_t *ep, int status){ + int dest_chip; + + int32_t rate,sjw,sampl_pt,flags; + + struct ul_usb1_chip_data *chip_data=NULL; + + usb_device_t *udev=ep->udev; + unsigned char *data=ep->ptr - ep->actual; + + if (udev->request.bRequest==USBCAN_VENDOR_BAUD_RATE_SET){ + dest_chip=(udev->request.wIndex); + if ((dest_chip>=MAX_TOT_CHIPS)||(dest_chip<0)) + goto error; + if (!chips_p[dest_chip]) + goto error; + if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL) + goto nodata; + + rate=*(int32_t *)(data); + sjw=*(int32_t *)(data+4); + sampl_pt=*(int32_t *)(data+8); + flags=*(int32_t *)(data+12); + #if __BYTE_ORDER == __BIG_ENDIAN + rate = bswap_32( rate); + sjw = bswap_32( sjw); + sampl_pt = bswap_32( sampl_pt); + flags = bswap_32( flags); + #endif + + if (chips_p[dest_chip]->chipspecops->baud_rate(chips_p[dest_chip], rate, chips_p[dest_chip]->clock, sjw, sampl_pt, flags)<0) + goto error; + chip_data->flags |= UL_USB1_CHIP_BAUD_SET; + } + return 0; +error: + chip_data->flags &= ~UL_USB1_CHIP_BAUD_SET; +nodata: + return -1; +} + +int usbcan_vendor(usb_device_t *udev) +{ + // wIndex, wValue, bRequest, wLength + int dest_chip; + struct ul_usb1_chip_data *chip_data; + + dest_chip=(udev->request.wIndex); + if ((dest_chip>=MAX_TOT_CHIPS)||(dest_chip<0)) + return -1; // Should look like ok (0) or stall (-1)? + if (!chips_p[dest_chip]) + return -1; // Should look like ok (0) or stall (-1)? + + switch ( udev->request.bRequest) { + case USBCAN_VENDOR_EXT_MASK_SET: + udev->ep0.complete_fnc=set_ext_mask_complete_fnc; + return 1; + case USBCAN_VENDOR_EXT_MASK_STATUS: + vendor_ret=-1; + if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL) + usb_send_control_data(udev,&vendor_ret,1); + else{ + vendor_ret=(chip_data->flags & UL_USB1_CHIP_MASK_SET)?1:0; + usb_send_control_data(udev,&vendor_ret,1); + } + chip_data->flags &= ~UL_USB1_CHIP_MASK_SET; + return 1; + + case USBCAN_VENDOR_BAUD_RATE_SET: + udev->ep0.complete_fnc=set_baud_rate_complete_fnc; + return 1; + case USBCAN_VENDOR_BAUD_RATE_STATUS: + vendor_ret=-1; + if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL) + usb_send_control_data(udev,&vendor_ret,1); + else{ + vendor_ret=(chip_data->flags & UL_USB1_CHIP_BAUD_SET)?1:0; + usb_send_control_data(udev,&vendor_ret,1); + } + chip_data->flags &= ~UL_USB1_CHIP_BAUD_SET; + return 1; + + case USBCAN_VENDOR_SET_BTREGS: + { + uint16_t value=udev->request.wValue; + vendor_ret=1; + if (chips_p[dest_chip]->chipspecops->set_btregs(chips_p[dest_chip],value&0xFF,(value>>8)&0xFF)<0) + vendor_ret=0; + usb_send_control_data(udev,&vendor_ret,1); + } + return 1; + + case USBCAN_VENDOR_CHECK_TX_STAT: + { + struct canque_edge_t *qedge; + struct canque_slot_t *slot; + vendor_ret=0; + if (canque_get_inslot(canuser->qends, &qedge, &slot, 0)>=0){ + canque_abort_inslot(canuser->qends, qedge, slot); + DEBUGMSG("USBCAN_VENDOR_CHECK_TX_STAT - Free slot found\r\n"); + vendor_ret=1; + } + DEBUGMSG("USBCAN_VENDOR_CHECK_TX_STAT - Sending %d\r\n",vendor_ret); + usb_send_control_data(udev,&vendor_ret,1); + return 1; + } + + case USBCAN_VENDOR_START_CHIP: + vendor_ret=1; + if (chips_p[dest_chip]->chipspecops->start_chip(chips_p[dest_chip])<0) + vendor_ret=0; + usb_send_control_data(udev,&vendor_ret,1); + return 1; + case USBCAN_VENDOR_STOP_CHIP: + vendor_ret=1; + if (chips_p[dest_chip]->chipspecops->stop_chip(chips_p[dest_chip])<0) + vendor_ret=0; + usb_send_control_data(udev,&vendor_ret,1); + return 1; + } + + return 0; +} diff --git a/embedded/arch/Makefile b/embedded/arch/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/Makefile.omk b/embedded/arch/Makefile.omk new file mode 100644 index 0000000..974732f --- /dev/null +++ b/embedded/arch/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = generic $(ARCH) diff --git a/embedded/arch/arm/Makefile b/embedded/arch/arm/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/Makefile.omk b/embedded/arch/arm/Makefile.omk new file mode 100644 index 0000000..3f99071 --- /dev/null +++ b/embedded/arch/arm/Makefile.omk @@ -0,0 +1 @@ +SUBDIRS = generic mach-$(MACH) diff --git a/embedded/arch/arm/generic/Makefile b/embedded/arch/arm/generic/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/generic/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/generic/Makefile.omk b/embedded/arch/arm/generic/Makefile.omk new file mode 100644 index 0000000..dba8475 --- /dev/null +++ b/embedded/arch/arm/generic/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = defines libs diff --git a/embedded/arch/arm/generic/defines/Makefile b/embedded/arch/arm/generic/defines/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/generic/defines/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/generic/defines/Makefile.omk b/embedded/arch/arm/generic/defines/Makefile.omk new file mode 100644 index 0000000..702e343 --- /dev/null +++ b/embedded/arch/arm/generic/defines/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +include_HEADERS = $(notdir $(wildcard $(SOURCES_DIR)/*.h)) diff --git a/embedded/arch/arm/generic/defines/cpu_def.h b/embedded/arch/arm/generic/defines/cpu_def.h new file mode 100644 index 0000000..8c7b97d --- /dev/null +++ b/embedded/arch/arm/generic/defines/cpu_def.h @@ -0,0 +1,262 @@ +#ifndef _ARM_CPU_DEF_H +#define _ARM_CPU_DEF_H + +#ifndef CODE + #define CODE +#endif + +#ifndef XDATA + #define XDATA +#endif + +#ifndef DATA + #define DATA +#endif + +struct pt_regs { + long uregs[18]; +}; + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + +struct undef_hook { + struct undef_hook *next; + unsigned long instr_mask; + unsigned long instr_val; + unsigned long cpsr_mask; + unsigned long cpsr_val; + int (*fn)(struct pt_regs *regs, unsigned int instr); +}; + +int register_undef_hook(struct undef_hook *hook); + +#define NR_IRQS 256 + +typedef struct irq_handler { + void (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; + struct irq_handler *next; + short vectno; +} irq_handler_t; + +#define IRQH_ON_LIST 0x100 /* handler is used */ + +extern irq_handler_t *irq_array[NR_IRQS]; +extern void *irq_vec[NR_IRQS]; + +int add_irq_handler(int vectno,irq_handler_t *handler); + +int del_irq_handler(int vectno,irq_handler_t *handler); + +int test_irq_handler(int vectno,const irq_handler_t *handler); + +void irq_redirect2vector(int vectno,struct pt_regs *regs); + +/* IRQ handling code */ + +#define sti() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ sti\n" \ +" bic %0, %0, #128\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +#define cli() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ cli\n" \ +" orr %0, %0, #128\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +#define save_and_cli(flags) \ + ({ \ + unsigned long temp; \ + (void) (&temp == &flags); \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ save_and_cli\n" \ +" orr %1, %0, #128\n" \ +" msr cpsr_c, %1" \ + : "=r" (flags), "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +#define save_flags(flags) \ + ({ \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ save_flags\n" \ + : "=r" (flags) \ + : \ + : "memory", "cc"); \ + }) + +#define restore_flags(flags) \ + __asm__ __volatile__( \ + "msr cpsr_c, %0 @ restore_flags\n" \ + : \ + : "r" (flags) \ + : "memory", "cc") + + +/* FIQ handling code */ + +#define fiq_sti() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ sti\n" \ +" bic %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +#define fiq_cli() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ cli\n" \ +" orr %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +#define fiq_save_and_cli(flags) \ + ({ \ + unsigned long temp; \ + (void) (&temp == &flags); \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ save_and_cli\n" \ +" orr %1, %0, #192\n" \ +" msr cpsr_c, %1" \ + : "=r" (flags), "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +void __cpu_coherent_range(unsigned long start, unsigned long end); + +static inline void flush_icache_range(unsigned long start, unsigned long end) +{ + __cpu_coherent_range(start, end); +} + +/* atomic access routines */ + +//typedef unsigned long atomic_t; + +static inline void atomic_clear_mask(unsigned long mask, volatile unsigned long *addr) +{ + unsigned long flags; + + save_and_cli(flags); + *addr &= ~mask; + restore_flags(flags); +} + +static inline void atomic_set_mask(unsigned long mask, volatile unsigned long *addr) +{ + unsigned long flags; + + save_and_cli(flags); + *addr |= mask; + restore_flags(flags); +} + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long flags; + + save_and_cli(flags); + *addr |= 1< + +//-------------------------------------------------------------------------- +// Static data used by HAL +// ISR tables +extern uint32_t hal_interrupt_handlers[HAL_ISR_COUNT]; +extern uint32_t hal_interrupt_data[HAL_ISR_COUNT]; + +//-------------------------------------------------------------------------- +// Default ISR +// The #define is used to test whether this routine exists, and to allow +// code outside the HAL to call it. + +typedef void (*hal_isr)(int vector, uint32_t data); //function ptr +extern uint32_t hal_default_isr(int vector, uint32_t data); +#define HAL_DEFAULT_ISR hal_default_isr + +//-------------------------------------------------------------------------- +// Vector translation. + +#ifndef HAL_TRANSLATE_VECTOR +#define HAL_TRANSLATE_VECTOR(_vector_,_index_) \ + (_index_) = (_vector_) +#endif + +//-------------------------------------------------------------------------- +// Interrupt and VSR attachment macros + +#define HAL_INTERRUPT_IN_USE( _vector_, _state_) \ + { \ + uint32_t _index_; \ + HAL_TRANSLATE_VECTOR ((_vector_), _index_); \ + \ + if( hal_interrupt_handlers[_index_] == (uint32_t)hal_default_isr ) \ + (_state_) = 0; \ + else \ + (_state_) = 1; \ + } + +#define HAL_INTERRUPT_ATTACH( _vector_, _isr_, _data_) \ + { \ + if( hal_interrupt_handlers[_vector_] == (uint32_t)hal_default_isr ) \ + { \ + hal_interrupt_handlers[_vector_] = (uint32_t)_isr_; \ + hal_interrupt_data[_vector_] = (uint32_t) _data_; \ + } \ + } + +#define HAL_INTERRUPT_DETACH( _vector_, _isr_ ) \ + { \ + if( hal_interrupt_handlers[_vector_] == (uint32_t)_isr_ ) \ + { \ + hal_interrupt_handlers[_vector_] = (uint32_t)hal_default_isr; \ + hal_interrupt_data[_vector_] = 0; \ + } \ + } + + +//-------------------------------------------------------------------------- +// Interrupt controller access + +extern void hal_interrupt_mask(int); +extern void hal_interrupt_unmask(int); +extern void hal_interrupt_acknowledge(int); +extern void hal_interrupt_configure(int, int, int); +extern void hal_interrupt_set_level(int, int); + +#define HAL_INTERRUPT_MASK( _vector_ ) \ + hal_interrupt_mask( _vector_ ) +#define HAL_INTERRUPT_UNMASK( _vector_ ) \ + hal_interrupt_unmask( _vector_ ) +#define HAL_INTERRUPT_ACKNOWLEDGE( _vector_ ) \ + hal_interrupt_acknowledge( _vector_ ) +#define HAL_INTERRUPT_CONFIGURE( _vector_, _level_, _up_ ) \ + hal_interrupt_configure( _vector_, _level_, _up_ ) +#define HAL_INTERRUPT_SET_LEVEL( _vector_, _level_ ) \ + hal_interrupt_set_level( _vector_, _level_ ) + +#endif /* HAL_DEFAULT_ISR */ diff --git a/embedded/arch/arm/generic/defines/types.h b/embedded/arch/arm/generic/defines/types.h new file mode 100644 index 0000000..e5d5a57 --- /dev/null +++ b/embedded/arch/arm/generic/defines/types.h @@ -0,0 +1,77 @@ +#ifndef __ASM_ARM_TYPES_H +#define __ASM_ARM_TYPES_H + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#endif /* __ASSEMBLY__ */ + +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ + +typedef __u8 uint8_t; +typedef __s8 int8_t; +typedef __u16 uint16_t; +typedef __s16 int16_t; +typedef __u32 uint32_t; +typedef __s32 int32_t; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __s64 int64_t; +typedef __u64 uint64_t; +#endif + +#endif /* !(__BIT_TYPES_DEFINED__) */ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#define BITS_PER_LONG 32 + +#ifndef __ASSEMBLY__ + +typedef __s8 s8; +typedef __u8 u8; + +typedef __s16 s16; +typedef __u16 u16; + +typedef __s32 s32; +typedef __u32 u32; + +typedef __s64 s64; +typedef __s64 u64; + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; +typedef u32 dma64_addr_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif + diff --git a/embedded/arch/arm/generic/libs/Makefile b/embedded/arch/arm/generic/libs/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/generic/libs/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/generic/libs/Makefile.omk b/embedded/arch/arm/generic/libs/Makefile.omk new file mode 100644 index 0000000..d833bce --- /dev/null +++ b/embedded/arch/arm/generic/libs/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = misc diff --git a/embedded/arch/arm/generic/libs/misc/Makefile b/embedded/arch/arm/generic/libs/misc/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/generic/libs/misc/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/generic/libs/misc/Makefile.omk b/embedded/arch/arm/generic/libs/misc/Makefile.omk new file mode 100644 index 0000000..b94858c --- /dev/null +++ b/embedded/arch/arm/generic/libs/misc/Makefile.omk @@ -0,0 +1,9 @@ +# -*- makefile -*- + +include_HEADERS = system_stub.h + +lib_LIBRARIES = arch + +arch_SOURCES = system_stub.c + +lib_obj_SOURCES = system_stub.c diff --git a/embedded/arch/arm/generic/libs/misc/system_stub.c b/embedded/arch/arm/generic/libs/misc/system_stub.c new file mode 100644 index 0000000..31a8f66 --- /dev/null +++ b/embedded/arch/arm/generic/libs/misc/system_stub.c @@ -0,0 +1,259 @@ +/* Support files for GNU libc. Files in the system namespace go here. + Files in the C namespace (ie those that do not start with an + underscore) go in .c. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register name faking - works in collusion with the linker. */ +register char * stack_ptr asm ("sp"); + +system_stub_ops_t system_stub_ops; + +int +_read (int file, + char * ptr, + int len) +{ + if(!system_stub_ops.read) + return -1; + return system_stub_ops.read(file,ptr,len); +} + +int +_write (int file, + const char * ptr, + int len) +{ + if(!system_stub_ops.write) + return len; + return system_stub_ops.write(file,ptr,len); +} + + +int +_lseek (int file, + int pos, + int dir) +{ + if(!system_stub_ops.lseek) + return -1; + return system_stub_ops.lseek(file,pos,dir); +} + +int +_open (const char * path, + int flags, + ...) +{ + if(!system_stub_ops.open) + return -1; + return system_stub_ops.open(path,flags,0); +} + +int +_close (int file) +{ + if(!system_stub_ops.close) + return -1; + return system_stub_ops.close(file); +} + +typedef int (local_call_t)(void); + +void +_exit (int n) +{ + ((local_call_t*)0)(); + while(1); +} + +void abort(void) +{ + ((local_call_t*)0)(); + while(1); +} + +int +_kill (int n, int m) +{ + return -1; +} + +int +_getpid (void) +{ + return 1; +} + + +void * +_sbrk (ptrdiff_t incr) +{ + extern char end asm ("end"); /* Defined by the linker. */ + static char *heap_end; + char * prev_heap_end; + + incr=(incr+3) & ~3; + + if (heap_end == NULL) + heap_end = & end; + + prev_heap_end = heap_end; + + if (heap_end + incr > stack_ptr) + { + /* Some of the libstdc++-v3 tests rely upon detecting + out of memory errors, so do not abort here. */ +#if 0 + extern void abort (void); + + _write (1, "_sbrk: Heap and stack collision\n", 32); + + abort (); +#else + errno = ENOMEM; + return (caddr_t) -1; +#endif + } + + heap_end += incr; + + return /*(caddr_t)*/ prev_heap_end; +} + +int +_fstat (int file, struct stat * st) +{ + return -1; +} + +int _stat (const char *fname, struct stat *st) +{ + return -1; +} + +int +_link (const char *path1, const char *path2 ) +{ + return -1; +} + +int +_unlink (const char *path) +{ + return -1; +} + +void +_raise (void) +{ + return; +} + +int +_gettimeofday (struct timeval * tp, struct timezone * tzp) +{ + + if(tp) + { + tp->tv_sec = 0; + tp->tv_usec = 0; + } + /* Return fixed data for the timezone. */ + if (tzp) + { + tzp->tz_minuteswest = 0; + tzp->tz_dsttime = 0; + } + + return 0; +} + +/* Return a clock that ticks at 100Hz. */ +clock_t +_times (struct tms * tp) +{ + clock_t timeval = 0; + + if (tp) + { + tp->tms_utime = timeval; /* user time */ + tp->tms_stime = 0; /* system time */ + tp->tms_cutime = 0; /* user time, children */ + tp->tms_cstime = 0; /* system time, children */ + } + + return timeval; +}; + + +int +isatty (int fd) +{ + return 1; +} + +int +_system (const char *s) +{ + return -1; +} + +int +_rename (const char * oldpath, const char * newpath) +{ + return -1; +} + +/* extern (.*) ([^ ]*) _PARAMS \(\(struct _reent \*(,*)(.*)\)\); */ +/* \1 \2 (struct _reent *\3\4) { return \2(\4);} */ + +struct _reent; + +int _close_r(struct _reent * reent, int file) + { return _close(file);} +/* +int _fcntl_r(struct _reent *, int, int, int) + { return _fcntl( int, int, int);} +*/ +int _fstat_r(struct _reent * reent, int file, struct stat * st) + { return _fstat(file, st);} + +int _getpid_r(struct _reent * reent) + { return _getpid();} + +int _kill_r(struct _reent * reent, int n, int m) + { return _kill(n, m);} + +int _link_r(struct _reent * reent, const char *path1, const char *path2) + { return _link(path1, path2);} + +_off_t _lseek_r(struct _reent * reent, int file, _off_t pos, int dir) + { return _lseek(file, pos, dir);} + +int _open_r(struct _reent * reent, const char * path, int flags, int opts) + { return _open(path, flags, opts);} + +_ssize_t _read_r(struct _reent * reent, int file, void * ptr, size_t len) + { return _read(file, ptr, len);} + +void *_sbrk_r(struct _reent * reent, ptrdiff_t incr) + { return _sbrk(incr);} + +int _stat_r(struct _reent * reent, const char * path, struct stat * st) + { return _stat(path, st);} + +int _unlink_r(struct _reent * reent, const char * path) + { return _unlink(path);} + +_ssize_t _write_r(struct _reent * reent, int file, const void * ptr, size_t len) + { return _write(file, ptr, len);} diff --git a/embedded/arch/arm/generic/libs/misc/system_stub.h b/embedded/arch/arm/generic/libs/misc/system_stub.h new file mode 100644 index 0000000..d697635 --- /dev/null +++ b/embedded/arch/arm/generic/libs/misc/system_stub.h @@ -0,0 +1,16 @@ +#ifndef _SYSTEM_STUB_H_ +#define _SYSTEM_STUB_H_ + +#include + +typedef struct system_stub_ops_t { + int (*open)(const char * path, int flags, ...); + int (*close)(int file); + int (*read)(int file, char * ptr, int len); + int (*write)(int file, const char * ptr, int len); + int (*lseek)(int file, int ptr, int dir); +} system_stub_ops_t; + +extern system_stub_ops_t system_stub_ops; + +#endif /* _SYSTEM_DEF_H_ */ diff --git a/embedded/arch/arm/generic/libs/misc/undef_support.c b/embedded/arch/arm/generic/libs/misc/undef_support.c new file mode 100644 index 0000000..a51b708 --- /dev/null +++ b/embedded/arch/arm/generic/libs/misc/undef_support.c @@ -0,0 +1,55 @@ +#include +#include + +static int undef_initialized = 0; + +static unsigned long cpu_undef_stack[256]; + +struct undef_hook *undef_hook_chain = NULL; + +static void undef_exception_handler(int excptnum, struct pt_regs *regs) +{ + /*unsigned int correction = thumb_mode(regs) ? 2 : 4;*/ + unsigned int correction = 0; + struct undef_hook *hook; + void *pc; + unsigned long instr; + + regs->ARM_pc -= correction; + + pc = (void *)regs->ARM_pc; + + instr = *(unsigned long *)pc; + + for(hook = undef_hook_chain; hook; hook = hook->next) { + if (((instr & hook->instr_mask) == hook->instr_val) && + ((regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val)) { + if (hook->fn(regs, instr) == 0) { + return; + } + } + } + + for(;;){ + /* Fatal error */ + } +} + +int register_undef_hook(struct undef_hook *hook) +{ + unsigned long flags; + + save_and_cli(flags); + + if(!undef_initialized) { + set_cpu_exception_handler(ARM_EXCEPTION_UNDEF, (long)undef_exception_handler); + set_cpu_exception_stack(ARM_EXCEPTION_UNDEF, (long)((char*)cpu_undef_stack+sizeof(cpu_undef_stack)-8)); + undef_initialized = 1; + } + + hook->next = undef_hook_chain; + undef_hook_chain = hook; + restore_flags(flags); + + return 0; +} diff --git a/embedded/arch/arm/mach-lpc21xx/Makefile b/embedded/arch/arm/mach-lpc21xx/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/mach-lpc21xx/Makefile.omk b/embedded/arch/arm/mach-lpc21xx/Makefile.omk new file mode 100644 index 0000000..2ebd5c8 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/Makefile.omk @@ -0,0 +1 @@ +SUBDIRS = defines libs diff --git a/embedded/arch/arm/mach-lpc21xx/defines/LPC210x.h b/embedded/arch/arm/mach-lpc21xx/defines/LPC210x.h new file mode 100644 index 0000000..1e4e2f4 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/LPC210x.h @@ -0,0 +1,6 @@ +#ifndef INC_LPC210x_H +#define INC_LPC210x_H + +#include "LPC21xx.h" + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/LPC214x.h b/embedded/arch/arm/mach-lpc21xx/defines/LPC214x.h new file mode 100644 index 0000000..d6a95d4 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/LPC214x.h @@ -0,0 +1,165 @@ +/****************************************************************************** + * + * $RCSfile: LPC214x.h,v $ + * $Revision: 1.4 $ + * + * Header file for Philips LPC214x ARM Processors + * Copyright 2006 Pavel Pisa + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact or GPL license is applied. + * + *****************************************************************************/ + +#ifndef INC_LPC214x_H +#define INC_LPC214x_H + +/////////////////////////////////////////////////////////////////////////////// +// ISP_RAM2FLASH_BLOCK_SIZE for 210x CPU +#ifndef ISP_RAM2FLASH_BLOCK_SIZE + #define ISP_RAM2FLASH_BLOCK_SIZE 256 +#endif /* ISP_RAM2FLASH_BLOCK_SIZE */ + +#include "LPC21xx.h" + +#include "lpcUSB.h" +#include "lpcADC-214x.h" + +// USB Phase Locked Loop Registers (PLL48) +#define PLLCON48 SCB->pll48.con /* Control Register */ +#define PLLCFG48 SCB->pll48.cfg /* Configuration Register */ +#define PLLSTAT48 SCB->pll48.stat /* Status Register */ +#define PLLFEED48 SCB->pll48.feed /* Feed Register */ + +/////////////////////////////////////////////////////////////////////////////// +// USB Device + +#define USBIntSt (*(REG32*)0xE01FC1C0) /* USB Interrupt Status (R/W) */ + +#if 1 + +#define USB ((usbRegs_t *)0xE0090000) + +#define USBDevIntSt USB->DevIntSt +#define USBDevIntEn USB->DevIntEn +#define USBDevIntClr USB->DevIntClr +#define USBDevIntSet USB->DevIntSet +#define USBDevIntPri USB->DevIntPri +#define USBEpIntSt USB->EpIntSt +#define USBEpIntEn USB->EpIntEn +#define USBEpIntClr USB->EpIntClr +#define USBEpIntSet USB->EpIntSet +#define USBEpIntPri USB->EpIntPri +#define USBReEp USB->ReEp +#define USBEpInd USB->EpInd +#define USBMaxPSize USB->MaxPSize +#define USBRxData USB->RxData +#define USBRxPLen USB->RxPLen +#define USBTxData USB->TxData +#define USBTxPLen USB->TxPLen +#define USBCtrl USB->Ctrl +#define USBCmdCode USB->CmdCode +#define USBCmdData USB->CmdData +#define USBDMARSt USB->DMARSt +#define USBDMARClr USB->DMARClr +#define USBDMARSet USB->DMARSet +#define USBUDCAH USB->UDCAH +#define USBEpDMASt USB->EpDMASt +#define USBEpDMAEn USB->EpDMAEn +#define USBEpDMADis USB->EpDMADis +#define USBDMAIntSt USB->DMAIntSt +#define USBDMAIntEn USB->DMAIntEn +#define USBEoTIntSt USB->EoTIntSt +#define USBEoTIntClr USB->EoTIntClr +#define USBEoTIntSet USB->EoTIntSet +#define USBNDDRIntSt USB->NDDRIntSt +#define USBNDDRIntClr USB->NDDRIntClr +#define USBNDDRIntSet USB->NDDRIntSet +#define USBSysErrIntSt USB->SysErrIntSt +#define USBSysErrIntClr USB->SysErrIntClr +#define USBSysErrIntSet USB->SysErrIntSet +#define USB_MODULE_ID USB->MODULE_ID +# else + +#define USB_REGS_BASE 0xE0090000 + +#define USBDevIntSt (*(REG32*)(USB_REGS_BASE+USBDevIntSt_o)) +#define USBDevIntEn (*(REG32*)(USB_REGS_BASE+USBDevIntEn_o)) +#define USBDevIntClr (*(REG32*)(USB_REGS_BASE+USBDevIntClr_o)) +#define USBDevIntSet (*(REG32*)(USB_REGS_BASE+USBDevIntSet_o)) +#define USBDevIntPri (*(REG_8*)(USB_REGS_BASE+USBDevIntPri_o)) +#define USBEpIntSt (*(REG32*)(USB_REGS_BASE+USBEpIntSt_o)) +#define USBEpIntEn (*(REG32*)(USB_REGS_BASE+USBEpIntEn_o)) +#define USBEpIntClr (*(REG32*)(USB_REGS_BASE+USBEpIntClr_o)) +#define USBEpIntSet (*(REG32*)(USB_REGS_BASE+USBEpIntSet_o)) +#define USBEpIntPri (*(REG32*)(USB_REGS_BASE+USBEpIntPri_o)) +#define USBReEp (*(REG32*)(USB_REGS_BASE+USBReEp_o)) +#define USBEpInd (*(REG32*)(USB_REGS_BASE+USBEpInd_o)) +#define USBMaxPSize (*(REG32*)(USB_REGS_BASE+USBMaxPSize_o)) +#define USBRxData (*(REG32*)(USB_REGS_BASE+USBRxData_o)) +#define USBRxPLen (*(REG32*)(USB_REGS_BASE+USBRxPLen_o)) +#define USBTxData (*(REG32*)(USB_REGS_BASE+USBTxData_o)) +#define USBTxPLen (*(REG32*)(USB_REGS_BASE+USBTxPLen_o)) +#define USBCtrl (*(REG32*)(USB_REGS_BASE+USBCtrl_o)) +#define USBCmdCode (*(REG32*)(USB_REGS_BASE+USBCmdCode_o)) +#define USBCmdData (*(REG32*)(USB_REGS_BASE+USBCmdData_o)) +#define USBDMARSt (*(REG32*)(USB_REGS_BASE+USBDMARSt_o)) +#define USBDMARClr (*(REG32*)(USB_REGS_BASE+USBDMARClr_o)) +#define USBDMARSet (*(REG32*)(USB_REGS_BASE+USBDMARSet_o)) +#define USBUDCAH (*(REG32*)(USB_REGS_BASE+USBUDCAH_o)) +#define USBEpDMASt (*(REG32*)(USB_REGS_BASE+USBEpDMASt_o)) +#define USBEpDMAEn (*(REG32*)(USB_REGS_BASE+USBEpDMAEn_o)) +#define USBEpDMADis (*(REG32*)(USB_REGS_BASE+USBEpDMADis_o)) +#define USBDMAIntSt (*(REG32*)(USB_REGS_BASE+USBDMAIntSt_o)) +#define USBDMAIntEn (*(REG32*)(USB_REGS_BASE+USBDMAIntEn_o)) +#define USBEoTIntSt (*(REG32*)(USB_REGS_BASE+USBEoTIntSt_o)) +#define USBEoTIntClr (*(REG32*)(USB_REGS_BASE+USBEoTIntClr_o)) +#define USBEoTIntSet (*(REG32*)(USB_REGS_BASE+USBEoTIntSet_o)) +#define USBNDDRIntSt (*(REG32*)(USB_REGS_BASE+USBNDDRIntSt_o)) +#define USBNDDRIntClr (*(REG32*)(USB_REGS_BASE+USBNDDRIntClr_o)) +#define USBNDDRIntSet (*(REG32*)(USB_REGS_BASE+USBNDDRIntSet_o)) +#define USBSysErrIntSt (*(REG32*)(USB_REGS_BASE+USBSysErrIntSt_o)) +#define USBSysErrIntClr (*(REG32*)(USB_REGS_BASE+USBSysErrIntClr_o)) +#define USBSysErrIntSet (*(REG32*)(USB_REGS_BASE+USBSysErrIntSet_o)) +#define USB_MODULE_ID (*(REG32*)(USB_REGS_BASE+USB_MODULE_ID_o)) + +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// A/D Converter +#define ADC0 ((adc214xRegs_t *)0xE0034000) + +#define AD0CR ADC0->cr // Control Register +#define AD0GDR ADC0->gdr // Global Data Register +#define AD0GSR ADC0->gsr // Global Start Register +#define AD0INTEN ADC0->inten // Interrupt Enable Register +#define AD0DR0 ADC0->dr0 // Channel 0 Data Register +#define AD0DR1 ADC0->dr1 // Channel 1 Data Register +#define AD0DR2 ADC0->dr2 // Channel 2 Data Register +#define AD0DR3 ADC0->dr3 // Channel 3 Data Register +#define AD0DR4 ADC0->dr4 // Channel 4 Data Register +#define AD0DR5 ADC0->dr5 // Channel 5 Data Register +#define AD0DR6 ADC0->dr6 // Channel 6 Data Register +#define AD0DR7 ADC0->dr7 // Channel 7 Data Register +#define AD0STAT ADC0->stat // Status Register + +#define ADC1 ((adc214xRegs_t *)0xE0060000) + +#define AD1CR ADC0->cr // Control Register +#define AD1GDR ADC0->gdr // Global Data Register +#define AD1GSR ADC0->gsr // Global Start Register +#define AD1INTEN ADC0->inten // Interrupt Enable Register +#define AD1DR0 ADC0->dr0 // Channel 0 Data Register +#define AD1DR1 ADC0->dr1 // Channel 1 Data Register +#define AD1DR2 ADC0->dr2 // Channel 2 Data Register +#define AD1DR3 ADC0->dr3 // Channel 3 Data Register +#define AD1DR4 ADC0->dr4 // Channel 4 Data Register +#define AD1DR5 ADC0->dr5 // Channel 5 Data Register +#define AD1DR6 ADC0->dr6 // Channel 6 Data Register +#define AD1DR7 ADC0->dr7 // Channel 7 Data Register +#define AD1STAT ADC0->stat // Status Register + + +#endif /*INC_LPC21xx_H*/ diff --git a/embedded/arch/arm/mach-lpc21xx/defines/LPC21xx.h b/embedded/arch/arm/mach-lpc21xx/defines/LPC21xx.h new file mode 100644 index 0000000..c9d06c8 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/LPC21xx.h @@ -0,0 +1,333 @@ +/****************************************************************************** + * + * $RCSfile: LPC21xx.h,v $ + * $Revision: 1.3 $ + * + * Header file for Philips LPC21xx ARM Processors + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC21xx_H +#define INC_LPC21xx_H + +#define REG_8 volatile unsigned char +#define REG16 volatile unsigned short +#define REG32 volatile unsigned long + +#include "lpcWD.h" +#include "lpcTMR.h" +#include "lpcUART.h" +#include "lpcI2C.h" +#include "lpcSPI.h" +#include "lpcRTC.h" +#include "lpcGPIO.h" +#include "lpcPIN.h" +#include "lpcADC.h" +#include "lpcSCB.h" +#include "lpcVIC.h" + +/////////////////////////////////////////////////////////////////////////////// +// Keyval +#define KVPB_CHUNK_SIZE 16 + +/////////////////////////////////////////////////////////////////////////////// +// ISP_RAM2FLASH_BLOCK_SIZE for CPU - minimal is 512, can be smaller for some CPU +#ifndef ISP_RAM2FLASH_BLOCK_SIZE + #define ISP_RAM2FLASH_BLOCK_SIZE 512 +#endif /* ISP_RAM2FLASH_BLOCK_SIZE */ + +/////////////////////////////////////////////////////////////////////////////// +// Watchdog +#define WD ((wdRegs_t *)0xE0000000) + +// Watchdog Registers +#define WDMOD WD->mod /* Watchdog Mode Register */ +#define WDTC WD->tc /* Watchdog Time Constant Register */ +#define WDFEED WD->feed /* Watchdog Feed Register */ +#define WDTV WD->tv /* Watchdog Time Value Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Timer 0 +#define TMR0 ((pwmTmrRegs_t *)0xE0004000) + +// Timer 0 Registers +#define T0IR TMR0->ir /* Interrupt Register */ +#define T0TCR TMR0->tcr /* Timer Control Register */ +#define T0TC TMR0->tc /* Timer Counter */ +#define T0PR TMR0->pr /* Prescale Register */ +#define T0PC TMR0->pc /* Prescale Counter Register */ +#define T0MCR TMR0->mcr /* Match Control Register */ +#define T0MR0 TMR0->mr0 /* Match Register 0 */ +#define T0MR1 TMR0->mr1 /* Match Register 1 */ +#define T0MR2 TMR0->mr2 /* Match Register 2 */ +#define T0MR3 TMR0->mr3 /* Match Register 3 */ +#define T0CCR TMR0->ccr /* Capture Control Register */ +#define T0CR0 TMR0->cr0 /* Capture Register 0 */ +#define T0CR1 TMR0->cr1 /* Capture Register 1 */ +#define T0CR2 TMR0->cr2 /* Capture Register 2 */ +#define T0CR3 TMR0->cr3 /* Capture Register 3 */ +#define T0EMR TMR0->emr /* External Match Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Timer 1 +#define TMR1 ((pwmTmrRegs_t *)0xE0008000) + +// Timer 1 Registers +#define T1IR TMR1->ir /* Interrupt Register */ +#define T1TCR TMR1->tcr /* Timer Control Register */ +#define T1TC TMR1->tc /* Timer Counter */ +#define T1PR TMR1->pr /* Prescale Register */ +#define T1PC TMR1->pc /* Prescale Counter Register */ +#define T1MCR TMR1->mcr /* Match Control Register */ +#define T1MR0 TMR1->mr0 /* Match Register 0 */ +#define T1MR1 TMR1->mr1 /* Match Register 1 */ +#define T1MR2 TMR1->mr2 /* Match Register 2 */ +#define T1MR3 TMR1->mr3 /* Match Register 3 */ +#define T1CCR TMR1->ccr /* Capture Control Register */ +#define T1CR0 TMR1->cr0 /* Capture Register 0 */ +#define T1CR1 TMR1->cr1 /* Capture Register 1 */ +#define T1CR2 TMR1->cr2 /* Capture Register 2 */ +#define T1CR3 TMR1->cr3 /* Capture Register 3 */ +#define T1EMR TMR1->emr /* External Match Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Pulse Width Modulator (PWM) +#define PWM ((pwmTmrRegs_t *)0xE0014000) + +// PWM Registers +#define PWMIR PWM->ir /* Interrupt Register */ +#define PWMTCR PWM->tcr /* Timer Control Register */ +#define PWMTC PWM->tc /* Timer Counter */ +#define PWMPR PWM->pr /* Prescale Register */ +#define PWMPC PWM->pc /* Prescale Counter Register */ +#define PWMMCR PWM->mcr /* Match Control Register */ +#define PWMMR0 PWM->mr0 /* Match Register 0 */ +#define PWMMR1 PWM->mr1 /* Match Register 1 */ +#define PWMMR2 PWM->mr2 /* Match Register 2 */ +#define PWMMR3 PWM->mr3 /* Match Register 3 */ +#define PWMMR4 PWM->mr4 /* Match Register 4 */ +#define PWMMR5 PWM->mr5 /* Match Register 5 */ +#define PWMMR6 PWM->mr6 /* Match Register 6 */ +#define PWMPCR PWM->pcr /* Control Register */ +#define PWMLER PWM->ler /* Latch Enable Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Universal Asynchronous Receiver Transmitter 0 (UART0) +#define UART0 ((uartRegs_t *)0xE000C000) +#define U0_PINSEL (0x00000005) /* PINSEL0 Value for UART0 */ +#define U0_PINMASK (0x0000000F) /* PINSEL0 Mask for UART0 */ + +// UART0 Registers +#define U0RBR UART0->rbr /* Receive Buffer Register */ +#define U0THR UART0->thr /* Transmit Holding Register */ +#define U0IER UART0->ier /* Interrupt Enable Register */ +#define U0IIR UART0->iir /* Interrupt ID Register */ +#define U0FCR UART0->fcr /* FIFO Control Register */ +#define U0LCR UART0->lcr /* Line Control Register */ +#define U0LSR UART0->lsr /* Line Status Register */ +#define U0SCR UART0->scr /* Scratch Pad Register */ +#define U0DLL UART0->dll /* Divisor Latch Register (LSB) */ +#define U0DLM UART0->dlm /* Divisor Latch Register (MSB) */ + +/////////////////////////////////////////////////////////////////////////////// +// Universal Asynchronous Receiver Transmitter 1 (UART1) +#define UART1 ((uartRegs_t *)0xE0010000) +#define U1_PINSEL (0x00050000) /* PINSEL0 Value for UART1 */ +#define U1_PINMASK (0x000F0000) /* PINSEL0 Mask for UART1 */ + +// UART1 Registers +#define U1RBR UART1->rbr /* Receive Buffer Register */ +#define U1THR UART1->thr /* Transmit Holding Register */ +#define U1IER UART1->ier /* Interrupt Enable Register */ +#define U1IIR UART1->iir /* Interrupt ID Register */ +#define U1FCR UART1->fcr /* FIFO Control Register */ +#define U1LCR UART1->lcr /* Line Control Register */ +#define U1MCR UART1->mcr /* MODEM Control Register */ +#define U1LSR UART1->lsr /* Line Status Register */ +#define U1MSR UART1->msr /* MODEM Status Register */ +#define U1SCR UART1->scr /* Scratch Pad Register */ +#define U1DLL UART1->dll /* Divisor Latch Register (LSB) */ +#define U1DLM UART1->dlm /* Divisor Latch Register (MSB) */ + +/////////////////////////////////////////////////////////////////////////////// +// I2C Interface +#define I2C ((i2cRegs_t *)0xE001C000) + +// I2C Registers +#define I2CONSET I2C->conset /* Control Set Register */ +#define I2STAT I2C->stat /* Status Register */ +#define I2DAT I2C->dat /* Data Register */ +#define I2ADR I2C->adr /* Slave Address Register */ +#define I2SCLH I2C->sclh /* SCL Duty Cycle Register (high half word) */ +#define I2SCLL I2C->scll /* SCL Duty Cycle Register (low half word) */ +#define I2CONCLR I2C->conclr /* Control Clear Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Serial Peripheral Interface 0 (SPI0) +#define SPI0 ((spiRegs_t *)0xE0020000) + +// SPI0 Registers +#define S0SPCR SPI0->cr /* Control Register */ +#define S0SPSR SPI0->sr /* Status Register */ +#define S0SPDR SPI0->dr /* Data Register */ +#define S0SPCCR SPI0->ccr /* Clock Counter Register */ +#define S0SPINT SPI0->flag /* Interrupt Flag Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Serial Peripheral Interface 1 (SPI1) +#define SPI1 ((spiRegs_t *)0xE0030000) + +// SPI1 Registers +#define S1SPCR SPI1->cr /* Control Register */ +#define S1SPSR SPI1->sr /* Status Register */ +#define S1SPDR SPI1->dr /* Data Register */ +#define S1SPCCR SPI1->ccr /* Clock Counter Register */ +#define S1SPINT SPI1->flag /* Interrupt Flag Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Real Time Clock +#define RTC ((rtcRegs_t *)0xE0024000) + +// RTC Registers +#define RTCILR RTC->ilr /* Interrupt Location Register */ +#define RTCCTC RTC->ctc /* Clock Tick Counter */ +#define RTCCCR RTC->ccr /* Clock Control Register */ +#define RTCCIIR RTC->ciir /* Counter Increment Interrupt Register */ +#define RTCAMR RTC->amr /* Alarm Mask Register */ +#define RTCCTIME0 RTC->ctime0 /* Consolidated Time Register 0 */ +#define RTCCTIME1 RTC->ctime1 /* Consolidated Time Register 1 */ +#define RTCCTIME2 RTC->ctime2 /* Consolidated Time Register 2 */ +#define RTCSEC RTC->sec /* Seconds Register */ +#define RTCMIN RTC->min /* Minutes Register */ +#define RTCHOUR RTC->hour /* Hours Register */ +#define RTCDOM RTC->dom /* Day Of Month Register */ +#define RTCDOW RTC->dow /* Day Of Week Register */ +#define RTCDOY RTC->doy /* Day Of Year Register */ +#define RTCMONTH RTC->month /* Months Register */ +#define RTCYEAR RTC->year /* Years Register */ +#define RTCALSEC RTC->alsec /* Alarm Seconds Register */ +#define RTCALMIN RTC->almin /* Alarm Minutes Register */ +#define RTCALHOUR RTC->alhour /* Alarm Hours Register */ +#define RTCALDOM RTC->aldom /* Alarm Day Of Month Register */ +#define RTCALDOW RTC->aldow /* Alarm Day Of Week Register */ +#define RTCALDOY RTC->aldoy /* Alarm Day Of Year Register */ +#define RTCALMON RTC->almon /* Alarm Months Register */ +#define RTCALYEAR RTC->alyear /* Alarm Years Register */ +#define RTCPREINT RTC->preint /* Prescale Value Register (integer) */ +#define RTCPREFRAC RTC->prefrac /* Prescale Value Register (fraction) */ + +/////////////////////////////////////////////////////////////////////////////// +// General Purpose Input/Output +#define GPIO ((gpioRegs_t *)0xE0028000) + +// GPIO Registers +#define IO0PIN GPIO->in0 /* P0 Pin Value Register */ +#define IO0SET GPIO->set0 /* P0 Pin Output Set Register */ +#define IO0DIR GPIO->dir0 /* P0 Pin Direction Register */ +#define IO0CLR GPIO->clr0 /* P0 Pin Output Clear Register */ +#define IO1PIN GPIO->in1 /* P1 Pin Value Register */ +#define IO1SET GPIO->set1 /* P1 Pin Output Set Register */ +#define IO1DIR GPIO->dir1 /* P1 Pin Direction Register */ +#define IO1CLR GPIO->clr1 /* P1 Pin Output Clear Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Pin Connect Block +#define PINSEL ((pinRegs_t *)0xE002C000) + +// Pin Connect Block Registers +#define PINSEL0 PINSEL->sel0 /* Pin Function Select Register 0 */ +#define PINSEL1 PINSEL->sel1 /* Pin Function Select Register 1 */ +#define PINSEL2 PINSEL->sel2 /* Pin Function Select Register 2 */ + +/////////////////////////////////////////////////////////////////////////////// +// A/D Converter +#define ADC ((adcRegs_t *)0xE0034000) + +// A/D Converter Registers +#define ADCR ADC->cr /* Control Register */ +#define ADDR ADC->dr /* Data Register */ + +/////////////////////////////////////////////////////////////////////////////// +// System Contol Block +#define SCB ((scbRegs_t *)0xE01FC000) + +// Memory Accelerator Module Registers (MAM) +#define MAMCR SCB->mam.cr /* Control Register */ +#define MAMTIM SCB->mam.tim /* Timing Control Register */ + +// Memory Mapping Control Register +#define MEMMAP SCB->memmap + +// Phase Locked Loop Registers (PLL) +#define PLLCON SCB->pll.con /* Control Register */ +#define PLLCFG SCB->pll.cfg /* Configuration Register */ +#define PLLSTAT SCB->pll.stat /* Status Register */ +#define PLLFEED SCB->pll.feed /* Feed Register */ + +// Power Control Registers +#define PCON SCB->p.con /* Control Register */ +#define PCONP SCB->p.conp /* Peripherals Register */ + +// VPB Divider Register +#define VPBDIV SCB->vpbdiv + +// External Interrupt Registers +#define EXTINT SCB->ext.flag /* Flag Register */ +#define EXTWAKE SCB->ext.wake /* Wakeup Register */ +#define EXTMODE SCB->ext.mode /* Mode Register */ +#define EXTPOLAR SCB->ext.polar /* Polarity Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Vectored Interrupt Controller +#define VIC ((vicRegs_t *)0xFFFFF000) + +// Vectored Interrupt Controller Registers +#define VICIRQStatus VIC->irqStatus /* IRQ Status Register */ +#define VICFIQStatus VIC->fiqStatus /* FIQ Status Register */ +#define VICRawIntr VIC->rawIntr /* Raw Interrupt Status Register */ +#define VICIntSelect VIC->intSelect /* Interrupt Select Register */ +#define VICIntEnable VIC->intEnable /* Interrupt Enable Register */ +#define VICIntEnClear VIC->intEnClear /* Interrupt Enable Clear Register */ +#define VICSoftInt VIC->softInt /* Software Interrupt Register */ +#define VICSoftIntClear VIC->softIntClear /* Software Interrupt Clear Register */ +#define VICProtection VIC->protection /* Protection Enable Register */ +#define VICVectAddr VIC->vectAddr /* Vector Address Register */ +#define VICDefVectAddr VIC->defVectAddr /* Default Vector Address Register */ +#define VICVectAddr0 VIC->vectAddr0 /* Vector Address 0 Register */ +#define VICVectAddr1 VIC->vectAddr1 /* Vector Address 1 Register */ +#define VICVectAddr2 VIC->vectAddr2 /* Vector Address 2 Register */ +#define VICVectAddr3 VIC->vectAddr3 /* Vector Address 3 Register */ +#define VICVectAddr4 VIC->vectAddr4 /* Vector Address 4 Register */ +#define VICVectAddr5 VIC->vectAddr5 /* Vector Address 5 Register */ +#define VICVectAddr6 VIC->vectAddr6 /* Vector Address 6 Register */ +#define VICVectAddr7 VIC->vectAddr7 /* Vector Address 7 Register */ +#define VICVectAddr8 VIC->vectAddr8 /* Vector Address 8 Register */ +#define VICVectAddr9 VIC->vectAddr9 /* Vector Address 9 Register */ +#define VICVectAddr10 VIC->vectAddr10 /* Vector Address 10 Register */ +#define VICVectAddr11 VIC->vectAddr11 /* Vector Address 11 Register */ +#define VICVectAddr12 VIC->vectAddr12 /* Vector Address 12 Register */ +#define VICVectAddr13 VIC->vectAddr13 /* Vector Address 13 Register */ +#define VICVectAddr14 VIC->vectAddr14 /* Vector Address 14 Register */ +#define VICVectAddr15 VIC->vectAddr15 /* Vector Address 15 Register */ +#define VICVectCntl0 VIC->vectCntl0 /* Vector Control 0 Register */ +#define VICVectCntl1 VIC->vectCntl1 /* Vector Control 1 Register */ +#define VICVectCntl2 VIC->vectCntl2 /* Vector Control 2 Register */ +#define VICVectCntl3 VIC->vectCntl3 /* Vector Control 3 Register */ +#define VICVectCntl4 VIC->vectCntl4 /* Vector Control 4 Register */ +#define VICVectCntl5 VIC->vectCntl5 /* Vector Control 5 Register */ +#define VICVectCntl6 VIC->vectCntl6 /* Vector Control 6 Register */ +#define VICVectCntl7 VIC->vectCntl7 /* Vector Control 7 Register */ +#define VICVectCntl8 VIC->vectCntl8 /* Vector Control 8 Register */ +#define VICVectCntl9 VIC->vectCntl9 /* Vector Control 9 Register */ +#define VICVectCntl10 VIC->vectCntl10 /* Vector Control 10 Register */ +#define VICVectCntl11 VIC->vectCntl11 /* Vector Control 11 Register */ +#define VICVectCntl12 VIC->vectCntl12 /* Vector Control 12 Register */ +#define VICVectCntl13 VIC->vectCntl13 /* Vector Control 13 Register */ +#define VICVectCntl14 VIC->vectCntl14 /* Vector Control 14 Register */ +#define VICVectCntl15 VIC->vectCntl15 /* Vector Control 15 Register */ + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/LPC22xx.h b/embedded/arch/arm/mach-lpc21xx/defines/LPC22xx.h new file mode 100644 index 0000000..c2d30e0 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/LPC22xx.h @@ -0,0 +1,342 @@ +/****************************************************************************** + * + * $RCSfile: LPC22xx.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC22xx ARM Processors + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC22xx_H +#define INC_LPC22xx_H + +#define REG_8 volatile unsigned char +#define REG16 volatile unsigned short +#define REG32 volatile unsigned long + +#include "lpcWD.h" +#include "lpcTMR.h" +#include "lpcUART.h" +#include "lpcI2C.h" +#include "lpcSPI.h" +#include "lpcRTC.h" +#include "lpcGPIO.h" +#include "lpcPIN.h" +#include "lpcADC.h" +#include "lpcSCB.h" +#include "lpcEMC.h" +#include "lpcVIC.h" + +/////////////////////////////////////////////////////////////////////////////// +// Watchdog +#define WD ((wdRegs_t *)0xE0000000) + +// Watchdog Registers +#define WDMOD WD->mod /* Watchdog Mode Register */ +#define WDTC WD->tc /* Watchdog Time Constant Register */ +#define WDFEED WD->feed /* Watchdog Feed Register */ +#define WDTV WD->tv /* Watchdog Time Value Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Timer 0 +#define TMR0 ((pwmTmrRegs_t *)0xE0004000) + +// Timer 0 Registers +#define T0IR TMR0->ir /* Interrupt Register */ +#define T0TCR TMR0->tcr /* Timer Control Register */ +#define T0TC TMR0->tc /* Timer Counter */ +#define T0PR TMR0->pr /* Prescale Register */ +#define T0PC TMR0->pc /* Prescale Counter Register */ +#define T0MCR TMR0->mcr /* Match Control Register */ +#define T0MR0 TMR0->mr0 /* Match Register 0 */ +#define T0MR1 TMR0->mr1 /* Match Register 1 */ +#define T0MR2 TMR0->mr2 /* Match Register 2 */ +#define T0MR3 TMR0->mr3 /* Match Register 3 */ +#define T0CCR TMR0->ccr /* Capture Control Register */ +#define T0CR0 TMR0->cr0 /* Capture Register 0 */ +#define T0CR1 TMR0->cr1 /* Capture Register 1 */ +#define T0CR2 TMR0->cr2 /* Capture Register 2 */ +#define T0CR3 TMR0->cr3 /* Capture Register 3 */ +#define T0EMR TMR0->emr /* External Match Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Timer 1 +#define TMR1 ((pwmTmrRegs_t *)0xE0008000) + +// Timer 1 Registers +#define T1IR TMR1->ir /* Interrupt Register */ +#define T1TCR TMR1->tcr /* Timer Control Register */ +#define T1TC TMR1->tc /* Timer Counter */ +#define T1PR TMR1->pr /* Prescale Register */ +#define T1PC TMR1->pc /* Prescale Counter Register */ +#define T1MCR TMR1->mcr /* Match Control Register */ +#define T1MR0 TMR1->mr0 /* Match Register 0 */ +#define T1MR1 TMR1->mr1 /* Match Register 1 */ +#define T1MR2 TMR1->mr2 /* Match Register 2 */ +#define T1MR3 TMR1->mr3 /* Match Register 3 */ +#define T1CCR TMR1->ccr /* Capture Control Register */ +#define T1CR0 TMR1->cr0 /* Capture Register 0 */ +#define T1CR1 TMR1->cr1 /* Capture Register 1 */ +#define T1CR2 TMR1->cr2 /* Capture Register 2 */ +#define T1CR3 TMR1->cr3 /* Capture Register 3 */ +#define T1EMR TMR1->emr /* External Match Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Pulse Width Modulator (PWM) +#define PWM ((pwmTmrRegs_t *)0xE0014000) + +// PWM Registers +#define PWMIR PWM->ir /* Interrupt Register */ +#define PWMTCR PWM->tcr /* Timer Control Register */ +#define PWMTC PWM->tc /* Timer Counter */ +#define PWMPR PWM->pr /* Prescale Register */ +#define PWMPC PWM->pc /* Prescale Counter Register */ +#define PWMMCR PWM->mcr /* Match Control Register */ +#define PWMMR0 PWM->mr0 /* Match Register 0 */ +#define PWMMR1 PWM->mr1 /* Match Register 1 */ +#define PWMMR2 PWM->mr2 /* Match Register 2 */ +#define PWMMR3 PWM->mr3 /* Match Register 3 */ +#define PWMMR4 PWM->mr4 /* Match Register 4 */ +#define PWMMR5 PWM->mr5 /* Match Register 5 */ +#define PWMMR6 PWM->mr6 /* Match Register 6 */ +#define PWMPCR PWM->pcr /* Control Register */ +#define PWMLER PWM->ler /* Latch Enable Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Universal Asynchronous Receiver Transmitter 0 (UART0) +#define UART0 ((uartRegs_t *)0xE000C000) +#define U0_PINSEL (0x00000005) /* PINSEL0 Value for UART0 */ +#define U0_PINMASK (0x0000000F) /* PINSEL0 Mask for UART0 */ + +// UART0 Registers +#define U0RBR UART0->rbr /* Receive Buffer Register */ +#define U0THR UART0->thr /* Transmit Holding Register */ +#define U0IER UART0->ier /* Interrupt Enable Register */ +#define U0IIR UART0->iir /* Interrupt ID Register */ +#define U0FCR UART0->fcr /* FIFO Control Register */ +#define U0LCR UART0->lcr /* Line Control Register */ +#define U0LSR UART0->lsr /* Line Status Register */ +#define U0SCR UART0->scr /* Scratch Pad Register */ +#define U0DLL UART0->dll /* Divisor Latch Register (LSB) */ +#define U0DLM UART0->dlm /* Divisor Latch Register (MSB) */ + +/////////////////////////////////////////////////////////////////////////////// +// Universal Asynchronous Receiver Transmitter 1 (UART1) +#define UART1 ((uartRegs_t *)0xE0010000) +#define U1_PINSEL (0x00050000) /* PINSEL0 Value for UART1 */ +#define U1_PINMASK (0x000F0000) /* PINSEL0 Mask for UART1 */ + +// UART1 Registers +#define U1RBR UART1->rbr /* Receive Buffer Register */ +#define U1THR UART1->thr /* Transmit Holding Register */ +#define U1IER UART1->ier /* Interrupt Enable Register */ +#define U1IIR UART1->iir /* Interrupt ID Register */ +#define U1FCR UART1->fcr /* FIFO Control Register */ +#define U1LCR UART1->lcr /* Line Control Register */ +#define U1MCR UART1->mcr /* MODEM Control Register */ +#define U1LSR UART1->lsr /* Line Status Register */ +#define U1MSR UART1->msr /* MODEM Status Register */ +#define U1SCR UART1->scr /* Scratch Pad Register */ +#define U1DLL UART1->dll /* Divisor Latch Register (LSB) */ +#define U1DLM UART1->dlm /* Divisor Latch Register (MSB) */ + +/////////////////////////////////////////////////////////////////////////////// +// I2C Interface +#define I2C ((i2cRegs_t *)0xE001C000) + +// I2C Registers +#define I2CONSET I2C->conset /* Control Set Register */ +#define I2STAT I2C->stat /* Status Register */ +#define I2DAT I2C->dat /* Data Register */ +#define I2ADR I2C->adr /* Slave Address Register */ +#define I2SCLH I2C->sclh /* SCL Duty Cycle Register (high half word) */ +#define I2SCLL I2C->scll /* SCL Duty Cycle Register (low half word) */ +#define I2CONCLR I2C->conclr /* Control Clear Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Serial Peripheral Interface 0 (SPI0) +#define SPI0 ((spiRegs_t *)0xE0020000) + +// SPI0 Registers +#define S0SPCR SPI0->cr /* Control Register */ +#define S0SPSR SPI0->sr /* Status Register */ +#define S0SPDR SPI0->dr /* Data Register */ +#define S0SPCCR SPI0->ccr /* Clock Counter Register */ +#define S0SPINT SPI0->flag /* Interrupt Flag Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Serial Peripheral Interface 1 (SPI1) +#define SPI1 ((spiRegs_t *)0xE0030000) + +// SPI1 Registers +#define S1SPCR SPI1->cr /* Control Register */ +#define S1SPSR SPI1->sr /* Status Register */ +#define S1SPDR SPI1->dr /* Data Register */ +#define S1SPCCR SPI1->ccr /* Clock Counter Register */ +#define S1SPINT SPI1->flag /* Interrupt Flag Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Real Time Clock +#define RTC ((rtcRegs_t *)0xE0024000) + +// RTC Registers +#define RTCILR RTC->ilr /* Interrupt Location Register */ +#define RTCCTC RTC->ctc /* Clock Tick Counter */ +#define RTCCCR RTC->ccr /* Clock Control Register */ +#define RTCCIIR RTC->ciir /* Counter Increment Interrupt Register */ +#define RTCAMR RTC->amr /* Alarm Mask Register */ +#define RTCCTIME0 RTC->ctime0 /* Consolidated Time Register 0 */ +#define RTCCTIME1 RTC->ctime1 /* Consolidated Time Register 1 */ +#define RTCCTIME2 RTC->ctime2 /* Consolidated Time Register 2 */ +#define RTCSEC RTC->sec /* Seconds Register */ +#define RTCMIN RTC->min /* Minutes Register */ +#define RTCHOUR RTC->hour /* Hours Register */ +#define RTCDOM RTC->dom /* Day Of Month Register */ +#define RTCDOW RTC->dow /* Day Of Week Register */ +#define RTCDOY RTC->doy /* Day Of Year Register */ +#define RTCMONTH RTC->month /* Months Register */ +#define RTCYEAR RTC->year /* Years Register */ +#define RTCALSEC RTC->alsec /* Alarm Seconds Register */ +#define RTCALMIN RTC->almin /* Alarm Minutes Register */ +#define RTCALHOUR RTC->alhour /* Alarm Hours Register */ +#define RTCALDOM RTC->aldom /* Alarm Day Of Month Register */ +#define RTCALDOW RTC->aldow /* Alarm Day Of Week Register */ +#define RTCALDOY RTC->aldoy /* Alarm Day Of Year Register */ +#define RTCALMON RTC->almon /* Alarm Months Register */ +#define RTCALYEAR RTC->alyear /* Alarm Years Register */ +#define RTCPREINT RTC->preint /* Prescale Value Register (integer) */ +#define RTCPREFRAC RTC->prefrac /* Prescale Value Register (fraction) */ + +/////////////////////////////////////////////////////////////////////////////// +// General Purpose Input/Output +#define GPIO ((gpioRegs_t *)0xE0028000) + +// GPIO Registers +#define IO0PIN GPIO->in0 /* P0 Pin Value Register */ +#define IO0SET GPIO->set0 /* P0 Pin Output Set Register */ +#define IO0DIR GPIO->dir0 /* P0 Pin Direction Register */ +#define IO0CLR GPIO->clr0 /* P0 Pin Output Clear Register */ +#define IO1PIN GPIO->in1 /* P1 Pin Value Register */ +#define IO1SET GPIO->set1 /* P1 Pin Output Set Register */ +#define IO1DIR GPIO->dir1 /* P1 Pin Direction Register */ +#define IO1CLR GPIO->clr1 /* P1 Pin Output Clear Register */ +#define IO2PIN GPIO->in2 /* P2 Pin Value Register */ +#define IO2SET GPIO->set2 /* P2 Pin Output Set Register */ +#define IO2DIR GPIO->dir2 /* P2 Pin Direction Register */ +#define IO2CLR GPIO->clr2 /* P2 Pin Output Clear Register */ +#define IO3PIN GPIO->in3 /* P3 Pin Value Register */ +#define IO3SET GPIO->set3 /* P3 Pin Output Set Register */ +#define IO3DIR GPIO->dir3 /* P3 Pin Direction Register */ +#define IO3CLR GPIO->clr3 /* P3 Pin Output Clear Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Pin Connect Block +#define PINSEL ((pinRegs_t *)0xE002C000) + +// Pin Connect Block Registers +#define PINSEL0 PINSEL->sel0 /* Pin Function Select Register 0 */ +#define PINSEL1 PINSEL->sel1 /* Pin Function Select Register 1 */ +#define PINSEL2 PINSEL->sel2 /* Pin Function Select Register 2 */ + +/////////////////////////////////////////////////////////////////////////////// +// A/D Converter +#define ADC ((adcRegs_t *)0xE0034000) + +// A/D Converter Registers +#define ADCR ADC->cr /* Control Register */ +#define ADDR ADC->dr /* Data Register */ + +/////////////////////////////////////////////////////////////////////////////// +// System Contol Block +#define SCB ((scbRegs_t *)0xE01FC000) + +// Memory Accelerator Module Registers (MAM) +#define MAMCR SCB->mam.cr /* Control Register */ +#define MAMTIM SCB->mam.tim /* Timing Control Register */ + +// Memory Mapping Control Register +#define MEMMAP SCB->memmap + +// Phase Locked Loop Registers (PLL) +#define PLLCON SCB->pll.con /* Control Register */ +#define PLLCFG SCB->pll.cfg /* Configuration Register */ +#define PLLSTAT SCB->pll.stat /* Status Register */ +#define PLLFEED SCB->pll.feed /* Feed Register */ + +// Power Control Registers +#define PCON SCB->p.con /* Control Register */ +#define PCONP SCB->p.conp /* Peripherals Register */ + +// VPB Divider Register +#define VPBDIV SCB->vpbdiv + +// External Interrupt Registers +#define EXTINT SCB->ext.flag /* Flag Register */ +#define EXTWAKE SCB->ext.wake /* Wakeup Register */ +#define EXTMODE SCB->ext.mode /* Mode Register */ +#define EXTPOLAR SCB->ext.polar /* Polarity Register */ + +/////////////////////////////////////////////////////////////////////////////// +// External Memory Controller (EMC) +#define EMC ((volatile emcRegs_t *)0xFFE00000) + +// External Memory Controller Registers +#define BCFG0 EMC->bcfg0 /* Bank 0 Configuration Register */ +#define BCFG1 EMC->bcfg1 /* Bank 1 Configuration Register */ +#define BCFG2 EMC->bcfg2 /* Bank 2 Configuration Register */ +#define BCFG3 EMC->bcfg3 /* Bank 3 Configuration Register */ + +/////////////////////////////////////////////////////////////////////////////// +// Vectored Interrupt Controller +#define VIC ((vicRegs_t *)0xFFFFF000) + +// Vectored Interrupt Controller Registers +#define VICIRQStatus VIC->irqStatus /* IRQ Status Register */ +#define VICFIQStatus VIC->fiqStatus /* FIQ Status Register */ +#define VICRawIntr VIC->rawIntr /* Raw Interrupt Status Register */ +#define VICIntSelect VIC->intSelect /* Interrupt Select Register */ +#define VICIntEnable VIC->intEnable /* Interrupt Enable Register */ +#define VICIntEnClear VIC->intEnClear /* Interrupt Enable Clear Register */ +#define VICSoftInt VIC->softInt /* Software Interrupt Register */ +#define VICSoftIntClear VIC->softIntClear /* Software Interrupt Clear Register */ +#define VICProtection VIC->protection /* Protection Enable Register */ +#define VICVectAddr VIC->vectAddr /* Vector Address Register */ +#define VICDefVectAddr VIC->defVectAddr /* Default Vector Address Register */ +#define VICVectAddr0 VIC->vectAddr0 /* Vector Address 0 Register */ +#define VICVectAddr1 VIC->vectAddr1 /* Vector Address 1 Register */ +#define VICVectAddr2 VIC->vectAddr2 /* Vector Address 2 Register */ +#define VICVectAddr3 VIC->vectAddr3 /* Vector Address 3 Register */ +#define VICVectAddr4 VIC->vectAddr4 /* Vector Address 4 Register */ +#define VICVectAddr5 VIC->vectAddr5 /* Vector Address 5 Register */ +#define VICVectAddr6 VIC->vectAddr6 /* Vector Address 6 Register */ +#define VICVectAddr7 VIC->vectAddr7 /* Vector Address 7 Register */ +#define VICVectAddr8 VIC->vectAddr8 /* Vector Address 8 Register */ +#define VICVectAddr9 VIC->vectAddr9 /* Vector Address 9 Register */ +#define VICVectAddr10 VIC->vectAddr10 /* Vector Address 10 Register */ +#define VICVectAddr11 VIC->vectAddr11 /* Vector Address 11 Register */ +#define VICVectAddr12 VIC->vectAddr12 /* Vector Address 12 Register */ +#define VICVectAddr13 VIC->vectAddr13 /* Vector Address 13 Register */ +#define VICVectAddr14 VIC->vectAddr14 /* Vector Address 14 Register */ +#define VICVectAddr15 VIC->vectAddr15 /* Vector Address 15 Register */ +#define VICVectCntl0 VIC->vectCntl0 /* Vector Control 0 Register */ +#define VICVectCntl1 VIC->vectCntl1 /* Vector Control 1 Register */ +#define VICVectCntl2 VIC->vectCntl2 /* Vector Control 2 Register */ +#define VICVectCntl3 VIC->vectCntl3 /* Vector Control 3 Register */ +#define VICVectCntl4 VIC->vectCntl4 /* Vector Control 4 Register */ +#define VICVectCntl5 VIC->vectCntl5 /* Vector Control 5 Register */ +#define VICVectCntl6 VIC->vectCntl6 /* Vector Control 6 Register */ +#define VICVectCntl7 VIC->vectCntl7 /* Vector Control 7 Register */ +#define VICVectCntl8 VIC->vectCntl8 /* Vector Control 8 Register */ +#define VICVectCntl9 VIC->vectCntl9 /* Vector Control 9 Register */ +#define VICVectCntl10 VIC->vectCntl10 /* Vector Control 10 Register */ +#define VICVectCntl11 VIC->vectCntl11 /* Vector Control 11 Register */ +#define VICVectCntl12 VIC->vectCntl12 /* Vector Control 12 Register */ +#define VICVectCntl13 VIC->vectCntl13 /* Vector Control 13 Register */ +#define VICVectCntl14 VIC->vectCntl14 /* Vector Control 14 Register */ +#define VICVectCntl15 VIC->vectCntl15 /* Vector Control 15 Register */ + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/Makefile b/embedded/arch/arm/mach-lpc21xx/defines/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/mach-lpc21xx/defines/Makefile.omk b/embedded/arch/arm/mach-lpc21xx/defines/Makefile.omk new file mode 100644 index 0000000..176b8a6 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/Makefile.omk @@ -0,0 +1,2 @@ +# -*- makefile -*- +include_HEADERS = $(notdir $(wildcard $(SOURCES_DIR)/*.h)) diff --git a/embedded/arch/arm/mach-lpc21xx/defines/armVIC.h b/embedded/arch/arm/mach-lpc21xx/defines/armVIC.h new file mode 100644 index 0000000..560a6b4 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/armVIC.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * + * $RCSfile: armVIC.h,v $ + * $Revision: 1.1 $ + * + * This module provides the interface definitions for setting up and + * controlling the various interrupt modes present on the ARM processor. + * Copyright 2004, R O SoftWare + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_ARM_VIC_H +#define INC_ARM_VIC_H + +/****************************************************************************** + * + * MACRO Name: ISR_ENTRY() + * + * Description: + * This MACRO is used upon entry to an ISR. The current version of + * the gcc compiler for ARM does not produce correct code for + * interrupt routines to operate properly with THUMB code. The MACRO + * performs the following steps: + * + * 1 - Adjust address at which execution should resume after servicing + * ISR to compensate for IRQ entry + * 2 - Save the non-banked registers r0-r12 and lr onto the IRQ stack. + * 3 - Get the status of the interrupted program is in SPSR. + * 4 - Push it onto the IRQ stack as well. + * + *****************************************************************************/ +#define ISR_ENTRY() asm volatile(" sub lr, lr,#4\n" \ + " stmfd sp!,{r0-r12,lr}\n" \ + " mrs r1, spsr\n" \ + " stmfd sp!,{r1}") + +/****************************************************************************** + * + * MACRO Name: ISR_EXIT() + * + * Description: + * This MACRO is used to exit an ISR. The current version of the gcc + * compiler for ARM does not produce correct code for interrupt + * routines to operate properly with THUMB code. The MACRO performs + * the following steps: + * + * 1 - Recover SPSR value from stack + * 2 - and restore its value + * 3 - Pop the return address & the saved general registers from + * the IRQ stack & return + * + *****************************************************************************/ +#define ISR_EXIT() asm volatile(" ldmfd sp!,{r1}\n" \ + " msr spsr_c,r1\n" \ + " ldmfd sp!,{r0-r12,pc}^") + +/****************************************************************************** + * + * Function Name: disableIRQ() + * + * Description: + * This function sets the IRQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned disableIRQ(void); + +/****************************************************************************** + * + * Function Name: enableIRQ() + * + * Description: + * This function clears the IRQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned enableIRQ(void); + +/****************************************************************************** + * + * Function Name: restoreIRQ() + * + * Description: + * This function restores the IRQ disable bit in the status register + * to the value contained within passed oldCPSR + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned restoreIRQ(unsigned oldCPSR); + +/****************************************************************************** + * + * Function Name: disableFIQ() + * + * Description: + * This function sets the FIQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned disableFIQ(void); + +/****************************************************************************** + * + * Function Name: enableFIQ() + * + * Description: + * This function clears the FIQ disable bit in the status register + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned enableFIQ(void); + +/****************************************************************************** + * + * Function Name: restoreIRQ() + * + * Description: + * This function restores the FIQ disable bit in the status register + * to the value contained within passed oldCPSR + * + * Calling Sequence: + * void + * + * Returns: + * previous value of CPSR + * + *****************************************************************************/ +unsigned restoreFIQ(unsigned oldCPSR); + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcADC-214x.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcADC-214x.h new file mode 100644 index 0000000..7e66dae --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcADC-214x.h @@ -0,0 +1,74 @@ +#ifndef INC_LPC_ADC_214x_H +#define INC_LPC_ADC_214x_H + +// A/D Converter Registers +typedef struct +{ + REG32 cr; // Control Register + REG32 gdr; // Global Data Register + REG32 gsr; // Global Start Register + REG32 inten; // Interrupt Enable Register + REG32 dr0; // Channel 0 Data Register + REG32 dr1; // Channel 1 Data Register + REG32 dr2; // Channel 2 Data Register + REG32 dr3; // Channel 3 Data Register + REG32 dr4; // Channel 4 Data Register + REG32 dr5; // Channel 5 Data Register + REG32 dr6; // Channel 6 Data Register + REG32 dr7; // Channel 7 Data Register + REG32 stat; // Status Register +} adc214xRegs_t; + +#define ADCR_SEL 0x000000FF +#define ADCR_CLKDIV 0x0000FF00 +#define ADCR_BURST 0x00010000 +#define ADCR_CLKS 0x000E0000 +#define ADCR_PDN 0x00200000 +#define ADCR_START 0x07000000 +#define ADCR_EDGE 0x08000000 + +#define ADGDR_RESULT 0x0000FFC0 +#define ADGDR_CHN 0x07000000 +#define ADGDR_OVERRUN 0x40000000 +#define ADGDR_DONE 0x80000000 + +#define ADGSR_BURST 0x00010000 +#define ADGSR_START 0x07000000 +#define ADGSR_EDGE 0x08000000 + +#define ADSTAT_DONE 0x000000FF +#define ADSTAT_DONE0 0x00000001 +#define ADSTAT_DONE1 0x00000002 +#define ADSTAT_DONE2 0x00000004 +#define ADSTAT_DONE3 0x00000008 +#define ADSTAT_DONE4 0x00000010 +#define ADSTAT_DONE5 0x00000020 +#define ADSTAT_DONE6 0x00000040 +#define ADSTAT_DONE7 0x00000080 +#define ADSTAT_OVERRUN 0x0000FF00 +#define ADSTAT_OVERRUN0 0x00000100 +#define ADSTAT_OVERRUN1 0x00000200 +#define ADSTAT_OVERRUN2 0x00000400 +#define ADSTAT_OVERRUN3 0x00000800 +#define ADSTAT_OVERRUN4 0x00001000 +#define ADSTAT_OVERRUN5 0x00002000 +#define ADSTAT_OVERRUN6 0x00004000 +#define ADSTAT_OVERRUN7 0x00008000 +#define ADSTAT_ADINT 0x00010000 + +#define ADINTEN_INTEN 0x000000FF +#define ADINTEN_INTEN0 0x00000001 +#define ADINTEN_INTEN1 0x00000002 +#define ADINTEN_INTEN2 0x00000004 +#define ADINTEN_INTEN3 0x00000008 +#define ADINTEN_INTEN4 0x00000010 +#define ADINTEN_INTEN5 0x00000020 +#define ADINTEN_INTEN6 0x00000040 +#define ADINTEN_INTEN7 0x00000080 +#define ADINTEN_GINTEN 0x00000100 + +#define ADDR_RESULT 0x0000FFC0 +#define ADDR_OVERRUN 0x40000000 +#define ADDR_DONE 0x80000000 + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcADC.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcADC.h new file mode 100644 index 0000000..11bc2a3 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcADC.h @@ -0,0 +1,24 @@ +/****************************************************************************** + * + * $RCSfile: lpcADC.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_ADC_H +#define INC_LPC_ADC_H + +// A/D Converter Registers +typedef struct +{ + REG32 cr; // Control Register + REG32 dr; // Data Register +} adcRegs_t; + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcEMC.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcEMC.h new file mode 100644 index 0000000..2349617 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcEMC.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * + * $RCSfile: lpcEMC.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_EMC_H +#define INC_LPC_EMC_H + +// External Memory Controller Registers +typedef struct +{ + REG32 bcfg0; // Bank 0 Configuration Register + REG32 bcfg1; // Bank 1 Configuration Register + REG32 bcfg2; // Bank 2 Configuration Register + REG32 bcfg3; // Bank 3 Configuration Register +} emcRegs_t; + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcGPIO.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcGPIO.h new file mode 100644 index 0000000..f4c78c9 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcGPIO.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * $RCSfile: lpcGPIO.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_GPIO_H +#define INC_LPC_GPIO_H + +// General Purpose Input/Output Registers (GPIO) +typedef struct +{ + REG32 in0; // P0 Pin Value Register + REG32 set0; // P0 Pin Output Set Register + REG32 dir0; // P0 Pin Direction Register + REG32 clr0; // P0 Pin Output Clear Register + REG32 in1; // P1 Pin Value Register + REG32 set1; // P1 Pin Output Set Register + REG32 dir1; // P1 Pin Direction Register + REG32 clr1; // P1 Pin Output Clear Register + REG32 in2; // P2 Pin Value Register + REG32 set2; // P2 Pin Output Set Register + REG32 dir2; // P2 Pin Direction Register + REG32 clr2; // P2 Pin Output Clear Register + REG32 in3; // P3 Pin Value Register + REG32 set3; // P3 Pin Output Set Register + REG32 dir3; // P3 Pin Direction Register + REG32 clr3; // P3 Pin Output Clear Register +} gpioRegs_t; + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcI2C.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcI2C.h new file mode 100644 index 0000000..e874abc --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcI2C.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * + * $RCSfile: lpcI2C.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_I2C_H +#define INC_LPC_I2C_H + +// I2C Interface Registers +typedef struct +{ + REG_8 conset; // Control Set Register + REG_8 _pad0[3]; + REG_8 stat; // Status Register + REG_8 _pad1[3]; + REG_8 dat; // Data Register + REG_8 _pad2[3]; + REG_8 adr; // Slave Address Register + REG_8 _pad3[3]; + REG16 sclh; // SCL Duty Cycle Register (high half word) + REG16 _pad4; + REG16 scll; // SCL Duty Cycle Register (low half word) + REG16 _pad5; + REG_8 conclr; // Control Clear Register + REG_8 _pad6[3]; +} i2cRegs_t; + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcPIN.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcPIN.h new file mode 100644 index 0000000..df52b37 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcPIN.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * + * $RCSfile: lpcPIN.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_PIN_H +#define INC_LPC_PIN_H + +// Pin Connect Block Registers +typedef struct +{ + REG32 sel0; // Pin Function Select Register 0 + REG32 sel1; // Pin Function Select Register 1 + REG32 _pad[3]; + REG32 sel2; // Pin Function Select Register 2 +} pinRegs_t; + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcRTC.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcRTC.h new file mode 100644 index 0000000..f9d9c0b --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcRTC.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * + * $RCSfile: lpcRTC.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_RTC_H +#define INC_LPC_RTC_H + +typedef struct +{ + REG_8 ilr; // Interrupt Location Register + REG_8 _pad0[3]; + REG16 ctc; // Clock Tick Counter + REG16 _pad1; + REG_8 ccr; // Clock Control Register + REG_8 _pad2[3]; + REG_8 ciir; // Counter Increment Interrupt Register + REG_8 _pad3[3]; + REG_8 amr; // Alarm Mask Register + REG_8 _pad4[3]; + REG32 ctime0; // Consolidated Time Register 0 + REG32 ctime1; // Consolidated Time Register 1 + REG32 ctime2; // Consolidated Time Register 2 + REG_8 sec; // Seconds Register + REG_8 _pad5[3]; + REG_8 min; // Minutes Register + REG_8 _pad6[3]; + REG_8 hour; // Hours Register + REG_8 _pad7[3]; + REG_8 dom; // Day Of Month Register + REG_8 _pad8[3]; + REG_8 dow; // Day Of Week Register + REG_8 _pad9[3]; + REG16 doy; // Day Of Year Register + REG16 _pad10; + REG_8 month; // Months Register + REG_8 _pad11[3]; + REG16 year; // Years Register + REG32 _pad12[8]; + REG_8 alsec; // Alarm Seconds Register + REG_8 _pad13[3]; + REG_8 almin; // Alarm Minutes Register + REG_8 _pad14[3]; + REG_8 alhour; // Alarm Hours Register + REG_8 _pad15[3]; + REG_8 aldom; // Alarm Day Of Month Register + REG_8 _pad16[3]; + REG_8 aldow; // Alarm Day Of Week Register + REG_8 _pad17[3]; + REG16 aldoy; // Alarm Day Of Year Register + REG16 _pad18; + REG_8 almon; // Alarm Months Register + REG_8 _pad19[3]; + REG16 alyear; // Alarm Years Register + REG16 _pad20; + REG16 preint; // Prescale Value Register (integer) + REG16 _pad21; + REG16 prefrac; // Prescale Value Register (fraction) + REG16 _pad22; +} rtcRegs_t; + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcSCB.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcSCB.h new file mode 100644 index 0000000..5612a94 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcSCB.h @@ -0,0 +1,129 @@ +/****************************************************************************** + * + * $RCSfile: lpcSCB.h,v $ + * $Revision: 1.2 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_SCB_H +#define INC_LPC_SCB_H + +// System Control Block Registers +typedef struct +{ + // Memory Accelerator Module Registers (MAM) + struct + { + REG_8 cr; // Control Register + REG_8 _pad0[3]; + REG_8 tim; // Timing Control Register + REG32 _pad1[14]; + } mam; + + // Memory Mapping Control Register + REG_8 memmap; + REG32 _pad0[15]; + + // Phase Locked Loop Registers (PLL) + struct + { + REG_8 con; // Control Register + REG_8 _pad0[3]; + REG_8 cfg; // Configuration Register + REG_8 _pad1[3]; + REG16 stat; // Status Register + REG16 _pad2; + REG_8 feed; // Feed Register + REG_8 _pad3[3]; + REG32 _pad4[4]; + } pll; + + struct + { + REG_8 con; // Control Register + REG_8 _pad0[3]; + REG_8 cfg; // Configuration Register + REG_8 _pad1[3]; + REG16 stat; // Status Register + REG16 _pad2; + REG_8 feed; // Feed Register + REG_8 _pad3[3]; + REG32 _pad4[4]; + } pll48; + + // Power Control Registers + struct + { + REG_8 con; // Control Register + REG_8 _pad0[3]; + REG32 conp; // Peripherals Register + REG32 _pad1[14]; + } p; + + // VPB Divider Register + REG_8 vpbdiv; + REG32 _pad1[15]; + + // External Interrupt Registers + struct + { + REG_8 flag; // Flag Register + REG_8 _pad0[3]; + REG_8 wake; // Wakeup Register + REG_8 _pad1[3]; + REG_8 mode; // Mode Register + REG_8 _pad2[3]; + REG_8 polar; // Polarity Register + REG32 _pad3[12]; + } ext; +} scbRegs_t; + + +/////////////////////////////////////////////////////////////////////////////// +// MAM defines +#define MAMCR_OFF 0 +#define MAMCR_PART 1 +#define MAMCR_FULL 2 + +#define MAMTIM_CYCLES (((CCLK) + 19999999) / 20000000) + +/////////////////////////////////////////////////////////////////////////////// +// MEMMAP defines +#define MEMMAP_BBLK 0 // Interrupt Vectors in Boot Block +#define MEMMAP_FLASH 1 // Interrupt Vectors in Flash +#define MEMMAP_SRAM 2 // Interrupt Vectors in SRAM + +/////////////////////////////////////////////////////////////////////////////// +// PLL defines & computations +// Compute the value of PLL_DIV and test range validity +// FOSC & PLL_MUL should be defined in project configuration file (config.h) +#ifndef CCLK +#define CCLK (FOSC * PLL_MUL) // CPU Clock Freq. +#endif + +#define FCCO_MAX (320000000) // Max CC Osc Freq. +#define PLL_DIV (FCCO_MAX / (2 * CCLK)) // PLL Divider +#define FCCO (FOSC * PLL_MUL * 2 * PLL_DIV) // CC Osc. Freq. + +// PLLCON Register Bit Definitions +#define PLLCON_PLLE (1 << 0) // PLL Enable +#define PLLCON_PLLC (1 << 1) // PLL Connect + +// PLLCFG Register Bit Definitions +#define PLLCFG_MSEL ((PLL_MUL - 1) << 0) // PLL Multiplier +#define PLLCFG_PSEL ((PLL_DIV - 1) << 5) // PLL Divider + +// PLLSTAT Register Bit Definitions +#define PLLSTAT_LOCK (1 << 10) // PLL Lock Status Bit + +/////////////////////////////////////////////////////////////////////////////// +// VPBDIV defines & computations +#define VPBDIV_VALUE (PBSD & 0x03) // VPBDIV value + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcSPI.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcSPI.h new file mode 100644 index 0000000..9e6bd2b --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcSPI.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * + * $RCSfile: lpcSPI.h,v $ + * $Revision: 1.2 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_SPI_H +#define INC_LPC_SPI_H + +// Serial Peripheral Interface Registers (SPI) +typedef struct +{ + REG_8 cr; // Control Register + REG_8 _pad0[3]; + REG_8 sr; // Status Register + REG_8 _pad1[3]; + REG_8 dr; // Data Register + REG_8 _pad2[3]; + REG_8 ccr; // Clock Counter Register + REG_8 _pad3[3]; + REG_8 tcr; // Test Control Register + REG_8 _pad4[3]; + REG_8 tsr; // Test Status Register + REG_8 _pad5[3]; + REG_8 tor; // Test Observe Register + REG_8 _pad6[3]; + REG_8 flag; // Interrupt Flag Register + REG_8 _pad7[3]; +} spiRegs_t; + + +// SPI Control Register +#define SPCR_BE (1 << 2) // BitEnable : If set the SPI controller + // sends and receives the number of bits + // selected by bits 11:8. +#define SPCR_CPHA (1 << 3) // Clock phase control +#define SPCR_CPOL (1 << 4) // Clock polarity control. +#define SPCR_MSTR (1 << 5) // Master mode select. +#define SPCR_LSBF (1 << 6) // LSB First controls +#define SPCR_SPIE (1 << 7) // Serial peripheral interrupt enable. +#define SPCR_BITS (0xF << 8) // When bit 2 of this register is 1, + // this field controls the number of + // bits per transfer + // 1000 : 8 bits per transfer + // 1001 : 9 bits per transfer + // 1010 : 10 bits per transfer + // 1011 : 11 bits per transfer + // 1100 : 12 bits per transfer + // 1101 : 13 bits per transfer + // 1110 : 14 bits per transfer + // 1111 : 15 bits per transfer + // 0000 : 16 bits per transfer + +//SPI Status Register +#define SPSR_ABRT (1 << 3) // Slave abort. +#define SPSR_MODF (1 << 4) // Mode fault. +#define SPSR_ROVR (1 << 5) // Read overrun. +#define SPSR_WCOL (1 << 6) // Write collision. +#define SPSR_SPIF (1 << 7) // SPI transfer complete flag. + +//SPI Interrupt register +#define SPINT_IF (1 << 0) // SPI interrupt flag. + + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcTMR.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcTMR.h new file mode 100644 index 0000000..cbc7bed --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcTMR.h @@ -0,0 +1,108 @@ +/****************************************************************************** + * + * $RCSfile: lpcTMR.h,v $ + * $Revision: 1.2 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_TMR_H +#define INC_LPC_TMR_H + +// Timer & PWM Registers +typedef struct +{ + REG32 ir; // Interrupt Register + REG32 tcr; // Timer Control Register + REG32 tc; // Timer Counter + REG32 pr; // Prescale Register + REG32 pc; // Prescale Counter Register + REG32 mcr; // Match Control Register + REG32 mr0; // Match Register 0 + REG32 mr1; // Match Register 1 + REG32 mr2; // Match Register 2 + REG32 mr3; // Match Register 3 + REG32 ccr; // Capture Control Register + REG32 cr0; // Capture Register 0 + REG32 cr1; // Capture Register 1 + REG32 cr2; // Capture Register 2 + REG32 cr3; // Capture Register 3 + REG32 emr; // External Match Register + REG32 mr4; // Match Register 4 + REG32 mr5; // Match Register 5 + REG32 mr6; // Match Register 6 + REG32 pcr; // Control Register + REG32 ler; // Latch Enable Register +} pwmTmrRegs_t; + +// Timer Interrupt Register Bit Definitions +#define TIR_MR0I (1 << 0) // Interrupt flag for match channel 0 +#define TIR_MR1I (1 << 1) // Interrupt flag for match channel 1 +#define TIR_MR2I (1 << 2) // Interrupt flag for match channel 2 +#define TIR_MR3I (1 << 3) // Interrupt flag for match channel 3 +#define TIR_CR0I (1 << 4) // Interrupt flag for capture channel 0 event +#define TIR_CR1I (1 << 5) // Interrupt flag for capture channel 1 event +#define TIR_CR2I (1 << 6) // Interrupt flag for capture channel 2 event +#define TIR_CR3I (1 << 7) // Interrupt flag for capture channel 3 event + +// PWM Interrupt Register Bit Definitions +#define PWMIR_MR0I (1 << 0) // Interrupt flag for match channel 0 +#define PWMIR_MR1I (1 << 1) // Interrupt flag for match channel 1 +#define PWMIR_MR2I (1 << 2) // Interrupt flag for match channel 2 +#define PWMIR_MR3I (1 << 3) // Interrupt flag for match channel 3 +#define PWMIR_MR4I (1 << 8) // Interrupt flag for match channel 4 +#define PWMIR_MR5I (1 << 9) // Interrupt flag for match channel 5 +#define PWMIR_MR6I (1 << 10) // Interrupt flag for match channel 6 +#define PWMIR_MASK (0x070F) + +// Timer Control Register Bit Definitions +#define TCR_ENABLE (1 << 0) +#define TCR_RESET (1 << 1) + +// PWM Control Register Bit Definitions +#define PWMCR_ENABLE (1 << 0) +#define PWMCR_RESET (1 << 1) + +// PWM Latch Enable Register Bit Definitions +#define PWMLER_PWML0E (1<<0) +#define PWMLER_PWML1E (1<<1) +#define PWMLER_PWML2E (1<<2) +#define PWMLER_PWML3E (1<<3) +#define PWMLER_PWML4E (1<<4) +#define PWMLER_PWML5E (1<<5) +#define PWMLER_PWML6E (1<<6) + +// Timer Match Control Register Bit Definitions +#define TMCR_MR0_I (1 << 0) // Enable Interrupt when MR0 matches TC +#define TMCR_MR0_R (1 << 1) // Enable Reset of TC upon MR0 match +#define TMCR_MR0_S (1 << 2) // Enable Stop of TC upon MR0 match +#define TMCR_MR1_I (1 << 3) // Enable Interrupt when MR1 matches TC +#define TMCR_MR1_R (1 << 4) // Enable Reset of TC upon MR1 match +#define TMCR_MR1_S (1 << 5) // Enable Stop of TC upon MR1 match +#define TMCR_MR2_I (1 << 6) // Enable Interrupt when MR2 matches TC +#define TMCR_MR2_R (1 << 7) // Enable Reset of TC upon MR2 match +#define TMCR_MR2_S (1 << 8) // Enable Stop of TC upon MR2 match +#define TMCR_MR3_I (1 << 9) // Enable Interrupt when MR3 matches TC +#define TMCR_MR3_R (1 << 10) // Enable Reset of TC upon MR3 match +#define TMCR_MR3_S (1 << 11) // Enable Stop of TC upon MR3 match + +// Timer Capture Control Register Bit Definitions +#define TCCR_CR0_R (1 << 0) // Enable Rising edge on CAPn.0 will load TC to CR0 +#define TCCR_CR0_F (1 << 1) // Enable Falling edge on CAPn.0 will load TC to CR0 +#define TCCR_CR0_I (1 << 2) // Enable Interrupt on load of CR0 +#define TCCR_CR1_R (1 << 3) // Enable Rising edge on CAPn.1 will load TC to CR1 +#define TCCR_CR1_F (1 << 4) // Enable Falling edge on CAPn.1 will load TC to CR1 +#define TCCR_CR1_I (1 << 5) // Enable Interrupt on load of CR1 +#define TCCR_CR2_R (1 << 6) // Enable Rising edge on CAPn.2 will load TC to CR2 +#define TCCR_CR2_F (1 << 7) // Enable Falling edge on CAPn.2 will load TC to CR2 +#define TCCR_CR2_I (1 << 8) // Enable Interrupt on load of CR2 +#define TCCR_CR3_R (1 << 9) // Enable Rising edge on CAPn.3 will load TC to CR3 +#define TCCR_CR3_F (1 << 10) // Enable Falling edge on CAPn.3 will load TC to CR3 +#define TCCR_CR3_I (1 << 11) // Enable Interrupt on load of CR3 + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcUART.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcUART.h new file mode 100644 index 0000000..74e257a --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcUART.h @@ -0,0 +1,122 @@ +/****************************************************************************** + * + * $RCSfile: lpcUART.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_UART_H +#define INC_LPC_UART_H + +// Universal Asynchronous Receiver Transmitter Registers +typedef struct +{ + union + { + REG_8 rbr; // Receive Buffer Register + REG_8 thr; // Transmit Holding Register + REG_8 dll; // Divisor Latch Register (LSB) + REG_8 _pad0[4]; + }; + + union + { + REG_8 ier; // Interrupt Enable Register + REG_8 dlm; // Divisor Latch Register (MSB) + REG_8 _pad1[4]; + }; + + union + { + REG_8 iir; // Interrupt ID Register + REG_8 fcr; // FIFO Control Register + REG_8 _pad2[4]; + }; + + REG_8 lcr; // Line Control Registe + REG_8 _pad3[3]; + REG_8 mcr; // MODEM Control Register + REG_8 _pad4[3]; + REG_8 lsr; // Line Status Register + REG_8 _pad5[3]; + REG_8 msr; // MODEM Status Register + REG_8 _pad6[3]; + REG_8 scr; // Scratch Pad Register + REG_8 _pad7[3]; +} uartRegs_t; + +/////////////////////////////////////////////////////////////////////////////// +// UART defines + +// Interrupt Enable Register bit definitions +#define UIER_ERBFI (1 << 0) // Enable Receive Data Available Interrupt +#define UIER_ETBEI (1 << 1) // Enable Transmit Holding Register Empty Interrupt +#define UIER_ELSI (1 << 2) // Enable Receive Line Status Interrupt +#define UIER_EDSSI (1 << 3) // Enable MODEM Status Interrupt + +// Interrupt ID Register bit definitions +#define UIIR_NO_INT (1 << 0) // NO INTERRUPTS PENDING +#define UIIR_MS_INT (0 << 1) // MODEM Status +#define UIIR_THRE_INT (1 << 1) // Transmit Holding Register Empty +#define UIIR_RDA_INT (2 << 1) // Receive Data Available +#define UIIR_RLS_INT (3 << 1) // Receive Line Status +#define UIIR_CTI_INT (6 << 1) // Character Timeout Indicator +#define UIIR_ID_MASK 0x0E + +// FIFO Control Register bit definitions +#define UFCR_FIFO_ENABLE (1 << 0) // FIFO Enable +#define UFCR_RX_FIFO_RESET (1 << 1) // Reset Receive FIFO +#define UFCR_TX_FIFO_RESET (1 << 2) // Reset Transmit FIFO +#define UFCR_FIFO_TRIG1 (0 << 6) // Trigger @ 1 character in FIFO +#define UFCR_FIFO_TRIG4 (1 << 6) // Trigger @ 4 characters in FIFO +#define UFCR_FIFO_TRIG8 (2 << 6) // Trigger @ 8 characters in FIFO +#define UFCR_FIFO_TRIG14 (3 << 6) // Trigger @ 14 characters in FIFO + +// Line Control Register bit definitions +#define ULCR_CHAR_5 (0 << 0) // 5-bit character length +#define ULCR_CHAR_6 (1 << 0) // 6-bit character length +#define ULCR_CHAR_7 (2 << 0) // 7-bit character length +#define ULCR_CHAR_8 (3 << 0) // 8-bit character length +#define ULCR_STOP_1 (0 << 2) // 1 stop bit +#define ULCR_STOP_2 (1 << 2) // 2 stop bits +#define ULCR_PAR_NO (0 << 3) // No Parity +#define ULCR_PAR_ODD (1 << 3) // Odd Parity +#define ULCR_PAR_EVEN (3 << 3) // Even Parity +#define ULCR_PAR_MARK (5 << 3) // MARK "1" Parity +#define ULCR_PAR_SPACE (7 << 3) // SPACE "0" Paruty +#define ULCR_BREAK_ENABLE (1 << 6) // Output BREAK line condition +#define ULCR_DLAB_ENABLE (1 << 7) // Enable Divisor Latch Access + +// Modem Control Register bit definitions +#define UMCR_DTR (1 << 0) // Data Terminal Ready +#define UMCR_RTS (1 << 1) // Request To Send +#define UMCR_LB (1 << 4) // Loopback + +// Line Status Register bit definitions +#define ULSR_RDR (1 << 0) // Receive Data Ready +#define ULSR_OE (1 << 1) // Overrun Error +#define ULSR_PE (1 << 2) // Parity Error +#define ULSR_FE (1 << 3) // Framing Error +#define ULSR_BI (1 << 4) // Break Interrupt +#define ULSR_THRE (1 << 5) // Transmit Holding Register Empty +#define ULSR_TEMT (1 << 6) // Transmitter Empty +#define ULSR_RXFE (1 << 7) // Error in Receive FIFO +#define ULSR_ERR_MASK 0x1E + +// Modem Status Register bit definitions +#define UMSR_DCTS (1 << 0) // Delta Clear To Send +#define UMSR_DDSR (1 << 1) // Delta Data Set Ready +#define UMSR_TERI (1 << 2) // Trailing Edge Ring Indicator +#define UMSR_DDCD (1 << 3) // Delta Data Carrier Detect +#define UMSR_CTS (1 << 4) // Clear To Send +#define UMSR_DSR (1 << 5) // Data Set Ready +#define UMSR_RI (1 << 6) // Ring Indicator +#define UMSR_DCD (1 << 7) // Data Carrier Detect + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcUSB.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcUSB.h new file mode 100644 index 0000000..3f924b5 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcUSB.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * $RCSfile: lpcUSB.h,v $ + * $Revision: 1.3 $ + * + * Header file for Philips LPC214x USB enabled ARM Processors + * Copyright 2006 Pavel Pisa + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact or GPL license is applied. + * + *****************************************************************************/ + +/* USBIntSt - USB Interrupt Status (R/W) */ +#define USB_INT_REQ_LP (1<<0) /*Low priority interrupt line status (RO) */ +#define USB_INT_REQ_HP (1<<1) /*High priority interrupt line status. (RO) */ +#define USB_INT_REQ_DMA (1<<2) /*DMA interrupt line status. This bit is read only. (LPC2146/8 only) 0*/ +#define USB_need_clock (1<<8) /*USB need clock indicator*/ +#define USB_EN_USB_INTS (1<<31) /*Enable all USB interrupts*/ + +/* Device interrupt registers */ +#define USBDevIntSt_o 0x0000 /* USB Device Interrupt Status (RO) */ +#define USBDevIntEn_o 0x0004 /* USB Device Interrupt Enable (R/W) */ +#define USBDevIntClr_o 0x0008 /* USB Device Interrupt Clear (WO) */ +#define USBDevIntSet_o 0x000C /* USB Device Interrupt Set (WO) */ +#define USBDevInt_FRAME (1<<0) /*Frame interrupt @1kHz for ISO transfers*/ +#define USBDevInt_EP_FAST (1<<1) /*Fast interrupt transfer for the endpoint*/ +#define USBDevInt_EP_SLOW (1<<2) /*Slow interrupt transfer for the endpoint*/ +#define USBDevInt_DEV_STAT (1<<3) /*USB Bus reset, USB suspend change or Connect occured*/ +#define USBDevInt_CCEMTY (1<<4) /*Command code register is empty/ready for CMD*/ +#define USBDevInt_CDFULL (1<<5) /*Command data register is full/data available*/ +#define USBDevInt_RxENDPKT (1<<6) /*Current packet in the FIFO is transferred to the CPU*/ +#define USBDevInt_TxENDPKT (1<<7) /*TxPacket bytes written to FIFO*/ +#define USBDevInt_EP_RLZED (1<<8) /*Endpoints realized after Maxpacket size update*/ +#define USBDevInt_ERR_INT (1<<9) /*Error Interrupt - Use Read Error Status Command 0xFB*/ + +#define USBDevIntPri_o 0x002C /* USB Device Interrupt Priority (WO) */ +#define USBDevIntPri_FRAME (1<<0) /*0/1 FRAME int routed to the low/high priority interrupt line*/ +#define USBDevIntPri_EP_FAST (1<<1) /*0/1 EP_FAST int routed to the low/high priority line*/ + +/* Endpoint interrupt registers - bits corresponds to EP0 to EP31 */ +#define USBEpIntSt_o 0x0030 /* USB Endpoint Interrupt Status (RO) */ +#define USBEpIntEn_o 0x0034 /* USB Endpoint Interrupt Enable (R/W) */ +#define USBEpIntClr_o 0x0038 /* USB Endpoint Interrupt Clear (WO) */ +#define USBEpIntSet_o 0x003C /* USB Endpoint Interrupt Set (WO) */ +#define USBEpIntPri_o 0x0040 /* USB Endpoint Priority (WO) */ +/* Endpoint realization registers */ +#define USBReEp_o 0x0044 /* USB Realize Endpoint (R/W) */ +#define USBEpInd_o 0x0048 /* USB Endpoint Index (WO) */ +#define USBEpInd_Ind 0x001F /* Index for subsequent USBMaxPSize (WO) */ +#define USBMaxPSize_o 0x004C /* USB MaxPacketSize (R/W) */ +#define USBMaxPSize_Size 0x03FF /* The maximum packet size value */ +/* USB transfer registers */ +#define USBRxData_o 0x0018 /* USB Receive Data (RO) */ +#define USBRxPLen_o 0x0020 /* USB Receive Packet Length (RO) */ +#define USBRxPLen_PKT_LNGTH (0x03FF) /*Remaining amount of bytes to be read from RAM*/ +#define USBRxPLen_DV (1<<10) /*Data valid. 0 only for error ISO packet*/ +#define USBRxPLen_PKT_RDY (1<<11) /*Packet length valid and packet is ready for reading*/ +#define USBTxData_o 0x001C /* USB Transmit Data (WO) */ +#define USBTxPLen_o 0x0024 /* USB Transmit Packet Length (WO) */ +#define USBTxPLen_PKT_LNGTH (0x03FF) /*Remaining amount of bytes to be written to the EP_RAM*/ +#define USBCtrl_o 0x0028 /* USB Control (R/W) */ +#define USBCtrl_RD_EN (1<<0) /*Read mode control*/ +#define USBCtrl_WR_EN (1<<1) /*Write mode control*/ +#define USBCtrl_LOG_ENDPOINT 0x003C /*Logical Endpoint number*/ +/* Command registers */ +#define USBCmdCode_o 0x0010 /* USB Command Code (WO) */ +#define USBCmdCode_CMD_PHASE 0x0000FF00 /*The command phase*/ +#define USBCmdCode_CMD_CODE 0x00FF0000 /*The code for the command*/ +#define USBCmdData_o 0x0014 /* USB Command Data (RO) */ +/* DMA registers (LPC2146/8 only) */ +#define USBDMARSt_o 0x0050 /* USB DMA Request Status (RO) */ +#define USBDMARClr_o 0x0054 /* USB DMA Request Clear (WO) */ +#define USBDMARSet_o 0x0058 /* USB DMA Request Set (WO) */ +#define USBUDCAH_o 0x0080 /* USB UDCA Head (R/W) has to be aligned to 128 bytes */ +#define USBEpDMASt_o 0x0084 /* USB Endpoint DMA Status (RO) */ +#define USBEpDMAEn_o 0x0088 /* USB Endpoint DMA Enable (WO) */ +#define USBEpDMADis_o 0x008C /* USB Endpoint DMA Disable (WO) */ +#define USBDMAIntSt_o 0x0090 /* USB DMA Interrupt Status (RO) */ +#define USBDMAIntEn_o 0x0094 /* USB DMA Interrupt Enable (R/W) */ +#define USBDMAInt_EoT (1<<0) /*End of Transfer Interrupt bit, 1 if USBEoTIntSt != 0*/ +#define USBDMAInt_New_DD_Rq (1<<1) /* New DD Request Interrupt bit, 1 if USBNDDRIntSt != 0*/ +#define USBDMAInt_SysError (1<<2) /*System Error Interrupt bit, 1 if USBSysErrIntSt != 0*/ +#define USBEoTIntSt_o 0x00A0 /* USB End of Transfer Interrupt Status (RO) */ +#define USBEoTIntClr_o 0x00A4 /* USB End of Transfer Interrupt Clear (WO) */ +#define USBEoTIntSet_o 0x00A8 /* USB End of Transfer Interrupt Set (WO) */ +#define USBNDDRIntSt_o 0x00AC /* USB New DD Request Interrupt Status (RO) */ +#define USBNDDRIntClr_o 0x00B0 /* USB New DD Request Interrupt Clear (WO) */ +#define USBNDDRIntSet_o 0x00B4 /* USB New DD Request Interrupt Set (WO) */ +#define USBSysErrIntSt_o 0x00B8 /* USB System Error Interrupt Status (RO) */ +#define USBSysErrIntClr_o 0x00BC /* USB System Error Interrupt Clear (WO) */ +#define USBSysErrIntSet_o 0x00C0 /* USB System Error Interrupt Set (WO) */ +#define USB_MODULE_ID_o 0x00FC /* USB Module ID */ + +/* Command Codes */ +#define USB_CMD_SET_ADDR 0x00D00500 +#define USB_CMD_CFG_DEV 0x00D80500 +#define USB_CMD_SET_MODE 0x00F30500 +#define USB_CMD_RD_FRAME 0x00F50500 +#define USB_DAT_RD_FRAME 0x00F50200 +#define USB_CMD_RD_TEST 0x00FD0500 +#define USB_DAT_RD_TEST 0x00FD0200 +#define USB_CMD_SET_DEV_STAT 0x00FE0500 +#define USB_CMD_GET_DEV_STAT 0x00FE0500 +#define USB_DAT_GET_DEV_STAT 0x00FE0200 +#define USB_CMD_GET_ERR_CODE 0x00FF0500 +#define USB_DAT_GET_ERR_CODE 0x00FF0200 +#define USB_CMD_RD_ERR_STAT 0x00FB0500 +#define USB_DAT_RD_ERR_STAT 0x00FB0200 +#define USB_DAT_WR_BYTE(x) (0x00000100 | ((x) << 16)) +#define USB_CMD_SEL_EP(x) (0x00000500 | ((x) << 16)) +#define USB_DAT_SEL_EP(x) (0x00000200 | ((x) << 16)) +#define USB_CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16)) +#define USB_DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16)) +#define USB_CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16)) +#define USB_CMD_CLR_BUF 0x00F20500 +#define USB_DAT_CLR_BUF 0x00F20200 +#define USB_CMD_VALID_BUF 0x00FA0500 + +/* Device Address Register Definitions */ +#define USBC_DEV_ADDR_MASK 0x7F +#define USBC_DEV_EN 0x80 + +/* Device Configure Register Definitions */ +#define USBC_CONF_DEVICE 0x01 + +/* Device Mode Register Definitions */ +#define USBC_AP_CLK 0x01 +#define USBC_INAK_CI 0x02 +#define USBC_INAK_CO 0x04 +#define USBC_INAK_II 0x08 +#define USBC_INAK_IO 0x10 +#define USBC_INAK_BI 0x20 +#define USBC_INAK_BO 0x40 + +/* Device Status Register Definitions */ +#define USBC_DEV_CON 0x01 +#define USBC_DEV_CON_CH 0x02 +#define USBC_DEV_SUS 0x04 +#define USBC_DEV_SUS_CH 0x08 +#define USBC_DEV_RST 0x10 + +/* Error Code Register Definitions */ +#define USBC_ERR_EC_MASK 0x0F +#define USBC_ERR_EA 0x10 + +/* Error Status Register Definitions */ +#define USBC_ERR_PID 0x01 +#define USBC_ERR_UEPKT 0x02 +#define USBC_ERR_DCRC 0x04 +#define USBC_ERR_TIMOUT 0x08 +#define USBC_ERR_EOP 0x10 +#define USBC_ERR_B_OVRN 0x20 +#define USBC_ERR_BTSTF 0x40 +#define USBC_ERR_TGL 0x80 + +/* Endpoint Select Register Definitions */ +#define USBC_EP_SEL_F 0x01 +#define USBC_EP_SEL_ST 0x02 +#define USBC_EP_SEL_STP 0x04 +#define USBC_EP_SEL_PO 0x08 +#define USBC_EP_SEL_EPN 0x10 +#define USBC_EP_SEL_B_1_FULL 0x20 +#define USBC_EP_SEL_B_2_FULL 0x40 + +/* Endpoint Status Register Definitions */ +#define USBC_EP_STAT_ST 0x01 +#define USBC_EP_STAT_DA 0x20 +#define USBC_EP_STAT_RF_MO 0x40 +#define USBC_EP_STAT_CND_ST 0x80 + +/* Clear Buffer Register Definitions */ +#define USBC_CLR_BUF_PO 0x01 + +typedef struct +{ +/* Device interrupt registers */ + REG32 DevIntSt; /* USB Device Interrupt Status (RO) 0000 */ + REG32 DevIntEn; /* USB Device Interrupt Enable (R/W) 0004 */ + REG32 DevIntClr; /* USB Device Interrupt Clear (WO) 0008 */ + REG32 DevIntSet; /* USB Device Interrupt Set (WO) 000C */ +/* Command registers */ + REG32 CmdCode; /* USB Command Code (WO) 0010 */ + REG32 CmdData; /* USB Command Data (RO) 0014 */ +/* USB transfer registers */ + REG32 RxData; /* USB Receive Data (RO) 0018 */ + REG32 TxData; /* USB Transmit Data (WO) 001C */ + REG32 RxPLen; /* USB Receive Packet Length (RO) 0020 */ + REG32 TxPLen; /* USB Transmit Packet Length (WO) 0024 */ + REG32 Ctrl; /* USB Control (R/W) 0028 */ +/* Device interrupt priority register */ + REG_8 USBDevIntPri; /* USB Device Interrupt Priority (WO) 002C */ + REG_8 _pad0[3]; +/* Endpoint interrupt registers */ + REG32 EpIntSt; /* USB Endpoint Interrupt Status (RO) 0030 */ + REG32 EpIntEn; /* USB Endpoint Interrupt Enable (R/W) 0034 */ + REG32 EpIntClr; /* USB Endpoint Interrupt Clear (WO) 0038 */ + REG32 EpIntSet; /* USB Endpoint Interrupt Set (WO) 003C */ + REG32 EpIntPri; /* USB Endpoint Priority (WO) 0040 */ +/* Endpoint realization registers */ + REG32 ReEp; /* USB Realize Endpoint (R/W) 0044 */ + REG32 EpInd; /* USB Endpoint Index (WO) 0048 */ + REG32 MaxPSize; /* USB MaxPacketSize (R/W) 004C */ +/* DMA registers (LPC2146/8 only) */ + REG32 DMARSt; /* USB DMA Request Status (RO) 0050 */ + REG32 DMARClr; /* USB DMA Request Clear (WO) 0054 */ + REG32 DMARSet; /* USB DMA Request Set (WO) 0058 */ + REG32 _pad1[9]; + REG32 UDCAH; /* USB UDCA Head (R/W) 0080 */ + REG32 EpDMASt; /* USB Endpoint DMA Status (RO) 0084 */ + REG32 EpDMAEn; /* USB Endpoint DMA Enable (WO) 0088 */ + REG32 EpDMADis; /* USB Endpoint DMA Disable (WO) 008C */ + REG32 DMAIntSt; /* USB DMA Interrupt Status (RO) 0090 */ + REG32 DMAIntEn; /* USB DMA Interrupt Enable (R/W) 0094 */ + REG32 _pad2[2]; + REG32 EoTIntSt; /* USB End of Transfer Interrupt Status (RO) 00A0 */ + REG32 EoTIntClr; /* USB End of Transfer Interrupt Clear (WO) 00A4 */ + REG32 EoTIntSet; /* USB End of Transfer Interrupt Set (WO) 00A8 */ + REG32 NDDRIntSt; /* USB New DD Request Interrupt Status (RO) 00AC */ + REG32 NDDRIntClr; /* USB New DD Request Interrupt Clear (WO) 00B0 */ + REG32 NDDRIntSet; /* USB New DD Request Interrupt Set (WO) 00B4 */ + REG32 SysErrIntSt; /* USB System Error Interrupt Status (RO) 00B8 */ + REG32 SysErrIntClr; /* USB System Error Interrupt Clear (WO) 00BC */ + REG32 SysErrIntSet; /* USB System Error Interrupt Set (WO) 00C0 */ + REG32 _pad3[0xE]; + REG32 MODULE_ID; /* Module ID (RO) 00FC */ +} usbRegs_t; + diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcVIC.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcVIC.h new file mode 100644 index 0000000..28d12a6 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcVIC.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * + * $RCSfile: lpcVIC.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_VIC_H +#define INC_LPC_VIC_H + +// Vectored Interrupt Controller Registers (VIC) +typedef struct +{ + REG32 irqStatus; // IRQ Status Register + REG32 fiqStatus; // FIQ Status Register + REG32 rawIntr; // Raw Interrupt Status Register + REG32 intSelect; // Interrupt Select Register + REG32 intEnable; // Interrupt Enable Register + REG32 intEnClear; // Interrupt Enable Clear Register + REG32 softInt; // Software Interrupt Register + REG32 softIntClear; // Software Interrupt Clear Register + REG32 protection; // Protection Enable Register + REG32 _pad0[3]; + REG32 vectAddr; // Vector Address Register + REG32 defVectAddr; // Default Vector Address Register + REG32 _pad1[50]; + REG32 vectAddr0; // Vector Address 0 Register + REG32 vectAddr1; // Vector Address 1 Register + REG32 vectAddr2; // Vector Address 2 Register + REG32 vectAddr3; // Vector Address 3 Register + REG32 vectAddr4; // Vector Address 4 Register + REG32 vectAddr5; // Vector Address 5 Register + REG32 vectAddr6; // Vector Address 6 Register + REG32 vectAddr7; // Vector Address 7 Register + REG32 vectAddr8; // Vector Address 8 Register + REG32 vectAddr9; // Vector Address 9 Register + REG32 vectAddr10; // Vector Address 10 Register + REG32 vectAddr11; // Vector Address 11 Register + REG32 vectAddr12; // Vector Address 12 Register + REG32 vectAddr13; // Vector Address 13 Register + REG32 vectAddr14; // Vector Address 14 Register + REG32 vectAddr15; // Vector Address 15 Register + REG32 _pad2[48]; + REG32 vectCntl0; // Vector Control 0 Register + REG32 vectCntl1; // Vector Control 1 Register + REG32 vectCntl2; // Vector Control 2 Register + REG32 vectCntl3; // Vector Control 3 Register + REG32 vectCntl4; // Vector Control 4 Register + REG32 vectCntl5; // Vector Control 5 Register + REG32 vectCntl6; // Vector Control 6 Register + REG32 vectCntl7; // Vector Control 7 Register + REG32 vectCntl8; // Vector Control 8 Register + REG32 vectCntl9; // Vector Control 9 Register + REG32 vectCntl10; // Vector Control 10 Register + REG32 vectCntl11; // Vector Control 11 Register + REG32 vectCntl12; // Vector Control 12 Register + REG32 vectCntl13; // Vector Control 13 Register + REG32 vectCntl14; // Vector Control 14 Register + REG32 vectCntl15; // Vector Control 15 Register +} vicRegs_t; + +// VIC Channel Assignments +#define VIC_WDT 0 +#define VIC_TIMER0 4 +#define VIC_TIMER1 5 +#define VIC_UART0 6 +#define VIC_UART1 7 +#define VIC_PWM 8 +#define VIC_PWM0 8 +#define VIC_I2C 9 +#define VIC_SPI 10 +#define VIC_SPI0 10 +#define VIC_SPI1 11 +#define VIC_PLL 12 +#define VIC_RTC 13 +#define VIC_EINT0 14 +#define VIC_EINT1 15 +#define VIC_EINT2 16 +#define VIC_EINT3 17 +#define VIC_ADC 18 + +// Vector Control Register bit definitions +#define VIC_ENABLE (1 << 5) + +// Convert Channel Number to Bit Value +#define VIC_BIT(chan) (1 << (chan)) + +#endif + diff --git a/embedded/arch/arm/mach-lpc21xx/defines/lpcWD.h b/embedded/arch/arm/mach-lpc21xx/defines/lpcWD.h new file mode 100644 index 0000000..65f1d73 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/defines/lpcWD.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * + * $RCSfile: lpcWD.h,v $ + * $Revision: 1.1 $ + * + * Header file for Philips LPC ARM Processors. + * Copyright 2004 R O SoftWare + * + * No guarantees, warrantees, or promises, implied or otherwise. + * May be used for hobby or commercial purposes provided copyright + * notice remains intact. + * + *****************************************************************************/ +#ifndef INC_LPC_WD_H +#define INC_LPC_WD_H + +// Watchdog Registers +typedef struct +{ + REG_8 mod; // Watchdog Mode Register + REG_8 _pad0[3]; + REG32 tc; // Watchdog Time Constant Register + REG_8 feed; // Watchdog Feed Register + REG32 tv; // Watchdog Time Value Register +} wdRegs_t; + +#endif diff --git a/embedded/arch/arm/mach-lpc21xx/libs/Makefile b/embedded/arch/arm/mach-lpc21xx/libs/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/mach-lpc21xx/libs/Makefile.omk b/embedded/arch/arm/mach-lpc21xx/libs/Makefile.omk new file mode 100644 index 0000000..778cdc0 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = hal iap diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile b/embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile.omk b/embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile.omk new file mode 100644 index 0000000..a7917db --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile.omk @@ -0,0 +1,12 @@ +# -*- makefile -*- + +lib_obj_SOURCES = startup.S ivt.S + +lib_LIBRARIES = mach_hal + +include_HEADERS = hal_ints.h hal_machperiph.h + +mach_hal_SOURCES = hal.c hal_machperiph.c + + + diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/hal.c b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal.c new file mode 100644 index 0000000..a983e95 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include + +// ------------------------------------------------------------------------- +// Hardware init + +// Return value of VPBDIV register. According to errata doc +// we need to read twice consecutively to get correct value +uint32_t lpc_get_vpbdiv(void) +{ + uint32_t vpbdiv_reg; + + vpbdiv_reg=VPBDIV; + vpbdiv_reg=VPBDIV; + + return (vpbdiv_reg); +} + + +// ------------------------------------------------------------------------- +// This routine is called to respond to a hardware interrupt (IRQ). It +// should interrogate the hardware and return the IRQ vector number. +int hal_IRQ_handler(void) +{ + uint32_t irq_num, irq_stat; + + irq_stat=VICIRQStatus; + for (irq_num = 0; irq_num < 32; irq_num++) + if (irq_stat & (1 << irq_num)) + break; + + // If not a valid interrrupt source, treat as spurious interrupt + if (irq_num < HAL_ISR_MIN || irq_num > HAL_ISR_MAX) + irq_num = HAL_INTERRUPT_NONE; + + return (irq_num); +} + + +// ------------------------------------------------------------------------- +// Interrupt control +// + +// Block the the interrupt associated with the vector +void hal_interrupt_mask(int vector) +{ + VICIntEnClear = 1 << vector; +} + +// Unblock the the interrupt associated with the vector +void hal_interrupt_unmask(int vector) +{ + VICIntEnable = 1 << vector; +} + +// Acknowledge the the interrupt associated with the vector. This +// clears the interrupt but may result in another interrupt being +// delivered +void hal_interrupt_acknowledge(int vector) +{ + + // External interrupts have to be cleared from the EXTINT register + if (vector >= HAL_INTERRUPT_EINT0 && + vector <= HAL_INTERRUPT_EINT3) + { + // Map int vector to corresponding bit (0..3) + vector = 1 << (vector - HAL_INTERRUPT_EINT0); + + // Clear the external interrupt + EXTINT=vector; + } + + // Acknowledge interrupt in the VIC + VICVectAddr=0; +} + +// This provides control over how an interrupt signal is detected. +// Options are between level or edge sensitive (level) and high/low +// level or rising/falling edge triggered (up). +// +// This should be simple, but unfortunately on some processor revisions, +// it trips up on two errata issues (for the LPC2294 Rev.A these are +// EXTINT.1 and VPBDIV.1) and so on these devices a somewhat convoluted +// sequence in order to work properly. There is nothing in the errata +// sequence that won't work on a processor without these issues. +void hal_interrupt_configure(int vector, int level, int up) +{ + uint32_t regval; +#ifdef HAL_ARM_LPC2XXX_EXTINT_ERRATA + uint32_t saved_vpbdiv; +#endif + + // Map int vector to corresponding bit (0..3) + vector = 1 << (vector - HAL_INTERRUPT_EINT0); + +#ifdef HAL_ARM_LPC2XXX_EXTINT_ERRATA + // From discussions with the Philips applications engineers on the + // Yahoo LPC2000 forum, it appears that in order up change both + // EXTMODE and EXTPOLAR, the operations have to be performed in + // two passes as follows: + // old=VPBDIV (x2), + // VPBDIV=0, EXTMODE=n, VPBDIV=n, VPBDIV=0, EXTPOLAR=y, VPBDIV=y + // VPCDIV=old + + // Save current VPBDIV register settings + saved_vpbdiv = lpc_get_vpbdiv(); + + // Clear VPBDIV register + VPBDIV=0; + + // Read current mode and update for level (0) or edge detection (1) + regval=EXTMODE; + if (level) + regval &= ~vector; + else + regval |= vector; + EXTMODE=regval; + + // Set VPBDIV register to same value as mode + VPBDIV=regval; + + // Clear VPBDIV register + VPBDIV=0; + + // Read current polarity and update for trigger level or edge + // level: high (1), low (0) edge: rising (1), falling (0) + regval=EXTPOLAR; + if (up) + regval |= vector; + else + regval &= ~vector; + EXTPOLAR=regval; + + + // Set VPBDIV register to same value as mode + VPBDIV=regval; + + // Restore saved VPBDIV register + VPBDIV=saved_vpbdiv; +#else + // Read current mode and update for level (0) or edge detection (1) + regval=EXTMODE; + if (level) + regval &= ~vector; + else + regval |= vector; + EXTMODE=regval; + + // Read current polarity and update for trigger level or edge + // level: high (1), low (0) edge: rising (1), falling (0) + regval=EXTPOLAR; + if (up) + regval |= vector; + else + regval &= ~vector; + EXTPOLAR=regval; +#endif + // Clear any spurious interrupt that might have been generated + EXTINT=vector; +} + +// Change interrupt level. This is a non-operation on the LPC2XXX +void hal_interrupt_set_level(int vector, int level) +{ +} + +uint32_t hal_default_isr(int vector, uint32_t data) +{ + return 0; +} + +uint32_t hal_interrupt_handlers[HAL_ISR_COUNT]={[0 ... HAL_ISR_COUNT-1]=(uint32_t)hal_default_isr}; +uint32_t hal_interrupt_data[HAL_ISR_COUNT]; + +void irq_handler_resolver(void) __attribute__ ((interrupt)); +void irq_handler_resolver(void) +{ + int v; + uint32_t f,d; + + v=hal_IRQ_handler(); + if (v==HAL_INTERRUPT_NONE) return; + f=hal_interrupt_handlers[v]; + d=hal_interrupt_data[v]; + ((hal_isr)f)(v,d); + hal_interrupt_acknowledge(v); +} diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_ints.h b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_ints.h new file mode 100644 index 0000000..d218725 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_ints.h @@ -0,0 +1,35 @@ +#ifndef HAL_INTS_H +#define HAL_INTS_H + +#define HAL_INTERRUPT_NONE -1 + +#define HAL_INTERRUPT_WD 0 +#define HAL_INTERRUPT_SOFT 1 +#define HAL_INTERRUPT_DCC_RX 2 +#define HAL_INTERRUPT_DCC_TX 3 +#define HAL_INTERRUPT_TIMER0 4 +#define HAL_INTERRUPT_TIMER1 5 +#define HAL_INTERRUPT_UART0 6 +#define HAL_INTERRUPT_UART1 7 +#define HAL_INTERRUPT_PWM0 8 +#define HAL_INTERRUPT_I2C0 9 +#define HAL_INTERRUPT_SPI0 10 +#define HAL_INTERRUPT_SPI1 11 +#define HAL_INTERRUPT_PLL 12 +#define HAL_INTERRUPT_RTCDEV 13 +#define HAL_INTERRUPT_EINT0 14 +#define HAL_INTERRUPT_EINT1 15 +#define HAL_INTERRUPT_EINT2 16 +#define HAL_INTERRUPT_EINT3 17 +#define HAL_INTERRUPT_AD 18 +#define HAL_INTERRUPT_I2C1 19 + +#define HAL_ISR_MIN 0 +#define HAL_ISR_MAX (31) + +#define HAL_ISR_COUNT (HAL_ISR_MAX+1) + +//The vector used by the Real time clock +#define HAL_INTERRUPT_RTC HAL_INTERRUPT_TIMER0 + +#endif /* HAL_INTS_H */ diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.c b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.c new file mode 100644 index 0000000..599fdc3 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.c @@ -0,0 +1,49 @@ +#include +#include +#include + +void lpc_pll_on() +{ + // set PLL multiplier & divisor. + // values computed from config.h + PLLCFG = PLLCFG_MSEL | PLLCFG_PSEL; + + // enable PLL + PLLCON = PLLCON_PLLE; + PLLFEED = 0xAA; // Make it happen. These two updates + PLLFEED = 0x55; // MUST occur in sequence. + + // wait for PLL lock + while (!(PLLSTAT & PLLSTAT_LOCK)) + continue; + + // enable & connect PLL + PLLCON = PLLCON_PLLE | PLLCON_PLLC; + PLLFEED = 0xAA; // Make it happen. These two updates + PLLFEED = 0x55; // MUST occur in sequence. +} + +void lpc_pll_off() +{ + // disable PLL + PLLCON = 0; + PLLFEED = 0xAA; // Make it happen. These two updates + PLLFEED = 0x55; // MUST occur in sequence. +} + +void lpc_watchdog_feed() +{ + unsigned long flags; + + save_and_cli(flags); + WDFEED = 0xAA; + WDFEED = 0x55; + restore_flags(flags); +} + +void lpc_watchdog_init(int on,int timeout_ms) +{ + if (!on) return; + WDTC = PCLK/(1000/timeout_ms); + WDMOD = 0x03; /* Enable watchdog timer and reset */ +} diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.h b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.h new file mode 100644 index 0000000..9f8c27f --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.h @@ -0,0 +1,10 @@ +#ifndef _HAL_MACHPERIPH_H +#define _HAL_MACHPERIPH_H + +void lpc_pll_on(); +void lpc_pll_off(); +void lpc_watchdog_init(int on,int timeout_ms); +void lpc_watchdog_feed(); + +#endif /* _HAL_MACHPERIPH_H */ + diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/ivt.S b/embedded/arch/arm/mach-lpc21xx/libs/hal/ivt.S new file mode 100644 index 0000000..ae9032a --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/ivt.S @@ -0,0 +1,34 @@ +/* Setup vector table. Note that undf, pabt, dabt, fiq just execute +a null loop. */ + +.section .ivt,"ax" + .code 32 + .align 0 + + .global hal_vectors + +hal_vectors: LDR PC, Reset_Addr + LDR PC, Undef_Addr + LDR PC, SWI_Addr + LDR PC, PAbt_Addr + LDR PC, DAbt_Addr + NOP /* Reserved Vector */ + LDR PC, IRQ_Addr + LDR PC, FIQ_Addr + +Reset_Addr: .word reset_handler +Undef_Addr: .word Undef_Handler +SWI_Addr: .word SWI_Handler +PAbt_Addr: .word PAbt_Handler +DAbt_Addr: .word DAbt_Handler + .word 0 /* Reserved Address */ +IRQ_Addr: .word irq_handler_resolver +FIQ_Addr: .word FIQ_Handler + +Undef_Handler: B Undef_Handler +SWI_Handler: B SWI_Handler +PAbt_Handler: B PAbt_Handler +DAbt_Handler: B DAbt_Handler +FIQ_Handler: B FIQ_Handler + + .end diff --git a/embedded/arch/arm/mach-lpc21xx/libs/hal/startup.S b/embedded/arch/arm/mach-lpc21xx/libs/hal/startup.S new file mode 100644 index 0000000..3201fbc --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/hal/startup.S @@ -0,0 +1,128 @@ +#/***********************************************************************/ +#/* Startup file for LPC21xx MCU applications */ +#/* Partially inspired by KEIL ELEKTRONIK startup code */ +#/***********************************************************************/ + + +# *** Startup Code (executed after Reset) *** + +# Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + .set MODE_USR, 0x10 // User Mode + .set MODE_FIQ, 0x11 // FIQ Mode + .set MODE_IRQ, 0x12 // IRQ Mode + .set MODE_SVC, 0x13 // Supervisor Mode + .set MODE_ABT, 0x17 // Abort Mode + .set MODE_UND, 0x1B // Undefined Mode + .set MODE_SYS, 0x1F // System Mode + + .equ I_BIT, 0x80 // when I bit is set, IRQ is disabled + .equ F_BIT, 0x40 // when F bit is set, FIQ is disabled + + .set UND_STACK_SIZE, 0x00000004 + .set ABT_STACK_SIZE, 0x00000004 + .set FIQ_STACK_SIZE, 0x00000004 + .set IRQ_STACK_SIZE, 0X00000400 + .set SVC_STACK_SIZE, 0x00000004 + +# Starupt Code must be linked first at Address at which it expects to run. + + .text +# .arm + + .global _stack // top of stack + .global _startup + .global reset_handler + .func _startup +_startup: + +reset_handler: + +# Memory Mapping (when Interrupt Vectors are in RAM) + .equ MEMMAP, 0xE01FC040 /* Memory Mapping Control */ + + MOV R1, #1 + LDR R0, =hal_vectors + CMP R0, #0 + BEQ mam_sram + MOV R1, #2 +mam_sram: + LDR R0, =MEMMAP + STR R1, [R0] + +# Initialize Interrupt System +# - Set stack location for each mode +# - Leave in System Mode with Interrupts Disabled +# ----------------------------------------------- + ldr r0,=_stack + msr CPSR_c,#MODE_UND|I_BIT|F_BIT // Undefined Instruction Mode + mov sp,r0 + sub r0,r0,#UND_STACK_SIZE + msr CPSR_c,#MODE_ABT|I_BIT|F_BIT // Abort Mode + mov sp,r0 + sub r0,r0,#ABT_STACK_SIZE + msr CPSR_c,#MODE_FIQ|I_BIT|F_BIT // FIQ Mode + mov sp,r0 + sub r0,r0,#FIQ_STACK_SIZE + msr CPSR_c,#MODE_IRQ|I_BIT|F_BIT // IRQ Mode + mov sp,r0 + sub r0,r0,#IRQ_STACK_SIZE + msr CPSR_c,#MODE_SVC|I_BIT|F_BIT // Supervisor Mode + mov sp,r0 + sub r0,r0,#SVC_STACK_SIZE + msr CPSR_c,#MODE_SYS|I_BIT|F_BIT // System Mode + mov sp,r0 + +# Disable interrupt from VIC + .equ VICINTENABLE, 0xFFFFF010 + .equ VICINTENCLR, 0xFFFFF014 + .equ VICSOFTINT, 0xFFFFF018 + .equ VICSOFTINTCLEAR, 0xFFFFF01C + LDR R0, =VICINTENABLE + MOV R1, #0 + STR R1, [R0] + MOV R1, #0xFFFFFFFF + STR R1, [R0,#VICINTENCLR-VICINTENABLE] + STR R1, [R0,#VICSOFTINTCLEAR-VICINTENABLE] + +# Enable interrupts and return back into supervisor mode + msr CPSR_c,#MODE_SVC // Supervisor Mode + +# Relocate .data section (Copy from ROM to RAM) + LDR R1, =_etext + LDR R2, =_data + LDR R3, =_edata + CMP R1, R2 + BEQ ZI +LoopRel:CMP R2, R3 + LDRLO R0, [R1], #4 + STRLO R0, [R2], #4 + BLO LoopRel + +ZI: +# Clear .bss section (Zero init) + MOV R0, #0 + LDR R1, =__bss_start__ + LDR R2, =__bss_end__ +LoopZI: CMP R1, R2 + STRLO R0, [R1], #4 + BLO LoopZI + + +# Enter the C _setup_board code + ADR LR, __main_start + LDR R0, =_setup_board + CMP R0, #0 + BEQ __main_start + BX R0 + +__main_start: + ADR LR, __main_exit + LDR R0, =main + BX R0 + +__main_exit: B __main_exit + + .size _start, . - _start + .endfunc + + .end diff --git a/embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile b/embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile.omk b/embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile.omk new file mode 100644 index 0000000..b0c47ee --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile.omk @@ -0,0 +1,14 @@ +# -*- makefile -*- + +lib_LIBRARIES = lpciap +lpciap_SOURCES = iap.c iap_asm.S + +include_HEADERS = lpciap.h + +ifeq ($(CONFIG_KEYVAL),y) +lib_LIBRARIES += lpciap_kvpb +lpciap_kvpb_SOURCES = iap_kvpb.c + +include_HEADERS += lpciap_kvpb.h + +endif diff --git a/embedded/arch/arm/mach-lpc21xx/libs/iap/iap.c b/embedded/arch/arm/mach-lpc21xx/libs/iap/iap.c new file mode 100644 index 0000000..cc39097 --- /dev/null +++ b/embedded/arch/arm/mach-lpc21xx/libs/iap/iap.c @@ -0,0 +1,128 @@ +#include +#include +#include + +#define IAP_PLL_FULL_SPEED 1 + +#define CMD_SUCCESS 0 +#define BUSY 11 + +#define IAP_CMD_PREPARE 50 +#define IAP_CMD_WRITE 51 +#define IAP_CMD_ERASE 52 +#define IAP_CMD_READ_PARTID 54 + +uint32_t command[5]; +uint32_t result[2]; + +extern void iap_asm_entry (unsigned int *,unsigned int *); +#define iap_entry iap_asm_entry + +#ifdef INC_LPC210x_H +inline int addr2sec(unsigned long addr) +{ + return addr/0x2000; +} +#elif defined INC_LPC214x_H || defined INC_LPC2348_H +inline int addr2sec(unsigned long addr) +{ + if (addr<0x8000) return (addr>>12); + else if (addr<0x78000) return (addr>>15)+7; + else return 22+((addr&0x7fff)>>12); +} +#else +#error "Undefined type of CPU for function addr2sec!" +#endif + +int lpcisp_read_partid() +{ + command[0] = IAP_CMD_READ_PARTID; + iap_entry(command, result); + return result[1]; +} + +int lpcisp_prepare_sectors(unsigned char start, unsigned char end) +{ + command[0] = IAP_CMD_PREPARE; + command[1] = start; + command[2] = end; + command[3] = FOSC/1000; + + iap_entry(command, result); + + return (CMD_SUCCESS == *result); +} + +int lpcisp_erase_sectors(unsigned char start, unsigned char end) +{ + command[0] = IAP_CMD_ERASE; + command[1] = start; + command[2] = end; + command[3] = FOSC/1000; + + iap_entry(command, result); + + return (CMD_SUCCESS == *result); +} + +int lpcisp_erase(void *addr, int len) +{ + int start,end; + unsigned long flags; + + start=addr2sec((unsigned long)addr); + end=addr2sec((unsigned long)addr+len-1); + + if (end +#include +#include + +unsigned long lpciap_buff[ISP_RAM2FLASH_BLOCK_SIZE/4]; +char *lpciap_addr_base=NULL; + +#define ISP_RAM2FLASH_BLOCK_SIZE_MASK (ISP_RAM2FLASH_BLOCK_SIZE-1) + +int lpcisp_kvpb_erase(struct kvpb_block *store, void *base,int size) +{ + return lpcisp_erase(base, size); +} + +int lpcisp_kvpb_flush(struct kvpb_block *store) +{ + if (lpciap_addr_base==NULL) return -1; + lpcisp_write(lpciap_addr_base,lpciap_buff,ISP_RAM2FLASH_BLOCK_SIZE); + lpciap_addr_base=NULL; + return 0; +} + +int lpcisp_kvpb_copy(struct kvpb_block *store,void *des, const void *src, int len) +{ + char *addr_base,*addr_src=(char*)src; + int cp_len; + + while(len) { + addr_base=(char*)((unsigned long)des&~ISP_RAM2FLASH_BLOCK_SIZE_MASK); + cp_len=ISP_RAM2FLASH_BLOCK_SIZE-((unsigned long)des&ISP_RAM2FLASH_BLOCK_SIZE_MASK); + if (len + +extern unsigned long lpciap_buff[ISP_RAM2FLASH_BLOCK_SIZE/4]; + +int lpcisp_kvpb_erase(struct kvpb_block *store, void *base,int size); +int lpcisp_kvpb_flush(struct kvpb_block *store); +int lpcisp_kvpb_copy(struct kvpb_block *store,void *des, const void *src, int len); + +#endif /* _LPCIAP_KVPB_ */ diff --git a/embedded/arch/generic/Makefile b/embedded/arch/generic/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/generic/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/generic/Makefile.omk b/embedded/arch/generic/Makefile.omk new file mode 100644 index 0000000..4291134 --- /dev/null +++ b/embedded/arch/generic/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = defines \ No newline at end of file diff --git a/embedded/arch/generic/defines/Makefile b/embedded/arch/generic/defines/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/arch/generic/defines/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/arch/generic/defines/Makefile.omk b/embedded/arch/generic/defines/Makefile.omk new file mode 100644 index 0000000..65c8142 --- /dev/null +++ b/embedded/arch/generic/defines/Makefile.omk @@ -0,0 +1,4 @@ +# -*- makefile -*- + +include_HEADERS += byteswap.h endian.h lt_timer.h lt_timer_types.h keyval_id_his.h +#include_HEADERS = $(notdir $(wildcard $(SOURCES_DIR)/*.h)) diff --git a/embedded/arch/generic/defines/byteswap.h b/embedded/arch/generic/defines/byteswap.h new file mode 100644 index 0000000..2324696 --- /dev/null +++ b/embedded/arch/generic/defines/byteswap.h @@ -0,0 +1,22 @@ +#ifndef _BYTESWAP_H +#define _BYTESWAP_H 1 + +#if defined(__KEIL__) +#define __bswap_16(x) ( (((x) << 8) & 0xFF00) | (((x) >> 8) & 0x00FF) ) +#else +#define __bswap_16(x) ({unsigned short __x=(x); \ + (((__x>>8)&0xff)|((__x&0xff)<<8)); }) +#endif + +#if defined(__KEIL__) + //todo +#else +#define __bswap_32(x) ({unsigned long __y=(x); \ + (__bswap_16(__y>>16)|__bswap_16(__y)<<16); }) +#endif + +#define bswap_16(x) __bswap_16 (x) + +#define bswap_32(x) __bswap_32 (x) + +#endif /* byteswap.h */ diff --git a/embedded/arch/generic/defines/endian.h b/embedded/arch/generic/defines/endian.h new file mode 100644 index 0000000..13d6d51 --- /dev/null +++ b/embedded/arch/generic/defines/endian.h @@ -0,0 +1,16 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H 1 + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 + +#if defined(__i386__) || defined(SDCC) || defined (__ARMEL__) +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif + +#if defined(__H8300__) || defined(__H8500__) || defined (__H8300H__) || defined(__W65__) || defined (__H8300S__) || defined (__m68k__) || defined (__ARMEB__) || defined(__KEIL__) +#define __BYTE_ORDER __BIG_ENDIAN +#endif + +#endif /* endian.h */ diff --git a/embedded/arch/generic/defines/keyval_id_his.h b/embedded/arch/generic/defines/keyval_id_his.h new file mode 100644 index 0000000..f07cc45 --- /dev/null +++ b/embedded/arch/generic/defines/keyval_id_his.h @@ -0,0 +1,12 @@ +#ifndef _KEYVAL_ID_HIS_H_ +#define _KEYVAL_ID_HISC_H_ + +#include "keyvalpb.h" + +#define KVPB_KEYID_BLINDER_POSSITION 0x20 +#define KVPB_KEYID_BLINDER_OPENTIME 0x21 +#define KVPB_KEYID_BLP_UP 0x22 +#define KVPB_KEYID_BLP_DOWN 0x23 + +#endif /* _KEYVAL_ID_HIS_H_ */ + diff --git a/embedded/arch/generic/defines/lt_timer.h b/embedded/arch/generic/defines/lt_timer.h new file mode 100644 index 0000000..772cf13 --- /dev/null +++ b/embedded/arch/generic/defines/lt_timer.h @@ -0,0 +1,64 @@ +#ifndef _LT_TIMER_H +#define _LT_TIMER_H + +#include +#include +#include +#include + +//timers + +#ifndef LT_TIMER_VAR_LOC +#define LT_TIMER_VAR_LOC +#endif + +static lt_ticks_t LT_TIMER_VAR_LOC last_ticks; +static lt_mstime_t LT_TIMER_VAR_LOC actual_msec; + +/* Declaration of ulan light timers */ + +#define lt_get_msbase() (1000/SYS_TIMER_HZ) /* in ms */ +#define lt_get_ticks() (get_sys_timer_ticks()) + +static inline void +lt_mstime_update() +{ + lt_ticks_t LT_TIMER_VAR_LOC act_ticks; + lt_mstime_t LT_TIMER_VAR_LOC msec_diff; + + act_ticks=lt_get_ticks(); + msec_diff=((lt_tidiff_t)(act_ticks-last_ticks))*lt_get_msbase(); + last_ticks=act_ticks; + + actual_msec+=msec_diff; +} + + +#define LT_TIMER_DEC(cust_prefix) \ +\ +extern lt_mstime_t LT_TIMER_VAR_LOC cust_prefix##_last_expired; \ +static inline void \ +cust_prefix##_init() \ +{\ + lt_mstime_update();\ + cust_prefix##_last_expired=actual_msec;\ +}\ +static inline int \ +cust_prefix##_expired(lt_mstime_t expiration) \ +{\ + lt_mstime_update();\ + \ + if ((lt_msdiff_t)(actual_msec-cust_prefix##_last_expired)>=expiration) {\ + cust_prefix##_last_expired=actual_msec;\ + return 1;\ + }\ + \ + return 0;\ +} + +#define LT_TIMER_IMP(cust_prefix) \ +\ +lt_mstime_t LT_TIMER_VAR_LOC cust_prefix##_last_expired; \ + + +#endif /* _LT_TIMER_H */ diff --git a/embedded/arch/generic/defines/lt_timer_types.h b/embedded/arch/generic/defines/lt_timer_types.h new file mode 100644 index 0000000..e7dc27c --- /dev/null +++ b/embedded/arch/generic/defines/lt_timer_types.h @@ -0,0 +1,19 @@ +#ifndef _LT_TIMER_TYPES_H +#define _LT_TIMER_TYPES_H + +//timers + +#ifdef SDCC +typedef unsigned char lt_ticks_t; +typedef char lt_tidiff_t; +typedef unsigned int lt_mstime_t; +typedef int lt_msdiff_t; +#define LT_TIMER_VAR_LOC DATA +#else +typedef unsigned int lt_ticks_t; +typedef int lt_tidiff_t; +typedef unsigned long lt_mstime_t; +typedef signed long lt_msdiff_t; +#endif + +#endif /* _LT_TIMER_TYPES_H */ diff --git a/embedded/board/Makefile b/embedded/board/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/board/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/board/Makefile.omk b/embedded/board/Makefile.omk new file mode 100644 index 0000000..ae8ebdc --- /dev/null +++ b/embedded/board/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = $(ARCH) diff --git a/embedded/board/arm/Makefile b/embedded/board/arm/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/board/arm/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/board/arm/Makefile.omk b/embedded/board/arm/Makefile.omk new file mode 100644 index 0000000..2ca7db1 --- /dev/null +++ b/embedded/board/arm/Makefile.omk @@ -0,0 +1,5 @@ +# -*- makefile -*- + +ifneq ($(wildcard $(SOURCES_DIR)/$(BOARD)),) +SUBDIRS = $(BOARD) +endif \ No newline at end of file diff --git a/embedded/board/arm/ul_usb1/Makefile b/embedded/board/arm/ul_usb1/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/board/arm/ul_usb1/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/board/arm/ul_usb1/Makefile.omk b/embedded/board/arm/ul_usb1/Makefile.omk new file mode 100644 index 0000000..dba8475 --- /dev/null +++ b/embedded/board/arm/ul_usb1/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = defines libs diff --git a/embedded/board/arm/ul_usb1/config/config.bell-keypad b/embedded/board/arm/ul_usb1/config/config.bell-keypad new file mode 100644 index 0000000..65b5279 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.bell-keypad @@ -0,0 +1,51 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 +CONFIG_BOARD_VARIANT=hisc-keypad + +CONFIG_APP_HISC_BELL_KEYPAD=y +CONFIG_OC_UL_DRV_SYSLESS=y +CONFIG_OC_UL_DRV_U450_TMELATE=y +CONFIG_ULAN_DY=y +CONFIG_ULOI_LT=y +CONFIG_KEYVAL=y +CONFIG_KBD=y + +#CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +LPC_BAUD = 38400 +TOLPC = tolpc --baud $(LPC_BAUD) --sdev /dev/ttyS0 +LOAD_CMD-ramisp = $(TOLPC) -v -q 7372 -L -f +LOAD_CMD-boot = lpc21isp -bin /dev/ttyS0 $(LPC_BAUD) 12000 + +# This selects linker script +LD_SCRIPT=lpc2148 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = bin + +PROG_BASE=0x20000 +PROG_SIZE=0x20000 + +UL_SENDHEX ?= ul_sendhex +MOD ?= 62 + +LOAD_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r -o 0 ; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -s $(PROG_BASE) -l $(PROG_SIZE) -e; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -b 256 -s $(PROG_BASE) -f binary + +RUN_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r diff --git a/embedded/board/arm/ul_usb1/config/config.garage-gate b/embedded/board/arm/ul_usb1/config/config.garage-gate new file mode 100644 index 0000000..2949391 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.garage-gate @@ -0,0 +1,50 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 +CONFIG_BOARD_VARIANT=hisc-garage-gate + +CONFIG_APP_HISC_GARAGE_GATE=y +CONFIG_OC_UL_DRV_SYSLESS=y +CONFIG_OC_UL_DRV_U450_TMELATE=y +CONFIG_ULAN_DY=y +CONFIG_ULOI_LT=y +CONFIG_KEYVAL=y + +#CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +LPC_BAUD = 38400 +TOLPC = tolpc --baud $(LPC_BAUD) --sdev /dev/ttyS0 +LOAD_CMD-ramisp = $(TOLPC) -v -q 7372 -L -f +LOAD_CMD-boot = lpc21isp -bin /dev/ttyS0 $(LPC_BAUD) 12000 + +# This selects linker script +LD_SCRIPT=lpc2148 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = bin + +PROG_BASE=0x20000 +PROG_SIZE=0x20000 + +UL_SENDHEX ?= ul_sendhex +MOD ?= 62 + +LOAD_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r -o 0 ; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -s $(PROG_BASE) -l $(PROG_SIZE) -e; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -b 256 -s $(PROG_BASE) -f binary + +RUN_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r diff --git a/embedded/board/arm/ul_usb1/config/config.ha-switch b/embedded/board/arm/ul_usb1/config/config.ha-switch new file mode 100644 index 0000000..4ed1f04 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.ha-switch @@ -0,0 +1,48 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 +CONFIG_BOARD_VARIANT=ha-switch + +CONFIG_HA_LIGHT_SWITCH=y + +CONFIG_OC_UL_DRV_SYSLESS=y +CONFIG_OC_UL_DRV_U450_VARPINS=y +CONFIG_OC_UL_DRV_U450_VARPINS_DIRNEG=y +CONFIG_OC_UL_DRV_U450_LOOPBACK=y +CONFIG_ULAN_DY=y +CONFIG_ULOI_LT=y +CONFIG_KEYVAL=y + +# CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +# This selects linker script +LD_SCRIPT=lpc2105 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = bin + +PROG_BASE=0xA000 +PROG_SIZE=0x10000 + +UL_SENDHEX ?= ul_sendhex +MOD ?= 62 + +LOAD_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r -o 0 ; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -s $(PROG_BASE) -l $(PROG_SIZE) -e; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -b 512 -s $(PROG_BASE) -f binary + +RUN_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r diff --git a/embedded/board/arm/ul_usb1/config/config.ha-switch-ulboot b/embedded/board/arm/ul_usb1/config/config.ha-switch-ulboot new file mode 100644 index 0000000..bda5aa0 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.ha-switch-ulboot @@ -0,0 +1,41 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 +CONFIG_BOARD_VARIANT=ha-switch + +CONFIG_ULBOOT=y + +CONFIG_OC_UL_DRV_SYSLESS=y +CONFIG_OC_UL_DRV_U450_VARPINS=y +CONFIG_OC_UL_DRV_U450_VARPINS_DIRNEG=y +CONFIG_OC_UL_DRV_U450_LOOPBACK=y +CONFIG_KEYVAL=y +CONFIG_ULAN_DY=y + +# CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +# This selects linker script +LD_SCRIPT=lpc2105 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = hex bin + +TOHIT=lpc21isp +DEV=/dev/ttyUSB0 +CPU_SYS_KHZ=14745 +BAUD=57600 + +LOAD_CMD-boot = \ + $(TOHIT) $(DEV) $(BAUD) $(CPU_SYS_KHZ) diff --git a/embedded/board/arm/ul_usb1/config/config.u2uv2 b/embedded/board/arm/ul_usb1/config/config.u2uv2 new file mode 100644 index 0000000..e320cf6 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.u2uv2 @@ -0,0 +1,59 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 + +CONFIG_OC_UL_DRV_SYSLESS=y +CONFIG_OC_UL_DRV_U450_VARPINS=y +CONFIG_OC_UL_DRV_U450_VARPINS_MSRSWAP=y +CONFIG_OC_UL_DRV_U450_TMELATE=y +#CONFIG_ULAN_DY=y +#CONFIG_ULOI_LT=y +#CONFIG_ULOI_GENOBJIDTAG=y +#CONFIG_KEYVAL=y +CONFIG_USB_BASE=y +CONFIG_USB_LPCUSB=y +CONFIG_USB_MORE=y +CONFIG_APP_U2U_V2=y + +#CONFIG_APP_TEST_LPC=y +#CONFIG_APP_ULAD31=y +#CONFIG_ULBOOT=y + +CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +LPC_BAUD = 38400 +TOLPC = tolpc --baud $(LPC_BAUD) --sdev /dev/ttyS0 +LOAD_CMD-ramisp = $(TOLPC) -v -q 7372 -L -f +LOAD_CMD-boot = lpc21isp -bin /dev/ttyUSB0 $(LPC_BAUD) 12000 + +# This selects linker script +LD_SCRIPT=lpc2148 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = bin + +PROG_BASE=0x20000 +PROG_SIZE=0x20000 + +UL_SENDHEX ?= ul_sendhex +MOD ?= 3 + +LOAD_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r -o 0 ; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -s $(PROG_BASE) -l $(PROG_SIZE) -e; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -b 256 -s $(PROG_BASE) -f binary + +RUN_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -g $(PROG_BASE) diff --git a/embedded/board/arm/ul_usb1/config/config.ul_usb1 b/embedded/board/arm/ul_usb1/config/config.ul_usb1 new file mode 100644 index 0000000..e0eccad --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.ul_usb1 @@ -0,0 +1,55 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 + +#CONFIG_BOARD_VARIANT=aa_rch +CONFIG_OC_UL_DRV_SYSLESS=y +CONFIG_OC_UL_DRV_U450_VARPINS=y +CONFIG_OC_UL_DRV_U450_VARPINS_MSRSWAP=y +CONFIG_OC_UL_DRV_U450_TMELATE=y +CONFIG_ULAN_DY=y +CONFIG_ULOI_LT=y +CONFIG_ULOI_GENOBJIDTAG=y +CONFIG_KEYVAL=y +CONFIG_APP_TEST_LPC=y +CONFIG_APP_ULAD31=y +CONFIG_ULBOOT=y + +CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +LPC_BAUD = 38400 +TOLPC = tolpc --baud $(LPC_BAUD) --sdev /dev/ttyS0 +LOAD_CMD-ramisp = $(TOLPC) -v -q 7372 -L -f +LOAD_CMD-boot = lpc21isp -bin /dev/ttyS0 $(LPC_BAUD) 12000 + +# This selects linker script +LD_SCRIPT=lpc2148 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = bin + +PROG_BASE=0x20000 +PROG_SIZE=0x20000 + +UL_SENDHEX ?= ul_sendhex +MOD ?= 3 + +LOAD_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -r -o 0 ; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -s $(PROG_BASE) -l $(PROG_SIZE) -e; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -b 256 -s $(PROG_BASE) -f binary + +RUN_CMD-app = \ + $(UL_SENDHEX) -m $(MOD) -g $(PROG_BASE) diff --git a/embedded/board/arm/ul_usb1/config/config.ulboot b/embedded/board/arm/ul_usb1/config/config.ulboot new file mode 100644 index 0000000..509c3d7 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.ulboot @@ -0,0 +1,45 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 + +CONFIG_ULBOOT=y +CONFIG_ULBOOT_WITH_USB=y + +CONFIG_OC_UL_DRV_SYSLESS=y +CONFIG_OC_UL_DRV_U450_VARPINS=y +CONFIG_OC_UL_DRV_U450_VARPINS_MSRSWAP=y +CONFIG_OC_UL_DRV_U450_TMELATE=y +CONFIG_KEYVAL=y +CONFIG_ULAN_DY=y + +CONFIG_USB_BASE=y +CONFIG_USB_LPCUSB=y +CONFIG_USB_MORE=y + +# CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +# This selects linker script +LD_SCRIPT=lpc2148 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = hex bin + +TOHIT=lpc21isp +DEV=/dev/ttyUSB0 +CPU_SYS_KHZ=12000 +BAUD=38400 + +LOAD_CMD-boot = \ + $(TOHIT) $(DEV) $(BAUD) $(CPU_SYS_KHZ) diff --git a/embedded/board/arm/ul_usb1/config/config.usbcan b/embedded/board/arm/ul_usb1/config/config.usbcan new file mode 100644 index 0000000..e8c9c82 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.usbcan @@ -0,0 +1,75 @@ +# -*- makefile -*- + +ARCH=arm +MACH=lpc21xx +BOARD=ul_usb1 + +#CONFIG_BOARD_VARIANT=aa_rch +#CONFIG_OC_UL_DRV_SYSLESS=y +#CONFIG_OC_UL_DRV_U450_VARPINS=y +#CONFIG_OC_UL_DRV_U450_VARPINS_MSRSWAP=y +#CONFIG_ULAN_DY=y +#CONFIG_ULOI_LT=y +#CONFIG_ULOI_GENOBJIDTAG=y +CONFIG_KEYVAL=y +#CONFIG_APP_TEST_LPC=y +#CONFIG_APP_ULAD31=y +#CONFIG_APP_TEST=y +#CONFIG_APP_USBTEST=y +#CONFIG_APP_U2U=y +#CONFIG_APP_U2U_V2=y +CONFIG_USB_BASE=y +CONFIG_USB_MORE=y +CONFIG_USB_LPCUSB=y +CONFIG_APP_USBCAN=y +#CONFIG_APP_USBBOOT=y +#CONFIG_ULBOOT=y + + +CONFIG_STDIO_COM_PORT=0 + +CROSS_COMPILE = arm-elf- +TARGET_ARCH = -mcpu=arm7tdmi + +# Set default C flags. If theese are set elsewhere (e.g. on a command +# line), these default flags are not used. +DEBUG ?= -g +OPTIMIZE ?= -O2 + +LPC_BAUD = 38400 +TOLPC = tolpc --baud $(LPC_BAUD) --sdev /dev/ttyUSB0 +LOAD_CMD-ramisp = $(TOLPC) -v -q 7372 -L -f +LOAD_CMD-boot = lpc21isp -bin /dev/ttyUSB0 $(LPC_BAUD) 12000 + +# This selects linker script +LD_SCRIPT=lpc2148 +#DEFAULT_LD_SCRIPT_VARIANT=boot + +#OUTPUT_FORMATS = bin hex srec + +OUTPUT_FORMATS = bin + +PROG_BASE=0x20000 +PROG_SIZE=0x20000 + +UL_SENDHEX ?= ul_sendhex +MOD ?= 3 + +LOAD_CMD-app-ulan = \ + $(UL_SENDHEX) -m $(MOD) -r -o 0 ; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -s $(PROG_BASE) -l $(PROG_SIZE) -e; \ + $(UL_SENDHEX) -m $(MOD) -o 0 -t 0x101 -b 256 -s $(PROG_BASE) -f binary + +RUN_CMD-app-ulan = \ + $(UL_SENDHEX) -m $(MOD) -g $(PROG_BASE) + +USB_SENDHEX ?= usb_sendhex +USB_VID ?= dead +USB_PID ?= 2263 + +LOAD_CMD-app = \ + $(USB_SENDHEX) -d $(USB_VID):$(USB_PID) -s $(PROG_BASE) -l $(PROG_SIZE) -e; sleep 2 ; \ + $(USB_SENDHEX) -d $(USB_VID):$(USB_PID) -s $(PROG_BASE) -f binary + +RUN_CMD-app = \ + $(USB_SENDHEX) -d $(USB_VID):$(USB_PID) -r diff --git a/embedded/board/arm/ul_usb1/defines/Makefile b/embedded/board/arm/ul_usb1/defines/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/board/arm/ul_usb1/defines/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/board/arm/ul_usb1/defines/Makefile.omk b/embedded/board/arm/ul_usb1/defines/Makefile.omk new file mode 100644 index 0000000..4ed4e2d --- /dev/null +++ b/embedded/board/arm/ul_usb1/defines/Makefile.omk @@ -0,0 +1,15 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_BOARD_VARIANT=x + +#include_HEADERS = $(notdir $(wildcard $(SOURCES_DIR)/*.h)) + +ifneq ($(CONFIG_BOARD_VARIANT),) + +renamed_include_HEADERS = system_def-$(CONFIG_BOARD_VARIANT).h->system_def.h + +else + +include_HEADERS = system_def.h + +endif # CONFIG_BOARD_VARIANT diff --git a/embedded/board/arm/ul_usb1/defines/system_def-ha-switch.h b/embedded/board/arm/ul_usb1/defines/system_def-ha-switch.h new file mode 100644 index 0000000..80c3ba3 --- /dev/null +++ b/embedded/board/arm/ul_usb1/defines/system_def-ha-switch.h @@ -0,0 +1,191 @@ +/******************************************************************* + Components for embedded applications builded for + laboratory and medical instruments firmware + + system_def.h - common cover for definition of hardware adresses, + registers, timing and other hardware dependant + parts of embedded hardware + + Copyright (C) 2001 by Pavel Pisa pisa@cmp.felk.cvut.cz + (C) 2002 by PiKRON Ltd. http://www.pikron.com + + *******************************************************************/ + +#ifndef _SYSTEM_DEF_H_ +#define _SYSTEM_DEF_H_ + +#include +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +#define WITH_SFI_SEL + +#define VER_CODE(major,minor,patch) (major*0x10000+minor*0x100+patch) +/* Software version */ +#define SW_VER_ID "UL_HA_SWITCH" +#define SW_VER_MAJOR 0 +#define SW_VER_MINOR 2 +#define SW_VER_PATCH 0 +#define SW_VER_CODE VER_CODE(SW_VER_MAJOR,SW_VER_MINOR,SW_VER_PATCH) +/* Hardware version */ +#define HW_VER_ID "UL_HA_SWITCH" +#define HW_VER_MAJOR 1 +#define HW_VER_MINOR 0 +#define HW_VER_PATCH 0 +#define HW_VER_CODE VER_CODE(HW_VER_MAJOR,HW_VER_MINOR,HW_VER_PATCH) +/* Version of mechanical */ +#define MECH_VER_ID "UL_HA_SWITCH" +#define MECH_VER_MAJOR 0 +#define MECH_VER_MINOR 0 +#define MECH_VER_PATCH 0 +#define MECH_VER_CODE VER_CODE(MECH_VER_MAJOR,MECH_VER_MINOR,MECH_VER_PATCH) + + +// PLL setup values are computed within the LPC include file +// It relies upon the following defines +#define FOSC (14745600) // Master Oscillator Freq. +#define PLL_MUL (4) // PLL Multiplier +#define CCLK (FOSC * PLL_MUL) // CPU Clock Freq. + +// Pheripheral Bus Speed Divider +#define PBSD 1 // MUST BE 1, 2, or 4 +#define PCLK (CCLK / PBSD) // Pheripheal Bus Clock Freq. + +#define SYS_TIMER_HZ 1000 + +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + +// Port Bit Definitions & Macros: Description - initial conditions +#define TXD0_BIT BIT(0) // used by UART0 +#define RXD0_BIT BIT(1) // used by UART0 +#define P0_02_UNUSED_BIT BIT(2) // P0.02 unused - low output +#define OUT2_BIT BIT(3) // P0.03 unused - low output +#define P0_04_UNUSED_BIT BIT(4) // P0.04 unused - low output +#define OUT1_BIT BIT(5) // P0.05 unused - low output +#define IR_BIT BIT(6) // P0.06 unused - low output +#define SPK_P_BIT BIT(7) // P0.07 unused - low output +#define TXD1_BIT BIT(8) // used by UART1 +#define RXD1_BIT BIT(9) // used by UART1 +#define RTS1_BIT BIT(10) // used by UART1 +#define CTS1_BIT BIT(11) // used by UART1 +#define DSR1_BIT BIT(12) // used by UART1 +#define LED3_BIT BIT(13) // used by LED +#define BOOT_BIT BIT(14) // SWITCH +#define IN1_BIT BIT(15) // P0.15 unused - low output +#define IN2_BIT BIT(16) // P0.16 unused - low output +#define P0_17_UNUSED_BIT BIT(17) // P0.17 unused - low output +#define P0_18_UNUSED_BIT BIT(18) // P0.18 unused - low output +#define LED4_BIT BIT(19) // used by LED +#define LED1_BIT BIT(20) // used by LED +#define LED2_BIT BIT(21) // used by LED +#define USENSE_BIT BIT(22) // P0.22 unused - low output +#define SW1_BIT BIT(23) // P0.23 unused - low output +#define SW3_BIT BIT(24) // P0.24 unused - low output +#define SW2_BIT BIT(25) // P0.25 unused - low output +#define SW4_BIT BIT(26) // P0.26 unused - low output +#define P0_27_UNUSED_BIT BIT(27) // P0.27 unused - low output +#define P0_28_UNUSED_BIT BIT(28) // P0.28 unused - low output +#define P0_29_UNUSED_BIT BIT(29) // P0.29 unused - low output +#define LED5_BIT BIT(30) // P0.30 unused - low output +#define P0_31_UNUSED_BIT BIT(31) // P0.31 unused - low output + + +#define P0IO_INPUT_BITS (uint32_t) ( \ + BOOT_BIT | \ + IR_BIT | \ + IN1_BIT | \ + IN2_BIT | \ + SW1_BIT | \ + SW2_BIT | \ + SW3_BIT | \ + SW4_BIT | \ + UNSENSE_BIT | \ + 0 ) + +#define P0IO_ZERO_BITS (uint32_t) ( \ + SPK_P_BIT | \ + OUT1_BIT | \ + OUT2_BIT | \ + LED1_BIT | \ + LED2_BIT | \ + LED3_BIT | \ + LED4_BIT | \ + LED5_BIT | \ + P0_02_UNUSED_BIT | \ + P0_04_UNUSED_BIT | \ + P0_17_UNUSED_BIT | \ + P0_18_UNUSED_BIT | \ + P0_27_UNUSED_BIT | \ + P0_28_UNUSED_BIT | \ + P0_29_UNUSED_BIT | \ + P0_31_UNUSED_BIT | \ + 0 ) + + + +#define P0IO_ONE_BITS (uint32_t) ( \ + BOOT_BIT | \ + 0 ) + +#define P0IO_OUTPUT_BITS (uint32_t) ( \ + P0IO_ZERO_BITS | \ + P0IO_ONE_BITS ) + + +/***************************************************************************/ +/* io functions */ +#define LED_GP LED1_BIT /* GENREAL PURPOSE LED */ +#define LED_ERR LED2_BIT + +/***************************************************************************/ +/* io functions */ +#define IN_PORT IO0 +#define OUT_PORT IO0 +#define LED_PORT IO0 + +#define CREATE_PORT_NAME_PIN(port) port##PIN +#define CREATE_PORT_NAME_CLR(port) port##CLR +#define CREATE_PORT_NAME_SET(port) port##SET + +#define GET_IN_PIN(port,in) ((CREATE_PORT_NAME_PIN(port) & in)?1:0) +#define SET_OUT_PIN(port,out) (CREATE_PORT_NAME_SET(port)=out) +#define CLR_OUT_PIN(port,out) (CREATE_PORT_NAME_CLR(port)=out) + +/***************************************************************************/ +/* watchdog */ +//#define WATCHDOG_ENABLED +#define WATCHDOG_TIMEOUT_MS 1000 + +/***************************************************************************/ +/* uLan configuration */ +#ifdef UL_LOG_ENABLE + #undef UL_LOG_ENABLE +#endif + +#ifdef ULD_DEFAULT_BUFFER_SIZE + #undef ULD_DEFAULT_BUFFER_SIZE + #define ULD_DEFAULT_BUFFER_SIZE 0x0400 +#endif + +#define UL_DRV_SYSLESS_PORT 0xE0010000 +#define UL_DRV_SYSLESS_BAUD 19200 +#define UL_DRV_SYSLESS_IRQ HAL_INTERRUPT_UART1 +#define UL_DRV_SYSLESS_MY_ADR_DEFAULT 1 + + +#define watchdog_feed lpc_watchdog_feed +#define kvpb_erase lpcisp_kvpb_erase +#define kvpb_copy lpcisp_kvpb_copy +#define kvpb_flush lpcisp_kvpb_flush +#define KVPB_DEFAULT_FLAGS KVPB_DESC_DOUBLE|KVPB_DESC_CHUNKWO + +#define HAL_ARM_LPC2XXX_EXTINT_ERRATA + +#endif /* _SYSTEM_DEF_H_ */ diff --git a/embedded/board/arm/ul_usb1/defines/system_def-hisc-garage-gate.h b/embedded/board/arm/ul_usb1/defines/system_def-hisc-garage-gate.h new file mode 100644 index 0000000..250d27b --- /dev/null +++ b/embedded/board/arm/ul_usb1/defines/system_def-hisc-garage-gate.h @@ -0,0 +1,239 @@ +/******************************************************************* + Components for embedded applications builded for + laboratory and medical instruments firmware + + system_def.h - common cover for definition of hardware adresses, + registers, timing and other hardware dependant + parts of embedded hardware + + Copyright (C) 2001 by Pavel Pisa pisa@cmp.felk.cvut.cz + (C) 2002 by PiKRON Ltd. http://www.pikron.com + + *******************************************************************/ + +#ifndef _SYSTEM_DEF_H_ +#define _SYSTEM_DEF_H_ + +#include +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +#define WITH_SFI_SEL + +#define VER_CODE(major,minor,patch) (major*0x10000+minor*0x100+patch) +/* Software version */ +#define SW_VER_ID "UL_USB" +#define SW_VER_MAJOR 0 +#define SW_VER_MINOR 2 +#define SW_VER_PATCH 0 +#define SW_VER_CODE VER_CODE(SW_VER_MAJOR,SW_VER_MINOR,SW_VER_PATCH) +/* Hardware version */ +#define HW_VER_ID "UL_USB" +#define HW_VER_MAJOR 1 +#define HW_VER_MINOR 0 +#define HW_VER_PATCH 0 +#define HW_VER_CODE VER_CODE(HW_VER_MAJOR,HW_VER_MINOR,HW_VER_PATCH) +/* Version of mechanical */ +#define MECH_VER_ID "UL_USB" +#define MECH_VER_MAJOR 0 +#define MECH_VER_MINOR 0 +#define MECH_VER_PATCH 0 +#define MECH_VER_CODE VER_CODE(MECH_VER_MAJOR,MECH_VER_MINOR,MECH_VER_PATCH) + + +// PLL setup values are computed within the LPC include file +// It relies upon the following defines +#define FOSC (14745600) // Master Oscillator Freq. +#define PLL_MUL (4) // PLL Multiplier +#define CCLK (FOSC * PLL_MUL) // CPU Clock Freq. + +// Pheripheral Bus Speed Divider +#define PBSD 1 // MUST BE 1, 2, or 4 +#define PCLK (CCLK / PBSD) // Pheripheal Bus Clock Freq. + +#define SYS_TIMER_HZ 1000 + +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + +// Port Bit Definitions & Macros: Description - initial conditions +#define TXD0_BIT BIT(0) // used by UART0 +#define RXD0_BIT BIT(1) // used by UART0 +#define P0_02_UNUSED_BIT BIT(2) // P0.02 unused - low output +#define P0_03_UNUSED_BIT BIT(3) // P0.03 unused - low output +#define P0_04_UNUSED_BIT BIT(4) // P0.04 unused - low output +#define P0_05_UNUSED_BIT BIT(5) // P0.05 unused - low output +#define P0_06_UNUSED_BIT BIT(6) // P0.06 unused - low output +#define P0_07_UNUSED_BIT BIT(7) // P0.07 unused - low output +#define TXD1_BIT BIT(8) // used by UART1 +#define RXD1_BIT BIT(9) // used by UART1 +#define RTS1_BIT BIT(10) // used by UART1 +#define CTS1_BIT BIT(11) // used by UART1 +#define DSR1_BIT BIT(12) // used by UART1 +#define P0_13_UNUSED_BIT BIT(13) // P0.13 unused - low output +#define BOOT_BIT BIT(14) // SWITCH +#define P0_15_UNUSED_BIT BIT(15) // P0.15 unused - low output +#define P0_16_UNUSED_BIT BIT(16) // P0.16 unused - low output +#define P0_17_UNUSED_BIT BIT(17) // P0.17 unused - low output +#define P0_18_UNUSED_BIT BIT(18) // P0.18 unused - low output +#define P0_19_UNUSED_BIT BIT(19) // P0.19 unused - low output +#define P0_20_UNUSED_BIT BIT(20) // P0.20 unused - low output +#define LED1_BIT BIT(21) // used by LED +#define LED2_BIT BIT(22) // used by LED +#define P0_23_UNUSED_BIT BIT(23) // P0.23 unused - low output +#define P0_24_UNUSED_BIT BIT(24) // P0.24 unused - low output +#define P0_25_UNUSED_BIT BIT(25) // P0.25 unused - low output +#define P0_26_UNUSED_BIT BIT(26) // P0.26 unused - low output +#define P0_27_UNUSED_BIT BIT(27) // P0.27 unused - low output +#define P0_28_UNUSED_BIT BIT(28) // P0.28 unused - low output +#define P0_29_UNUSED_BIT BIT(29) // P0.29 unused - low output +#define P0_30_UNUSED_BIT BIT(30) // P0.30 unused - low output +#define P0_31_UNUSED_BIT BIT(31) // P0.31 unused - low output + + +#define P1_16_UNUSED_BIT BIT(16) // P1.16 unused - low output +#define P1_17_UNUSED_BIT BIT(17) // P1.17 unused - low output +#define P1_18_UNUSED_BIT BIT(18) // P1.18 unused - low output +#define P1_19_UNUSED_BIT BIT(19) // P1.19 unused - low output +#define P1_20_UNUSED_BIT BIT(20) // P1.20 unused - low output +#define P1_21_UNUSED_BIT BIT(21) // P1.21 unused - low output +#define P1_22_UNUSED_BIT BIT(22) // P1.22 unused - low output +#define P1_23_UNUSED_BIT BIT(23) // P1.23 unused - low output +#define P1_24_UNUSED_BIT BIT(24) // P1.24 unused - low output +#define P1_25_UNUSED_BIT BIT(25) // P1.25 unused - low output +#define P1_26_GATE BIT(26) // used by JTAG +#define P1_27_UNUSED_BIT BIT(27) // used by JTAG +#define P1_28_UNUSED_BIT BIT(28) // used by JTAG +#define P1_29_UNUSED_BIT BIT(29) // used by JTAG +#define P1_30_UNUSED_BIT BIT(30) // used by JTAG +#define P1_31_UNUSED_BIT BIT(31) // used by JTAG + +#define P0IO_INPUT_BITS (uint32_t) ( \ + BOOT_BIT | \ + 0 ) + +#define P1IO_INPUT_BITS (uint32_t) ( \ + 0 ) + +#define P0IO_ZERO_BITS (uint32_t) ( \ + P0_02_UNUSED_BIT | \ + P0_03_UNUSED_BIT | \ + P0_04_UNUSED_BIT | \ + P0_05_UNUSED_BIT | \ + P0_06_UNUSED_BIT | \ + P0_07_UNUSED_BIT | \ + P0_13_UNUSED_BIT | \ + P0_15_UNUSED_BIT | \ + P0_16_UNUSED_BIT | \ + P0_17_UNUSED_BIT | \ + P0_18_UNUSED_BIT | \ + P0_19_UNUSED_BIT | \ + P0_20_UNUSED_BIT | \ + P0_23_UNUSED_BIT | \ + P0_24_UNUSED_BIT | \ + P0_25_UNUSED_BIT | \ + P0_26_UNUSED_BIT | \ + P0_27_UNUSED_BIT | \ + P0_28_UNUSED_BIT | \ + P0_29_UNUSED_BIT | \ + P0_30_UNUSED_BIT | \ + P0_31_UNUSED_BIT | \ + 0 ) + +#define P1IO_ZERO_BITS (uint32_t) ( \ + P1_16_UNUSED_BIT | \ + P1_17_UNUSED_BIT | \ + P1_18_UNUSED_BIT | \ + P1_19_UNUSED_BIT | \ + P1_20_UNUSED_BIT | \ + P1_21_UNUSED_BIT | \ + P1_22_UNUSED_BIT | \ + P1_23_UNUSED_BIT | \ + P1_24_UNUSED_BIT | \ + P1_25_UNUSED_BIT | \ + P1_27_UNUSED_BIT | \ + P1_28_UNUSED_BIT | \ + P1_29_UNUSED_BIT | \ + P1_30_UNUSED_BIT | \ + P1_31_UNUSED_BIT | \ + 0 ) + + +#define P0IO_ONE_BITS (uint32_t) ( \ + LED1_BIT | \ + BOOT_BIT | \ + LED2_BIT | \ + 0 ) + +#define P1IO_ONE_BITS (uint32_t) ( \ + P1_26_GATE | \ + 0 ) + +#define P0IO_OUTPUT_BITS (uint32_t) ( \ + P0IO_ZERO_BITS | \ + P0IO_ONE_BITS ) + +#define P1IO_OUTPUT_BITS (uint32_t) ( \ + P1IO_ZERO_BITS | \ + P1IO_ONE_BITS ) + + +/***************************************************************************/ +/* io functions */ +#define LED_GP LED1_BIT /* GENREAL PURPOSE LED */ +#define LED_ERR LED2_BIT + +#define LED_YELLOW LED1_BIT +#define LED_RED LED2_BIT + +/***************************************************************************/ +/* io functions */ +#define KBD_PORT IO1 +#define IN_PORT IO0 +#define LED_PORT IO0 +#define OUT_PORT IO1 + +#define CREATE_PORT_NAME_PIN(port) port##PIN +#define CREATE_PORT_NAME_CLR(port) port##CLR +#define CREATE_PORT_NAME_SET(port) port##SET + +#define GET_IN_PIN(port,in) ((CREATE_PORT_NAME_PIN(port) & in)?1:0) +#define SET_OUT_PIN(port,out) (CREATE_PORT_NAME_SET(port)=out) +#define CLR_OUT_PIN(port,out) (CREATE_PORT_NAME_CLR(port)=out) + +/***************************************************************************/ +/* watchdog */ +#define WATCHDOG_ENABLED +#define WATCHDOG_TIMEOUT_MS 1000 + +/***************************************************************************/ +/* uLan configuration */ +#ifdef UL_LOG_ENABLE + #undef UL_LOG_ENABLE +#endif + +#ifdef ULD_DEFAULT_BUFFER_SIZE + #undef ULD_DEFAULT_BUFFER_SIZE + #define ULD_DEFAULT_BUFFER_SIZE 0x0800 +#endif + +#define UL_DRV_SYSLESS_PORT 0xE0010000 +#define UL_DRV_SYSLESS_BAUD 19200 +#define UL_DRV_SYSLESS_IRQ HAL_INTERRUPT_UART1 +#define UL_DRV_SYSLESS_MY_ADR_DEFAULT 1 + +#define watchdog_feed lpc_watchdog_feed +#define kvpb_erase lpcisp_kvpb_erase +#define kvpb_copy lpcisp_kvpb_copy +#define kvpb_flush lpcisp_kvpb_flush +#define KVPB_DEFAULT_FLAGS KVPB_DESC_DOUBLE|KVPB_DESC_CHUNKWO + +#define HAL_ARM_LPC2XXX_EXTINT_ERRATA + +#endif /* _SYSTEM_DEF_H_ */ diff --git a/embedded/board/arm/ul_usb1/defines/system_def-hisc-keypad.h b/embedded/board/arm/ul_usb1/defines/system_def-hisc-keypad.h new file mode 100644 index 0000000..09a90c5 --- /dev/null +++ b/embedded/board/arm/ul_usb1/defines/system_def-hisc-keypad.h @@ -0,0 +1,276 @@ +/******************************************************************* + Components for embedded applications builded for + laboratory and medical instruments firmware + + system_def.h - common cover for definition of hardware adresses, + registers, timing and other hardware dependant + parts of embedded hardware + + Copyright (C) 2001 by Pavel Pisa pisa@cmp.felk.cvut.cz + (C) 2002 by PiKRON Ltd. http://www.pikron.com + + *******************************************************************/ + +#ifndef _SYSTEM_DEF_H_ +#define _SYSTEM_DEF_H_ + +#include +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +#define WITH_SFI_SEL + +#define VER_CODE(major,minor,patch) (major*0x10000+minor*0x100+patch) +/* Software version */ +#define SW_VER_ID "UL_USB" +#define SW_VER_MAJOR 0 +#define SW_VER_MINOR 2 +#define SW_VER_PATCH 0 +#define SW_VER_CODE VER_CODE(SW_VER_MAJOR,SW_VER_MINOR,SW_VER_PATCH) +/* Hardware version */ +#define HW_VER_ID "UL_USB" +#define HW_VER_MAJOR 1 +#define HW_VER_MINOR 0 +#define HW_VER_PATCH 0 +#define HW_VER_CODE VER_CODE(HW_VER_MAJOR,HW_VER_MINOR,HW_VER_PATCH) +/* Version of mechanical */ +#define MECH_VER_ID "UL_USB" +#define MECH_VER_MAJOR 0 +#define MECH_VER_MINOR 0 +#define MECH_VER_PATCH 0 +#define MECH_VER_CODE VER_CODE(MECH_VER_MAJOR,MECH_VER_MINOR,MECH_VER_PATCH) + + +// PLL setup values are computed within the LPC include file +// It relies upon the following defines +#define FOSC (14745600) // Master Oscillator Freq. +#define PLL_MUL (4) // PLL Multiplier +#define CCLK (FOSC * PLL_MUL) // CPU Clock Freq. + +// Pheripheral Bus Speed Divider +#define PBSD 1 // MUST BE 1, 2, or 4 +#define PCLK (CCLK / PBSD) // Pheripheal Bus Clock Freq. + +#define SYS_TIMER_HZ 1000 + +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + +// Port Bit Definitions & Macros: Description - initial conditions +#define TXD0_BIT BIT(0) // used by UART0 +#define RXD0_BIT BIT(1) // used by UART0 +#define P0_02_UNUSED_BIT BIT(2) // P0.02 unused - low output +#define P0_03_UNUSED_BIT BIT(3) // P0.03 unused - low output +#define P0_04_UNUSED_BIT BIT(4) // P0.04 unused - low output +#define P0_05_UNUSED_BIT BIT(5) // P0.05 unused - low output +#define IP1_BIT BIT(6) // P0.06 unused - low output +#define IP2_BIT BIT(7) // P0.07 unused - low output +#define TXD1_BIT BIT(8) // used by UART1 +#define RXD1_BIT BIT(9) // used by UART1 +#define RTS1_BIT BIT(10) // used by UART1 +#define CTS1_BIT BIT(11) // used by UART1 +#define DSR1_BIT BIT(12) // used by UART1 +#define P0_13_UNUSED_BIT BIT(13) // P0.13 unused - low output +#define BOOT_BIT BIT(14) // SWITCH +#define P0_15_UNUSED_BIT BIT(15) // P0.15 unused - low output +#define P0_16_UNUSED_BIT BIT(16) // P0.16 unused - low output +#define P0_17_UNUSED_BIT BIT(17) // P0.17 unused - low output +#define P0_18_UNUSED_BIT BIT(18) // P0.18 unused - low output +#define P0_19_UNUSED_BIT BIT(19) // P0.19 unused - low output +#define P0_20_UNUSED_BIT BIT(20) // P0.20 unused - low output +#define LED1_BIT BIT(21) // used by LED +#define LED2_BIT BIT(22) // used by LED +#define P0_23_UNUSED_BIT BIT(23) // P0.23 unused - low output +#define P0_24_UNUSED_BIT BIT(24) // P0.24 unused - low output +#define P0_25_UNUSED_BIT BIT(25) // P0.25 unused - low output +#define P0_26_UNUSED_BIT BIT(26) // P0.26 unused - low output +#define P0_27_UNUSED_BIT BIT(27) // P0.27 unused - low output +#define P0_28_UNUSED_BIT BIT(28) // P0.28 unused - low output +#define P0_29_SOUND BIT(29) // P0.29 unused - low output +#define P0_30_LED_R BIT(30) // P0.30 unused - low output +#define P0_31_LED_G BIT(31) // P0.31 unused - low output + + +#define P1_16_RELE BIT(16) // P1.16 unused - low output +#define P1_17_UNUSED_BIT BIT(17) // P1.17 unused - low output +#define P1_18_UNUSED_BIT BIT(18) // P1.18 unused - low output +#define P1_19_UNUSED_BIT BIT(19) // P1.19 unused - low output +#define P1_20_UNUSED_BIT BIT(20) // P1.20 unused - low output +#define P1_21_UNUSED_BIT BIT(21) // P1.21 unused - low output +#define P1_22_UNUSED_BIT BIT(22) // P1.22 unused - low output +#define P1_23_UNUSED_BIT BIT(23) // P1.23 unused - low output +#define P1_24_COL369H BIT(24) // P1.24 unused - low output +#define P1_25_COL2580 BIT(25) // P1.25 unused - low output +#define P1_26_COL147S BIT(26) // used by JTAG +#define P1_27_ROW123 BIT(27) // used by JTAG +#define P1_28_ROW456 BIT(28) // used by JTAG +#define P1_29_ROW789 BIT(29) // used by JTAG +#define P1_30_ROWS0H BIT(30) // used by JTAG +#define P1_31_RING BIT(31) // used by JTAG + +#define P0IO_INPUT_BITS (uint32_t) ( \ + BOOT_BIT | \ + IP1_BIT | \ + IP2_BIT | \ + 0 ) + +#define P1IO_INPUT_BITS (uint32_t) ( \ + P1_27_ROW123 | \ + P1_28_ROW456 | \ + P1_29_ROW789 | \ + P1_30_ROWS0H | \ + P1_31_RING | \ + 0 ) + +#define P0IO_ZERO_BITS (uint32_t) ( \ + P0_02_UNUSED_BIT | \ + P0_03_UNUSED_BIT | \ + P0_04_UNUSED_BIT | \ + P0_05_UNUSED_BIT | \ + P0_13_UNUSED_BIT | \ + P0_15_UNUSED_BIT | \ + P0_16_UNUSED_BIT | \ + P0_17_UNUSED_BIT | \ + P0_18_UNUSED_BIT | \ + P0_19_UNUSED_BIT | \ + P0_20_UNUSED_BIT | \ + P0_23_UNUSED_BIT | \ + P0_24_UNUSED_BIT | \ + P0_25_UNUSED_BIT | \ + P0_26_UNUSED_BIT | \ + P0_27_UNUSED_BIT | \ + P0_28_UNUSED_BIT | \ + P0_29_SOUND | \ + 0 ) + +#define P1IO_ZERO_BITS (uint32_t) ( \ + P1_16_RELE | \ + P1_17_UNUSED_BIT | \ + P1_18_UNUSED_BIT | \ + P1_19_UNUSED_BIT | \ + P1_20_UNUSED_BIT | \ + P1_21_UNUSED_BIT | \ + P1_22_UNUSED_BIT | \ + P1_23_UNUSED_BIT | \ + 0 ) + + +#define P0IO_ONE_BITS (uint32_t) ( \ + LED1_BIT | \ + BOOT_BIT | \ + LED2_BIT | \ + P0_30_LED_R | \ + P0_31_LED_G | \ + 0 ) + +#define P1IO_ONE_BITS (uint32_t) ( \ + P1_24_COL369H | \ + P1_25_COL2580 | \ + P1_26_COL147S | \ + 0 ) + +#define P0IO_OUTPUT_BITS (uint32_t) ( \ + P0IO_ZERO_BITS | \ + P0IO_ONE_BITS ) + +#define P1IO_OUTPUT_BITS (uint32_t) ( \ + P1IO_ZERO_BITS | \ + P1IO_ONE_BITS ) + + +/***************************************************************************/ +/* io functions */ +#define LED_GP LED1_BIT /* GENREAL PURPOSE LED */ +#define LED_ERR LED2_BIT + +#define LED_YELLOW LED1_BIT +#define LED_RED LED2_BIT +#define LED_KEYPAD_RED P0_30_LED_R +#define LED_KEYPAD_YELLOW P0_31_LED_G + +/***************************************************************************/ +/* io functions */ +#define KBD_PORT IO1 +#define IN_PORT IO0 +#define LED_PORT IO0 +#define OUT_PORT IO1 + +#define CREATE_PORT_NAME_PIN(port) port##PIN +#define CREATE_PORT_NAME_CLR(port) port##CLR +#define CREATE_PORT_NAME_SET(port) port##SET + +#define GET_IN_PIN(port,in) ((CREATE_PORT_NAME_PIN(port) & in)?1:0) +#define SET_OUT_PIN(port,out) (CREATE_PORT_NAME_SET(port)=out) +#define CLR_OUT_PIN(port,out) (CREATE_PORT_NAME_CLR(port)=out) + +/***************************************************************************/ +/* watchdog */ +#define WATCHDOG_ENABLED +#define WATCHDOG_TIMEOUT_MS 1000 + +/***************************************************************************/ +/* uLan configuration */ +#ifdef UL_LOG_ENABLE + #undef UL_LOG_ENABLE +#endif + +#ifdef ULD_DEFAULT_BUFFER_SIZE + #undef ULD_DEFAULT_BUFFER_SIZE + #define ULD_DEFAULT_BUFFER_SIZE 0x0800 +#endif + +#define UL_DRV_SYSLESS_PORT 0xE0010000 +#define UL_DRV_SYSLESS_BAUD 19200 +#define UL_DRV_SYSLESS_IRQ HAL_INTERRUPT_UART1 +#define UL_DRV_SYSLESS_MY_ADR_DEFAULT 1 + +#define watchdog_feed lpc_watchdog_feed +#define kvpb_erase lpcisp_kvpb_erase +#define kvpb_copy lpcisp_kvpb_copy +#define kvpb_flush lpcisp_kvpb_flush +#define KVPB_DEFAULT_FLAGS KVPB_DESC_DOUBLE|KVPB_DESC_CHUNKWO + +#define HAL_ARM_LPC2XXX_EXTINT_ERRATA + +/***************************************************************************/ +/* kbd */ +#define KEY_TIMER sys_timer_ticks +#define KBDDEVICE void + +typedef unsigned short kbd_key_t; +typedef unsigned int kbd_keymod_t; +typedef long kbd_interval_t; +typedef unsigned short kbd_scan_code_t; + +#define KEY_DEFAULT_TIMES +#define KEY_PUSH_T 70 +#define KEY_RELEASE_T 50 +#define KEY_REPFIRST_T 60000 +#define KEY_REPNEXT_T 300 + +#define KBD_DR _reg_PTD_DR +#define KBD_SSR IO1PIN +#define KBD_DDIR _reg_PTD_DDIR +#define KBD_PUEN _reg_PTD_PUEN + +typedef unsigned long kbdisr_lock_level_t; +#define kbdisr_lock save_and_cli +#define kbdisr_unlock restore_flags + +#define KBD_SCAN_CNT 3 +#define KBD_SCAN_BIT0 24 +#define KBD_RET_CNT 5 +#define KBD_RET_BIT0 27 + +#define KBD_SCAN_MASK (((1< +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +#define WITH_SFI_SEL + +#define VER_CODE(major,minor,patch) (major*0x10000+minor*0x100+patch) +/* Software version */ +#define SW_VER_ID "UL_USB" +#define SW_VER_MAJOR 0 +#define SW_VER_MINOR 2 +#define SW_VER_PATCH 0 +#define SW_VER_CODE VER_CODE(SW_VER_MAJOR,SW_VER_MINOR,SW_VER_PATCH) +/* Hardware version */ +#define HW_VER_ID "UL_USB" +#define HW_VER_MAJOR 1 +#define HW_VER_MINOR 0 +#define HW_VER_PATCH 0 +#define HW_VER_CODE VER_CODE(HW_VER_MAJOR,HW_VER_MINOR,HW_VER_PATCH) +/* Version of mechanical */ +#define MECH_VER_ID "UL_USB" +#define MECH_VER_MAJOR 0 +#define MECH_VER_MINOR 0 +#define MECH_VER_PATCH 0 +#define MECH_VER_CODE VER_CODE(MECH_VER_MAJOR,MECH_VER_MINOR,MECH_VER_PATCH) + + +// PLL setup values are computed within the LPC include file +// It relies upon the following defines +//#define FOSC (11059200) // Master Oscillator Freq. +#define FOSC (12000000) // Master Oscillator Freq. +#define PLL_MUL (4) // PLL Multiplier +#define CCLK (FOSC * PLL_MUL) // CPU Clock Freq. + +// Pheripheral Bus Speed Divider +#define PBSD 1 // MUST BE 1, 2, or 4 +#define PCLK (CCLK / PBSD) // Pheripheal Bus Clock Freq. + +#define SYS_TIMER_HZ 1000 + +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + +// Port Bit Definitions & Macros: Description - initial conditions +#define TXD0_BIT BIT(0) // used by UART0 +#define RXD0_BIT BIT(1) // used by UART0 +#define P0_SCL0_PIN BIT(2) // I2C 0 SCL +#define P0_SDA0_PIN BIT(3) // I2C 0 SDA +#define P0_SCK0_PIN BIT(4) // SPI0 clocks +#define P0_MISO0_PIN BIT(5) // SPI0 master input +#define P0_MOSI0_PIN BIT(6) // SPI0 master output +#define P0_SSEL0_PIN BIT(7) // SPI0 external select/ADS1218 DRDY +#define TXD1_BIT BIT(8) // used by UART1 +#define RXD1_BIT BIT(9) // used by UART1 +#define RTS1_BIT BIT(10) // used by UART1 +#define CTS1_BIT BIT(11) // used by UART1 +#define DSR1_BIT BIT(12) // used by UART1 +#define LED2_BIT BIT(13) // used by LED +#define BOOT_BIT BIT(14) // SWITCH +#define LED1_BIT BIT(15) // used by LED +#define P0_SWITCH1_PIN BIT(16) // pin connected to the switch 1 +#define P0_SCK1_PIN BIT(17) // SPI1 clocks +#define P0_MISO1_PIN BIT(18) // SPI1 master input +#define P0_MOSI1_PIN BIT(19) // SPI1 master output +#define P0_SSEL1_PIN BIT(20) // SPI1 slave select/25VF016 chipselect +#define P0_21_UNUSED_BIT BIT(21) // P0.21 unused - low output +#define P0_22_UNUSED_BIT BIT(22) // P0.22 unused - low output +#define P0_SJA1000_ALE_PIN BIT(23) // SJA1000 ALE +#define P0_24_UNUSED_BIT BIT(24) // P0.24 unused - low output +#define P0_SJA1000_CS_PIN BIT(25) // SJA1000 CS +#define P0_26_UNUSED_BIT BIT(26) // P0.26 unused - low output +#define P0_27_UNUSED_BIT BIT(27) // P0.27 unused - low output +#define P0_SJA1000_RD_PIN BIT(28) // SJA1000 RD +#define P0_SJA1000_WR_PIN BIT(29) // SJA1000 WR +#define P0_SJA1000_INT_PIN BIT(30) // SJA1000 INT +#define P0_USB_CONNECT_PIN BIT(31) // USB Connect Control + +#define P1_SJA1000_D0_PIN BIT(16) // SJA1000 D0 +#define P1_SJA1000_D1_PIN BIT(17) // SJA1000 D1 +#define P1_SJA1000_D2_PIN BIT(18) // SJA1000 D2 +#define P1_SJA1000_D3_PIN BIT(19) // SJA1000 D3 +#define P1_SJA1000_D4_PIN BIT(20) // SJA1000 D4 +#define P1_SJA1000_D5_PIN BIT(21) // SJA1000 D5 +#define P1_SJA1000_D6_PIN BIT(22) // SJA1000 D6 +#define P1_SJA1000_D7_PIN BIT(23) // SJA1000 D7 +#define P1_OUT_PORT_CS_PIN BIT(24) // Chip select for 74HC574 chip +#define P1_SJA1000_RST_PIN BIT(25) // SJA1000 RST +#define P1_26_UNUSED_BIT BIT(26) // used by JTAG +#define P1_27_UNUSED_BIT BIT(27) // used by JTAG +#define P1_28_UNUSED_BIT BIT(28) // used by JTAG +#define P1_29_UNUSED_BIT BIT(29) // used by JTAG +#define P1_30_UNUSED_BIT BIT(30) // used by JTAG +#define P1_31_UNUSED_BIT BIT(31) // used by JTAG + +#define P1_SJA1000_DATA_PINS (uint32_t) ( \ + P1_SJA1000_D0_PIN | \ + P1_SJA1000_D1_PIN | \ + P1_SJA1000_D2_PIN | \ + P1_SJA1000_D3_PIN | \ + P1_SJA1000_D4_PIN | \ + P1_SJA1000_D5_PIN | \ + P1_SJA1000_D6_PIN | \ + P1_SJA1000_D7_PIN | \ + 0 ) + +#define P0IO_INPUT_BITS (uint32_t) ( \ + P0_SCL0_PIN | \ + P0_SDA0_PIN | \ + P0_MISO0_PIN | \ + P0_SSEL0_PIN | \ + P0_MISO1_PIN | \ + BOOT_BIT | \ + P0_SWITCH1_PIN | \ + P0_SJA1000_INT_PIN | \ + 0 ) + +#define P1IO_INPUT_BITS (uint32_t) ( \ + P1_26_UNUSED_BIT | \ + P1_27_UNUSED_BIT | \ + P1_28_UNUSED_BIT | \ + P1_29_UNUSED_BIT | \ + P1_30_UNUSED_BIT | \ + P1_31_UNUSED_BIT | \ + 0 ) + +#define P0IO_ZERO_BITS (uint32_t) ( \ + P0_21_UNUSED_BIT | \ + P0_22_UNUSED_BIT | \ + P0_24_UNUSED_BIT | \ + P0_26_UNUSED_BIT | \ + P0_27_UNUSED_BIT | \ + P0_USB_CONNECT_PIN | \ + 0 ) + +#define P1IO_ZERO_BITS (uint32_t) ( \ + P1_SJA1000_DATA_PINS | \ + P1_SJA1000_RST_PIN | \ + 0 ) + + +#define P0IO_ONE_BITS (uint32_t) ( \ + P0_SCK0_PIN | \ + P0_MOSI0_PIN | \ + LED1_BIT | \ + BOOT_BIT | \ + LED2_BIT | \ + P0_SCK1_PIN | \ + P0_MOSI1_PIN | \ + P0_SSEL1_PIN | \ + P0_SJA1000_ALE_PIN | \ + P0_SJA1000_CS_PIN | \ + P0_SJA1000_RD_PIN | \ + P0_SJA1000_WR_PIN | \ + 0 ) + +#define P1IO_ONE_BITS (uint32_t) ( \ + P1_OUT_PORT_CS_PIN | \ + 0 ) + +#define P0IO_OUTPUT_BITS (uint32_t) ( \ + P0IO_ZERO_BITS | \ + P0IO_ONE_BITS ) + +#define P1IO_OUTPUT_BITS (uint32_t) ( \ + P1IO_ZERO_BITS | \ + P1IO_ONE_BITS ) + +/***************************************************************************/ +/* io functions */ +#define LED_GP LED1_BIT /* GENREAL PURPOSE LED */ +#define LED_ERR LED2_BIT + +#define LED_YELLOW LED1_BIT +#define LED_RED LED2_BIT + +/***************************************************************************/ +/* io functions */ +#define IN_PORT IO0 +#define LED_PORT IO0 +#define OUT_PORT IO1 + +#define CREATE_PORT_NAME_PIN(port) port##PIN +#define CREATE_PORT_NAME_CLR(port) port##CLR +#define CREATE_PORT_NAME_SET(port) port##SET + +#define GET_IN_PIN(port,in) ((CREATE_PORT_NAME_PIN(port) & in)?1:0) +#define SET_OUT_PIN(port,out) (CREATE_PORT_NAME_SET(port)=out) +#define CLR_OUT_PIN(port,out) (CREATE_PORT_NAME_CLR(port)=out) + +/***************************************************************************/ +/* watchdog */ +//#define WATCHDOG_ENABLED +#define WATCHDOG_TIMEOUT_MS 1000 + +/***************************************************************************/ +/* uLan configuration */ + +#ifdef UL_LOG_ENABLE + #undef UL_LOG_ENABLE +#endif + +#ifdef ULD_DEFAULT_BUFFER_SIZE + #undef ULD_DEFAULT_BUFFER_SIZE + #define ULD_DEFAULT_BUFFER_SIZE 0x0800 +#endif + +#define UL_DRV_SYSLESS_PORT 0xE0010000 +#define UL_DRV_SYSLESS_BAUD 19200 +#define UL_DRV_SYSLESS_IRQ HAL_INTERRUPT_UART1 +#define UL_DRV_SYSLESS_MY_ADR_DEFAULT 1 + +#define watchdog_feed lpc_watchdog_feed +#define kvpb_erase lpcisp_kvpb_erase +#define kvpb_copy lpcisp_kvpb_copy +#define kvpb_flush lpcisp_kvpb_flush +#define KVPB_DEFAULT_FLAGS KVPB_DESC_DOUBLE|KVPB_DESC_CHUNKWO + +/***************************************************************************/ +/* USB configuration */ +#define USB_WITH_UDEV_FNC +#define USB_EP_NUM 32 +#define USB_MAX_PACKET0 64 +#define USB_MAX_PACKET 8 +#define USB_DMA_EP 0x00000000 + +/***************************************************************************/ +/* i2c0 configuration */ +#define I2C_DRV_SYSLESS_IRQ HAL_INTERRUPT_I2C0 +#define I2C_DRV_SYSLESS_PORT 0xE001C000 +#define I2C_DRV_SYSLESS_BITRATE 100000 +#define I2C_DRV_SYSLESS_SLADR 0 + +/***************************************************************************/ +/* Constants for JTAG and supply control port pins: */ +#define JTAGIN (IO0PIN) // Control ports are on P5.x +#define JTAGSET (IO0SET) +#define JTAGCLR (IO0CLR) +#define JTAGDIR (IO0DIR) +#define JTAGOUT_RDBACK (IO0PIN) // used to read actual TCLK output value +#undef JTAGSEL +#define TMS_PIN (1<<20) // P0.20 JTAG TMS input pin +#define TDI_PIN (1<<19) // P0.19 JTAG TDI input pin (SIMO1 if SPI mode) +#define TDO_PIN (1<<18) // P0.18 JTAG TDO output pin (SOMI1 if SPI mode) +#define TCK_PIN (1<<17) // P0.17 JTAG TCK input pin (UCLK1 if SPI mode) +#define TDICTRL2_PIN 0 // Px.x switch TDO to TDI +#define TDICTRL1_PIN 0 // Px.x connects TDI +#define TEST_PIN 0 // Px.x TEST pin (20 & 28-pin devices only) +#define VCCTGT_PIN 0 // Px.x Supply voltage of target board +#define TCLK_PIN TDI_PIN // P7.3 TDI (former XOUT) receives TCLK + +#define ClrTMS() do {(JTAGCLR) |= (TMS_PIN);} while(0); +#define SetTMS() do {(JTAGSET) |= (TMS_PIN);} while(0); +#define ClrTDI() do {(JTAGCLR) |= (TDI_PIN);} while(0); +#define SetTDI() do {(JTAGSET) |= (TDI_PIN);} while(0); +#define ClrTCK() do {(JTAGCLR) |= (TCK_PIN);} while(0); +#define SetTCK() do {(JTAGSET) |= (TCK_PIN);} while(0); +#define ClrTCLK() do {(JTAGCLR) |= (TCLK_PIN);} while(0); +#define SetTCLK() do {(JTAGSET) |= (TCLK_PIN);} while(0); +#define StoreTCLK() ((JTAGOUT_RDBACK & TCLK_PIN) ? 1:0) +#define RestoreTCLK(x) (x == 0 ? (JTAGCLR |= TCLK_PIN) : (JTAGSET |= TCLK_PIN)) +#define ScanTDO() ((JTAGIN & TDO_PIN)) // assumes TDO to be bit0 + +#define JTAG_IODELAY() __asm__ __volatile__ ("nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n": : ) + +/****************************************************************************/ +/* Define section for user, related to the controller used (here MSP430F149)*/ +/****************************************************************************/ + +// Constants for Error LED control port: +#define JTAGLEDSET (IO0SET) // LED ports are P0.x +#define JTAGLEDCLR (IO0CLR) // LED ports are P0.x +#define JTAGLEDDIR (IO0DIR) +#undef JTAGLEDSEL /*P1SEL*/ +#define JTAGLEDRED (1<<13) // P0.13 Red LED (ERROR) +#define JTAGLEDGREEN (1<<15) // P0.15 Green LED (OK) + +#endif /* _SYSTEM_DEF_H_ */ diff --git a/embedded/board/arm/ul_usb1/libs/Makefile b/embedded/board/arm/ul_usb1/libs/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/board/arm/ul_usb1/libs/Makefile.omk b/embedded/board/arm/ul_usb1/libs/Makefile.omk new file mode 100644 index 0000000..1e281da --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = bspbase ldscripts diff --git a/embedded/board/arm/ul_usb1/libs/bspbase/Makefile b/embedded/board/arm/ul_usb1/libs/bspbase/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/bspbase/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/board/arm/ul_usb1/libs/bspbase/Makefile.omk b/embedded/board/arm/ul_usb1/libs/bspbase/Makefile.omk new file mode 100644 index 0000000..72f7977 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/bspbase/Makefile.omk @@ -0,0 +1,28 @@ +# -*- makefile -*- + +default_CONFIG += CONFIG_OC_UL_DRV_SYSLESS=x +default_CONFIG += CONFIG_OC_IC_DRV_SYSLESS=x +default_CONFIG += CONFIG_KEYVAL=x +default_CONFIG += CONFIG_STDIO_COM_PORT=x +default_CONFIG += CONFIG_OC_UL_DRV_U450_VARPINS=x +default_CONFIG += CONFIG_OC_UL_DRV_U450_VARPINS_MSRSWAP=x +default_CONFIG += CONFIG_OC_UL_DRV_U450_VARPINS_DIRNEG=x +default_CONFIG += CONFIG_OC_I2C_DRV_SYSLESS=x + +LOCAL_CONFIG_H = local_config.h + +INCLUDES += -I . + +include_HEADERS = bspbase.h + +lib_LIBRARIES = bspbase + +bspbase_SOURCES = bsp0hwinit.c + +ifneq ($(CONFIG_STDIO_COM_PORT),) +bspbase_SOURCES += uart.c +endif #CONFIG_STDIO_COM_PORT + +ifeq ($(CONFIG_KBD),y) +bspbase_SOURCES += kbd_io_hisc.c +endif #CONFIG_KBD \ No newline at end of file diff --git a/embedded/board/arm/ul_usb1/libs/bspbase/bsp0hwinit.c b/embedded/board/arm/ul_usb1/libs/bspbase/bsp0hwinit.c new file mode 100644 index 0000000..468e172 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/bspbase/bsp0hwinit.c @@ -0,0 +1,347 @@ +#include "local_config.h" +#include +#ifdef CONFIG_KEYVAL + #include + #include + #include +#endif /* CONFIG_KEYVAL */ +#ifdef CONFIG_STDIO_COM_PORT + #include +#endif +#ifdef CONFIG_OC_UL_DRV_SYSLESS + #include + #include + #include + #include + #include + extern long int uld_jiffies; +#endif /* CONFIG_OC_UL_DRV_SYSLESS */ +#ifdef CONFIG_OC_I2C_DRV_SYSLESS + #include +#endif /* CONFIG_OC_I2C_DRV_SYSLESS */ +#include +#include + +/* timers */ +volatile lt_ticks_t sys_timer_ticks; + +static void sysInit(void) +{ + + lpc_pll_off(); + lpc_pll_on(); + + // setup & enable the MAM + MAMCR = 0; + MAMTIM = MAMTIM_CYCLES; + MAMCR = MAMCR_FULL; + + // set the peripheral bus speed + // value computed from config.h + VPBDIV = VPBDIV_VALUE; // set the peripheral bus clock speed + + // setup the parallel port pin + IO0CLR = P0IO_ZERO_BITS; // clear the ZEROs output + IO0SET = P0IO_ONE_BITS; // set the ONEs output + IO0DIR = P0IO_OUTPUT_BITS; // set the output bit direction + + #ifdef P1IO_OUTPUT_BITS + IO1CLR = P1IO_ZERO_BITS; // clear the ZEROs output + IO1SET = P1IO_ONE_BITS; // set the ONEs output + IO1DIR = P1IO_OUTPUT_BITS; // set the output bit direction + #endif + + IO0CLR = LED1_BIT; // Indicate functional state on the LED1 +} + +void timer0_isr(void) +{ + unsigned int ir; + ir=T0IR; + if (ir&TIR_MR0I) { + do { + T0MR0+=PCLK/SYS_TIMER_HZ; + T0IR=TIR_MR0I; // Clear match0 interrupt + #ifdef CONFIG_OC_UL_DRV_SYSLESS + uld_jiffies++; + #endif + sys_timer_ticks++; + } while (((int32_t)(T0MR0-T0TC))<0); + } +} + +void timerInit(void) +{ + sys_timer_ticks=0; + + HAL_INTERRUPT_ATTACH(HAL_INTERRUPT_TIMER0,timer0_isr,0); + HAL_INTERRUPT_UNMASK(HAL_INTERRUPT_TIMER0); + + T0TC=0; + T0MCR=0; + + T0MR0=PCLK/SYS_TIMER_HZ; /* ms tics */ + T0MCR|=TMCR_MR0_I; + + T0TCR = TCR_ENABLE; //Run timer 0 +} + +#ifdef CONFIG_STDIO_COM_PORT + +int uartcon_write(int file, const char * ptr, int len) +{ + int cnt; + unsigned char ch; + for(cnt=0;cntlen=0; + + if(ul_iac_mem_head_rd((uint8_t *)ibuff, msginfo->len,&mtype,&start,&len)) + return UL_IAC_RC_PROC; + + if (mtype==0x00) { + data->len=len; + data->buff=(unsigned char*)start; + return UL_IAC_RC_FREEMSG; + } + return UL_IAC_RC_PROC; +} + +int ul_iac_call_erm(struct ul_drv *udrv,ul_msginfo *msginfo,char *ibuff,ul_iac_data *data) +{ + uint32_t mtype,start,len; + + data->len=0; + + if(ul_iac_mem_head_rd((uint8_t *)ibuff, msginfo->len,&mtype,&start,&len)) + return UL_IAC_RC_PROC; + + #ifdef CONFIG_KEYVAL + if (mtype==0x01) { + lpcisp_erase((void*)start,len); + data->len=0; + return UL_IAC_RC_FREEMSG; + } + #endif /* CONFIG_KEYVAL */ + return UL_IAC_RC_PROC; +} + +int ul_iac_call_wrm(struct ul_drv *udrv,ul_msginfo *msginfo,char *ibuff,ul_iac_data *data) +{ + uint32_t mtype,start,len; + + data->len=0; + + if(ul_iac_mem_head_rd((uint8_t *)ibuff, msginfo->len,&mtype,&start,&len)) + return UL_IAC_RC_PROC; + + if (mtype==0x00) { + memcpy((void*)start,data->buff,data->len); + return UL_IAC_RC_FREEMSG; + } + #ifdef CONFIG_KEYVAL + if (mtype==0x01) { + lpcisp_write((char*)start, data->buff, ISP_RAM2FLASH_BLOCK_SIZE); + return UL_IAC_RC_FREEMSG; + } + #endif /* CONFIG_KEYVAL */ + return UL_IAC_RC_PROC; +} + + +int ul_iac_call_deb(struct ul_drv *udrv,ul_msginfo *msginfo,char *ibuff,ul_iac_data *data) +{ + uint32_t debcmd,mtype,start; + uint8_t *p=(uint8_t*)ibuff; + + if (msginfo->len<1) return UL_IAC_RC_PROC; + debcmd=*(p++); + switch (debcmd) { + case 0x10: /* goto */ + data->len=0; + if (msginfo->len<5) return UL_IAC_RC_PROC; + mtype=*(p++); + mtype+=*(p++)<<8; + start=*(p++); + start+=*(p++)<<8; + if(mtype&UL_MTYPE_START32BIT){ + mtype&=~UL_MTYPE_START32BIT; + if (msginfo->len<7) return UL_IAC_RC_PROC; + start+=(uint32_t)*(p++)<<16; + start+=(uint32_t)*(p++)<<24; + } + if (mtype==0x00) + ((void (*)())start)(); + default:break; + } + return UL_IAC_RC_PROC; +} + +int ul_iac_call_res(struct ul_drv *udrv,ul_msginfo *msginfo,char *ibuff,ul_iac_data *data) +{ + uint32_t rescmd,pass; + uint8_t *p=(uint8_t*)ibuff; + + if (msginfo->len<1) return UL_IAC_RC_PROC; + rescmd=*(p++); + switch (rescmd) { + case ULRES_CPU: /* CPU */ + data->len=0; + if (msginfo->len<3) return UL_IAC_RC_PROC; + pass=*(p++); + pass+=*(p++)<<8; + if (pass==0xaa55) { + MEMMAP=MEMMAP_FLASH; + lpc_watchdog_init(1,10); /* 10ms */ + lpc_watchdog_feed(); + while(1); + } + default:break; + } + return UL_IAC_RC_PROC; +} + +int uLanInit() +{ + struct ul_drv *udrv; + + /* set rs485 mode for UART1 */ + PINSEL0 = (PINSEL0 & ~0xFFFF0000) | 0x01550000; /* dsr(txd), cts(rxd), rts(rs485_dir), rxd, txd */ + + udrv=ul_drv_new(UL_DRV_SYSLESS_PORT, /* port */ + UL_DRV_SYSLESS_IRQ, /* irq */ + UL_DRV_SYSLESS_BAUD, /* baud */ + UL_DRV_SYSLESS_MY_ADR_DEFAULT, /* my adr */ + #ifdef CONFIG_OC_UL_DRV_U450_VARPINS + #if defined(CONFIG_OC_UL_DRV_U450_VARPINS_DIRNEG) && defined(CONFIG_OC_UL_DRV_U450_VARPINS_MSRSWAP) + "16450-dirneg-msrswap", /* chip name */ + #elif defined(CONFIG_OC_UL_DRV_U450_VARPINS_MSRSWAP) + "16450-msrswap", /* chip name */ + #elif defined(CONFIG_OC_UL_DRV_U450_VARPINS_DIRNEG) + "16450-dirneg", /* chip name */ + #else + "16450", /* chip name */ + #endif + #else /*CONFIG_OC_UL_DRV_U450_VARPINS*/ + "16450", /* chip name */ + #endif /*CONFIG_OC_UL_DRV_U450_VARPINS*/ + 0); /* baud base - default */ + + if (udrv==NULL) + return -1; + + ul_drv_add_iac(udrv,UL_CMD_RDM,UL_IAC_OP_SND,ul_iac_call_rdm,NULL,0,0,NULL); + ul_drv_add_iac(udrv,UL_CMD_ERM,UL_IAC_OP_CALLBACK,ul_iac_call_erm,NULL,0,0,NULL); + ul_drv_add_iac(udrv,UL_CMD_WRM,UL_IAC_OP_REC,ul_iac_call_wrm,(char*)lpciap_buff,0,0,NULL); + ul_drv_add_iac(udrv,UL_CMD_DEB,UL_IAC_OP_CALLBACK,ul_iac_call_deb,NULL,0,0,NULL); + ul_drv_add_iac(udrv,UL_CMD_RES,UL_IAC_OP_CALLBACK,ul_iac_call_res,NULL,0,0,NULL); + + return ul_drv_add_dev(udrv); +} +#endif /* CONFIG_OC_UL_DRV_SYSLESS */ + +#ifdef CONFIG_OC_I2C_DRV_SYSLESS + +i2c_drv_t i2c_drv; + +int +i2cInit(void) +{ + + /* set io pins */ + PINSEL0 = (PINSEL0 & ~0x000000F0) | 0x00000050; /* I2C - SCL, SDA */ + + if (i2c_drv_init(&i2c_drv, + I2C_DRV_SYSLESS_PORT, + I2C_DRV_SYSLESS_IRQ, + I2C_DRV_SYSLESS_BITRATE, + I2C_DRV_SYSLESS_SLADR)<0) return -1; + + return 1; +} + +#endif /*CONFIG_OC_I2C_DRV_SYSLESS*/ + +void _setup_board() +{ + // initialize the system + sysInit(); + + #ifdef WATCHDOG_ENABLED + lpc_watchdog_init(1,WATCHDOG_TIMEOUT_MS); + lpc_watchdog_feed(); + #endif /* WATCHDOG_ENABLED */ + + // initialize the system timer + timerInit(); + + #ifdef CONFIG_STDIO_COM_PORT + uart0Init( B57600 , UART_8N1, UART_FIFO_8); + init_system_stub(); + #endif /* CONFIG_STDIO_COM_PORT */ + + #ifdef CONFIG_OC_UL_DRV_SYSLESS +// uld_debug_flg=0x3ff; + uLanInit(); + #endif /* CONFIG_OC_UL_DRV_SYSLESS */ + + #ifdef CONFIG_OC_I2C_DRV_SYSLESS + i2cInit(); + #endif /* CONFIG_OC_I2C_DRV_SYSLESS */ +} diff --git a/embedded/board/arm/ul_usb1/libs/bspbase/bspbase.h b/embedded/board/arm/ul_usb1/libs/bspbase/bspbase.h new file mode 100644 index 0000000..5369f81 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/bspbase/bspbase.h @@ -0,0 +1,11 @@ +#ifndef _BSPBASE_H +#define _BSPBASE_H + +#include +#include + +extern volatile lt_ticks_t sys_timer_ticks; + +#define get_sys_timer_ticks() sys_timer_ticks + +#endif /* _BSPBASE_H */ diff --git a/embedded/board/arm/ul_usb1/libs/bspbase/kbd_io_hisc.c b/embedded/board/arm/ul_usb1/libs/bspbase/kbd_io_hisc.c new file mode 100644 index 0000000..ff4d1d5 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/bspbase/kbd_io_hisc.c @@ -0,0 +1,88 @@ +#include +#include "kbd.h" + +unsigned char kbd_onerow(unsigned char scan) +{ + kbdisr_lock_level_t level; + unsigned int scan_mask=KBD_SCAN_MASK; + unsigned int scan_val; + unsigned int ret; + int delay=10; + + kbdisr_lock(level); + + #ifdef KBD_USE_IO_SETCLR_OPS + scan_val=(scan<>KBD_RET_BIT0)&((1<> 8); // set for baud high byte + + // set the number of characters and other + // user specified operating parameters + // Databits, Parity, Stopbits - Settings in Line Control Register + U0LCR = (mode & ~(1< + +/////////////////////////////////////////////////////////////////////////////// +// use the following macros to determine the 'baud' parameter values +// for uart0Init() and uart1Init() +// CAUTION - 'baud' SHOULD ALWAYS BE A CONSTANT or +// a lot of code will be generated. +// Baud-Rate is calculated based on pclk (VPB-clock) +// the devisor must be 16 times the desired baudrate +#define UART_BAUD(baud) (uint16_t)((PCLK / ((baud) * 16.0)) + 0.5) + +/////////////////////////////////////////////////////////////////////////////// +// Definitions for typical UART 'baud' settings +#define B1200 UART_BAUD(1200) +#define B9600 UART_BAUD(9600) +#define B19200 UART_BAUD(19200) +#define B38400 UART_BAUD(38400) +#define B57600 UART_BAUD(57600) +#define B115200 UART_BAUD(115200) + +/////////////////////////////////////////////////////////////////////////////// +// Definitions for typical UART 'mode' settings +#define UART_8N1 (uint8_t)(ULCR_CHAR_8 + ULCR_PAR_NO + ULCR_STOP_1) +#define UART_7N1 (uint8_t)(ULCR_CHAR_7 + ULCR_PAR_NO + ULCR_STOP_1) +#define UART_8N2 (uint8_t)(ULCR_CHAR_8 + ULCR_PAR_NO + ULCR_STOP_2) +#define UART_7N2 (uint8_t)(ULCR_CHAR_7 + ULCR_PAR_NO + ULCR_STOP_2) +#define UART_8E1 (uint8_t)(ULCR_CHAR_8 + ULCR_PAR_EVEN + ULCR_STOP_1) +#define UART_7E1 (uint8_t)(ULCR_CHAR_7 + ULCR_PAR_EVEN + ULCR_STOP_1) +#define UART_8E2 (uint8_t)(ULCR_CHAR_8 + ULCR_PAR_EVEN + ULCR_STOP_2) +#define UART_7E2 (uint8_t)(ULCR_CHAR_7 + ULCR_PAR_EVEN + ULCR_STOP_2) +#define UART_8O1 (uint8_t)(ULCR_CHAR_8 + ULCR_PAR_ODD + ULCR_STOP_1) +#define UART_7O1 (uint8_t)(ULCR_CHAR_7 + ULCR_PAR_ODD + ULCR_STOP_1) +#define UART_8O2 (uint8_t)(ULCR_CHAR_8 + ULCR_PAR_ODD + ULCR_STOP_2) +#define UART_7O2 (uint8_t)(ULCR_CHAR_7 + ULCR_PAR_ODD + ULCR_STOP_2) + +/////////////////////////////////////////////////////////////////////////////// +// Definitions for typical UART 'fmode' settings +#define UART_FIFO_OFF (0x00) +#define UART_FIFO_1 (uint8_t)(UFCR_FIFO_ENABLE + UFCR_FIFO_TRIG1) +#define UART_FIFO_4 (uint8_t)(UFCR_FIFO_ENABLE + UFCR_FIFO_TRIG4) +#define UART_FIFO_8 (uint8_t)(UFCR_FIFO_ENABLE + UFCR_FIFO_TRIG8) +#define UART_FIFO_14 (uint8_t)(UFCR_FIFO_ENABLE + UFCR_FIFO_TRIG14) + +void uart0Init(uint16_t baud, uint8_t mode, uint8_t fmode); +int uart0Putch(int ch); +uint16_t uart0Space(void); +const char *uart0Puts(const char *string); +int uart0TxEmpty(void); +void uart0TxFlush(void); +int uart0Getch(void); +int uart0GetchW(void); + +#endif diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/Makefile b/embedded/board/arm/ul_usb1/libs/ldscripts/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/Makefile.omk b/embedded/board/arm/ul_usb1/libs/ldscripts/Makefile.omk new file mode 100644 index 0000000..01e6b77 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/Makefile.omk @@ -0,0 +1,5 @@ +# -*- makefile -*- + +lib_LDSCRIPTS = $(notdir $(wildcard $(SOURCES_DIR)/*.ld*)) + +include_HEADERS = mem_loc.h keyval_loc.h diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/keyval_loc.h b/embedded/board/arm/ul_usb1/libs/ldscripts/keyval_loc.h new file mode 100644 index 0000000..2ee23e5 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/keyval_loc.h @@ -0,0 +1,10 @@ +#ifndef _KEYVAL_LOC_H +#define _KEYVAL_LOC_H + +extern int _keyval_start; +extern int _keyval_page_len; + +#define KEYVAL_START ((unsigned int)&_keyval_start) +#define KEYVAL_PAGE_LEN ((unsigned int)&_keyval_page_len) + +#endif /* _KVPB_LOC */ diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-cfg b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-cfg new file mode 100644 index 0000000..a29dfc8 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-cfg @@ -0,0 +1,12 @@ + +/* Memory Definitions */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00008000 + RAM (rw) : ORIGIN = 0x40000000, LENGTH = 0x00001FE0 + STACK (rw) : ORIGIN = 0x40000000 + 0x00001FE0 - 4, LENGTH = 4 + + FLASHVEC (rx) : ORIGIN = 0x00000000, LENGTH = 0x00000020 + RAMVEC (w) : ORIGIN = 0x40000000, LENGTH = 0x00000020 +} + diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-flash b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-flash new file mode 100644 index 0000000..e1a20c6 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-flash @@ -0,0 +1,94 @@ +/***********************************************************************/ +/* */ +/* ROM.ld: Linker Script File */ +/* */ +/***********************************************************************/ +ENTRY(_startup) + +INCLUDE "lpc2103.ld-cfg" + +STARTUP(startup.o) + +PROVIDE (_setup_board = 0); + +/* Section Definitions */ +SECTIONS +{ + + /* first section is .text which is used for code */ + .text : + { + . = ALIGN(4); + *(.ivt) + *(.text) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + _etext = ALIGN( 4 ) ; + } > FLASH + + /* .data section which is used for initialized data */ +/* .data : AT (_etext) */ + .data : + AT ( ADDR( .text ) + SIZEOF( .text ) ) + { + . = ALIGN(4); + _data = .; + *(.data) + _edata = ALIGN( 4 ) ; + } > RAM + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + __bss_start = . ; + __bss_start__ = . ; + *(.bss) + *(COMMON) + __bss_end__ = ALIGN( 4 ) ; + end = ALIGN( 4 ) ; + _end = ALIGN( 4 ) ; + } > RAM + + .stack : + { + _stack = .; + } > STACK + + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-app b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-app new file mode 100644 index 0000000..4998f11 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-app @@ -0,0 +1,99 @@ +/***********************************************************************/ +/* */ +/* ROM.ld: Linker Script File */ +/* */ +/***********************************************************************/ +ENTRY(_startup) + +INCLUDE "lpc2105.ld-cfg" + +STARTUP(startup.o) + +PROVIDE (_setup_board = 0); + +/* Section Definitions */ +SECTIONS +{ + + /* first section is .text which is used for code */ + .text : + { + . = ALIGN(4); + *(.text) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + _etext = ALIGN( 4 ) ; + } > FLASHAPP + + .keyval : + { + PROVIDE (_keyval_start = .); + PROVIDE (_keyval_page_len = KEYVAL_PAGE_LEN ); + }> KEYVAL + + /* .data section which is used for initialized data */ +/* .data : AT (_etext) */ + .data : + AT ( ADDR( .text ) + SIZEOF( .text ) ) + { + . = ALIGN(4); + _data = .; + *(.ivt) + *(.data) + _edata = ALIGN( 4 ) ; + } > RAM + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + __bss_start = . ; + __bss_start__ = . ; + *(.bss) + *(COMMON) + __bss_end__ = ALIGN( 4 ) ; + end = ALIGN( 4 ) ; + _end = ALIGN( 4 ) ; + } > RAM + + .stack : + { + _stack = .; + } > STACK + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-boot b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-boot new file mode 100644 index 0000000..5ddb822 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-boot @@ -0,0 +1,104 @@ +/***********************************************************************/ +/* */ +/* ROM.ld: Linker Script File */ +/* */ +/***********************************************************************/ +ENTRY(_startup) + +INCLUDE "lpc2105.ld-cfg" + +STARTUP(startup.o) + +PROVIDE (_setup_board = 0); + +/* Section Definitions */ +SECTIONS +{ + + /* first section is .text which is used for code */ + .text : + { + . = ALIGN(4); + *(.ivt) + *(.text) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + _etext = ALIGN( 4 ) ; + } > FLASHBOOT + + .app : + { + PROVIDE (_mem_app_start = . ); + } > FLASHAPP + + .keyval : + { + PROVIDE (_keyval_start = .); + PROVIDE (_keyval_page_len = KEYVAL_PAGE_LEN ); + }> KEYVAL + + /* .data section which is used for initialized data */ +/* .data : AT (_etext) */ + .data : + AT ( ADDR( .text ) + SIZEOF( .text ) ) + { + . = ALIGN(4); + _data = .; + *(.data) + _edata = ALIGN( 4 ) ; + } > RAM + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + __bss_start = . ; + __bss_start__ = . ; + *(.bss) + *(COMMON) + __bss_end__ = ALIGN( 4 ) ; + end = ALIGN( 4 ) ; + _end = ALIGN( 4 ) ; + } > RAM + + .stack : + { + _stack = .; + } > STACK + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-cfg b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-cfg new file mode 100644 index 0000000..d5a9ba9 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-cfg @@ -0,0 +1,18 @@ + +KEYVAL_PAGE_LEN = 0x00002000; + +/* Memory Definitions */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00020000 + RAM (rw) : ORIGIN = 0x40000000, LENGTH = 0x00003FE0 + STACK (rw) : ORIGIN = 0x40000000 + 0x00003FE0 - 4, LENGTH = 4 + + FLASHVEC (rx) : ORIGIN = 0x00000000, LENGTH = 0x00000020 + FLASHBOOT (rx) : ORIGIN = 0x0000000, LENGTH = 0x0000A000 + FLASHAPP (rx) : ORIGIN = 0x0000A000, LENGTH = 0x0001A000 + KEYVAL (rx) : ORIGIN = 0x00001A000, LENGTH = 0x00004000 + + RAMVEC (w) : ORIGIN = 0x40000000, LENGTH = 0x00000020 +} + diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-app b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-app new file mode 100644 index 0000000..767081f --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-app @@ -0,0 +1,99 @@ +/***********************************************************************/ +/* */ +/* ROM.ld: Linker Script File */ +/* */ +/***********************************************************************/ +ENTRY(_startup) + +INCLUDE "lpc2148.ld-cfg" + +STARTUP(startup.o) + +PROVIDE (_setup_board = 0); + +/* Section Definitions */ +SECTIONS +{ + + /* first section is .text which is used for code */ + .text : + { + . = ALIGN(4); + *(.text) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + _etext = ALIGN( 4 ) ; + } > FLASHAPP + + .keyval : + { + PROVIDE (_keyval_start = .); + PROVIDE (_keyval_page_len = KEYVAL_PAGE_LEN ); + }> KEYVAL + + /* .data section which is used for initialized data */ +/* .data : AT (_etext) */ + .data : + AT ( ADDR( .text ) + SIZEOF( .text ) ) + { + . = ALIGN(4); + _data = .; + *(.ivt) + *(.data) + _edata = ALIGN( 4 ) ; + } > RAM + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + __bss_start = . ; + __bss_start__ = . ; + *(.bss) + *(COMMON) + __bss_end__ = ALIGN( 4 ) ; + end = ALIGN( 4 ) ; + _end = ALIGN( 4 ) ; + } > RAM + + .stack : + { + _stack = .; + } > STACK + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-boot b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-boot new file mode 100644 index 0000000..de00d81 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-boot @@ -0,0 +1,104 @@ +/***********************************************************************/ +/* */ +/* ROM.ld: Linker Script File */ +/* */ +/***********************************************************************/ +ENTRY(_startup) + +INCLUDE "lpc2148.ld-cfg" + +STARTUP(startup.o) + +PROVIDE (_setup_board = 0); + +/* Section Definitions */ +SECTIONS +{ + + /* first section is .text which is used for code */ + .text : + { + . = ALIGN(4); + *(.ivt) + *(.text) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + _etext = ALIGN( 4 ) ; + } > FLASHBOOT + + .app : + { + PROVIDE (_mem_app_start = . ); + } > FLASHAPP + + .keyval : + { + PROVIDE (_keyval_start = .); + PROVIDE (_keyval_page_len = KEYVAL_PAGE_LEN ); + }> KEYVAL + + /* .data section which is used for initialized data */ +/* .data : AT (_etext) */ + .data : + AT ( ADDR( .text ) + SIZEOF( .text ) ) + { + . = ALIGN(4); + _data = .; + *(.data) + _edata = ALIGN( 4 ) ; + } > RAM + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + __bss_start = . ; + __bss_start__ = . ; + *(.bss) + *(COMMON) + __bss_end__ = ALIGN( 4 ) ; + end = ALIGN( 4 ) ; + _end = ALIGN( 4 ) ; + } > RAM + + .stack : + { + _stack = .; + } > STACK + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-cfg b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-cfg new file mode 100644 index 0000000..7534208 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-cfg @@ -0,0 +1,18 @@ + +KEYVAL_PAGE_LEN = 0x00001000; + +/* Memory Definitions */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00080000 + RAM (rw) : ORIGIN = 0x40000000, LENGTH = 0x00007FE0 + STACK (rw) : ORIGIN = 0x40000000 + 0x00007FE0 - 4, LENGTH = 4 + + FLASHVEC (rx) : ORIGIN = 0x00000000, LENGTH = 0x00000020 + FLASHBOOT (rx) : ORIGIN = 0x0000000, LENGTH = 0x00020000 + FLASHAPP (rx) : ORIGIN = 0x00020000, LENGTH = 0x00058000 + KEYVAL (rx) : ORIGIN = 0x000078000, LENGTH = 0x00002000 + + RAMVEC (w) : ORIGIN = 0x40000000, LENGTH = 0x00000020 +} + diff --git a/embedded/board/arm/ul_usb1/libs/ldscripts/mem_loc.h b/embedded/board/arm/ul_usb1/libs/ldscripts/mem_loc.h new file mode 100644 index 0000000..77b24d1 --- /dev/null +++ b/embedded/board/arm/ul_usb1/libs/ldscripts/mem_loc.h @@ -0,0 +1,8 @@ +#ifndef _MEM_LOC_H +#define _MEM_LOC_H + +extern int _mem_app_start; + +#define MEM_APP_START ((unsigned int)&_mem_app_start) + +#endif /* _MEM_LOC */ diff --git a/embedded/libs4c/Makefile b/embedded/libs4c/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/Makefile.omk b/embedded/libs4c/Makefile.omk new file mode 100644 index 0000000..f76e30f --- /dev/null +++ b/embedded/libs4c/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = keyval usb kbd i2c \ No newline at end of file diff --git a/embedded/libs4c/i2c/Makefile b/embedded/libs4c/i2c/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/i2c/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/i2c/Makefile.omk b/embedded/libs4c/i2c/Makefile.omk new file mode 100644 index 0000000..f58b859 --- /dev/null +++ b/embedded/libs4c/i2c/Makefile.omk @@ -0,0 +1,19 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_OC_I2C_DRV_SYSLESS=n +default_CONFIG += CONFIG_OC_I2C_CHIP_C552=y + +LOCAL_CONFIG_H = i2c_drv_config.h + +INCLUDES += -I . + +ifeq ($(CONFIG_OC_I2C_DRV_SYSLESS),y) +lib_LIBRARIES = i2c_drv +include_HEADERS += i2c_drv.h +i2c_drv_SOURCES += i2c_drv.c + +ifeq ($(CONFIG_OC_I2C_CHIP_C552),y) +i2c_drv_SOURCES += i2c_c552.c +endif #CONFIG_OC_I2C_CHIP_C552 + +endif #CONFIG_OC_I2C_DRV_SYSLESS diff --git a/embedded/libs4c/i2c/i2c_c552.c b/embedded/libs4c/i2c/i2c_c552.c new file mode 100644 index 0000000..7cede72 --- /dev/null +++ b/embedded/libs4c/i2c/i2c_c552.c @@ -0,0 +1,396 @@ +/******************************************************************* + Components for embedded applications builded for + laboratory and medical instruments firmware + + i2c_mx1.c - I2C communication automata for M9328 MX1 microcontroller + + Copyright holders and project originators + (C) 2001-2008 by Pavel Pisa pisa@cmp.felk.cvut.cz + (C) 2002-2008 by PiKRON Ltd. http://www.pikron.com + (C) 2007-2008 by Petr Smolik + + The COLAMI components can be used and copied under next licenses + - MPL - Mozilla Public License + - GPL - GNU Public License + - LGPL - Lesser GNU Public License + - and other licenses added by project originators + Code can be modified and re-distributed under any combination + of the above listed licenses. If contributor does not agree with + some of the licenses, he can delete appropriate line. + Warning, if you delete all lines, you are not allowed to + distribute code or build project. + *******************************************************************/ + + +#include +#include +#include "i2c_drv_config.h" +#include "i2c_drv.h" + +int c552_poll(i2c_drv_t *drv); +void c552_irq_handler(int intno, void *dev_id); +static int c552_ctrl_fnc(struct i2c_drv *drv, int ctrl, void *p); + +// I2C Registers +#define C552_CONSET(port) (((i2cRegs_t *)(port))->conset) /* Control Set Register */ +#define C552_STAT(port) (((i2cRegs_t *)(port))->stat) /* Status Register */ +#define C552_DAT(port) (((i2cRegs_t *)(port))->dat) /* Data Register */ +#define C552_ADR(port) (((i2cRegs_t *)(port))->adr) /* Slave Address Register */ +#define C552_SCLH(port) (((i2cRegs_t *)(port))->sclh) /* SCL Duty Cycle Register (high half word) */ +#define C552_SCLL(port) (((i2cRegs_t *)(port))->scll) /* SCL Duty Cycle Register (low half word) */ +#define C552_CONCLR(port) (((i2cRegs_t *)(port))->conclr) /* Control Clear Register */ + +#define C552CON_AA (1 << 2) +#define C552CON_SI (1 << 3) +#define C552CON_STO (1 << 4) +#define C552CON_STA (1 << 5) +#define C552CON_EN (1 << 6) + +#define C552CON_AAC (1 << 2) +#define C552CON_SIC (1 << 3) +#define C552CON_STAC (1 << 5) +#define C552CON_ENC (1 << 6) + +/***************************************************************************/ +int c552_init_start(struct i2c_drv *drv, int port, int irq, int bitrate, int sladr) +{ + C552_ADR(port)=sladr; + C552_SCLH(port)=((PCLK/2)/bitrate); //minimal value + C552_SCLL(port)=((PCLK/2)/bitrate); + drv->irq=irq; + drv->port=port; + drv->sfnc_act=NULL; + drv->ctrl_fnc=c552_ctrl_fnc; + drv->poll_fnc=c552_poll; + drv->flags=I2C_DRV_ON; /* todo - use atomic operation */ + C552_CONCLR(port)=0x6C; /* clearing all flags */ + C552_CONSET(port)=C552CON_EN; + HAL_INTERRUPT_ATTACH(irq,c552_irq_handler,drv); + HAL_INTERRUPT_UNMASK(irq); + return 0; +} + +static int c552_sfnc_ms_end(struct i2c_drv *drv); +static inline i2c_msg_head_t *c552_sfnc_sl_prep(struct i2c_drv *drv, int cmd, int rxtx); + +/***************************************************************************/ +static int c552_sfnc_ms_end(struct i2c_drv *drv) +{ + i2c_msg_head_t *msg=drv->msg_act; + + if(msg) { + if(msg->flags&I2C_MSG_REPEAT){ + drv->master_queue=msg->next; + }else{ + i2c_drv_queue_msg(msg->flags&I2C_MSG_NOPROC?NULL:&drv->proc_queue,msg); + } + msg->flags|=I2C_MSG_FINISHED; + if((msg->flags&I2C_MSG_CB_END) && (msg->callback)) + msg->callback(drv,I2C_MSG_CB_END,msg); + } + + if(drv->master_queue) { + /* there is some more work for master*/ + /* We need to request start of the next transfer somewhere */ + C552_CONSET(drv->port)=C552CON_STA; + } else { + drv->flags&=~I2C_DRV_MS_INPR; + } + + drv->msg_act = NULL; + return 0; +} + +static inline +i2c_msg_head_t *c552_sfnc_sl_prep(struct i2c_drv *drv, int cmd, int rxtx) +{ + i2c_msg_head_t *msg=drv->slave_queue; + if(!msg) do { + if((msg->flags&rxtx) && !((cmd^msg->sl_cmd)&msg->sl_msk)){ + drv->slave_queue=msg; + if((msg->flags&I2C_MSG_CB_START) && (msg->callback)) + msg->callback(drv,I2C_MSG_CB_START|rxtx,msg); + return msg; + } + } while((msg=msg->next)!=drv->slave_queue); + return NULL; +} + +/***************************************************************************/ +static int c552_ctrl_fnc(struct i2c_drv *drv, int ctrl, void *p) +{ + unsigned long saveif; + switch(ctrl){ + case I2C_CTRL_MS_RQ: + if(!(drv->flags&I2C_DRV_ON)) + return -1; + if(!drv->master_queue) + return 0; + save_and_cli(saveif); + if(!(drv->flags&I2C_DRV_MS_INPR)) { + drv->flags|=I2C_DRV_MS_INPR; + drv->flags&=~I2C_DRV_NA; + C552_CONSET(drv->port)=C552CON_STA; + } + restore_flags(saveif); + return 0; + default: + return -1; + } + return 0; +} + +/***************************************************************************/ +int c552_poll(i2c_drv_t *drv) +{ + i2c_msg_head_t *msg; + + if((msg=drv->proc_queue)!=NULL){ + i2c_drv_queue_msg(NULL,msg); + if((msg->flags&I2C_MSG_CB_PROC) && (msg->callback)) + msg->callback(drv,I2C_MSG_CB_PROC,msg); + } + return 0; +} + +int i2c_irq_seq_num=0; + +/***************************************************************************/ +void c552_irq_handler(int intno, void *dev_id) +{ + i2c_drv_t *drv; + i2c_msg_head_t *msg; + int port; + int stat; + + drv=(i2c_drv_t*)dev_id; + if(drv->magic!=I2C_DRV_MAGIC) + { + #ifdef FOR_LINUX_KERNEL + panic("i2c_irq_handler : BAD drv magic !!!"); + #elif defined(_WIN32) + I2C_PRINTF("i2c_irq_handler : BAD drv magic !!!\n"); + return FALSE; + #elif defined(__DJGPP__)||defined(CONFIG_OC_I2C_DRV_SYSLESS) + I2C_PRINTF("i2c_irq_handler : BAD drv magic !!!\n"); + return; + #else + error("i2c_irq_handler : BAD drv magic !!!"); + #endif + } + drv->flags&=~I2C_DRV_NA; + + port=drv->port; + msg=drv->msg_act; + + stat=C552_STAT(port); + + switch(stat) { + case 0x00: + /* Bus Error has occured */ + drv->msg_act=NULL; + C552_CONSET(port)=C552CON_STO; + if(drv->master_queue) { + /* there is some work for master*/ + C552_CONSET(port)=C552CON_STA; + } + break; + case 0x08: /* MS_STA */ + /* the initial start condition has been sent */ + if(!drv->master_queue) { + C552_CONCLR(port)=C552CON_STAC; + C552_CONSET(port)=C552CON_STO; + drv->msg_act=NULL; + break; + } + C552_CONCLR(port)=C552CON_STAC; + C552_CONSET(port)=C552CON_AA; + + msg=drv->master_queue; + drv->msg_act=msg; + msg->tx_len=msg->rx_len=0; + + if((msg->flags&I2C_MSG_CB_START) && (msg->callback)) + msg->callback(drv,I2C_MSG_CB_START,msg); + + if (msg->flags&I2C_MSG_MS_TX) { + /* proceed Tx request first */ + C552_DAT(port) = msg->addr&~1; + break; + } + /* if there is no request for transmit, continue by Rx immediately */ + case 0x10: /* MS_REPS */ + /* the repeated start has been successfully sent, continue by Rx */ + C552_CONCLR(port)=C552CON_STAC; + C552_CONSET(port)=C552CON_AA; + C552_DAT(port) = msg->addr|1; + if (!msg || !(msg->flags&I2C_MSG_MS_RX)) { + /* there are no data to be received */ + C552_CONSET(port)=C552CON_STO; + c552_sfnc_ms_end(drv); + } else { + msg->rx_len=0; + } + break; + case 0x18: + /* sent SLA W received ACK */ + case 0x28: + /* sent DATA received ACK */ + if (msg->tx_lentx_rq) { + C552_DAT(port) = msg->tx_buf[msg->tx_len]; + msg->tx_len++; + break; + } + /* all data has been sent */ + if (!(msg->flags&I2C_MSG_MS_RX)) { + C552_CONSET(port)=C552CON_STO; + c552_sfnc_ms_end(drv); + } else { + C552_CONSET(port)=C552CON_STA; + } + break; + case 0x30: + /* sent DATA received NACK */ + case 0x48: + /* sent SLA R received ACK */ + case 0x20: + /* vyslano SLA W prijato NACK */ + C552_CONSET(port)=C552CON_STO; + msg->flags|=I2C_MSG_FAIL; + c552_sfnc_ms_end(drv); + break; + case 0x38: + /* arbitration lost during Tx */ + C552_CONSET(port)=C552CON_STA; + break; + case 0x40: + /* sent SLA R received ACK */ + if (msg->rx_rq==1) + C552_CONCLR(port)=C552CON_AAC; + break; + case 0x50: + /* received DATA sent ACK */ + msg->rx_buf[msg->rx_len]= C552_DAT(port); + msg->rx_len++; + if (msg->rx_rq==msg->rx_len) + C552_CONCLR(port)=C552CON_AAC; + break; + case 0x58: + /* received DATA sent NACK */ + msg->rx_buf[msg->rx_len]= C552_DAT(port); + msg->rx_len++; + C552_CONSET(port)=C552CON_STO; + c552_sfnc_ms_end(drv); + break; + + /*** slave mode ***/ + + case 0x68: + /* received own SLA W sent ACK after arbitration lost */ + + case 0x78: + /* received Generall CALL sent ACK after arbitration lost */ + C552_CONSET(port)=C552CON_STA; + + case 0x60: + /* received own SLA W sent ACK */ + + case 0x70: + /* received Generall CALL sent ACK */ + if(!drv->slave_queue) { + C552_CONCLR(port)=C552CON_AAC; + break; + } + C552_CONSET(port)=C552CON_AA; + drv->flags|=I2C_DRV_SL_CEXP|I2C_DRV_SL_INRX; + break; + + case 0x80: + /* SLA W : received DATA sent ACK */ + + case 0x90: + /* GCall : received DATA sent ACK */ + + if(drv->flags&I2C_DRV_SL_CEXP){ + drv->flags&=~I2C_DRV_SL_CEXP; + drv->sl_last_cmd=C552_DAT(port); + msg=c552_sfnc_sl_prep(drv, drv->sl_last_cmd, I2C_MSG_SL_RX); + drv->msg_act=msg; + } + if(!msg || (msg->rx_len>=msg->rx_rq)){ + C552_CONCLR(port)=C552CON_AAC; + break; + } + msg->rx_buf[msg->rx_len]= C552_DAT(port); + msg->rx_len++; + break; + + case 0x88: + /* SLA W : received DATA sent NACK */ + /* may it be, the handling should fall into A0 state */ + + case 0x98: + /* GCall : received DATA sent NACK */ + /* may it be, the handling should fall into A0 state */ + + C552_CONSET(port)=C552CON_AA; + break; + + case 0xA0: + /* Slave : Repeated START or STOP */ + if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) { + int cbcode; + if(drv->flags&I2C_DRV_SL_INRX) + cbcode=I2C_MSG_CB_END|I2C_MSG_SL_RX; + else + cbcode=I2C_MSG_CB_END|I2C_MSG_SL_TX; + msg->callback(drv,cbcode,msg); + } + C552_CONSET(port)=C552CON_AA; + break; + + case 0xB0: + /* received own SLA R sent ACK after arbitration lost */ + C552_CONSET(port)=C552CON_STA; + + case 0xA8: + /* received own SLA R sent ACK */ + drv->flags&=~I2C_DRV_SL_INRX; + msg=c552_sfnc_sl_prep(drv, drv->sl_last_cmd, I2C_MSG_SL_RX); + drv->msg_act=msg; + if(!msg) { + C552_CONCLR(port)=C552CON_AAC; + break; + } + C552_CONSET(port)=C552CON_AA; + + case 0xB8: + /* SLA R : sent DATA received ACK */ + if(!msg || (msg->tx_len>=msg->tx_rq)){ + C552_DAT(port) = 0xff; + break; + } + C552_DAT(port) = msg->tx_buf[msg->tx_len]; + msg->tx_len++; + break; + + case 0xC0: + /* SLA R : sent DATA received NACK */ + /* the A0 state is not enerred most probably */ + + case 0xC8: + /* SLA R : last data sent, DATA (AA=0) received ACK */ + /* the A0 state is not enerred most probably */ + C552_CONSET(port)=C552CON_AA; + + if(msg && (msg->flags&I2C_MSG_CB_END) && (msg->callback)) { + msg->callback(drv,I2C_MSG_CB_END|I2C_MSG_SL_TX,msg); + } + break; + + default: break; + } + + /* vymaz SI bit */ + C552_CONCLR(port)=C552CON_SIC; +} diff --git a/embedded/libs4c/i2c/i2c_drv.c b/embedded/libs4c/i2c/i2c_drv.c new file mode 100644 index 0000000..3a2f12a --- /dev/null +++ b/embedded/libs4c/i2c/i2c_drv.c @@ -0,0 +1,182 @@ +/******************************************************************* + Components for embedded applications builded for + laboratory and medical instruments firmware + + i2c_mx1.c - I2C communication automata for M9328 MX1 microcontroller + + Copyright holders and project originators + (C) 2001-2004 by Pavel Pisa pisa@cmp.felk.cvut.cz + (C) 2002-2004 by PiKRON Ltd. http://www.pikron.com + (C) 2007-2008 by Petr Smolik + + The COLAMI components can be used and copied under next licenses + - MPL - Mozilla Public License + - GPL - GNU Public License + - LGPL - Lesser GNU Public License + - and other licenses added by project originators + Code can be modified and re-distributed under any combination + of the above listed licenses. If contributor does not agree with + some of the licenses, he can delete appropriate line. + Warning, if you delete all lines, you are not allowed to + distribute code or build project. + *******************************************************************/ + + +#include +#include +#include "i2c_drv_config.h" +#include "i2c_drv.h" + +/***************************************************************************/ +int +i2c_drv_init(i2c_drv_t *drv, int port, int irq, int bitrate,int sladr) +{ + int r=-1; + memset(drv,0,sizeof(i2c_drv_t)); + drv->magic=I2C_DRV_MAGIC; + #ifdef CONFIG_OC_I2C_CHIP_C552 + r=c552_init_start(drv,port,irq,bitrate,sladr); + #endif /* CONFIG_OC_I2C_CHIP_C552 */ + if (r<0) return r; + return 0; +} + +/********************************************************************/ +/* Generic I2C functions */ + +void i2c_drv_queue_msg(i2c_msg_head_t **queue, i2c_msg_head_t *msg) +{ + I2C_IRQ_LOCK_FINI + i2c_msg_head_t *prev, *next; + I2C_IRQ_LOCK; + if(msg->on_queue){ + if(msg->next==msg){ + if(*msg->on_queue==msg) + *msg->on_queue=NULL; + }else{ + msg->next->prev=msg->prev; + msg->prev->next=msg->next; + if(*msg->on_queue==msg) + *msg->on_queue=msg->next; + } + } + if((msg->on_queue=queue)!=NULL){ + if((next=*queue)!=NULL){ + msg->prev=prev=next->prev; + msg->next=next; + next->prev=msg; + prev->next=msg; + }else{ + *queue=msg->prev=msg->next=msg; + } + } + I2C_IRQ_UNLOCK; + return; +} + +int i2c_drv_master_msg_ins(i2c_drv_t *drv, i2c_msg_head_t *msg) +{ + if(!drv) return -1; + if(!(drv->flags&I2C_DRV_ON)) return -1; + if(!msg->tx_buf) msg->flags&=~I2C_MSG_MS_TX; + if(!msg->rx_buf) msg->flags&=~I2C_MSG_MS_RX; + i2c_drv_queue_msg(&drv->master_queue,msg); + drv->ctrl_fnc(drv,I2C_CTRL_MS_RQ,NULL); + return 0; +} + +int i2c_drv_master_msg_rem(i2c_drv_t *drv, i2c_msg_head_t *msg) +{ + int act; + I2C_IRQ_LOCK_FINI + do { + i2c_drv_queue_msg(NULL,msg); + I2C_IRQ_LOCK; + act = (msg==drv->msg_act); + if(act) { + drv->msg_act=NULL; + } + I2C_IRQ_UNLOCK; + } while(msg->on_queue || act); + return 0; +} + +int i2c_drv_flush_all(i2c_drv_t *drv) +{ + I2C_IRQ_LOCK_FINI + i2c_msg_head_t *msg, *next; + i2c_msg_head_t *queue[3]; + int quenum; + + I2C_IRQ_LOCK; + queue[0]=drv->master_queue; + queue[1]=drv->slave_queue; + queue[2]=drv->proc_queue; + drv->master_queue=NULL; + drv->slave_queue=NULL; + drv->proc_queue=NULL; + drv->msg_act=NULL; + I2C_IRQ_UNLOCK; + for(quenum=0;quenum<3;quenum++){ + msg=queue[quenum]; + if(!msg) continue; + msg->prev->next=NULL; + for(;msg;msg=next){ + next=msg->next; + msg->flags|=I2C_MSG_FAIL; + msg->on_queue=NULL; + if((msg->flags&I2C_MSG_CB_PROC) && (msg->callback)) + msg->callback(drv,I2C_MSG_CB_PROC,msg); + } + } + return 0; +} + +int i2c_drv_master_transfer_callback(struct i2c_drv *drv, int code, struct i2c_msg_head *msg) +{ + if(code!=I2C_MSG_CB_PROC) return 0; + set_bit(0,&(msg->private)); + return 0; +} + + +int i2c_drv_master_transfer(i2c_drv_t *drv, int addr, int tx_rq, int rx_rq, + void *tx_buf, void *rx_buf, int *ptx_len, int *prx_len) +{ + i2c_msg_head_t msg; + + msg.flags = I2C_MSG_CB_PROC; + msg.addr = addr; + msg.tx_rq = tx_rq; + msg.rx_rq = rx_rq; + msg.tx_buf = tx_buf; + msg.rx_buf = rx_buf; + msg.on_queue = NULL; + msg.callback = i2c_drv_master_transfer_callback; + msg.private = 0; + + if(msg.tx_buf) + msg.flags |= I2C_MSG_MS_TX; + + if(msg.rx_buf && (msg.rx_rq>=1)) + msg.flags |= I2C_MSG_MS_RX; + + if(!(msg.flags & (I2C_MSG_MS_TX | I2C_MSG_MS_RX))) + return 0; + + if(i2c_drv_master_msg_ins(drv, &msg)<0) + return -1; + + /* wait for message process */ + while(test_bit(0,&(msg.private))==0) + drv->poll_fnc(drv); + + if(ptx_len) *ptx_len = msg.tx_len; + if(prx_len) *prx_len = msg.rx_len; + + if(msg.flags & I2C_MSG_FAIL) + return -1; + + return msg.tx_len+msg.rx_len; +} + diff --git a/embedded/libs4c/i2c/i2c_drv.h b/embedded/libs4c/i2c/i2c_drv.h new file mode 100644 index 0000000..50725d1 --- /dev/null +++ b/embedded/libs4c/i2c/i2c_drv.h @@ -0,0 +1,122 @@ +/******************************************************************* + Components for embedded applications builded for + laboratory and medical instruments firmware + + i2c_drv.h - I2C communication automat interface + + Copyright holders and project originators + (C) 2001-2008 by Pavel Pisa pisa@cmp.felk.cvut.cz + (C) 2002-2008 by PiKRON Ltd. http://www.pikron.com + (C) 2007-2008 by Petr Smolik + + The COLAMI components can be used and copied under next licenses + - MPL - Mozilla Public License + - GPL - GNU Public License + - LGPL - Lesser GNU Public License + - and other licenses added by project originators + Code can be modified and re-distributed under any combination + of the above listed licenses. If contributor does not agree with + some of the licenses, he can delete appropriate line. + Warning, if you delete all lines, you are not allowed to + distribute code or build project. + *******************************************************************/ + +#ifndef _I2C_DRV_H_ +#define _I2C_DRV_H_ + +#include +#include + +#if defined(CONFIG_OC_I2C_DRV_SYSLESS) + #define I2C_IRQ_LOCK_FINI unsigned long i2c_irq_lock_flags=0; + #define I2C_IRQ_LOCK \ + {save_flags(i2c_irq_lock_flags);cli();} + #define I2C_IRQ_UNLOCK \ + {restore_flags(i2c_irq_lock_flags);} + #define I2C_MB() {asm volatile ("":::"memory");} +#endif + +struct i2c_drv; + +#define I2C_MSG_TX 0x001 +#define I2C_MSG_RX 0x002 +#define I2C_MSG_MS_TX I2C_MSG_TX +#define I2C_MSG_MS_RX I2C_MSG_RX +#define I2C_MSG_SL_TX I2C_MSG_TX +#define I2C_MSG_SL_RX I2C_MSG_RX +#define I2C_MSG_SLAVE 0x004 +#define I2C_MSG_FAIL 0x008 +#define I2C_MSG_REPEAT 0x010 +#define I2C_MSG_NOPROC 0x020 +#define I2C_MSG_FINISHED 0x040 +#define I2C_MSG_CB_START 0x100 +#define I2C_MSG_CB_END 0x200 +#define I2C_MSG_CB_PROC 0x400 + +typedef struct i2c_msg_head { + unsigned long flags;/* message flags */ + uint8_t sl_cmd; /* command for slave queue lookup */ + uint8_t sl_msk; /* sl_cmd match mask */ + uint16_t addr; /* message destination address */ + uint16_t tx_rq; /* requested TX transfer length */ + uint16_t rx_rq; /* requested RX transfer length */ + uint16_t tx_len; /* finished TX transfer length */ + uint16_t rx_len; /* finished RX transfer length */ + uint8_t *tx_buf; /* pointer to TX data */ + uint8_t *rx_buf; /* pointer to RX data */ + struct i2c_msg_head *prev; + struct i2c_msg_head *next; + struct i2c_msg_head **on_queue; + int (*callback)(struct i2c_drv *ifc, int code, struct i2c_msg_head *msg); + unsigned long private; + } i2c_msg_head_t; + +typedef int (i2c_sfnc_t)(struct i2c_drv *drv, int code); +typedef int (i2c_ctrl_fnc_t)(struct i2c_drv *drv, int ctrl, void *p); + +#define I2C_DRV_ON 1 /* flag indicating that driver is ready to operate */ +#define I2C_DRV_MS_INPR 2 /* master request in in progress */ +#define I2C_DRV_NA 4 /* driver is not active for some period */ +#define I2C_DRV_SL_CEXP 8 /* slave expect receive of the first byte */ +#define I2C_DRV_SL_INRX 0x10 /* slave in mode */ + +#define I2C_DRV_MAGIC 0x12345432 + +typedef struct i2c_drv { + int magic; /* magic number */ + int irq; /* irq number */ + long port; /* base port number */ + uint8_t flags; + uint16_t self_addr; + i2c_msg_head_t *master_queue; + i2c_msg_head_t *slave_queue; + i2c_msg_head_t *proc_queue; + i2c_msg_head_t *msg_act; + i2c_sfnc_t *sfnc_act; + void *failed; + i2c_ctrl_fnc_t *ctrl_fnc; + int (*poll_fnc)(struct i2c_drv *drv); + uint8_t sl_last_cmd; /* last received slave command */ + } i2c_drv_t; + +#define I2C_CTRL_MS_RQ 1 + +#ifdef CONFIG_OC_I2C_CHIP_C552 +int c552_init_start(struct i2c_drv *drv, int port, int irq, int bitrate, int sladr); +#endif /* CONFIG_OC_I2C_CHIP_C552 */ + +void i2c_drv_queue_msg(i2c_msg_head_t **queue, i2c_msg_head_t *msg); +int i2c_drv_init(i2c_drv_t *drv, int port, int irq, int bitrate,int sladr); +int i2c_drv_master_msg_ins(i2c_drv_t *drv, i2c_msg_head_t *msg); +int i2c_drv_master_msg_rem(i2c_drv_t *drv, i2c_msg_head_t *msg); +int i2c_drv_flush_all(i2c_drv_t *drv); +int i2c_drv_master_transfer(i2c_drv_t *drv, int addr, int tx_rq, int rx_rq, + void *tx_buf, void *rx_buf, int *ptx_len, int *prx_len); + +#ifdef I2C_LOG_ENABLE + /* todo */ +#else + #define I2C_PRINTF(x,args...) +#endif + +#endif /* _I2C_DRV_H_ */ diff --git a/embedded/libs4c/kbd/Makefile b/embedded/libs4c/kbd/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/kbd/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/kbd/Makefile.omk b/embedded/libs4c/kbd/Makefile.omk new file mode 100644 index 0000000..72023f5 --- /dev/null +++ b/embedded/libs4c/kbd/Makefile.omk @@ -0,0 +1,9 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_KBD=n + +ifeq ($(CONFIG_KBD),y) +lib_LIBRARIES = kbd +include_HEADERS += kbd.h +kbd_SOURCES += kbd_base.c kbd_dev_ops.c +endif #CONFIG_KBD diff --git a/embedded/libs4c/kbd/kbd.h b/embedded/libs4c/kbd/kbd.h new file mode 100644 index 0000000..6721c8d --- /dev/null +++ b/embedded/libs4c/kbd/kbd.h @@ -0,0 +1,45 @@ +#include + +#ifndef KEY_DEFAULT_TIMES + #define KEY_PUSH_T 20 + #define KEY_RELEASE_T 10 + #define KEY_REPFIRST_T 800 + #define KEY_REPNEXT_T 300 +#endif /* KEY_DEFAULT_TIMES */ + +typedef struct { + kbd_key_t bc; + kbd_key_t sc; +} scan2key_t; + +typedef struct { + int scan; + int flag; + kbd_keymod_t is_mod; + kbd_keymod_t set_mod; + kbd_keymod_t xor_mod; +} scan2mod_t; + +#define KBDMOD_SGM_SC 0x8000 +#define KBDMOD_SGM_RELEASE 0x0080 + +extern int key_last_changed; +extern kbd_keymod_t key_mod; +extern unsigned char key_hit; +extern short key_use_timer; +extern unsigned char key_down_arr[KBD_SCAN_CNT]; + +unsigned char kbd_onerow(unsigned char scan); +void kbd_setio(void); + +int kbd_scan(); +void kbd_scan2mod(int scan_code); +int kbd_down(); +kbd_key_t kbd_scan2key(int scan); + +int kbd_Open(KBDDEVICE *pkd); +void kbd_Close(void); +void kbd_GetModifierInfo(kbd_keymod_t *modifiers, kbd_keymod_t *curmodifiers); +int kbd_Read(kbd_key_t *buf, kbd_keymod_t *modifiers, kbd_scan_code_t *scancode); +int kbd_Poll(void); + diff --git a/embedded/libs4c/kbd/kbd_base.c b/embedded/libs4c/kbd/kbd_base.c new file mode 100644 index 0000000..f59dd52 --- /dev/null +++ b/embedded/libs4c/kbd/kbd_base.c @@ -0,0 +1,183 @@ +#include "kbd.h" + +extern scan2key_t *kbd_scan2key_tab; +extern scan2mod_t *kbd_scan2mod_tab; + +/* State of keyboard matrix and key press reporting */ + +unsigned char key_down_arr[KBD_SCAN_CNT]; +unsigned char key_chng_arr[KBD_SCAN_CNT]; +unsigned char key_hit; + +kbd_keymod_t key_mod; + +int key_last_changed; + +/* Internal state for repeat processing */ + +short key_use_timer; +short key_state; +kbd_interval_t key_time; + +#define KEY_STATE_IDLE 0 +#define KEY_STATE_PUSH 1 +#define KEY_STATE_RELEASE 2 +#define KEY_STATE_REPEAT 4 +#define KEY_STATE_NOISE 8 +#define KEY_STATE_BUSY (KEY_STATE_PUSH|KEY_STATE_RELEASE) + + +/** + * kbd_scan - Scan keyboard matrix and report requests for state change + * + * Scans keyboard matrix connected row by row by calling function + * mx1_kbd_onerow(). Number of scanned output lines is defined + * by %KBD_SCAN_CNT. Checks read keyboard state against @key_down_arr + * and updates @key_change_arr array. The @key_down_arr state is + * left unchanged. It is changed later by kbd_down() function. + * Returns 0, if no keyboard activity is found. Returns 1 + * if at least one key is pressed. Returns 2 or 3 in case + * of detected change. + */ +int +kbd_scan() +{ + int i, ret=0; + unsigned char mask, val, chng; + for(i=0,mask=1;iscan);mt++) { + chng=(s==scan_code); + s--; + val=key_down_arr[s/KBD_RET_CNT]&(1<<(s%KBD_RET_CNT)); + if(val) { + key_mod|=mt->set_mod; + if(chng){ + key_mod^=mt->xor_mod; + } + } else { + key_mod&=~mt->set_mod; + } + } +} + +/** + * kbd_down - Detects changed key scancode and applies changes to matrix state + * + * Functions check @key_chng_arr and process changes. + * It updates its internal state @key_state, does + * noise cancellation and repeat timing, then updates + * @key_down_arr, stores detected scancode to @key_last_changed + * and calls modifiers processing kbd_scan2mod(). + * Return value is zero if no change is detected. + * In other case evaluated scancode is returned. + * Variable @key_hit signals by value 1 pressed key, by value + * 2 key release. + */ +int +kbd_down() +{ + int i, j=0; + unsigned char val; + + if(!(key_state&KEY_STATE_BUSY)){ + for(i=0;i>=1; + key_last_changed=i*KBD_RET_CNT+j+1; + if(key_down_arr[i]&(1< +#include "kbd.h" + +#ifdef _DEVICE_H +/* create the microwindows keyboard device */ + +KBDDEVICE kbddev = { + kbd_Open, + kbd_Close, + kbd_GetModifierInfo, + kbd_Read, + kbd_Poll +}; +#endif /* _DEVICE_H */ + +/** + * kbd_Open - Open the keyboard + * @pkd: Pointer to keyboard device + */ +int +kbd_Open(KBDDEVICE *pkd) +{ + key_last_changed=0; + key_mod=0; + key_hit=0; + key_use_timer=0; + memset(key_down_arr,0,sizeof(key_down_arr)); + kbd_setio(); + return 1; +} + +/** + * mx1_kbd_Close - Closes keyboard + */ +void +kbd_Close(void) +{ +} + +/** + * mx1_kbd_Poll - Polls for keyboard events + * + * Returns non-zero value if change is detected. + */ +int +kbd_Poll(void) +{ + if(key_hit) + return 1; + if(kbd_scan()) + kbd_down(); + return key_hit?1:0; +} + +/** + * kbd_GetModifierInfo - Returns the possible modifiers for the keyboard + * @modifiers: If non-NULL, ones in defined modifiers bits are returned. + * @curmodifiers: If non-NULL, ones in actually active modifiers + * bits are returned. + */ +void +kbd_GetModifierInfo(kbd_keymod_t *modifiers, kbd_keymod_t *curmodifiers) +{ + if (modifiers) + *modifiers = 0; /* no modifiers available */ + if (curmodifiers) + *curmodifiers = key_mod&~KBDMOD_SGM_SC; +} + +/** + * mx1_kbd_Read - Reads resolved MWKEY value, modifiers and scancode + * @buf: If non-NULL, resolved MWKEY is stored here + * @modifiers: If non-NULL, ones in actually active modifiers + * bits are returned + * @scancode: If non-NULL, scancode of resolved key is stored + * here + * + * This function reads one keystroke from the keyboard, and the current state + * of the modifier keys (ALT, SHIFT, etc). Returns -1 on error, 0 if no data + * is ready, 1 on a keypress, and 2 on keyrelease. + * This is a non-blocking call. + */ +int +kbd_Read(kbd_key_t *buf, kbd_keymod_t *modifiers, kbd_scan_code_t *scancode) +{ + int ret; + if(!key_hit) { + if(kbd_scan()){ + kbd_down(); + } + } + if(modifiers) + *modifiers = key_mod&~KBDMOD_SGM_SC; + if(!key_hit) + return 0; + if(scancode) + *scancode = key_last_changed; + if(buf) + *buf = kbd_scan2key(key_last_changed); + ret=key_hit; + key_hit=0; + return ret; +} diff --git a/embedded/libs4c/keyval/Makefile b/embedded/libs4c/keyval/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/keyval/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/keyval/Makefile.omk b/embedded/libs4c/keyval/Makefile.omk new file mode 100644 index 0000000..35b5272 --- /dev/null +++ b/embedded/libs4c/keyval/Makefile.omk @@ -0,0 +1,13 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_KEYVAL=n + +ifeq ($(CONFIG_KEYVAL),y) +lib_LIBRARIES = keyval +include_HEADERS += keyvalpb.h keyval_id.h +keyval_SOURCES += keyvalpb.c + +include_HEADERS += keyval_mem_store.h +keyval_SOURCES += keyval_mem_store.c + +endif #CONFIG_KEYVAL diff --git a/embedded/libs4c/keyval/keyval_id.h b/embedded/libs4c/keyval/keyval_id.h new file mode 100644 index 0000000..60641d2 --- /dev/null +++ b/embedded/libs4c/keyval/keyval_id.h @@ -0,0 +1,12 @@ +#ifndef _KEYVAL_ID_H_ +#define _KEYVAL_ID_H_ + +#include "keyvalpb.h" + +#define KVPB_KEYID_ULAN_ADDR 0x10 +#define KVPB_KEYID_ULAN_SN 0x11 + +#define KVPB_KEYID_HIS_ACCESS_CODE 0x20 + +#endif /* _KEYVAL_ID_H_ */ + diff --git a/embedded/libs4c/keyval/keyval_mem_store.c b/embedded/libs4c/keyval/keyval_mem_store.c new file mode 100644 index 0000000..b32e4df --- /dev/null +++ b/embedded/libs4c/keyval/keyval_mem_store.c @@ -0,0 +1,63 @@ +/******************************************************************************/ +/* Key Value block in RAM */ + +#include +#include +#include +#include + +int kvpb_mem_erase(kvpb_block_t *store, void *base,int size) +{ + memset(base,0xff,size); + return 0; +} + +int kvpb_mem_copy(kvpb_block_t *store, void *dst,const void *src,int len) +{ + memcpy(dst,src,len); + return 0; +} + +#ifndef KVPB_MINIMALIZED +kvpb_block_t *kvpb_store_create_ram(int size) +{ + kvpb_block_t *store; + int res; + + if(!size) + size=0x4000; + + store = malloc(sizeof(*store)); + if(store == NULL) + return NULL; + + memset(store, 0, sizeof(*store)); + + store->base = malloc(size*2); + if(store->base == NULL) + goto error_ret; + + store->size = size; + store->flags = KVPB_DESC_DOUBLE; + #ifndef KVPB_MINIMALIZED + store->erase = kvpb_mem_erase, + store->copy = kvpb_mem_copy; + #endif /* KVPB_MINIMALIZED */ + + kvpb_block_erase(store, store->base,store->size); + if(store->flags & KVPB_DESC_DOUBLE) + kvpb_block_erase(store, (uint8_t*)store->base+store->size,store->size); + + res=kvpb_check(store,3); + + if(res<0) + goto error_ret; + + return store; + + error_ret: + if(store) + free(store); + return NULL; +} +#endif /* KVPB_MINIMALIZED */ diff --git a/embedded/libs4c/keyval/keyval_mem_store.h b/embedded/libs4c/keyval/keyval_mem_store.h new file mode 100644 index 0000000..af3fdeb --- /dev/null +++ b/embedded/libs4c/keyval/keyval_mem_store.h @@ -0,0 +1,10 @@ +#ifndef _KEYVAL_MEM_STORE_H +#define _KEYVAL_MEM_STORE_H + +#include + +int kvpb_mem_erase(kvpb_block_t *store, void *base,int size); +int kvpb_mem_copy(kvpb_block_t *store, void *dst,const void *src,int len); +kvpb_block_t *kvpb_store_create_ram(int size); + +#endif /*_KEYVAL_MEM_STORE_H*/ diff --git a/embedded/libs4c/keyval/keyvalpb.c b/embedded/libs4c/keyval/keyvalpb.c new file mode 100644 index 0000000..e1f48b3 --- /dev/null +++ b/embedded/libs4c/keyval/keyvalpb.c @@ -0,0 +1,496 @@ +/******************************************************************* + Key Value Persistent Storage + + keyvalpb.c - key value parameters block + + (C) Copyright 2003-2005 by Pavel Pisa - Originator + (C) Copyright 2004-2005 by Petr Smolik - Originator + + The uLan utilities library can be used, copied and modified under + next licenses + - GPL - GNU General Public License + - LGPL - GNU Lesser General Public License + - MPL - Mozilla Public License + - and other licenses added by project originators + Code can be modified and re-distributed under any combination + of the above listed licenses. If contributor does not agree with + some of the licenses, he/she can delete appropriate line. + Warning, if you delete all lines, you are not allowed to + distribute source code and/or binaries utilizing code. + + See files COPYING and README for details. + + *******************************************************************/ + +#include +#include "keyvalpb.h" + +/* + * kvpb_memsum - Compute checksum of given memory area + * @base: Pointer to the base of of the region + * @size: Size of utilized part of the region + * + * Return Value: Computed checksum value + * File: keyvalpb.c + */ +kvpb_sum_t kvpb_memsum(KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size) +{ + KVPB_LOCALDATA kvpb_sum_t sum=0; + KVPB_DPTRTYPE uint16_t *p=(KVPB_DPTRTYPE uint16_t *)base; + size=(size+1)>>1; + while(size--){ + sum+=*(p++); + } + sum&=KVPB_SUM_MASK; + sum|=KVPB_SUM_OKVAL; + return sum; +} + +#ifndef KVPB_WITHOUT_HADLE +/* + * kvpb_get_psum - Get pointer to the region check sum + * @kvpb_block: Pointer to the KVPB access information/state structure + * @base: Pointer to the base of of the region + * @size: Size of one data block region + * + * Return Value: Pointer to the actual region check sum placement + * File: keyvalpb.c + */ +KVPB_DPTRTYPE kvpb_sum_t *kvpb_get_psum(kvpb_block_t *kvpb_block, + KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size) +#else +KVPB_DPTRTYPE kvpb_sum_t *__kvpb_get_psum( + KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size) +#endif +{ + KVPB_DPTRTYPE kvpb_sum_t *psum; + psum=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(base+size)-1); + while((KVPB_DPTRTYPE uint8_t*)psum>=base) { + if (*kvpb_psum_valid_loc(kvpb_block,psum)!=0) + return psum; + psum=kvpb_psum_align(kvpb_block,psum-1); + } + return NULL; +} + +#ifndef KVPB_WITHOUT_HADLE +/* + * kvpb_get_cfk - Get space where to place new key-value pair + * @kvpb_block: Pointer to the KVPB access information/state structure + * @mode: 0 .. work on active/valid data region; + * 1 .. work on the first copy/region, 2 .. work on the second copy/region + * @size: Size of required space for stored value + * + * Return Value: Pointer where next pair should be stored or %NULL + * File: keyvalpb.c + */ +KVPB_DPTRTYPE kvpb_key_t *kvpb_get_cfk(kvpb_block_t *kvpb_block,uint8_t mode,int size) +#else +KVPB_DPTRTYPE kvpb_key_t *__kvpb_get_cfk(uint8_t mode,int size) +#endif +{ + KVPB_DPTRTYPE kvpb_sum_t *psum; + KVPB_DPTRTYPE uint8_t *p; + KVPB_DPTRTYPE uint8_t *r; + p=kvpb_region_base(kvpb_block,0); + size=kvpb_chunk_align(kvpb_block,size+sizeof(kvpb_key_t))+ + (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0); + psum=kvpb_block->psum1; + if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) { + if(!(kvpb_block->flags&KVPB_DESC_DOUBLE)) + return NULL; + p=kvpb_region_base(kvpb_block,1); + psum=kvpb_block->psum2; + } + do { + kvpb_size_t ksize=((KVPB_DPTRTYPE kvpb_key_t *)p)->size; + if(ksize==KVPB_EMPTY) + break; + if(((uint8_t*)psum-(uint8_t*)p)flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0); + } while(1); + r=(KVPB_DPTRTYPE uint8_t*)p+size+sizeof(kvpb_key_t); + if(rflags&=~KVPB_DESC_USE2ND; + + p=kvpb_region_base(kvpb_block,0); + kvpb_block->psum1=kvpb_get_psum(kvpb_block,p,kvpb_block->size); + if (kvpb_block->psum1) { + sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p); + if(*kvpb_block->psum1==sum){ + ret=1; + } + } + + if(kvpb_block->flags&KVPB_DESC_DOUBLE){ + p=kvpb_region_base(kvpb_block,1); + kvpb_block->psum2=kvpb_get_psum(kvpb_block,p,kvpb_block->size); + if (kvpb_block->psum2) { + sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p); + if(*kvpb_block->psum2==sum) { + if(ret>=0){ + ret=0; + } else { + ret=2; + kvpb_block->flags|=KVPB_DESC_USE2ND; + } + } + } + } else { + if(ret>=0) + ret=0; + } + + if(ret){ + if(!mode) { + kvpb_block->flags|=KVPB_DESC_RO; + } else { + /* correct for FLASH */ + if(ret<0){ + p=kvpb_region_base(kvpb_block,0); + kvpb_block_erase(kvpb_block,p,kvpb_block->size); + kvpb_block->psum1=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1); + sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p); + kvpb_block_copy(kvpb_block,kvpb_block->psum1,&sum,sizeof(kvpb_sum_t)); + if(kvpb_block->flags&KVPB_DESC_DOUBLE){ + p=kvpb_region_base(kvpb_block,1); + kvpb_block_erase(kvpb_block,p,kvpb_block->size); + kvpb_block->psum2=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1); + sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p); + kvpb_block_copy(kvpb_block,kvpb_block->psum2,&sum,sizeof(kvpb_sum_t)); + } + ret=3; + }else{ + if(ret==1){ + kvpb_block_erase(kvpb_block,kvpb_region_base(kvpb_block,1),kvpb_block->size); + kvpb_block_copy(kvpb_block,kvpb_region_base(kvpb_block,1), + kvpb_region_base(kvpb_block,0),kvpb_block->size); + + }else{ + kvpb_block_erase(kvpb_block,kvpb_region_base(kvpb_block,0),kvpb_block->size); + kvpb_block_copy(kvpb_block,kvpb_region_base(kvpb_block,0), + kvpb_region_base(kvpb_block,1),kvpb_block->size); + } + } + kvpb_block->flags&=~KVPB_DESC_RO; + } + } + kvpb_block_flush(kvpb_block); + if(ret>=0) kvpb_block->flags|=KVPB_DESC_VALID; + return ret; +} + +#ifndef KVPB_WITHOUT_HADLE +/** + * kvpb_first - Get pointer to the first key-value pair in the KVPB storage + * @kvpb_block: Pointer to the KVPB access information/state structure + * @mode: 0 .. iterate over active/valid data region; + * 1 .. iterate over first copy/region, 2 .. iterate over second copy/region + * + * Return Value: Pointer to the first key-value pair + * or %NULL if no pair exist. + * File: keyvalpb.c + */ +KVPB_DPTRTYPE kvpb_key_t *kvpb_first(kvpb_block_t *kvpb_block, uint8_t mode) +#else +KVPB_DPTRTYPE kvpb_key_t *__kvpb_first(uint8_t mode) +#endif +{ + KVPB_DPTRTYPE kvpb_key_t *key=(KVPB_DPTRTYPE kvpb_key_t *)kvpb_region_base(kvpb_block,0); + if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) { + if(!(kvpb_block->flags&KVPB_DESC_DOUBLE)) + return NULL; + key=(KVPB_DPTRTYPE kvpb_key_t *)kvpb_region_base(kvpb_block,1); + } + while(*kvpb_keyid_valid(kvpb_block,key)==KVPB_KEYID_INVALID) { + key=kvpb_next(kvpb_block,key); + if (!key) + return NULL; + } + return key->size!=KVPB_EMPTY?key:NULL; +} + +#ifndef KVPB_WITHOUT_HADLE +/** + * kvpb_next - Iterate to the next consecutive key-value pair + * @kvpb_block: Pointer to the KVPB access information/state structure + * @key: Pointer to the previous key-value pair + * + * Return Value: Pointer to the next key-value pair + * or %NULL if no/no-more pairs exist. + * File: keyvalpb.c + */ +KVPB_DPTRTYPE kvpb_key_t *kvpb_next(kvpb_block_t *kvpb_block, KVPB_DPTRTYPE kvpb_key_t *key) +#else +KVPB_DPTRTYPE kvpb_key_t *__kvpb_next(KVPB_DPTRTYPE kvpb_key_t *key) +#endif +{ + do { + key=(KVPB_DPTRTYPE kvpb_key_t *)((KVPB_DPTRTYPE uint8_t *)key+ + kvpb_chunk_align(kvpb_block,key->size+sizeof(kvpb_key_t))+ + (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0)); + if (key->size==KVPB_EMPTY) return NULL; + } while(*kvpb_keyid_valid(kvpb_block,key)==KVPB_KEYID_INVALID); + return key; +} + +#ifndef KVPB_WITHOUT_HADLE +/** + * kvpb_find - Find first of occurrence of given key ID + * @kvpb_block: Pointer to the KVPB access information/state structure + * @keyid: Ordinal value representing key ID + * @mode: iteration mode modifier: 0 .. search in the active/valid data region; + * 1 .. search in the first copy/region, 2 .. search in the second copy/region + * @key: Previous key occurrence pointer or %NULL value to find first key ID named key-value pair + * + * Return Value: Pointer to the first on subsequent occurrence of key-value pair addressed by given key ID + * or %NULL if no/no-more occurrences exists. + * File: keyvalpb.c + */ +KVPB_DPTRTYPE kvpb_key_t *kvpb_find(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key) +#else +KVPB_DPTRTYPE kvpb_key_t *__kvpb_find(kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key) +#endif +{ + if(!(kvpb_block->flags&KVPB_DESC_VALID)) + return NULL; + if (key) { + key=kvpb_next(kvpb_block, key); + } else { + key=kvpb_first(kvpb_block, mode); + } + while(key) { + if((key->keyid==keyid) || (keyid==0)) + return key; + key=kvpb_next(kvpb_block, key); + } + return key; +} + +#ifndef KVPB_WITHOUT_HADLE +/** + * kvpb_compact_region - Compact one KVPB data block/region + * @kvpb_block: Pointer to the KVPB access information/state structure + * @keyid: Key ID which should be omitted from compacted data + * @mode: 0 .. compact active/valid data region; + * 1 .. compact the first data copy, 2 .. compact the second copy + * + * Return Value: Operation cannot be finished. + * File: keyvalpb.c + */ +int kvpb_compact_region(kvpb_block_t *kvpb_block, uint8_t mode, kvpb_keyid_t keyid) +#else +int __kvpb_compact_region(uint8_t mode, kvpb_keyid_t keyid) +#endif +{ + KVPB_DPTRTYPE uint8_t *p; + KVPB_DPTRTYPE kvpb_key_t *des,*src; + + p=kvpb_region_base(kvpb_block,0); + src=(KVPB_DPTRTYPE kvpb_key_t*)kvpb_region_base(kvpb_block,1); + des=(KVPB_DPTRTYPE kvpb_key_t*)p; + if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) { + if(!(kvpb_block->flags&KVPB_DESC_DOUBLE)) + return -1; + des=src; + src=(KVPB_DPTRTYPE kvpb_key_t*)p; + p=(KVPB_DPTRTYPE uint8_t *)des; + kvpb_block->psum2=kvpb_psum_align(kvpb_block, + (KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1); + } else { + kvpb_block->psum1=kvpb_psum_align(kvpb_block, + (KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1); + } + kvpb_block_flush(kvpb_block); + kvpb_block_erase(kvpb_block,des,kvpb_block->size); + while(src) { + int s=kvpb_chunk_align(kvpb_block,src->size+sizeof(kvpb_key_t)); + if((*kvpb_keyid_valid(kvpb_block,src)!=KVPB_KEYID_INVALID) && (src->keyid!=keyid)) { + kvpb_block_copy(kvpb_block,des,src,s); + if (kvpb_block->flags&KVPB_DESC_CHUNKWO) s+=kvpb_chunk_size(kvpb_block); + des=(KVPB_DPTRTYPE kvpb_key_t*)((uint8_t*)des+s); + } + src=kvpb_next(kvpb_block, src); + } + kvpb_block_flush(kvpb_block); + return 0; +} + +#ifndef KVPB_WITHOUT_HADLE +/** + * kvpb_get_key - Get value for given key ID + * @kvpb_block: Pointer to the KVPB access information/state structure + * @keyid: Ordinal value representing key ID + * @size: The size of the buffer provided to store data into + * @buf: Pointer to the buffer, where retrieved data should be copied + * + * Return Value: Number of retrieved value bytes if operation is successful + * or -1 if there is no such key ID or operation fails for other reason. + * File: keyvalpb.c + */ +int kvpb_get_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, void *buf) +#else +int __kvpb_get_key(kvpb_keyid_t keyid, kvpb_size_t size, void *buf) +#endif +{ + KVPB_DPTRTYPE kvpb_key_t *key; + key=kvpb_find(kvpb_block,keyid,0,NULL); + if(!key) return -1; + if(size && buf){ + if(key->sizesize; + memcpy(buf,key+1,size); + } + return key->size; +} + + +#ifndef KVPB_WITHOUT_HADLE +/** + * kvpb_set_key - Set new value or define new key-value pair + * @kvpb_block: Pointer to the KVPB access information/state structure + * @keyid: Ordinal value representing key ID, if or-red with %KVPB_KEYID_DUPLIC, + * the key ID can be defined/inserted multiple times + * @size: Stored value size in bytes + * @buf: Pointer to the stored value data + * + * Return Value: Number of stored bytes (equal to @size) if operation is successful + * or -1 if operation fails. + * File: keyvalpb.c + */ +int kvpb_set_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, const void *buf) +#else +int __kvpb_set_key(kvpb_keyid_t keyid, kvpb_size_t size, const void *buf) +#endif +{ + KVPB_LOCALDATA kvpb_sum_t sum; + KVPB_DPTRTYPE kvpb_sum_t *psum; + KVPB_DPTRTYPE kvpb_key_t *key; + KVPB_DPTRTYPE uint8_t *p; + + if(!(kvpb_block->flags&KVPB_DESC_VALID)) + return -1; + if(kvpb_block->flags&KVPB_DESC_RO) + return -1; + + /*first region*/ + psum=kvpb_psum_align(kvpb_block,kvpb_block->psum1); + sum=0; + kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t)); + kvpb_block->psum1=kvpb_psum_align(kvpb_block,kvpb_block->psum1-1); + if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) { + kvpb_each_from(kvpb_block,keyid,1,key) { + kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID; + kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t)); + } + } + key=kvpb_get_cfk(kvpb_block,1,size); + if (!key) { + kvpb_compact_region(kvpb_block,1,(keyid&KVPB_KEYID_DUPLIC)?0:keyid); + key=kvpb_get_cfk(kvpb_block,1,size); + } + if (keyid && key && buf) { + kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t)); + kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t)); + kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size); + } + /* need flush data to count correct value of new check sum */ + kvpb_block_flush(kvpb_block); + + p=kvpb_region_base(kvpb_block,0); + sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p); + kvpb_block_copy(kvpb_block,kvpb_block->psum1,&sum,sizeof(kvpb_sum_t)); + kvpb_block_flush(kvpb_block); + if(!(kvpb_block->flags&KVPB_DESC_DOUBLE)) + return key?size:-1; + + /*Write in the first region failed, switching to backup region */ + if(kvpb_block->flags&KVPB_DESC_RO){ + kvpb_block->flags|=KVPB_DESC_USE2ND; + return -1; + } + + /*second region*/ + psum=kvpb_psum_align(kvpb_block,kvpb_block->psum2); + sum=0; + kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t)); + kvpb_block->psum2=kvpb_psum_align(kvpb_block,kvpb_block->psum2-1); + if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) { + kvpb_each_from(kvpb_block,keyid,2,key) { + kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID; + kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t)); + } + } + key=kvpb_get_cfk(kvpb_block,2,size); + if (!key) { + kvpb_compact_region(kvpb_block,2,(keyid&KVPB_KEYID_DUPLIC)?0:keyid); + key=kvpb_get_cfk(kvpb_block,2,size); + } + if (keyid && key && buf) { + kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t)); + kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t)); + kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size); + } + kvpb_block_flush(kvpb_block); + + p=kvpb_region_base(kvpb_block,1); + sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p); + kvpb_block_copy(kvpb_block,kvpb_block->psum2,&sum,sizeof(kvpb_sum_t)); + kvpb_block_flush(kvpb_block); + /*Write in the second region failed, switching to the first region */ + if(kvpb_block->flags&KVPB_DESC_RO){ + kvpb_block->flags&=~KVPB_DESC_USE2ND; + return -1; + } + + return key?size:-1; +} + +#ifndef KVPB_MINIMALIZED +/** + * kvpb_err_keys - Erase/delete key-value pair + * @kvpb_block: Pointer to the KVPB access information/state structure + * @keyid: Ordinal value representing key ID + * + * Return Value: Positive or zero value informs about successful operation, + * -1 if operation fails. + * File: keyvalpb.c + */ +int kvpb_err_keys(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid) +{ + return kvpb_set_key(kvpb_block,keyid,0,NULL); +} +#endif /*KVPB_MINIMALIZED*/ + diff --git a/embedded/libs4c/keyval/keyvalpb.h b/embedded/libs4c/keyval/keyvalpb.h new file mode 100644 index 0000000..210a02b --- /dev/null +++ b/embedded/libs4c/keyval/keyvalpb.h @@ -0,0 +1,331 @@ +/******************************************************************* + Key Value Persistent Storage + + keyvalpb.h - key value parameters block + + (C) Copyright 2003-2005 by Pavel Pisa - Originator + (C) Copyright 2004-2005 by Petr Smolik - Originator + + The uLan utilities library can be used, copied and modified under + next licenses + - GPL - GNU General Public License + - LGPL - GNU Lesser General Public License + - MPL - Mozilla Public License + - and other licenses added by project originators + Code can be modified and re-distributed under any combination + of the above listed licenses. If contributor does not agree with + some of the licenses, he/she can delete appropriate line. + Warning, if you delete all lines, you are not allowed to + distribute source code and/or binaries utilizing code. + + See files COPYING and README for details. + + *******************************************************************/ + +#ifndef _KEYVALPB_H_ +#define _KEYVALPB_H_ + +//#include +#include +#include +#include + +#ifdef KVPB_MINIMALIZED +#define KVPB_WITHOUT_HADLE +#define KVPB_DPTRTYPE CODE +#define KVPB_LOCALDATA DATA +#endif /*KVPB_MINIMALIZED*/ + +#ifndef KVPB_DPTRTYPE +#define KVPB_DPTRTYPE +#endif /*KVPB_DPTRTYPE*/ + +#ifndef KVPB_LOCALDATA +#define KVPB_LOCALDATA +#endif /*KVPB_DPTRTYPE*/ + +#ifndef KVPB_BLOCK_LOC +#define KVPB_BLOCK_LOC +#endif /*KVPB_BLOCK_LOC*/ + +#define KVPB_EMPTY ((kvpb_size_t)~0) + +#define KVPB_KEYID_INVALID 0 +#define KVPB_KEYID_DUPLIC ((((kvpb_keyid_t)~0)>>1)+1) +#define KBPB_KEYID_INVALID_BIT (KVPB_KEYID_DUPLIC>>1) + +#define KVPB_SUM_MASK (((kvpb_sum_t)~0)>>2) +#define KVPB_SUM_OKVAL (KVPB_SUM_MASK+1) + +#define KVPB_DESC_DOUBLE 0x01 +#define KVPB_DESC_USE2ND 0x02 +#define KVPB_DESC_VALID 0x04 +#define KVPB_DESC_RO 0x08 +#define KVPB_DESC_CHUNKWO 0x10 +#define KVPB_DESC_ALIGN4 0x40 +#define KVPB_DESC_FLASH 0x80 + +#ifdef KVPB_MINIMALIZED +typedef uint16_t kvpb_sum_t; +typedef uint16_t kvpb_size_t; +typedef uint8_t kvpb_keyid_t; +#else /*KVPB_MINIMALIZED*/ +typedef uint32_t kvpb_sum_t; +typedef uint32_t kvpb_size_t; +typedef uint32_t kvpb_keyid_t; +#endif /*KVPB_MINIMALIZED*/ + +/** + * struct kvpb_block - Key-value parameter block access information + * @base: Pointer to the start of physically mapped key-value block data + * @size: Size of one region (one data copy) of parameter block + * @flags: Block state flags: + * %KVPB_DESC_DOUBLE - the information is stored in two consecutive redundant copies/regions; + * %KVPB_DESC_USE2ND - data will be read from the second copy because first one is damaged; + * %KVPB_DESC_VALID - at least one region is valid; + * %KVPB_DESC_RO - because of some problems, only read access is allowed + * %KVPB_DESC_CHUNKWO - chunk can be written only once between erase operations + * %KVPB_DESC_ALIGN4 - data has to be aligned to four bytes + * %KVPB_DESC_FLASH - flash memory is used for data storage + * @psum1: Pointer to the control checksum of the first data region + * @psum2: Pointer to the control checksum of the second data region + * @erase: Function to erase some range of the storage region + * @copy: Function to copy data into or between storage regions + * @flush: Function to finish pending copy operations + * @chunk_size: Minimal store chunk size which can be independently modified + * + * File: keyvalpb.h + */ +typedef struct kvpb_block { + KVPB_DPTRTYPE uint8_t *base; + kvpb_size_t size; + short flags; + KVPB_DPTRTYPE kvpb_sum_t *psum1; + KVPB_DPTRTYPE kvpb_sum_t *psum2; + #ifndef KVPB_MINIMALIZED + int (*erase)(struct kvpb_block *store, void *base,int size); + int (*copy)(struct kvpb_block *store, void *des,const void *src,int len); + int (*flush)(struct kvpb_block *store); + unsigned chunk_size; + #endif /* KVPB_MINIMALIZED */ +} kvpb_block_t; + + +#define kvpb_region_base(block,regidx) \ + ((((KVPB_DPTRTYPE uint8_t *)(block)->base)+(regidx*(block)->size))) + +#ifndef KVPB_MINIMALIZED + #ifndef kvpb_chunk_size + #define kvpb_chunk_size(store) ((store)->chunk_size<4?4:(store)->chunk_size) + #endif /*kvpb_chunk_size*/ + #define kvpb_chunk_size_mask(store) (kvpb_chunk_size(store)-1) + +/** + * kvpb_chunk_align - Round up KVPB size to minimal store chunk size multiple + * @store: Pointer to the KVPB access information/state structure + * @size: Unaligned size + * + * Return Value: Minimal aligned size to hold unaligned size. + * File: keyvalpb.h + */ + static inline unsigned kvpb_chunk_align(struct kvpb_block *store, unsigned size) + { + return ((size)+kvpb_chunk_size_mask(store))&~kvpb_chunk_size_mask(store); + } + +/** + * kvpb_psum_align - Round up KVPB size to minimal store chunk size multiple + * @store: Pointer to the KVPB access information/state structure + * @psum: Pointer to proposed location of next check sum location + * + * Return Value: Pointer to next check sum location rounded down to next slot. + * File: keyvalpb.h + */ + static inline kvpb_sum_t* kvpb_psum_align(struct kvpb_block *store, kvpb_sum_t *psum) + { + unsigned long mask=~kvpb_chunk_size_mask(store); + if(store->flags&KVPB_DESC_CHUNKWO) + mask<<=1; + return (kvpb_sum_t*)(((unsigned long)(psum))&mask); + } + +/** + * kvpb_psum_valid_loc - Return pointer to check sum validity info location + * @store: Pointer to the KVPB access information/state structure + * @psum: Pointer to corectly aligned check sum location + * + * Return Value: Pointer to location which indicates by zero value, that check sum + * is invalidated. + * File: keyvalpb.h + */ + static inline kvpb_sum_t* kvpb_psum_valid_loc(struct kvpb_block *store, kvpb_sum_t *psum) + { + if(!(store->flags&KVPB_DESC_CHUNKWO)) + return psum; + else + return (kvpb_sum_t*)(((char *)(psum))+kvpb_chunk_size(store)); + } + +/** + * kvpb_block_erase - Wrapper function to call KVPB specific data erase function + * @store: Pointer to the KVPB access information/state structure + * @base: Base address of erased region inside parameter block data region + * @size: Number of bytes to erase + * + * The KVPB mechanism is intended for FLASH type memories and it expect + * that only whole data region can be erased at time. The expected erase state + * is all bits set to the ones. + * + * Return Value: Negative value indicates operation fault. + * File: keyvalpb.h + */ + static inline int kvpb_block_erase(struct kvpb_block *store, void *base,int size) + { + return store->erase(store, base,size) ; + } + +/** + * kvpb_block_copy - Wrapper function to call KVPB specific data copy function + * @store: Pointer to the KVPB access information/state structure + * @des: Address of data destination pointing inside mapped parameter block data region + * @src: Address of data source pointing inside mapped parameter block data or RAM memory + * @len: Number of bytes to transfer + * + * Return Value: Negative value indicates operation fault. + * File: keyvalpb.h + */ + static inline int kvpb_block_copy(struct kvpb_block *store, void *des,const void *src,int len) + { + return store->copy(store, des, src, len); + } + +/** + * kvpb_block_flush - Wrapper function to call KVPB specific flush function + * @store: Pointer to the KVPB access information/state structure + * + * Return Value: Negative value indicates operation fault. + * File: keyvalpb.h + */ + static inline int kvpb_block_flush(struct kvpb_block *store) + { + if(!(store->flush)) return 0; + return store->flush(store); + } + +#else /* KVPB_MINIMALIZED */ + #ifndef kvpb_chunk_size + #define kvpb_chunk_size(store) 1 + #endif /*kvpb_chunk_size*/ + #define kvpb_chunk_size_mask(store) (kvpb_chunk_size(store)-1) + #define kvpb_chunk_align(store,x) \ + (((x)+kvpb_chunk_size_mask(store))&~kvpb_chunk_size_mask(store)) + #define kvpb_psum_align(store,x) \ + ((KVPB_DPTRTYPE kvpb_sum_t*)((unsigned)(x)&~kvpb_chunk_size_mask(store))) + #define kvpb_psum_valid_loc(store,x) \ + ((kvpb_sum_t*)((char*)(x)+0*kvpb_chunk_size(store))) +#ifndef kvpb_block_copy + #define kvpb_block_erase(store, base, size) flash_erase(base, size) + #define kvpb_block_copy(store, des, src, len) flash_copy(des, src, len) + #define kvpb_block_flush(store) flash_flush() + + /* forward declarations for external procedures */ + int flash_erase(void *base,int size); + int flash_copy(void *des,const void *src,int len); +#ifndef flash_flush + int flash_flush(void); +#endif /* flash_flush */ +#endif /* kvpb_block_copy */ +#endif /* KVPB_MINIMALIZED */ + +/** + * struct kvpb_key - Header of stored key value pair and structure for iteration over KVPB + * @size: Non-aligned byte size of the stored value + * @keyid: Ordinal value representing stored data key + * + * The header structure is followed by @size data bytes in the KVPB storage block. + * Because only word aligned write accesses are possible on some architectures + * and memory types the whole size of space occupied by one key-value pair is + * sum of rounded-up data size kvpb_chunk_align(@size) and size of header sizeof(kvpb_key_t). + */ +typedef struct kvpb_key { + kvpb_size_t size; + kvpb_keyid_t keyid; +} kvpb_key_t; + +#ifndef KVPB_WITHOUT_HADLE + static inline kvpb_keyid_t* kvpb_keyid_valid(struct kvpb_block *store, kvpb_key_t *key) + { + if(store->flags&KVPB_DESC_CHUNKWO) + return (kvpb_keyid_t*)((uint8_t*)key+(kvpb_chunk_align(store,key->size+sizeof(kvpb_key_t)))); + return &(key->keyid); + } +#else + #define kvpb_keyid_valid(store,key) (&((key)->keyid)) +#endif /*KVPB_WITHOUT_HADLE*/ + + +#ifndef KVPB_WITHOUT_HADLE +KVPB_DPTRTYPE kvpb_key_t *kvpb_first(kvpb_block_t *block, uint8_t mode); +KVPB_DPTRTYPE kvpb_key_t *kvpb_next(kvpb_block_t *block, KVPB_DPTRTYPE kvpb_key_t *key); +KVPB_DPTRTYPE kvpb_key_t *kvpb_find(kvpb_block_t *block, kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key); +int kvpb_get_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, void *buf); +int kvpb_set_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, const void *buf); +int kvpb_err_keys(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid); +int kvpb_check(kvpb_block_t *kvpb_block, uint8_t mode); +#else +extern KVPB_BLOCK_LOC kvpb_block_t kvpb_block_global; +#define kvpb_block (&kvpb_block_global) +KVPB_DPTRTYPE kvpb_sum_t *__kvpb_get_psum(KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size); +KVPB_DPTRTYPE kvpb_key_t *__kvpb_first(uint8_t mode); +KVPB_DPTRTYPE kvpb_key_t *__kvpb_next(KVPB_DPTRTYPE kvpb_key_t *key); +KVPB_DPTRTYPE kvpb_key_t *__kvpb_find(kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key); +int __kvpb_get_key(kvpb_keyid_t keyid, kvpb_size_t size, void *buf); +int __kvpb_set_key(kvpb_keyid_t keyid, kvpb_size_t size, const void *buf); +int __kvpb_check(uint8_t mode); +#define kvpb_get_psum(block, base, size) __kvpb_get_psum(base, size) +#define kvpb_first(block, mode) __kvpb_first(mode) +#define kvpb_next(block, key) __kvpb_next(key) +#define kvpb_find(block, keyid, mode, key) __kvpb_find(keyid, mode, key) +#define kvpb_get_key(block, keyid, size, buf) __kvpb_get_key(keyid, size, buf) +#define kvpb_set_key(block, keyid, size, buf) __kvpb_set_key(keyid, size, buf) +#define kvpb_err_keys(block,keyid) kvpb_set_key(block,keyid,0,NULL) +#define kvpb_check(block, mode) __kvpb_check(mode) +#define kvpb_compact_region(block, mode, keyid) __kvpb_compact_region(mode, keyid) +#define kvpb_get_cfk(block,mode,size) __kvpb_get_cfk(mode,size) +#endif + +/** + * kvpb_for_each - Iterate over all key value pairs + * @root: Pointer to the KVPB access information/state structure + * @key: Iterator of kvpb_key_t* type + * @mode: iteration mode modifier: 0 .. iterate over active/valid data region; + * 1 .. iterate over first copy, 2 .. iterate over second copy + * + * File: keyvalpb.h + */ +#define kvpb_for_each(root, key,mode) \ + for(key=kvpb_first(root,mode);key;\ + key=kvpb_next(root, key)) + +/** + * kvpb_for_each - Iterate over all key value pairs matching given key ID + * @root: Pointer to the KVPB access information/state structure + * @keyid: Ordinal value representing key ID + * @key: Iterator of kvpb_key_t* type + * @mode: iteration mode modifier: 0 .. iterate over active/valid data region; + * 1 .. iterate over first copy, 2 .. iterate over second copy + * + * File: keyvalpb.h + */ +#define kvpb_each_from(root, keyid, mode, key) \ + for(key=kvpb_find(root,keyid,mode,NULL);key;\ + key=kvpb_find(root,keyid,mode,key)) + +#ifdef KVPB_MINIMALIZED +#define kvpb_key2data(key) ((void*)(key+1)) +#else /*KVPB_MINIMALIZED*/ +static inline void* kvpb_key2data(kvpb_key_t *key) { return key+1; } +#endif /*KVPB_MINIMALIZED*/ + +#endif /* _KEYVALPB_H_ */ + diff --git a/embedded/libs4c/usb/Makefile b/embedded/libs4c/usb/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/usb/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/usb/Makefile.omk b/embedded/libs4c/usb/Makefile.omk new file mode 100644 index 0000000..71e412a --- /dev/null +++ b/embedded/libs4c/usb/Makefile.omk @@ -0,0 +1,3 @@ +# -*- makefile -*- + +SUBDIRS = base pdiusb more lpcusb diff --git a/embedded/libs4c/usb/base/Makefile b/embedded/libs4c/usb/base/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/usb/base/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/usb/base/Makefile.omk b/embedded/libs4c/usb/base/Makefile.omk new file mode 100644 index 0000000..b9d0731 --- /dev/null +++ b/embedded/libs4c/usb/base/Makefile.omk @@ -0,0 +1,21 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_USB_BASE=n + +ifeq ($(CONFIG_USB_BASE),y) +lib_LIBRARIES = usbbase + +#shared_LIBRARIES = + +#include_HEADERS = + +nobase_include_HEADERS = usb/usb.h usb/usb_spec.h usb/usb_srq.h usb/usbdebug.h usb/usb_devdes.h + +usbbase_SOURCES = usb.c usbdebug.c + +#lib_LOADLIBES = +#bin_PROGRAMS = +endif #CONFIG_USB_BASE + + + diff --git a/embedded/libs4c/usb/base/usb.c b/embedded/libs4c/usb/base/usb.c new file mode 100644 index 0000000..2061c8c --- /dev/null +++ b/embedded/libs4c/usb/base/usb.c @@ -0,0 +1,335 @@ +/*****************************************************/ +/*** Module : USB module ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002, 16.04.2003 ***/ +/*****************************************************/ + +//#include "hal.h" +#include +#include +#include +#include +#if __BYTE_ORDER == __BIG_ENDIAN + #include +#endif + +//#include /* to by tu pak nemelo bejt vubec ... */ +#include +#include + +#include /* temporary include - standard control request responses */ + +/* ep0 buffer */ + xdata unsigned char ep0_buffer[ MAX_CONTROL_XFER_DATA_SIZE]; + + +/* usb initialize */ + int usb_init( usb_device_t *udev) { + int ret = 0; + usb_debug_print( DEBUG_LEVEL_LOW, ("init_usb\r\n")); + /* create dynamic fields - endpoints */ + + udev->ep_events = 0; + udev->flags = 0; + udev->configuration = 0; + //udev->altinterface = 0; + udev->ep0.udev = udev; + udev->ep0.flags = USB_STATE_IDLE; + udev->ep0.epnum = 0; + +// usb_init_stdreq_fnc( udev); + + if ( usb_udev_is_fnc(udev,init)) { + ret = usb_udev_init( udev); + } + return ret; + } + + +// connecting to USB by SoftConnect + int usb_connect( usb_device_t *udev) { + int ret = 0; + usb_debug_print( DEBUG_LEVEL_LOW,("USB:ON\n")); + + udev->ep_events = 0; + udev->flags = 0; + udev->configuration = 0; + //udev->altinterface = 0; + udev->ep0.flags &= ~USB_STATE_MASK; //state = USB_STATE_IDLE; + + if ( usb_udev_is_fnc(udev,connect)) { + ret = usb_udev_connect( udev); + } + return ret; + } + + + int usb_disconnect( usb_device_t *udev) { + int ret = 0; + usb_debug_print( DEBUG_LEVEL_LOW,("USB:OFF\n")); + + udev->flags &= ~USB_FLAG_CONFIGURED; + udev->configuration = 0; + udev->ep_events = 0; + //udev->altinterface = 0; + udev->ep0.flags &= ~USB_STATE_MASK; //state = USB_STATE_IDLE; + + if ( usb_udev_is_fnc(udev,disconnect)) { + ret = usb_udev_disconnect( udev); + } + return ret; + } + + + void usb_stall( usb_ep_t *ep) { + usb_debug_print( DEBUG_LEVEL_HIGH, ("USB:STALL %1d\n", ep->epnum)); + if ( usb_udev_is_fnc(ep->udev,stall)) { + usb_udev_stall( ep); + } + } + + + int usb_check_events( usb_device_t *udev) + { + int ret = 0; + if ( usb_udev_is_fnc( udev, check_events)) { + ret = usb_udev_check_events( udev); + } + return ret; + } + + +// ************************************ +// *** Control transfer functions *** +// ************************************ + + void usb_complete_control_transfer(usb_ep_t *ep0, int status) { + usb_debug_print( DEBUG_LEVEL_HIGH, ( "CCT:st=%d", status)); + #ifdef USB_WITH_CB_FNC + if ( ep0->complete_fnc ) + ep0->complete_fnc( ep0, status); + ep0->next_pkt_fnc = NULL; + ep0->complete_fnc = NULL; + #endif /*USB_WITH_CB_FNC*/ + ep0->flags &= ~USB_STATE_MASK; //state = USB_STATE_IDLE; + } + +/* Send any data in the data phase of the control transfer */ + void usb_send_control_data( usb_device_t *udev, unsigned char *pData, unsigned short len) { + usb_ep_t *ep0 = &(udev->ep0); + usb_debug_print( DEBUG_LEVEL_HIGH, ( "SCD:ptr=%p,s=%d\n", pData, len)); + ep0->efnc = NULL; + ep0->ptr = pData; + ep0->actual = 0; + if ( ep0->size > len) ep0->size = len; + + /* Schedule TX processing for later execution */ + ep0->flags = (ep0->flags & ~USB_STATE_MASK) | USB_STATE_TRANSMIT; + udev->flags |= USB_FLAG_EVENT_TX0; + } + + void usb_set_control_endfnc( usb_device_t *udev, endfnc_t *efnc) { //REENTRANT_SIGN { + udev->ep0.efnc = efnc; + } + + void usb_ack_setup( usb_ep_t *ep) { + usb_udev_ack_setup(ep->udev); + } + + +/************************************************************* + *** Control endpoint0 responses + *************************************************************/ + int usb_control_response( usb_device_t *udev) { + int ret = 0; + usb_ep_t *ep0 = &(udev->ep0); + +/* response to interrupt BusReset */ + if ( udev->flags & USB_FLAG_BUS_RESET) { + udev->flags &= ~(USB_FLAG_BUS_RESET | USB_FLAG_SUSPEND); // usb_flags.bus_reset = 0; usb_flags.configured = 0; + usb_debug_print( DEBUG_LEVEL_MEDIUM, ( "USBreset\n")); + ret = 1; + } +/* response to interrupt Suspend */ + if ( udev->flags & USB_FLAG_SUSPEND) { + udev->flags &= ~(USB_FLAG_SUSPEND); //usb_flags.suspend = 0; + usb_debug_print( DEBUG_LEVEL_MEDIUM, ( "USBsuspend\n")); + ret = 1; + } + + +/* response to interrupt SetupPacket execute response to standard device request or vendor request */ + if ( udev->flags & USB_FLAG_SETUP) { + unsigned char type, req; + USB_DEVICE_REQUEST *preq = &(udev->request); + + ep0->ptr = NULL; + ep0->size = 0; + ep0->actual = 0; + ep0->efnc = NULL; + ep0->flags &= ~USB_STATE_MASK; //state = USB_STATE_IDLE; + udev->flags &= ~USB_FLAG_SETUP; // usb_flags.setup_packet = 0; + #ifdef USB_WITH_CB_FNC + ep0->next_pkt_fnc = NULL; + ep0->complete_fnc = NULL; + #endif /*USB_WITH_CB_FNC*/ + + if ( usb_udev_read_endpoint(ep0, preq, sizeof( USB_DEVICE_REQUEST)) + != sizeof( USB_DEVICE_REQUEST)) { + usb_udev_stall( ep0); + return -1; + } + #if __BYTE_ORDER == __BIG_ENDIAN + preq->wValue = bswap_16( preq->wValue); + preq->wIndex = bswap_16( preq->wIndex); + preq->wLength = bswap_16( preq->wLength); + #endif + usb_debug_print( DEBUG_LEVEL_MEDIUM,( "SePa:x%02X,x%02X,x%04X,x%04X,x%04X\n", preq->bmRequestType, preq->bRequest, preq->wValue, preq->wIndex, preq->wLength)); + + // acknowledge setup here + if(usb_udev_is_fnc( udev, ack_control_setup)) { + usb_udev_ack_control_setup(udev); + } + + ep0->size = preq->wLength; + if ((( preq->bmRequestType & USB_DATA_DIR_MASK) == USB_DATA_DIR_FROM_HOST) && preq->wLength) { + ep0->ptr = ep0_buffer; + ep0->flags = (ep0->flags & ~USB_STATE_MASK) | USB_STATE_RECEIVE; + } + + type = preq->bmRequestType & USB_REQUEST_TYPE_MASK; + req = preq->bRequest & USB_REQUEST_MASK; + if ( type == USB_STANDARD_REQUEST) { + int ret = -1; + usb_debug_print( DEBUG_LEVEL_HIGH, ( "StdReq-%d\n", req)); +/* + if ( (udev->stdreq[ req]) != NULL) { + ret = udev->stdreq[ req]( udev); + } + if( ret < 0) + udev->ack_setup( udev); +*/ + switch( req) { + case USB_REQUEST_GET_STATUS: ret=usb_stdreq_get_status( udev); break; + case USB_REQUEST_CLEAR_FEATURE: ret=usb_stdreq_clear_feature( udev); break; + case USB_REQUEST_SET_FEATURE: ret=usb_stdreq_set_feature( udev); break; + case USB_REQUEST_SET_ADDRESS: ret=usb_stdreq_set_address( udev); break; + + case USB_REQUEST_GET_DESCRIPTOR: ret=usb_stdreq_get_descriptor( udev); break; +// case USB_REQUEST_SET_DESCRIPTOR: break; + case USB_REQUEST_GET_CONFIGURATION: ret=usb_stdreq_get_configuration( udev); break; + case USB_REQUEST_SET_CONFIGURATION: ret=usb_stdreq_set_configuration( udev); break; + case USB_REQUEST_GET_INTERFACE: ret=usb_stdreq_get_interface( udev); break; + case USB_REQUEST_SET_INTERFACE: ret=usb_stdreq_set_interface( udev); break; +// case USB_REQUEST_SYNC_FRAME: break; +// default: ret=-1; break; + } + if (ret<0) + usb_udev_stall( ep0); + } else { + if ( type == USB_VENDOR_REQUEST) { +//putchar('#'); + #ifdef USB_WITH_CB_FNC + int ret = -1; +// if(USBVendorRequestCBFnc != NULL) +// ret = USBVendorRequestCBFnc(&usb_ep0, &dreq); + if ( udev->vendor_fnc != NULL) + ret = udev->vendor_fnc( udev); + if ( ret < 0) + usb_udev_stall( ep0); +// #else /*USB_WITH_CB_FNC*/ +// if ( USBVendorRequest(&dreq) == -1) +// udev->ack_setup( udev); + #endif /*USB_WITH_CB_FNC*/ + } else if ( type == USB_CLASS_REQUEST) { + #ifdef USB_WITH_CB_FNC + int ret = -1; +// if(USBClassRequestCBFnc != NULL) +// ret = USBClassRequestCBFnc(&usb_ep0, &dreq); + if( udev->class_fnc != NULL) + ret = udev->class_fnc( udev); + if( ret < 0) + usb_udev_stall( ep0); +// #else /*USB_WITH_CB_FNC*/ +// if ( USBClassRequest(&dreq) == -1) +// udev->ack_setup( udev); + #endif /*USB_WITH_CB_FNC*/ + } else + usb_udev_stall( ep0); + } + ret = 1; + } + +/* response to interrupt Ep0RxInt - receive data */ + if ( udev->flags & USB_FLAG_EVENT_RX0) { + int i; + udev->flags &= ~USB_FLAG_EVENT_RX0; + usb_debug_print( DEBUG_LEVEL_MEDIUM, ( "Ep0Rx\n")); + if (( ep0->flags & USB_STATE_MASK) == USB_STATE_RECEIVE) { + usb_debug_print( DEBUG_LEVEL_HIGH, ( "RCV:p=%04lX,s=%d\n", (unsigned long)ep0->ptr, ep0->size)); + + i = usb_udev_read_endpoint(ep0, ep0->ptr, ep0->max_packet_size); + ep0->actual += i; + ep0->ptr +=i; + + #ifdef USB_WITH_CB_FNC + if ( ep0->next_pkt_fnc ) { + if( ep0->next_pkt_fnc( ep0, i, USB_NEXT_PKT_REC) < 0) { + usb_udev_stall( ep0); + return -1; + } + } + #endif /*USB_WITH_CB_FNC*/ + + if (( i != ep0->max_packet_size) || ( ep0->actual >= ep0->size)) { + usb_complete_control_transfer( ep0, USB_COMPLETE_OK ); + if ( ep0->efnc) { + ep0->efnc(ep0); + } + } + } else { + ep0->flags &= ~USB_STATE_MASK; //state = USB_STATE_IDLE; + } + } + +/* response to interrupt Ep0TxInt */ + if ( udev->flags & USB_FLAG_EVENT_TX0) { + short i = ep0->size - ep0->actual; + udev->flags &= ~USB_FLAG_EVENT_TX0; +//usb_debug_print( DEBUG_LEVEL_LOW, ("0S-%d(%d){%d}\n", ep0->state, ep0->size, ep0->max_packet_size)); + usb_debug_print( DEBUG_LEVEL_MEDIUM, ( "EP0Tx:i=%d\n", i)); + + if (( ep0->flags & USB_STATE_MASK) == USB_STATE_TRANSMIT) { + + if(i > ep0->max_packet_size) i = ep0->max_packet_size; + + if ( i > 0 ) { + #ifdef USB_WITH_CB_FNC + if ( ep0->next_pkt_fnc) { + if( ep0->next_pkt_fnc( ep0, i, USB_NEXT_PKT_SEND) < 0) { + usb_udev_stall( ep0); + return -1; + } + } + #endif /*USB_WITH_CB_FNC*/ + usb_debug_print( DEBUG_LEVEL_HIGH, ("Wr(%d)\n",i)); + usb_udev_write_endpoint( ep0, ep0->ptr, i); + ep0->actual += i; + ep0->ptr +=i; + + if( i != ep0->max_packet_size) { + /* last packed without full size has been sent, state can change to idle */ + usb_complete_control_transfer( ep0, USB_COMPLETE_OK ); + } + } else { + usb_udev_ack_setup( udev); // Send zero packet at the end ??? + usb_complete_control_transfer( ep0, USB_COMPLETE_OK ); + } + } + ret = 1; + } + + return ret; + } + + diff --git a/embedded/libs4c/usb/base/usb/usb.h b/embedded/libs4c/usb/base/usb/usb.h new file mode 100644 index 0000000..4807b59 --- /dev/null +++ b/embedded/libs4c/usb/base/usb/usb.h @@ -0,0 +1,191 @@ +/**************************************************************/ +/*** Module : USB module - header file ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002 ***/ +/*** Rewrite: 05.09.2002 ***/ +/**************************************************************/ + +#ifndef _USB_MODULE_ + #define _USB_MODULE_ + + #include "usb_spec.h" + #include "usb_devdes.h" + +#if defined(SDCC) || defined(__KEIL__) || defined(__C51__) + /*8051 special handling*/ + #define REENTRANT_SIGN reentrant +#else + #define xdata /*nothing*/ + #define REENTRANT_SIGN /*nothing*/ +#endif + +#define USB_WITH_CB_FNC +//#define USB_WITH_UDEV_FNC + +#ifdef USB_WITH_UDEV_FNC + #define USB_UDEV_REENTRANT_SIGN REENTRANT_SIGN +#else /*USB_WITH_UDEV_FNC*/ + #define USB_UDEV_REENTRANT_SIGN /*nothing*/ +#endif /*USB_WITH_UDEV_FNC*/ + +/* control endpoint */ + #define MAX_CONTROL_XFER_DATA_SIZE 8 + + struct usb_ep_t; + + typedef void endfnc_t( struct usb_ep_t *ep) REENTRANT_SIGN; + + #define USB_NEXT_PKT_SEND 0 + #define USB_NEXT_PKT_REC 1 + + #define USB_COMPLETE_OK 0 + #define USB_COMPLETE_FAIL -1 + + typedef struct usb_ep_t { + struct usb_device_t *udev; /* pointer to parent device */ + unsigned short max_packet_size; /* max. size of endpoint package, e.g. PDI_EP0_PACKET_SIZE */ + unsigned char *ptr; /* pointer to current transmitted data */ + unsigned int size; /* full size of current transmitted data */ + unsigned int actual; /* transmitted data size */ + endfnc_t *efnc; /* ??? */ + unsigned char flags; /* endpoint flags & state - idle,receiving, transmitting ??? HERE ??? */ + unsigned char epnum; /* endpoint number (index) - endpoint0 must be set to 0 */ + unsigned short event_mask; /* event(interrupt) mask for this endpoint, e.g. PDI_INT_EP1_IN for pdiusbd1x */ + #ifdef USB_WITH_CB_FNC + int (*next_pkt_fnc)(struct usb_ep_t *ep, int len, int codeval) REENTRANT_SIGN; + int (*complete_fnc)(struct usb_ep_t *ep, int status) REENTRANT_SIGN; + long user_data; + #endif /*USB_WITH_CB_FNC*/ + } usb_ep_t; + + +/* Vendor & Class functions */ +/* + #ifdef USB_WITH_CB_FNC + typedef int usb_vendor_extension_fnc_t(usb_ep_t *ep, USB_DEVICE_REQUEST *dreq); + extern xdata usb_vendor_extension_fnc_t USBVendorRequestCBFnc; + + typedef int usb_class_extension_fnc_t(usb_ep_t *ep, USB_DEVICE_REQUEST *dreq); + extern xdata usb_class_extension_fnc_t USBClassRequestCBFnc; + #else //USB_WITH_CB_FNC + char USBVendorRequest( USB_DEVICE_REQUEST *dr); + char USBClassRequest( USB_DEVICE_REQUEST *dr); + #endif //USB_WITH_CB_FNC +*/ + + +/* USB device */ + typedef struct usb_device_t { + unsigned char id; /* device ID ??? */ + unsigned char flags; /* usb device flags + endpoint0 events */ + unsigned char ep_events; /* one bit for each endpoint (without ep0) event,(bit0 for udev->ep[0], bit1 for udev->ep[1], ...)*/ + unsigned char configuration; /* current configuration */ +// unsigned char interface; /* current interface */ +// unsigned char altinterface; /* current alternative interface */ + + //int (stdreq[13])( struct usb_device_t *udev) REENTRANT_SIGN; /* pointer to array of standard request processing functions */ + int (*vendor_fnc)( struct usb_device_t *udev) REENTRANT_SIGN; /* pointer to vendor request processing function */ + int (*class_fnc)( struct usb_device_t *udev) REENTRANT_SIGN; /* pointer to class request processing function */ + + const USB_DEVICE_DESCRIPTORS_TABLE *devdes_table; + + #ifdef USB_WITH_UDEV_FNC + int (*init)( struct usb_device_t *udev) REENTRANT_SIGN; /* function for hw specific part of initialize usb device */ + int (*set_addr)( struct usb_device_t *udev, unsigned char addr) REENTRANT_SIGN; /* set device address */ + int (*set_configuration)( struct usb_device_t *udev, unsigned char iCfg) REENTRANT_SIGN; /* set device configuration */ + int (*connect)( struct usb_device_t *udev) REENTRANT_SIGN; /* function for hw specific part of connecting device to usb */ + int (*disconnect)( struct usb_device_t *udev) REENTRANT_SIGN; /* function for hw specific part of disconnecting device to usb */ + void (*ack_setup)( struct usb_device_t *udev) REENTRANT_SIGN; /* function for hw specific part of control response acknowledge */ + void (*ack_control_setup)( struct usb_device_t *udev) REENTRANT_SIGN; /* function for hw specific part of control response acknowledge */ + int (*check_events)( struct usb_device_t *udev) REENTRANT_SIGN; /* hw specific part of function for checking events */ + void (*stall)( usb_ep_t *ep) REENTRANT_SIGN; /* hw specific function to stall endpoint */ + void (*unstall)( usb_ep_t *ep) REENTRANT_SIGN; /* hw specific function to unstall endpoint */ + int (*read_endpoint)( usb_ep_t *ep, void *ptr, int size) REENTRANT_SIGN; + int (*write_endpoint)( usb_ep_t *ep, const void *ptr, int size) REENTRANT_SIGN; + #endif /*USB_WITH_UDEV_FNC*/ + +// USB_DEVICE_REQUEST *request; /* current usb request - only if there is a valid usb request in processing */ + USB_DEVICE_REQUEST request; /* usb device request */ + + unsigned char cntep; /* number of device endpoints in ep array without EP0 */ + usb_ep_t ep0; /* endpoint 0 */ + usb_ep_t *ep; /* others endpoints in array */ + } usb_device_t; + + +/* endpoint flags */ + /* endpoint state */ + #define USB_STATE_IDLE 0x00 + #define USB_STATE_TRANSMIT 0x01 + #define USB_STATE_RECEIVE 0x02 + #define USB_STATE_MASK 0x03 + +/* usb_device flags */ + #define USB_FLAG_CONFIGURED 0x01 + #define USB_FLAG_BUS_RESET 0x02 + #define USB_FLAG_SUSPEND 0x04 + #define USB_FLAG_SETUP 0x08 // setup_packet + #define USB_FLAG_REMOTE_WAKE 0x10 + + #define USB_FLAG_EVENT_RX0 0x40 + #define USB_FLAG_EVENT_TX0 0x80 + + + +/* device functions - inline ??? */ + int usb_init( usb_device_t *udev); + int usb_connect( usb_device_t *udev); + int usb_disconnect( usb_device_t *udev); + void usb_stall( usb_ep_t *ep); + void usb_unstall( usb_ep_t *ep); + + #define usb_stall_ep0( udev) \ + do { \ + usb_stall( &(udev->ep0)); \ + } while(0) + +/* check usb events(interrupts) */ + int usb_check_events( usb_device_t *udev); +/* response to standard constrol requests */ + int usb_control_response( usb_device_t *udev); +/* send control data */ + void usb_send_control_data( usb_device_t *udev, unsigned char *pData, unsigned short len); + void usb_set_control_endfnc( usb_device_t *udev, endfnc_t *efnc);// REENTRANT_SIGN; + void usb_ack_setup( usb_ep_t *ep); + + +/* Standard requests functions */ +// typedef int (*usb_stdreq_fnc_t)( usb_device_t *udev) REENTRANT_SIGN; +// extern xdata usb_stdreq_fnc_t usb_standard_requests[13]; + + +#ifdef USB_WITH_UDEV_FNC + + #define usb_udev_is_fnc(_M_udev, _M_fnc) (_M_udev->_M_fnc) + + #define usb_udev_init(_M_udev) (_M_udev->init(_M_udev)) + #define usb_udev_set_addr(_M_udev, _M_addr) (_M_udev->set_addr(_M_udev, _M_addr)) + #define usb_udev_set_configuration(_M_udev, _M_iCfg) (_M_udev->set_configuration(_M_udev, _M_iCfg)) + #define usb_udev_connect(_M_udev) (_M_udev->connect(_M_udev)) + #define usb_udev_disconnect(_M_udev) (_M_udev->disconnect(_M_udev)) + #define usb_udev_ack_setup(_M_udev) (_M_udev->ack_setup(_M_udev)) + #define usb_udev_ack_control_setup(_M_udev) (_M_udev->ack_control_setup(_M_udev)) + #define usb_udev_check_events(_M_udev) (_M_udev->check_events(_M_udev)) + + #define usb_udev_stall(_M_ep) ((_M_ep)->udev->stall(_M_ep)) + #define usb_udev_unstall(_M_ep) ((_M_ep)->udev->unstall(_M_ep)) + + #define usb_udev_read_endpoint(_M_ep, _M_ptr, _M_size) \ + ((_M_ep)->udev->read_endpoint(_M_ep, _M_ptr, _M_size)) + + #define usb_udev_write_endpoint(_M_ep, _M_ptr, _M_size) \ + ((_M_ep)->udev->write_endpoint(_M_ep, _M_ptr, _M_size)) + +#else /*USB_WITH_UDEV_FNC*/ + + #define USB_PDI_DIRECT_FNC + #include "pdi.h" + +#endif /*USB_WITH_UDEV_FNC*/ + +#endif diff --git a/embedded/libs4c/usb/base/usb/usb_devdes.h b/embedded/libs4c/usb/base/usb/usb_devdes.h new file mode 100644 index 0000000..11d1337 --- /dev/null +++ b/embedded/libs4c/usb/base/usb/usb_devdes.h @@ -0,0 +1,34 @@ +/*************************************************/ +/*** Module : USB device descriptor table ***/ +/*** Author : Roman Bartosinski, Pavel Pisa ***/ +/*** Modify : 10.11.2008 ***/ +/*************************************************/ + +#ifndef _USB_DEVICE_DESCRIPTOR_TABLE + #define _USB_DEVICE_DESCRIPTOR_TABLE + + #include "usb_spec.h" + + struct _tag_usb_device_configuration_entry { + const USB_CONFIGURATION_DESCRIPTOR *pConfigDescription; + int iConfigTotalLength; + }; + typedef struct _tag_usb_device_configuration_entry + USB_DEVICE_CONFIGURATION_ENTRY, *PUSB_DEVICE_CONFIGURATION_ENTRY; + + struct _tag_usb_device_descriptors_table { + const USB_DEVICE_DESCRIPTOR *pDeviceDescription; + const USB_DEVICE_CONFIGURATION_ENTRY *pConfigurations; + const USB_INTERFACE_DESCRIPTOR **pInterfaceDescriptors; + const PUSB_STRING_DESCRIPTOR *pStrings; + int iNumStrings; + uint8_t bNumEndpoints; + uint8_t bNumConfigurations; + uint8_t bNumInterfaces; + }; + typedef struct _tag_usb_device_descriptors_table + USB_DEVICE_DESCRIPTORS_TABLE, *PUSB_DEVICE_DESCRIPTOR_TABLE; + + +#endif /*_USB_DEVICE_DESCRIPTOR_TABLE*/ + diff --git a/embedded/libs4c/usb/base/usb/usb_spec.h b/embedded/libs4c/usb/base/usb/usb_spec.h new file mode 100644 index 0000000..7d6f87b --- /dev/null +++ b/embedded/libs4c/usb/base/usb/usb_spec.h @@ -0,0 +1,228 @@ +/*************************************************/ +/*** Module : USB specification ***/ +/*** Author : Roman Bartosinski 29.07.2002 ***/ +/*** Modify : 08.08.2002, 14.01.2003 ***/ +/*************************************************/ + +#ifndef _USB_SPECIFICATIONS_AND_DEFINITIONS_MODULE + #define _USB_SPECIFICATIONS_AND_DEFINITIONS_MODULE + +/*#include */ +#include + +#ifndef PACKED + #ifdef __GNUC__ + #define PACKED __attribute__((packed)) + #else /*__GNUC__*/ + #define PACKED /*nothing*/ + #endif /*__GNUC__*/ +#endif + +/* this section is from __USB100.H__ and __CHAP9.H__ and define USB constants and structs */ + +/* *** USB Device Request *** (spec. 9.3) */ + typedef struct _tag_usb_device_request { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + } USB_DEVICE_REQUEST; + +/****************************************************************************************/ +/*** definitions for USB tranfer standard packets described in USB secif. - chapter 9 ***/ +/****************************************************************************************/ + #define DEVICE_ADDRESS_MASK 0x7F + +/* bmRequestType D7 - Data transfer direction */ + #define USB_DATA_DIR_MASK (uint8_t)0x80 + #define USB_DATA_DIR_FROM_HOST (uint8_t)0x00 + #define USB_DATA_DIR_TO_HOST (uint8_t)0x80 +/* bmRequestType D4..D0 - Recipient */ + #define USB_RECIPIENT (uint8_t)0x1F + #define USB_RECIPIENT_DEVICE (uint8_t)0x00 + #define USB_RECIPIENT_INTERFACE (uint8_t)0x01 + #define USB_RECIPIENT_ENDPOINT (uint8_t)0x02 + #define USB_RECIPIENT_OTHER (uint8_t)0x03 +/* bmRequestType D6..D5 - Type */ + #define USB_REQUEST_TYPE_MASK (uint8_t)0x60 + #define USB_STANDARD_REQUEST (uint8_t)0x00 + #define USB_CLASS_REQUEST (uint8_t)0x20 + #define USB_VENDOR_REQUEST (uint8_t)0x40 +/* Standard request codes (spec. 9.4) */ + #define USB_REQUEST_MASK (uint8_t)0x0F + #define USB_REQUEST_GET_STATUS 0x00 + #define USB_REQUEST_CLEAR_FEATURE 0x01 + #define USB_REQUEST_SET_FEATURE 0x03 + #define USB_REQUEST_SET_ADDRESS 0x05 + #define USB_REQUEST_GET_DESCRIPTOR 0x06 + #define USB_REQUEST_SET_DESCRIPTOR 0x07 + #define USB_REQUEST_GET_CONFIGURATION 0x08 + #define USB_REQUEST_SET_CONFIGURATION 0x09 + #define USB_REQUEST_GET_INTERFACE 0x0A + #define USB_REQUEST_SET_INTERFACE 0x0B + #define USB_REQUEST_SYNC_FRAME 0x0C +/* Descriptor types (spec. 9.4) */ + #define USB_DESCRIPTOR_TYPE_DEVICE 0x01 + #define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02 + #define USB_DESCRIPTOR_TYPE_STRING 0x03 + #define USB_DESCRIPTOR_TYPE_INTERFACE 0x04 + #define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05 + #define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06 + #define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 0x07 + #define USB_DESCRIPTOR_TYPE_POWER 0x08 + +/* values for the bits returned by the USB GET_STATUS command (spec. 9.4.5) */ + #define USB_GETSTATUS_SELF_POWERED 0x01 + #define USB_GETSTATUS_REMOTE_WAKEUP_ENABLED 0x02 + +/* values for standard request Clear Feature */ + #define USB_FEATURE_ENDPOINT_STALL 0x0000 + #define USB_FEATURE_REMOTE_WAKEUP 0x0001 + + +/*******************************************************/ +/*** Standard USB Descriptor Definitions (spec. 9.6) ***/ +/*******************************************************/ + +/* *** DEVICE *** (spec. 9.6.1) */ + struct _tag_usb_device_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; + } PACKED; + typedef struct _tag_usb_device_descriptor + USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; + +/* *** DEVICE_QUALIFIER *** (spec. 9.6.2) */ + struct _tag_usb_device_qualifier_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; + } PACKED; + typedef struct _tag_usb_device_qualifier_descriptor + USB_DEVICE_QUALIFIER_DESCRIPTOR, *PUSB_DEVICE_QUALIFIER_DESCRIPTOR; + +/* *** CONFIGURATION *** (spec. 9.6.3) */ + struct _tag_usb_configuration_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t MaxPower; + } PACKED; + typedef struct _tag_usb_configuration_descriptor + USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; +/* definitions for bits in the bmAttributes field of a configuration descriptor. (spec. 9.6.3) */ + #define USB_CONFIG_POWERED_MASK 0xc0 + #define USB_CONFIG_BUS_POWERED 0x80 + #define USB_CONFIG_SELF_POWERED 0x40 + #define USB_CONFIG_REMOTE_WAKEUP 0x20 + #define BUS_POWERED 0x80 + #define SELF_POWERED 0x40 + #define REMOTE_WAKEUP 0x20 + +/* *** OTHER_SPEED_CONFIGURATION *** (spec. 9.6.4) */ + struct _tag_usb_other_speed_configuration { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; + } PACKED; + typedef struct _tag_usb_other_speed_configuration + USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR, *PUSB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR; + +/* *** INTERFACE *** (spec. 9.6.5) */ + struct _tag_usb_interface_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; + } PACKED; + typedef struct _tag_usb_interface_descriptor + USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; + +/* *** ENDPOINT *** (spec. 9.6.6) */ + struct _tag_usb_endpoint_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; + } PACKED; + typedef struct _tag_usb_endpoint_descriptor + USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; + +/* Endpoint direction bit, stored in address (spec. 9.6.6) */ + #define USB_ENDPOINT_DIRECTION_MASK 0x80 +/* test direction bit in the bEndpointAddress field of an endpoint descriptor. */ + #define USB_ENDPOINT_DIRECTION_OUT(addr) (!((addr) & USB_ENDPOINT_DIRECTION_MASK)) + #define USB_ENDPOINT_DIRECTION_IN(addr) ((addr) & USB_ENDPOINT_DIRECTION_MASK) +/* Values for bmAttributes field of an endpoint descriptor (spec. 9.6.6) */ + #define USB_ENDPOINT_TYPE_MASK 0x03 + #define USB_ENDPOINT_TYPE_CONTROL 0x00 + #define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 + #define USB_ENDPOINT_TYPE_BULK 0x02 + #define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + +/* *** STRING *** (spec. 9.6.7) */ + struct _tag_usb_string_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t *bString; + } PACKED; + typedef struct _tag_usb_string_descriptor + USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR; + + +/*******************************************/ +/*** USB_IF - Defined USB device classes ***/ +/*******************************************/ + #define USB_DEVICE_CLASS_RESERVED 0x00 + #define USB_DEVICE_CLASS_AUDIO 0x01 + #define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 + #define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 + #define USB_DEVICE_CLASS_MONITOR 0x04 + #define USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05 + #define USB_DEVICE_CLASS_POWER 0x06 + #define USB_DEVICE_CLASS_PRINTER 0x07 + #define USB_DEVICE_CLASS_STORAGE 0x08 + #define USB_DEVICE_CLASS_HUB 0x09 + #define USB_DEVICE_CLASS_APPLICATION_SPECIFIC 0xFE + #define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF + + /* define application specific device class subclasses */ + #define USB_APPL_SUBCLASS_FIRMWARE_UPDATE 0x01 + #define USB_APPL_SUBCLASS_IRDA_USB_BRIDGE 0x02 + +#endif diff --git a/embedded/libs4c/usb/base/usb/usb_srq.h b/embedded/libs4c/usb/base/usb/usb_srq.h new file mode 100644 index 0000000..1821ab4 --- /dev/null +++ b/embedded/libs4c/usb/base/usb/usb_srq.h @@ -0,0 +1,23 @@ +#ifndef _USB_STDREQ_MODULE_ + #define _USB_STDREQ_MODULE_ + + int usb_stdreq_get_status( usb_device_t *udev); + + int usb_stdreq_clear_feature( usb_device_t *udev); + + int usb_stdreq_set_feature( usb_device_t *udev); + + int usb_stdreq_set_address( usb_device_t *udev); + + int usb_stdreq_get_configuration( usb_device_t *udev); + + int usb_stdreq_set_configuration( usb_device_t *udev); + + int usb_stdreq_get_interface( usb_device_t *udev); + + int usb_stdreq_set_interface( usb_device_t *udev); + + int usb_stdreq_get_descriptor( usb_device_t *udev); + +#endif /*_USB_STDREQ_MODULE_*/ + diff --git a/embedded/libs4c/usb/base/usb/usbdebug.h b/embedded/libs4c/usb/base/usb/usbdebug.h new file mode 100644 index 0000000..6a82e83 --- /dev/null +++ b/embedded/libs4c/usb/base/usb/usbdebug.h @@ -0,0 +1,81 @@ +/* Global debug macros, variables, functions - header file */ +/* R.B. - 23.4.2003 */ + +#ifndef _USB_DEBUG_H_ +#define _USB_DEBUG_H_ + +#if 1 + #include + #define usb_printf printf +#else + int simple_printf(const char *f, ...); + #define usb_printf simple_printf +#endif + +/* Debug levels */ +#define DEBUG_LEVEL_NONE 0 +#define DEBUG_LEVEL_LOW 1 +#define DEBUG_LEVEL_MEDIUM 2 +#define DEBUG_LEVEL_HIGH 3 +#define DEBUG_LEVEL_VERBOSE 4 + +#ifndef DEBUG_STATIC_LEVEL +/* Global static debug level */ +#define DEBUG_STATIC_LEVEL DEBUG_LEVEL_NONE +#endif + +/* If it is defined, current global debug level is + in 'global_debug_level' variable. Otherwise will + be used 'DEBUG_STATIC_LEVEL' as current global + debug level +*/ +/*#define DEBUG_USE_DYNAMIC_LEVEL*/ + +/* #define DEBUG */ + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +#ifdef DEBUG + +/* use static or dynamic global debug level */ +#if defined(DEBUG_USE_DYNAMIC_LEVEL) /* use dynamic debug level */ + extern unsigned char usb_debug_level; +#else /* use only static debug level */ + #define usb_debug_level DEBUG_STATIC_LEVEL +#endif + + +/* usb_debug_print( level, printargs) print debug info in printargs if + level is lower or equal to 'global_debug_level'/'DEBUG_STATIC_LEVEL'. + 'printargs' is with parenthesis. + usage : usb_debug_print( DEBUG_LEVEL_MEDIUM,("i=%d",i)); +*/ +#define usb_debug_print( _lvl_, _prnargs_) \ + do { \ + if ( usb_debug_level >= _lvl_) { \ + usb_printf _prnargs_; \ + } \ + } while(0) + +/* usb_debug_info( printargs) print debug info always + usage : usb_debug_info( "debug info"); +*/ +#define usb_debug_info usb_printf /* FIXME: this is not correct */ + +#else /* DEBUG */ + #define usb_debug_print( _lvl_, _prnargs_) + #define usb_debug_info(...) +#endif /* DEBUG */ + + + void usb_debug_set_level(int level); + + char *usb_debug_get_req_recipient( char rqt); + char *usb_debug_get_req_type( char rqt); + char *usb_debug_get_std_request( char req); + char *usb_debug_get_std_descriptor( unsigned char desc); + + +#endif /* _GLOBAL_DEBUG_H_ */ diff --git a/embedded/libs4c/usb/base/usbdebug.c b/embedded/libs4c/usb/base/usbdebug.c new file mode 100644 index 0000000..48bee80 --- /dev/null +++ b/embedded/libs4c/usb/base/usbdebug.c @@ -0,0 +1,76 @@ +/* Global debug macros, variables, functions - header file */ +/* R.B. - 23.4.2003 */ + +#include +#include + +#ifdef DEBUG + +/* debug can be enabled in run-time */ +#if defined(DEBUG_USE_DYNAMIC_LEVEL) /* use dynamic debug level */ + unsigned char usb_debug_level = DEBUG_LEVEL_NONE; +#endif + +/************************************************************* + *** Debug infos + *************************************************************/ + + void usb_debug_set_level(int level) { + #if defined(DEBUG_USE_DYNAMIC_LEVEL) /* use dynamic debug level */ + usb_debug_level = level; + #endif + } + + + char *usb_debug_get_req_recipient( char rqt) { + switch ( rqt & USB_RECIPIENT) { + case USB_RECIPIENT_DEVICE: return "DEVICE"; + case USB_RECIPIENT_INTERFACE: return "INTERFACE"; + case USB_RECIPIENT_ENDPOINT: return "ENDPOINT"; + } + return "OTHER"; + } + char *usb_debug_get_req_type( char rqt) { + switch ( rqt & USB_REQUEST_TYPE_MASK) { + case USB_STANDARD_REQUEST: return "STANDARD"; + case USB_CLASS_REQUEST: return "CLASS"; + case USB_VENDOR_REQUEST: return "VENDOR"; + } + return "RESERVED"; + } + char *usb_debug_get_std_request( char req) { + switch ( req & USB_REQUEST_MASK) { + case USB_REQUEST_GET_STATUS: return "GET STATUS"; + case USB_REQUEST_CLEAR_FEATURE: return "CLEAR FEATURE"; + case USB_REQUEST_SET_FEATURE: return "SET FEATURE"; + case USB_REQUEST_SET_ADDRESS: return "SET ADDRESS"; + + case USB_REQUEST_GET_DESCRIPTOR: return "GET DESCRIPTOR"; + case USB_REQUEST_SET_DESCRIPTOR: return "SET DESCRIPTOR"; + case USB_REQUEST_GET_CONFIGURATION: return "GET CONFIGURATION"; + case USB_REQUEST_SET_CONFIGURATION: return "SET CONFIGURATION"; + case USB_REQUEST_GET_INTERFACE: return "GET INTERFACE"; + case USB_REQUEST_SET_INTERFACE: return "SET INTERFACE"; + case USB_REQUEST_SYNC_FRAME: return "SYNC FRAME"; + } + return "UNKNOWN"; + } + char *usb_debug_get_std_descriptor( unsigned char desc) { + + switch ( desc) { + case USB_DESCRIPTOR_TYPE_DEVICE: return "DEVICE"; + case USB_DESCRIPTOR_TYPE_CONFIGURATION: return "CONFIGURATION"; + case USB_DESCRIPTOR_TYPE_STRING: return "STRING"; + case USB_DESCRIPTOR_TYPE_INTERFACE: return "INTERFACE"; + case USB_DESCRIPTOR_TYPE_ENDPOINT: return "ENDPOINT"; + case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: return "DEVICE_QUALIFIER"; + case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION: return "OTHER_SPEED_CONFIG"; + case USB_DESCRIPTOR_TYPE_POWER: return "POWER"; + } + return "UNKNOWN"; + } + +#else /*DEBUG*/ + void usb_debug_set_level(int level) { + } +#endif /* DEBUG */ diff --git a/embedded/libs4c/usb/lpcusb/Makefile b/embedded/libs4c/usb/lpcusb/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/usb/lpcusb/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/usb/lpcusb/Makefile.omk b/embedded/libs4c/usb/lpcusb/Makefile.omk new file mode 100644 index 0000000..00a4c72 --- /dev/null +++ b/embedded/libs4c/usb/lpcusb/Makefile.omk @@ -0,0 +1,11 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_USB_LPCUSB=n + +ifeq ($(CONFIG_USB_LPCUSB),y) +lib_LIBRARIES = lpcusb + +nobase_include_HEADERS = usb/lpcusb.h usb/lpc.h + +lpcusb_SOURCES = lpcusb.c lpc.c +endif #CONFIG_USB_LPCUSB diff --git a/embedded/libs4c/usb/lpcusb/lpc.c b/embedded/libs4c/usb/lpcusb/lpc.c new file mode 100644 index 0000000..159c899 --- /dev/null +++ b/embedded/libs4c/usb/lpcusb/lpc.c @@ -0,0 +1,186 @@ +/*****************************************************/ +/*** Module : USB PDI ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002, 16.04.2003 ***/ +/*****************************************************/ + +#include +#include +#include + +/* set device address */ +int usb_lpc_set_addr( usb_device_t *udev, unsigned char addr) { + lpc_usb_set_addr(addr); + return 0; +} + +int usb_lpc_set_configuration( usb_device_t *udev, unsigned char iCfg) { + lpc_usb_config_device(iCfg); + if ( iCfg) { + int i; + for(i = 0; i < udev->cntep; i++) { + lpc_usb_configEP(udev->ep[i].epnum, udev->ep[i].max_packet_size); + } + } + return 0; +} + +/* connect usb */ +int usb_lpc_connect( usb_device_t *udev) { + lpc_write_cmd_data(USB_CMD_SET_DEV_STAT,USB_DAT_WR_BYTE(USBC_DEV_CON)); + return 0; +} + +/* disconnect usb */ +int usb_lpc_disconnect( usb_device_t *udev) { + lpc_write_cmd_data(USB_CMD_SET_DEV_STAT,USB_DAT_WR_BYTE(0)); + return 0; +} + +/* acknowledge control transfer */ +void usb_lpc_ack_setup( usb_device_t *udev) { + lpc_usb_write_endpoint(0x80|0x00, NULL, 0); +} + +/* stall endpoint X */ +void usb_lpc_stall( usb_ep_t *ep) { + if (!ep->epnum) + lpc_usb_setstallEP(0x80|ep->epnum); + lpc_usb_setstallEP(ep->epnum); +} + +/* unstall endpoint X */ +void usb_lpc_unstall( usb_ep_t *ep) { + if (!ep->epnum) + lpc_usb_clrstallEP(0x80|ep->epnum); + lpc_usb_clrstallEP(ep->epnum); +} + +/** + * usb_lpc_check events + * function reads interrupt register and sets event flags + * function returns 1 if there is some new event. + * function returns 0 if there isn't new event but all is OK + * function returns -1 if there is any error +*/ +int usb_lpc_check_events( usb_device_t *udev) +{ + unsigned int disr,val,last_int; + int ret=0,n,m,i; + + disr=USBDevIntSt; + + /* Device Status Interrupt (Reset, Connect change, Suspend/Resume) */ + if (disr & USBDevInt_DEV_STAT) { + USBDevIntClr = USBDevInt_DEV_STAT; + disr&=~USBDevInt_DEV_STAT; + lpc_write_cmd(USB_CMD_GET_DEV_STAT); + val=lpc_read_cmd_data(USB_DAT_GET_DEV_STAT); + if (val & USBC_DEV_RST) { /* Reset */ + lpc_usb_reset(); + udev->flags |= USB_FLAG_BUS_RESET; + ret = 1; + } + if (val & USBC_DEV_SUS_CH) { /* Suspend/Resume */ + if (val & USBC_DEV_SUS) { /* Suspend */ + udev->flags |= USB_FLAG_SUSPEND; + ret = 1; + } else { /* Resume */ + /* todo */ + } + } + } + + /* Endpoint's Slow Interrupt */ + if (disr & USBDevInt_EP_SLOW) { + USBDevIntClr = USBDevInt_EP_SLOW; + disr&=~USBDevInt_EP_SLOW; + + last_int = USBEpIntSt; + + /* EP0_OUT */ + if (last_int & (1 << 0)) { + last_int &= ~(1 << 0); + USBEpIntClr = 1 << 0; + lpc_wait4devint(USBDevInt_CDFULL); + val = USBCmdData; + /* Setup Packet */ + if (val & USBC_EP_SEL_STP) + udev->flags |= USB_FLAG_SETUP; + else + udev->flags |= USB_FLAG_EVENT_RX0; + ret = 1; + } + + /* EP0_IN */ + if (last_int & (1 << 1)) { + last_int &= ~(1 << 1); + USBEpIntClr = 1 << 1; + lpc_wait4devint(USBDevInt_CDFULL); + val = USBCmdData; + udev->flags |= USB_FLAG_EVENT_TX0; + ret = 1; + } + + /* user endpoints */ + for( i=0; icntep; i++) { + if ( last_int & (udev->ep+i)->event_mask) { + last_int &= ~((udev->ep+i)->event_mask); + USBEpIntClr = (udev->ep+i)->event_mask; + lpc_wait4devint(USBDevInt_CDFULL); + val = USBCmdData; + udev->ep_events |= 1<> 1; + if (n&1) m|=0x80; + lpc_wait4devint(USBDevInt_CDFULL); + val = USBCmdData; + lpc_usb_setstallEP(m); + } + } + } + } + if (!disr) + USBDevIntClr = disr; + return ret; +} + +int usb_lpc_read_endpoint( usb_ep_t *ep, void *ptr, int size) +{ + return lpc_usb_read_endpoint(ep->epnum, ptr, size); +} + +int usb_lpc_write_endpoint( usb_ep_t *ep, const void *ptr, int size) +{ + return lpc_usb_write_endpoint(0x80|ep->epnum, ptr, size); +} + + +/* init usb structures and chip */ +int usb_lpc_init( usb_device_t *udev) { + + udev->connect = usb_lpc_connect; + udev->set_addr = usb_lpc_set_addr; + udev->set_configuration = usb_lpc_set_configuration; + udev->disconnect = usb_lpc_disconnect; + udev->ack_setup = usb_lpc_ack_setup; + udev->ack_control_setup = NULL; + udev->stall = usb_lpc_stall; + udev->unstall = usb_lpc_unstall; + udev->check_events = usb_lpc_check_events; + udev->read_endpoint = usb_lpc_read_endpoint; + udev->write_endpoint = usb_lpc_write_endpoint; + + udev->ep0.max_packet_size = USB_MAX_PACKET0; + + lpc_usb_hw_init(); + return 0; +} diff --git a/embedded/libs4c/usb/lpcusb/lpcusb.c b/embedded/libs4c/usb/lpcusb/lpcusb.c new file mode 100644 index 0000000..09b1eac --- /dev/null +++ b/embedded/libs4c/usb/lpcusb/lpcusb.c @@ -0,0 +1,194 @@ +/*****************************************************/ +/*** Module : USB PDI ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002, 16.04.2003 ***/ +/*****************************************************/ + +#include +#include +#include + +unsigned int lpc_ep2addr(unsigned int ep_num) +{ + unsigned int val; + val = (ep_num & 0x0F) << 1; + if (ep_num & 0x80) + val += 1; + return val; +} + +void lpc_wait4devint(unsigned int intrs) +{ + while ((USBDevIntSt & intrs) != intrs); + USBDevIntClr = intrs; +} + + +void lpc_write_cmd(unsigned int cmd) +{ + USBDevIntClr = USBDevInt_CCEMTY | USBDevInt_CDFULL; + USBCmdCode = cmd; + lpc_wait4devint(USBDevInt_CCEMTY); +} + +void lpc_write_cmd_data (unsigned int cmd, unsigned int val) +{ + lpc_write_cmd(cmd); + USBCmdCode = val; + lpc_wait4devint(USBDevInt_CCEMTY); +} + +unsigned int lpc_read_cmd_data (unsigned int cmd) +{ + lpc_write_cmd(cmd); + lpc_wait4devint(USBDevInt_CDFULL); + return USBCmdData; +} + +void lpc_usb_realizeEP(unsigned int idx,unsigned int wmaxpsize) +{ + USBReEp |= (1 << idx); + USBEpInd = idx; + USBMaxPSize = wmaxpsize; + lpc_wait4devint(USBDevInt_EP_RLZED); +} + +void lpc_usb_configEP(unsigned int ep_num,unsigned int wmaxpsize) +{ + lpc_usb_realizeEP(lpc_ep2addr(ep_num),wmaxpsize); + lpc_usb_enableEP(ep_num); +} + +void lpc_usb_setstallEP(unsigned int ep_num) +{ + lpc_write_cmd_data(USB_CMD_SET_EP_STAT(lpc_ep2addr(ep_num)),USB_DAT_WR_BYTE(USBC_EP_STAT_ST)); +} + +void lpc_usb_clrstallEP(unsigned int ep_num) +{ + lpc_write_cmd_data(USB_CMD_SET_EP_STAT(lpc_ep2addr(ep_num)),USB_DAT_WR_BYTE(0)); +} + +void lpc_usb_enableEP(unsigned int ep_num) +{ + lpc_write_cmd_data(USB_CMD_SET_EP_STAT(lpc_ep2addr(ep_num)),USB_DAT_WR_BYTE(0)); +} + +void lpc_usb_disableEP(unsigned int ep_num) +{ + lpc_write_cmd_data(USB_CMD_SET_EP_STAT(lpc_ep2addr(ep_num)),USB_DAT_WR_BYTE(USBC_EP_STAT_DA)); +} + +void lpc_usb_set_addr(unsigned int adr) +{ + lpc_write_cmd_data(USB_CMD_SET_ADDR,USB_DAT_WR_BYTE(USBC_DEV_EN | adr)); /* Setup Status Phase */ +} + +void lpc_usb_config_device(int fConfigured) +{ + lpc_write_cmd_data(USB_CMD_CFG_DEV,USB_DAT_WR_BYTE(fConfigured ? USBC_CONF_DEVICE : 0)); /* Setup Status Phase */ +} + +void lpc_usb_reset(void) +{ + USBEpIntClr = 0xFFFFFFFF; + USBEpIntEn = 0xFFFFFFFF ^ USB_DMA_EP; + USBDevIntClr = 0xFFFFFFFF; + USBDevIntEn = USBDevInt_DEV_STAT | USBDevInt_EP_SLOW; + + lpc_usb_configEP(0x00, USB_MAX_PACKET0); + lpc_usb_configEP(0x80, USB_MAX_PACKET0); +} + +void lpc_usb_hw_init (void) +{ + + PINSEL1 &= ~0xC000C000; +// PINSEL1 |= 0x40004000; /* Select USB Link, VBUS */ + PINSEL1 |= 0x80000000; /* Select USB Link, VBUS */ + + PCONP |= 0x80000000; /* Turn On USB PCLK */ + + /* Configure 48MHz USB Clock; FOsc = 12MHz, M = 4, P = 2 */ + PLLCFG48 = 0x23; /* M = 4, P = 2 */ + PLLCON48 = PLLCON_PLLE; /* PLL Enable */ + PLLFEED48 = 0xAA; /* Feed Sequence 1 */ + PLLFEED48 = 0x55; /* Feed Sequence 2 */ + + while ((PLLSTAT48 & PLLSTAT_LOCK) == 0); /* Wait for PLL Lock */ + + PLLCON48 = PLLCON_PLLE | PLLCON_PLLC; /* PLL Enable & Connect */ + PLLFEED48 = 0xAA; /* Feed Sequence 1 */ + PLLFEED48 = 0x55; /* Feed Sequence 2 */ + + USBDevIntEn = USBDevInt_DEV_STAT; /* Enable Device Status Interrupt */ + + /* Partial Manual Reset since Automatic Bus Reset is not working */ + lpc_usb_reset(); + lpc_usb_set_addr(0); +} + +/* + * lpc_usb_read_endpoint: Read USB Endpoint Data + * @EPNum: Endpoint Number - EPNum.0..3: Address, EPNum.7: Dir + * @ptr: Pointer to Data Buffer + * @size: + * Return Value: Number of bytes read + */ +int lpc_usb_read_endpoint( unsigned int ep_num, void *ptr, int size) +{ + unsigned int cnt,i,dwData; + unsigned char *p=ptr; + + USBCtrl = ((ep_num & 0x0F) << 2) | USBCtrl_RD_EN; + do { + cnt = USBRxPLen; + } while ((cnt & USBRxPLen_PKT_RDY) == 0); + cnt &= USBRxPLen_PKT_LNGTH; + + // get data + while (USBCtrl & USBCtrl_RD_EN) { + dwData = USBRxData; + if (p != NULL) { + for (i = 0; (i < 4) && size; i++) { + size--; + *p = dwData & 0xFF; + p++; + dwData >>= 8; + } + } + } + + lpc_write_cmd(USB_CMD_SEL_EP(lpc_ep2addr(ep_num))); + lpc_write_cmd(USB_CMD_CLR_BUF); + + return cnt; +} + +/* + * lpc_usb_write_endpoint: Write USB Endpoint Data + * @ep_num: Endpoint Number - ep_num.0..3: Address, ep_num.7: Dir + * @ptr: Pointer to Data Buffer + * @size: Number of bytes to write + * Return Value: Number of bytes written + */ +int lpc_usb_write_endpoint( unsigned int ep_num, const void *ptr, int size) +{ + unsigned int n; + const unsigned char *p=ptr; + + USBCtrl = ((ep_num & 0x0F) << 2) | USBCtrl_WR_EN; + USBTxPLen = size; + + for (n = 0; n < (size + 3) / 4; n++) { + USBTxData = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; + p += 4; + } + + USBCtrl=0; + + lpc_write_cmd(USB_CMD_SEL_EP(lpc_ep2addr(ep_num))); + lpc_write_cmd(USB_CMD_VALID_BUF); + + return size; +} diff --git a/embedded/libs4c/usb/lpcusb/usb/lpc.h b/embedded/libs4c/usb/lpcusb/usb/lpc.h new file mode 100644 index 0000000..c693182 --- /dev/null +++ b/embedded/libs4c/usb/lpcusb/usb/lpc.h @@ -0,0 +1,9 @@ +#ifndef _USB_LPC_SUBMODULE_HEADER_FILE_ +#define _USB_LPC_SUBMODULE_HEADER_FILE_ + +#include + +int usb_lpc_init( usb_device_t *udev); + +#endif /* _USB_LPC_SUBMODULE_HEADER_FILE_ */ + diff --git a/embedded/libs4c/usb/lpcusb/usb/lpcusb.h b/embedded/libs4c/usb/lpcusb/usb/lpcusb.h new file mode 100644 index 0000000..0f111bb --- /dev/null +++ b/embedded/libs4c/usb/lpcusb/usb/lpcusb.h @@ -0,0 +1,27 @@ +#ifndef _LPCUSB_BASE_MODULE +#define _PLCUSB_BASE_MODULE + +/*********************************************************/ +// Function prototypes +// +// LPCUSB common commands + +unsigned int lpc_ep2addr(unsigned int ep_num); +void lpc_wait4devint(unsigned int intrs); +void lpc_write_cmd(unsigned int cmd); +void lpc_write_cmd_data (unsigned int cmd, unsigned int val); +unsigned int lpc_read_cmd_data (unsigned int cmd); +void lpc_usb_realizeEP(unsigned int idx,unsigned int wmaxpsize); +void lpc_usb_configEP(unsigned int ep_num,unsigned int wmaxpsize); +void lpc_usb_setstallEP (unsigned int ep_num); +void lpc_usb_clrstallEP (unsigned int ep_num); +void lpc_usb_enableEP(unsigned int ep_num); +void lpc_usb_disableEP(unsigned int ep_num); +void lpc_usb_config_device(int fConfigured); +void lpc_usb_reset(void); +void lpc_usb_set_addr(unsigned int adr); +void lpc_usb_hw_init (void); +int lpc_usb_read_endpoint( unsigned int ep_num, void *ptr, int size); +int lpc_usb_write_endpoint( unsigned int ep_num, const void *ptr, int size); + +#endif // from _LPC_BASE_MODULE diff --git a/embedded/libs4c/usb/more/Makefile b/embedded/libs4c/usb/more/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/usb/more/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/usb/more/Makefile.omk b/embedded/libs4c/usb/more/Makefile.omk new file mode 100644 index 0000000..e90fb15 --- /dev/null +++ b/embedded/libs4c/usb/more/Makefile.omk @@ -0,0 +1,20 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_USB_MORE=n + +ifeq ($(CONFIG_USB_MORE),y) +lib_LIBRARIES = usbmore + +nobase_include_HEADERS = usb/usb_loader.h + +#shared_LIBRARIES = + +#include_HEADERS = + +usbmore_SOURCES = usb_srq.c + +#lib_LOADLIBES = +#bin_PROGRAMS = + +endif #CONFIG_USB_MORE + diff --git a/embedded/libs4c/usb/more/usb/msc_loader.h b/embedded/libs4c/usb/more/usb/msc_loader.h new file mode 100644 index 0000000..f912d2b --- /dev/null +++ b/embedded/libs4c/usb/more/usb/msc_loader.h @@ -0,0 +1,8 @@ +#ifndef _MSC_LOADER_H +#define _MSC_LOADER_H + +#include + +int usb_msc1210_loader(usb_device_t *udev); + +#endif /*_MSC_LOADER_H*/ diff --git a/embedded/libs4c/usb/more/usb/usb_com.h b/embedded/libs4c/usb/more/usb/usb_com.h new file mode 100644 index 0000000..1f87b9b --- /dev/null +++ b/embedded/libs4c/usb/more/usb/usb_com.h @@ -0,0 +1,17 @@ + +#ifndef _USB_COM_H + #define _USB_COM_H + +/* Queued USB Module */ + extern int usb_tm_snd; + extern int usb_tm_snded; + extern int usb_tm_rcv; + + int usb_com_init( void); + void usb_com_start_send( void); + + int usb_com_sendch(int c); + int usb_com_recch(); + int usb_com_sendstr(const char *s); + +#endif /* _USB_COM_H */ diff --git a/embedded/libs4c/usb/more/usb/usb_loader.h b/embedded/libs4c/usb/more/usb/usb_loader.h new file mode 100644 index 0000000..1246534 --- /dev/null +++ b/embedded/libs4c/usb/more/usb/usb_loader.h @@ -0,0 +1,38 @@ +#include + +#ifndef _USB_LOADER_H +#define _USB_LOADER_H + +#define USB_VENDOR_GET_CAPABILITIES 0x00 // get capabilities +#define USB_VENDOR_RESET_DEVICE 0x08 +// #define USB_VENDOR_SET_BYTE 0x10 +// #define USB_VENDOR_SET_WORD 0x20 +#define USB_VENDOR_GET_SET_MEMORY 0x30 +#define USB_VENDOR_ERASE_MEMORY 0x40 // erase memory for 1 Byte +#define USB_VENDOR_ERASE_1KB_MEMORY 0x48 // erase memory for 1 KB +#define USB_VENDOR_MASS_ERASE 0x50 // erase all device memory +#define USB_VENDOR_GOTO 0x60 +#define USB_VENDOR_CALL 0x70 +#define USB_VENDOR_GET_STATUS 0xF0 +#define USB_VENDOR_MASK 0xF8 // mask for vendor commands + +#define USB_VENDOR_MEMORY_BY_BULK 0x80 + +/* COMMON */ +#define USB_VENDOR_TARGET_RAM 0x01 +#define USB_VENDOR_TARGET_FLASH 0x02 +/* MSP430 */ +#define USB_VENDOR_TARGET_ADAPTER 0x01 +#define USB_VENDOR_TARGET_MSP430 0x02 +/* MSC1210 */ +#define USB_VENDOR_TARGET_DATA 0x01 +#define USB_VENDOR_TARGET_XDATA 0x02 + +#define USB_VENDOR_TARGET_MASK 0x07 + +/* bRequest - type of request */ +/* wValue - lower address word */ +/* wIndex - higher address word */ +/* wLength - data or length of data */ + +#endif /*_USB_LOADER_H*/ diff --git a/embedded/libs4c/usb/more/usb_com.c b/embedded/libs4c/usb/more/usb_com.c new file mode 100644 index 0000000..71991ba --- /dev/null +++ b/embedded/libs4c/usb/more/usb_com.c @@ -0,0 +1,1061 @@ +/*********************************************************/ +/*** Module : USB communication ***/ +/*** Author : Roman Bartosinski (bartosr@centrum.cz) ***/ +/*** Modify : 14.01.2003 ***/ +/*********************************************************/ + +#include +#include +#include +#include "pdiusb.h" +#include +/*#include */ +#include "usb_defs.h" +#include +#include + + +/* Queued USB Module */ +typedef volatile struct{ + unsigned char *first; + unsigned char *last; + unsigned char *begin; + unsigned char *end; +} usb_com_que_t; + +#define USB_COM_BUF_LEN 80 //(80*8) + +usb_com_que_t usb_com_que_in; /* input queue */ +unsigned char usb_com_buf_in[USB_COM_BUF_LEN]; +usb_com_que_t usb_com_que_out; /* output queue */ +unsigned char usb_com_buf_out[USB_COM_BUF_LEN]; + +int usb_com_init( void); +int usb_com_put(usb_com_que_t *q, int c); +int usb_com_get(usb_com_que_t *q); + +usb_vendor_extension_fnc_t *usb_vendor_extension=0; + +#ifdef PDIUSB_WITH_ADD_IRQ_HANDLER +/* usb irq handler struct */ +irq_handler_t usb_irq_handler; +#elif defined(PDIUSB_WITH_EXCPTVECT_SET) +void usb_isr(void) __attribute__ ((interrupt_handler)); +#endif /*PDIUSB_WITH_EXCPTVECT_SET*/ + +int usb_irq_cnt; + +/* common external function for pdiusb module */ + void pdiSendCommand( unsigned char byCmd) { + writeb( byCmd, PDIUSB_COMMAND_ADDR); + } + unsigned char pdiReadData( unsigned char byCount, unsigned char *pbyData) { + unsigned char out = byCount; + + while (byCount--) { + *pbyData = readb( PDIUSB_READ_DATA_ADDR); + pbyData++; + } + + return out; + } + void pdiWriteData( unsigned char byCount, unsigned char *pbyData) { + while (byCount--) { + writeb( *pbyData++, PDIUSB_WRITE_DATA_ADDR); + } + } + + +/* usb communication module */ + /* data */ + usb_flags_t usb_flags; + unsigned char usb_address; + unsigned char usb_interface; + usb_control_ep_t usb_rxtx_control; + usb_bulk_ep_t usb_rx_bulk, usb_tx_bulk; + + volatile unsigned int usb_last_irq; + // internal buffer for data from/to control req. - must be global + unsigned char ctrl_data[PDI_EP0_PACKET_SIZE]; + + typeof(msec_time) usb_start = 0, usb_stop = 0; + + + +/* functions */ + int usb_run( void) { + int ret = 0; + if ( usb_flags.running) { +#ifdef USE_USB_WITH_IRQ + if (!usb_flags.bits.was_int) return ret; + usb_flags.was_int = 0; +#else + ret = usb_test_interrupt(); + if ( usb_flags.request == 1) { + usb_answer_to_request(); + } + if ( usb_flags.request == 2) { // request is set in usb_answer_to_request() + if (( usb_rxtx_control.dreq.bmRequestType & USB_DATA_DIR_MASK)==USB_DATA_DIR_TO_HOST) { + unsigned int now = usb_rxtx_control.bytes; + if ( now > PDI_EP0_PACKET_SIZE) now = PDI_EP0_PACKET_SIZE; + if ( usb_rxtx_control.next_pkt_fnc ) + if( usb_rxtx_control.next_pkt_fnc(&usb_rxtx_control, now, USB_NEXT_PKT_SEND) ) { + usb_stall_ep0(); + return -1; + } + debugPrint( DBG_HIGH, ("CNTR send 1.data (%d)\n", now)); + pdiWriteEndpoint( PDI_EP0_TX, now, usb_rxtx_control.data); + usb_rxtx_control.data += now; + if ( !(usb_rxtx_control.bytes -= now)) { + usb_flags.request = 3; + } + } + } + if ( usb_flags.request == 3) { + if ( !usb_rxtx_control.dreq.wLength || + (usb_rxtx_control.dreq.bmRequestType & USB_DATA_DIR_MASK)==USB_DATA_DIR_FROM_HOST) { + pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + if ( usb_rxtx_control.complete_fnc ) + usb_rxtx_control.complete_fnc(&usb_rxtx_control, USB_COMPLETE_OK); + usb_rxtx_control.next_pkt_fnc = NULL; + usb_rxtx_control.complete_fnc = NULL; + } + } +#endif + } + return ret; + } + + int usb_test_interrupt( void) { //_naked { + unsigned char usb_last_status; + int ret = 0; +// INTERRUPT_PRE(0); +// LEDr = 1; +// EA=0; + usb_last_irq = pdiGetInterrupt(); + if ( usb_last_irq) { + ret = 1; + debugPrint( DBG_MEDIUM, ("USB Interrupt 0x%X\n",usb_last_irq)); + if ( usb_last_irq & PDI_INT_BUSRESET) { // D12 - Bus reset reached + usb_flags.configured = 0; + if ( usb_flags.running && usb_flags.stop_request) { + usb_flags.running = 0; + usb_flags.stop_request = 0; + } + debugPrint( DBG_HIGH, ("Bus Reset\n")); + } else { + if ( usb_last_irq & PDI_INT_SUSPEND) { // D12 - Suspend flag changed + debugPrint( DBG_HIGH, ("Suspend Changed\n")); + } + // it must be first b/c tx and rx can be sended all together + if ( usb_last_irq & PDI_INT_EP0_IN) { // D12 - Ep0TxDone - data in EP0 was sended + usb_last_status = pdiGetLastTransStatus( PDI_EP0_TX); + debugPrint( DBG_HIGH, ("Ep0-Tx LTS=0x%X\n", usb_last_status)); + if (( usb_last_status & PDI_LTSTAT_RXTX_OK) && usb_flags.request > 1) { + if ( usb_flags.request == 2) { + unsigned int now = usb_rxtx_control.bytes; + if ( now > PDI_EP0_PACKET_SIZE) now = PDI_EP0_PACKET_SIZE; + + if ( usb_rxtx_control.next_pkt_fnc ) + if( usb_rxtx_control.next_pkt_fnc(&usb_rxtx_control, now, USB_NEXT_PKT_SEND) ) { + usb_stall_ep0(); + return -1; + } + + debugPrint( DBG_HIGH, ("CNTR data\n")); + pdiWriteEndpoint( PDI_EP0_TX, now, usb_rxtx_control.data); + usb_rxtx_control.data += now; + if ( !(usb_rxtx_control.bytes -= now)) { + usb_flags.request = 3; + } + } else if ( usb_flags.request == 3) { + debugPrint( DBG_HIGH, ("CNTR ack\n")); + usb_flags.request = 0; + + if ( usb_rxtx_control.complete_fnc ) + usb_rxtx_control.complete_fnc(&usb_rxtx_control, USB_COMPLETE_OK); + usb_rxtx_control.next_pkt_fnc = NULL; + usb_rxtx_control.complete_fnc = NULL; + + } else { + debugPrint( DBG_LOW, ("tx ... ???\n")); + } + } + } + + if ( usb_last_irq & PDI_INT_EP0_OUT) { // D12 - Ep0RxDone - some data was received in EP0 + usb_last_status = pdiGetLastTransStatus( PDI_EP0_RX); + debugPrint( DBG_HIGH, ("Ep0-Rx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + if ( usb_last_status & PDI_LTSTAT_SETUP) { + if ( usb_flags.request) { + debugPrint( DBG_HIGH, ("!!! New setup, but last not ack ...\n")); + } + usb_flags.request = 1; // Standard_requests(); + if ( usb_rxtx_control.complete_fnc ) + usb_rxtx_control.complete_fnc(&usb_rxtx_control, USB_COMPLETE_FAIL); + usb_rxtx_control.next_pkt_fnc = NULL; + usb_rxtx_control.complete_fnc = NULL; + } else { + if ( usb_flags.request == 2) { + unsigned int now = usb_rxtx_control.bytes; + if ( now > PDI_EP0_PACKET_SIZE) now = PDI_EP0_PACKET_SIZE; + debugPrint( DBG_HIGH, ("CNTR data\n")); + ret = pdiReadEndpoint( PDI_EP0_RX, now, usb_rxtx_control.data); + + if(ret>usb_rxtx_control.bytes) + ret = usb_rxtx_control.bytes; + + usb_rxtx_control.data += ret; + + if ( usb_rxtx_control.next_pkt_fnc ) { + if( usb_rxtx_control.next_pkt_fnc(&usb_rxtx_control, ret, USB_NEXT_PKT_REC) ) { + usb_stall_ep0(); + return -1; + } + } + + if (!(usb_rxtx_control.bytes -= ret)) { + usb_rxtx_control.data -= usb_rxtx_control.dreq.wLength; + usb_flags.request = 3; + } + } else if ( usb_flags.request == 3) { + debugPrint( DBG_HIGH, ("CNTR ack\n")); + usb_flags.request = 0; + pdiReadEndpoint( PDI_EP0_RX, 0, 0); + if ( usb_rxtx_control.complete_fnc ) + usb_rxtx_control.complete_fnc(&usb_rxtx_control, USB_COMPLETE_OK); + usb_rxtx_control.next_pkt_fnc = NULL; + usb_rxtx_control.complete_fnc = NULL; + } else { + pdiReadEndpoint( PDI_EP0_RX, 0, 0); + } + } + } + } + if ( usb_last_irq & PDI_INT_EP1_OUT) { // D12 - Ep1RxDone - some data was received in EP1 + usb_last_status = pdiGetLastTransStatus( PDI_EP1_RX); + debugPrint( DBG_HIGH, ("Ep1-Rx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + pdiSetEpStatus( PDI_EP1_OUT, PDI_SET_EP_STALLED); + } + } + if ( usb_last_irq & PDI_INT_EP1_IN) { // D12 - Ep1TxDone - data in EP1 was sended + usb_last_status = pdiGetLastTransStatus( PDI_EP1_TX); + debugPrint( DBG_HIGH, ("Ep1-Tx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + pdiSetEpStatus( PDI_EP1_IN, PDI_SET_EP_STALLED); + } + } + + if ( usb_last_irq & PDI_INT_EP2_OUT) { // D12 - Ep2RxDone - some data was received in EP2 + usb_last_status = pdiGetLastTransStatus( PDI_EP2_RX); + debugPrint( DBG_HIGH, ("Ep2-Rx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + if ( usb_flags.terminal_mode) { + unsigned char hlpbfr[PDI_EP2_PACKET_SIZE], now = PDI_EP2_PACKET_SIZE, i; + MoreRead: + now = pdiReadEndpoint( PDI_EP2_RX, now, hlpbfr); + for(i=0;i PDI_EP2_PACKET_SIZE) now = PDI_EP2_PACKET_SIZE; + + if ( !usb_flags.bits.bulk_rx_data) { + usb_flags.bulk_rx_data = 1; + usb_start = msec_time; + } + + ReadAgain: + ret = pdiReadEndpoint( PDI_EP2_RX, now, usb_rx_bulk.data); + usb_rx_bulk.data += now; + if ( !( usb_rx_bulk.remain -= now)) { + //usb_rx_bulk.data -= usb_rx_bulk.bytes; /* read again */ + usb_stop = msec_time; + usb_flags.bulk_rx_data = 0; + // complete_func or set flag(event) + } + if ( usb_rx_bulk.remain > 0 && usb_rx_bulk.remain <= PDI_EP2_PACKET_SIZE) + goto ReadAgain; + } + } + } + if ( usb_last_irq & PDI_INT_EP2_IN) { // D12 - Ep2TxDone - data in EP2 was sended + usb_last_status = pdiGetLastTransStatus( PDI_EP2_TX); + debugPrint( DBG_HIGH, ("Ep2-Tx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + if ( usb_flags.terminal_mode) { + int ch = usb_com_get( &usb_com_que_out); + usb_tm_snded++; + if ( ch < 0) { + usb_flags.bulk_tx_data = 0; + } else { + unsigned char uchr = ch; + usb_flags.bulk_tx_data = 1; + pdiWriteEndpoint( PDI_EP2_TX, 1, &uchr); + } + } else { + if ( usb_tx_bulk.remain) { + unsigned int now = usb_tx_bulk.remain; + if ( now > PDI_EP2_PACKET_SIZE) now = PDI_EP2_PACKET_SIZE; + pdiWriteEndpoint( PDI_EP2_TX, now, usb_tx_bulk.data); + usb_tx_bulk.data += now; + if (!(usb_tx_bulk.remain -= now)) { + // complete_func or set flag(event) + } + } + } + } + } + ret = 0; + } + } +// EA=1; +// LEDr = 0; +// INTERRUPT_POST(); + return ret; + } + + +// ************************************ + void usb_init( void) { + usb_last_irq = 0; usb_address = 0; usb_interface = 0; + usb_flags.word = 0; + + usb_com_init(); + +#ifdef USE_USB_WITH_IRQ + usb_irq_cnt=0; + #ifdef PDIUSB_WITH_ADD_IRQ_HANDLER + if( test_irq_handler( ISR_USB_INTV, &usb_irq_handler)==0) + add_irq_handler( ISR_USB_INTV, &usb_irq_handler); + #elif defined(PDIUSB_WITH_EXCPTVECT_SET) + excptvec_set(ISR_USB_INTV,&usb_isr); + #endif /*PDIUSB_WITH_ADD_IRQ_HANDLER*/ + //*((char*)0xfffa1f) |= 0x04; /* It must be here for pull-up INT signal in usb_isr function */ +#endif + debugPrint(DBG_MEDIUM,("# Usb Inited\n")); + } + + void usb_connect_bus( void) { + debugPrint(DBG_MEDIUM,("Usb connect to bus\n")); + usb_flags.running = 1; + usb_last_irq = 0; + pdiSetDMA( PDI_DMA_EP4_INT | PDI_DMA_EP5_INT); // ??? + pdiSetMode( PDI_MODE_NO_LAZY_CLOCK | PDI_MODE_CLOCK_RUNNING | PDI_MODE_SOFT_CONNECT | PDI_CLOCK_SET_TO_ONE | PDI_CLOCK_4M); + } + void usb_disconnect_bus( void) { + debugPrint(DBG_MEDIUM,("Usb disconnect from bus\n")); + pdiSetMode( PDI_MODE_NO_LAZY_CLOCK | PDI_MODE_CLOCK_RUNNING | PDI_CLOCK_SET_TO_ONE | PDI_CLOCK_4M); + usb_flags.configured = 0; + usb_flags.stop_request = 1; + } + + void usb_stall_ep0( void) { + pdiSetEpStatus( PDI_EP0_TX, PDI_SET_EP_STALLED); pdiSetEpStatus( PDI_EP0_RX, PDI_SET_EP_STALLED); + } + + +// ************************************ +// *** Common send/receive fncs *** +// ************************************ +/* + void usb_send_to_usb( unsigned char idx, unsigned char maxb) { + debugPrint( DBG_HIGH,("USB Send EP#%d (max=%d) <- buff 0x%lX, cnt %d\n",usb_ep[idx].ep, maxb, (unsigned long)usb_ep[idx].buff,usb_ep[idx].bytes)); + if ( !usb_ep[idx].bytes) pdiWriteEndpoint( usb_ep[idx].ep, 0, 0); + else { + if ( usb_ep[idx].bytes > maxb) { + pdiWriteEndpoint( usb_ep[idx].ep, maxb, usb_ep[idx].buff); + usb_ep[idx].bytes -= maxb; + usb_ep[idx].buff += maxb; + } else { + pdiWriteEndpoint( usb_ep[idx].ep, usb_ep[idx].bytes, usb_ep[idx].buff); + usb_ep[idx].buff += usb_ep[idx].bytes; + usb_ep[idx].bytes = 0; +// if ( usending) usending = 0; + } + } + } + + unsigned char usb_receive_from_usb( unsigned char idx, unsigned char maxb) { + unsigned char ret = 0; + + ret = (unsigned char)usb_ep[idx].bytes; + if ( !ret || ret > maxb) ret = maxb; + debugPrint( DBG_HIGH,("USB Receive EP#%d ->buff 0x%lX,cnt %d,(max %d)\n",usb_ep[idx].ep,(unsigned long)usb_ep[idx].buff,usb_ep[idx].bytes,ret)); + if ( !usb_ep[idx].bytes) { +// ureceiving = 0; + pdiReadEndpoint( usb_ep[idx].ep, 0, 0); + return 0xff; // too_small_buffer error + } + do { + ret = pdiReadEndpoint( usb_ep[idx].ep, ret, usb_ep[idx].buff); + debugPrint( DBG_HIGH,(" - really readed %d\n", ret)); + usb_ep[idx].buff += ret; + usb_ep[idx].bytes -= ret; + } while (( ret == maxb) && usb_ep[idx].bytes); + return ret; + } +*/ + + +#ifdef DEBUG + char *ReqRecipient( char rqt) { + switch ( rqt & USB_RECIPIENT) { + case USB_RECIPIENT_DEVICE: return "DEVICE"; + case USB_RECIPIENT_INTERFACE: return "INTERFACE"; + case USB_RECIPIENT_ENDPOINT: return "ENDPOINT"; + } + return "OTHER"; + } + char *ReqType( char rqt) { + switch ( rqt & USB_REQUEST_TYPE_MASK) { + case USB_STANDARD_REQUEST: return "STANDARD"; + case USB_CLASS_REQUEST: return "CLASS"; + case USB_VENDOR_REQUEST: return "VENDOR"; + } + return "RESERVED"; + } + char *ReqName( char req) { + switch ( req & USB_REQUEST_MASK) { + case USB_REQUEST_GET_STATUS: return "GET STATUS"; + case USB_REQUEST_CLEAR_FEATURE: return "CLEAR FEATURE"; + case USB_REQUEST_SET_FEATURE: return "SET FEATURE"; + case USB_REQUEST_SET_ADDRESS: return "SET ADDRESS"; + case USB_REQUEST_GET_DESCRIPTOR: return "GET DESCRIPTOR"; + case USB_REQUEST_SET_DESCRIPTOR: return "SET DESCRIPTOR"; + case USB_REQUEST_GET_CONFIGURATION: return "GET CONFIGURATION"; + case USB_REQUEST_SET_CONFIGURATION: return "SET CONFIGURATION"; + case USB_REQUEST_GET_INTERFACE: return "GET INTERFACE"; + case USB_REQUEST_SET_INTERFACE: return "SET INTERFACE"; + case USB_REQUEST_SYNC_FRAME: return "SYNC FRAME"; + } + return "UNKNOWN"; + } +#endif + + + void usb_set_control_data(usb_control_ep_t *ep, void *buff, int size) + { + ep->data = (unsigned char *) buff; + ep->bytes = size; + usb_flags.request = 2; + debugPrint( DBG_HIGH,("usb_set_control_data buff=0x%lx, len=%d\n", (long)buff, size)); + } + + void usb_set_control_ack(usb_control_ep_t *ep) + { + ep->data = NULL; + ep->bytes = 0; + usb_flags.request = 3; + debugPrint( DBG_HIGH,("usb_set_control_ack\n")); + } + + + /* + *********************************** + *** Execute device requests *** + *********************************** + */ + void usb_answer_to_request( void) { + USB_DEVICE_REQUEST *pdreq = &usb_rxtx_control.dreq; + + debugPrint( DBG_MEDIUM,("Process usb setup packet\n")); + usb_rxtx_control.req_size=pdiReadEndpoint( PDI_EP0_RX, 255, (unsigned char *)pdreq); + if ( usb_rxtx_control.req_size == 0xff) { + /*LEDr = 1; SetLeds( hlp[0]);*/ + debugPrint( DBG_LOW,("! BIG Setup packet\n")); + usb_stall_ep0(); + return; + } + pdiAckSetupControl(); + /* !!! it must be here !!! */ + pdreq->wValue = SWAP( pdreq->wValue); + pdreq->wIndex = SWAP( pdreq->wIndex); + pdreq->wLength = SWAP( pdreq->wLength); + + usb_rxtx_control.next_pkt_fnc = NULL; + usb_rxtx_control.complete_fnc = NULL; + + ctrl_data[0] = ctrl_data[1] = 0; // we need only 2 bytes + + #ifdef DEBUG + debugPrint( DBG_HIGH, ("Receive (0x%X) %s req. for %s , data %s host\n", + pdreq->bmRequestType, ReqType( pdreq->bmRequestType), + ReqRecipient(pdreq->bmRequestType), + ((pdreq->bmRequestType & USB_DATA_DIR_MASK) ? "TO":"FROM"))); + debugPrint( DBG_HIGH, (" Request (0x%X) %s\n", pdreq->bRequest, + ((!(pdreq->bmRequestType&USB_REQUEST_TYPE_MASK))? ReqName( pdreq->bRequest):"UNKNOWN"))); + #endif + + switch( pdreq->bmRequestType & USB_RECIPIENT) { + case USB_RECIPIENT_DEVICE: + switch( pdreq->bmRequestType & USB_REQUEST_TYPE_MASK) { + case USB_STANDARD_REQUEST: + switch( pdreq->bRequest) { + case USB_REQUEST_GET_STATUS: + #ifdef USB_MY_SELF_POWER + ctrl_data[0]=1; + #else + ctrl_data[0]=0; + #endif + USB_SET_CONTROL_DATA( &ctrl_data, 2); + //pdiWriteEndpoint( PDI_EP0_TX, 2, hlp); + break; + case USB_REQUEST_SET_ADDRESS: + usb_address = ( unsigned char)( pdreq->wValue & DEVICE_ADDRESS_MASK); + pdiSetAddressEnable( usb_address | PDI_ENAD_ENABLE); + USB_SET_CONTROL_ACK; + //pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + break; + case USB_REQUEST_GET_DESCRIPTOR: + usb_get_descriptor(); + break; + case USB_REQUEST_GET_CONFIGURATION: + if ( usb_flags.configured) ctrl_data[0] = 1; + USB_SET_CONTROL_DATA( &ctrl_data, 1); + //pdiWriteEndpoint( PDI_EP0_TX, 1, hlp); + break; + case USB_REQUEST_SET_CONFIGURATION: + if (LSB( pdreq->wValue) < 2) { + if ( LSB( pdreq->wValue)) { + pdiSetEndpointEnable( usb_flags.configured=1); + } else { + pdiSetEndpointEnable( usb_flags.configured=0); + } + USB_SET_CONTROL_ACK; + //pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + } else + usb_stall_ep0(); + break; + default: + usb_stall_ep0(); + break; + } + + break; + case USB_VENDOR_REQUEST: + if(usb_vendor_extension) { + int ret; + ret = usb_vendor_extension(&usb_rxtx_control, pdreq); + if (ret<0) { + usb_stall_ep0(); + break; + } + if (ret>0) { + break; + } + } + + switch ( pdreq->bRequest) { + case USB_VENDOR_START_TRANSFER: + { + unsigned long max = ((long)pdreq->wIndex << 16)+pdreq->wValue; + usb_rx_bulk.remain = ( usb_rx_bulk.bytes < max) ? usb_rx_bulk.bytes : max; + } + USB_SET_CONTROL_ACK; + break; + case USB_VENDOR_CONTROL_TERMINAL_MODE: + if ( pdreq->wValue == 1) usb_flags.terminal_mode = 1; + else usb_flags.terminal_mode = 0; + USB_SET_CONTROL_ACK; + break; + default: + USB_SET_CONTROL_ACK; + //pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + break; + } + break; + case USB_CLASS_REQUEST: + usb_stall_ep0(); + default: + usb_stall_ep0(); + break; + } + break; + case USB_RECIPIENT_INTERFACE: + if (( pdreq->bmRequestType & USB_REQUEST_TYPE_MASK) == USB_STANDARD_REQUEST) { + switch( pdreq->bRequest) { + case USB_REQUEST_GET_STATUS: + USB_SET_CONTROL_DATA( &ctrl_data, 2); + //pdiWriteEndpoint( PDI_EP0_TX, 2, hlp); + break; + case USB_REQUEST_GET_INTERFACE: + debugPrint( DBG_HIGH,("ReqIfc=%d Now ifc=%d\n", pdreq->wIndex, usb_interface)); + USB_SET_CONTROL_DATA( &ctrl_data, 1); // alternate interface + //pdiWriteEndpoint( PDI_EP0_TX, 1, hlp); + break; + case USB_REQUEST_SET_INTERFACE: + //if (( dreq.wValue == 0) && ( dreq.wIndex == 0)) + if ( pdreq->wIndex < 1) { // mame jen 2 pokusne interface + usb_interface = (unsigned char) pdreq->wIndex; + USB_SET_CONTROL_ACK; + //pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + } else + usb_stall_ep0(); + break; + default: + usb_stall_ep0(); + } + } else + usb_stall_ep0(); + break; + case USB_RECIPIENT_ENDPOINT: + if (( pdreq->bmRequestType & USB_REQUEST_TYPE_MASK) == USB_STANDARD_REQUEST) { + switch( pdreq->bRequest) { + case USB_REQUEST_GET_STATUS: + case USB_REQUEST_CLEAR_FEATURE: + case USB_REQUEST_SET_FEATURE: + { + ctrl_data[0] = ( unsigned char)(( pdreq->wIndex & PDI_CNT_EP)<<1); + if ( pdreq->wIndex & ( unsigned char) USB_ENDPOINT_DIRECTION_MASK) + ctrl_data[0]++; + if ( pdreq->bRequest == USB_REQUEST_GET_STATUS) { + ctrl_data[0] = pdiSelectEp( ctrl_data[0]); // endpoint in + ctrl_data[0] = (( ctrl_data[0] & PDI_SELEP_STALL) == PDI_SELEP_STALL); + USB_SET_CONTROL_DATA( &ctrl_data, 2); + //pdiWriteEndpoint( PDI_EP0_TX, 2, hlp); + } else { + if ( pdreq->bRequest == USB_REQUEST_CLEAR_FEATURE) { + pdiSetEpStatus( ctrl_data[0], 0); + //pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + } else { + pdiSetEpStatus( ctrl_data[0], 1); + //pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + } + USB_SET_CONTROL_ACK; + } + } + break; + default: + usb_stall_ep0(); + } + } else + usb_stall_ep0(); + break; +// case USB_RECIPIENT_OTHER: + default: + usb_stall_ep0(); + break; + } +// usb_flags.command = 0; // ??? data or ack stage ??? + +#ifdef USE_USB_WITH_IRQ +// send data if it is needed + if ( usb_flags.request == 2) { // request is set to data stage + if (( usb_rxtx_control.dreq.bmRequestType & USB_DATA_DIR_MASK)==USB_DATA_DIR_TO_HOST) { + unsigned int now = usb_rxtx_control.bytes; + if ( now > PDI_EP0_PACKET_SIZE) now = PDI_EP0_PACKET_SIZE; + if ( usb_rxtx_control.next_pkt_fnc ) + if( usb_rxtx_control.next_pkt_fnc(&usb_rxtx_control, now, USB_NEXT_PKT_SEND) ) { + usb_stall_ep0(); + return; + } + debugPrint( DBG_HIGH, ("CNTR send 1.data (%d)\n", now)); + pdiWriteEndpoint( PDI_EP0_TX, now, usb_rxtx_control.data); + usb_rxtx_control.data += now; + if ( !(usb_rxtx_control.bytes -= now)) { + usb_flags.request = 3; + } + } + } + if ( usb_flags.request == 3) { + if ( !usb_rxtx_control.dreq.wLength || + (usb_rxtx_control.dreq.bmRequestType & USB_DATA_DIR_MASK)==USB_DATA_DIR_FROM_HOST) { + pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + if ( usb_rxtx_control.complete_fnc ) + usb_rxtx_control.complete_fnc(&usb_rxtx_control, USB_COMPLETE_OK); + usb_rxtx_control.next_pkt_fnc = NULL; + usb_rxtx_control.complete_fnc = NULL; + } + } +#endif + } + +#ifdef DEBUG + char *DescType( unsigned char desc) { + switch ( desc) { + case USB_DESCRIPTOR_TYPE_DEVICE: return"DEVICE"; + case USB_DESCRIPTOR_TYPE_CONFIGURATION: return"CONFIGURATION"; + case USB_DESCRIPTOR_TYPE_STRING: return"STRING"; + case USB_DESCRIPTOR_TYPE_INTERFACE: return"INTERFACE"; + case USB_DESCRIPTOR_TYPE_ENDPOINT: return"ENDPOINT"; + case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: return"DEVICE_QUALIFIER"; + case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION: return"OTHER_SPEED_CONFIG"; + case USB_DESCRIPTOR_TYPE_POWER: return"POWER"; + } + return "UNKNOWN"; + } +#endif + + void usb_get_descriptor( void) { + unsigned int size; + unsigned short wVal = usb_rxtx_control.dreq.wValue; + debugPrint( DBG_MEDIUM, (" - %s descriptor\n", DescType(MSB( wVal)))); + switch ( MSB( wVal)) { + case USB_DESCRIPTOR_TYPE_DEVICE: + usb_rxtx_control.data = (unsigned char *) &usb_device_descriptor; + size = sizeof( USB_DEVICE_DESCRIPTOR); + break; + case USB_DESCRIPTOR_TYPE_CONFIGURATION: + usb_rxtx_control.data = (unsigned char *) &usb_config_0; + size = CONFIG_0_DESCRIPTOR_LENGTH; + break; + case USB_DESCRIPTOR_TYPE_STRING: + if ( LSB( wVal) < USB_CNT_STRINGS) { + usb_rxtx_control.data = (unsigned char *) StringDescriptors[ LSB( wVal)]; + size = *usb_rxtx_control.data; + } else { + usb_stall_ep0(); + return; + } + break; + default: + usb_stall_ep0(); + return; + } + usb_rxtx_control.bytes = ( usb_rxtx_control.dreq.wLength < size) ? usb_rxtx_control.dreq.wLength : size; + usb_flags.request = 2; + //usb_send_to_usb( SEND_EP0, PDI_EP0_PACKET_SIZE); + } + + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/*** ***/ +/*** USB with IRQ ***/ +/*** ***/ +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + + #ifdef PDIUSB_WITH_EXCPTVECT_SET + void usb_isr(void) + #else /*PDIUSB_WITH_EXCPTVECT_SET*/ + void usb_isr(int intno, void *dev_id, struct pt_regs *regs) + #endif /*PDIUSB_WITH_EXCPTVECT_SET*/ + { + unsigned char usb_last_status; + + usb_irq_cnt++; + usb_last_irq = pdiGetInterrupt(); + if ( usb_last_irq) { + usb_flags.was_int = 1; + + debugPrint( DBG_INT, ("USB Interrupt 0x%X\n",usb_last_irq)); + if ( usb_last_irq & PDI_INT_BUSRESET) { // D12 - Bus reset reached + usb_flags.configured = 0; + if ( usb_flags.running && usb_flags.stop_request) { + usb_flags.running = 0; + usb_flags.stop_request = 0; + } + debugPrint( DBG_INT, ("Bus Reset\n")); + } else { + if ( usb_last_irq & PDI_INT_SUSPEND) { // D12 - Suspend flag changed + debugPrint( DBG_INT, ("Suspend Changed\n")); + } + // it must be first b/c tx and rx can be sended all together + if ( usb_last_irq & PDI_INT_EP0_IN) { // D12 - Ep0TxDone - data in EP0 was sended + usb_last_status = pdiGetLastTransStatus( PDI_EP0_TX); + debugPrint( DBG_INT, ("Ep0-Tx LTS=0x%X\n", usb_last_status)); + if (( usb_last_status & PDI_LTSTAT_RXTX_OK) && usb_flags.request > 1) { + if ( usb_flags.request == 2) { + unsigned int now = usb_rxtx_control.bytes; + if ( now > PDI_EP0_PACKET_SIZE) now = PDI_EP0_PACKET_SIZE; + debugPrint( DBG_INT, ("CNTR data\n")); + pdiWriteEndpoint( PDI_EP0_TX, now, usb_rxtx_control.data); + usb_rxtx_control.data += now; + if ( !(usb_rxtx_control.bytes -= now)) { + usb_flags.request = 3; + } + } else if ( usb_flags.request == 3) { + debugPrint( DBG_INT, ("CNTR ack\n")); + usb_flags.request = 0; + } else { + debugPrint( DBG_INT, ("tx 0 ... ???\n")); + } + } + } + + if ( usb_last_irq & PDI_INT_EP0_OUT) { // D12 - Ep0RxDone - some data was received in EP0 + usb_last_status = pdiGetLastTransStatus( PDI_EP0_RX); + debugPrint( DBG_INT, ("Ep0-Rx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + if ( usb_last_status & PDI_LTSTAT_SETUP) { + if ( usb_flags.request) { + debugPrint( DBG_INT, ("!!! New setup, but last not ack ...\n")); + } + usb_flags.request = 1; // Standard_requests(); + usb_answer_to_request(); + } else { + if ( usb_flags.request == 2) { + unsigned int now = usb_rxtx_control.bytes, ret; + if ( now > PDI_EP0_PACKET_SIZE) now = PDI_EP0_PACKET_SIZE; + debugPrint( DBG_INT, ("CNTR data\n")); + ret = pdiReadEndpoint( PDI_EP0_RX, now, usb_rxtx_control.data); + + if(ret>usb_rxtx_control.bytes) + ret = usb_rxtx_control.bytes; + + usb_rxtx_control.data += ret; + + if ( usb_rxtx_control.next_pkt_fnc ) { + if( usb_rxtx_control.next_pkt_fnc(&usb_rxtx_control, ret, USB_NEXT_PKT_REC) ) { + usb_stall_ep0(); + } + } + + if (!(usb_rxtx_control.bytes -= ret)) { + usb_rxtx_control.data -= usb_rxtx_control.dreq.wLength; + usb_flags.request = 3; + } + } else if ( usb_flags.request == 3) { + debugPrint( DBG_INT, ("CNTR ack\n")); + usb_flags.request = 0; + pdiReadEndpoint( PDI_EP0_RX, 0, 0); + if ( usb_rxtx_control.complete_fnc ) + usb_rxtx_control.complete_fnc(&usb_rxtx_control, USB_COMPLETE_OK); + usb_rxtx_control.next_pkt_fnc = NULL; + usb_rxtx_control.complete_fnc = NULL; + } else { + pdiReadEndpoint( PDI_EP0_RX, 0, 0); + } + } + } + } + if ( usb_last_irq & PDI_INT_EP1_OUT) { // D12 - Ep1RxDone - some data was received in EP1 + usb_last_status = pdiGetLastTransStatus( PDI_EP1_RX); + debugPrint( DBG_INT, ("Ep1-Rx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + pdiSetEpStatus( PDI_EP1_OUT, PDI_SET_EP_STALLED); + } + } + if ( usb_last_irq & PDI_INT_EP1_IN) { // D12 - Ep1TxDone - data in EP1 was sended + usb_last_status = pdiGetLastTransStatus( PDI_EP1_TX); + debugPrint( DBG_INT, ("Ep1-Tx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + pdiSetEpStatus( PDI_EP1_IN, PDI_SET_EP_STALLED); + } + } + + if ( usb_last_irq & PDI_INT_EP2_OUT) { // D12 - Ep2RxDone - some data was received in EP2 + usb_last_status = pdiGetLastTransStatus( PDI_EP2_RX); + debugPrint( DBG_INT, ("Ep2-Rx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + if ( usb_flags.terminal_mode) { + unsigned char hlpbfr[PDI_EP2_PACKET_SIZE], now = PDI_EP2_PACKET_SIZE, i; + MoreRead: + now = pdiReadEndpoint( PDI_EP2_RX, now, hlpbfr); + for(i=0;i (unsigned long)PDI_EP2_PACKET_SIZE)?PDI_EP2_PACKET_SIZE:(unsigned char)usb_rx_bulk.remain; + // unsigned char hlp[2]; + + if ( !usb_flags.bits.bulk_rx_data) { + usb_flags.bulk_rx_data = 1; + usb_start = msec_time; + } + // if ( now > PDI_EP2_PACKET_SIZE) now = PDI_EP2_PACKET_SIZE; + ReadAgain: + now = pdiReadEndpoint( PDI_EP2_RX, now, usb_rx_bulk.data); + usb_rx_bulk.data += now; + if ( !( usb_rx_bulk.remain -= now)) { + usb_stop = msec_time; + usb_flags.bulk_rx_data = 0; + // complete_func or set flag(event) + } + if ( usb_rx_bulk.remain > 0 && usb_rx_bulk.remain <= PDI_EP2_PACKET_SIZE) + goto ReadAgain; + } + } + } + if ( usb_last_irq & PDI_INT_EP2_IN) { // D12 - Ep2TxDone - data in EP2 was sended + usb_last_status = pdiGetLastTransStatus( PDI_EP2_TX); + debugPrint( DBG_INT, ("Ep2-Tx LTS=0x%X\n", usb_last_status)); + if ( usb_last_status & PDI_LTSTAT_RXTX_OK) { + if ( usb_flags.terminal_mode) { + int ch; + usb_tm_snded++; + ch = usb_com_get( &usb_com_que_out); + if ( ch < 0) { + usb_flags.bulk_tx_data = 0; + } else { + unsigned char uchr = ch; + usb_flags.bulk_tx_data = 1; + pdiWriteEndpoint( PDI_EP2_TX, 1, &uchr); + } + } else { + if ( usb_tx_bulk.remain) { + unsigned int now = usb_tx_bulk.remain; + if ( now > PDI_EP2_PACKET_SIZE) now = PDI_EP2_PACKET_SIZE; + pdiWriteEndpoint( PDI_EP2_TX, now, usb_tx_bulk.data); + usb_tx_bulk.data += now; + if (!(usb_tx_bulk.remain -= now)) { + // complete_func or set flag(event) + } + } + } + } + } + } + } + } + +#ifdef PDIUSB_WITH_ADD_IRQ_HANDLER + irq_handler_t usb_irq_handler = { + handler: usb_isr, + flags: 0, + dev_id: 0, + devname: "usb", + next: 0 + }; +#endif /*PDIUSB_WITH_ADD_IRQ_HANDLER*/ + + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/*** ***/ +/*** USB COM Emulator Module ***/ +/*** ***/ +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + int usb_tm_snd; + int usb_tm_snded; + int usb_tm_rcv; + + int usb_com_init( void) { + usb_tm_snd = 0; + usb_tm_snded = 0; + usb_tm_rcv = 0; + + usb_com_que_in.begin=usb_com_buf_in; + usb_com_que_in.end=usb_com_que_in.begin+sizeof(usb_com_buf_in); + usb_com_que_in.first=usb_com_que_in.begin; + usb_com_que_in.last=usb_com_que_in.begin; + + usb_com_que_out.begin=usb_com_buf_out; + usb_com_que_out.end=usb_com_que_out.begin+sizeof(usb_com_buf_out); + usb_com_que_out.first=usb_com_que_out.begin; + usb_com_que_out.last=usb_com_que_out.begin; + + return 1; + } + + /* put character c into queue, if full return -1 */ + int usb_com_put(usb_com_que_t *q, int c) + { + unsigned char *p=q->last; + *(p++)=(unsigned char)c; + if (p==q->end) p=q->begin; + if (p==q->first) return -1; + q->last=p; + return c; + } + /* get character from queue, if empty return -1 */ + int usb_com_get(usb_com_que_t *q) + { + unsigned char *p; + int c; + p=q->first; + if(p==q->last) return -1; + c=*(p++); + if(p==q->end) p=q->begin; + q->first=p; + return c; + } + +/* + int usb_com_sendch(int c) { + if ( usb_flags.terminal_mode) { + usb_tm_snd++; + if ( !usb_flags.bits.bulk_tx_data) { // hned poslat - atomicke nastaveni flagu ... + unsigned char byte = c; + pdiWriteEndpoint( PDI_EP2_TX, 1, (unsigned char *)&byte); + usb_flags.bulk_tx_data = 1; + } else { + if( usb_com_put(&usb_com_que_out,c)<0){ // nevejde se +#ifdef USE_USB_WITH_IRQ + while( usb_com_que_out.last == usb_com_que_out.first-1); // Wait if buffer is full !@#$%^&* + if( usb_com_put(&usb_com_que_out,c)<0) // case (last==end and first==begin) not respected +#endif + c=-1; + } + } + } + return c; + } +*/ + void usb_com_start_send( void) { + if ( !usb_flags.bits.bulk_tx_data && + usb_com_que_out.first != usb_com_que_out.last) { + int ch; + ch = usb_com_get( &usb_com_que_out); + if ( ch >= 0) { + unsigned char byte = ch; + usb_flags.bulk_tx_data = 1; + pdiWriteEndpoint( PDI_EP2_TX, 1, &byte); + } + } + } + + int usb_com_sendch(int c) { + if ( usb_flags.terminal_mode) { + usb_tm_snd++; +#ifndef USE_USB_WITH_IRQ + if( !usb_flags.bits.bulk_tx_data) { + unsigned char byte = c; + usb_flags.bulk_tx_data = 1; + pdiWriteEndpoint( PDI_EP2_TX, 1, &byte); + return c; + } +#endif + if( usb_com_put(&usb_com_que_out,c)<0){ /* nevejde se */ + +#ifdef USE_USB_WITH_IRQ + if ( !usb_flags.bits.bulk_tx_data) { + usb_com_start_send(); + } else { + while( usb_com_que_out.last == usb_com_que_out.first-1); /* Wait if buffer is full !@#$%^&* */ + } + if( usb_com_put(&usb_com_que_out,c)<0) /* case (last==end and first==begin) isn't respected */ +#endif + c=-1; + } + } + return c; + } + + + + int usb_com_recch() { + int val; + if ( !usb_flags.bits.terminal_mode) return -1; + val=usb_com_get(&usb_com_que_in); + return val; + } + + int usb_com_sendstr(const char *s) { + int cnt=0; + while(*s) + { + if(usb_com_sendch((unsigned char)(*(s++)))<0) break; + cnt++; + } + return cnt; + } + diff --git a/embedded/libs4c/usb/more/usb_srq.c b/embedded/libs4c/usb/more/usb_srq.c new file mode 100644 index 0000000..d235bb5 --- /dev/null +++ b/embedded/libs4c/usb/more/usb_srq.c @@ -0,0 +1,266 @@ +/*****************************************************/ +/*** Module : USB module ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002, 16.04.2003 ***/ +/*****************************************************/ + +#include +#include +#include +#include +#include +#include +#include + + // **************************** + int usb_stdreq_get_status( usb_device_t *udev) + { + unsigned char c, buf[2] = { 0, 0}; + unsigned char epid = (unsigned char) udev->request.wIndex; + usb_ep_t *ep0 = &(udev->ep0); + + usb_debug_print( DEBUG_LEVEL_HIGH, ("GetStatus\n")); + switch( udev->request.bmRequestType & USB_RECIPIENT) { + case USB_RECIPIENT_DEVICE: + if ( udev->flags & USB_FLAG_REMOTE_WAKE) //.remote_wake_up == 1) + buf[0] = USB_GETSTATUS_REMOTE_WAKEUP_ENABLED | USB_GETSTATUS_SELF_POWERED; + else + buf[0] = USB_GETSTATUS_SELF_POWERED; + break; + case USB_RECIPIENT_INTERFACE: + break; + case USB_RECIPIENT_ENDPOINT: + #if 0 + if ( epid & USB_ENDPOINT_DIRECTION_MASK) + c = pdiSelectEp(pdiEp2Idx(epid)); // endpoint in + else + c = pdiSelectEp(pdiEp2Idx(epid)); // endpoint Out + #ifdef PDIUSBD12 + buf[0] = (( c & PDI_SELEP_STALL) == PDI_SELEP_STALL); + #else + buf[0] = 0; + #endif + #endif + #warning usb_stdreq_get_status is DUMMY + break; + default: + return USB_COMPLETE_FAIL; + } + usb_udev_write_endpoint( ep0, buf, 2); + return USB_COMPLETE_OK; + } + + int usb_stdreq_clear_feature( usb_device_t *udev) + { + usb_ep_t *ep = NULL; + USB_DEVICE_REQUEST *dreq = &(udev->request); + unsigned char epid = (unsigned char) dreq->wIndex; + + usb_debug_print( DEBUG_LEVEL_HIGH, ("ClearFeature\n")); + switch( dreq->bmRequestType & USB_RECIPIENT) { + case USB_RECIPIENT_DEVICE: + if ( dreq->wValue == USB_FEATURE_REMOTE_WAKEUP) { + udev->flags &= ~USB_FLAG_REMOTE_WAKE; //.remote_wake_up = 0; + usb_udev_ack_setup( udev); + return USB_COMPLETE_OK; + } + break; + case USB_RECIPIENT_ENDPOINT: + if(!epid) { + ep = &udev->ep0; + } else { + unsigned char i; + for(i = 0; i < udev->cntep; i++) { + if(udev->ep[i].epnum == epid) { + ep = &udev->ep[i]; + } + } + if(!ep) + break; + } + if ( dreq->wValue == USB_FEATURE_ENDPOINT_STALL) { + usb_udev_unstall(ep); + usb_udev_ack_setup( udev); + return USB_COMPLETE_OK; + } + break; + } + return USB_COMPLETE_FAIL; + } + + int usb_stdreq_set_feature( usb_device_t *udev) + { + usb_ep_t *ep = NULL; + USB_DEVICE_REQUEST *dreq = &(udev->request); + unsigned char epid = (unsigned char) dreq->wIndex; + + usb_debug_print( DEBUG_LEVEL_HIGH, ("SetFeature\n")); + switch( dreq->bmRequestType & USB_RECIPIENT) { + case USB_RECIPIENT_DEVICE: + if ( dreq->wValue == USB_FEATURE_REMOTE_WAKEUP) { + udev->flags |= USB_FLAG_REMOTE_WAKE; //.remote_wake_up = 1; + usb_udev_ack_setup( udev); + return USB_COMPLETE_OK; + } + break; + case USB_RECIPIENT_ENDPOINT: + if(!epid) { + ep = &udev->ep0; + } else { + unsigned char i; + for(i = 0; i < udev->cntep; i++) { + if(udev->ep[i].epnum == epid) { + ep = &udev->ep[i]; + } + } + if(!ep) + break; + } + if ( dreq->wValue == USB_FEATURE_ENDPOINT_STALL) { + usb_udev_stall(ep); + usb_udev_ack_setup( udev); + return USB_COMPLETE_OK; + } + break; + } + return USB_COMPLETE_FAIL; + } + + int usb_stdreq_set_address( usb_device_t *udev) + { + int adr; + USB_DEVICE_REQUEST *dreq = &(udev->request); + adr=dreq->wValue & DEVICE_ADDRESS_MASK; + usb_debug_print( DEBUG_LEVEL_HIGH, ("SetAddr-%d\n",adr)); + usb_udev_ack_setup( udev); + usb_udev_set_addr( udev, adr); + return USB_COMPLETE_OK; + } + + int usb_stdreq_get_configuration( usb_device_t *udev) + { + unsigned char buf = udev->configuration; //usb_flags.configured; + usb_ep_t *ep0 = &(udev->ep0); + usb_debug_print( DEBUG_LEVEL_HIGH, ("GetConfig\n")); + usb_udev_write_endpoint( ep0, &buf, 1); + return USB_COMPLETE_OK; + } + + int usb_stdreq_set_configuration( usb_device_t *udev) + { + USB_DEVICE_REQUEST *dreq = &(udev->request); + unsigned char iCfg = dreq->wValue & 0xff; + usb_debug_print( DEBUG_LEVEL_HIGH, ("SetConfig\n")); + while (1) { // put device in unconfigured state or set configuration 1 ( no else) + const USB_DEVICE_CONFIGURATION_ENTRY *pcd = udev->devdes_table->pConfigurations; + if(iCfg) { + unsigned char i = udev->devdes_table->bNumConfigurations; + for(; i && (pcd->pConfigDescription->bConfigurationValue != iCfg); i--, pcd++); + if(!i) + break; + } + + udev->flags &= ~USB_FLAG_CONFIGURED; + + usb_udev_ack_setup( udev); + + usb_udev_set_configuration( udev, iCfg); + + udev->configuration = iCfg; //usb_flags.configured = iCfg; + + if(iCfg) + udev->flags |= USB_FLAG_CONFIGURED; + + return USB_COMPLETE_OK; + } + return USB_COMPLETE_FAIL; + } + + int usb_stdreq_get_interface( usb_device_t *udev) + { + unsigned char buf = 0; /// udev->interface + usb_ep_t *ep0 = &(udev->ep0); + usb_debug_print( DEBUG_LEVEL_HIGH, ("GetIface\n")); + usb_udev_write_endpoint( ep0, &buf, 1); + return USB_COMPLETE_OK; + } + + int usb_stdreq_set_interface( usb_device_t *udev) + { + USB_DEVICE_REQUEST *dreq = &(udev->request); + + usb_debug_print( DEBUG_LEVEL_HIGH, ("SetIface\n")); + if (( dreq->wValue == 0) && ( dreq->wIndex == 0)) { + usb_udev_ack_setup( udev); + return USB_COMPLETE_OK; + } else { + return USB_COMPLETE_FAIL; + } + } + + int usb_stdreq_get_descriptor( usb_device_t *udev) + { + unsigned char confidx; + unsigned char *pDesc; + unsigned short Len = 0; + USB_DEVICE_REQUEST *dreq = &(udev->request); + const USB_DEVICE_CONFIGURATION_ENTRY *pconfent; + int i; + + i = (dreq->wValue >> 8) & 0xff; /* MSB part of wValue */ + usb_debug_print( DEBUG_LEVEL_HIGH, ("GetDesc\n")); + usb_debug_print( DEBUG_LEVEL_VERBOSE, ( " - %s desc.\n", /*(unsigned int)*/ usb_debug_get_std_descriptor(i))); + + switch (i) { + case USB_DESCRIPTOR_TYPE_DEVICE: + pDesc = (unsigned char *)udev->devdes_table->pDeviceDescription; + Len = sizeof( USB_DEVICE_DESCRIPTOR); + break; + case USB_DESCRIPTOR_TYPE_CONFIGURATION: + /* FIXME confidx = udev->configuration; */ + confidx = 0; + pconfent = &udev->devdes_table->pConfigurations[confidx]; + pDesc = (unsigned char *)pconfent->pConfigDescription; + Len = pconfent->iConfigTotalLength; + break; + case USB_DESCRIPTOR_TYPE_INTERFACE: + /* FIXME multiple interfaces */ + pDesc = (unsigned char *)udev->devdes_table->pInterfaceDescriptors[0]; + Len = sizeof( USB_INTERFACE_DESCRIPTOR); + break; + case USB_DESCRIPTOR_TYPE_STRING: + i = dreq->wValue & 0xff; /* LSB part of wValue */ + /*printf("Get descriptor indx=0x%02x\n", i);*/ + if ( i < udev->devdes_table->iNumStrings) { + pDesc = (unsigned char *) udev->devdes_table->pStrings[i]; + Len = *pDesc; + /*usb_debug_print(0,("indx=0x%02x ptr=%p len=%d : '%c'\n", i, pDesc, Len, pDesc[2]));*/ + } else { + return USB_COMPLETE_FAIL; + } + break; + default: + return USB_COMPLETE_FAIL; + } + if ( dreq->wLength < Len) Len = dreq->wLength; + usb_send_control_data( udev, pDesc, Len); + return USB_COMPLETE_OK; + } + + +/* + void usb_init_stdreq_fnc( usb_device_t *udev) + { + // memset( udev->stdreq, 0, sizeof(udev->stdreq)); + + udev->stdreq[USB_REQUEST_GET_STATUS] = usb_stdreq_get_status; + udev->stdreq[USB_REQUEST_CLEAR_FEATURE] = usb_stdreq_clear_feature; + udev->stdreq[USB_REQUEST_SET_FEATURE] = usb_stdreq_set_feature; + udev->stdreq[USB_REQUEST_SET_ADDRESS] = usb_stdreq_set_address; + udev->stdreq[USB_REQUEST_GET_DESCRIPTOR] = usb_stdreq_get_descriptor; + udev->stdreq[USB_REQUEST_GET_CONFIGURATION] = usb_stdreq_get_configuration; + udev->stdreq[USB_REQUEST_SET_CONFIGURATION] = usb_stdreq_set_configuration; + udev->stdreq[USB_REQUEST_GET_INTERFACE] = usb_stdreq_get_interface; + udev->stdreq[USB_REQUEST_SET_INTERFACE] = usb_stdreq_set_interface; + } +*/ diff --git a/embedded/libs4c/usb/pdiusb/Makefile b/embedded/libs4c/usb/pdiusb/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/embedded/libs4c/usb/pdiusb/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/embedded/libs4c/usb/pdiusb/Makefile.omk b/embedded/libs4c/usb/pdiusb/Makefile.omk new file mode 100644 index 0000000..40b9dfd --- /dev/null +++ b/embedded/libs4c/usb/pdiusb/Makefile.omk @@ -0,0 +1,12 @@ +# -*- makefile -*- + +default_CONFIG = CONFIG_USB_PDIUSB=n + +ifeq ($(CONFIG_USB_PDIUSB),y) +lib_LIBRARIES = usbpdi + +nobase_include_HEADERS = usb/pdi.h usb/pdiusb.h + +usbpdi_SOURCES = pdi.c pdiusb.c +#usbpdi_SOURCES += pdi4rtems.c +endif #CONFIG_USB_PDIUSB diff --git a/embedded/libs4c/usb/pdiusb/pdi.c b/embedded/libs4c/usb/pdiusb/pdi.c new file mode 100644 index 0000000..1cc4cb2 --- /dev/null +++ b/embedded/libs4c/usb/pdiusb/pdi.c @@ -0,0 +1,232 @@ +/*****************************************************/ +/*** Module : USB PDI ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002, 16.04.2003 ***/ +/*****************************************************/ + +#include +#include +#include + +#define USB_PDI_EXPORT_FNC + +#include +#include +#include + + +/* init chip state */ + void pdiInitChipState( void) { + #ifdef PDIUSBD11 + pdiSetHUBAddressEnable( 0, 0); + #endif /*PDIUSBD11*/ + pdiSetAddressEnable( PDI_ENAD_ENABLE); + pdiSetEndpointEnable( PDI_EPEN_ENABLE); + } + +#ifdef PDIUSBD11 + + #define PDI_MODE_BASE_VALUE (PDI_MODE_MUSTBEONE | \ + PDI_MODE_REMOTE_WAKEUP | PDI_MODE_NO_LAZY_CLOCK | \ + PDI_MODE_CLOCK_RUNNING | PDI_CLOCK_4M) + +#else /*PDIUSBD11*/ + + #define PDI_MODE_BASE_VALUE (PDI_CLOCK_SET_TO_ONE | \ + PDI_MODE_NO_LAZY_CLOCK | PDI_MODE_CLOCK_RUNNING | \ + PDI_CLOCK_4M) + +#endif /*PDIUSBD11*/ + + int usb_pdi_set_addr( usb_device_t *udev, unsigned char addr) { + #if !defined(PDIUSBH11A_MULTIPLE) // D11,D12,H11,H11A_S(emb.fnc) + pdiSetAddressEnable(addr | PDI_ENAD_ENABLE); + #else + /*void pdiSetEmbFncAddressEnable( unsigned char byFnc, unsigned char byAddress, unsigned char byEnable);*/ + #error usb_pdi_set_addr not implemented for PDIUSBH11A_MULTIPLE + #endif + return 0; + } + + int usb_pdi_set_configuration( usb_device_t *udev, unsigned char iCfg) USB_UDEV_REENTRANT_SIGN + { + pdiSetEndpointEnable( 0); // USBInitUnconfig(); + if ( iCfg) { + pdiSetEndpointEnable( PDI_EPEN_ENABLE); //USBInitConfig(); + } + return 0; + } + +/* connect usb */ + int usb_pdi_connect( usb_device_t *udev) { + pdiSetMode( PDI_MODE_BASE_VALUE | PDI_MODE_SOFT_CONNECT ); + return 0; + } + +/* disconnect usb */ + int usb_pdi_disconnect( usb_device_t *udev) { + pdiSetMode( PDI_MODE_BASE_VALUE & ~PDI_MODE_SOFT_CONNECT ); + return 0; + } + +/* acknowledge control transfer */ + void usb_pdi_ack_setup( usb_device_t *udev) { + pdiWriteEndpoint( PDI_EP0_TX, 0, 0); + } + + +/* acknowledge control transfer */ + void usb_pdi_ack_control_setup( usb_device_t *udev) { + pdiAckSetupControl(); + } + + +/** + * usb_pdi_check events + * function reads interrupt register and sets event flags + * function returns 1 if there is some new event. + * function returns 0 if there isn't new event but all is OK + * function returns -1 if there is any error +*/ + int usb_pdi_check_events( usb_device_t *udev) { + volatile unsigned char LastTrans = 0; + volatile unsigned int LastInt; + int ret = 0, i; + + LastInt = pdiGetInterrupt(); +if ( LastInt) { + usb_debug_print( DEBUG_LEVEL_LOW, ("PI=0x%04X\n", LastInt)); +} + usb_debug_print( DEBUG_LEVEL_HIGH, ("PDI Int=0x%04X\n", LastInt)); + + if ( LastInt & PDI_INT_BUSRESET) { // D12 - Bus reset reached + pdiInitChipState(); + udev->flags |= USB_FLAG_BUS_RESET; + ret = 1; + } else { + #ifdef PDIUSBD12 + if ( LastInt & PDI_INT_SUSPEND) { // D12 - Suspend flag changed + udev->flags |= USB_FLAG_SUSPEND; + ret = 1; + } + #endif + + + if ( LastInt & PDI_INT_EP0_OUT) { // D12 - Ep0RxDone - some data was received in EP0 + LastTrans = pdiGetLastTransStatus( PDI_EP0_RX); + if ( LastTrans & PDI_LTSTAT_SETUP) { // setup packet + udev->flags |= USB_FLAG_SETUP; + } else { + udev->flags |= USB_FLAG_EVENT_RX0; + } + ret = 1; + } + if ( LastInt & PDI_INT_EP0_IN) { // D12 - Ep0TxDone - data in EP0 was sended + LastTrans = pdiGetLastTransStatus( PDI_EP0_TX); + udev->flags |= USB_FLAG_EVENT_TX0; + ret = 1; + } + + + for( i=0; icntep; i++) { + if ( LastInt & (udev->ep+i)->event_mask) { + LastTrans = pdiGetLastTransStatus( (udev->ep+i)->epnum); + udev->ep_events |= 1<ep+i)->event_mask); + ret = 1; + } + } + + /* check unsupported endpoints */ + if ( LastInt & PDI_INT_EP1_OUT) { // D12 - Ep1RxDone - some data was received in EP1 + LastTrans = pdiGetLastTransStatus( PDI_EP1_RX); + pdiSetEpStatus( PDI_EP1_RX, PDI_SET_EP_STALLED); + } + if ( LastInt & PDI_INT_EP1_IN) { // D12 - Ep1TxDone - data in EP1 was sended + LastTrans = pdiGetLastTransStatus( PDI_EP1_TX); + pdiSetEpStatus( PDI_EP1_TX, PDI_SET_EP_STALLED); + } + if ( LastInt & PDI_INT_EP2_OUT) { // D12 - Ep2RxDone - some data was received in EP2 + LastTrans = pdiGetLastTransStatus( PDI_EP2_RX); + pdiSetEpStatus( PDI_EP2_RX, PDI_SET_EP_STALLED); + } + if ( LastInt & PDI_INT_EP2_IN) { // D12 - Ep2TxDone - data in EP2 was sended + LastTrans = pdiGetLastTransStatus( PDI_EP2_TX); + pdiSetEpStatus( PDI_EP2_TX, PDI_SET_EP_STALLED); + } + #if defined(PDIUSBD11) || defined(PDIUSBH11A_SINGLE) // D11,H11_S + if ( LastInt & PDI_INT_EP3_OUT) { // D11 - Ep3RxDone - some data was received in EP3 + LastTrans = pdiGetLastTransStatus( PDI_EP3_RX); + pdiSetEpStatus( PDI_EP3_RX, PDI_SET_EP_STALLED); + } + if ( LastInt & PDI_INT_EP3_IN) { // D11 - Ep3TxDone - data in EP3 was sended + LastTrans = pdiGetLastTransStatus( PDI_EP3_TX); + pdiSetEpStatus( PDI_EP3_TX, PDI_SET_EP_STALLED); + } + #endif /* D11,H11_S */ + } + return ret; + } + + +/* stall endpoint X */ + void usb_pdi_stall( usb_ep_t *ep) { + if ( ep->epnum) { + pdiSetEpStatus( ep->epnum, PDI_SET_EP_STALLED); + } else { // endpoint0 + pdiSetEpStatus( PDI_EP0_TX, PDI_SET_EP_STALLED); + pdiSetEpStatus( PDI_EP0_RX, PDI_SET_EP_STALLED); + } + } + +/* stall endpoint X */ + void usb_pdi_unstall( usb_ep_t *ep) { + if ( ep->epnum) { + pdiSetEpStatus( ep->epnum, 0); + } else { // endpoint0 + pdiSetEpStatus( PDI_EP0_TX, 0); + pdiSetEpStatus( PDI_EP0_RX, 0); + } + } + + int usb_pdi_read_endpoint( usb_ep_t *ep, void *ptr, int size) USB_UDEV_REENTRANT_SIGN + { + if(!ep->epnum) + return pdiReadEndpoint( PDI_EP0_RX, size, ptr); + else + return pdiReadEndpoint( ep->epnum, size, ptr); + } + + int usb_pdi_write_endpoint( usb_ep_t *ep, const void *ptr, int size) USB_UDEV_REENTRANT_SIGN + { + if(!ep->epnum) + pdiWriteEndpoint( PDI_EP0_TX, size, ptr); + else + pdiWriteEndpoint( ep->epnum, size, ptr); + return size; + } + + +/* init usb structures and chip */ + int usb_pdi_init( usb_device_t *udev) { + + #ifndef USB_PDI_DIRECT_FNC + udev->connect = usb_pdi_connect; + udev->set_addr = usb_pdi_set_addr; + udev->set_configuration = usb_pdi_set_configuration; + udev->disconnect = usb_pdi_disconnect; + udev->ack_setup = usb_pdi_ack_setup; + udev->ack_control_setup = usb_pdi_ack_control_setup; + udev->stall = usb_pdi_stall; + udev->unstall = usb_pdi_unstall; + udev->check_events = usb_pdi_check_events; + udev->read_endpoint = usb_pdi_read_endpoint; + udev->write_endpoint = usb_pdi_write_endpoint; + #endif /*USB_PDI_DIRECT_FNC*/ + + udev->ep0.max_packet_size = PDI_EP0_PACKET_SIZE; + + pdiInitChipState(); + pdiSetMode( PDI_MODE_BASE_VALUE); + return 0; + } diff --git a/embedded/libs4c/usb/pdiusb/pdiusb.c b/embedded/libs4c/usb/pdiusb/pdiusb.c new file mode 100644 index 0000000..280717c --- /dev/null +++ b/embedded/libs4c/usb/pdiusb/pdiusb.c @@ -0,0 +1,527 @@ +/*********************************************************/ +/*** Module : PDIUSB D11,H11,H11A,D12 - implement. ***/ +/*** Author : Roman Bartosinski (C) 03.10.2002 ***/ +/*** Description : Integrate common functions for ***/ +/*** PDIUSBD11,PDIUSBD12,PDIUSBH11(old) ***/ +/*** PDIUSBH11A in Single/Multiple mode ***/ +/*** to one common file. ***/ +/*** Modify : 10.10.2002 - add H11 ***/ +/*** 13.10.2002 - add spec.fnc for 'using' ***/ +/*********************************************************/ + +#include +#include +#if __BYTE_ORDER == __BIG_ENDIAN + #include +#endif +#include +#include + + #ifdef PDI_CMD_RWD_INTERNAL + #ifndef PDIUSBD12 + #include + #endif + #endif + + #ifndef SDCC + #define xdata + #endif + + +/*********************************************************/ +// Function for read and write from/into chip + + #if defined(PDI_CMD_RWD_INTERNAL) + #if defined(PDIUSBD12) // parallel interface + + void pdiSendCommand( unsigned char byCmd) { + *((volatile xdata unsigned char *) PDIUSB_COMMAND_ADDR) = byCmd; + } + unsigned char pdiReadData( unsigned char byCount, void *pbyData) { + unsigned char out = byCount; + while (byCount) { + byCount--; + *(unsigned char*)pbyData++ = *((volatile xdata unsigned char *) PDIUSB_READ_DATA_ADDR); + } + return out; + } + void pdiWriteData( unsigned char byCount, const void *pbyData) { + while (byCount) { + byCount--; + *((volatile xdata unsigned char *) PDIUSB_WRITE_DATA_ADDR) = *(unsigned char*)pbyData++; + } + } + + #if defined(PDI_USE_USING) + unsigned short pdiIntCmdReadData( unsigned char byCmd, unsigned char byShort) _PDI_USING { + unsigned char i[2]; + *((volatile xdata unsigned char *) PDIUSB_COMMAND_ADDR) = byCmd; + i[0] = *((volatile xdata unsigned char *) PDIUSB_READ_DATA_ADDR); + if ( !byShort) { + i[1] = 0; + return i[0]; + } + i[1] = *((volatile xdata unsigned char *) PDIUSB_READ_DATA_ADDR); + return (((unsigned short) i[1]) << 8) + i[0]; + } + #endif + + #else // serial interface iic + #ifndef D11_REG_CMD + #define D11_REG_CMD PDIUSB_COMMAND_ADDR + #endif + #ifndef D11_REG_DATA_WRITE + #define D11_REG_DATA_WRITE PDIUSB_WRITE_DATA_ADDR + #endif + #ifndef D11_REG_DATA_READ + #define D11_REG_DATA_READ PDIUSB_READ_DATA_ADDR + #endif + + void pdiSendCommand( unsigned char byCmd) { + I2C_Write( D11_REG_CMD, &byCmd, 1); + } + unsigned char pdiReadData( unsigned char byCount, void *pbyData) { + I2C_Read( D11_REG_DATA_READ, pbyData, byCount); + return byCount; + } + void pdiWriteData( unsigned char byCount, const void *pbyData) { + I2C_Write( D11_REG_DATA_WRITE, pbyData, byCount); + } + #if defined(PDI_USE_USING) + unsigned short pdiIntCmdReadData( unsigned char byCmd, unsigned char byShort) _PDI_USING { + } + #endif + + #endif + #endif + + +/*********************************************************/ +/*********************************************************/ +// PDIUSB common commands + +#if defined(PDIUSBH11) || defined(PDIUSBH11A) || defined(PDIUSBD11) + + /*********************************************************/ + // pdiSetHUBAddressEnable + // enable HUB function and set address (byAddress is 0-0x7F, byEnable is 0 or 1) + void pdiSetHUBAddressEnable( unsigned char byAddress, unsigned char byEnable) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("H ")); + byAddress = (byAddress & 0x7F) | (byEnable << 7); + pdiSendCommand( PDI_CMD_HUB_ENB_ADDR); + pdiWriteData( 1, &byAddress); + } + +#endif +#if !defined(PDIUSBH11A_MULTPLE) // D11,D12,H11,H11A_S(emb.fnc) + + /*********************************************************/ + // pdiSetAddressEnable + // Enable function and set address (byAddress is 0-0x7F, byEnable is 0 or 1) + void pdiSetAddressEnable( unsigned char byAddr_Enb) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("A ")); + pdiSendCommand( PDI_CMD_FNC_ENB_ADDR); + pdiWriteData( 1, &byAddr_Enb); + } + +#else + + /*********************************************************/ + // pdiSetEmbFncAddressEnable + // Enable Embedded function and set address (byAddress is 0-0x7F, byEnable is 0 or 1) + // byFnc - function index (zero based) 0-3 + void pdiSetEmbFncAddressEnable( unsigned char byFnc, unsigned char byAddress, unsigned char byEnable) { + byAddress = (byAddress & 0x7F) | (byEnable << 7); + pdiSendCommand( PDI_CMD_FNC1_ENB_ADDR + byFnc); + pdiWriteData( 1, &byAddress); + } + +#endif + + + + /*********************************************************/ + // pdiSetEndpointEnable + // enable/disable endpoints (PDI_EPEN_xxx) + void pdiSetEndpointEnable( unsigned char byEnable) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("E ")); + pdiSendCommand( PDI_CMD_EPEN); + pdiWriteData( 1, &byEnable); + } + + +#if !defined(PDIUSBH11) // H11 has not it + + /*********************************************************/ + // pdiSetMode + // set chip mode (PDI_MODE_xxx) and clock division factor (PDI_CLOCK_xxx) + void pdiSetMode( unsigned short wMode_Clock) { + unsigned char sm[2]; +// usb_debug_print( DEBUG_LEVEL_HIGH, ("M%04X ",wMode_Clock)); + sm[0] = (unsigned char) (wMode_Clock & 0xff); + sm[1] = (unsigned char) (wMode_Clock >> 8); + pdiSendCommand( PDI_CMD_SET_MODE); + pdiWriteData( 2, sm); + } + +#endif + + #if defined(PDIUSBD12) + + /*********************************************************/ + // pdiSetDMA + // set DMA mode (PDI_DMA_xxx) + void pdiSetDMA( unsigned char byDma) { + pdiSendCommand( PDI_CMD_SET_DMA); + pdiWriteData( 1, &byDma); + } + + /*********************************************************/ + // pdiGetDMA + // get current DMA mode + unsigned char pdiGetDMA( void) { + unsigned char dma; + pdiSendCommand( PDI_CMD_GET_DMA); + pdiReadData( 1, &dma); + return dma; + } + + #endif + + + #if defined(PDIUSBH11) + + /*********************************************************/ + + // pdiGetInterrupt - H11 return only one byte + // get interrupt register (PDI_INT_xxx) + unsigned char pdiGetInterrupt( void) _PDI_USING { + unsigned char gin; +#if defined(PDI_USE_USING) + return pdiIntCmdReadData( PDI_CMD_GET_INT_REG, 0); +#else + pdiSendCommand( PDI_CMD_GET_INT_REG); + pdiReadData( 1, &gin); + return gin; +#endif + } + + #else + + /*********************************************************/ + // pdiGetInterrupt + // get interrupt register (PDI_INT_xxx) + unsigned short pdiGetInterrupt( void) _PDI_USING { + unsigned short gin; +#if defined(PDI_USE_USING) + return pdiIntCmdReadData( PDI_CMD_GET_INT_REG, 1); +#else + pdiSendCommand( PDI_CMD_GET_INT_REG); + pdiReadData( 2, &gin); + #if __BYTE_ORDER == __BIG_ENDIAN + gin=bswap_16(gin); + #endif + return gin; //pdiData[0] + (((unsigned short)pdiData[1])<<8); +#endif + } + + #endif + + /*********************************************************/ + // pdiSelectEp + // set internal buffer pointer to selected endpoint (zero based) (PDI_SELEP_xxx) + unsigned char pdiSelectEp( unsigned char byEpIdx) { + unsigned char sep; +// usb_debug_print( DEBUG_LEVEL_HIGH, ("e%1d ",byEpIdx)); + pdiSendCommand( PDI_CMD_SELECT_EP + byEpIdx); + pdiReadData( 1, &sep); + return sep; + } + + /*********************************************************/ + // pdiGetLastTransStatus + // get Last transaction status (PDI_LTSTAT_xxx and PDI_ERR_xxx) + unsigned char pdiGetLastTransStatus( unsigned char byEpIdx) _PDI_USING { + unsigned char lts; +// usb_debug_print( DEBUG_LEVEL_HIGH, ("L ")); +#if defined(PDI_USE_USING) + return pdiIntCmdReadData( PDI_CMD_GET_LAST_STAT + byEpIdx, 0); +#else + pdiSendCommand( PDI_CMD_GET_LAST_STAT + byEpIdx); + pdiReadData( 1, <s); + return lts; +#endif + } + + + #if defined(PDIUSBD11) || defined(PDIUSBH11) || defined(PDIUSBH11A) + + /*********************************************************/ + // pdiGetEpStatus + // get Endpoint Status (PDI_EPSTAT_xxx) + unsigned char pdiGetEpStatus( unsigned char byEpIdx) { + unsigned char ges; +// usb_debug_print( DEBUG_LEVEL_HIGH, ("G ")); + pdiSendCommand( PDI_CMD_GET_EP_STAT + byEpIdx); + pdiReadData( 1, &ges); + return ges; + } + + #endif + + /*********************************************************/ + // pdiReadFromEpBuffer - raw reading + // read data from selected internal chip buffer + // if byLength < length of buffer data, so we read only byLength data) + unsigned char pdiReadFromEpBuffer( unsigned char byLength, unsigned char *pToBuff) { + unsigned char rdep[2]; +// usb_debug_print( DEBUG_LEVEL_HIGH, ("R ")); + pdiSendCommand( PDI_CMD_READ_BUFFER); + pdiReadData( 2, rdep); + if ( rdep[1]) { // there is some data + if ( byLength < rdep[1]) // we need less data then is received + rdep[1] = byLength; + pdiReadData( rdep[1], pToBuff); + } + return rdep[1]; + } + + /*********************************************************/ + // pdiWriteToEpBuffer - raw writing + // write data to selected internal chip buffer + void pdiWriteToEpBuffer( unsigned char byLength, const unsigned char *pFromBuff) { + unsigned char hd[2]; +// usb_debug_print( DEBUG_LEVEL_HIGH, ("W ")); + pdiSendCommand( PDI_CMD_WRITE_BUFFER); + hd[0] = 0; hd[1] = byLength; + pdiWriteData( 2, hd); + if ( byLength) { + pdiWriteData( byLength, pFromBuff); + } + } + + /*********************************************************/ + // pdiSetEpStatus + // set endpoint stall flag + void pdiSetEpStatus( unsigned char byEpIdx, unsigned char byStatus) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("T ")); + pdiSendCommand( PDI_CMD_SET_EP_STAT + byEpIdx); + pdiWriteData( 1, &byStatus); + } + + /*********************************************************/ + // pdiAcknowledgeSetup + // chip disable fncs Validate and Clear after SETUP packet, + // this cmd re-enable these fncs + void pdiAcknowledgeSetup( void) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("C ")); + pdiSendCommand( PDI_CMD_ACK_SETUP); + } + + /*********************************************************/ + // pdiClearBuffer + // set endpoint flag 'empty' and next data can be receive + void pdiClearBuffer( void) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("B ")); + pdiSendCommand( PDI_CMD_CLEAR_BUFFER); + } + + + /*********************************************************/ + // pdiValidateBuffer + // set endpoint flag 'full' and data can be send + void pdiValidateBuffer( void) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("V ")); + pdiSendCommand( PDI_CMD_VALID_BUFFER); + } + + /*********************************************************/ + // pdiSendResume + // send an upstream resume signal for 10ms + void pdiSendResume( void) { +// usb_debug_print( DEBUG_LEVEL_HIGH, ("M ")); + pdiSendCommand( PDI_CMD_SEND_RESUME); + } + + /*********************************************************/ + // pdiGetFrameNumber + // return frame number of last successfully received SOF + unsigned short pdiGetFrameNumber( void) { + unsigned short gfn; + pdiSendCommand( PDI_CMD_GET_FRAME); + pdiReadData( 2, &gfn); + #if __BYTE_ORDER == __BIG_ENDIAN + gfn=bswap_16(gfn); + #endif + return gfn; //pdiData[0] + (((unsigned short)pdiData[1])<<8); + } + + /*********************************************************/ + // pdiGetChipID - this function is undocumented + // read chip ID (not documented function) ( LSB is maybe type of chip in hex (0x12,0x11)) + unsigned short pdiGetChipID( void) { + unsigned short gid; + pdiSendCommand( PDI_CMD_GET_CHIP_ID); + pdiReadData( 2, &gid); + #if __BYTE_ORDER == __BIG_ENDIAN + gid=bswap_16(gid); + #endif + return gid; //pdiData[0] + (((unsigned short)pdiData[1])<<8); + } + + + /*********************************************************/ + /*********************************************************/ + // HUB command +#if defined(PDIUSBH11) || defined(PDIUSBH11A) + /*********************************************************/ + // pdiClearPortFeature + // clear feature 'byFeature' in downstream port 2-5 'byEpIdx' (zero based) + void pdiClearPortFeature( unsigned char byEpIdx, unsigned char byFeature) { + pdiSendCommand( PDI_CMD_P2_CLR_FEATURE + byEpIdx); + pdiWriteData( 1, &byFeature); + } + + /*********************************************************/ + // pdiSetPortFeature + // set feature 'byFeature' in downstream port 2-5 'byEpIdx' (zero based) + void pdiSetPortFeature( unsigned char byEpIdx, unsigned char byFeature) { + pdiSendCommand( PDI_CMD_P2_SET_FEATURE + byEpIdx); + pdiWriteData( 1, &byFeature); + } + + /*********************************************************/ + // pdiGetPortFeature + // get port status (port status byte and port status change byte) + unsigned short pdiGetPortFeature( unsigned char byEpIdx) { + unsigned short gpf; + pdiSendCommand( PDI_CMD_P2_GET_STATUS + byEpIdx); + pdiReadData( 2, &gpf); + #if __BYTE_ORDER == __BIG_ENDIAN + gpf=bswap_16(gpf); + #endif + return gpf; //pdiData[0] + (((unsigned short)pdiData[1])<<8); + } + + /*********************************************************/ + // pdiSetStatusChangeBits + // set local power change bits status + void pdiSetStatusChangeBits( unsigned char byBits) { + pdiSendCommand( PDI_CMD_SET_CHNG_BITS); + pdiWriteData( 1, &byBits); + } + +#endif + + + +/*********************************************************/ +/*********************************************************/ +// PDIUSB other commands + + // complex function for select endpoint, write data and validate data in endpoint buffer + void pdiWriteEndpoint( unsigned char byEpIdx, unsigned char byLength, const unsigned char *pbyData) { + pdiSelectEp( byEpIdx); + pdiWriteToEpBuffer( byLength, pbyData); + pdiValidateBuffer(); + } + + // complex function for select endpoint, read data and clear endpoint buffer + // byMaxLength means how many bytes will be maximally read. + unsigned char pdiReadEndpoint( unsigned char byEpIdx, unsigned char byMaxLength, unsigned char *pbyData) { + unsigned char cnt = 0, sep; + sep = pdiSelectEp( byEpIdx); + if ( sep & PDI_SELEP_FULL) { + cnt = pdiReadFromEpBuffer( byMaxLength, pbyData); + pdiClearBuffer(); + } + return cnt; + } + + // complex universal function for select command and read/write data to/from PDIUSB + unsigned char pdiCmdData( unsigned char byCmd, unsigned char *pbyData, + unsigned char byCount, unsigned char byRead) { + pdiSendCommand( byCmd); + if ( byCount) { + if( byRead) byCount = pdiReadData( byCount, pbyData); // Read Data + else pdiWriteData( byCount, pbyData); // Write Data + } + return byCount; + } + +#if !defined(PDIUSBH11A_MULTIPLE) + // complex function for acknowledge control endpoint + void pdiAckSetupControl( void) { + pdiSendCommand( PDI_CMD_SELECT_EP + PDI_EP0_RX); + pdiSendCommand( PDI_CMD_ACK_SETUP); + pdiSendCommand( PDI_CMD_CLEAR_BUFFER); + pdiSendCommand( PDI_CMD_SELECT_EP + PDI_EP0_TX); + pdiSendCommand( PDI_CMD_ACK_SETUP); + } +#else + // complex function for acknowledge control endpoint ( for one emb.fnc. 1,6,7) (zero-based 0,1,2) + void pdiAckSetupFncControl( unsigned char Fnc) { + unsigned char FncTab[3] = { PDI_F1_EP0_RX, PDI_F6_EP0_RX, PDI_F7_EP0_RX}; + pdiSendCommand( PDI_CMD_SELECT_EP + FncTab[Fnc]); + pdiSendCommand( PDI_CMD_ACK_SETUP); + pdiSendCommand( PDI_CMD_CLEAR_BUFFER); + pdiSendCommand( PDI_CMD_SELECT_EP + FncTab[Fnc] + 1); + pdiSendCommand( PDI_CMD_ACK_SETUP); + } +#endif + +#if defined(PDIUSBD12) // parallel interface + void pdiInit( void) { + pdiSetAddressEnable( PDI_ENAD_ENABLE); + pdiSetEndpointEnable( PDI_EPEN_ENABLE); + pdiSetDMA( PDI_DMA_EP4_INT | PDI_DMA_EP5_INT); + pdiSetMode( PDI_MODE_NO_LAZY_CLOCK | PDI_MODE_CLOCK_RUNNING | + PDI_MODE_SOFT_CONNECT | PDI_CLOCK_12M); + } +#endif + +#if defined(PDIUSBH11A_SINGLE) // serial interface + void pdiInit( void) { + pdiSetHUBAddressEnable( 0, 0); // disable HUB + pdiSetAddressEnable( PDI_ENAD_ENABLE); // enable emb.function + pdiSetEndpointEnable( PDI_EPEN_FNC_ENB); + pdiSetMode( PDI_MODE_REMOTE_WAKEUP | PDI_MODE_NO_LAZY_CLOCK | PDI_MODE_CLOCK_RUNNING | + PDI_MODE_SOFT_CONNECT | PDI_MODE_SINGLE_FNC | PDI_CLOCK_12M); + } +#endif + +/*********************************************************/ + + static const unsigned char epin2idx[]={ + PDI_EP0_IN, + PDI_EP1_IN, + #if PDI_CNT_EP > 1 + PDI_EP2_IN, + #if PDI_CNT_EP > 2 + PDI_EP3_IN, + #endif + #endif + }; + + static const unsigned char epout2idx[]={ + PDI_EP0_OUT, + PDI_EP1_OUT, + #if PDI_CNT_EP > 1 + PDI_EP2_OUT, + #if PDI_CNT_EP > 2 + PDI_EP3_OUT, + #endif + #endif + }; + + // pdiEp2Idx + // convert endpoint number to pdi index number + unsigned char pdiEp2Idx(unsigned char ep) { + if(ep & USB_ENDPOINT_DIRECTION_MASK) + return epin2idx[ep & 0xf]; + else + return epout2idx[ep & 0xf]; + } + + /*********************************************************/ + /*********************************************************/ diff --git a/embedded/libs4c/usb/pdiusb/usb/pdi.h b/embedded/libs4c/usb/pdiusb/usb/pdi.h new file mode 100644 index 0000000..3493c00 --- /dev/null +++ b/embedded/libs4c/usb/pdiusb/usb/pdi.h @@ -0,0 +1,55 @@ +/*****************************************************/ +/*** Module : USB PDI - header file ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002, 16.04.2003 ***/ +/*****************************************************/ + +#ifndef _USB_PDI_SUBMODULE_HEADER_FILE_ + #define _USB_PDI_SUBMODULE_HEADER_FILE_ + + #include + +// int usb_pdi_init( usb_device_t *udev) REENTRANT_SIGN; + int usb_pdi_init( usb_device_t *udev); + + #ifdef USB_PDI_DIRECT_FNC + #define USB_PDI_EXPORT_FNC + + #define usb_udev_is_fnc(_M_udev, _M_fnc) (1) + + #define usb_udev_init usb_pdi_init + #define usb_udev_set_addr usb_pdi_set_addr + #define usb_udev_set_configuration usb_pdi_set_configuration + #define usb_udev_connect usb_pdi_connect + #define usb_udev_disconnect usb_pdi_disconnect + #define usb_udev_ack_setup usb_pdi_ack_setup + #define usb_udev_ack_control_setup usb_pdi_ack_control_setup + #define usb_udev_check_events usb_pdi_check_events + + #define usb_udev_stall usb_pdi_stall + #define usb_udev_unstall usb_pdi_unstall + #define usb_udev_read_endpoint usb_pdi_read_endpoint + #define usb_udev_write_endpoint usb_pdi_write_endpoint + + #endif /*USB_PDI_DIRECT_FNC*/ + + #ifdef USB_PDI_EXPORT_FNC + + int usb_pdi_init( usb_device_t *udev); + int usb_pdi_set_addr( usb_device_t *udev, unsigned char addr); + int usb_pdi_set_configuration( usb_device_t *udev, unsigned char iCfg); + int usb_pdi_connect( usb_device_t *udev); + int usb_pdi_disconnect( usb_device_t *udev); + void usb_pdi_ack_setup( usb_device_t *udev); + void usb_pdi_ack_control_setup( usb_device_t *udev); + int usb_pdi_check_events( usb_device_t *udev); + + void usb_pdi_stall( usb_ep_t *ep); + void usb_pdi_unstall( usb_ep_t *ep); + int usb_pdi_read_endpoint( usb_ep_t *ep, void *ptr, int size) USB_UDEV_REENTRANT_SIGN; + int usb_pdi_write_endpoint( usb_ep_t *ep, const void *ptr, int size) USB_UDEV_REENTRANT_SIGN; + + #endif /*USB_PDI_EXPORT_FNC*/ + +#endif /* _USB_PDI_SUBMODULE_HEADER_FILE_ */ + diff --git a/embedded/libs4c/usb/pdiusb/usb/pdiusb.h b/embedded/libs4c/usb/pdiusb/usb/pdiusb.h new file mode 100644 index 0000000..14ce3ab --- /dev/null +++ b/embedded/libs4c/usb/pdiusb/usb/pdiusb.h @@ -0,0 +1,674 @@ +/*********************************************************/ +/*** Module : PDIUSB D11,H11,H11A,D12 - header file ***/ +/*** Author : Roman Bartosinski (C) 03.10.2002 ***/ +/*** Description : Integrate common functions for ***/ +/*** PDIUSBD11,PDIUSBD12,PDIUSBH11(old) ***/ +/*** PDIUSBH11A in Single/Multiple mode ***/ +/*** to one common file. ***/ +/*** Modify : 10.10.2002 - add H11 ***/ +/*** 13.10.2002 - add spec.fnc for 'using' ***/ +/*** 22.12.2002 - rebuild for smaller out ***/ +/*********************************************************/ + +#ifndef _PDIUSB_BASE_MODULE + #define _PDIUSB_BASE_MODULE + +/*********************************************************/ +// Comments - !!! Please, read this section !!! +// +// +// If you can use included functions for read and write +// byte from/to PDIUSB, please uncomment defined PDI_CMD_RWD_INTERNAL +// and check defined addresses for communication with PDIUSB. +// Else you must uncomment defined PDI_CMD_RWD_EXTERNAL and declare +// and implement next functions : +// void pdiSendCommand( unsigned char byCmd); +// unsigned char pdiReadData( unsigned char byCount, void *pbyData); +// void pdiWriteData( unsigned char byCount, const void *pbyData); +// - if you want use 'using' (see below), you must implement next function(on i51 is NEEDED). +// unsigned short pdiIntCmdReadData( unsigned char byCmd, unsigned char byShort) _PDI_USING; +// -- all in section 'External functions' +// +// +// Next you must select type of chip.(uncomment line with defined type) +// -- in section 'Type of PDIUSB' +// +// +// If you want use functions 'pdiGetInterrupt' and 'pdiGetLastTransStatus' +// with keyword 'using' (for i51 it means using spec.reg.bank), uncomment +// define 'USING'. Only these two functions need pdiIntCmdReadData. +// -- in section 'Use using in interrupt functions' +// +// *** External choice *** +// Or you can make all previous choises externally before including this file +// by defining one of PDIUSBD11,PDIUSBD12,PDIUSBH11,PDIUSBH11A_SINGLE,PDIUSBH11A_MULTIPLE +// +// defining one of PDI_CMD_RWD_INTERNAL,PDI_CMD_RWD_EXTERNAL +// (you can define externally PDIUSB_COMMAND_ADDR, PDIUSB_READ_DATA_ADDR, PDIUSB_WRITE_DATA_ADDR) +// +// and defining one of PDI_USE_USING,PDI_DONTUSE_USING +// (you can define externally _PDI_USING_NUMBER) + + + +/*********************************************************/ +// Type of PDIUSB + + +// +// PDIUSBD11 - USB device with serial interface +// PDIUSBH11 - USB hub with one embedded fnc and serial interface +// PDIUSBH11A_SINGLE - USB hub with one embedded fnc, serial interface and additional functions +// PDIUSBH11A_MULTIPLE - USB hub with multiple(3) embedded fncs, serial interface and add.fncs +// - H11A_SINGLE and H11A_MULTIPLE is divided by pdiusb command SetMode (bit is set automatically) +// PDIUSBD12 - USB device with parallel interface +// + +// uncomment right chip type below + +#define PDIUSBD11 +//#define PDIUSBH11 +//#define PDIUSBH11A_SINGLE +//#define PDIUSBH11A_MULTIPLE +//#define PDIUSBD12 + + +/*********************************************************/ +// Create common type PDIUSBH11A for SINGLE and MULTIPLE +// for mux H11A_S & H11A_M +#if defined(PDIUSBH11A_SINGLE) || defined(PDIUSBH11A_MULTIPLE) + #define PDIUSBH11A +#else + #undef PDIUSBH11A +#endif + + + +/*********************************************************/ +// Use using in interrupt functions + + // If you want use keyword 'using' in function + // 'pdiGetInterrupt' and 'pdiGetLastTransStatus', + // uncomment next line.(and check and correct number in _PDI_USING_NUMBER) +//#define PDI_USE_USING + // If you don't want use keyword 'using', + // uncomment next line. +#define PDI_DONTUSE_USING + + #if defined(PDI_USE_USING) + #if !defined(_PDI_USING_NUMBER) + #define _PDI_USING_NUMBER 2 + #endif + #define _PDI_USING using _PDI_USING_NUMBER + #else + #define _PDI_USING + #endif + + +/*********************************************************/ +// External functions + + // If you want use internal functions, uncomment next line. +//#define PDI_CMD_RWD_INTERNAL + // If you want use your own external functions, uncomment next line. +//#define PDI_CMD_RWD_EXTERNAL + +// this is automatically selected by your choice + + #if defined(PDI_CMD_RWD_INTERNAL) + #if !defined(PDIUSB_COMMAND_ADDR) // if not defined address for select command + #if defined(PDIUSBD12) + #define PDIUSB_COMMAND_ADDR 0x7001 // sel.cmd address for D12 (this is address for my application) + #else + #define PDIUSB_COMMAND_ADDR 0x36 // sel.cmd address for all other + #endif + #endif + #if !defined(PDIUSB_READ_DATA_ADDR) // if not defined address for read data from chip + #if defined(PDIUSBD12) + #define PDIUSB_READ_DATA_ADDR 0x7000 // read data address for D12 + #else + #define PDIUSB_READ_DATA_ADDR 0x35 // read data address for all other + #endif + #endif + #if !defined(PDIUSB_WRITE_DATA_ADDR) // if not defined address for write data to chip + #if defined(PDIUSBD12) + #define PDIUSB_WRITE_DATA_ADDR 0x7000 // write data address for D12 + #else + #define PDIUSB_WRITE_DATA_ADDR 0x34 // write data address for all other + #endif + #endif + + #endif + +/* Build internal version of functions, but do not define addresses */ +#define PDI_CMD_RWD_INTERNAL + + extern void pdiSendCommand( unsigned char byCmd); + extern unsigned char pdiReadData( unsigned char byCount, void *pbyData); + extern void pdiWriteData( unsigned char byCount, const void *pbyData); +#if defined(PDI_USE_USING) + extern unsigned short pdiIntCmdReadData( unsigned char byCmd, unsigned char byShort) _PDI_USING; +#endif + + +/*********************************************************/ +// Check chip selection, int/ext rw functions, using + +#if !defined(PDIUSBD11) && !defined(PDIUSBH11) && !defined(PDIUSBH11A) && !defined(PDIUSBD12) + #define _PDI_ERROR_NO_CONTINUE + #error "!!! Any type of PDIUSB wasn't selected !!!" + #error "Please select one of PDIUSB in file pdiusb.h in section 'Type of PDIUSB'." +#endif +#if !defined(PDI_CMD_RWD_INTERNAL) && !defined(PDI_CMD_RWD_EXTERNAL) + #define _PDI_ERROR_NO_CONTINUE + #error "!!! You must select if you want use internal or external basic fncs for PDIUSB !!!" + #error "Please select your choice in file pdiusb.h in section 'External functions'." +#endif +#if !defined(PDI_USE_USING) && !defined(PDI_DONTUSE_USING) + #define _PDI_ERROR_NO_CONTINUE + #error "!!! You must choose if you want keyword 'using' !!!" + #error "Please see into file pdiusb.h in section 'Use using in interrupt functions'." +#endif + +#if defined(_PDI_ERROR_NO_CONTINUE) + #error " For help ... read in file pdiusb.h section 'Comments'." +#endif + + +/*********************************************************/ +/*********************************************************/ +#if !defined(_PDI_ERROR_NO_CONTINUE) + +/*********************************************************/ +// Endpoints - size and index defines + + // PDI_CNT_EP - number of endpoints without control endpoints +#if defined(PDIUSBD11) || defined(PDIUSBH11A_SINGLE) // D11, H11A_S + #define PDI_CNT_EP 0x03 +#elif defined(PDIUSBH11) || defined(PDIUSBH11A_MULTIPLE) // H11, H11A_M + #define PDI_CNT_EP 0x01 +#elif defined(PDIUSBD12) // D12 + #define PDI_CNT_EP 0x02 +#endif + + // PDI_EPx_yyyy_SIZE - max packet size for endpoint x +#if defined(PDIUSBH11) || defined(PDIUSBH11A) // H11, H11A + #define PDI_HUB_TX_SIZE 8 + #define PDI_HUB_RX_SIZE 8 + #define PDI_HUB_PACKET_SIZE 8 + #if defined(PDIUSBH11) + #define PDI_HUB_INT_SIZE 1 + #endif +#endif + + +#if !defined(PDIUSBD12) // D11,H11,H11A + #define PDI_EP0_TX_SIZE 8 + #define PDI_EP0_RX_SIZE 8 + #define PDI_EP0_PACKET_SIZE 8 + #define PDI_EP1_TX_SIZE 8 + #define PDI_EP1_RX_SIZE 8 + #define PDI_EP1_PACKET_SIZE 8 + #if defined(PDIUSBD11) || defined(PDIUSBH11A_SINGLE) + #define PDI_EP2_TX_SIZE 8 + #define PDI_EP2_RX_SIZE 8 + #define PDI_EP2_PACKET_SIZE 8 + #define PDI_EP3_TX_SIZE 8 + #define PDI_EP3_RX_SIZE 8 + #define PDI_EP3_PACKET_SIZE 8 + #endif +#else // D12 + #define PDI_EP0_TX_SIZE 16 + #define PDI_EP0_RX_SIZE 16 + #define PDI_EP0_PACKET_SIZE 16 + #define PDI_EP1_TX_SIZE 16 + #define PDI_EP1_RX_SIZE 16 + #define PDI_EP1_PACKET_SIZE 16 + #define PDI_EP2_TX_SIZE 64 + #define PDI_EP2_RX_SIZE 64 + #define PDI_EP2_PACKET_SIZE 64 +#endif + + // PDI_EPx_TX, PDI_EPx_RX - index for endpoint x (write/read) +#if defined(PDIUSBH11) || defined(PDIUSBH11A) // H11 + #define PDI_HUB_EP0_RX 0 + #define PDI_HUB_EP0_TX 1 + // another index names + #define PDI_HUB_EP0_OUT PDI_HUB_EP0_RX + #define PDI_HUB_EP0_IN PDI_HUB_EP0_TX +#endif + +#if defined(PDIUSBH11) + #define PDI_EP0_RX 2 + #define PDI_EP0_TX 3 + #define PDI_EP1_TX 4 + // another index names + #define PDI_EP0_OUT PDI_EP0_RX + #define PDI_EP0_IN PDI_EP0_TX + #define PDI_EP1_IN PDI_EP1_TX +#elif defined(PDIUSBD11) || defined(PDIUSBH11A_SINGLE) // D11,H11A_S + #define PDI_EP0_RX 2 + #define PDI_EP0_TX 3 + #define PDI_EP1_RX 5 + #define PDI_EP1_TX 4 + #define PDI_EP2_RX 6 + #define PDI_EP2_TX 7 + #define PDI_EP3_RX 8 + #define PDI_EP3_TX 9 + // another index names + #define PDI_EP0_OUT PDI_EP0_RX + #define PDI_EP0_IN PDI_EP0_TX + #define PDI_EP1_OUT PDI_EP1_RX + #define PDI_EP1_IN PDI_EP1_TX + #define PDI_EP2_OUT PDI_EP2_RX + #define PDI_EP2_IN PDI_EP2_TX + #define PDI_EP3_OUT PDI_EP3_RX + #define PDI_EP3_IN PDI_EP3_TX +#elif defined(PDIUSBH11A_MULTIPLE) // H11_M + #define PDI_F1_EP0_RX 2 + #define PDI_F1_EP0_TX 3 + #define PDI_F1_EP1_RX 5 + #define PDI_F1_EP1_TX 4 + #define PDI_F6_EP0_RX 10 + #define PDI_F6_EP0_TX 11 + #define PDI_F6_EP1_RX 6 + #define PDI_F6_EP1_TX 7 + #define PDI_F7_EP0_RX 12 + #define PDI_F7_EP0_TX 13 + #define PDI_F7_EP1_RX 8 + #define PDI_F7_EP1_TX 9 + // another index names + #define PDI_F1_EP0_OUT PDI_F1_EP0_RX + #define PDI_F1_EP0_IN PDI_F1_EP0_TX + #define PDI_F1_EP1_OUT PDI_F1_EP1_RX + #define PDI_F1_EP1_IN PDI_F1_EP1_TX + #define PDI_F6_EP0_OUT PDI_F6_EP0_RX + #define PDI_F6_EP0_IN PDI_F6_EP0_TX + #define PDI_F6_EP1_OUT PDI_F6_EP1_RX + #define PDI_F6_EP1_IN PDI_F6_EP1_TX + #define PDI_F7_EP0_OUT PDI_F7_EP0_RX + #define PDI_F7_EP0_IN PDI_F7_EP0_TX + #define PDI_F7_EP1_OUT PDI_F7_EP1_RX + #define PDI_F7_EP1_IN PDI_F7_EP1_TX +#elif defined(PDIUSBD12) // D12 + #define PDI_EP0_RX 0 + #define PDI_EP0_TX 1 + #define PDI_EP1_RX 2 + #define PDI_EP1_TX 3 + #define PDI_EP2_RX 4 + #define PDI_EP2_TX 5 + // another index names + #define PDI_EP0_OUT PDI_EP0_RX + #define PDI_EP0_IN PDI_EP0_TX + #define PDI_EP1_OUT PDI_EP1_RX + #define PDI_EP1_IN PDI_EP1_TX + #define PDI_EP2_OUT PDI_EP2_RX + #define PDI_EP2_IN PDI_EP2_TX +#endif + +/*********************************************************/ +// Commands - index and bits, description + + // Set Address/Enable +#if defined(PDIUSBH11) || defined(PDIUSBH11A) || defined(PDIUSBD11) // only H11 or H11A + #define PDI_CMD_HUB_ENB_ADDR 0x00D0 + #if defined(PDIUSBH11) || defined(PDIUSBH11A_SINGLE) // for H11 and H11A_SINGLE + #define PDI_CMD_FNC_ENB_ADDR 0x00D1 + #else // for H11A_MULTIPLE + #define PDI_CMD_FNC1_ENB_ADDR 0x00D1 + #define PDI_CMD_FNC6_ENB_ADDR 0x00D2 + #define PDI_CMD_FNC7_ENB_ADDR 0x00D3 +// for compatible with H11A_SINGLE and other + #define PDI_CMD_FNC_ENB_ADDR PDI_CMD_FNC1_ENB_ADDR + #endif +#elif defined(PDIUSBD11) // for D11 + #define PDI_CMD_FNC_ENB_ADDR 0x00D1 +#elif defined(PDIUSBD12) // for D12 + #define PDI_CMD_FNC_ENB_ADDR 0x00D0 +#endif + // set address/enable bits - for all + #define PDI_ENAD_ENABLE 0x0080 + #define PDI_ENAD_ADDRMASK 0x007F + + // Set Endpoint enable + #define PDI_CMD_EPEN 0x00D8 + // set endpoint enable bits + #if defined(PDIUSBD12) // D12 - generic ep + #define PDI_EPEN_ENABLE 0x0001 + #elif defined(PDIUSBD11) // D11 - generic ep + #define PDI_EPEN_ENABLE 0x0002 + #elif defined(PDIUSBH11A) || defined(PDIUSBH11) // H11,H11A + #define PDI_EPEN_HUB_ENB 0x0001 + #if defined(PDIUSBH11A_MULTIPLE) // H11A_M + #define PDI_EPEN_FNC1_ENB 0x0002 + #define PDI_EPEN_FNC6_ENB 0x0004 + #define PDI_EPEN_FNC7_ENB 0x0008 + #else // H11,H11A_S + #define PDI_EPEN_FNC_ENB 0x0002 + #endif + #endif + + #if !defined(PDIUSBH11) + // Set Mode + #define PDI_CMD_SET_MODE 0x00F3 + // set mode bits - configuration + #if !defined(PDIUSBD12) + #define PDI_MODE_REMOTE_WAKEUP 0x0001 // D11,H11A + #endif + #define PDI_MODE_NO_LAZY_CLOCK 0x0002 // all + #define PDI_MODE_CLOCK_RUNNING 0x0004 // all + #if defined(PDIUSBD12) + #define PDI_MODE_INTERRUPT_MODE 0x0008 // D12 + #else + #define PDI_MODE_DEBUG_MODE 0x0008 // D11,H11A + #endif + #define PDI_MODE_SOFT_CONNECT 0x0010 // all + #if defined(PDIUSBH11A) + #define PDI_MODE_DWN_RESISTORS 0x0020 // H11A + #define PDI_MODE_NONBLINK_LED 0x0040 // H11A + #define PDI_MODE_SINGLE_FNC 0x0080 // H11A + #elif defined(PDIUSBD11) + #define PDI_MODE_MUSTBEONE 0x0080 // D11 + #else + #define PDI_MODE_EP_NONISO 0x0000 // D12 + #define PDI_MODE_EP_ISOOUT 0x0040 + #define PDI_MODE_EP_ISOIN 0x0080 + #define PDI_MODE_EP_ISOIO 0x00C0 + + #endif + // set mode bits - clock div factor [48Mhz/(N+1)] + #if defined(PDIUSBH11A) + #define PDI_CLOCK_CRYSTAL_12M 0x3000 // for 12Mhz crystal + #define PDI_CLOCK_CRYSTAL_48M 0x0000 // for 48Mhz crystal + #endif + #if defined(PDIUSBD12) // D12 + #define PDI_CLOCK_48M 0x0000 // 48 Mhz + #endif // all + #define PDI_CLOCK_24M 0x0100 // 24 Mhz + #define PDI_CLOCK_16M 0x0200 // 16 Mhz + #define PDI_CLOCK_12M 0x0300 // 12 Mhz + #define PDI_CLOCK_9M6 0x0400 // 9.6 Mhz + #define PDI_CLOCK_8M 0x0500 // 8 Mhz + #define PDI_CLOCK_6M8 0x0600 // 6.857142857 Mhz + #define PDI_CLOCK_6M 0x0700 // 6 Mhz + #define PDI_CLOCK_5M3 0x0800 // 5.333333333 Mhz + #define PDI_CLOCK_4M8 0x0900 // 4.8 Mhz + #define PDI_CLOCK_4M3 0x0A00 // 4.363636364 Mhz + #define PDI_CLOCK_4M 0x0B00 // 4 Mhz + #if defined(PDIUSBD12) // D12 + #define PDI_CLOCK_SET_TO_ONE 0x4000 + #define PDI_CLOCK_SOF_ONLY 0x8000 + #endif + #endif + + // Set DMA + #if defined(PDIUSBD12) + #define PDI_CMD_SET_DMA 0x00FB + #define PDI_CMD_GET_DMA 0x00FB + // set dma bits + #define PDI_DMA_SINGLE_DMA 0x0000 + #define PDI_DMA_BURST_4 0x0001 + #define PDI_DMA_BURST_8 0x0002 + #define PDI_DMA_BURST_16 0x0003 + #define PDI_DMA_ENABLE 0x0004 + #define PDI_DMA_DIRECTION 0x0008 + #define PDI_DMA_AUTOLOAD 0x0010 + #define PDI_DMA_INT_SOF 0x0020 + #define PDI_DMA_EP4_INT 0x0040 + #define PDI_DMA_EP5_INT 0x0080 + #endif + + // Read Interrupt Register + // be careful with PDIUSBH11 - you must read only 1 byte + #define PDI_CMD_GET_INT_REG 0x00F4 + // read interrupt register bits + #if defined(PDIUSBD11) || defined(PDIUSBH11) || defined(PDIUSBH11A) // D11,H11,H11A + #if defined(PDIUSBH11) || defined(PDIUSBH11A) + #define PDI_INT_HUB_OUT 0x0001 + #define PDI_INT_HUB_IN 0x0002 + #endif + #if defined(PDIUSBH11) + #define PDI_INT_EP0_OUT 0x0004 + #define PDI_INT_EP0_IN 0x0008 + #define PDI_INT_EP1_IN 0x0010 + #elif defined(PDIUSBD11) || defined(PDIUSBH11A_SINGLE) // D11,H11_S + #define PDI_INT_EP0_OUT 0x0004 + #define PDI_INT_EP0_IN 0x0008 + #define PDI_INT_EP1_OUT 0x0020 + #define PDI_INT_EP1_IN 0x0010 + #define PDI_INT_EP2_OUT 0x0040 + #define PDI_INT_EP2_IN 0x0080 + #define PDI_INT_EP3_OUT 0x0100 + #define PDI_INT_EP3_IN 0x0200 + #else // H11_M + #define PDI_INT_F1_EP0_OUT 0x0004 + #define PDI_INT_F1_EP0_IN 0x0008 + #define PDI_INT_F1_EP1_OUT 0x0020 + #define PDI_INT_F1_EP1_IN 0x0010 + #define PDI_INT_F6_EP0_OUT 0x0400 + #define PDI_INT_F6_EP0_IN 0x0800 + + #define PDI_INT_F6_EP1_OUT 0x0040 + #define PDI_INT_F6_EP1_IN 0x0080 + #define PDI_INT_F7_EP0_OUT 0x1000 + #define PDI_INT_F7_EP0_IN 0x2000 + #define PDI_INT_F7_EP1_OUT 0x0100 + #define PDI_INT_F7_EP1_IN 0x0200 + #endif + #define PDI_INT_BUSRESET 0x4000 + #elif defined(PDIUSBD12) + #define PDI_INT_EP0_OUT 0x0001 + #define PDI_INT_EP0_IN 0x0002 + #define PDI_INT_EP1_OUT 0x0004 + #define PDI_INT_EP1_IN 0x0008 + #define PDI_INT_EP2_OUT 0x0010 + #define PDI_INT_EP2_IN 0x0020 + #define PDI_INT_BUSRESET 0x0040 + #define PDI_INT_SUSPEND 0x0080 + #define PDI_INT_DMA_EOT 0x0100 + #endif + + // Select Endpoint + #define PDI_CMD_SELECT_EP 0x0000 // base index for select endpoint + // select endpoint bits + #define PDI_SELEP_FULL 0x0001 + #if defined(PDIUSBD12) + #define PDI_SELEP_STALL 0x0002 + #endif + + // Read Last Transaction Status Register + #define PDI_CMD_GET_LAST_STAT 0x0040 // base index for read last transaction + // read last transaction bits and errors + #define PDI_LTSTAT_RXTX_OK 0x0001 + #define PDI_LTSTAT_ERR_MASK 0x001E + #define PDI_LTSTAT_SETUP 0x0020 + #define PDI_LTSTAT_DATA1 0x0040 + #define PDI_LTSTAT_PREV_NRD 0x0080 + // error codes + #define PDI_ERR_NO_ERROR 0x0000 + #define PDI_ERR_PID_ENCODING 0x0001 + #define PDI_ERR_PID_UNKNOWN 0x0002 + #define PDI_ERR_UNEXPECT_PKT 0x0003 + + #define PDI_ERR_TOKEN_CRC 0x0004 + #define PDI_ERR_DATA_CRC 0x0005 + #define PDI_ERR_TIME_OUT 0x0006 + #define PDI_ERR_NEVER_HAPPENS 0x0007 + #define PDI_ERR_UNEXPECT_EOP 0x0008 + #define PDI_ERR_NAK 0x0009 + #define PDI_ERR_STALL 0x000A + #define PDI_ERR_OVERFLOW 0x000B + #define PDI_ERR_BITSTUFF 0x000D + #define PDI_ERR_DATA_PID 0x000F + + // Read Endpoint Status + #if defined(PDIUSBD11) || defined(PDIUSBH11) || defined(PDIUSBH11A) + #define PDI_CMD_GET_EP_STAT 0x0080 // base index for read ep status + // read ep status bits + #define PDI_EPSTAT_SETUP 0x0004 + #define PDI_EPSTAT_STALL 0x0008 + #define PDI_EPSTAT_DATA1 0x0010 + #define PDI_EPSTAT_FULL 0x0020 + #endif + + // Read Buffer + #define PDI_CMD_READ_BUFFER 0x00F0 + + // Write Buffer + #define PDI_CMD_WRITE_BUFFER 0x00F0 + + // Clear Buffer + #define PDI_CMD_CLEAR_BUFFER 0x00F2 + + // Validate Buffer + #define PDI_CMD_VALID_BUFFER 0x00FA + + + // Set Endpoint Status + #define PDI_CMD_SET_EP_STAT 0x0040 // base index for endpoint status + // set endpoint status bits + #define PDI_SET_EP_STALLED 0x0001 + + // Acknowledge Setup + #define PDI_CMD_ACK_SETUP 0x00F1 + + // Send Resume + #define PDI_CMD_SEND_RESUME 0x00F6 + + // Read Current Frame Number + #define PDI_CMD_GET_FRAME 0x00F5 + + // Get Chip ID + #define PDI_CMD_GET_CHIP_ID 0x00FD + +// HUB commands +#if defined(PDIUSBH11) || defined(PDIUSBH11A) + // Clear Port Feature + #define PDI_CMD_P2_CLR_FEATURE 0x00E0 + #define PDI_CMD_P3_CLR_FEATURE 0x00E1 + #define PDI_CMD_P4_CLR_FEATURE 0x00E2 + #define PDI_CMD_P5_CLR_FEATURE 0x00E3 + // Set Port Feature + #define PDI_CMD_P2_SET_FEATURE 0x00E8 + #define PDI_CMD_P3_SET_FEATURE 0x00E9 + #define PDI_CMD_P4_SET_FEATURE 0x00EA + #define PDI_CMD_P5_SET_FEATURE 0x00EB + // Feature code + #define PDI_F_PORT_ENABLE 0 + #define PDI_F_PORT_SUSPEND 1 + #define PDI_FC_PORT_RESET 2 + #define PDI_F_PORT_POWER 3 + #define PDI_C_PORT_CONNECTION 4 + #define PDI_C_PORT_ENABLE 5 + #define PDI_C_PORT_SUSPEND 6 + #define PDI_C_PORT_OVERCURRENT 7 + + // Get Port Status + #define PDI_CMD_P2_GET_STATUS 0x00E0 + #define PDI_CMD_P3_GET_STATUS 0x00E1 + #define PDI_CMD_P4_GET_STATUS 0x00E2 + #define PDI_CMD_P5_GET_STATUS 0x00E3 + // get port status bits - port status byte + #define PDI_PSTAT_CONNECT 0x0001 + #define PDI_PSTAT_ENABLED 0x0002 + #define PDI_PSTAT_SUSPEND 0x0004 + #define PDI_PSTAT_OVERCUR 0x0008 + #define PDI_PSTAT_RESET 0x0010 + #define PDI_PSTAT_POWER 0x0020 + #define PDI_PSTAT_LOWSPEED 0x0040 + // get port status bits - port status change byte + #define PDI_PSTAT_CHANGE_CONNECT 0x0100 + #define PDI_PSTAT_CHANGE_ENABLED 0x0200 + #define PDI_PSTAT_CHANGE_SUSPEND 0x0400 + #define PDI_PSTAT_CHANGE_OVERCUR 0x0800 + #define PDI_PSTAT_CHANGE_RESET 0x1000 + // Set Status Change Bits + #define PDI_CMD_SET_CHNG_BITS 0x00F7 + // set status change bits - bits + #define PDI_SCHB_LOCAL_POWER 0x0001 + #define PDI_SCHB_FNC1 0x0002 + #if !defined(PDIUSBH11) && !defined(PDIUSBH11A_SINGLE) + #define PDI_SCHB_FNC6 0x0004 + #define PDI_SCHB_FNC7 0x0008 + #endif +#endif + + +/*********************************************************/ +// Function prototypes +// +// PDIUSB common commands + + #if defined(PDIUSBH11) || defined(PDIUSBH11A) || defined(PDIUSBD11) + void pdiSetHUBAddressEnable( unsigned char byAddress, unsigned char byEnable); + #endif + + #if !defined(PDIUSBH11A_MULTIPLE) // D11,D12,H11,H11A_S(emb.fnc) + void pdiSetAddressEnable( unsigned char byAddr_Enb); +// void pdiSetAddressEnable( unsigned char byAddress, unsigned char byEnable); + #else + void pdiSetEmbFncAddressEnable( unsigned char byFnc, unsigned char byAddress, unsigned char byEnable); + #endif + + void pdiSetEndpointEnable( unsigned char byEnable); + + #if !defined(PDIUSBH11) // H11 has not it ( !!! is great - try give single quote mark into comments ;-) + void pdiSetMode( unsigned short wMode_Clock); + #endif + + #if defined(PDIUSBD12) + void pdiSetDMA( unsigned char byDma); + unsigned char pdiGetDMA( void); + #endif + + #if defined(PDIUSBH11) + unsigned char pdiGetInterrupt( void) _PDI_USING; + #else + unsigned short pdiGetInterrupt( void) _PDI_USING; + #endif + + unsigned char pdiSelectEp( unsigned char byEpIdx); + unsigned char pdiGetLastTransStatus( unsigned char byEpIdx) _PDI_USING; + + #if defined(PDIUSBD11) || defined(PDIUSBH11) || defined(PDIUSBH11A) + unsigned char pdiGetEpStatus( unsigned char byEpIdx); + #endif + + unsigned char pdiReadFromEpBuffer( unsigned char byLength, unsigned char *pToBuff); + void pdiWriteToEpBuffer( unsigned char byLength, const unsigned char *pFromBuff); + void pdiSetEpStatus( unsigned char byEpIdx, unsigned char byStatus); + void pdiAcknowledgeSetup( void); + void pdiClearBuffer( void); + void pdiValidateBuffer( void); + + void pdiSendResume( void); + unsigned short pdiGetFrameNumber( void); + unsigned short pdiGetChipID( void); // this function is undocumented + + // HUB command + #if defined(PDIUSBH11) || defined(PDIUSBH11A) + void pdiClearPortFeature( unsigned char byEpIdx, unsigned char byFeature); + void pdiSetPortFeature( unsigned char byEpIdx, unsigned char byFeature); + unsigned short pdiGetPortFeature( unsigned char byEpIdx); + void pdiSetStatusChangeBits( unsigned char byBits); + #endif + +// PDIUSB other commands + void pdiWriteEndpoint( unsigned char byEpIdx, unsigned char byLength, const unsigned char *pbyData); + unsigned char pdiReadEndpoint( unsigned char byEpIdx, unsigned char byMaxLength, unsigned char *pbyData); + + unsigned char pdiCmdData( unsigned char byCmd, unsigned char *pbyData, + unsigned char byCount, unsigned char byRead); + void pdiInit( void); +#if !defined(PDIUSBH11A_MULTIPLE) + void pdiAckSetupControl( void); +#else + void pdiAckSetupFncControl( unsigned char Fnc); +#endif + +unsigned char pdiEp2Idx(unsigned char ep); + +/*********************************************************/ +#endif // from _PDI_ERROR_NO_CONTINUE +/*********************************************************/ +#endif // from _PDI_BASE_MODULE diff --git a/lincan/include/can_sysdep.h b/lincan/include/can_sysdep.h index 77f9d8a..b4ffff5 100644 --- a/lincan/include/can_sysdep.h +++ b/lincan/include/can_sysdep.h @@ -263,4 +263,20 @@ extern can_spinlock_t can_irq_manipulation_lock; #endif /*CAN_WITH_RTL*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4)) + #include + #define can_kthread_create kthread_create + #define can_kthread_run kthread_run + #define can_kthread_bind kthread_bind + #define can_kthread_stop kthread_stop + #define can_kthread_should_stop kthread_should_stop +#else + #define can_kthread_create + #define can_kthread_run + #define can_kthread_bind + #define can_kthread_stop + #define can_kthread_should_stop +#endif + + #endif /*_CAN_SYSDEP_H*/ diff --git a/lincan/include/main.h b/lincan/include/main.h index 651d0c2..f360dcf 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -512,3 +512,6 @@ void can_filltimestamp(canmsg_tstamp_t *ptimestamp) #ifdef CAN_WITH_RTL extern int can_rtl_priority; #endif /*CAN_WITH_RTL*/ + +extern struct candevice_t* register_usbdev(const char *hwname,void *devdata,void (*chipdataregfnc)(struct canchip_t *chip,void *data)); +extern void cleanup_usbdev(struct candevice_t *dev); diff --git a/lincan/include/proc.h b/lincan/include/proc.h index a89f45a..504b58a 100644 --- a/lincan/include/proc.h +++ b/lincan/include/proc.h @@ -11,7 +11,9 @@ #include "./constants.h" int can_init_procdir(void); +int can_init_procentry(int board); int can_delete_procdir(void); +int can_delete_procentry(struct candevice_t *candev); struct canproc_t { struct proc_dir_entry *can_proc_entry; diff --git a/lincan/include/setup.h b/lincan/include/setup.h index d35a8b1..d07e3fd 100644 --- a/lincan/include/setup.h +++ b/lincan/include/setup.h @@ -8,6 +8,7 @@ */ int init_hw_struct(void); +int init_new_hw_struct(int devnr); int list_hw(void); void *can_checked_malloc(size_t size); int can_checked_free(void *address_p); diff --git a/lincan/include/usbcan.h b/lincan/include/usbcan.h index e69de29..36c3753 100644 --- a/lincan/include/usbcan.h +++ b/lincan/include/usbcan.h @@ -0,0 +1,188 @@ +/* usbcan.h + * Header file for the Linux CAN-bus driver. + * Written by Jan Kriz email:johen@post.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jul 2008 + */ + +#ifndef USBCAN_H +#define USBCAN_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/kthread.h" + +/* our private defines. if this grows any larger, use your own .h file */ +#define MAX_TRANSFER (PAGE_SIZE - 512) +/* MAX_TRANSFER is chosen so that the VM is not stressed by + allocations > PAGE_SIZE and the number of packets in a page + is an integer 512 is the largest possible packet on EHCI */ +#define WRITES_IN_FLIGHT 8 +/* arbitrarily chosen */ + +/* Define these values to match your devices */ +#define USBCAN_VENDOR_ID 0x1669 +#define USBCAN_PRODUCT_ID 0x1011 + +#define RESET_ADDR 0x0 + +/* + * IO_RANGE is the io-memory range that gets reserved, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + */ +#define IO_RANGE 0x100 + + +int usbcan_request_io(struct candevice_t *candev); +int usbcan_release_io(struct candevice_t *candev); +int usbcan_reset(struct candevice_t *candev); +int usbcan_init_hw_data(struct candevice_t *candev); +int usbcan_init_chip_data(struct candevice_t *candev, int chipnr); +int usbcan_init_obj_data(struct canchip_t *chip, int objnr); +void usbcan_write_register(unsigned data, unsigned long address); +unsigned usbcan_read_register(unsigned long address); +int usbcan_program_irq(struct candevice_t *candev); +int usbcan_register(struct hwspecops_t *hwspecops); + +int usbcan_chip_config(struct canchip_t *chip); +int usbcan_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask); +int usbcan_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, + int sampl_pt, int flags); +int usbcan_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj); +int usbcan_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); +int usbcan_send_msg(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg); +int usbcan_fill_chipspecops(struct canchip_t *chip); +int usbcan_irq_handler(int irq, struct canchip_t *chip); + +int usbcan_init(void); +void usbcan_exit(void); + +int usbcan_kthread(void *data); +int usbcan_chip_queue_status(struct canchip_t *chip); + +#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS + +// static const char *sja1000_ecc_errc_str[]={ +// "bit error", +// "form error", +// "stuff error", +// "other type of error" +// }; +// +// static const char *sja1000_ecc_seg_str[]={ +// "?0?", +// "?1?", +// "ID.28 to ID.21", +// "start of frame", +// "bit SRTR", +// "bit IDE", +// "ID.20 to ID.18", +// "ID.17 to ID.13", +// "CRC sequence", +// "reserved bit 0", +// "data field", +// "data length code", +// "bit RTR", +// "reserved bit 1", +// "ID.4 to ID.0", +// "ID.12 to ID.5", +// "?16?" +// "active error flag", +// "intermission", +// "tolerate dominant bits", +// "?20?", +// "?21?", +// "passive error flag", +// "error delimiter", +// "CRC delimiter", +// "acknowledge slot", +// "end of frame", +// "acknowledge delimiter", +// "overload flag", +// "?29?", +// "?30?", +// "?31?" +// }; + +#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/ + +struct usbcan_usb; + +#define USBCAN_TOT_RX_URBS 8 +#define USBCAN_TOT_TX_URBS 8 + +#define USBCAN_TRANSFER_SIZE 16 + +struct usbcan_message { + struct urb *u; + struct usbcan_usb *dev; + u8 msg[USBCAN_TRANSFER_SIZE]; + spinlock_t acc; /* access lock */ + struct canque_edge_t *qedge; + struct canque_slot_t *slot; + volatile long flags; +}; + +#define USBCAN_MESSAGE_FREE (1) +#define USBCAN_MESSAGE_URB_PENDING (2) +#define USBCAN_MESSAGE_TERMINATE (3) +#define USBCAN_MESSAGE_ERROR (4) +#define USBCAN_MESSAGE_DATA_OK (5) +#define USBCAN_MESSAGE_TYPE_RX (6) +#define USBCAN_MESSAGE_TYPE_TX (7) + +/* Structure to hold all of our device specific stuff */ +struct usbcan_usb { + struct usb_device *udev; /* the usb device for this device */ + struct usb_interface *interface; /* the interface for this device */ + unsigned char *bulk_in_buffer; /* the buffer to receive data */ + size_t bulk_in_size; /* the size of the receive buffer */ + u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ + u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ + struct mutex io_mutex; /* synchronize I/O with disconnect */ + struct usbcan_message rx[USBCAN_TOT_RX_URBS]; + struct usbcan_message tx[USBCAN_TOT_TX_URBS]; + + struct task_struct *comthread; /* usb communication kernel thread */ + wait_queue_head_t queue; + + struct canchip_t *chip; + volatile long flags; +}; + +#define USBCAN_DATA_OK (1) +#define USBCAN_DATA_RX (2) +#define USBCAN_DATA_TX (3) +#define USBCAN_TERMINATE (4) +#define USBCAN_ERROR (5) +#define USBCAN_TX_PENDING (6) +#define USBCAN_THREAD_RUNNING (7) +#define USBCAN_FREE_TX_URB (8) + +#define USBCAN_VENDOR_BAUD_RATE_SET (1) +#define USBCAN_VENDOR_BAUD_RATE_STATUS (2) +#define USBCAN_VENDOR_SET_BTREGS (3) +#define USBCAN_VENDOR_CHECK_TX_STAT (4) +#define USBCAN_VENDOR_START_CHIP (5) +#define USBCAN_VENDOR_STOP_CHIP (6) +#define USBCAN_VENDOR_EXT_MASK_SET (7) +#define USBCAN_VENDOR_EXT_MASK_STATUS (8) + +struct usbcan_devs { + struct usbcan_usb **devs; + int count; + struct candevice_t *candev; +}; + + +#endif /*USBCAN_H*/ diff --git a/lincan/src/Makefile.omk b/lincan/src/Makefile.omk index 8a71a1f..a273b78 100644 --- a/lincan/src/Makefile.omk +++ b/lincan/src/Makefile.omk @@ -1,6 +1,6 @@ lincan_cards_NAMES = pip pccan smartcan nsi cc_can104 ems_cpcpci \ pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan gensja1000io gensja1000mm eb8245 \ - kv_pcican msmcan oscar adlink7841 pcan_pci esdpci200 unican virtual template + kv_pcican msmcan oscar adlink7841 pcan_pci esdpci200 unican usbcan virtual template lincan_morecards_NAMES = esdpci266 hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 ts7kv nsi_canpci sh7760 @@ -37,6 +37,10 @@ ifeq ($(CONFIG_OC_LINCAN_CARD_sh7760),y) lincan_cards_SOURCES += sh7760.c endif +ifeq ($(CONFIG_OC_LINCAN_CARD_usbcan),y) +lincan_cards_SOURCES += kthread.c +endif + ifneq ($(filter hms30c7202_can ns_dev_can,$(lincan_cards_SELECTED)),) $(warning Not finished C_CAN support requested) lincan_cards_SOURCES += c_can.c c_can_irq.c diff --git a/lincan/src/finish.c b/lincan/src/finish.c index d25e936..5e789ae 100644 --- a/lincan/src/finish.c +++ b/lincan/src/finish.c @@ -14,7 +14,7 @@ #include "../include/finish.h" #include "../include/setup.h" - +extern int next_minor; /** * msgobj_done - destroys one CAN message object * @obj: pointer to CAN message object structure @@ -37,8 +37,11 @@ void msgobj_done(struct msgobj_t *obj) } if((obj->minor>=0)) { - if(objects_p[obj->minor] == obj) + if(objects_p[obj->minor] == obj){ objects_p[obj->minor] = NULL; + if (--next_minor<0) + next_minor=0; + } else CANMSG("msgobj_done: not registered as minor\n"); } @@ -127,7 +130,7 @@ void canhardware_done(struct canhardware_t *canhw) int i; struct candevice_t *candev; - for(i=0; inr_boards; i++){ + for(i=0; icandevice[i])==NULL) continue; candevice_done(candev); diff --git a/lincan/src/main.c b/lincan/src/main.c index c0c6d00..b8edf46 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -74,6 +74,10 @@ #include "../include/can_iortl.h" #endif /*CAN_WITH_RTL*/ +#if defined(CONFIG_OC_LINCAN_CARD_usbcan) + #include "../include/usbcan.h" +#endif + can_spinlock_t canuser_manipulation_lock; int major=CAN_MAJOR; @@ -362,6 +366,15 @@ int init_module(void) } } #endif + +#if defined(CONFIG_OC_LINCAN_CARD_usbcan) + res = usbcan_init(); + if (res){ + CANMSG("usb_register for usbcan failed. Error number %d.\n", res); + return -ENODEV; + } +#endif + return 0; #ifdef CONFIG_PROC_FS @@ -400,12 +413,225 @@ int init_module(void) return -ENODEV; } + + + + +struct candevice_t* register_usbdev(const char *hwname,void *devdata,void (*chipdataregfnc)(struct canchip_t *ch,void *data)){ + int i=0, j, board=0; + struct candevice_t *candev; + struct canchip_t *chip; + struct boardtype_t *brp; + + while ( (hw[board] != NULL) && (board < MAX_HW_CARDS) ) + board++; + if (board>=MAX_HW_CARDS){ + CANMSG("Maximum number of devices has been reached, no space for new device"); + return NULL; + } + brp = boardtype_find(hwname); + if(!brp) { + CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",hw[board]); + return NULL; + } + if (board==MAX_HW_CARDS){ + CANMSG("Device \"%s\" could not be registered due to internal limits.\n",hw[board]); + return NULL; + } + hw[board]=brp->boardtype; + + if (init_new_hw_struct(board)) + return NULL; + + #ifdef CAN_DEBUG + list_hw(); + #endif + + candev=hardware_p->candevice[board]; + + /* Adding link to usb device structure into can device */ + candev->sysdevptr.anydev=devdata; + + if (candev->hwspecops->request_io(candev)) + goto request_io_error; + candev->flags|=CANDEV_IO_RESERVED; + + if (candev->hwspecops->reset(candev)) + goto reset_error; + + for(j=0; jnr_all_chips; j++) { + if((chip=candev->chip[j])==NULL) + continue; + + chipdataregfnc(chip,devdata); + + if(chip->chipspecops->attach_to_chip(chip)<0) { + CANMSG("Initial attach to the chip HW failed\n"); + goto interrupt_error; + } + + chip->flags |= CHIP_ATTACHED; + + if(can_chip_setup_irq(chip)<0) { + CANMSG("Error to setup chip IRQ\n"); + goto interrupt_error; + } + } + + if (candev->flags & CANDEV_PROGRAMMABLE_IRQ) + if (candev->hwspecops->program_irq(candev)){ + CANMSG("Error to program board interrupt\n"); + goto interrupt_error; + } + +#ifdef CONFIG_PROC_FS + if (can_init_procentry(board)) + goto proc_error; +#endif + +#if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + { + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0)) + char dev_name[32]; + #else + struct class_device *this_dev; + #endif + int dev_minor; + for(i=0;ihostchip->hostdevice != candev) continue; + + dev_minor=objects_p[i]->minor; + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0)) + sprintf (dev_name, "can%d", dev_minor); + devfs_handles[i]=devfs_register(NULL, dev_name, + DEVFS_FL_DEFAULT, major, dev_minor, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + &can_fops, (void*)objects_p[i]); + #else + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14)) + this_dev=class_device_create(can_class, MKDEV(major, dev_minor), NULL, "can%d", dev_minor); + #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) /* >= 2.6.15 */ + this_dev=class_device_create(can_class, NULL, MKDEV(major, dev_minor), NULL, "can%d", dev_minor); + #else /* >= 2.6.26 */ + this_dev=device_create_drvdata(can_class, NULL, MKDEV(major, dev_minor), objects_p[i], "can%d", dev_minor); + #endif /* >= 2.6.26 */ + if(IS_ERR(this_dev)){ + CANMSG("problem to create device \"can%d\" in the class \"can\"\n", dev_minor); + #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) + }else{ + /*this_dev->class_data=objects_p[i];*/ + class_set_devdata(this_dev,objects_p[i]); + #endif /* <= 2.6.25 */ + } + #ifdef CONFIG_DEVFS_FS + devfs_mk_cdev(MKDEV(major, dev_minor), S_IFCHR | S_IRUGO | S_IWUGO, "can%d", dev_minor); + #endif + #endif + } + } +#endif + return candev; + +#ifdef CONFIG_PROC_FS + proc_error: ; + CANMSG("Error registering /proc entry.\n"); + goto memory_error; +#endif + + interrupt_error: ; + goto memory_error; + + reset_error: ; + CANMSG("Error resetting device.\n"); + goto memory_error; + + request_io_error: ; + CANMSG("Error to request IO resources for device.\n"); + goto memory_error; + + memory_error: ; + + #ifdef CAN_WITH_RTL + rtldev_error: + #endif /*CAN_WITH_RTL*/ + +// register_error: + if ( can_del_mem_list() ) + CANMSG("Error deallocating memory\n"); + + return NULL; +} + + + + + + + +void cleanup_usbdev(struct candevice_t *dev) +{ + int i=0; + int dev_minor; + + if (!dev) + return; + +#ifdef CONFIG_PROC_FS + if (can_delete_procentry(dev)) + CANMSG("Error unregistering /proc/can entry.\n"); +#endif + +#if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + for(i=0;ihostchip->hostdevice != dev) continue; + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0)) + if(devfs_handles[i]) + devfs_unregister(devfs_handles[i]); + #else + dev_minor=objects_p[i]->minor; + if(dev_minor>=0){ + #ifdef CONFIG_DEVFS_FS + devfs_remove("can%d", dev_minor); + #endif + #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) + class_device_destroy(can_class, MKDEV(major, dev_minor)); + #else /* >= 2.6.26 */ + device_destroy(can_class, MKDEV(major, dev_minor)); + #endif /* >= 2.6.26 */ + } + #endif + } +#endif + + for(i=0;ihostdevice != dev) continue; + chips_p[i]=NULL; + } + + hardware_p->candevice[dev->candev_idx]=NULL; + hardware_p->nr_boards--; + hw[dev->candev_idx]=NULL; + + candevice_done(dev); + can_checked_free(dev); +} + + + + void cleanup_module(void) { #if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) int i=0; #endif +#if defined(CONFIG_OC_LINCAN_CARD_usbcan) + usbcan_exit(); +#endif + #ifdef CONFIG_PROC_FS if (can_delete_procdir()) CANMSG("Error unregistering /proc/can entry.\n"); diff --git a/lincan/src/modparms.c b/lincan/src/modparms.c index a0aad04..c53971f 100644 --- a/lincan/src/modparms.c +++ b/lincan/src/modparms.c @@ -19,9 +19,10 @@ int parse_mod_parms(void) const struct boardtype_t *brp; if ( (hw[0] == NULL) | (io[0] == -1) ) { - CANMSG("You must supply your type of hardware, interrupt numbers and io address.\n"); + //CANMSG("You must supply your type of hardware, interrupt numbers and io address.\n"); + CANMSG("Autodetection works only for USB devices, supply your type of hardware for PCI devices \n"); CANMSG("Example: # insmod lincan.ko hw=pip5 irq=4 io=0x8000\n"); - return -ENODEV; + //return -ENODEV; } while ( (hw[i] != NULL) && (i < MAX_HW_CARDS) ) { diff --git a/lincan/src/proc.c b/lincan/src/proc.c index 4fb2343..e423b92 100644 --- a/lincan/src/proc.c +++ b/lincan/src/proc.c @@ -15,9 +15,11 @@ #define __NO_VERSION__ #include +#include int add_channel_to_procdir(struct candevice_t *candev); -int remove_channel_from_procdir(void); +int remove_channels_from_procdir(void); +int remove_channel_from_procdir(struct candevice_t *candev); int add_object_to_procdir(int chip_nr); int remove_object_from_procdir(int chip_nr); @@ -35,6 +37,7 @@ static int cc=0; /* static counter for each CAN chip */ static struct canproc_t can_proc_base; static struct canproc_t *base=&can_proc_base; +DEFINE_MUTEX(proc_mutex); /* synchronize access to canproc_t array */ /* The following functions are needed only for kernel version 2.2. Kernel * version 2.4 already defines them for us. @@ -155,6 +158,9 @@ int can_init_procdir(void) { int board; struct candevice_t *candev; + + mutex_init(&proc_mutex); + base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO | S_IXUGO, CAN_PROC_ROOT); if (base->can_proc_entry == NULL) @@ -168,13 +174,34 @@ int can_init_procdir(void) return 0; } +/* can_init_procentry registers entry of a new board in CAN directory tree at + * the proc system. + */ +int can_init_procentry(int board) +{ + struct candevice_t *candev; + candev=hardware_p->candevice[board]; + if(candev) + return add_channel_to_procdir(candev); + return -ENODEV; +} + /* can_delete_procdir removes the entire CAN tree from the proc system */ int can_delete_procdir(void) { - if (remove_channel_from_procdir()) + if (remove_channels_from_procdir()) return -ENODEV; /* name: "can" */ - if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT)) + if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT)) + return -ENODEV; + + return 0; +} + +/* can_delete_procentry removes device entries from CAN tree in the proc system */ +int can_delete_procentry(struct candevice_t *candev) +{ + if (remove_channel_from_procdir(candev)) return -ENODEV; return 0; @@ -214,58 +241,108 @@ int add_channel_to_procdir(struct candevice_t *candev) { int i=0; - for (i=0; i < candev->nr_all_chips; i++) { + mutex_lock(&proc_mutex); + for (i=0; i < MAX_TOT_CHIPS; i++){ + if (!chips_p[i]) continue; + if (chips_p[i]->hostdevice != candev) continue; - base->channel[cc] = (struct channelproc_t *) + base->channel[i] = (struct channelproc_t *) can_checked_malloc(sizeof(struct channelproc_t)); - if (base->channel[cc] == NULL) + if (base->channel[i] == NULL){ + mutex_unlock(&proc_mutex); return -ENOMEM; + } - sprintf(base->channel[cc]->ch_name, "channel%d",cc); + sprintf(base->channel[i]->ch_name, "channel%d",i); - base->channel[cc]->ch_entry = can_create_proc_entry( - base->channel[cc]->ch_name, + base->channel[i]->ch_entry = can_create_proc_entry( + base->channel[i]->ch_name, S_IFDIR | S_IRUGO |S_IXUGO, base->can_proc_entry); - if (base->channel[cc]->ch_entry == NULL) + if (base->channel[i]->ch_entry == NULL){ + mutex_unlock(&proc_mutex); return -ENODEV; + } - add_object_to_procdir(cc); + add_object_to_procdir(i); create_proc_read_entry("chip_info", /* proc entry name */ 0, /* protection mask, 0->default */ - base->channel[cc]->ch_entry, /* parent dir, NULL->/proc */ + base->channel[i]->ch_entry, /* parent dir, NULL->/proc */ can_chip_procinfo, - candev->chip[i]); - + chips_p[i]); cc++; } + mutex_unlock(&proc_mutex); return 0; } -int remove_channel_from_procdir(void) +int remove_channels_from_procdir(void) { + int i=0; + + mutex_lock(&proc_mutex); + for (i=0; i < MAX_TOT_CHIPS; i++){ + if (!chips_p[i]) continue; - while (cc != 0) { cc--; - if(!base->channel[cc]) continue; + if(!base->channel[i]) continue; - remove_proc_entry("chip_info", base->channel[cc]->ch_entry); + remove_proc_entry("chip_info", base->channel[i]->ch_entry); - if (remove_object_from_procdir(cc)) + if (remove_object_from_procdir(i)){ + mutex_unlock(&proc_mutex); return -ENODEV; + } /* name: base->channel[cc]->ch_name */ - if (can_remove_proc_entry(base->channel[cc]->ch_entry, - base->can_proc_entry)) + if (can_remove_proc_entry(base->channel[i]->ch_entry, + base->can_proc_entry)){ + mutex_unlock(&proc_mutex); return -ENODEV; + } - can_checked_free(base->channel[cc]); - base->channel[cc] = NULL; + can_checked_free(base->channel[i]); + base->channel[i] = NULL; + } + mutex_unlock(&proc_mutex); + + return 0; +} + +int remove_channel_from_procdir(struct candevice_t *candev) +{ + int i=0,j=0; + + mutex_lock(&proc_mutex); + for (i=0; i < MAX_TOT_CHIPS; i++){ + if (!chips_p[i]) continue; + if (chips_p[i]->hostdevice != candev) continue; + if (!base->channel[i]) continue; + + remove_proc_entry("chip_info", base->channel[i]->ch_entry); + + if (remove_object_from_procdir(i)){ + mutex_unlock(&proc_mutex); + return -ENODEV; + } + + /* name: base->channel[cc]->ch_name */ + if (can_remove_proc_entry(base->channel[i]->ch_entry, + base->can_proc_entry)){ + mutex_unlock(&proc_mutex); + return -ENODEV; + } + + can_checked_free(base->channel[i]); + base->channel[i] = NULL; + + cc--; } + mutex_unlock(&proc_mutex); return 0; } diff --git a/lincan/src/setup.c b/lincan/src/setup.c index 64c67be..cb6550d 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -19,6 +19,8 @@ int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p); int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate, long clock); int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int objnr); +int next_minor=0; + /** * can_base_addr_fixup - relocates board physical memory addresses to the CPU accessible ones * @candev: pointer to the previously filled device/board, chips and message objects structures @@ -78,7 +80,6 @@ int can_check_dev_taken(void *anydev) */ int register_obj_struct(struct msgobj_t *obj, int minorbase) { - static int next_minor=0; int i; if(minorbase>=0) @@ -156,6 +157,30 @@ int init_hw_struct(void) return 0; } +/** + * init_new_hw_struct - initializes driver description structures for new hardware + * + * The function init_new_hw_struct() is used to initialize the hardware structure. + * + * Return Value: returns negative number in the case of fail + */ +int init_new_hw_struct(int devnr) +{ + int irq_param_idx=0; + int chan_param_idx=0; + + if ( (hw[devnr] != NULL) & (devnr < MAX_HW_CARDS) ) { + hardware_p->nr_boards++; + + if (init_device_struct(devnr, &chan_param_idx, &irq_param_idx)) { + CANMSG("Error initializing candevice_t structures.\n"); + return -ENODEV; + } + } + + return 0; +} + /** * init_device_struct - initializes single CAN device/board * @card: index into @hardware_p HW description diff --git a/lincan/src/usbcan.c b/lincan/src/usbcan.c index e69de29..f67f252 100644 --- a/lincan/src/usbcan.c +++ b/lincan/src/usbcan.c @@ -0,0 +1,1395 @@ +/* usbcan.h + * Header file for the Linux CAN-bus driver. + * Written by Jan Kriz email:johen@post.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jul 2008 + */ + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/devcommon.h" +#include "../include/setup.h" +#include "../include/usbcan.h" + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) + #include +#endif + +static int usbcan_probe(struct usb_interface *interface, const struct usb_device_id *id); +static void usbcan_disconnect(struct usb_interface *interface); + +volatile int usbcan_chip_count=0; + +/* table of devices that work with this driver */ +static struct usb_device_id usbcan_table [] = { + { USB_DEVICE(USBCAN_VENDOR_ID, USBCAN_PRODUCT_ID) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, usbcan_table); + +static struct usb_driver usbcan_driver = { + .name = "usbcan", + .id_table = usbcan_table, + .probe = usbcan_probe, + .disconnect = usbcan_disconnect, +}; + +/** + * usbcan_request_io: - reserve io or memory range for can board + * @candev: pointer to candevice/board which asks for io. Field @io_addr + * of @candev is used in most cases to define start of the range + * + * The function usbcan_request_io() is used to reserve the io-memory. If your + * hardware uses a dedicated memory range as hardware control registers you + * will have to add the code to reserve this memory as well. + * %IO_RANGE is the io-memory range that gets reserved, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/usbcan.c + */ +int usbcan_request_io(struct candevice_t *candev) +{ + struct usbcan_devs *usbdevs = (struct usbcan_devs *)candev->sysdevptr.anydev; + + if (!usbdevs){ + CANMSG("USBCAN_REQUEST_IO: Cannot register usbcan while usb device is not present.\n"); + CANMSG("USBCAN_REQUEST_IO: Usbcan registers automatically on device insertion.\n"); + return -ENODEV; + } + + return 0; +} + +/** + * usbcan_release_io - free reserved io memory range + * @candev: pointer to candevice/board which releases io + * + * The function usbcan_release_io() is used to free reserved io-memory. + * In case you have reserved more io memory, don't forget to free it here. + * IO_RANGE is the io-memory range that gets released, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function always returns zero + * File: src/usbcan.c + */ +int usbcan_release_io(struct candevice_t *candev) +{ + return 0; +} + +/** + * usbcan_reset - hardware reset routine + * @candev: Pointer to candevice/board structure + * + * The function usbcan_reset() is used to give a hardware reset. This is + * rather hardware specific so I haven't included example code. Don't forget to + * check the reset status of the chip before returning. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/usbcan.c + */ +int usbcan_reset(struct candevice_t *candev) +{ + return 0; +} + +/** + * usbcan_init_hw_data - Initialize hardware cards + * @candev: Pointer to candevice/board structure + * + * The function usbcan_init_hw_data() is used to initialize the hardware + * structure containing information about the installed CAN-board. + * %RESET_ADDR represents the io-address of the hardware reset register. + * %NR_82527 represents the number of Intel 82527 chips on the board. + * %NR_SJA1000 represents the number of Philips sja1000 chips on the board. + * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that + * the hardware uses programmable interrupts. + * Return Value: The function always returns zero + * File: src/usbcan.c + */ +int usbcan_init_hw_data(struct candevice_t *candev) +{ + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=usbcan_chip_count; + candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0; + + return 0; +} + +/** + * usbcan_init_obj_data - Initialize message buffers + * @chip: Pointer to chip specific structure + * @objnr: Number of the message buffer + * + * The function usbcan_init_obj_data() is used to initialize the hardware + * structure containing information about the different message objects on the + * CAN chip. In case of the sja1000 there's only one message object but on the + * i82527 chip there are 15. + * The code below is for a i82527 chip and initializes the object base addresses + * The entry @obj_base_addr represents the first memory address of the message + * object. In case of the sja1000 @obj_base_addr is taken the same as the chips + * base address. + * Unless the hardware uses a segmented memory map, flags can be set zero. + * Return Value: The function always returns zero + * File: src/usbcan.c + */ +int usbcan_init_obj_data(struct canchip_t *chip, int objnr) +{ + chip->msgobj[objnr]->obj_base_addr=0; + + return 0; +} + +/** + * usbcan_program_irq - program interrupts + * @candev: Pointer to candevice/board structure + * + * The function usbcan_program_irq() is used for hardware that uses + * programmable interrupts. If your hardware doesn't use programmable interrupts + * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and + * leave this function unedited. Again this function is hardware specific so + * there's no example code. + * Return value: The function returns zero on success or %-ENODEV on failure + * File: src/usbcan.c + */ +int usbcan_program_irq(struct candevice_t *candev) +{ + return 0; +} + +/* !!! Don't change this function !!! */ +int usbcan_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = usbcan_request_io; + hwspecops->release_io = usbcan_release_io; + hwspecops->reset = usbcan_reset; + hwspecops->init_hw_data = usbcan_init_hw_data; + hwspecops->init_chip_data = usbcan_init_chip_data; + hwspecops->init_obj_data = usbcan_init_obj_data; + hwspecops->write_register = NULL; + hwspecops->read_register = NULL; + hwspecops->program_irq = usbcan_program_irq; + return 0; +} + +// static int sja1000_report_error_limit_counter; + +static void usbcan_report_error(struct canchip_t *chip, + unsigned sr, unsigned ir, unsigned ecc) +{ + /*TODO : Error reporting from device */ + +#if 0 + if(sja1000_report_error_limit_counter>=100) + return; + + CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n", + sr, ir, ecc); + + sja1000_report_error_limit_counter+=10; + + if(sja1000_report_error_limit_counter>=100){ + sja1000_report_error_limit_counter+=10; + CANMSG("Error: too many errors, reporting disabled\n"); + return; + } + +#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS + CANMSG("SR: BS=%c ES=%c TS=%c RS=%c TCS=%c TBS=%c DOS=%c RBS=%c\n", + sr&sjaSR_BS?'1':'0',sr&sjaSR_ES?'1':'0', + sr&sjaSR_TS?'1':'0',sr&sjaSR_RS?'1':'0', + sr&sjaSR_TCS?'1':'0',sr&sjaSR_TBS?'1':'0', + sr&sjaSR_DOS?'1':'0',sr&sjaSR_RBS?'1':'0'); + CANMSG("IR: BEI=%c ALI=%c EPI=%c WUI=%c DOI=%c EI=%c TI=%c RI=%c\n", + sr&sjaIR_BEI?'1':'0',sr&sjaIR_ALI?'1':'0', + sr&sjaIR_EPI?'1':'0',sr&sjaIR_WUI?'1':'0', + sr&sjaIR_DOI?'1':'0',sr&sjaIR_EI?'1':'0', + sr&sjaIR_TI?'1':'0',sr&sjaIR_RI?'1':'0'); + if((sr&sjaIR_EI) || 1){ + CANMSG("EI: %s %s %s\n", + sja1000_ecc_errc_str[(ecc&(sjaECC_ERCC1|sjaECC_ERCC0))/sjaECC_ERCC0], + ecc&sjaECC_DIR?"RX":"TX", + sja1000_ecc_seg_str[ecc&sjaECC_SEG_M] + ); + } +#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/ +#endif +} + + +/** + * usbcan_enable_configuration - enable chip configuration mode + * @chip: pointer to chip state structure + */ +int usbcan_enable_configuration(struct canchip_t *chip) +{ + return 0; +} + +/** + * usbcan_disable_configuration - disable chip configuration mode + * @chip: pointer to chip state structure + */ +int usbcan_disable_configuration(struct canchip_t *chip) +{ + return 0; +} + +/** + * usbcan_chip_config: - can chip configuration + * @chip: pointer to chip state structure + * + * This function configures chip and prepares it for message + * transmission and reception. The function resets chip, + * resets mask for acceptance of all messages by call to + * usbcan_extended_mask() function and then + * computes and sets baudrate with use of function usbcan_baud_rate(). + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_chip_config(struct canchip_t *chip) +{ + return 0; +} + +/** + * usbcan_extended_mask: - setup of extended mask for message filtering + * @chip: pointer to chip state structure + * @code: can message acceptance code + * @mask: can message acceptance mask + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask) +{ + int retval; + struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data; + + u8 usbbuf[USBCAN_TRANSFER_SIZE]; + + if (!dev) + return -ENODEV; + + *(uint32_t *)(usbbuf)=cpu_to_le32(mask); + *(uint32_t *)(usbbuf+4)=cpu_to_le32(code); + + retval=usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + USBCAN_VENDOR_EXT_MASK_SET, + USB_TYPE_VENDOR, + cpu_to_le16(0), cpu_to_le16(chip->chip_idx), + &usbbuf, USBCAN_TRANSFER_SIZE, + 10000); + if (retval<0) + return -ENODEV; + + retval = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USBCAN_VENDOR_EXT_MASK_STATUS, + USB_TYPE_VENDOR, + cpu_to_le16(0), cpu_to_le16(chip->chip_idx), + &usbbuf, USBCAN_TRANSFER_SIZE, + 10000); + + if (retval==1){ + if(usbbuf[0]==1){ + DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code); + DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask); + return 0; + } + } + + CANMSG("Setting extended mask failed\n"); + return -EINVAL; +} + +/** + * usbcan_baud_rate: - set communication parameters. + * @chip: pointer to chip state structure + * @rate: baud rate in Hz + * @clock: frequency of sja1000 clock in Hz (ISA osc is 14318000) + * @sjw: synchronization jump width (0-3) prescaled clock cycles + * @sampl_pt: sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio + * @flags: fields %BTR1_SAM, %OCMODE, %OCPOL, %OCTP, %OCTN, %CLK_OFF, %CBP + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, + int sampl_pt, int flags) +{ + int retval; + struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data; + + u8 usbbuf[USBCAN_TRANSFER_SIZE]; + + if (!dev) + return -ENODEV; + + *(int32_t *)(usbbuf)=cpu_to_le32(rate); + *(int32_t *)(usbbuf+4)=cpu_to_le32(sjw); + *(int32_t *)(usbbuf+8)=cpu_to_le32(sampl_pt); + *(int32_t *)(usbbuf+12)=cpu_to_le32(flags); + + retval=usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + USBCAN_VENDOR_BAUD_RATE_SET, + USB_TYPE_VENDOR, + cpu_to_le16(0), cpu_to_le16(chip->chip_idx), + &usbbuf, USBCAN_TRANSFER_SIZE, + 10000); + if (retval<0) + return -ENODEV; + + retval = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USBCAN_VENDOR_BAUD_RATE_STATUS, + USB_TYPE_VENDOR, + cpu_to_le16(0), cpu_to_le16(chip->chip_idx), + usbbuf, USBCAN_TRANSFER_SIZE, + 10000); + + if (retval==1){ + if(usbbuf[0]==1) + return 0; + } + + CANMSG("baud rate %d is not possible to set\n", + rate); + return -EINVAL; +} + +/** + * usbcan_pre_read_config: - prepares message object for message reception + * @chip: pointer to chip state structure + * @obj: pointer to message object state structure + * + * Return Value: negative value reports error. + * Positive value indicates immediate reception of message. + * File: src/usbcan.c + */ +int usbcan_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj) +{ + return 0; +} + +#define MAX_TRANSMIT_WAIT_LOOPS 10 +/** + * usbcan_pre_write_config: - prepares message object for message transmission + * @chip: pointer to chip state structure + * @obj: pointer to message object state structure + * @msg: pointer to CAN message + * + * This function prepares selected message object for future initiation + * of message transmission by usbcan_send_msg() function. + * The CAN message data and message ID are transfered from @msg slot + * into chip buffer in this function. + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg) +{ + return 0; +} + +/** + * usbcan_send_msg: - initiate message transmission + * @chip: pointer to chip state structure + * @obj: pointer to message object state structure + * @msg: pointer to CAN message + * + * This function is called after usbcan_pre_write_config() function, + * which prepares data in chip buffer. + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_send_msg(struct canchip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg) +{ + return 0; +} + +/** + * usbcan_check_tx_stat: - checks state of transmission engine + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * Positive return value indicates transmission under way status. + * Zero value indicates finishing of all issued transmission requests. + * File: src/usbcan.c + */ +int usbcan_check_tx_stat(struct canchip_t *chip) +{ + struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data; + if (!dev) + return 0; + if (test_bit(USBCAN_TX_PENDING,&dev->flags)) + return 1; + return 0; +} + +/** + * usbcan_set_btregs: - configures bitrate registers + * @chip: pointer to chip state structure + * @btr0: bitrate register 0 + * @btr1: bitrate register 1 + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_set_btregs(struct canchip_t *chip, unsigned short btr0, + unsigned short btr1) +{ + int retval; + u8 buf[USBCAN_TRANSFER_SIZE]; + struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data; + uint16_t value=(btr1&0xFF)<<8 | (btr0&0xFF); + + if (!dev) + return -ENODEV; + + retval = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USBCAN_VENDOR_SET_BTREGS, + USB_TYPE_VENDOR, + cpu_to_le16(value), cpu_to_le16(chip->chip_idx), + &buf, USBCAN_TRANSFER_SIZE, + 10000); + + if (retval==1){ + if(buf[0]==1) + return 0; + } + return -ENODEV; +} + +/** + * usbcan_start_chip: - starts chip message processing + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_start_chip(struct canchip_t *chip) +{ + int retval; + u8 buf[USBCAN_TRANSFER_SIZE]; + struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data; + + if (!dev) + return -ENODEV; + + retval = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USBCAN_VENDOR_START_CHIP, + USB_TYPE_VENDOR, + cpu_to_le16(0), cpu_to_le16(chip->chip_idx), + &buf, USBCAN_TRANSFER_SIZE, + 10000); + + if (retval==1){ + if(buf[0]==1) + return 0; + } + return -ENODEV; +} + +/** + * usbcan_chip_queue_status: - gets queue status from usb device + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * 0 means queue is not full + * 1 means queue is full + * File: src/usbcan.c + */ +int usbcan_chip_queue_status(struct canchip_t *chip) +{ + int retval; + u8 buf[USBCAN_TRANSFER_SIZE]; + struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data; + + if (!dev) + return -ENODEV; + retval = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USBCAN_VENDOR_CHECK_TX_STAT, + USB_TYPE_VENDOR, + cpu_to_le16(0), cpu_to_le16(chip->chip_idx), + &buf, USBCAN_TRANSFER_SIZE, + 10000); + + if (retval==1){ + DEBUGMSG("Chip_queue_status: %d\n",buf[0]); + if(buf[0]==1) + return 0; + if(buf[0]==0) + return 1; + } + CANMSG("Chip_queue_status error: %d\n",retval); + return -ENODEV; +} + +/** + * usbcan_stop_chip: - stops chip message processing + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_stop_chip(struct canchip_t *chip) +{ + int retval; + u8 buf[USBCAN_TRANSFER_SIZE]; + struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data; + + if (!dev) + return -ENODEV; + + retval = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USBCAN_VENDOR_STOP_CHIP, + USB_TYPE_VENDOR, + cpu_to_le16(0), cpu_to_le16(chip->chip_idx), + &buf, USBCAN_TRANSFER_SIZE, + 10000); + + if (retval==1){ + if(buf[0]==1) + return 0; + } + return -ENODEV; +} + +/** + * usbcan_register_devs: - attaches usb device data to the chip structure + * @chip: pointer to chip state structure + * @data: usb device data + * + * File: src/usbcan.c + */ +void usbcan_register_devs(struct canchip_t *chip,void *data){ + struct usbcan_devs *usbdevs=(struct usbcan_devs *)data; + if (!usbdevs){ + CANMSG("Bad structure given\n"); + return; + } + if (chip->chip_idx>=usbdevs->count) { + CANMSG("Requested chip number is bigger than chip count\n"); + return; + } + + usbdevs->devs[chip->chip_idx]->chip=chip; + chip->chip_data=(void *)usbdevs->devs[chip->chip_idx]; +} + +/** + * usbcan_attach_to_chip: - attaches to the chip, setups registers and state + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_attach_to_chip(struct canchip_t *chip) +{ + struct usbcan_usb *dev = (struct usbcan_usb *)chip->chip_data; + + /* start kernel thread */ + dev->comthread=can_kthread_run(usbcan_kthread, (void *)dev, "usbcan_%d",chip->chip_idx); + + return 0; +} + +/** + * usbcan_release_chip: - called before chip structure removal if %CHIP_ATTACHED is set + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_release_chip(struct canchip_t *chip) +{ + struct usbcan_usb *dev = (struct usbcan_usb *)chip->chip_data; + + usbcan_stop_chip(chip); + + /* terminate the kernel thread */ + set_bit(USBCAN_TERMINATE,&dev->flags); + wake_up_process(dev->comthread); +// can_kthread_stop(dev->comthread); + + return 0; +} + +/** + * usbcan_remote_request: - configures message object and asks for RTR message + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_remote_request(struct canchip_t *chip, struct msgobj_t *obj) +{ + CANMSG("usbcan_remote_request not implemented\n"); + return -ENOSYS; +} + +/** + * usbcan_standard_mask: - setup of mask for message filtering + * @chip: pointer to chip state structure + * @code: can message acceptance code + * @mask: can message acceptance mask + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_standard_mask(struct canchip_t *chip, unsigned short code, + unsigned short mask) +{ + CANMSG("usbcan_standard_mask not implemented\n"); + return -ENOSYS; +} + +/** + * usbcan_clear_objects: - clears state of all message object residing in chip + * @chip: pointer to chip state structure + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_clear_objects(struct canchip_t *chip) +{ + CANMSG("usbcan_clear_objects not implemented\n"); + return -ENOSYS; +} + +/** + * usbcan_config_irqs: - tunes chip hardware interrupt delivery + * @chip: pointer to chip state structure + * @irqs: requested chip IRQ configuration + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_config_irqs(struct canchip_t *chip, short irqs) +{ + CANMSG("usbcan_config_irqs not implemented\n"); + return -ENOSYS; +} + +/** + * usbcan_kthread_read_handler: - part of kthread code responsible for receive completed events + * @dev: pointer to usb device related structure + * @obj: pointer to attached message object description + * + * The main purpose of this function is to read message from usb urb + * and transfer message contents to CAN queue ends. + * This subroutine is called by + * usbcan_kthread(). + * File: src/usbcan.c + */ +void usbcan_kthread_read_handler(struct usbcan_usb *dev, struct msgobj_t *obj){ + int i, j, len, retval; + DEBUGMSG("USBCAN RX handler\n"); + for (i=0;irx[i].flags)){ + DEBUGMSG("USBCAN Thread has received a message\n"); + if ((dev->chip)&&(dev->chip->flags & CHIP_CONFIGURED)){ + u8 *ptr; + struct usbcan_message *mess=&dev->rx[i]; + + len=*(u8 *)(mess->msg+1); + if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; + obj->rx_msg.length = len; + + obj->rx_msg.flags=le16_to_cpu(*(u16 *)(mess->msg+2)); + obj->rx_msg.id=le32_to_cpu((*(u32 *)(mess->msg+4))); + + for(ptr=mess->msg+8,j=0; j < len; ptr++,j++) { + obj->rx_msg.data[j]=*ptr; + } + + // fill CAN message timestamp + can_filltimestamp(&obj->rx_msg.timestamp); + canque_filter_msg2edges(obj->qends, &obj->rx_msg); + } + else + CANMSG("Destination chip not found\n"); + } + if (!test_bit(USBCAN_MESSAGE_URB_PENDING,&dev->rx[i].flags)){ + DEBUGMSG("Renewing RX urb\n"); + retval = usb_submit_urb (dev->rx[i].u, GFP_KERNEL); + if (retval<0){ + CANMSG("%d. URB error %d\n", i, retval); + set_bit(USBCAN_ERROR,&dev->flags); + } + else + set_bit(USBCAN_MESSAGE_URB_PENDING,&dev->rx[i].flags); + } + } +} + +/** + * usbcan_kthread_write_handler: - part of kthread code responsible for transmit done events + * @dev: pointer to usb device related structure + * @obj: pointer to attached message object description + * + * The main purpose of this function is to free allocated resources on transmit done event + * This subroutine is called by + * usbcan_kthread(). + * File: src/usbcan.c + */ +void usbcan_kthread_write_handler(struct usbcan_usb *dev, struct msgobj_t *obj){ + int i; + DEBUGMSG("USBCAN TX handler\n"); + for (i=0;itx[i].flags)){ + struct usbcan_message *mess=&dev->tx[i]; + DEBUGMSG("USBCAN Message successfully sent\n"); + + if(mess->slot){ + // Do local transmitted message distribution if enabled + if (processlocal){ + // fill CAN message timestamp + can_filltimestamp(&mess->slot->msg.timestamp); + + mess->slot->msg.flags |= MSG_LOCAL; + canque_filter_msg2edges(obj->qends, &mess->slot->msg); + } + // Free transmitted slot + canque_free_outslot(obj->qends, mess->qedge, mess->slot); + mess->slot=NULL; + } + can_msgobj_clear_fl(obj,TX_PENDING); + + set_bit(USBCAN_FREE_TX_URB,&dev->flags); + set_bit(USBCAN_MESSAGE_FREE,&dev->tx[i].flags); + + // Test if some new messages arrived + set_bit(USBCAN_TX_PENDING,&dev->flags); + } + } +} + +/** + * usbcan_kthread_write_request_handler: - part of kthread code responsible for sending transmit urbs + * @dev: pointer to usb device related structure + * @obj: pointer to attached message object description + * + * The main purpose of this function is to create a usb transmit safe object + * and send it via free transmit usb urb + * This subroutine is called by + * usbcan_kthread(). + * File: src/usbcan.c + */ +void usbcan_kthread_write_request_handler(struct usbcan_usb *dev, struct msgobj_t *obj){ + int i, j, cmd, len, retval; + for (i=0;itx[i].flags)){ + struct usbcan_message *mess=&dev->tx[i]; + u8 *ptr; + cmd=canque_test_outslot(obj->qends, &mess->qedge, &mess->slot); + if(cmd>=0){ + DEBUGMSG("USBCAN Sending a message\n"); + + can_msgobj_set_fl(obj,TX_PENDING); + clear_bit(USBCAN_FREE_TX_URB,&dev->flags); + clear_bit(USBCAN_MESSAGE_FREE,&dev->tx[i].flags); + + *(u8 *)(mess->msg)=0; + len = mess->slot->msg.length; + if(len > CAN_MSG_LENGTH) + len = CAN_MSG_LENGTH; + *(u8 *)(mess->msg+1)=len & 0xFF; + *(u16 *)(mess->msg+2)=cpu_to_le16(mess->slot->msg.flags); + *(u32 *)(mess->msg+4)=cpu_to_le32(mess->slot->msg.id); + + for(ptr=mess->msg+8,j=0; j < len; ptr++,j++) { + *ptr=mess->slot->msg.data[j] & 0xFF; + } + for(; j < 8; ptr++,j++) { + *ptr=0; + } + + set_bit(USBCAN_MESSAGE_URB_PENDING,&mess->flags); + retval = usb_submit_urb (dev->tx[i].u, GFP_KERNEL); + if (retval){ + CANMSG("%d. URB error %d\n",i,retval); + clear_bit(USBCAN_MESSAGE_URB_PENDING,&mess->flags); + set_bit(USBCAN_FREE_TX_URB,&dev->flags); + set_bit(USBCAN_MESSAGE_FREE,&dev->tx[i].flags); + obj->ret = -1; + canque_notify_inends(mess->qedge, CANQUEUE_NOTIFY_ERRTX_SEND); + canque_free_outslot(obj->qends, mess->qedge, mess->slot); + mess->slot=NULL; + } + } + else{ + set_bit(USBCAN_FREE_TX_URB,&dev->flags); + break; + } + } + } +} + +#define MAX_RETR 10 + +/** + * usbcan_irq_handler: - interrupt service routine + * @irq: interrupt vector number, this value is system specific + * @chip: pointer to chip state structure + * + * Interrupt handler is activated when state of CAN controller chip changes, + * there is message to be read or there is more space for new messages or + * error occurs. The receive events results in reading of the message from + * CAN controller chip and distribution of message through attached + * message queues. + * File: src/usbcan.c + */ +int usbcan_irq_handler(int irq, struct canchip_t *chip) +{ + return CANCHIP_IRQ_HANDLED; +} + +/** + * usbcan_wakeup_tx: - wakeups TX processing + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Function is responsible for initiating message transmition. + * It is responsible for clearing of object TX_REQUEST flag + * + * Return Value: negative value reports error. + * File: src/usbcan.c + */ +int usbcan_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj) +{ + struct usbcan_usb *dev=(struct usbcan_usb *)chip->chip_data; + + DEBUGMSG("Trying to send message\n"); + can_preempt_disable(); + + can_msgobj_set_fl(obj,TX_PENDING); + can_msgobj_set_fl(obj,TX_REQUEST); + while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ + can_msgobj_clear_fl(obj,TX_REQUEST); + + if (test_and_clear_bit(USBCAN_FREE_TX_URB,&dev->flags)){ + obj->tx_retry_cnt=0; + set_bit(USBCAN_TX_PENDING,&dev->flags); + if (test_bit(USBCAN_THREAD_RUNNING,&dev->flags)) + wake_up_process(dev->comthread); + } + + can_msgobj_clear_fl(obj,TX_LOCK); + if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + CANMSG("TX looping in usbcan_wakeup_tx\n"); + } + + can_preempt_enable(); + return 0; +} + +int usbcan_chipregister(struct chipspecops_t *chipspecops) +{ + CANMSG("initializing usbcan chip operations\n"); + chipspecops->chip_config=usbcan_chip_config; + chipspecops->baud_rate=usbcan_baud_rate; + chipspecops->standard_mask=usbcan_standard_mask; + chipspecops->extended_mask=usbcan_extended_mask; + chipspecops->message15_mask=usbcan_extended_mask; + chipspecops->clear_objects=usbcan_clear_objects; + chipspecops->config_irqs=usbcan_config_irqs; + chipspecops->pre_read_config=usbcan_pre_read_config; + chipspecops->pre_write_config=usbcan_pre_write_config; + chipspecops->send_msg=usbcan_send_msg; + chipspecops->check_tx_stat=usbcan_check_tx_stat; + chipspecops->wakeup_tx=usbcan_wakeup_tx; + chipspecops->remote_request=usbcan_remote_request; + chipspecops->enable_configuration=usbcan_enable_configuration; + chipspecops->disable_configuration=usbcan_disable_configuration; + chipspecops->attach_to_chip=usbcan_attach_to_chip; + chipspecops->release_chip=usbcan_release_chip; + chipspecops->set_btregs=usbcan_set_btregs; + chipspecops->start_chip=usbcan_start_chip; + chipspecops->stop_chip=usbcan_stop_chip; + chipspecops->irq_handler=usbcan_irq_handler; + chipspecops->irq_accept=NULL; + return 0; +} + +/** + * usbcan_fill_chipspecops - fills chip specific operations + * @chip: pointer to chip representation structure + * + * The function fills chip specific operations for sja1000 (PeliCAN) chip. + * + * Return Value: returns negative number in the case of fail + */ +int usbcan_fill_chipspecops(struct canchip_t *chip) +{ + chip->chip_type="usbcan"; + chip->max_objects=1; + usbcan_chipregister(chip->chipspecops); + return 0; +} + +/** + * usbcan_init_chip_data - Initialize chips + * @candev: Pointer to candevice/board structure + * @chipnr: Number of the CAN chip on the hardware card + * + * The function usbcan_init_chip_data() is used to initialize the hardware + * structure containing information about the CAN chips. + * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or + * "sja1000". + * The @chip_base_addr entry represents the start of the 'official' memory map + * of the installed chip. It's likely that this is the same as the @io_addr + * argument supplied at module loading time. + * The @clock entry holds the chip clock value in Hz. + * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider + * register. Options defined in the %sja1000.h file: + * %sjaCDR_CLKOUT_MASK, %sjaCDR_CLK_OFF, %sjaCDR_RXINPEN, %sjaCDR_CBP, %sjaCDR_PELICAN + * The entry @sja_ocr_reg holds hardware specific options for the Output Control + * register. Options defined in the %sja1000.h file: + * %sjaOCR_MODE_BIPHASE, %sjaOCR_MODE_TEST, %sjaOCR_MODE_NORMAL, %sjaOCR_MODE_CLOCK, + * %sjaOCR_TX0_LH, %sjaOCR_TX1_ZZ. + * The entry @int_clk_reg holds hardware specific options for the Clock Out + * register. Options defined in the %i82527.h file: + * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1. + * The entry @int_bus_reg holds hardware specific options for the Bus + * Configuration register. Options defined in the %i82527.h file: + * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY. + * The entry @int_cpu_reg holds hardware specific options for the cpu interface + * register. Options defined in the %i82527.h file: + * %iCPU_CEN, %iCPU_MUX, %iCPU_SLP, %iCPU_PWD, %iCPU_DMC, %iCPU_DSC, %iCPU_RST. + * Return Value: The function always returns zero + * File: src/usbcan.c + */ +int usbcan_init_chip_data(struct candevice_t *candev, int chipnr) +{ + struct canchip_t *chip=candev->chip[chipnr]; + + usbcan_fill_chipspecops(chip); + + candev->chip[chipnr]->flags|=CHIP_IRQ_CUSTOM; + candev->chip[chipnr]->chip_base_addr=0; + candev->chip[chipnr]->clock = 0; + + return 0; +} + + +/** ********************************* + * USB related functions + * ********************************* */ + +static int usbcan_sleep_thread(struct usbcan_usb *dev) +{ + int rc = 0; + + /* Wait until a signal arrives or we are woken up */ + for (;;) { + try_to_freeze(); + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + rc = -EINTR; + break; + } + if ( + can_kthread_should_stop() || + test_bit(USBCAN_DATA_OK,&dev->flags) || + test_bit(USBCAN_TX_PENDING,&dev->flags) || + test_bit(USBCAN_TERMINATE,&dev->flags) || + test_bit(USBCAN_ERROR,&dev->flags) + ) + break; + schedule(); + } + __set_current_state(TASK_RUNNING); + return rc; +} + +static void usbcan_callback(struct urb *urb) +{ + struct usbcan_message *mess = urb->context; + int retval; + + if (!test_bit(USBCAN_THREAD_RUNNING,&mess->dev->flags)) + return; + if (test_bit(USBCAN_MESSAGE_TERMINATE,&mess->flags)) + return; + + switch (urb->status) { + case 0: + /* success */ + DEBUGMSG("%s > Message OK\n", __FUNCTION__); + set_bit(USBCAN_DATA_OK,&mess->dev->flags); + set_bit(USBCAN_MESSAGE_DATA_OK,&mess->flags); + if (test_bit(USBCAN_MESSAGE_TYPE_RX,&mess->flags)){ + DEBUGMSG("%s > RX flag set\n", __FUNCTION__); + set_bit(USBCAN_DATA_RX,&mess->dev->flags); + } + if (test_bit(USBCAN_MESSAGE_TYPE_TX,&mess->flags)) + DEBUGMSG("%s > TX flag set\n", __FUNCTION__); + set_bit(USBCAN_DATA_TX,&mess->dev->flags); + clear_bit(USBCAN_MESSAGE_URB_PENDING,&mess->flags); + if (test_bit(USBCAN_THREAD_RUNNING,&mess->dev->flags)) + wake_up_process(mess->dev->comthread); + else + CANMSG("%s > USBCAN thread not running\n", __FUNCTION__); +// wake_up(&mess->dev->queue); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + CANMSG("%s > Urb shutting down with status: %d\n", __FUNCTION__, urb->status); + set_bit(USBCAN_TERMINATE,&mess->dev->flags); + set_bit(USBCAN_MESSAGE_TERMINATE,&mess->flags); + clear_bit(USBCAN_MESSAGE_URB_PENDING,&mess->flags); + return; + default: + //CANMSG("%s > Nonzero status received: %d\n", __FUNCTION__, urb->status); + break; + } + + // Try to send urb again on non significant errors + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval<0){ + CANMSG("%s > Retrying urb failed with result %d\n", __FUNCTION__, retval); + set_bit(USBCAN_ERROR,&mess->dev->flags); + clear_bit(USBCAN_MESSAGE_URB_PENDING,&mess->flags); + if (test_bit(USBCAN_THREAD_RUNNING,&mess->dev->flags)) + wake_up_process(mess->dev->comthread); +// wake_up(&mess->dev->queue); + } +} + +int usbcan_kthread(void *data) +{ + int i,retval=0; + struct usbcan_usb *dev=(struct usbcan_usb *)data; + struct msgobj_t *obj; + + CANMSG("Usbcan thread started...\n"); + + if (!dev->chip) + goto error; + obj=dev->chip->msgobj[0]; + + /* Prepare receive urbs */ + for (i=0;irx[i].u = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->rx[i].u){ + CANMSG("Error allocating %d. usb receive urb\n",i); + goto error; + } + dev->rx[i].u->dev = dev->udev; + dev->rx[i].dev = dev; + usb_fill_bulk_urb(dev->rx[i].u, dev->udev, + usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), + dev->rx[i].msg, USBCAN_TRANSFER_SIZE, + usbcan_callback, &dev->rx[i]); + set_bit(USBCAN_MESSAGE_TYPE_RX,&dev->rx[i].flags); + } + + /* Prepare transmit urbs */ + for (i=0;itx[i].u = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->tx[i].u){ + CANMSG("Error allocating %d. usb transmit urb\n",i); + goto error; + } + dev->tx[i].u->dev = dev->udev; + dev->tx[i].dev = dev; + usb_fill_bulk_urb(dev->tx[i].u, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + dev->tx[i].msg, USBCAN_TRANSFER_SIZE, + usbcan_callback, &dev->tx[i]); + set_bit(USBCAN_MESSAGE_FREE,&dev->tx[i].flags); + set_bit(USBCAN_MESSAGE_TYPE_TX,&dev->tx[i].flags); + } + + set_bit(USBCAN_THREAD_RUNNING,&dev->flags); + set_bit(USBCAN_FREE_TX_URB,&dev->flags); + + for (i=0;irx[i].u, GFP_KERNEL); + if (retval){ + CANMSG("%d. URB error %d\n",i,retval); + set_bit(USBCAN_ERROR,&dev->flags); + goto exit; + } + else + set_bit(USBCAN_MESSAGE_URB_PENDING,&dev->rx[i].flags); + } + /* an endless loop in which we are doing our work */ + for(;;) + { + /* We need to do a memory barrier here to be sure that + the flags are visible on all CPUs. */ + mb(); + /* fall asleep */ + if (!(can_kthread_should_stop() || test_bit(USBCAN_TERMINATE,&dev->flags))){ + if (usbcan_sleep_thread(dev)<0) + break; +/* wait_event_interruptible(dev->queue, + can_kthread_should_stop() || + test_bit(USBCAN_DATA_OK,&dev->flags) || + test_bit(USBCAN_TX_PENDING,&dev->flags) || + test_bit(USBCAN_TERMINATE,&dev->flags) || + test_bit(USBCAN_ERROR,&dev->flags) + );*/ + } + /* We need to do a memory barrier here to be sure that + the flags are visible on all CPUs. */ + mb(); + + /* here we are back from sleep because we caught a signal. */ + if (can_kthread_should_stop()){ + /* we received a request to terminate ourself */ + break; + } + + /* here we are back from sleep because we caught a signal. */ + if (test_bit(USBCAN_TERMINATE,&dev->flags)){ + /* we received a request to terminate ourself */ + break; + } + + { /* Normal work to do */ + if (test_and_clear_bit(USBCAN_DATA_OK,&dev->flags)){ + DEBUGMSG("USBCAN Succesfull data transfer\n"); + + if (test_and_clear_bit(USBCAN_DATA_RX,&dev->flags)){ + usbcan_kthread_read_handler(dev, obj); + } + if (test_and_clear_bit(USBCAN_DATA_TX,&dev->flags)){ + usbcan_kthread_write_handler(dev, obj); + } + } + if (test_and_clear_bit(USBCAN_TX_PENDING,&dev->flags)){ + usbcan_kthread_write_request_handler(dev, obj); + } + } + } + set_bit(USBCAN_TERMINATE,&dev->flags); +exit: + /* here we go only in case of termination of the thread */ + for (i=0;irx[i].u){ + set_bit(USBCAN_MESSAGE_TERMINATE,&dev->rx[i].flags); + usb_kill_urb(dev->rx[i].u); + usb_free_urb(dev->rx[i].u); + } + } + for (i=0;itx[i].u){ + set_bit(USBCAN_MESSAGE_TERMINATE,&dev->tx[i].flags); + usb_kill_urb(dev->tx[i].u); + usb_free_urb(dev->tx[i].u); + } + } + clear_bit(USBCAN_THREAD_RUNNING,&dev->flags); + + CANMSG ("usbcan thread finished!\n"); + return 0; +error: + /* cleanup the thread, leave */ + CANMSG ("kernel thread terminated!\n"); + return -ENOMEM; +} + +static int usbcan_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usbcan_devs *usbdevs=NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + size_t buffer_size; + int i,j,k; + int retval = -ENOMEM; + + iface_desc = interface->cur_altsetting; + if (iface_desc->desc.bNumEndpoints % 2){ + CANMSG("Endpoint count must be even"); + goto noalloc; + } + + usbcan_chip_count = iface_desc->desc.bNumEndpoints / 2; + + usbdevs = (struct usbcan_devs *) can_checked_malloc(sizeof(struct usbcan_devs)); + if (!usbdevs) { + CANMSG("Out of memory"); + goto error; + } + memset(usbdevs, 0, sizeof(struct usbcan_devs)); + + usbdevs->count=usbcan_chip_count; + + usbdevs->devs = (struct usbcan_usb **) can_checked_malloc(usbcan_chip_count * sizeof(struct usbcan_usb *)); + if (!usbdevs->devs) { + CANMSG("Out of memory"); + goto error; + } + memset(usbdevs->devs, 0, usbcan_chip_count * sizeof(struct usbcan_usb *)); + + for (j=0;jdevs[j] = (struct usbcan_usb *) can_checked_malloc(sizeof(struct usbcan_usb)); + if (!usbdevs->devs[j]) { + CANMSG("Out of memory"); + goto error; + } + memset(usbdevs->devs[j], 0, sizeof(struct usbcan_usb)); + dev=usbdevs->devs[j]; + + mutex_init(&dev->io_mutex); + init_waitqueue_head(&dev->queue); + dev->udev = interface_to_usbdev(interface); + dev->interface = interface; + + /* set up the endpoint information */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (epnum==-1){ + was=0; + for (k=0;kdevs[k]->bulk_in_endpointAddr & USB_ENDPOINT_NUMBER_MASK) == (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) + was=1; + } + if (was) continue; + epnum=endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + } + + if (!dev->bulk_in_endpointAddr && + usb_endpoint_is_bulk_in(endpoint)) { + if (epnum == (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)){ + /* we found a bulk in endpoint */ + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + dev->bulk_in_size = buffer_size; + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_in_buffer = can_checked_malloc(buffer_size); + if (!dev->bulk_in_buffer) { + CANMSG("Could not allocate bulk_in_buffer"); + goto error; + } + } + } + + if (!dev->bulk_out_endpointAddr && + usb_endpoint_is_bulk_out(endpoint)) { + if (epnum == (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)){ + /* we found a bulk out endpoint */ + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; + } + } + + } + if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { + CANMSG("Could not find all bulk-in and bulk-out endpoints for chip %d",j); + goto error; + } + } + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, usbdevs); + + if (!(usbdevs->candev=register_usbdev("usbcan",(void *) usbdevs, usbcan_register_devs))) + goto register_error; + + /* let the user know what node this device is now attached to */ + CANMSG("USBCAN device now attached\n"); + return 0; + +register_error: + cleanup_usbdev(usbdevs->candev); +error: + if (usbdevs){ + if (usbdevs->devs){ + if (usbdevs->devs[0]){ + usb_put_dev(usbdevs->devs[0]->udev); + } + for (j=0;jcount;j++){ + if (!usbdevs->devs[j]) continue; + + if (usbdevs->devs[j]->bulk_in_buffer) + can_checked_free(usbdevs->devs[j]->bulk_in_buffer); + if (usbdevs->devs[j]->chip){ + usbdevs->devs[j]->chip->chip_data=NULL; + } + can_checked_free(usbdevs->devs[j]); + } + can_checked_free(usbdevs->devs); + } + can_checked_free(usbdevs); + } +noalloc: + return retval; +} + +// Physically disconnected device +static void usbcan_disconnect(struct usb_interface *interface) +{ + struct usbcan_devs *usbdevs; + int j; + usbdevs = usb_get_intfdata(interface); + if (usbdevs==NULL){ + CANMSG("USBCAN device seems to be removed\n"); + return; + } + usb_set_intfdata(interface, NULL); + + if (usbdevs->devs){ + usb_put_dev((*usbdevs->devs)->udev); + } + cleanup_usbdev(usbdevs->candev); + if (usbdevs->devs){ + for (j=0;jcount;j++){ + if (!usbdevs->devs[j]) continue; + + /* prevent more I/O from starting */ + mutex_lock(&usbdevs->devs[j]->io_mutex); + usbdevs->devs[j]->interface = NULL; + mutex_unlock(&usbdevs->devs[j]->io_mutex); + + while (test_bit(USBCAN_THREAD_RUNNING,&usbdevs->devs[j]->flags)) + { + CANMSG("USBCAN thread has not stopped, trying to wake...\n"); + set_bit(USBCAN_TERMINATE,&usbdevs->devs[j]->flags); + wake_up_process(usbdevs->devs[j]->comthread); + schedule(); +// can_kthread_stop(dev->comthread); + } + + if (usbdevs->devs[j]->bulk_in_buffer) + can_checked_free(usbdevs->devs[j]->bulk_in_buffer); + // if (usbdevs->devs[j]->chip){ + // usbdevs->devs[j]->chip->chip_data=NULL; + // } + can_checked_free(usbdevs->devs[j]); + usbdevs->devs[j]=NULL; + } + can_checked_free(usbdevs->devs); + } + can_checked_free(usbdevs); + + CANMSG("USBCAN now disconnected\n"); +} + +int usbcan_init(void){ + return usb_register(&usbcan_driver); +} + +void usbcan_exit(void){ + usb_deregister(&usbcan_driver); +} diff --git a/omk/rules/sysless/Makefile.rules b/omk/rules/sysless/Makefile.rules new file mode 100644 index 0000000..e444ab3 --- /dev/null +++ b/omk/rules/sysless/Makefile.rules @@ -0,0 +1,1010 @@ +# Version for system-less builds. #OMK@sysless +# +# Makefile.rules - OCERA make framework common project rules -*- makefile -*- #OMK@base +# +# (C) Copyright 2003 by Pavel Pisa - OCERA team member +# (C) Copyright 2006 by Michal Sojka - Czech Technical University, FEE, DCE +# +# Homepage: http://rtime.felk.cvut.cz/omk/ +# +# The OMK build system is distributed under the GNU General Public +# License. See file COPYING for details. +# +# input variables +# V .. if set to 1, full command text is shown else short form is used +# W .. whole tree - if set to 1, make is always called from the top-level directory +# SUBDIRS .. list of subdirectories intended for make from actual directory +# default_CONFIG .. list of default config assignments CONFIG_XXX=y/n ... +# LN_HEADERS .. if "y", header files are symbolicaly linked instead of copied. #OMK@include +# #OMK@sysless +# bin_PROGRAMS .. list of the require binary programs +# test_PROGRAMS .. list of the test programs +# include_HEADERS .. list of the user-space public header files +# lib_LIBRARIES .. list of the user-space libraries +# lib_LDSCRIPTS .. list of LD scripts that should be copied to the lib direcotry +# lib_obj_SOURCES .. list of source files which should be compiled and +# the produced object file placed to the lib directory (e.g. crt0.S) +# shared_LIBRARIES .. list of the user-space shared libraries +# nobase_include_HEADERS .. public headers copied even with directory part +# renamed_include_HEADERS .. public headers copied to the different target name (xxx.h->yyy.h) +# utils_PROGRAMS .. list of the development utility programs (compiled for host computer, this might change in future) +# xxx_SOURCES .. list of specific target sources +# xxx_LIBS .. list of specific target libraries +# INCLUDES .. additional include directories and defines for user-space +# lib_LOADLIBES .. list of libraries linked to each executable +# link_VARIANTS .. list of ld script suffixes (after hypen `-') that +# should be used for linking (e.g. ram flash). If this is not +# specified, then the value of DEFAULT_LD_SCRIPT_VARIANT from config.target is used. +# PREFIX_DIR .. Prefix to directories in _compiled and _build. Used in config.omk. +# LOCAL_CONFIG_H .. name of local config.h file generated from values #OMK@config_h +# of options defined in the current directory +# config_include_HEADERS .. names of global config files (possibly +# with subdirectories) +# xxx_DEFINES .. list of config directives to be included in +# config header file of the name /xxx.h +# DOXYGEN .. if non-empty, generated headers includes Doxygen's @file +# command, so it is possible to document config +# variables. +# local_EVALUATE .. Makefile hook, which is executed at the end of #OMK@localeval +# the Makefile.rules. Used only for dirty hacks. +OMK_RULES_TYPE=sysless #OMK@__type + #OMK@base +# We need to ensure definition of sources directory first +ifndef SOURCES_DIR +# Only shell built-in pwd understands -L +SOURCES_DIR := $(shell ( pwd -L ) ) +endif + +# If we are not called by OMK leaf Makefile... +ifndef MAKERULES_DIR +MAKERULES_DIR := $(abspath $(dir $(filter %Makefile.rules,$(MAKEFILE_LIST)))) +endif + +# OUTPUT_DIR is the place where _compiled, _build and possible other +# files/directories are created. By default is the same as +# $(MAKERULES_DIR). +ifndef OUTPUT_DIR +OUTPUT_DIR := $(MAKERULES_DIR) +endif + +.PHONY: all default check-make-ver omkize + +ifdef W + ifeq ("$(origin W)", "command line") + OMK_WHOLE_TREE:=$(W) + endif +endif +ifndef OMK_WHOLE_TREE + OMK_WHOLE_TREE:=0 +endif + +ifneq ($(OMK_WHOLE_TREE),1) +all: check-make-ver default + @echo "Compilation finished" +else +# Run make in the top-level directory +all: + @$(MAKE) -C $(MAKERULES_DIR) OMK_SERIALIZE_INCLUDED=n SOURCES_DIR=$(MAKERULES_DIR) RELATIVE_DIR="" $(MAKECMDGOALS) W=0 +endif + +ifdef OMK_TESTSROOT +# Usage: $(call canttest,) +define canttest + ( echo "$(1)" > $(OUTPUT_DIR)/_canttest; echo "$(1)"; exit 1 ) +endef +else +define canttest + echo "$(1)" +endef +endif + +#========================= +# Include the config file + +# FIXME: I think CONFIG_FILE_OK variable is useless. We have three +# config files and it is not clearly defined to which file is this +# variable related. +ifneq ($(CONFIG_FILE_OK),y) +ifndef CONFIG_FILE +CONFIG_FILE := $(OUTPUT_DIR)/config.omk +endif +ifneq ($(wildcard $(CONFIG_FILE)-default),) +-include $(CONFIG_FILE)-default +else +ifneq ($(MAKECMDGOALS),default-config) +$(warning Please, run "make default-config" first) +endif +endif + +-include $(OUTPUT_DIR)/config.target + +ifneq ($(wildcard $(CONFIG_FILE)),) +-include $(CONFIG_FILE) +CONFIG_FILE_OK = y +endif +endif #$(CONFIG_FILE_OK) + + +CONFIG_FILES ?= $(wildcard $(CONFIG_FILE)-default) $(wildcard $(OUTPUT_DIR)/config.target) $(wildcard $(CONFIG_FILE)) + + +export SOURCES_DIR MAKERULES_DIR RELATIVE_DIR +export CONFIG_FILE CONFIG_FILES OMK_SERIALIZE_INCLUDED OMK_VERBOSE OMK_SILENT +# OMK_SERIALIZE_INCLUDED has to be exported to submakes because passes +# must to be serialized only in the toplevel make. + +ifndef RELATIVE_DIR +RELATIVE_DIR := $(SOURCES_DIR:$(OUTPUT_DIR)%=%) +endif +#$(warning === RELATIVE_DIR = "$(RELATIVE_DIR)" ===) +override RELATIVE_DIR := $(RELATIVE_DIR:/%=%) +override RELATIVE_DIR := $(RELATIVE_DIR:\\%=%) +#$(warning RELATIVE_DIR = "$(RELATIVE_DIR)") +override BACK2TOP_DIR := $(shell echo $(RELATIVE_DIR)/ | sed -e 's_//_/_g' -e 's_/\./_/_g' -e 's_^\./__g' -e 's_\([^/][^/]*\)_.._g' -e 's_/$$__') +#$(warning BACK2TOP_DIR = "$(BACK2TOP_DIR)") + +#$(warning SOURCES_DIR = "$(SOURCES_DIR)") +#$(warning MAKERULES_DIR = "$(OUTPUT_DIR)") +#$(warning RELATIVE_DIR = "$(RELATIVE_DIR)") + +# We have to use RELATIVE_PREFIX because of mingw +override RELATIVE_PREFIX := $(RELATIVE_DIR)/ +override RELATIVE_PREFIX := $(RELATIVE_PREFIX:/%=%) + +#vpath %.c $(SOURCES_DIR) +#vpath %.cc $(SOURCES_DIR) +#vpath %.cxx $(SOURCES_DIR) + +# Define srcdir for Automake compatibility +srcdir = $(SOURCES_DIR) + +# Defines for quiet compilation +ifdef V + ifeq ("$(origin V)", "command line") + OMK_VERBOSE = $(V) + endif +endif +ifndef OMK_VERBOSE + OMK_VERBOSE = 0 +endif +ifneq ($(OMK_VERBOSE),0) + Q = +else + Q = @ +endif +ifneq ($(findstring s,$(MAKEFLAGS)),) + QUIET_CMD_ECHO = true + OMK_SILENT = 1 +else + QUIET_CMD_ECHO = echo +endif + +MAKEFILE_OMK=Makefile.omk +# All subdirectories (even linked ones) containing Makefile.omk +# Usage in Makefile.omk: SUBDIRS = $(ALL_OMK_SUBDIRS) +ALL_OMK_SUBDIRS = $(patsubst %/$(MAKEFILE_OMK),%,$(patsubst $(SOURCES_DIR)/%,%,$(wildcard $(SOURCES_DIR)/*/$(MAKEFILE_OMK)))) + +# =================================================================== +# We have set up all important variables, so we can check and include +# real OCERA style Makefile.omk now +ifndef OMK_INCLUDED +include $(SOURCES_DIR)/$(MAKEFILE_OMK) +ifeq ($(AUTOMATIC_SUBDIRS),y) +SUBDIRS?=$(ALL_OMK_SUBDIRS) +endif +OMK_INCLUDED := 1 +endif + +check-make-ver: + @GOOD_MAKE_VERSION=`echo $(MAKE_VERSION) | sed -n -e 's/^[4-9]\..*\|^3\.9[0-9].*\|^3\.8[1-9].*/y/p'` ; \ + if [ x$$GOOD_MAKE_VERSION != xy ] ; then \ + echo "Your make program version is too old and does not support OMK system." ; \ + echo "Please update to make program 3.81beta1 or newer." ; exit 1 ; \ + fi + +distclean dist-clean: + @$(QUIET_CMD_ECHO) " RM $(COMPILED_DIR_NAME) $(BUILD_DIR_NAME)" + @rm -fr $(OUTPUT_DIR)/$(COMPILED_DIR_NAME) $(OUTPUT_DIR)/$(BUILD_DIR_NAME) + +# Common OMK templates +# ==================== + +# Syntax: $(call mkdir,) +define mkdir_def + [ -d $(1) ] || mkdir -p $(1) || exit 1 +endef + +ifneq ($(OMK_VERBOSE),2) +NO_PRINT_DIRECTORY := --no-print-directory +endif + +ifeq ($(USE_LEAF_MAKEFILES),n) +export USE_LEAF_MAKEFILES +SUBDIR_MAKEFILE=$(MAKERULES_DIR)/Makefile.rules +SOURCESDIR_MAKEFILE=$(MAKERULES_DIR)/Makefile.rules +else +SUBDIR_MAKEFILE=$(SOURCES_DIR)/$(3)/Makefile +SOURCESDIR_MAKEFILE=$(SOURCES_DIR)/Makefile +endif + +pass = $(strip $(1)) + +# Call a pass in a subdirectory +# Usage: $(call omk_pass_subdir_template,,,) +define omk_pass_subdir_template +.PHONY: $(pass)-$(3)-subdir +$(pass)-submakes: $(pass)-$(3)-subdir +$(pass)-$(3)-subdir: + @$(call mkdir_def,$(2)/$(3)) + +@$(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(3) $(NO_PRINT_DIRECTORY) \ + RELATIVE_DIR=$(RELATIVE_PREFIX)$(3) -C $(2)/$(3) \ + -f $(SUBDIR_MAKEFILE) $(pass)-submakes +# In subdirectories we can call submakes directly since passes are +# already searialized on the toplevel make. +endef + +ifdef OMK_TESTSROOT +check-target = $(1:%=%-check) +endif + +# Call a pass in a subdirectory +# Usage: $(call extra_rules_subdir_template,) +define extra_rules_subdir_template +extra-rules-subdirs: extra-rules-$(1) +extra-rules-$(1): + +@$(MAKE) OMK_SERIALIZE_INCLUDED=n MAKERULES_DIR=$(SOURCES_DIR)/$(1) OUTPUT_DIR=$(OUTPUT_DIR) \ + SOURCES_DIR=$(SOURCES_DIR)/$(1) RELATIVE_DIR=$(RELATIVE_PREFIX)$(1) -C $(SOURCES_DIR)/$(1) +endef + +.PHONY: extra-rules-subdirs +extra-rules-subdirs: + +$(foreach subdir,$(EXTRA_RULES_SUBDIRS),$(eval $(call extra_rules_subdir_template,$(subdir)))) + +# Usage: $(call omk_pass_template,,,[],[]) +define omk_pass_template +.PHONY: $(pass) $(pass)-local $(pass)-check $(pass)-submakes +$(foreach subdir,$(SUBDIRS),$(eval $(call omk_pass_subdir_template,$(pass),$(2),$(subdir)))) +$(pass): +# Submakes have to be called this way and not as dependecies for pass +# serialization to work + +@$(MAKE) SOURCES_DIR=$(SOURCES_DIR) $(NO_PRINT_DIRECTORY) \ + RELATIVE_DIR=$(RELATIVE_DIR) \ + -f $(SOURCESDIR_MAKEFILE) $(pass)-submakes +$(pass)-submakes: + @true # Do not emit "nothing to be done" messages + +ifneq ($(4)$($(pass)_HOOKS),) +$(pass)-submakes: $(pass)-this-dir +$(pass)-this-dir: $(foreach subdir,$(SUBDIRS),$(pass)-$(subdir)-subdir) + +@echo "make[omk]: $(pass) in $(RELATIVE_DIR)" + @$(call mkdir_def,$(2)) + +@$(MAKE) $(NO_PRINT_DIRECTORY) SOURCES_DIR=$(SOURCES_DIR) RELATIVE_DIR=$(RELATIVE_DIR) -C $(2) \ + -f $(SOURCESDIR_MAKEFILE) $(3) $(check-target) $(1:%=%-local) +$(pass)-local: $($(pass)_HOOKS) +endif +endef + +# ======================= +# DEFAULT CONFIG PASS + +default-config: + @echo "# Start of OMK config file" > "$(CONFIG_FILE)-default" + @echo "# This file should not be altered manually" >> "$(CONFIG_FILE)-default" + @echo "# Overrides should be stored in file $(notdir $(CONFIG_FILE))" >> "$(CONFIG_FILE)-default" + @echo >> "$(CONFIG_FILE)-default" + @$(MAKE) $(NO_PRINT_DIRECTORY) -C $(OUTPUT_DIR) \ + RELATIVE_DIR="" SOURCES_DIR=$(OUTPUT_DIR) \ + -f $(OUTPUT_DIR)/Makefile default-config-pass + +$(eval $(call omk_pass_template,default-config-pass,$$(LOCAL_BUILD_DIR),,always)) + +default-config-pass-local: +# @echo Default config for $(RELATIVE_DIR) + @echo "# Config for $(RELATIVE_DIR)" >> "$(CONFIG_FILE)-default" + @$(foreach x, $(default_CONFIG), echo '$(x)' | \ + sed -e 's/^[^=]*=x$$/#\0/' >> "$(CONFIG_FILE)-default" ; ) + + +omkize: + $(Q)if ! grep -q MAKERULES_DIR Makefile; then \ + echo "Makefile is not OMK leaf makefile!" >&2; exit 1; \ + fi + $(Q)for i in `find -L . -name Makefile.omk` ; do \ + d=`dirname $${i}`; \ + if ! test -f "$${d}/Makefile.rules" && ( ! test -f "$${d}/Makefile" || ! cmp --silent Makefile "$${d}/Makefile" ); then \ + rm -f "$${d}/Makefile"; \ + cp -v Makefile "$${d}/Makefile"; \ + fi \ + done + #OMK@gcc +# Rules for compilation of C, C++ and assembler sources using GNU +# toolchain. + +# Interface to other rules: + +# Input variables: +# LIB_DIR - directory where compiled libraries are stored +# OBJS_DIR - directory where intermediate files (.o, .map, ...) are stored +# INCLUDE_DIR - where includes can be found +# from config.omk or Makefile.omk +# CROSS_COMPILE - +# TARGET_ARCH, DEBUG, OPTIMIZE, DEFS - forms CFLAGS +# from base: SOURCES_DIR +# from Makefile.omk: lib_LOADLIBES + +# Output variables: +# SOURCES - all the source files that needs to be compiled (except for shared library sources) +# SOLIB_SOURCES - all the source files that needs to be compiled for a shared library +# OBJ_EXT - extension of object files +# LIB_EXT - extension of library files +# LIB_PREF - prefix for library files +# ASM_EXT - extension of assembler sources + +# Templates: +# COMPILER_DEFS_template - definitions that should be defined before +# the following templates can be used. The input variables needs to be +# defined before evaluating this template + +# COMPILE_c_o_template, COMPILE_cc_o_template, COMPILE_S_o_template - +# templates that create rules for compilation of sources + +# CMETRIC_o_h_template - FIXME + +# PROGRAM_template, LIBRARY_template, SOLIB_template - templates that +# create rules for compilation of a program, library and shared +# library. The rules can use rules produced by COMPILE_xxx_template. + +define COMPILER_DEFS_template +OBJ_EXT = .o +LIB_EXT = .a +LIB_PREF = lib +ASM_EXT = .S + +CC = $(CROSS_COMPILE)gcc +LINK = $(CROSS_COMPILE)ld +AR = $(CROSS_COMPILE)ar +OBJCOPY = $(CROSS_COMPILE)objcopy +NM = $(CROSS_COMPILE)nm + +CFLAGS += $(TARGET_ARCH) $(DEBUG) $(OPTIMIZE) +CFLAGS += -Wall +CFLAGS += -I$(SOURCES_DIR) +CFLAGS += -I$(INCLUDE_DIR) + +LOADLIBES += -L$(LIB_DIR) +LOADLIBES += $(lib_LOADLIBES:%=-l%) + + +-include $(OBJS_DIR)/*.d + +#%.lo: %.c +# $(CC) -o $@ $(LCFLAGS) -c $< + +c_o_COMPILE = $$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $$(CFLAGS) + +cc_o_COMPILE = $$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $$(CFLAGS) + +S_o_COMPILE = $$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(CPPFLAGS) $(AM_CFLAGS) $$(CFLAGS) $(ASFLAGS) + + +# Check GCC version for user build +ifndef CC_MAJOR_VERSION +CC_MAJOR_VERSION = $$(shell $$(CC) -dumpversion | sed -e 's/\([^.]\)\..*/\1/') +endif +# Prepare suitable define for dependency building +ifeq ($$(CC_MAJOR_VERSION),2) +CC_DEPFLAGS = -Wp,-MD,"$$@.d.tmp" +else +CC_DEPFLAGS = -MT $$@ -MD -MP -MF "$$@.d.tmp" +endif + +endef # COMPILER_DEFS_template + + +# Syntax: $(call COMPILE_c_o_template,,,) +define COMPILE_c_o_template +$(2): $(1) $$(GEN_HEADERS) + @$(QUIET_CMD_ECHO) " CC $$@" + $(Q) if $$(c_o_COMPILE) $$(CC_DEPFLAGS) $(3) -o $$@ -c $$< ; \ + then mv -f "$$@.d.tmp" "$$@.d" ; \ + else rm -f "$$@.d.tmp" ; exit 1; \ + fi +endef + + + +# Syntax: $(call COMPILE_cc_o_template,,,) +define COMPILE_cc_o_template +$(2): $(1) $$(GEN_HEADERS) + @$(QUIET_CMD_ECHO) " CXX $$@" + $(Q) if $$(cc_o_COMPILE) $$(CC_DEPFLAGS) $(3) -o $$@ -c $$< ; \ + then mv -f "$$@.d.tmp" "$$@.d" ; \ + else rm -f "$$@.d.tmp" ; exit 1; \ + fi +endef + +# Syntax: $(call COMPILE_S_o_template,,,) +define COMPILE_S_o_template +$(2): $(1) $$(GEN_HEADERS) + @$(QUIET_CMD_ECHO) " AS $$@" + $(Q) if $$(S_o_COMPILE) -D__ASSEMBLY__ $$(CC_DEPFLAGS) $(3) -o $$@ -c $$< ; \ + then if [ -e "$$@.d.tmp" ] ; then mv -f "$$@.d.tmp" "$$@.d" ; fi ; \ + else rm -f "$$@.d.tmp" ; exit 1; \ + fi +endef + +# Syntax: $(call CMETRIC_o_h_template,,) +define CMETRIC_o_h_template +$(2): $(1) + @$(QUIET_CMD_ECHO) " CMETRIC $$@" + $(Q)if [ -n `dirname $$@` ] ; then \ + if [ ! -e `dirname $$@` ] ; then \ + mkdir -p `dirname $$@` ; fi ; fi + $(Q)echo >$$@ '/* Automatically generated from $$< */' + $(Q)echo >>$$@ '/* Conditionals to control compilation */' + $(Q)set -o pipefail ; $(NM) $$< \ + | sed -n 's/^ *0*\(0[0-9A-Fa-f]*\) *A *_cmetric2cond_\([A-Za-z_0-9]*\) */#define \2 0x\1/p' \ + | sort >>$$@ + $(Q)echo >>$$@ '/* Defines from the values defined to symbols */' + $(Q)set -o pipefail ; $(NM) $$< \ + | sed -n 's/^ *0*\(0[0-9A-Fa-f]*\) *A *_cmetric2def_\([A-Za-z_0-9]*\) */#define \2 0x\1/p' \ + | sort >>$$@ +endef + +# Syntax: $(call PROGRAM_template,,,) +define PROGRAM_template +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.c=%.o)) +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.cc=%.o)) +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.cxx=%.o)) +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.S=%.o)) +$(1)_OBJS += $$(filter %.o,$(1)_SOURCES) +$(1)_OBJS := $$(sort $$($(1)_OBJS)) + +SOURCES += $$($(1)_SOURCES) + +ifneq ($(LD_SCRIPT),) +$(1)$(3:%=-%)_LDFLAGS = -Wl,-T,$(LD_SCRIPT).ld$(3:%=-%) +endif + +$(2)/$(1)$(3:%=-%): $$($(1)_OBJS) + @$(QUIET_CMD_ECHO) " LINK $$@" + $(Q) $$(shell if [ -z "$$(filter %.cc,$$($(1)_SOURCES))" ] ; \ + then echo $$(CC) $$(CPPFLAGS) $$(AM_CPPFLAGS) $$(AM_CFLAGS) $$(CFLAGS) ; \ + else echo $$(CXX) $$(CPPFLAGS) $$(AM_CPPFLAGS) $$(AM_CXXFLAGS) $$(CXXFLAGS) ; fi) \ + $$(AM_LDFLAGS) $$(LDFLAGS) $$($(1)$(3:%=-%)_LDFLAGS) -Wl,-Map,$(1)$(3:%=-%).map \ + $$($(1)_OBJS) $$(LOADLIBES) $$($(1)_MOREOBJS) $$($(1)_LIBS:%=-l%) \ + -o $$@ + @echo "$(2)/$(1)$(3:%=-%): \\" >$(OBJS_DIR)/$(1)$(3:%=-%).exe.d + @if [ -n "$(LD_SCRIPT)" ]; then \ + echo " $(LIB_DIR)/$(LD_SCRIPT).ld$(3:%=-%) \\" >>$(OBJS_DIR)/$(1)$(3:%=-%).exe.d; fi + @sed -n -e 's|^LOAD \(.*\)$$$$| \1 \&|p' $(OBJS_DIR)/$(1)$(3:%=-%).map|tr '&' '\134' >>$(OBJS_DIR)/$(1)$(3:%=-%).exe.d + @echo >>$(OBJS_DIR)/$(1).exe.d +endef + +# Rules for other output formats (can be specified by OUTPUT_FORMATS) +%.bin: % + @$(QUIET_CMD_ECHO) " OBJCOPY $@" + $(Q) $(OBJCOPY) --output-target=binary -S $< $@ + +%.hex: % + @$(QUIET_CMD_ECHO) " OBJCOPY $@" + $(Q) $(OBJCOPY) --output-target=ihex -S $< $@ + +%.srec: % + @$(QUIET_CMD_ECHO) " OBJCOPY $@" + $(Q) $(OBJCOPY) --output-target=srec -S $< $@ + +# Syntax: $(call LIBRARY_template,) +define LIBRARY_template +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.c=%.o)) +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.cc=%.o)) +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.cxx=%.o)) +$(1)_OBJS += $$(filter %.o,$$($(1)_SOURCES:%.S=%.o)) +$(1)_OBJS := $$(sort $$($(1)_OBJS)) + +SOURCES += $$($(1)_SOURCES) + +$(LIB_DIR)/lib$(1).a: $$($(1)_OBJS) + @$(QUIET_CMD_ECHO) " AR $$@" + $(Q) $(AR) rcs $$@ $$^ +endef + + +# Syntax: $(call SOLIB_template,) +define SOLIB_template +$(1)_OBJSLO += $$(filter %.lo,$$($(1)_SOURCES:%.c=%.lo)) +$(1)_OBJSLO += $$(filter %.lo,$$($(1)_SOURCES:%.cc=%.lo)) +$(1)_OBJSLO += $$(filter %.lo,$$($(1)_SOURCES:%.cxx=%.lo)) +$(1)_OBJSLO += $$(filter %.lo,$$($(1)_SOURCES:%.S=%.lo)) +$(1)_OBJSLO := $$(sort $$($(1)_OBJSLO)) + +SOLIB_OBJS += $$($(1)_OBJSLO) +SOLIB_SOURCES += $$($(1)_SOURCES) + +$(LIB_DIR)/lib$(1).so: $$($(1)_OBJSLO) + @$(QUIET_CMD_ECHO) " LINK $$@" + $(Q) $(LD) --shared --soname=lib$(1).so -o $$@ $$^ +endef + +# Local Variables: +# mode:makefile +# End: +ifeq ($(OMK_VERBOSE),1) #OMK@include +CPHEADER_FLAGS += -v +LNHEADER_FLAGS += -v +endif + +ifneq ($(LN_HEADERS),y) +define cp_cmd +( echo " CP $(1:$(OUTPUT_DIR)/%=%) -> $(2:$(OUTPUT_DIR)/%=%)"; cp $(CPHEADER_FLAGS) $(1) $(2) ) +endef +else +define cp_cmd +( echo " LN $(1:$(OUTPUT_DIR)/%=%) -> $(2:$(OUTPUT_DIR)/%=%)"; [ -f $(1) ] && ln -sf $(LNHEADER_FLAGS) $(1) $(2) ) +endef +endif + +# TODO: Check modification date of changed header files. If it is +# newer that in source dir, show a warning. + +# Syntax: $(call include-pass-template,,) +define include-pass-template +include-pass-local: include-pass-local-$(2) +include-pass-local-$(2): $$($(2)_GEN_HEADERS) $$(foreach f,$$(renamed_$(2)_GEN_HEADERS),$$(shell echo '$$(f)' | sed -e 's/^\(.*\)->.*$$$$/\1/')) + @$$(foreach f, $$($(2)_HEADERS), cmp --quiet $$(SOURCES_DIR)/$$(f) $(1)/$$(notdir $$(f)) \ + || $$(call cp_cmd,$$(SOURCES_DIR)/$$(f),$(1)/$$(notdir $$(f))) || exit 1 ; ) + @$$(foreach f, $$($(2)_GEN_HEADERS), cmp --quiet $$(f) $(1)/$$(notdir $$(f)) \ + || $$(call cp_cmd,$$(LOCAL_BUILD_DIR)/$$(f),$(1)/$$(notdir $$(f))) || exit 1 ; ) # FIXME: Use correct build dir, then document it + @$$(foreach f, $$(nobase_$(2)_HEADERS), cmp --quiet $$(SOURCES_DIR)/$$(f) $(1)/$$(f) \ + || ( mkdir -p $(1)/$$(dir $$(f)) && $$(call cp_cmd,$$(SOURCES_DIR)/$$(f),$(1)/$$(f)) ) || exit 1 ; ) + @$$(foreach f, $$(renamed_$(2)_HEADERS), \ + srcfname=`echo '$$(f)' | sed -e 's/^\(.*\)->.*$$$$/\1/'` ; destfname=`echo '$$(f)' | sed -e 's/^.*->\(.*\)$$$$/\1/'` ; \ + cmp --quiet $$(SOURCES_DIR)/$$$${srcfname} $(1)/$$$${destfname} \ + || ( mkdir -p `dirname $(1)/$$$${destfname}` && $$(call cp_cmd,$$(SOURCES_DIR)/$$$${srcfname},$(1)/$$$${destfname}) ) || exit 1 ; ) + @$$(foreach f, $$(renamed_$(2)_GEN_HEADERS), \ + srcfname=`echo '$$(f)' | sed -e 's/^\(.*\)->.*$$$$/\1/'` ; destfname=`echo '$$(f)' | sed -e 's/^.*->\(.*\)$$$$/\1/'` ; \ + cmp --quiet $$$${srcfname} $(1)/$$$${destfname} \ + || ( mkdir -p `dirname $(1)/$$$${destfname}` && $$(call cp_cmd,$$(LOCAL_BUILD_DIR)/$$$${srcfname},$(1)/$$$${destfname}) ) || exit 1 ; ) +endef + +# Local Variables: +# mode:makefile +# End: + #OMK@sysless +BUILD_DIR_NAME = _build$(addprefix /,$(PREFIX_DIR)) +COMPILED_DIR_NAME = _compiled$(addprefix /,$(PREFIX_DIR)) + +LOCAL_BUILD_DIR=$(MAKERULES_DIR)/$(BUILD_DIR_NAME)/$(RELATIVE_DIR) +#$(warning LOCAL_BUILD_DIR = $(LOCAL_BUILD_DIR)) + +#===================================================================== +# Common utility rules + +link_VARIANTS ?= $(DEFAULT_LD_SCRIPT_VARIANT) + + +#===================================================================== +# Include correct rules for just running pass + +USER_COMPILED_DIR_NAME=$(MAKERULES_DIR)/$(COMPILED_DIR_NAME) + +USER_INCLUDE_DIR = $(USER_COMPILED_DIR_NAME)/include +USER_LIB_DIR = $(USER_COMPILED_DIR_NAME)/lib +USER_UTILS_DIR = $(USER_COMPILED_DIR_NAME)/bin-utils +USER_TESTS_DIR = $(USER_COMPILED_DIR_NAME)/bin-tests +USER_BIN_DIR = $(USER_COMPILED_DIR_NAME)/bin +USER_OBJS_DIR = $(LOCAL_BUILD_DIR) + +.PHONY: check-dir + +# Some support to serialize some targets for parallel make +ifneq ($(OMK_SERIALIZE_INCLUDED),y) +include-pass: check-dir +library-pass: include-pass +binary-pass utils-pass: library-pass + +override OMK_SERIALIZE_INCLUDED = y +MAKEOVERRIDES := $(filter-out OMK_SERIALIZE_INCLUDED=n,$(MAKEOVERRIDES)) +endif + +# ------------------------------------- +# Rules for compilation for target +ifdef TARGET_RULE_TEMPLATES + +LDFLAGS += -nostartfiles + + # FIXME: These are not used. What they are good for? +LIB_CPPFLAGS += $(CPPFLAGS) +LIB_CFLAGS += $(CFLAGS) + +SOLIB_PICFLAGS += -shared -fpic + +CFLAGS += -DOMK_FOR_TARGET + +INCLUDE_DIR := $(USER_INCLUDE_DIR) +LIB_DIR := $(USER_LIB_DIR) +OBJS_DIR := $(USER_OBJS_DIR) + +$(eval $(COMPILER_DEFS_template)) + +# Special rules for CMETRIC generated headers + +$(foreach cmetrh,$(cmetric_include_HEADERS),$(eval $(call COMPILE_c_o_template,\ + $(SOURCES_DIR)/$($(basename $(notdir $(cmetrh)))_CMETRIC_SOURCES),\ + $($(basename $(notdir $(cmetrh)))_CMETRIC_SOURCES:%.c=%.o),))) +$(foreach cmetrh,$(cmetric_include_HEADERS),$(eval $(call CMETRIC_o_h_template,\ + $($(basename $(notdir $(cmetrh)))_CMETRIC_SOURCES:%.c=%.o),\ + $(addprefix $(USER_INCLUDE_DIR)/,$(cmetrh))))) + +GEN_HEADERS+=$(cmetric_include_HEADERS:%=$(USER_INCLUDE_DIR)/%) + +# Generate rules for compilation of programs and libraries +ifneq ($(link_VARIANTS),) +$(foreach prog,$(bin_PROGRAMS),$(foreach link,$(link_VARIANTS),$(eval $(call PROGRAM_template,$(prog),$(USER_BIN_DIR),$(link))))) +$(foreach prog,$(test_PROGRAMS),$(foreach link,$(link_VARIANTS),$(eval $(call PROGRAM_template,$(prog),$(USER_TESTS_DIR),$(link))))) +else +$(foreach prog,$(bin_PROGRAMS),$(eval $(call PROGRAM_template,$(prog),$(USER_BIN_DIR)))) +$(foreach prog,$(test_PROGRAMS),$(eval $(call PROGRAM_template,$(prog),$(USER_TESTS_DIR)))) +endif + +$(foreach lib,$(lib_LIBRARIES),$(eval $(call LIBRARY_template,$(lib)))) +$(foreach src,$(lib_obj_SOURCES),$(eval $(call LIBOBJ_template,$(addsuffix $(OBJ_EXT),$(basename $(src)))))) +$(foreach lib,$(shared_LIBRARIES),$(eval $(call SOLIB_template,$(lib)))) + + +# lib_obj_SOURCES handling +lib_OBJS = $(addsuffix $(OBJ_EXT),$(basename $(lib_obj_SOURCES))) +#$(warning lib_OBJS = $(lib_OBJS)) +SOURCES += $(filter-out %$(OBJ_EXT),$(lib_obj_SOURCES)) + +$(LIB_DIR)/%$(OBJ_EXT): %$(OBJ_EXT) + @echo " CP $(^:$(MAKERULES_DIR)/%=%) -> $(@:$(MAKERULES_DIR)/%=%)" + $(Q)cp $(CP_FLAGS) $< $@ + + +# User-space static libraries and applications object files +SOURCES := $(sort $(SOURCES)) +#$(warning SOURCES = $(SOURCES)) + +# User-space shared libraries object files +SOLIB_SOURCES := $(sort $(SOLIB_SOURCES)) +#$(warning SOLIB_SOURCES = $(SOLIB_SOURCES)) + + +# The above generated rules produced $(SOURCES) and $(SOLIB_SOURCES) +# variables. Now generate rules for compilation of theese sources +$(foreach src,$(filter %.c,$(SOURCES)),$(eval $(call COMPILE_c_o_template,$(SOURCES_DIR)/$(src),$(src:%.c=%$(OBJ_EXT)),))) +$(foreach src,$(filter %.cc,$(SOURCES)),$(eval $(call COMPILE_cc_o_template,$(SOURCES_DIR)/$(src),$(src:%.cc=%$(OBJ_EXT)),))) +$(foreach src,$(filter %.cxx,$(SOURCES)),$(eval $(call COMPILE_cc_o_template,$(SOURCES_DIR)/$(src),$(src:%.cxx=%$(OBJ_EXT)),))) +$(foreach src,$(filter %$(ASM_EXT),$(SOURCES)),$(eval $(call COMPILE_S_o_template,$(SOURCES_DIR)/$(src),$(src:%$(ASM_EXT)=%$(OBJ_EXT)),))) + +$(foreach src,$(filter %.c,$(SOLIB_SOURCES)),$(eval $(call COMPILE_c_o_template,$(SOURCES_DIR)/$(src),$(src:%.c=%.lo),$(SOLIB_PICFLAGS)))) +$(foreach src,$(filter %.cc,$(SOLIB_SOURCES)),$(eval $(call COMPILE_cc_o_template,$(SOURCES_DIR)/$(src),$(src:%.cc=%.lo),$(SOLIB_PICFLAGS)))) +$(foreach src,$(filter %.cxx,$(SOLIB_SOURCES)),$(eval $(call COMPILE_cc_o_template,$(SOURCES_DIR)/$(src),$(src:%.cxx=%.lo),$(SOLIB_PICFLAGS)))) +$(foreach src,$(filter %$(ASM_EXT),$(SOLIB_SOURCES)),$(eval $(call COMPILE_S_o_template,$(SOURCES_DIR)/$(src),$(src:%$(ASM_EXT)=%.lo),$(SOLIB_PICFLAGS)))) + +library-pass-local: $(addprefix $(USER_INCLUDE_DIR)/,$(cmetric_include_HEADERS)) \ + $(lib_LIBRARIES:%=$(LIB_DIR)/$(LIB_PREF)%$(LIB_EXT)) $(shared_LIBRARIES:%=$(LIB_DIR)/$(LIB_PREF)%.so) \ + $(addprefix $(LIB_DIR)/,$(lib_OBJS)) + +ifneq ($(link_VARIANTS),) +binary-pass-local: $(foreach link,$(link_VARIANTS),$(bin_PROGRAMS:%=$(USER_BIN_DIR)/%-$(link)) $(test_PROGRAMS:%=$(USER_TESTS_DIR)/%-$(link)) \ + $(foreach of,$(OUTPUT_FORMATS),$(bin_PROGRAMS:%=$(USER_BIN_DIR)/%-$(link).$(of)) $(test_PROGRAMS:%=$(USER_TESTS_DIR)/%-$(link).$(of)))) +else +binary-pass-local: $(bin_PROGRAMS:%=$(USER_BIN_DIR)/%) $(test_PROGRAMS:%=$(USER_TESTS_DIR)/%) \ + $(foreach of,$(OUTPUT_FORMATS),$(bin_PROGRAMS:%=$(USER_BIN_DIR)/%.$(of)) $(test_PROGRAMS:%=$(USER_TESTS_DIR)/%.$(of))) +endif + +endif # TARGET_RULE_TEMPLATES + + +# ------------------------------------- +# Rules for compilation utilities for host (user space) +ifdef HOST_RULE_TEMPLATES + +CROSS_COMPILE = +TARGET_ARCH = + +SOLIB_PICFLAGS += -shared -fpic + +# For host compilation, we don't use a specfic ld script +LD_SCRIPT = + +# TODO: It is probably better to use different directories for host +# includes, libraries and objects +INCLUDE_DIR := $(USER_INCLUDE_DIR) +LIB_DIR := $(USER_LIB_DIR) +OBJS_DIR := $(USER_OBJS_DIR) + +$(eval $(COMPILER_DEFS_template)) + + #User-space static libraries and applications object files +#SOURCES := $(sort $(SOURCES)) +#$(warning SOURCES = $(SOURCES)) + +# Generate rules for compilation of utility programs +$(foreach prog,$(utils_PROGRAMS),$(eval $(call PROGRAM_template,$(prog),$(USER_UTILS_DIR),))) + +# The above generated rule produced $(SOURCES) variable. Now generate +# rules for compilation of theese sources +$(foreach src,$(filter %.c,$(SOURCES)),$(eval $(call COMPILE_c_o_template,$(SOURCES_DIR)/$(src),$(src:%.c=%$(OBJ_EXT)),))) +$(foreach src,$(filter %.cc,$(SOURCES)),$(eval $(call COMPILE_cc_o_template,$(SOURCES_DIR)/$(src),$(src:%.cc=%$(OBJ_EXT)),))) +$(foreach src,$(filter %.cxx,$(SOURCES)),$(eval $(call COMPILE_cc_o_template,$(SOURCES_DIR)/$(src),$(src:%.cxx=%$(OBJ_EXT)),))) +$(foreach src,$(filter %$(ASM_EXT),$(SOURCES)),$(eval $(call COMPILE_S_o_template,$(SOURCES_DIR)/$(src),$(src:%$(ASM_EXT)=%$(OBJ_EXT)),))) + +utils-pass-local: $(utils_PROGRAMS:%=$(USER_UTILS_DIR)/%) + +endif # HOST_RULE_TEMPLATES + +# Checks for OMK tester +ifdef OMK_TESTSROOT +default-config-pass-check include-pass-check: +library-pass-check binary-pass-check: + @[ -x "$(shell which $(CC))" ] || $(call canttest,Cannot find compiler: $(CC)) +endif + +#===================================================================== +# Automatic loading of compiled program by issuing "make load" + +ifneq ($(OUTPUT_FORMATS),) +# Select a file extension (e.g. .bin) for "make load" command to load. +LOAD_EXTENSION = .$(firstword $(OUTPUT_FORMATS)) +endif + +# Syntax: $(call LOAD_PROGRAM_template,,,) +# Used to load program to the target hardware +define LOAD_PROGRAM_template +.PHONY: load-$(1)$(3:%=-%) +load-$(1)$(3:%=-%): $(2)/$(1)$(3:%=-%)$(LOAD_EXTENSION) + @$(QUIET_CMD_ECHO) " LOAD $$<" + @if [ -z '$$(LOAD_CMD$(3:%=-%))' ]; then echo "No command for loading applications to '$(3)' is specified."; exit 1; fi + $(Q) $$(LOAD_CMD$(3:%=-%)) $$< +endef + +# Syntax: $(call LOAD__RUN_VARIANT_template,) +# Used to load and/or run non-default variant of the default program +define LOAD_RUN_VARIANT_template +.PHONY: load-$(1) run-$(1) + +load-$(1): load-$(firstword $(bin_PROGRAMS) $(test_PROGRAMS))-$(1) + +run-$(1): + @$(QUIET_CMD_ECHO) " RUN $(1)" + @if [ -z "$(RUN_CMD-$(1))" ]; then echo "No command for running '$(1)' variant is specified."; exit 1; fi + $(Q) $(RUN_CMD-$(1)) + +endef + +$(foreach link,$(link_VARIANTS),$(foreach prog,$(bin_PROGRAMS),$(eval $(call LOAD_PROGRAM_template,$(prog),$(USER_BIN_DIR),$(link))))) +$(foreach link,$(link_VARIANTS),$(foreach prog,$(test_PROGRAMS),$(eval $(call LOAD_PROGRAM_template,$(prog),$(USER_TESTS_DIR),$(link))))) +$(foreach link,$(link_VARIANTS),$(eval $(call LOAD_RUN_VARIANT_template,$(link)))) + +.PHONY: load run +load: $(addprefix load-,$(firstword $(bin_PROGRAMS) $(test_PROGRAMS))-$(firstword $(link_VARIANTS))) + +run: run-$(firstword $(link_VARIANTS)) + + + +#===================================================================== +# Generate pass rules from generic templates + +$(eval $(call omk_pass_template, include-pass, $(LOCAL_BUILD_DIR),,$(include_HEADERS)$(nobase_include_HEADERS)$(renamed_include_HEADERS)$(lib_LDSCRIPTS)$(config_include_HEADERS)$(LOCAL_CONFIG_H))) +$(eval $(call omk_pass_template, library-pass, $(LOCAL_BUILD_DIR),TARGET_RULE_TEMPLATES=y,$(lib_LIBRARIES)$(shared_LIBRARIES)$(lib_obj_SOURCES))) +$(eval $(call omk_pass_template, binary-pass, $(LOCAL_BUILD_DIR),TARGET_RULE_TEMPLATES=y,$(bin_PROGRAMS) $(test_PROGRAMS))) +$(eval $(call omk_pass_template, utils-pass, $(LOCAL_BUILD_DIR),HOST_RULE_TEMPLATES=y,$(utils_PROGRAMS))) +$(eval $(call omk_pass_template, dep, $(LOCAL_BUILD_DIR),,always)) +$(eval $(call omk_pass_template, clean, $(LOCAL_BUILD_DIR),,always)) +$(eval $(call omk_pass_template, install,$(LOCAL_BUILD_DIR),,always)) + + +dep-local: + +install-local: + +$(eval $(call include-pass-template,$(USER_INCLUDE_DIR),include)) + +include-pass-local: + @$(foreach f, $(lib_LDSCRIPTS), cmp --quiet $(SOURCES_DIR)/$(f) $(USER_LIB_DIR)/$(notdir $(f)) \ + || $(call cp_cmd,$(SOURCES_DIR)/$(f),$(USER_LIB_DIR)/$(notdir $(f))) || exit 1 ; ) + + +.PHONY: clean-custom +clean-local: clean-custom + $(Q)rm -f $(USER_OBJS_DIR)/*.o $(USER_OBJS_DIR)/*.lo \ + $(USER_OBJS_DIR)/*.d \ + $(USER_OBJS_DIR)/*.map \ + $(LOCAL_CONFIG_H:%=$(USER_OBJS_DIR)/%) + +check-dir: + @$(call mkdir_def,$(USER_INCLUDE_DIR)) + @$(call mkdir_def,$(USER_LIB_DIR)) + @$(call mkdir_def,$(USER_BIN_DIR)) + @$(call mkdir_def,$(USER_UTILS_DIR)) + @$(call mkdir_def,$(USER_TESTS_DIR)) + +include-pass-submakes: extra-rules-subdirs +# Which passes to pass +default: include-pass library-pass binary-pass utils-pass + +# Local Variables: +# mode:makefile +# End: + #OMK@config_h +# Syntax: $(call BUILD_CONFIG_H_template,,,,) +define BUILD_CONFIG_H_template + +$(addprefix $(1)/,$(notdir $(addsuffix .stamp,$(2)))) : $(CONFIG_FILES) + @$(QUIET_CMD_ECHO) " CONFGEN $$(@:%.stamp=%)" + @if [ ! -d `dirname $(2).tmp` ] ; then \ + mkdir -p `dirname $(2).tmp` ; fi + @echo "/* Automatically generated from */" > "$(2).tmp" + @echo "/* config files: $$(^:$(OUTPUT_DIR)/%=%) */" >> "$(2).tmp" + $(if $(DOXYGEN),@echo "/** @file */" >> "$(2).tmp") + @echo "#ifndef $(4)" >> "$(2).tmp" + @echo "#define $(4)" >> "$(2).tmp" + @( $(foreach x, $(shell echo '$($(3))' | tr 'x\t ' 'x\n\n' | sed -e 's/^\([^ =]*\)\(=[^ ]\+\|\)$$/\1/' ), \ + echo '$(x).$($(x))' ; ) echo ; ) | \ + sed -e '/^[^.]*\.n$$$$/d' -e '/^[^.]*\.$$$$/d' -e 's/^\([^.]*\)\.[ym]$$$$/\1.1/' | \ + sed -n -e 's/^\([^.]*\)\.\(.*\)$$$$/#define \1 \2/p' \ + >> "$(2).tmp" + @echo "#endif /*$(4)*/" >> "$(2).tmp" + @touch "$$@" + @if cmp --quiet "$(2).tmp" "$(2)" ; then rm "$(2).tmp"; \ + else mv "$(2).tmp" "$(2)" ; \ + echo "Updated configuration $(2)" ; fi + +endef + +ifdef LOCAL_CONFIG_H + +# This must be declared after the default cflags are assigned! +# Override is used to override command line assignemnt. +override CFLAGS += -I $(USER_OBJS_DIR) +override kernel_INCLUDES += -I $(KERN_OBJS_DIR) +$(eval $(call BUILD_CONFIG_H_template,$(USER_OBJS_DIR),$(USER_OBJS_DIR)/$(LOCAL_CONFIG_H),default_CONFIG,_LOCAL_CONFIG_H) ) + +endif + +# Special rules for configuration exported headers + +#FIXME: The directory for headers should not be specified here. +$(foreach confh,$(config_include_HEADERS),$(eval $(call BUILD_CONFIG_H_template,$(USER_OBJS_DIR),$(addprefix $(USER_INCLUDE_DIR)/,$(confh)),$(basename $(notdir $(confh)))_DEFINES,\ +_$(basename $(notdir $(confh)))_H \ +))) + +config_h_stamp_files = $(addprefix $(USER_OBJS_DIR)/,$(notdir $(addsuffix .stamp,$(config_include_HEADERS) $(LOCAL_CONFIG_H)))) + +# Add some hooks to standard passes +include-pass-local: $(config_h_stamp_files) + +ifneq ($(KERN_CONFIG_HEADERS_REQUIRED),) + +ifdef LOCAL_CONFIG_H +$(eval $(call BUILD_CONFIG_H_template,$(KERN_OBJS_DIR),$(KERN_OBJS_DIR)/$(LOCAL_CONFIG_H),default_CONFIG,_LOCAL_CONFIG_H) ) +endif + +$(foreach confh,$(config_include_HEADERS),$(eval $(call BUILD_CONFIG_H_template,$(KERN_OBJS_DIR),$(addprefix $(KERN_INCLUDE_DIR)/,$(confh)),$(basename $(notdir $(confh)))_DEFINES,\ +_$(basename $(notdir $(confh)))_H \ +))) + +kern_config_h_stamp_files = $(addprefix $(KERN_OBJS_DIR)/,$(notdir $(addsuffix .stamp,$(config_include_HEADERS) $(LOCAL_CONFIG_H)))) + +# Add some hooks to standard passes +include-pass-local: $(kern_config_h_stamp_files) + +endif + +clean-local: clean-local-config-h + +clean-local-config-h: + @$(foreach confh,$(config_h_stamp_files) $(kern_config_h_stamp_files),\ + if [ -e $(confh) ] ; then rm $(confh) ; fi ; \ + ) + + +# Local Variables: +# mode:makefile +# End: + #OMK@sources-list +# Rules that creates the list of files which are used during +# compilation. The list reflects conditional compilation depending on +# config.omk and other variables. + +SOURCES_LIST_FN=sources.txt +ifndef SOURCES_LIST +SOURCES_LIST_DIR:=$(RELATIVE_DIR) +SOURCES_LIST:=$(OUTPUT_DIR)/$(SOURCES_LIST_DIR)/$(SOURCES_LIST_FN) +SOURCES_LIST_D := $(LOCAL_BUILD_DIR)/$(SOURCES_LIST_FN).d +export SOURCES_LIST SOURCES_LIST_DIR SOURCES_LIST_D +endif + +ifeq ($(MAKECMDGOALS),sources-list) +NEED_SOURCES_LIST=y +endif +ifeq ($(MAKECMDGOALS),TAGS) +NEED_SOURCES_LIST=y +endif +ifeq ($(MAKECMDGOALS),tags) +NEED_SOURCES_LIST=y +endif + +ifeq ($(NEED_SOURCES_LIST),y) # avoid execution of find command bellow if it is not useful +.PHONY: sources-list +sources-list: $(SOURCES_LIST) + +$(SOURCES_LIST): $(CONFIG_FILES) $(shell find -name $(MAKEFILE_OMK)) + @$(call mkdir_def,$(dir $(SOURCES_LIST_D))) + @echo -n "" > "$(SOURCES_LIST).tmp" + @echo -n "" > "$(SOURCES_LIST_D).tmp" + @$(MAKE) --no-print-directory sources-list-pass + @echo "# Automatically generated list of files in '$(RELATIVE_DIR)' that are used during OMK compilation" > "$(SOURCES_LIST).tmp2" + @cat "$(SOURCES_LIST).tmp"|sort|uniq >> "$(SOURCES_LIST).tmp2" + @rm "$(SOURCES_LIST).tmp" + @mv "$(SOURCES_LIST).tmp2" "$(SOURCES_LIST)" + @echo "$(SOURCES_LIST): \\" > "$(SOURCES_LIST_D).tmp2" + @cat "$(SOURCES_LIST_D).tmp"|grep -v "$(SOURCES_LIST_D).tmp"|sort|uniq|\ + sed -e 's/$$/\\/' >> "$(SOURCES_LIST_D).tmp2" + @rm "$(SOURCES_LIST_D).tmp" + @mv "$(SOURCES_LIST_D).tmp2" "$(SOURCES_LIST_D)" +endif + +$(eval $(call omk_pass_template,sources-list-pass,$$(LOCAL_BUILD_DIR),,always)) + +sources-list-pass-local: + @$(foreach m,$(MAKEFILE_LIST),echo ' $(m)' >> "$(SOURCES_LIST_D).tmp";) + @$(foreach h,$(include_HEADERS) $(nobase_include_HEADERS) $(kernel_HEADERS),\ + echo "$(addsuffix /,$(RELATIVE_DIR:$(SOURCES_LIST_DIR)/%=%))$(h)" >> "$(SOURCES_LIST).tmp";) + @$(foreach ch,$(config_include_HEADERS), \ + echo "$(USER_INCLUDE_DIR:$(OUTPUT_DIR)/$(addsuffix /,$(SOURCES_LIST_DIR))%=%)/$(ch)" >> "$(SOURCES_LIST).tmp";) + @$(foreach h,$(renamed_include_HEADERS),echo '$(h)'|sed -e 's|\(.*\)->.*|$(addsuffix /,$(RELATIVE_DIR:$(SOURCES_LIST_DIR)/%=%))\1|' >> "$(SOURCES_LIST).tmp";) + @$(foreach bin,$(lib_LIBRARIES) $(shared_LIBRARIES) $(bin_PROGRAMS) $(test_PROGRAMS) $(utils_PROGRAMS) \ + $(kernel_LIBRARIES) $(rtlinux_LIBRARIES) $(kernel_MODULES),\ + $(foreach src,$(filter-out %.o,$($(bin)_SOURCES)),echo "$(addsuffix /,$(RELATIVE_DIR:$(SOURCES_LIST_DIR)/%=%))$(src)" >> "$(SOURCES_LIST).tmp";)) + +############ TAGS ########### + +ifeq ($(MAKECMDGOALS),TAGS) +ETAGS=etags +TAGS_CMD = $(ETAGS) +TAGS: $(SOURCES_LIST) + @$(MAKE) --no-print-directory do-tags +endif +ifeq ($(MAKECMDGOALS),tags) +CTAGS=ctags -N +TAGS_CMD = $(CTAGS) +tags: $(SOURCES_LIST) + @$(MAKE) --no-print-directory do-tags +endif +export TAGS_CMD + +ifeq ($(MAKECMDGOALS),do-tags) +.PHONY: do-tags +do-tags: $(shell sed -e '/^\#/d' $(SOURCES_LIST)) + @$(QUIET_CMD_ECHO) " TAGS $(SOURCES_LIST_FN)" + $(Q)$(TAGS_CMD) $^ +endif + +############ CSCOPE ########### + +cscope: $(SOURCES_LIST) + @$(QUIET_CMD_ECHO) " CSCOPE < $(SOURCES_LIST_FN)" + $(Q)sed -e '/^#/d' $(SOURCES_LIST)|cscope -b -i- +#FIXME: see doc to -i in cscope(1) + +# Local Variables: +# mode:makefile +# End: + #OMK@localeval +ifneq ($(local_EVALUATE),) +#$(warning $(local_EVALUATE)) +$(eval $(local_EVALUATE)) +endif + +# Local Variables: +# mode:makefile +# End: