From: Jan Kriz Date: Sun, 6 Jul 2008 08:59:31 +0000 (+0200) Subject: skeleton of ul_usb1-can module (doesn't work yet) X-Git-Tag: CLT_COMM_CAN_usb_can1_kriz_bp~22 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/a0ec4dd6a947bc0bb5775ba1455ade73fa405d35 skeleton of ul_usb1-can module (doesn't work yet) --- diff --git a/embedded/app/Makefile.omk b/embedded/app/Makefile.omk index ff939fc..fd0ecae 100644 --- a/embedded/app/Makefile.omk +++ b/embedded/app/Makefile.omk @@ -1,4 +1,4 @@ # -*- makefile -*- -SUBDIRS = +SUBDIRS = usbcan diff --git a/embedded/app/usbcan/Makefile b/embedded/app/usbcan/Makefile new file mode 100644 index 0000000..f595272 --- /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..24985a6 --- /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 usb_srq.c can.c can_queue.c sja1000p.c can_quesysless.c + +#usbtest_SOURCES += ul_idstr.c +#lib_LOADLIBES = bspbase ul_drv lpciap keyval lpciap_kvpb mach_hal uldy +lib_LOADLIBES = bspbase usbbase 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 = boot + +endif #CONFIG_ULBOOT diff --git a/embedded/app/usbcan/can.c b/embedded/app/usbcan/can.c new file mode 100644 index 0000000..ae9d530 --- /dev/null +++ b/embedded/app/usbcan/can.c @@ -0,0 +1,272 @@ +/** +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" + +/// Baud rates +#if SJA1000_CLK==(24000000) + /* Bus speed, Precaler, SJW, TSEG1, TSEG2 + * For SJW setting we assume 1% xtal accuracy + */ + const long sja1000_freqs[3][5]= + {{1000, 0x00, 0xC0, 0x08, 0x10} + ,{250, 0x02, 0xC0, 0x0A, 0x30} + ,{100, 0x07, 0xC0, 0x09, 0x30}}; + const int sja1000_freq_cnt=3; +#endif + +struct can_baudparams_t canbaud; + +void can_comm_init() +{ + // 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); + for (slowdown=0;slowdown<20*SJA1000_SCLK;slowdown++); + 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); + for (slowdown=0;slowdown<20*SJA1000_SCLK;slowdown++); + +} + +int can_write(uint8_t address,uint8_t* data) +{ + IO1DIR|=0x00FF0000; // Port as output to send data + IO1CLR=0x00FF0000; // Clear all data on port + // 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 + for (slowdown=0;slowdown 50) + return -1; + } while (!(data&sjaMOD_RM)); + + data=sjaCDR_CLKOUT_DIV1|sjaCDR_CLK_OFF|sjaCDR_CBP|sjaCDR_PELICAN; + can_write((uint8_t)SJACDR,(uint8_t*)&data); + + // Single acceptance filter, reset mode + data=sjaMOD_AFM|sjaMOD_RM; + can_write((uint8_t)SJAMOD,(uint8_t*)&data); + + // Enabling all interrupt sources + data=sjaENABLE_INTERRUPTS; + can_write((uint8_t)SJAIER,(uint8_t*)&data); + + // Accept all messages + data=0xFF; + can_write((uint8_t)SJAAMR0,(uint8_t*)&data); + can_write((uint8_t)SJAAMR0+1,(uint8_t*)&data); + can_write((uint8_t)SJAAMR0+2,(uint8_t*)&data); + can_write((uint8_t)SJAAMR0+3,(uint8_t*)&data); + + data=sjaCMR_CDO; + can_write((uint8_t)SJACMR,(uint8_t*)&data); + + return 0; +} + +int can_autobaud(int tries){ + uint8_t data=0; + int i=0,j,baudset=0; + // Single acceptance filter, reset mode, listen mode for baud determination + data=sjaMOD_LOM|sjaMOD_AFM|sjaMOD_RM; + can_write((uint8_t)SJAMOD,(uint8_t*)&data); + do { + canbaud.baudrate=sja1000_freqs[i][0]*1000; + canbaud.sjw=(sja1000_freqs[i][1]&0x3F)|(sja1000_freqs[i][2]&0xC0); + canbaud.sample_pt=(sja1000_freqs[i][3]&0x0F)|(sja1000_freqs[i][4]&0x70); + can_write(SJABTR0,(uint8_t *)(&canbaud.sjw)); + can_write(SJABTR1,(uint8_t *)(&canbaud.sample_pt)); + uint8_t intstor,temp; + can_read(SJAIER,&intstor); + temp=sjaIER_RIE|sjaIER_BEIE; + can_write(SJAIER,&temp); + + /// Leave reset mode + can_read(SJAMOD,&temp); + temp&=~sjaMOD_RM; + can_write(SJAMOD,&temp); + j=0; + do{ + can_read(SJAMOD,&temp); + if (j++>20) + return -1; + } while (temp&sjaMOD_RM); + + /// Wait for successfull packet receive or receive error + j=0; + while (!(IO0PIN & P0_SJA1000_INT_PIN)){ + } + + can_read(SJAIR,&temp); + if (temp & sjaIR_RI) + baudset=1; + + /// Back to reset + can_read(SJAMOD,&temp); + temp|=sjaMOD_RM; + can_write(SJAMOD,&temp); + j=0; + do{ + can_read(SJAMOD,&temp); + if (j++>20) + return -1; + } while (!(temp&sjaMOD_RM)); + + if (++i==sja1000_freq_cnt) + return -1; + } while (baudset==0); + return 0; +} + +int can_poll(){ + + return 0; +} + +int can_transmit_direct(uint8_t *data){ + int len=0,ext=0,i; + uint8_t *ptr=data,tmitptr,temp; + ext=(*ptr)& sjaFRM_FF; + len=(*ptr)& 0xFF; + + // check if transmit buffer is free + do { + if (can_poll()==-1) + return -1; + can_read(SJASR,&temp); + temp&=sjaSR_TBS; + } while (!temp); + + tmitptr=SJAFRM; + can_write(tmitptr++,data++); // Header + can_write(tmitptr++,data++); // Ident 1 + can_write(tmitptr++,data++); // Ident 2 + if (ext){ + can_write(tmitptr++,data++); // Ident 3 + can_write(tmitptr++,data++); // Ident 4 + } + for (i=0;i8?0x08:numbytes); + can_write(tmitptr++,&temp); // Header + + can_write(tmitptr++,mask++); // Ident 1 + can_write(tmitptr++,mask++); // Ident 2 + if (ext_header){ + can_write(tmitptr++,mask++); // Ident 3 + can_write(tmitptr++,mask++); // Ident 4 + } + for (i=0;i<(numbytes>8?0x08:numbytes);i++) + can_write(tmitptr++,data++); // Data i; + + // Set TR bit + temp=sjaCMR_TR; + can_write(SJACMR,&temp); + + return 0; +} + +int can_receive(uint8_t len,uint8_t *data){ + + + return 0; +} diff --git a/embedded/app/usbcan/can/can.h b/embedded/app/usbcan/can/can.h new file mode 100644 index 0000000..38c68dd --- /dev/null +++ b/embedded/app/usbcan/can/can.h @@ -0,0 +1,70 @@ +#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 + */ + + /* + NOP count for synchronizing 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 */ + + volatile int slowdown; + +/** + * struct can_baudparams_t - datatype for calling CONF_BAUDPARAMS IOCTL + * @flags: reserved for additional flags for chip configuration, should be written -1 or 0 + * @baudrate: baud rate in Hz + * @sjw: synchronization jump width (0-3) prescaled clock cycles + * @sampl_pt: sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio + * + * The structure is used to configure new set of parameters into CAN controller chip. + * If default value of some field should be preserved, fill field by value -1. + */ +struct can_baudparams_t { + long flags; + long baudrate; + long sjw; + long sample_pt; +}; + +extern int can_init(); +extern int can_autobaud(int tries); +extern int can_read(uint8_t address,uint8_t *data); +extern int can_write(uint8_t address,uint8_t *data); + +extern int can_set_mask(int dual_mask,int count,uint8_t *mask,uint8_t *accept); + +extern int can_poll(); +extern int can_transmit_direct(uint8_t *data); +//int can_transmit(char ext_header,char rtr,int mask_size,uint8_t *mask,int numbytes,uint8_t *data); +extern int can_transmit(int ext_header,int rtr,uint8_t *mask,int numbytes,uint8_t *data); +//int can_receive(uint8_t *data); +extern int can_receive(uint8_t len,uint8_t *data); + +#endif /* SJA1000_CAN_H */ diff --git a/embedded/app/usbcan/can/can_queue.h b/embedded/app/usbcan/can/can_queue.h new file mode 100644 index 0000000..42eeef4 --- /dev/null +++ b/embedded/app/usbcan/can/can_queue.h @@ -0,0 +1,809 @@ +/* can_queue.h - CAN queues and message passing infrastructure + * 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_QUEUE_H +#define _CAN_QUEUE_H + +#include "./canmsg.h" +#include "./constants.h" +#include "./can_sysdep.h" + +/** + * struct canque_slot_t - one CAN message slot in the CAN FIFO queue + * @next: pointer to the next/younger slot + * @slot_flags: space for flags and optional command describing action + * associated with slot data + * @msg: space for one CAN message + * + * This structure is used to store CAN messages in the CAN FIFO queue. + */ + struct canque_slot_t { + struct canque_slot_t *next; + unsigned long slot_flags; + struct canmsg_t msg; +}; + +#define CAN_SLOTF_CMD 0x00ff /* */ + +/** + * struct canque_fifo_t - CAN FIFO queue representation + * @fifo_flags: this field holds global flags describing state of the FIFO. + * %CAN_FIFOF_ERROR is set when some error condition occurs. + * %CAN_FIFOF_ERR2BLOCK defines, that error should lead to the FIFO block state. + * %CAN_FIFOF_BLOCK state blocks insertion of the next messages. + * %CAN_FIFOF_OVERRUN attempt to acquire new slot, when FIFO is full. + * %CAN_FIFOF_FULL indicates FIFO full state. + * %CAN_FIFOF_EMPTY indicates no allocated slot in the FIFO. + * %CAN_FIFOF_DEAD condition indication. Used when FIFO is beeing destroyed. + * @error_code: futher description of error condition + * @head: pointer to the FIFO head, oldest slot + * @tail: pointer to the location, where pointer to newly inserted slot + * should be added + * @flist: pointer to list of the free slots associated with queue + * @entry: pointer to the memory allocated for the list slots. + * @fifo_lock: the lock to ensure atomicity of slot manipulation operations. + * @slotsnr: number of allocated slots + * + * This structure represents CAN FIFO queue. It is implemented as + * a single linked list of slots prepared for processing. The empty slots + * are stored in single linked list (@flist). + */ +struct canque_fifo_t { + unsigned long fifo_flags; + unsigned long error_code; + struct canque_slot_t *head; /* points to the oldest entry */ + struct canque_slot_t **tail; /* points to NULL pointer for chaining */ + struct canque_slot_t *flist; /* points the first entry in the free list */ + struct canque_slot_t *entry; /* points to first allocated entry */ + can_spinlock_t fifo_lock; /* can_spin_lock_irqsave / can_spin_unlock_irqrestore */ + int slotsnr; +}; + +#define CAN_FIFOF_DESTROY_b 15 +#define CAN_FIFOF_ERROR_b 14 +#define CAN_FIFOF_ERR2BLOCK_b 13 +#define CAN_FIFOF_BLOCK_b 12 +#define CAN_FIFOF_OVERRUN_b 11 +#define CAN_FIFOF_FULL_b 10 +#define CAN_FIFOF_EMPTY_b 9 +#define CAN_FIFOF_DEAD_b 8 +#define CAN_FIFOF_INACTIVE_b 7 +#define CAN_FIFOF_FREEONEMPTY_b 6 +#define CAN_FIFOF_READY_b 5 +#define CAN_FIFOF_NOTIFYPEND_b 4 +#define CAN_FIFOF_RTL_MEM_b 3 + +#define CAN_FIFOF_DESTROY (1<fifo_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/main.h b/embedded/app/usbcan/can/main.h new file mode 100644 index 0000000..9a1d65b --- /dev/null +++ b/embedded/app/usbcan/can/main.h @@ -0,0 +1,515 @@ +/* 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 + */ + +#include + +#include "./can.h" +#include "./constants.h" +#include "./ul_listbase.h" +#include "./can_sysless.h" +#include "./can_queue.h" + +#ifdef CAN_DEBUG + #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "can.o (debug): " fmt,\ + ##args) +#else + #define DEBUGMSG(fmt,args...) +#endif + +#define CANMSG(fmt,args...) can_printk(KERN_ERR "can.o: " 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]; +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*/ diff --git a/embedded/app/usbcan/can/sja1000p.h b/embedded/app/usbcan/can/sja1000p.h new file mode 100644 index 0000000..1aa0923 --- /dev/null +++ b/embedded/app/usbcan/can/sja1000p.h @@ -0,0 +1,200 @@ +/* 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 + */ + +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) 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_quekern.c b/embedded/app/usbcan/can_quekern.c new file mode 100644 index 0000000..ac1554c --- /dev/null +++ b/embedded/app/usbcan/can_quekern.c @@ -0,0 +1,519 @@ +/* can_quekern.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 "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/can_queue.h" + +//#define CAN_DEBUG + +extern atomic_t edge_num_cnt; + +#ifdef CAN_DEBUG + #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_quekern (debug): " fmt,\ + ##args) + +#else + #define DEBUGQUE(fmt,args...) +#endif + +#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_quekern: " 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); + kfree(qedge); + } + + can_spin_lock_irqsave(&canque_dead_func_lock, flags); + entry=canque_dead_ends.next; + can_spin_unlock_irqrestore(&canque_dead_func_lock,flags); + /* lock can be released there, because only one instance of canque_dead_tl + can run at once and all other functions add ends only to head */ + 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*/ + kfree(qends); + } + +} + +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(); +} + + + +/*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=kmalloc(size,GFP_KERNEL); + 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) + kfree(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 *)kmalloc(sizeof(struct canque_edge_t), GFP_KERNEL); + 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){ + kfree(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); + kfree(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_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; + } + + kfree(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_quesysless.c b/embedded/app/usbcan/can_quesysless.c new file mode 100644 index 0000000..7ceeb43 --- /dev/null +++ b/embedded/app/usbcan/can_quesysless.c @@ -0,0 +1,519 @@ +/* can_quekern.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_quekern (debug): " fmt,\ + ##args) + +#else + #define DEBUGQUE(fmt,args...) +#endif + +#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_quekern: " 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; + can_spin_unlock_irqrestore(&canque_dead_func_lock,flags); + /* lock can be released there, because only one instance of canque_dead_tl + can run at once and all other functions add ends only to head */ + 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); + } + +} + +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(); +} + + + +/*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_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..3f72015 --- /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 "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/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..2af0f86 --- /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 "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/can_queue.h" +#include "../include/main.h" +#include "../include/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/main.c b/embedded/app/usbcan/main.c new file mode 100644 index 0000000..d28cc13 --- /dev/null +++ b/embedded/app/usbcan/main.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "can/can.h" +#include "can/sja1000p.h" + +#define MASK_EP1RX 0x01 +#define MASK_EP1TX 0x02 + +#ifdef USB_MAX_PACKET + #undef USB_MAX_PACKET + #define USB_MAX_PACKET 8 +#endif + +#define CAN_OP_MASK 0x80 +#define CAN_OP_READ 0x80 +#define CAN_OP_WRITE 0x00 + + +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[2]; +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,usb_can_send; +volatile uint8_t bootloader_run; + +int processlocal; + +/** + 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 +*/ +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; + }*/ +} + +/***********************************/ +int main(void) +{ +// 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); + + //******************** + // USB init + memset( &usb_device, 0, sizeof( usb_device)); + usb_device.id = 1; + usb_device.init = usb_lpc_init; + usb_debug_set_level(DEBUG_LEVEL_NONE); + usb_device.cntep = 3; + 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=usb_loader; + + usb_init(&usb_device); + usb_connect(&usb_device); + + can_init(); + usb_can_send=1; + + /********************/ + // 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 ((usb_device.ep_events & MASK_EP1RX)&&(usb_can_send)) { //EP1RX + int size; + uint8_t *data; + uint8_t val; + size=usb_udev_read_endpoint(&eps[0],ep1_rx_buff,USB_MAX_PACKET); + data=(uint8_t *)ep1_rx_buff; + if (size==2){ + if (((*data)&CAN_OP_MASK)==CAN_OP_READ){ // Get data from CAN device and return to caller + can_read((*data) & 0x7F,&val); + *(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)&CAN_OP_MASK)==CAN_OP_WRITE){ // Save data to CAN device + can_write((*data)&(~CAN_OP_MASK),data+1); + timer_tx_off=50; //rozsviceni diod pri vysilani + CLR_OUT_PIN(LED_PORT,LED1_BIT); + } + } + usb_device.ep_events &= ~MASK_EP1RX; + } + + if(usb_device.ep_events & MASK_EP1TX){ + usb_can_send=1; + usb_device.ep_events &= ~MASK_EP1TX; + } + +#ifdef WATCHDOG_ENABLED + watchdog_feed(); +#endif /* WATCHDOG_ENABLED */ + + /* 10ms timer */ + if (lt_10msec_expired(10)) + timer_10ms(); + } + + SET_OUT_PIN(LED_PORT,LED_GP); + SET_OUT_PIN(LED_PORT,LED_ERR); + + /* unreachable code */ +#ifdef SDCC + vec_jmp(0x0); /* need to call a function from misc to correct linking */ +#endif + return 0; +} diff --git a/embedded/app/usbcan/sja1000p.c b/embedded/app/usbcan/sja1000p.c new file mode 100644 index 0000000..ffadb6c --- /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 "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/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/usb/usb_defs.h b/embedded/app/usbcan/usb/usb_defs.h new file mode 100644 index 0000000..6eef8b0 --- /dev/null +++ b/embedded/app/usbcan/usb/usb_defs.h @@ -0,0 +1,448 @@ + +#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 + +/*****************************************************/ +/*** Static data structures for device descriptors ***/ +/*****************************************************/ +#ifndef USB_VENDOR_ID + #define USB_VENDOR_ID 0xDEAD /* vymyslene cislo ( snad ho nikdo nema ... ;-) */ +#endif +#ifndef USB_PRODUCT_ID + #define USB_PRODUCT_ID 0x1001 /* 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 */ + 48,0x03, + 'S',0, + 'm',0, + 'o',0, + 'l',0, + 'i',0, + 'k',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 */ + 38, 0x03, + 'u',0, + 'L',0, + 'a',0, + 'n',0, + '2',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, + '2',0, + '3',0, + '.',0, + '0',0, + '7',0, + '.',0, + '0',0, + '4',0, + '-',0, + '1',0, + '.',0, + '1',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 */ + 26,0x03, + 'I',0, + 'n',0, + 't',0, + 'e',0, + 'r',0, + 'f',0, + 'a',0, + 'c',0, + 'e',0, + ' ',0, + '#',0, + '0',0 + }; + + CODE const char Str6Desc[] = { /* EP1 OUT descriptor */ + 136,0x03, + 'E',0, + 'P',0, + '1',0, + 'O',0, + 'U',0, + 'T',0, + '-',0, + 's',0, + 'e',0, + 'n',0, + 'd',0, + ' ',0, + 'm',0, + 'e',0, + 's',0, + 's',0, + 'a',0, + 'g',0, + 'e',0, + '-',0, + 'd',0, + 'a',0, + 'd',0, + 'r',0, + ',',0, + 's',0, + 'a',0, + 'd',0, + 'r',0, + ',',0, + 'c',0, + 'm',0, + 'd',0, + ',',0, + 'f',0, + 'l',0, + 'g',0, + ',',0, + 's',0, + 't',0, + 'a',0, + 'm',0, + 'p',0, + ',',0, + 'f',0, + 'r',0, + 'e',0, + 'e',0, + ',',0, + 'l',0, + 'e',0, + 'n',0, + '-',0, + 'l',0, + 'o',0, + ',',0, + 'l',0, + 'e',0, + 'n',0, + '-',0, + 'h',0, + 'i',0, + ',',0, + 'd',0, + 'a',0, + 't',0, + 'a',0 + }; + + CODE const char Str7Desc[] = { /* EP2 IN descriptor */ + 140,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, + 'm',0, + 'e',0, + 's',0, + 's',0, + 'a',0, + 'g',0, + 'e',0, + '-',0, + 'd',0, + 'a',0, + 'd',0, + 'r',0, + ',',0, + 's',0, + 'a',0, + 'd',0, + 'r',0, + ',',0, + 'c',0, + 'm',0, + 'd',0, + ',',0, + 'f',0, + 'l',0, + 'g',0, + ',',0, + 's',0, + 't',0, + 'a',0, + 'm',0, + 'p',0, + ',',0, + 'f',0, + 'r',0, + 'e',0, + 'e',0, + ',',0, + 'l',0, + 'e',0, + 'n',0, + '-',0, + 'l',0, + 'o',0, + ',',0, + 'l',0, + 'e',0, + 'n',0, + '-',0, + 'h',0, + 'i',0, + ',',0, + 'd',0, + 'a',0, + 't',0, + 'a',0 + }; + + CODE const char Str8Desc[] = { /* EP1 OUT descriptor */ + 136,0x03, + 'E',0, + 'P',0, + '2',0, + 'O',0, + 'U',0, + 'T',0, + '-',0, + 's',0, + 'e',0, + 'n',0, + 'd',0, + ' ',0, + 'm',0, + 'e',0, + 's',0, + 's',0, + 'a',0, + 'g',0, + 'e',0, + '-',0, + 'd',0, + 'a',0, + 'd',0, + 'r',0, + ',',0, + 's',0, + 'a',0, + 'd',0, + 'r',0, + ',',0, + 'c',0, + 'm',0, + 'd',0, + ',',0, + 'f',0, + 'l',0, + 'g',0, + ',',0, + 's',0, + 't',0, + 'a',0, + 'm',0, + 'p',0, + ',',0, + 'f',0, + 'r',0, + 'e',0, + 'e',0, + ',',0, + 'l',0, + 'e',0, + 'n',0, + '-',0, + 'l',0, + 'o',0, + ',',0, + 'l',0, + 'e',0, + 'n',0, + '-',0, + 'h',0, + 'i',0, + ',',0, + 'd',0, + 'a',0, + 't',0, + 'a',0 + }; + + #define CNT_STRINGS 0x09 + + /* 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, + (PUSB_STRING_DESCRIPTOR) Str8Desc + }; + +#endif /* USB_DEFS_MODULE */ diff --git a/embedded/app/usbcan/usb_srq.c b/embedded/app/usbcan/usb_srq.c new file mode 100644 index 0000000..4299a83 --- /dev/null +++ b/embedded/app/usbcan/usb_srq.c @@ -0,0 +1,238 @@ +/*****************************************************/ +/*** Module : USB module ***/ +/*** Author : Roman Bartosinski (C) 28.04.2002 ***/ +/*** Modify : 08.08.2002, 16.04.2003 ***/ +/*****************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//extern ul_dcnv_state_t ep1_dcnv_state; + + // **************************** + 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 ( 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*/ + 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_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 ( dreq->wValue == USB_FEATURE_ENDPOINT_STALL) { + lpc_usb_clrstallEP(epid); + usb_udev_ack_setup( udev); + //initialize state of ulan convertor + switch (epid&(USB_ENDPOINT_DIRECTION_MASK|0x03)) { + case 0x01: //rx USB -> tx ulan +// ul_freemsg(ep1_dcnv_state.tx_fd); +// ep1_dcnv_state.tx_2send=-1; + break; + case 0x81: //tx USB -> rx ulan +// ul_freemsg(ep1_dcnv_state.rx_fd); +// ep1_dcnv_state.rx_2rec=-1; +// ep1_dcnv_state.rx_wait4host=0; + break; + } + return USB_COMPLETE_OK; + } + break; + } + return USB_COMPLETE_FAIL; + } + + int usb_stdreq_set_feature( usb_device_t *udev) + { + 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; + lpc_usb_setstallEP (epid); + usb_udev_ack_setup( udev); + return USB_COMPLETE_OK; + } + break; + case USB_RECIPIENT_ENDPOINT: + if ( dreq->wValue == USB_FEATURE_ENDPOINT_STALL) { + 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); + lpc_usb_set_addr(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")); + if ( iCfg < 2) { // put device in unconfigured state or set configuration 1 ( no else) + usb_udev_ack_setup( udev); + lpc_usb_config_device(iCfg); + if ( iCfg) { + udev->flags |= USB_FLAG_CONFIGURED; + lpc_usb_configEP(0x01,USB_MAX_PACKET0); + lpc_usb_configEP(0x81,USB_MAX_PACKET0); + } else { + udev->flags &= ~USB_FLAG_CONFIGURED; + } + udev->configuration = iCfg; //usb_flags.configured = iCfg; + return USB_COMPLETE_OK; + } else + 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 *pDesc; + unsigned short Len = 0; + USB_DEVICE_REQUEST *dreq = &(udev->request); + 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 *)&DeviceDescription; + Len = sizeof( USB_DEVICE_DESCRIPTOR); + break; + case USB_DESCRIPTOR_TYPE_CONFIGURATION: + pDesc = (unsigned char *)&ConfigDescription; + Len = CONFIG_DESCRIPTOR_LENGTH; + break; + case USB_DESCRIPTOR_TYPE_INTERFACE: + pDesc = (unsigned char *)&ConfigDescription.interface; + 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 < CNT_STRINGS) { + pDesc = (unsigned char *) StringDescriptors[ 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/board/arm/ul_usb1/config/config.usbcan b/embedded/board/arm/ul_usb1/config/config.usbcan new file mode 100644 index 0000000..cc5d422 --- /dev/null +++ b/embedded/board/arm/ul_usb1/config/config.usbcan @@ -0,0 +1,63 @@ +# -*- 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_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 = \ + $(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)