From 11132ea490f9e860744ee4f851c67e7fb4444231 Mon Sep 17 00:00:00 2001 From: ppisa Date: Mon, 25 Aug 2003 03:52:35 +0000 Subject: [PATCH] CAN driver infrastructure redesign to LinCAN-0.2 version --- lincan/README | 134 ++++++-- lincan/TODO | 2 +- lincan/include/aim104.h | 18 +- lincan/include/can.h | 15 +- lincan/include/can_queue.h | 453 ++++++++++++++++++++++++++ lincan/include/cc_can104.h | 18 +- lincan/include/close.h | 4 +- lincan/include/constants.h | 16 +- lincan/include/devcommon.h | 19 ++ lincan/include/i82527.h | 10 +- lincan/include/ioctl.h | 4 +- lincan/include/irq.h | 10 +- lincan/include/m437.h | 18 +- lincan/include/main.h | 157 ++++----- lincan/include/modparms.h | 4 +- lincan/include/nsi.h | 18 +- lincan/include/open.h | 4 +- lincan/include/pc-i03.h | 18 +- lincan/include/pccan.h | 30 +- lincan/include/pcccan.h | 18 +- lincan/include/pcm3680.h | 18 +- lincan/include/pikronisa.h | 19 +- lincan/include/pip.h | 18 +- lincan/include/proc.h | 4 +- lincan/include/read.h | 4 +- lincan/include/select.h | 6 +- lincan/include/setup.h | 4 +- lincan/include/sja1000.h | 6 +- lincan/include/smartcan.h | 16 +- lincan/include/ssv.h | 14 +- lincan/include/template.h | 18 +- lincan/src/Makefile | 30 +- lincan/src/aim104.c | 66 ++-- lincan/src/bfadcan.c | 71 ++-- lincan/src/can_queue.c | 650 +++++++++++++++++++++++++++++++++++++ lincan/src/cc_can104.c | 62 ++-- lincan/src/close.c | 53 +-- lincan/src/devcommon.c | 66 ++++ lincan/src/i82527.c | 309 ++++++++++++++---- lincan/src/ioctl.c | 77 ++--- lincan/src/irq.c | 309 +----------------- lincan/src/m437.c | 63 ++-- lincan/src/main.c | 59 ++-- lincan/src/modparms.c | 26 +- lincan/src/nsi.c | 80 +++-- lincan/src/open.c | 105 +++--- lincan/src/pc_i03.c | 62 ++-- lincan/src/pccan.c | 284 +++++++--------- lincan/src/pcccan.c | 76 ++--- lincan/src/pcm3680.c | 89 +++-- lincan/src/pikronisa.c | 83 +++-- lincan/src/pip.c | 138 ++++---- lincan/src/proc.c | 102 +++--- lincan/src/read.c | 109 +++---- lincan/src/select.c | 82 +++-- lincan/src/setup.c | 276 +++++++++------- lincan/src/sja1000.c | 185 +++++++++-- lincan/src/sja1000p.c | 336 +++++++++++++++---- lincan/src/smartcan.c | 82 +++-- lincan/src/ssv.c | 68 ++-- lincan/src/template.c | 74 ++--- lincan/src/write.c | 160 +++------ 62 files changed, 3360 insertions(+), 1969 deletions(-) create mode 100644 lincan/include/can_queue.h create mode 100644 lincan/include/devcommon.h create mode 100644 lincan/src/can_queue.c create mode 100644 lincan/src/devcommon.c diff --git a/lincan/README b/lincan/README index f2095a8..b7a546b 100644 --- a/lincan/README +++ b/lincan/README @@ -1,45 +1,117 @@ -Because we are not able to contact original author Arnaud Westenberg, -and we have put piece of work to bugfixes and enhancements of the -driver, we decided to offer our latest version to more tests. -Please, if you know Arnaud's new address, contact us. -Most of new bugs belongs to + Linux CAN Driver (LinCAN) version 0.2 snapshot + Pavel Pisa + OCERA team member + - Pavel Pisa pisa@cmp.felk.cvut.cz -and Tomasz Motylewski, T.Motylewski@bfad.de -Main enhancements: - interrupts service cleanup and partial redesign - deep module build redesign - support for select - preliminary support for 2.5.48 (UP only now) - CAN Ethernet proxy +INTRODUCTION +============ +The LinCAN is an implementation of the Linux CAN-bus device driver supporting +more CAN controller chips and many CAN interface boards. Its development +has long history already. The OCERA version of the driver has new better +designed internal structure, adds new features (as support for open by multiple +applications, select system call) and other enhancements. + +The driver consist of four main layers: + - chip level manipulation routines + - board specific support + - message queues + - user-space API and ABI character device interface ------------------------------------------------------------------------- -README for the linux CAN-bus driver. -Written by Arnaud Westenberg email:arnaud@wanadoo.nl -This software is released under the GPL-License. -Version 0.7 6 Aug 2001 +DRIVER HISTORY +============== -Modified version can-0.7.1-pi2.2 +The driver originates in The Linux Lab Project + http://www.llp.fu-berlin.de/ +then it has been first rewritten by Arnaud Westenberg + http://home.wanadoo.nl/arnaud/ +now it is developed and maintained as part of OCERA framework + http://www.ocera.org/ -This version adds new Makefile system. -DEVFS support -Select/poll support for read/write events -Preliminary cleanups for 2.5.xx kernels, -it cannot work with SMP 2.5.xx until we get rid off -CLI ans STI global directives +I am unable to contact previous maintainer Arnaud Westenberg +(arnaud@wanadoo.nl). If you know something about him, I like +to hear it. + +Versions: + +can-0.7.1 latest driver version version published + by Arnaud Westenberg + +can-0.7.1-tm5 the enhanced version with better support of + SJA1000 PeliCAN mode and CAN Ethernet proxy + contributed by Tomasz Motylewski + +can-0.7.1-pi1 the import and usage of previous version for +(Dec 2002) OCERA group purposes + +can-0.7.1-pi3.4 enhanced version with select support and rewritten +(Mar 2003) make system for Linux kernels (2.2.x,2.4.x,2.5.x), + interrupts service cleanup and partial redesign + and DEVFS support + +lincan-0.2-pre heavily rewritten infrastructure of the driver based +(Aug 2003) on atomic slot management of queues + +The actual version of driver have been latest tested it with +PC104 Advantech PCM3680 dual channel board on 2.4 kernel. +It takes more time to test it with more cards and polish +support for 2.2 and 2.6 kernels, but these should be mainly +cosmetic changes (I hope ;-), infrastructure and original +support for more than 14 boards with more variants is in. + + +SOURCES AND URLs +================ + +The LinCAN driver component page at OCERA web site +(not updated to the new version yet) + + http://www.ocera.org/download/components/WP7/lincan-0.1.html + +List of related communication components + + http://www.ocera.org/download/components/WP7/index.html + +The CVS repository of OCERA project at SourceForge + + EXTCVS=":pserver:anonymous@cvs.ocera.sourceforge.net:/cvsroot/ocera" + cvs -d$EXTCVS login + cvs -z3 -d$EXTCVS co ocera + +Web access into CVS + + http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/ocera/ocera/components/comm/can/lincan/ + +Experimental directory at maintainer (Pavel Pisa's) pages + + http://cmp.felk.cvut.cz/~pisa/can/ + http://cmp.felk.cvut.cz/~pisa/can/lincan-YYMMDD.tar.gz + +Please send comments, bug-fixes and enhancements directly to +me (Pavel Pisa ) or to OCERA discussion +forum +and lists -Changes made by Pavel Pisa pisa@cmp.felk.cvut.cz as preliminary -study for OCERA Real Time CAN/CANOpen project ORTCAN COMPILATION -Just type 'make' at the command line and it should compile without errors. +=========== + +Just type 'make' at the command line and driver module should compile +without errors for current running kernel. -INSTALLATION. -Currently there's no installation procedure, just compile and load the driver. +More information can be found in driver documentation at + http://cmp.felk.cvut.cz/~pisa/can/ + http://cmp.felk.cvut.cz/~pisa/can/lincan-X.Y.pdf + +INSTALLATION +============ +Type 'make install'. The driver should be copied into actual kernel version +modules directory "/lib/modules/x.y.z/kernel/drivers/char". LOADING +======= + To load the driver type: # insmod can.o hw='your hardware' irq='irq number' io='io address' Example: # insmod can.o hw=pip5 irq=4 io=0x8000 @@ -63,7 +135,7 @@ The hw argument can be one of: options can be one of: - major=, major specifies the major number of the driver. -- minor=, you can specify wich minor numbers the driver should use for your +- minor=, you can specify which minor numbers the driver should use for your hardware. - extended=[1|0], configures the driver to use extended message format. - pelican=[1|0], configures the driver to set the CAN chips into pelican mode. diff --git a/lincan/TODO b/lincan/TODO index 7a4c555..d2a99aa 100644 --- a/lincan/TODO +++ b/lincan/TODO @@ -10,5 +10,5 @@ Version 0.7 6 Aug 2001 - Proc directory - Lot of ioctl's -- Get rid of CLI and STI, they are not longer supported ++ Get rid of CLI and STI, they are not longer supported in 2.5.xx kernels diff --git a/lincan/include/aim104.h b/lincan/include/aim104.h index 5e9c0b8..c269114 100644 --- a/lincan/include/aim104.h +++ b/lincan/include/aim104.h @@ -1,17 +1,19 @@ /* aim104.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int aim104_request_io(unsigned long io_addr); -int aim104_release_io(unsigned long io_addr); -int aim104_reset(int card); -int aim104_init_hw_data(int card); -int aim104_init_chip_data(int card, int chipnr); -int aim104_init_obj_data(int chipnr, int objnr); +int aim104_request_io(struct candevice_t *candev); +int aim104_release_io(struct candevice_t *candev); +int aim104_reset(struct candevice_t *candev); +int aim104_init_hw_data(struct candevice_t *candev); +int aim104_init_chip_data(struct candevice_t *candev, int chipnr); +int aim104_init_obj_data(struct chip_t *chip, int objnr); void aim104_write_register(unsigned char data, unsigned long address); unsigned aim104_read_register(unsigned long address); -int aim104_program_irq(int card); +int aim104_program_irq(struct candevice_t *candev); diff --git a/lincan/include/can.h b/lincan/include/can.h index 6ccb6dc..e310732 100644 --- a/lincan/include/can.h +++ b/lincan/include/can.h @@ -1,3 +1,6 @@ +#ifndef _CANMSG_T_H +#define _CANMSG_T_H + #include #include @@ -16,6 +19,13 @@ struct canmsg_t { unsigned char data[CAN_MSG_LENGTH]; } PACKED; +struct canfilt_t { + int flags; + int cob; + unsigned long id; + unsigned long mask; +}; + /* Definitions to use for canmsg_t flags */ #define MSG_RTR (1<<0) #define MSG_OVR (1<<1) @@ -38,8 +48,11 @@ typedef unsigned short channel_t; //#define CONF_TIMING //#define CONF_OMODE #define CONF_FILTER _IOW(CAN_IOC_MAGIC, 8, unsigned char) + //#define CONF_FENABLE //#define CONF_FDISABLE - #define STAT _IO(CAN_IOC_MAGIC, 9) +#define CONF_FILTER_QUE0 _IOW(CAN_IOC_MAGIC, 10, struct canfilt_t) + +#endif /*_CANMSG_T_H*/ diff --git a/lincan/include/can_queue.h b/lincan/include/can_queue.h new file mode 100644 index 0000000..bf092cd --- /dev/null +++ b/lincan/include/can_queue.h @@ -0,0 +1,453 @@ +#ifndef _CAN_QUEUE_H +#define _CAN_QUEUE_H + +#include +#include +#include +#include +#include +#include "./can.h" +#include "./constants.h" + +/* 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 */ + + +/** + * struct canque_slot_t - one CAN message slot in the CAN FIFO queue + * @next: pointer to the next/younger slot + * @mrs_do_inp: 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 + * @tail: pointer to the location, where pointer to newly inserted slot + * @entry: pointer to the memory allocated for the list slots. + * @fifo_lock: the lock to ensure atomicity of slot manipulation operations. + * + * 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 */ + spinlock_t fifo_lock; /* spin_lock_irqsave / spin_lock_irqrestore */ +}; + +#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_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) +{ + unsigned long flags; + struct canque_slot_t *slot; + 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); + 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); + 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; + unsigned long flags; + slot->next=NULL; + spin_lock_irqsave(&fifo->fifo_lock, flags); + if(*fifo->tail) printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n"); + *fifo->tail=slot; + fifo->tail=&slot->next; + if(canque_fifo_test_and_clear_fl(fifo,EMPTY)) + ret=CAN_FIFOF_EMPTY; /* Fifo has been empty before put */ + else + ret=0; + 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; + unsigned long flags; + 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; + 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) +{ + unsigned long flags; + int cmd; + struct canque_slot_t *slot; + spin_lock_irqsave(&fifo->fifo_lock, flags); + if(!(slot=fifo->head)){; + canque_fifo_set_fl(fifo,EMPTY); + spin_unlock_irqrestore(&fifo->fifo_lock, flags); + *slotp=NULL; + return -1; + } + if(!(fifo->head=slot->next)) + fifo->tail=&fifo->head; + 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; + unsigned long flags; + 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; + } + 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) +{ + unsigned long flags; + spin_lock_irqsave(&fifo->fifo_lock, flags); + if(!(slot->next=fifo->head)) + fifo->tail=&slot->next; + fifo->head=slot; + 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, int slotsnr); + +int canque_fifo_done(struct canque_fifo_t *fifo); + +#define CANQUEUE_PRIO_NR 3 + +/* Forward declarations for external types */ +struct msgobj_t; +struct chip_t; + +/** + * 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 peer FIFOs connected by their + * input side (@inends) to the same terminal (@struct canque_ends_t). + * @outpeers: the lists of all peer FIFOs connected by their + * output side (@outends) to the same terminal (@struct canque_ends_t). + * @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 + */ +struct canque_edge_t { + struct canque_fifo_t fifo; + unsigned long filtid; + unsigned long filtmask; + struct list_head inpeers; + struct list_head outpeers; + struct canque_ends_t *inends; + struct canque_ends_t *outends; + atomic_t edge_used; + int edge_prio; + int edge_num; +}; + +/** + * canque_edge_t - CAN message delivery subsystem graph vertex (FIFO ends) + * @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. + * @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. + * @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. + */ +struct canque_ends_t { + struct list_head active[CANQUEUE_PRIO_NR]; + struct list_head idle; + struct list_head inlist; + spinlock_t ends_lock; /* spin_lock_irqsave / spin_lock_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; + } fileinfo; + struct { + wait_queue_head_t daemonq; + struct msgobj_t *msgobj; + struct chip_t *chip; + } chipinfo; + } endinfo; +}; + +#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_ATACH 6 /* */ +#define CANQUEUE_NOTIFY_FILTCH 7 /* 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 */ + +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); +} + +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); +} + +static inline +void canque_notify_bothends(struct canque_edge_t *qedge, int what) +{ + canque_notify_inends(qedge, what); + canque_notify_outends(qedge, what); +} + +static inline +void canque_activate_edge(struct canque_ends_t *inends, struct canque_edge_t *qedge) +{ + unsigned long flags; + struct canque_ends_t *outends; + if(qedge->edge_prio>=CANQUEUE_PRIO_NR) + qedge->edge_prio=CANQUEUE_PRIO_NR-1; + spin_lock_irqsave(&inends->ends_lock, flags); + if((outends=qedge->outends)){ + spin_lock(&outends->ends_lock); + spin_lock(&qedge->fifo.fifo_lock); + if(!canque_fifo_test_fl(&qedge->fifo,EMPTY)){ + list_del(&qedge->outpeers); + list_add_tail(&qedge->outpeers,&outends->active[qedge->edge_prio]); + } + spin_unlock(&qedge->fifo.fifo_lock); + spin_unlock(&outends->ends_lock); + + } + spin_unlock_irqrestore(&inends->ends_lock, flags); +} + +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 canque_flush(struct canque_edge_t *qedge); + +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_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); + +int canqueue_ends_init_kern(struct canque_ends_t *qends); + +int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync); + +#endif /*_CAN_QUEUE_H*/ diff --git a/lincan/include/cc_can104.h b/lincan/include/cc_can104.h index 64da797..c557f5c 100644 --- a/lincan/include/cc_can104.h +++ b/lincan/include/cc_can104.h @@ -1,17 +1,19 @@ /* cc_can104.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int cc104_request_io(unsigned long io_addr); -int cc104_release_io(unsigned long io_addr); -int cc104_reset(int card); -int cc104_init_hw_data(int card); -int cc104_init_chip_data(int card, int chipnr); -int cc104_init_obj_data(int chipnr, int objnr); +int cc104_request_io(struct candevice_t *candev); +int cc104_release_io(struct candevice_t *candev); +int cc104_reset(struct candevice_t *candev); +int cc104_init_hw_data(struct candevice_t *candev); +int cc104_init_chip_data(struct candevice_t *candev, int chipnr); +int cc104_init_obj_data(struct chip_t *chip, int objnr); void cc104_write_register(unsigned char data, unsigned long address); unsigned cc104_read_register(unsigned long address); -int cc104_program_irq(int card); +int cc104_program_irq(struct candevice_t *candev); diff --git a/lincan/include/close.h b/lincan/include/close.h index f164b31..7c8cdee 100644 --- a/lincan/include/close.h +++ b/lincan/include/close.h @@ -1,8 +1,10 @@ /* close.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ int can_close(struct inode *inode, struct file *file); diff --git a/lincan/include/constants.h b/lincan/include/constants.h index 10af2ce..2d86cc3 100644 --- a/lincan/include/constants.h +++ b/lincan/include/constants.h @@ -1,8 +1,10 @@ /* constants.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #ifdef __CONSTANTS_H__ @@ -36,15 +38,15 @@ #define SIE (1<<2) #define EIE (1<<3) -#define SPACING 0x3c0 - /* These flags can be used for the msgobj_t structure flags data entry */ -#define OPENED (1<<0) -#define BUFFERS_ALLOCATED (1<<1) +#define OBJ_OPENED (1<<0) +#define OBJ_BUFFERS_ALLOCATED (1<<1) +#define OBJ_TX_REQUEST (1<<2) +#define OBJ_TX_LOCK (1<<3) /* These flags can be used for the chip_t structure flags data entry */ -#define CONFIGURED (1<<0) -#define SEGMENTED (1<<1) +#define CHIP_CONFIGURED (1<<0) +#define CHIP_SEGMENTED (1<<1) /* These flags can be used for the candevices_t structure flags data entry */ #define PROGRAMMABLE_IRQ (1<<0) diff --git a/lincan/include/devcommon.h b/lincan/include/devcommon.h new file mode 100644 index 0000000..e19471e --- /dev/null +++ b/lincan/include/devcommon.h @@ -0,0 +1,19 @@ +/* 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.2 9 Jul 2003 + */ + +#include +#include +#include +#include +#include + +#include "./can.h" +#include "./constants.h" +#include "./can_queue.h" + +int canqueue_ends_init_chip(struct canque_ends_t *qends, struct chip_t *chip, struct msgobj_t *obj); diff --git a/lincan/include/i82527.h b/lincan/include/i82527.h index 14df44e..c80ed00 100644 --- a/lincan/include/i82527.h +++ b/lincan/include/i82527.h @@ -1,8 +1,10 @@ /* i82527.h * Header file for the Linux CAN-bus driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ int i82527_enable_configuration(struct chip_t *chip); @@ -29,6 +31,9 @@ int i82527_set_btregs(struct chip_t *chip, unsigned short btr0, int i82527_start_chip(struct chip_t *chip); int i82527_stop_chip(struct chip_t *chip); int i82527_check_tx_stat(struct chip_t *chip); +irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs); + +#define MSG_OFFSET(object) ((object)*0x10) #define iCTL 0x00 // Control Register #define iSTAT 0x01 // Status Register @@ -165,3 +170,6 @@ enum i82527_iMSGCFG { MCFG_XTD = 1<<2, // Extended Identifier MCFG_DIR = 1<<3 // Direction is Transmit }; + +void i82527_seg_write_reg(const struct chip_t *chip, unsigned char data, unsigned address); +unsigned i82527_seg_read_reg(const struct chip_t *chip, unsigned address); diff --git a/lincan/include/ioctl.h b/lincan/include/ioctl.h index 794b779..c45e104 100644 --- a/lincan/include/ioctl.h +++ b/lincan/include/ioctl.h @@ -1,8 +1,10 @@ /* ioctl.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); diff --git a/lincan/include/irq.h b/lincan/include/irq.h index 7410882..959a94b 100644 --- a/lincan/include/irq.h +++ b/lincan/include/irq.h @@ -1,10 +1,12 @@ /* irq.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs); -void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs); -void dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs); diff --git a/lincan/include/m437.h b/lincan/include/m437.h index 869dc1e..2c77bd3 100644 --- a/lincan/include/m437.h +++ b/lincan/include/m437.h @@ -1,19 +1,21 @@ /* m437.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 * * Header file for the SECO M437 (see m437.c for details) */ -int m437_request_io(unsigned long io_addr); -int m437_release_io(unsigned long io_addr); -int m437_reset(int card); -int m437_init_hw_data(int card); -int m437_init_chip_data(int card, int chipnr); -int m437_init_obj_data(int chipnr, int objnr); +int m437_request_io(struct candevice_t *candev); +int m437_release_io(struct candevice_t *candev); +int m437_reset(struct candevice_t *candev); +int m437_init_hw_data(struct candevice_t *candev); +int m437_init_chip_data(struct candevice_t *candev, int chipnr); +int m437_init_obj_data(struct chip_t *chip, int objnr); void m437_write_register(unsigned char data, unsigned long address); unsigned m437_read_register(unsigned long address); -int m437_program_irq(int card); +int m437_program_irq(struct candevice_t *candev); int m437_register(struct hwspecops_t *hwspecops); diff --git a/lincan/include/main.h b/lincan/include/main.h index c811d87..81f1818 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -1,16 +1,20 @@ /* 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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ +#include #include #include #include -#include +#include #include "./can.h" #include "./constants.h" +#include "./can_queue.h" #ifdef CAN_DEBUG #define DEBUGMSG(fmt,args...) printk(KERN_ERR "can.o (debug): " fmt,\ @@ -32,7 +36,12 @@ (minor(file->f_dentry->d_inode->i_rdev)) #endif /* Linux kernel > 2.5.7 */ -#define MSG_OFFSET(object) ((object)*0x10) +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL)) + typedef void irqreturn_t; + #define IRQ_NONE + #define IRQ_HANDLED + #define IRQ_RETVAL(x) +#endif /* <=2.5.67 */ struct canhardware_t { int nr_boards; @@ -42,14 +51,17 @@ struct canhardware_t { }; struct candevice_t { - char *hwname; - unsigned long io_addr; - unsigned long res_addr; + 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 seset register port */ + unsigned long dev_base_addr; /* CPU translated IO/virtual MEM address */ unsigned int flags; /* Hardware chip configuration. In case of multiple chips *chip * is the first in an array of chip_t structures. */ + int nr_all_chips; int nr_82527_chips; int nr_sja1000_chips; struct chip_t *chip[MAX_HW_CHIPS]; @@ -61,11 +73,20 @@ struct candevice_t { struct chip_t { char *chip_type; + int chip_idx; /* chip index in candevice_t.chip[] */ int chip_irq; unsigned long chip_base_addr; unsigned int flags; int clock; // Chip clock in Hz + /* This is copy of the chip->hostdevice->hwspecops->read_register + * and the chip->hostdevice->hwspecops->write_register. + * The pointers were added for performance reasons, and are initialized + * by init_chip_struct() from values given by hardware specific init_hwspecops(). + */ + void (*write_register)(unsigned char data,unsigned long address); + unsigned (*read_register)(unsigned long address); + /* sja_cdr_reg 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 @@ -98,30 +119,49 @@ struct chip_t { struct chipspecops_t *chipspecops; struct candevice_t *hostdevice; + + int max_objects; /* 1 for sja1000, 15 for */ }; struct msgobj_t { unsigned long obj_base_addr; - unsigned int minor; - unsigned int object; - unsigned int flags; + unsigned int minor; /* associated device minor number */ + unsigned int object; /* object number in chip_t +1 for debug printk */ + unsigned long flags; int ret; - struct canfifo_t *fifo; + struct canque_ends_t *qends; + struct canque_edge_t *tx_qedge; + struct canque_slot_t *tx_slot; + struct canmsg_t rx_msg; struct chip_t *hostchip; + + atomic_t obj_used; + struct list_head obj_users; +}; + +#define CAN_USER_MAGIC 0x05402033 + +struct canuser_t { + struct list_head peers; + struct canque_ends_t *qends; + struct file *file; /* back ptr to file */ + struct msgobj_t *msgobj; + struct canque_edge_t *rx_edge0; /* simplifies IOCTL */ + int magic; }; struct hwspecops_t { - int (*request_io)(unsigned long io_addr); - int (*release_io)(unsigned long io_addr); - int (*reset)(int card); - int (*init_hw_data)(int card); - int (*init_chip_data)(int card, int chipnr); - int (*init_obj_data)(int chipnr, int objnr); + 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 chip_t *chip, int objnr); + int (*program_irq)(struct candevice_t *candev); void (*write_register)(unsigned char data,unsigned long address); unsigned (*read_register)(unsigned long address); - int (*program_irq)(int card); }; struct chipspecops_t { @@ -143,13 +183,14 @@ struct chipspecops_t { struct canmsg_t *msg); int (*remote_request)(struct chip_t *chip, struct msgobj_t *obj); int (*check_tx_stat)(struct chip_t *chip); + int (*wakeup_tx)(struct chip_t *chip, struct msgobj_t *obj); int (*enable_configuration)(struct chip_t *chip); int (*disable_configuration)(struct chip_t *chip); int (*set_btregs)(struct chip_t *chip, unsigned short btr0, unsigned short btr1); int (*start_chip)(struct chip_t *chip); int (*stop_chip)(struct chip_t *chip); - void (*irq_handler)(int irq, void *dev_id, struct pt_regs *regs); + irqreturn_t (*irq_handler)(int irq, void *dev_id, struct pt_regs *regs); }; struct mem_addr { @@ -157,45 +198,6 @@ struct mem_addr { struct mem_addr *next; }; -/* Structure for the drivers main input and output buffers. The readq, writeq - * entries are the wait queues for the driver to sleep on in case of blocking - * read/write calls. buf_rx_entry and buf_tx_entry are pointers to the input and - * output buffers. The buffers are dynamically allocated. The tx_readp, - * tx_writep, rx_readp and rx_writep pointers are the various read/write - * pointers used when reading or writing the input and output buffers. The - * rx/tx_size entries are the dynamically allocated input and output buffer size - * The rx/tx_in_progress entries are used to determine whether the device is - * already set up for transmission. - */ -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) -struct canfifo_t { - struct wait_queue *readq, *writeq; - struct canmsg_t *buf_tx_entry; - struct canmsg_t *buf_rx_entry; - struct canmsg_t *tx_readp; - struct canmsg_t *rx_writep; - struct canmsg_t *tx_writep; - struct canmsg_t *rx_readp; - int rx_size, tx_size; - volatile int rx_in_progress, tx_in_progress; - /*int head, tail;*/ /* removed */ -}; -#else -struct canfifo_t { - struct __wait_queue_head readq; - struct __wait_queue_head writeq; - struct canmsg_t *buf_tx_entry; - struct canmsg_t *buf_rx_entry; - struct canmsg_t *tx_readp; - struct canmsg_t *rx_writep; - struct canmsg_t *tx_writep; - struct canmsg_t *rx_readp; - int rx_size, tx_size; - volatile int rx_in_progress, tx_in_progress; - /*int head, tail;*/ /* removed */ -}; -#endif - /* Structure for the RTR queue */ struct rtr_id { unsigned long id; @@ -217,7 +219,6 @@ extern int irq[MAX_IRQ]; extern unsigned long io[MAX_HW_CARDS]; extern struct canhardware_t *hardware_p; -extern struct candevice_t *candevices_p[MAX_HW_CARDS]; extern struct chip_t *chips_p[MAX_TOT_CHIPS]; extern struct msgobj_t *objects_p[MAX_TOT_MSGOBJS]; @@ -226,31 +227,37 @@ extern struct mem_addr *mem_head; /* 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 chip_t *chip, unsigned char data, unsigned short address) +extern inline void can_write_reg(const struct chip_t *chip, unsigned char data, unsigned address) { - unsigned short segment_number; unsigned long address_to_write; - address_to_write = chip->chip_base_addr+address; + chip->write_register(data, address_to_write); +} - if ( (chip->flags & SEGMENTED) != 0) { - segment_number = (unsigned short)(address >> 6); - address_to_write += SPACING * segment_number; - } +extern inline unsigned can_read_reg(const struct chip_t *chip, unsigned address) +{ + unsigned long address_to_read; + address_to_read = chip->chip_base_addr+address; + return chip->read_register(address_to_read); +} - chip->hostdevice->hwspecops->write_register(data, address_to_write); +extern inline void canobj_write_reg(const struct chip_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 can_read_reg(const struct chip_t *chip, unsigned short address) +extern inline unsigned canobj_read_reg(const struct chip_t *chip, const struct msgobj_t *obj, + unsigned address) { - unsigned short segment_number; unsigned long address_to_read; + address_to_read = obj->obj_base_addr+address; + return chip->read_register(address_to_read); +} - address_to_read = chip->chip_base_addr+address; +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); - if ( (chip->flags & SEGMENTED) != 0) { - segment_number = (unsigned short)(address >> 6); - address_to_read += SPACING * segment_number; - } - return chip->hostdevice->hwspecops->read_register(address_to_read); -} diff --git a/lincan/include/modparms.h b/lincan/include/modparms.h index 18879fc..4fa44f6 100644 --- a/lincan/include/modparms.h +++ b/lincan/include/modparms.h @@ -1,8 +1,10 @@ /* mod_parms.h * Header file for the Linux CAN-bus driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ int parse_mod_parms(void); diff --git a/lincan/include/nsi.h b/lincan/include/nsi.h index fd69113..ec6db23 100644 --- a/lincan/include/nsi.h +++ b/lincan/include/nsi.h @@ -1,17 +1,19 @@ /* nsi.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int nsi_request_io(unsigned long io_addr); -int nsi_release_io(unsigned long io_addr); -int nsi_reset(int card); -int nsi_init_hw_data(int card); -int nsi_init_chip_data(int card, int chipnr); -int nsi_init_obj_data(int chipnr, int objnr); +int nsi_request_io(struct candevice_t *candev); +int nsi_release_io(struct candevice_t *candev); +int nsi_reset(struct candevice_t *candev); +int nsi_init_hw_data(struct candevice_t *candev); +int nsi_init_chip_data(struct candevice_t *candev, int chipnr); +int nsi_init_obj_data(struct chip_t *chip, int objnr); void nsi_write_register(unsigned char data, unsigned long address); unsigned nsi_read_register(unsigned long address); -int nsi_program_irq(int card); +int nsi_program_irq(struct candevice_t *candev); diff --git a/lincan/include/open.h b/lincan/include/open.h index 997bd9f..fca1bf1 100644 --- a/lincan/include/open.h +++ b/lincan/include/open.h @@ -1,8 +1,10 @@ /* open.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ int can_open(struct inode *inode, struct file *file); diff --git a/lincan/include/pc-i03.h b/lincan/include/pc-i03.h index beb8aed..9b34ca3 100644 --- a/lincan/include/pc-i03.h +++ b/lincan/include/pc-i03.h @@ -1,17 +1,19 @@ /* pc-i03.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int pci03_request_io(unsigned long io_addr); -int pci03_release_io(unsigned long io_addr); -int pci03_reset(int card); -int pci03_init_hw_data(int card); -int pci03_init_chip_data(int card, int chipnr); -int pci03_init_obj_data(int chipnr, int objnr); +int pci03_request_io(struct candevice_t *candev); +int pci03_release_io(struct candevice_t *candev); +int pci03_reset(struct candevice_t *candev); +int pci03_init_hw_data(struct candevice_t *candev); +int pci03_init_chip_data(struct candevice_t *candev, int chipnr); +int pci03_init_obj_data(struct chip_t *chip, int objnr); void pci03_write_register(unsigned char data, unsigned long address); unsigned pci03_read_register(unsigned long address); -int pci03_program_irq(int card); +int pci03_program_irq(struct candevice_t *candev); diff --git a/lincan/include/pccan.h b/lincan/include/pccan.h index f5b8901..d47804c 100644 --- a/lincan/include/pccan.h +++ b/lincan/include/pccan.h @@ -1,24 +1,26 @@ /* pccan.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int pccanf_request_io(unsigned long io_addr); -int pccanf_release_io(unsigned long io_addr); -int pccand_request_io(unsigned long io_addr); -int pccand_release_io(unsigned long io_addr); -int pccanq_request_io(unsigned long io_addr); -int pccanq_release_io(unsigned long io_addr); -int pccanf_reset(int card); -int pccand_reset(int card); -int pccanq_reset(int card); -int pccan_init_hw_data(int card); -int pccan_init_chip_data(int card, int chipnr); -int pccan_init_obj_data(int chipnr, int objnr); +int pccanf_request_io(struct candevice_t *candev); +int pccanf_release_io(struct candevice_t *candev); +int pccand_request_io(struct candevice_t *candev); +int pccand_release_io(struct candevice_t *candev); +int pccanq_request_io(struct candevice_t *candev); +int pccanq_release_io(struct candevice_t *candev); +int pccanf_reset(struct candevice_t *candev); +int pccand_reset(struct candevice_t *candev); +int pccanq_reset(struct candevice_t *candev); +int pccan_init_hw_data(struct candevice_t *candev); +int pccan_init_chip_data(struct candevice_t *candev, int chipnr); +int pccan_init_obj_data(struct chip_t *chip, int objnr); void pccan_write_register(unsigned char data, unsigned long address); unsigned pccan_read_register(unsigned long address); -int pccan_program_irq(int card); +int pccan_program_irq(struct candevice_t *candev); diff --git a/lincan/include/pcccan.h b/lincan/include/pcccan.h index 77cdd80..cf98553 100644 --- a/lincan/include/pcccan.h +++ b/lincan/include/pcccan.h @@ -1,17 +1,19 @@ /* pcccan.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int pcccan_request_io(unsigned long io_addr); -int pcccan_release_io(unsigned long io_addr); -int pcccan_reset(int card); -int pcccan_init_hw_data(int card); -int pcccan_init_chip_data(int card, int chipnr); -int pcccan_init_obj_data(int chipnr, int objnr); +int pcccan_request_io(struct candevice_t *candev); +int pcccan_release_io(struct candevice_t *candev); +int pcccan_reset(struct candevice_t *candev); +int pcccan_init_hw_data(struct candevice_t *candev); +int pcccan_init_chip_data(struct candevice_t *candev, int chipnr); +int pcccan_init_obj_data(struct chip_t *chip, int objnr); void pcccan_write_register(unsigned char data, unsigned long address); unsigned pcccan_read_register(unsigned long address); -int pcccan_program_irq(int card); +int pcccan_program_irq(struct candevice_t *candev); diff --git a/lincan/include/pcm3680.h b/lincan/include/pcm3680.h index c0d5957..324854e 100644 --- a/lincan/include/pcm3680.h +++ b/lincan/include/pcm3680.h @@ -1,17 +1,19 @@ /* pcm3680.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int pcm3680_request_io(unsigned long io_addr); -int pcm3680_release_io(unsigned long io_addr); -int pcm3680_reset(int card); -int pcm3680_init_hw_data(int card); -int pcm3680_init_chip_data(int card, int chipnr); -int pcm3680_init_obj_data(int chipnr, int objnr); +int pcm3680_request_io(struct candevice_t *candev); +int pcm3680_release_io(struct candevice_t *candev); +int pcm3680_reset(struct candevice_t *candev); +int pcm3680_init_hw_data(struct candevice_t *candev); +int pcm3680_init_chip_data(struct candevice_t *candev, int chipnr); +int pcm3680_init_obj_data(struct chip_t *chip, int objnr); void pcm3680_write_register(unsigned char data, unsigned long address); unsigned pcm3680_read_register(unsigned long address); -int pcm3680_program_irq(int card); +int pcm3680_program_irq(struct candevice_t *candev); diff --git a/lincan/include/pikronisa.h b/lincan/include/pikronisa.h index 7fa56dd..360cc08 100644 --- a/lincan/include/pikronisa.h +++ b/lincan/include/pikronisa.h @@ -1,21 +1,22 @@ /* pikronisa.h * Header file for the Linux CAN-bus driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Added by Pavel Pisa pisa@cmp.felk.cvut.cz + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 * * Support for PiKRON Ltd ISA CAN card using * memory mapped SJA1000 controller - * Added by Pavel Pisa pisa@cmp.felk.cvut.cz */ -int pikronisa_request_io(unsigned long io_addr); -int pikronisa_release_io(unsigned long io_addr); -int pikronisa_reset(int card); -int pikronisa_init_hw_data(int card); -int pikronisa_init_chip_data(int card, int chipnr); -int pikronisa_init_obj_data(int chipnr, int objnr); +int pikronisa_request_io(struct candevice_t *candev); +int pikronisa_release_io(struct candevice_t *candev); +int pikronisa_reset(struct candevice_t *candev); +int pikronisa_init_hw_data(struct candevice_t *candev); +int pikronisa_init_chip_data(struct candevice_t *candev, int chipnr); +int pikronisa_init_obj_data(struct chip_t *chip, int objnr); +int pikronisa_program_irq(struct candevice_t *candev); void pikronisa_write_register(unsigned char data, unsigned long address); unsigned pikronisa_read_register(unsigned long address); -int pikronisa_program_irq(int card); diff --git a/lincan/include/pip.h b/lincan/include/pip.h index fefe48d..c32b2b5 100644 --- a/lincan/include/pip.h +++ b/lincan/include/pip.h @@ -1,17 +1,19 @@ /* pip.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int pip5_request_io(unsigned long io_addr); -int pip5_release_io(unsigned long io_addr); -int pip5_reset(int card); -int pip5_init_hw_data(int card); -int pip5_init_chip_data(int card, int chipnr); -int pip5_init_obj_data(int chipnr, int objnr); +int pip5_request_io(struct candevice_t *candev); +int pip5_release_io(struct candevice_t *candev); +int pip5_reset(struct candevice_t *candev); +int pip5_init_hw_data(struct candevice_t *candev); +int pip5_init_chip_data(struct candevice_t *candev, int chipnr); +int pip5_init_obj_data(struct chip_t *chip, int objnr); void pip5_write_register(unsigned char data, unsigned long address); unsigned pip5_read_register(unsigned long address); -int pip5_program_irq(int card); +int pip5_program_irq(struct candevice_t *candev); diff --git a/lincan/include/proc.h b/lincan/include/proc.h index 8a3d004..c07ab0a 100644 --- a/lincan/include/proc.h +++ b/lincan/include/proc.h @@ -1,8 +1,10 @@ /* proc.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include diff --git a/lincan/include/read.h b/lincan/include/read.h index 9716105..09e01d1 100644 --- a/lincan/include/read.h +++ b/lincan/include/read.h @@ -1,8 +1,10 @@ /* read.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ ssize_t can_read(struct file *file,char *buffer,size_t length,loff_t *offset); diff --git a/lincan/include/select.h b/lincan/include/select.h index cdf9195..3f24002 100644 --- a/lincan/include/select.h +++ b/lincan/include/select.h @@ -1,10 +1,10 @@ /* select.h * Header file for the Linux CAN-bus driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Added by Pavel Pisa pisa@cmp.felk.cvut.cz + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7.1-pi2 15 Nov 2002 - * - * added by Pavel Pisa pisa@cmp.felk.cvut.cz + * Version lincan-0.2 9 Jul 2003 */ unsigned int can_poll(struct file *file, poll_table *wait); diff --git a/lincan/include/setup.h b/lincan/include/setup.h index 3e9a35a..551adac 100644 --- a/lincan/include/setup.h +++ b/lincan/include/setup.h @@ -1,8 +1,10 @@ /* setup.h * Header file for the Linux CAN-bus driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ int init_hw_struct(void); diff --git a/lincan/include/sja1000.h b/lincan/include/sja1000.h index 9c6a6c6..35865b8 100644 --- a/lincan/include/sja1000.h +++ b/lincan/include/sja1000.h @@ -1,8 +1,10 @@ /* sja1000.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ int sja1000_enable_configuration(struct chip_t *chip); @@ -21,7 +23,7 @@ int sja1000_set_btregs(struct chip_t *chip, unsigned short btr0, unsigned short btr1); int sja1000_start_chip(struct chip_t *chip); int sja1000_stop_chip(struct chip_t *chip); -void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs); /* BasicCAN mode address map */ #define SJACR 0x00 /* Control register */ diff --git a/lincan/include/smartcan.h b/lincan/include/smartcan.h index 939df87..74fa2aa 100644 --- a/lincan/include/smartcan.h +++ b/lincan/include/smartcan.h @@ -1,16 +1,18 @@ /* smartcan.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int smartcan_request_io(unsigned long io_addr); -int smartcan_release_io(unsigned long io_addr); -int smartcan_reset(int card); -int smartcan_init_hw_data(int card); -int smartcan_init_chip_data(int card, int chipnr); -int smartcan_init_obj_data(int chipnr,int objnr); +int smartcan_request_io(struct candevice_t *candev); +int smartcan_release_io(struct candevice_t *candev); +int smartcan_reset(struct candevice_t *candev); +int smartcan_init_hw_data(struct candevice_t *candev); +int smartcan_init_chip_data(struct candevice_t *candev, int chipnr); +int smartcan_init_obj_data(struct chip_t *chip, int objnr); void smartcan_write_register(unsigned char data, unsigned long address); unsigned smartcan_read_register(unsigned long address); diff --git a/lincan/include/ssv.h b/lincan/include/ssv.h index d6a1151..9371487 100644 --- a/lincan/include/ssv.h +++ b/lincan/include/ssv.h @@ -5,13 +5,13 @@ * Version 0.6 18 Sept 2000 */ -int ssv_request_io(unsigned long io_addr); -int ssv_release_io(unsigned long io_addr); -int ssv_reset(int card); -int ssv_init_hw_data(int card); -int ssv_init_chip_data(int card, int chipnr); -int ssv_init_obj_data(int chipnr, int objnr); +int ssv_request_io(struct candevice_t *candev); +int ssv_release_io(struct candevice_t *candev); +int ssv_reset(struct candevice_t *candev); +int ssv_init_hw_data(struct candevice_t *candev); +int ssv_init_chip_data(struct candevice_t *candev, int chipnr); +int ssv_init_obj_data(struct chip_t *chip, int objnr); void ssv_write_register(unsigned char data, unsigned long address); unsigned ssv_read_register(unsigned long address); -int ssv_program_irq(int card); +int ssv_program_irq(struct candevice_t *candev); diff --git a/lincan/include/template.h b/lincan/include/template.h index 410a46b..f61e31f 100644 --- a/lincan/include/template.h +++ b/lincan/include/template.h @@ -1,17 +1,19 @@ /* template.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ -int template_request_io(unsigned long io_addr); -int template_release_io(unsigned long io_addr); -int template_reset(int card); -int template_init_hw_data(int card); -int template_init_chip_data(int card, int chipnr); -int template_init_obj_data(int chipnr, int objnr); +int template_request_io(struct candevice_t *candev); +int template_release_io(struct candevice_t *candev); +int template_reset(struct candevice_t *candev); +int template_init_hw_data(struct candevice_t *candev); +int template_init_chip_data(struct candevice_t *candev, int chipnr); +int template_init_obj_data(struct chip_t *chip, int objnr); void template_write_register(unsigned char data, unsigned long address); unsigned template_read_register(unsigned long address); -int template_program_irq(int card); +int template_program_irq(struct candevice_t *candev); diff --git a/lincan/src/Makefile b/lincan/src/Makefile index b83aa6d..8f5cfa2 100644 --- a/lincan/src/Makefile +++ b/lincan/src/Makefile @@ -1,7 +1,7 @@ # Makefile for the Linux CAN-bus driver. # Written by Arnaud Westenberg email:arnaud@wanadoo.nl # This software is released under the GPL-License. -# Version 0.7 6 Aug 2001 +# Version lincan-0.2 9 Aug 2003 # # This version is adapted from uLan Communication driver # (C) Copyright 1999 by Pavel Pisa pisa@cmp.felk.cvut.cz @@ -13,12 +13,8 @@ #KERNEL_LOCATION=/usr/src/linux #KERNEL_LOCATION=/usr/src/linux-2.2.19 #KERNEL_LOCATION=/usr/src/linux-2.2.22 -#KERNEL_LOCATION=/usr/src/linux-2.5.47 - -# Comment-out next two lines, if you do not build driver -# in the OCERA source tree -TOP=../../../../.. -KERNEL_LOCATION=$(TOP)/kernel/linux +#KERNEL_LOCATION=/usr/src/linux-2.5.69 +#KERNEL_LOCATION=/home/cvs/ocera/ocera-build/kernel/linux # Enable debugging messages DEBUG = y @@ -33,6 +29,10 @@ SUPPORTED_CARDS = pip pccan smartcan nsi cc_can104 \ pc_i03 pcm3680 aim104 m437 pcccan ssv \ bfadcan pikronisa template +#SUPPORTED_CARDS = pcm3680 bfadcan pikronisa template + +#SUPPORTED_CARDS = pikronisa + ########## Don't change anything under this line ################ # currently running kernel @@ -91,7 +91,8 @@ O_TARGET = can.o endif # Regular object files O_OBJS += $(SUPPORTED_CARDS:%=%.o) -O_OBJS += main.o modparms.o setup.o sja1000.o i82527.o close.o ioctl.o \ +O_OBJS += can_queue.o devcommon.o main.o modparms.o setup.o \ + sja1000.o i82527.o close.o ioctl.o \ open.o write.o read.o sja1000p.o irq.o select.o # Objects with exported symbols (-DEXPORT_SYMTAB) OX_OBJS = @@ -111,12 +112,18 @@ can-objs := $(O_OBJS) obj-y := $(O_OBJS) obj-m := can.o +ifndef KERNEL_MODULE_V26 +FINAL_MODULE_OBJS=$(obj-m) +else +FINAL_MODULE_OBJS=$(obj-m:%.o=%.ko) +endif + ########## Source/target independent buil of module ############# all : default default : make_this_module - cp can.o ../can.o + cp $(FINAL_MODULE_OBJS) ../$(FINAL_MODULE_OBJS) dep: make_this_module_dep @@ -133,17 +140,16 @@ make_this_module: .supported_cards.h echo Module target $(obj-m) echo Module objects $(can-objs) DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR modules) - for f in $(obj-m:%.o=%) ; do if [ -f $$f.ko ] ; then cp -u $$f.ko $$f.o ; fi ; done make_this_module_dep: DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR dep) install_this_module: make_this_module - su -c "mkdir -v -p $(MODULE_CHAR_LOC); cp -v $(obj-m) $(MODULE_CHAR_LOC)" + su -c "mkdir -v -p $(MODULE_CHAR_LOC) && cp -v $(FINAL_MODULE_OBJS) $(MODULE_CHAR_LOC)" clean: rm -f $(M_OBJS) $(MX_OBJS) $(O_OBJS) $(OX_OBJS) $(obj-m) $(obj-m:%.o=%.ko) \ - .*.o.flags .*.o.cmd .depend .supported_cards.h *~ + .*.o.flags .*.o.cmd .*.ko.cmd .depend .supported_cards.h *~ ifndef KERNEL_MODULE_V26 include $(KERNEL_LOCATION)/Rules.make diff --git a/lincan/src/aim104.c b/lincan/src/aim104.c index d679b52..da8afc0 100644 --- a/lincan/src/aim104.c +++ b/lincan/src/aim104.c @@ -1,18 +1,13 @@ /* aim104.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -44,15 +39,13 @@ * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int aim104_request_io(unsigned long io_addr) +int aim104_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + } else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); } return 0; } @@ -69,9 +62,9 @@ int aim104_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/template.c */ -int aim104_release_io(unsigned long io_addr) +int aim104_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -86,17 +79,17 @@ int aim104_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int aim104_reset(int card) +int aim104_reset(struct candevice_t *candev) { int i=0; DEBUGMSG("Resetting aim104 hardware ...\n"); - aim104_write_register(0x00, candevices_p[card]->io_addr + SJACR); + aim104_write_register(0x00, candev->io_addr + SJACR); /* Check hardware reset status chip 0 */ i=0; - while ( (aim104_read_register(candevices_p[card]->io_addr + SJACR) + while ( (aim104_read_register(candev->io_addr + SJACR) & CR_RR) && (i<=15) ) { udelay(20000); i++; @@ -130,12 +123,13 @@ int aim104_reset(int card) * Return Value: The function always returns zero * File: src/template.c */ -int aim104_init_hw_data(int card) +int aim104_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=0; - candevices_p[card]->nr_sja1000_chips=1; - candevices_p[card]->flags |= ~PROGRAMMABLE_IRQ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=1; + candev->nr_all_chips=1; + candev->flags &= ~PROGRAMMABLE_IRQ; return 0; } @@ -170,14 +164,14 @@ int aim104_init_hw_data(int card) * Return Value: The function always returns zero * File: src/template.c */ -int aim104_init_chip_data(int card, int chipnr) +int aim104_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->flags = 0; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = 0x08; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = 0xfa; + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->flags = 0; + candev->chip[chipnr]->sja_cdr_reg = 0x08; + candev->chip[chipnr]->sja_ocr_reg = 0xfa; return 0; } @@ -199,10 +193,10 @@ int aim104_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/template.c */ -int aim104_init_obj_data(int chipnr, int objnr) +int aim104_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + chip->msgobj[objnr]->flags=0; return 0; } @@ -219,7 +213,7 @@ int aim104_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int aim104_program_irq(int card) +int aim104_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/bfadcan.c b/lincan/src/bfadcan.c index 930e91a..3e145f6 100644 --- a/lincan/src/bfadcan.c +++ b/lincan/src/bfadcan.c @@ -1,8 +1,10 @@ /* bfadcan.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ /* This file is intended as a bfadcan file for currently unsupported hardware. @@ -13,13 +15,7 @@ #define __NO_VERSION__ /* this is not a main module, do not include module info */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -77,15 +73,13 @@ void bfadcan_write_register(unsigned char data, unsigned long address); * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/bfadcan.c */ -int bfadcan_request_io(unsigned long io_addr) +int bfadcan_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + } else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); } return 0; } @@ -102,9 +96,9 @@ int bfadcan_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/bfadcan.c */ -int bfadcan_release_io(unsigned long io_addr) +int bfadcan_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -119,11 +113,11 @@ int bfadcan_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/bfadcan.c */ -int bfadcan_reset(int card) +int bfadcan_reset(struct candevice_t *candev) { int i; - struct chip_t *chip=candevices_p[card]->chip[0]; + struct chip_t *chip=candev->chip[0]; unsigned cdr; bfadcan_write_register(MOD_RM, chip->chip_base_addr+SJAMOD); @@ -168,12 +162,13 @@ int bfadcan_reset(int card) * Return Value: The function always returns zero * File: src/bfadcan.c */ -int bfadcan_init_hw_data(int card) +int bfadcan_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=NR_82527; - candevices_p[card]->nr_sja1000_chips=NR_SJA1000; - candevices_p[card]->flags |= 0 /* PROGRAMMABLE_IRQ */ ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=NR_SJA1000; + candev->nr_all_chips=NR_82527+NR_SJA1000; + candev->flags |= 0 /* PROGRAMMABLE_IRQ */ ; return 0; } @@ -211,24 +206,24 @@ int bfadcan_init_hw_data(int card) * Return Value: The function always returns zero * File: src/bfadcan.c */ -int bfadcan_init_chip_data(int card, int chipnr) +int bfadcan_init_chip_data(struct candevice_t *candev, int chipnr) { unsigned int id1, id2; - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = clock_freq; - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC; - candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = clock_freq; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_LH; id1 = inb(0xe284); id2 = inb(0xe285); - CANMSG("can driver ver 0.7.1-tm5, at %04lx, CPLD v%d.%d.%d.%d\n", - candevices_p[card]->chip[chipnr]->chip_base_addr, + CANMSG("can driver ver lincan-0.2, at %04lx, CPLD v%d.%d.%d.%d\n", + candev->chip[chipnr]->chip_base_addr, id1>>4, id1&0x0f, id2>>4, id2&0x0f); @@ -252,10 +247,10 @@ int bfadcan_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/bfadcan.c */ -int bfadcan_init_obj_data(int chipnr, int objnr) +int bfadcan_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } @@ -272,7 +267,7 @@ int bfadcan_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/bfadcan.c */ -int bfadcan_program_irq(int card) +int bfadcan_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/can_queue.c b/lincan/src/can_queue.c new file mode 100644 index 0000000..ad6160c --- /dev/null +++ b/lincan/src/can_queue.c @@ -0,0 +1,650 @@ +/* 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.2 9 Jul 2003 + */ + +#define __NO_VERSION__ +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#include +#else +#include +#endif +#include +#include "../include/can.h" +#include "../include/can_queue.h" + +#ifdef CAN_DEBUG + #define DEBUGQUE(fmt,args...) printk(KERN_ERR "can_queue (debug): " fmt,\ + ##args) + + atomic_t edge_num_cnt; +#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; + unsigned long flags; + struct canque_slot_t *slot; + spin_lock_irqsave(&fifo->fifo_lock, flags); + slot=fifo->head; + *fifo->tail=fifo->flist; + fifo->flist=slot; + fifo->head=NULL; + fifo->tail=&fifo->head; + ret=canque_fifo_test_and_set_fl(fifo,EMPTY); + spin_unlock_irqrestore(&fifo->fifo_lock, flags); + return ret; +} + + +/** + * canque_fifo_init_slots - 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_slots(struct canque_fifo_t *fifo, int slotsnr) +{ + int size; + struct canque_slot_t *slot; + if(!slotsnr) slotsnr=MAX_BUF_LENGTH; + size=sizeof(struct canque_slot_t)*slotsnr; + fifo->entry=kmalloc(size,GFP_KERNEL); + if(!fifo->entry) 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; +} + +/** + * canque_fifo_done - frees slots allocated for CAN FIFO + * @fifo: pointer to the FIFO structure + */ +int canque_fifo_done(struct canque_fifo_t *fifo) +{ + if(fifo->entry) + kfree(fifo->entry); + fifo->entry=NULL; + 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) +*/ + +int canque_get_inslot(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd) +{ + int ret=-2; + unsigned long flags; + struct canque_edge_t *edge; + + spin_lock_irqsave(&qends->ends_lock, flags); + if(!list_empty(&qends->inlist)){ + edge=list_entry(qends->inlist.next,struct canque_edge_t,inpeers); + if(!canque_fifo_test_fl(&edge->fifo,BLOCK)&&!canque_fifo_test_fl(&edge->fifo,DEAD)){ + atomic_inc(&edge->edge_used); + spin_unlock_irqrestore(&qends->ends_lock, flags); + 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; + + } + spin_lock_irqsave(&qends->ends_lock, flags); + if(atomic_dec_and_test(&edge->edge_used)) + canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); + } + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + *qedgep=NULL; + DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd); + return ret; +} + +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; + unsigned long flags; + struct canque_edge_t *edge, *bestedge=NULL; + struct list_head *entry; + + spin_lock_irqsave(&qends->ends_lock, flags); + list_for_each(entry,&qends->inlist){ + edge=list_entry(entry,struct canque_edge_t,inpeers); + if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD)) + continue; + if((id^edge->filtid)&edge->filtmask) + continue; + if(bestedge){ + if(bestedge->filtmask){ + if (!edge->filtmask) continue; + } else { + if(edge->filtmask){ + bestedge=edge; + continue; + } + } + if(bestedge->edge_prioedge_prio){ + if(edge->edge_prio>prio) continue; + } else { + if(bestedge->edge_prio<=prio) continue; + } + } + bestedge=edge; + } + if((edge=bestedge)!=NULL){ + atomic_inc(&edge->edge_used); + spin_unlock_irqrestore(&qends->ends_lock, flags); + 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; + } + spin_lock_irqsave(&qends->ends_lock, flags); + if(atomic_dec_and_test(&edge->edge_used)) + canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + *qedgep=NULL; + DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio); + return ret; +} + + +int canque_put_inslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + unsigned long flags; + ret=canque_fifo_put_inslot(&qedge->fifo,slot); + if(ret) { + canque_activate_edge(qends,qedge); + canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC); + } + spin_lock_irqsave(&qends->ends_lock, flags); + if(atomic_dec_and_test(&qedge->edge_used)) + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); + spin_unlock_irqrestore(&qends->ends_lock, flags); + DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +int canque_abort_inslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + unsigned long flags; + ret=canque_fifo_abort_inslot(&qedge->fifo,slot); + if(ret) { + canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE); + } + spin_lock_irqsave(&qends->ends_lock, flags); + if(atomic_dec_and_test(&qedge->edge_used)) + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); + spin_unlock_irqrestore(&qends->ends_lock, flags); + DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg) +{ + int destnr=0; + int ret; + unsigned long flags; + struct canque_edge_t *edge; + struct list_head *entry; + struct canque_slot_t *slot; + + DEBUGQUE("canque_filter_msg2edges for msg ID %ld\n",msg->id); + spin_lock_irqsave(&qends->ends_lock, flags); + list_for_each(entry,&qends->inlist){ + edge=list_entry(entry,struct canque_edge_t,inpeers); + if(canque_fifo_test_fl(&edge->fifo,BLOCK)||canque_fifo_test_fl(&edge->fifo,DEAD)) + continue; + if((msg->id^edge->filtid)&edge->filtmask) + continue; + atomic_inc(&edge->edge_used); + spin_unlock_irqrestore(&qends->ends_lock, flags); + 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); + } + + } + spin_lock_irqsave(&qends->ends_lock, flags); + if(atomic_dec_and_test(&edge->edge_used)) + canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR); + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr); + return destnr; +} + +int canque_test_outslot(struct canque_ends_t *qends, + struct canque_edge_t **qedgep, struct canque_slot_t **slotp) +{ + unsigned long flags; + int prio; + struct canque_edge_t *edge; + + spin_lock_irqsave(&qends->ends_lock, flags); + for(prio=CANQUEUE_PRIO_NR;--prio>=0;){ + if(!list_empty(&qends->active[prio])){ + edge=list_entry(qends->active[prio].next,struct canque_edge_t,outpeers); + atomic_inc(&edge->edge_used); + spin_unlock_irqrestore(&qends->ends_lock, flags); + *qedgep=edge; + DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num); + return canque_fifo_test_outslot(&edge->fifo, slotp); + } + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + *qedgep=NULL; + DEBUGQUE("canque_test_outslot no ready slot\n"); + return -1; +} + +int canque_free_outslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + unsigned long 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); + spin_lock_irqsave(&qends->ends_lock, flags); + if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB){ + spin_lock(&qedge->fifo.fifo_lock); + if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){ + list_del(&qedge->outpeers); + list_add(&qedge->outpeers,&qends->idle); + } + #if CANQUE_ROUNDROB + else{ + list_del(&qedge->outpeers); + list_add_tail(&qedge->outpeers,&qends->active[qedge->edge_prio]); + } + #endif /*CANQUE_ROUNDROB*/ + spin_unlock(&qedge->fifo.fifo_lock); + } + if(atomic_dec_and_test(&qedge->edge_used)) + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); + spin_unlock_irqrestore(&qends->ends_lock, flags); + DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +int canque_again_outslot(struct canque_ends_t *qends, + struct canque_edge_t *qedge, struct canque_slot_t *slot) +{ + int ret; + unsigned long flags; + ret=canque_fifo_again_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); + spin_lock_irqsave(&qends->ends_lock, flags); + if(atomic_dec_and_test(&qedge->edge_used)) + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); + spin_unlock_irqrestore(&qends->ends_lock, flags); + DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +int canque_set_filt(struct canque_edge_t *qedge, + unsigned long filtid, unsigned long filtmask) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&qedge->fifo.fifo_lock,flags); + atomic_inc(&qedge->edge_used); + qedge->filtid=filtid; + qedge->filtmask=filtmask; + if(canque_fifo_test_fl(&qedge->fifo,DEAD)) ret=-1; + else ret=canque_fifo_test_and_set_fl(&qedge->fifo,BLOCK)?1:0; + + spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags); + if(ret>=0){ + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH); + } + spin_lock_irqsave(&qedge->fifo.fifo_lock,flags); + if(!ret)canque_fifo_clear_fl(&qedge->fifo,BLOCK); + if(atomic_dec_and_test(&qedge->edge_used)) + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); + spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags); + + DEBUGQUE("canque_set_filt for edge %d, ID %ld and mask %ld returned %d\n",qedge->edge_num,filtid,filtmask,ret); + return ret; +} + +int canque_flush(struct canque_edge_t *qedge) +{ + int ret; + unsigned long flags; + + atomic_inc(&qedge->edge_used); + ret=canque_fifo_flush_slots(&qedge->fifo); + if(ret){ + canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY); + canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE); + spin_lock_irqsave(&qedge->outends->ends_lock, flags); + spin_lock(&qedge->fifo.fifo_lock); + if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){ + list_del(&qedge->outpeers); + list_add(&qedge->outpeers,&qedge->outends->idle); + } + if(atomic_dec_and_test(&qedge->edge_used)) + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); + spin_unlock(&qedge->fifo.fifo_lock); + spin_unlock_irqrestore(&qedge->outends->ends_lock, flags); + } + DEBUGQUE("canque_flush for edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +int canqueue_ends_init_gen(struct canque_ends_t *qends) +{ + int i; + for(i=CANQUEUE_PRIO_NR;--i>=0;){ + INIT_LIST_HEAD(&qends->active[i]); + } + INIT_LIST_HEAD(&qends->idle); + INIT_LIST_HEAD(&qends->inlist); + spin_lock_init(&qends->ends_lock); + return 0; +} + + +void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what) +{ + DEBUGQUE("canqueue_notify_kern for edge %d and event %d\n",qedge->edge_num,what); + switch(what){ + case CANQUEUE_NOTIFY_EMPTY: + wake_up_interruptible(&qends->endinfo.fileinfo.emptyq); + break; + case CANQUEUE_NOTIFY_SPACE: + wake_up_interruptible(&qends->endinfo.fileinfo.writeq); + break; + case CANQUEUE_NOTIFY_PROC: + wake_up_interruptible(&qends->endinfo.fileinfo.readq); + break; + case CANQUEUE_NOTIFY_NOUSR: + wake_up_interruptible(&qends->endinfo.fileinfo.readq); + wake_up_interruptible(&qends->endinfo.fileinfo.writeq); + wake_up_interruptible(&qends->endinfo.fileinfo.emptyq); + break; + case CANQUEUE_NOTIFY_DEAD: + if(atomic_read(&qedge->edge_used)>0) + atomic_dec(&qedge->edge_used); + break; + case CANQUEUE_NOTIFY_ATACH: + atomic_inc(&qedge->edge_used); + break; + } +} + +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); + qends->notify=canqueue_notify_kern; + DEBUGQUE("canqueue_ends_init_kern\n"); + return 0; +} + + +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; +} + +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; +} + +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))); + return ret; +} + + +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)); + if(canque_fifo_init_slots(&qedge->fifo, slotsnr)<0){ + kfree(qedge); + DEBUGQUE("canque_new_edge_kern failed\n"); + return NULL; + } + atomic_set(&qedge->edge_used,0); + qedge->filtid = 0; + qedge->filtmask = 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; +} + +int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends) +{ + unsigned long flags; + if(qedge == NULL) return -1; + DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num); + atomic_inc(&qedge->edge_used); + spin_lock_irqsave(&inends->ends_lock, flags); + spin_lock(&outends->ends_lock); + spin_lock(&qedge->fifo.fifo_lock); + qedge->inends=inends; + list_add(&qedge->inpeers,&inends->inlist); + qedge->outends=outends; + list_add(&qedge->outpeers,&outends->idle); + spin_unlock(&qedge->fifo.fifo_lock); + spin_unlock(&outends->ends_lock); + spin_unlock_irqrestore(&inends->ends_lock, flags); + canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATACH); + + spin_lock_irqsave(&qedge->fifo.fifo_lock, flags); + if(atomic_dec_and_test(&qedge->edge_used)) + canque_notify_bothends(qedge,CANQUEUE_NOTIFY_NOUSR); + spin_unlock_irqrestore(&qedge->fifo.fifo_lock, flags); + return 0; +} + +int canqueue_disconnect_edge(struct canque_edge_t *qedge) +{ + int ret; + unsigned long flags; + spin_lock_irqsave(&qedge->inends->ends_lock,flags); + spin_lock(&qedge->outends->ends_lock); + spin_lock(&qedge->fifo.fifo_lock); + if(atomic_read(&qedge->edge_used)==0) { + if(qedge->outends){ + list_del(&qedge->outpeers); + qedge->outends=NULL; + } + if(qedge->inends){ + list_del(&qedge->inpeers); + qedge->inends=NULL; + } + ret=1; + } else ret=-1; + spin_unlock(&qedge->fifo.fifo_lock); + spin_unlock(&qedge->outends->ends_lock); + spin_unlock_irqrestore(&qedge->inends->ends_lock,flags); + DEBUGQUE("canqueue_disconnect_edge %d returned %d\n",qedge->edge_num,ret); + return ret; +} + +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_interruptible((qends->endinfo.fileinfo.emptyq), + (canqueue_disconnect_edge(qedge)>=0)); + return 0; + } else { + DEBUGQUE("canqueue_disconnect_edge_kern failed\n"); + return -1; + } +} + + +int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list) +{ + struct canque_edge_t *edge; + unsigned long flags; + for(;;){ + spin_lock_irqsave(&qends->ends_lock,flags); + if(list_empty(list)){ + 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); + spin_unlock_irqrestore(&qends->ends_lock,flags); + if(canqueue_disconnect_edge_kern(qends, edge)>=0) { + /* Free edge memory */ + canque_fifo_done(&edge->fifo); + kfree(edge); + }else{ + 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; + } + } +} + +void canqueue_block_list(struct canque_ends_t *qends, struct list_head *list) +{ + struct canque_edge_t *edge; + struct list_head *entry; + unsigned long flags; + + spin_lock_irqsave(&qends->ends_lock, flags); + list_for_each(entry,&qends->inlist){ + 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); + canque_fifo_set_fl(&edge->fifo,BLOCK); + /*spin_unlock_irqrestore(&qends->ends_lock, flags);*/ + /* Loop can be break by interrupts and preempts there */ + /*spin_lock_irqsave(&qends->ends_lock, flags);*/ + } + spin_unlock_irqrestore(&qends->ends_lock, flags); +} + + +int canqueue_ends_done_kern(struct canque_ends_t *qends, int sync) +{ + unsigned long flags; + int i; + + DEBUGQUE("canqueue_ends_done_kern\n"); + spin_lock_irqsave(&qends->ends_lock,flags); + canqueue_block_list(qends, &qends->idle); + for(i=CANQUEUE_PRIO_NR;--i>=0;){ + canqueue_block_list(qends, &qends->active[i]); + } + canqueue_block_list(qends, &qends->idle); + canqueue_block_list(qends, &qends->inlist); + spin_unlock_irqrestore(&qends->ends_lock,flags); + + for(i=CANQUEUE_PRIO_NR;--i>=0;){ + canqueue_disconnect_list_kern(qends, &qends->active[i]); + } + canqueue_disconnect_list_kern(qends, &qends->idle); + canqueue_disconnect_list_kern(qends, &qends->inlist); + + wake_up_interruptible(&qends->endinfo.fileinfo.readq); + wake_up_interruptible(&qends->endinfo.fileinfo.writeq); + wake_up_interruptible(&qends->endinfo.fileinfo.emptyq); + + + return 0; +} + diff --git a/lincan/src/cc_can104.c b/lincan/src/cc_can104.c index 8530a76..521bec7 100644 --- a/lincan/src/cc_can104.c +++ b/lincan/src/cc_can104.c @@ -1,18 +1,13 @@ /* cc_can104.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -45,15 +40,13 @@ * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int cc104_request_io(unsigned long io_addr) +int cc104_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + }else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); } return 0; } @@ -70,9 +63,9 @@ int cc104_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/template.c */ -int cc104_release_io(unsigned long io_addr) +int cc104_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -87,7 +80,7 @@ int cc104_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int cc104_reset(int card) +int cc104_reset(struct candevice_t *candev) { return 0; } @@ -110,12 +103,13 @@ int cc104_reset(int card) * Return Value: The function always returns zero * File: src/template.c */ -int cc104_init_hw_data(int card) +int cc104_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=0; - candevices_p[card]->nr_sja1000_chips=1; - candevices_p[card]->flags |= ~PROGRAMMABLE_IRQ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=1; + candev->nr_all_chips=1; + candev->flags &= ~PROGRAMMABLE_IRQ; return 0; } @@ -150,14 +144,14 @@ int cc104_init_hw_data(int card) * Return Value: The function always returns zero * File: src/template.c */ -int cc104_init_chip_data(int card, int chipnr) +int cc104_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->flags = 0; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->flags = 0; + candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_LH; return 0; @@ -180,10 +174,10 @@ int cc104_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/template.c */ -int cc104_init_obj_data(int chipnr, int objnr) +int cc104_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + chip->msgobj[objnr]->flags=0; return 0; } @@ -200,7 +194,7 @@ int cc104_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int cc104_program_irq(int card) +int cc104_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/close.c b/lincan/src/close.c index 5f7d112..b1146be 100644 --- a/lincan/src/close.c +++ b/lincan/src/close.c @@ -1,23 +1,24 @@ /* close.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #define __NO_VERSION__ #include #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#include +#else +#include +#endif #include "../include/main.h" #include "../include/close.h" @@ -26,20 +27,30 @@ int can_close(struct inode *inode, struct file *file) { - objects_p[MINOR_NR]->flags &= ~BUFFERS_ALLOCATED; - /* Give up message buffer memory */ - if (objects_p[MINOR_NR]->fifo->buf_tx_entry) - del_mem_from_list(objects_p[MINOR_NR]->fifo->buf_tx_entry); - else - CANMSG("objects_p[MINOR_NR]->fifo->buf_tx_entry is NULL\n"); - if (objects_p[MINOR_NR]->fifo->buf_rx_entry) - del_mem_from_list(objects_p[MINOR_NR]->fifo->buf_rx_entry); - else - CANMSG("objects_p[MINOR_NR]->fifo->buf_rx_entry is NULL\n"); - -/* FIXME: what about clearing chip HW status, stopping sending messages etc? */ + struct canuser_t *canuser = (struct canuser_t*)(file->private_data); + struct canque_ends_t *qends; + struct msgobj_t *obj; + + if(!canuser || (canuser->magic != CAN_USER_MAGIC)){ + CANMSG("can_close: bad canuser magic\n"); + return -ENODEV; + } + + obj = canuser->msgobj; + qends = canuser->qends; + + list_del(&canuser->peers); + canqueue_ends_done_kern(qends, 1); + canuser->qends = NULL; + kfree(qends); + + kfree(canuser); + + if(atomic_dec_and_test(&obj->obj_used)){ + obj->flags &= ~OBJ_OPENED; + /* FIXME: what about clearing chip HW status, stopping sending messages etc? */ + }; - objects_p[MINOR_NR]->flags &= ~OPENED; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50)) MOD_DEC_USE_COUNT; #endif diff --git a/lincan/src/devcommon.c b/lincan/src/devcommon.c new file mode 100644 index 0000000..9cd29d0 --- /dev/null +++ b/lincan/src/devcommon.c @@ -0,0 +1,66 @@ +/* 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.2 9 Jul 2003 + */ + +#define __NO_VERSION__ +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#include +#else +#include +#endif +#include +#include "../include/can.h" +#include "../include/can_queue.h" +#include "../include/main.h" +#include "../include/devcommon.h" + +void canqueue_notify_chip(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what) +{ + struct chip_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_interruptible(&qends->endinfo.chipinfo.daemonq); + break;*/ + case CANQUEUE_NOTIFY_PROC: + /*wake_up_interruptible(&qends->endinfo.chipinfo.daemonq);*/ + chip->chipspecops->wakeup_tx(chip, obj); + break; + case CANQUEUE_NOTIFY_DEAD: + if(atomic_read(&qedge->edge_used)>0) + atomic_dec(&qedge->edge_used); + break; + case CANQUEUE_NOTIFY_ATACH: + atomic_inc(&qedge->edge_used); + break; + } +} + + +int canqueue_ends_init_chip(struct canque_ends_t *qends, struct chip_t *chip, struct msgobj_t *obj) +{ + int ret; + ret=canqueue_ends_init_gen(qends); + if(ret<0) return ret; + + qends->context=NULL; + init_waitqueue_head(&qends->endinfo.chipinfo.daemonq); + qends->endinfo.chipinfo.chip=chip; + qends->endinfo.chipinfo.msgobj=obj; + qends->notify=canqueue_notify_chip; + + DEBUGMSG("canqueue_ends_init_chip\n"); + return 0; +} + + diff --git a/lincan/src/i82527.c b/lincan/src/i82527.c index 5ab2dcf..c10db6b 100644 --- a/lincan/src/i82527.c +++ b/lincan/src/i82527.c @@ -1,31 +1,50 @@ /* i82527.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #define __NO_VERSION__ #include #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif +#include #include #include "../include/main.h" #include "../include/i82527.h" +void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *obj, + struct rtr_id *rtr_search, unsigned long message_id); + + extern int stdmask; extern int extmask; extern int mo15mask; +/* helper functions for segmented cards read and write configuration and status registers + above 0xf offset */ + +void i82527_seg_write_reg(const struct chip_t *chip, unsigned char data, unsigned address) +{ + if((address > 0xf) && (chip->flags & CHIP_SEGMENTED)) + canobj_write_reg(chip, chip->msgobj[(address>>4)-1],data, address & 0xf); + else + can_write_reg(chip, data, address); +} + +unsigned i82527_seg_read_reg(const struct chip_t *chip, unsigned address) +{ + if((address > 0xf) && (chip->flags & CHIP_SEGMENTED)) + return canobj_read_reg(chip, chip->msgobj[(address>>4)-1], address & 0xf); + else + return can_read_reg(chip, address); +} + int i82527_enable_configuration(struct chip_t *chip) { unsigned short flags=0; @@ -50,19 +69,19 @@ int i82527_chip_config(struct chip_t *chip) { can_write_reg(chip,chip->int_cpu_reg,iCPU); // Configure cpu interface can_write_reg(chip,(iCTL_CCE|iCTL_INI),iCTL); // Enable configuration - can_write_reg(chip,chip->int_clk_reg,iCLK); // Set clock out slew rates - can_write_reg(chip,chip->int_bus_reg,iBUS); /* Bus configuration */ + i82527_seg_write_reg(chip,chip->int_clk_reg,iCLK); // Set clock out slew rates + i82527_seg_write_reg(chip,chip->int_bus_reg,iBUS); /* Bus configuration */ can_write_reg(chip,0x00,iSTAT); /* Clear error status register */ /* Check if we can at least read back some arbitrary data from the * card. If we can not, the card is not properly configured! */ - can_write_reg(chip,0x25,MSG_OFFSET(1)+iMSGDAT1); - can_write_reg(chip,0x52,MSG_OFFSET(2)+iMSGDAT3); - can_write_reg(chip,0xc3,MSG_OFFSET(10)+iMSGDAT6); - if ( (can_read_reg(chip,MSG_OFFSET(1)+iMSGDAT1) != 0x25) || - (can_read_reg(chip,MSG_OFFSET(2)+iMSGDAT3) != 0x52) || - (can_read_reg(chip,MSG_OFFSET(10)+iMSGDAT6) != 0xc3) ) { + canobj_write_reg(chip,chip->msgobj[1],0x25,iMSGDAT1); + canobj_write_reg(chip,chip->msgobj[2],0x52,iMSGDAT3); + canobj_write_reg(chip,chip->msgobj[10],0xc3,iMSGDAT6); + if ( (canobj_read_reg(chip,chip->msgobj[1],iMSGDAT1) != 0x25) || + (canobj_read_reg(chip,chip->msgobj[2],iMSGDAT3) != 0x52) || + (canobj_read_reg(chip,chip->msgobj[10],iMSGDAT6) != 0xc3) ) { CANMSG("Could not read back from the hardware.\n"); CANMSG("This probably means that your hardware is not correctly configured!\n"); return -1; @@ -160,7 +179,7 @@ int i82527_baud_rate(struct chip_t *chip, int rate, int clock, int sjw, (100*(best_tseg-tseg2)/(best_tseg+1))); - can_write_reg(chip, sjw<<6 | best_brp, iBT0); + i82527_seg_write_reg(chip, sjw<<6 | best_brp, iBT0); can_write_reg(chip, ((flags & BTR1_SAM) != 0)<<7 | tseg2<<4 | tseg1, iBT1); DEBUGMSG("Writing 0x%x to iBT0\n",(sjw<<6 | best_brp)); @@ -230,24 +249,24 @@ int i82527_message15_mask(struct chip_t *chip, unsigned long code, unsigned long int i82527_clear_objects(struct chip_t *chip) { int i=0,id=0,data=0; + struct msgobj_t *obj; DEBUGMSG("Cleared all message objects on chip\n"); for (i=1; i<=15; i++) { - can_write_reg(chip,(INTPD_RES|RXIE_RES|TXIE_RES|MVAL_RES) , - MSG_OFFSET(i)+iMSGCTL0); - can_write_reg(chip,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES) , - MSG_OFFSET(i)+iMSGCTL1); + obj=chip->msgobj[i]; + canobj_write_reg(chip,obj,(INTPD_RES|RXIE_RES|TXIE_RES|MVAL_RES),iMSGCTL0); + canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1); for (data=0x07; data<0x0f; data++) - can_write_reg(chip,0x00,MSG_OFFSET(i)+data); + canobj_write_reg(chip,obj,0x00,data); for (id=2; id<6; id++) { - can_write_reg(chip,0x00,MSG_OFFSET(i)+id); + canobj_write_reg(chip,obj,0x00,id); } if (extended==0) { - can_write_reg(chip,0x00,MSG_OFFSET(i)+iMSGCFG); + canobj_write_reg(chip,obj,0x00,iMSGCFG); } else { - can_write_reg(chip,MCFG_XTD,MSG_OFFSET(i)+iMSGCFG); + canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG); } } if (extended==0) @@ -268,56 +287,49 @@ int i82527_config_irqs(struct chip_t *chip, short irqs) int i82527_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) { if (extended) { - can_write_reg(chip,MCFG_XTD,MSG_OFFSET(obj->object)+iMSGCFG); + canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG); } else { - can_write_reg(chip,0x00,MSG_OFFSET(obj->object)+iMSGCFG); + canobj_write_reg(chip,obj,0x00,iMSGCFG); } - can_write_reg(chip ,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), - MSG_OFFSET(obj->object)+iMSGCTL1); - can_write_reg(chip ,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), - MSG_OFFSET(obj->object)+iMSGCTL0); + canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1); + canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0); return 0; } -int i82527_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, +int i82527_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { int i=0,id0=0,id1=0,id2=0,id3=0; - can_write_reg(chip,(RMPD_RES|TXRQ_RES|CPUU_SET|NEWD_RES), - MSG_OFFSET(obj->object)+iMSGCTL1); - can_write_reg(chip,(MVAL_SET|TXIE_SET|RXIE_RES|INTPD_RES), - MSG_OFFSET(obj->object)+iMSGCTL0); + canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|CPUU_SET|NEWD_RES),iMSGCTL1); + canobj_write_reg(chip,obj,(MVAL_SET|TXIE_SET|RXIE_RES|INTPD_RES),iMSGCTL0); if (extended) { - can_write_reg(chip,(msg->length<<4)+(MCFG_DIR|MCFG_XTD), - MSG_OFFSET(obj->object)+iMSGCFG); + canobj_write_reg(chip,obj,(msg->length<<4)+(MCFG_DIR|MCFG_XTD),iMSGCFG); } else { - can_write_reg(chip,(msg->length<<4)+MCFG_DIR, - MSG_OFFSET(obj->object)+iMSGCFG); + canobj_write_reg(chip,obj,(msg->length<<4)+MCFG_DIR,iMSGCFG); } if (extended) { id0 = (unsigned char) (msg->id<<3); id1 = (unsigned char) (msg->id>>5); id2 = (unsigned char) (msg->id>>13); id3 = (unsigned char) (msg->id>>21); - can_write_reg(chip,id0,MSG_OFFSET(obj->object)+iMSGID3); - can_write_reg(chip,id1,MSG_OFFSET(obj->object)+iMSGID2); - can_write_reg(chip,id2,MSG_OFFSET(obj->object)+iMSGID1); - can_write_reg(chip,id3,MSG_OFFSET(obj->object)+iMSGID0); + canobj_write_reg(chip,obj,id0,iMSGID3); + canobj_write_reg(chip,obj,id1,iMSGID2); + canobj_write_reg(chip,obj,id2,iMSGID1); + canobj_write_reg(chip,obj,id3,iMSGID0); } else { id1 = (unsigned char) (msg->id<<5); id0 = (unsigned char) (msg->id>>3); - can_write_reg(chip,id1,MSG_OFFSET(obj->object)+iMSGID1); - can_write_reg(chip,id0,MSG_OFFSET(obj->object)+iMSGID0); + canobj_write_reg(chip,obj,id1,iMSGID1); + canobj_write_reg(chip,obj,id0,iMSGID0); } - can_write_reg(chip,0xfa,MSG_OFFSET(obj->object)+iMSGCTL1); + canobj_write_reg(chip,obj,0xfa,iMSGCTL1); for (i=0; ilength; i++) { - can_write_reg(chip,msg->data[i],MSG_OFFSET(obj->object)+ - iMSGDAT0+i); + canobj_write_reg(chip,obj,msg->data[i],iMSGDAT0+i); } return 0; @@ -327,12 +339,10 @@ int i82527_send_msg(struct chip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { if (msg->flags & MSG_RTR) { - can_write_reg(chip,(RMPD_RES|TXRQ_RES|CPUU_RES|NEWD_SET), - MSG_OFFSET(obj->object)+iMSGCTL1); + canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|CPUU_RES|NEWD_SET),iMSGCTL1); } else { - can_write_reg(chip,(RMPD_RES|TXRQ_SET|CPUU_RES|NEWD_SET), - MSG_OFFSET(obj->object)+iMSGCTL1); + canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_SET|CPUU_RES|NEWD_SET),iMSGCTL1); } return 0; @@ -352,10 +362,8 @@ int i82527_check_tx_stat(struct chip_t *chip) int i82527_remote_request(struct chip_t *chip, struct msgobj_t *obj) { - can_write_reg(chip, (MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), - MSG_OFFSET(obj->object)+iMSGCTL0); - can_write_reg(chip, (RMPD_RES|TXRQ_SET|MLST_RES|NEWD_RES), - MSG_OFFSET(obj->object)+iMSGCTL1); + canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0); + canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_SET|MLST_RES|NEWD_RES),iMSGCTL1); return 0; } @@ -366,8 +374,8 @@ int i82527_set_btregs(struct chip_t *chip, unsigned short btr0, if (i82527_enable_configuration(chip)) return -ENODEV; - can_write_reg(chip, btr0, iBT0); - can_write_reg(chip, btr1, iBT1); + i82527_seg_write_reg(chip, btr0, iBT0); + i82527_seg_write_reg(chip, btr1, iBT1); i82527_disable_configuration(chip); @@ -394,6 +402,187 @@ int i82527_stop_chip(struct chip_t *chip) return 0; } +inline void i82527_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj) +{ + int cmd; + + canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),+iMSGCTL0); + + if(obj->tx_slot){ + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + } + + cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot); + if(cmd<0) + return; + + 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; + } +} + +inline void i82527_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj, + unsigned long message_id) +{ + int i=0, tmp=1 ; + + while (tmp) { + canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),iMSGCTL1); + canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0); + + obj->rx_msg.length =(canobj_read_reg(chip,obj,iMSGCFG) & 0xf0) >> 4; + obj->rx_msg.id = message_id; + for (i=0; i < obj->rx_msg.length; i++) + obj->rx_msg.data[i] = canobj_read_reg(chip,obj,iMSGDAT0+i); + +//FIXME: Add buffer overflow check, currently it's silently over written! + + canque_filter_msg2edges(obj->qends, &obj->rx_msg); + + if (!((tmp=canobj_read_reg(chip,obj,iMSGCTL1)) & NEWD_SET)) { + break; + } + + if (tmp & MLST_SET) + CANMSG("Message lost!\n"); + + } +} + +irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + int id0=0, id1=0, id2=0, id3=0; + + unsigned irq_register; + unsigned object; + struct chip_t *chip=(struct chip_t *)dev_id; + struct msgobj_t *obj; + unsigned long message_id; + struct rtr_id *rtr_search; + + /*put_reg=device->hwspecops->write_register;*/ + /*get_reg=device->hwspecops->read_register;*/ + + irq_register = i82527_seg_read_reg(chip, iIRQ); + + while (irq_register) { + + if (irq_register == 0x01) { + DEBUGMSG("Status register: 0x%x\n",can_read_reg(chip, iSTAT)); + return IRQ_NONE; + } + + if (irq_register == 0x02) + object = 14; + else + object = irq_register-3; + + obj=chip->msgobj[object]; + + if (canobj_read_reg(chip,obj,iMSGCFG) & MCFG_DIR) { + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES) + i82527_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + } + } + else { + + if (extended) { + id0=canobj_read_reg(chip,obj,iMSGID3); + id1=canobj_read_reg(chip,obj,iMSGID2)<<8; + id2=canobj_read_reg(chip,obj,iMSGID1)<<16; + id3=canobj_read_reg(chip,obj,iMSGID0)<<24; + message_id=(id0|id1|id2|id3)>>3; + } + else { + id0=canobj_read_reg(chip,obj,iMSGID1); + id1=canobj_read_reg(chip,obj,iMSGID0)<<8; + message_id=(id0|id1)>>5; + } + + spin_lock(&hardware_p->rtr_lock); + rtr_search=hardware_p->rtr_queue; + while (rtr_search != NULL) { + if (rtr_search->id == message_id) + break; + rtr_search=rtr_search->next; + } + spin_unlock(&hardware_p->rtr_lock); + if ((rtr_search!=NULL) && (rtr_search->id==message_id)) + i82527_irq_rtr_handler(chip, obj, rtr_search, message_id); + else + i82527_irq_read_handler(chip, obj, message_id); + } + + irq_register=i82527_seg_read_reg(chip, iIRQ); + } + return IRQ_HANDLED; +} + +void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *obj, + struct rtr_id *rtr_search, unsigned long message_id) +{ + short int i=0; + + canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),iMSGCTL0); + canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),iMSGCTL1); + + spin_lock(&hardware_p->rtr_lock); + + rtr_search->rtr_message->id=message_id; + rtr_search->rtr_message->length=(canobj_read_reg(chip,obj,iMSGCFG) & 0xf0)>>4; + for (i=0; irtr_message->length; i++) + rtr_search->rtr_message->data[i]=canobj_read_reg(chip,obj,iMSGDAT0+i); + + spin_unlock(&hardware_p->rtr_lock); + + if (waitqueue_active(&rtr_search->rtr_wq)) + wake_up_interruptible(&rtr_search->rtr_wq); +} + +int i82527_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj) +{ + /* dummy lock to prevent preemption fully portable way */ + spinlock_t dummy_lock; + + /* preempt_disable() */ + spin_lock_init(&dummy_lock); + spin_lock(&dummy_lock); + + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES) + i82527_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + } + + /* preempt_enable(); */ + spin_unlock(&dummy_lock); + return 0; +} + int i82527_register(struct chipspecops_t *chipspecops) { chipspecops->chip_config = i82527_chip_config; @@ -407,11 +596,13 @@ int i82527_register(struct chipspecops_t *chipspecops) chipspecops->pre_write_config = i82527_pre_write_config; chipspecops->send_msg = i82527_send_msg; chipspecops->check_tx_stat = i82527_check_tx_stat; + chipspecops->wakeup_tx = i82527_wakeup_tx; chipspecops->remote_request = i82527_remote_request; chipspecops->enable_configuration = i82527_enable_configuration; chipspecops->disable_configuration = i82527_disable_configuration; chipspecops->set_btregs = i82527_set_btregs; chipspecops->start_chip = i82527_start_chip; chipspecops->stop_chip = i82527_stop_chip; + chipspecops->irq_handler = i82527_irq_handler; return 0; } diff --git a/lincan/src/ioctl.c b/lincan/src/ioctl.c index ec029ab..40a4204 100644 --- a/lincan/src/ioctl.c +++ b/lincan/src/ioctl.c @@ -1,22 +1,18 @@ /* ioctl.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include #include +#include #include "../include/main.h" #include "../include/ioctl.h" @@ -27,16 +23,25 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int i=0; unsigned short channel=0; unsigned btr0=0, btr1=0; + struct canuser_t *canuser = (struct canuser_t*)(file->private_data); struct msgobj_t *obj; - struct chip_t *chip = objects_p[MINOR_NR]->hostchip; - struct canfifo_t *fifo = objects_p[MINOR_NR]->fifo; - - /* Initialize hardware pointers */ - if ( (obj = objects_p[MINOR_NR]) == NULL) { + struct chip_t *chip; + struct canque_ends_t *qends; + + if(!canuser || (canuser->magic != CAN_USER_MAGIC)){ + CANMSG("can_close: bad canuser magic\n"); + return -ENODEV; + } + + obj = canuser->msgobj; + if (obj == NULL) { CANMSG("Could not assign buffer structure\n"); return -1; } - if ( (chip = obj->hostchip) == NULL) { + + qends = canuser->qends; + chip = obj->hostchip; + if (chip == NULL) { CANMSG("Device is not correctly configured.\n"); CANMSG("Please reload the driver.\n"); return -1; @@ -49,60 +54,58 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned break; } case CMD_START: { - if (chips_p[arg]->chipspecops->start_chip(chip)) + if (chip->chipspecops->start_chip(chip)) return -1; break; } case CMD_STOP: { - if (chips_p[arg]->chipspecops->stop_chip(chip)) + if (chip->chipspecops->stop_chip(chip)) return -1; break; } case CONF_FILTER: { + #if 0 if (!strcmp(chip->chip_type,"i82527")) { unsigned char id1, id0; id1 = (unsigned char) (arg << 5); id0 = (unsigned char) (arg >> 3); - DEBUGMSG("configuring ID=%lx in message object: - %02x, %02x\n", arg, id0, id1); + DEBUGMSG("configuring ID=%lx in message object:" + " %02x, %02x\n", arg, id0, id1); can_write_reg(chip,id1,MSG_OFFSET(obj->object) + iMSGID1); can_write_reg(chip,id0,MSG_OFFSET(obj->object) + iMSGID0); } + #endif /* In- and output buffer re-initialization */ - fifo->tx_readp = fifo->buf_tx_entry; - fifo->tx_writep = fifo->buf_tx_entry; - fifo->rx_readp = fifo->buf_rx_entry; - fifo->rx_writep = fifo->buf_rx_entry; - fifo->rx_size= MAX_BUF_LENGTH * sizeof(struct canmsg_t); - fifo->tx_size = fifo->rx_size; - - #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) - init_waitqueue(&fifo->readq); - init_waitqueue(&fifo->writeq); - #else - init_waitqueue_head(&fifo->readq); - init_waitqueue_head(&fifo->writeq); - #endif - - fifo->rx_in_progress = 0; - fifo->tx_in_progress = 0; + if(canuser->rx_edge0){ + canque_set_filt(canuser->rx_edge0, arg, ~0); + canque_flush(canuser->rx_edge0); + } break; } + + case CONF_FILTER_QUE0: { + struct canfilt_t canfilt; + copy_from_user(&canfilt, (void*)arg, sizeof(struct canfilt_t)); + if(canuser->rx_edge0){ + canque_set_filt(canuser->rx_edge0, canfilt.id, canfilt.mask); + canque_flush(canuser->rx_edge0); + } + break; + } case CONF_BAUD: { channel = arg & 0xff; btr0 = (arg >> 8) & 0xff; btr1 = (arg >> 16) & 0xff; - if (chips_p[channel]->chipspecops->set_btregs(chip, - btr0, btr1)) { + if (chip->chipspecops->set_btregs(chip, btr0, btr1)) { CANMSG("Error setting bit timing registers\n"); return -1; } diff --git a/lincan/src/irq.c b/lincan/src/irq.c index caf0ac6..1623ce8 100644 --- a/lincan/src/irq.c +++ b/lincan/src/irq.c @@ -1,18 +1,13 @@ /* irq.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -25,303 +20,9 @@ #include "../include/main.h" #include "../include/irq.h" -#include "../include/i82527.h" -#include "../include/sja1000.h" - -void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *msgobj, - struct rtr_id *rtr_search, unsigned long message_id); -void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj); -void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj); - -/*struct candevice_t *device=NULL; -unsigned object=0,irq_register=0; -unsigned long msgbase=0; -struct canfifo_t *fifo=NULL; -unsigned long message_id=0; -struct rtr_id *rtr_search; -*/ - -inline void i82527_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj) -{ - struct canfifo_t *fifo=msgobj->fifo; - unsigned long msgbase=msgobj->obj_base_addr; - void (*write_reg)(unsigned char data, unsigned long address); - unsigned (*read_reg)(unsigned long address); - write_reg=chip->hostdevice->hwspecops->write_register; - read_reg=chip->hostdevice->hwspecops->read_register; - - (*write_reg)((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase+iMSGCTL0); - - fifo->tx_readp++; - if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH) - fifo->tx_readp = fifo->buf_tx_entry; - if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty - fifo->tx_in_progress = 0; - if (waitqueue_active(&fifo->writeq)) { - msgobj->ret = 0; - wake_up_interruptible(&fifo->writeq); - } - return; - } - if (chip->chipspecops->pre_write_config(chip, msgobj, fifo->tx_readp)) { - if (waitqueue_active(&fifo->writeq)) { - msgobj->ret = -1; - wake_up_interruptible(&fifo->writeq); - return; - } - } - if (chip->chipspecops->send_msg(chip, msgobj, fifo->tx_readp)) { - if (waitqueue_active(&fifo->writeq)) { - msgobj->ret = -1; - wake_up_interruptible(&fifo->writeq); - return; - } - } -} - -inline void i82527_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj, - unsigned long message_id) -{ - int i=0, tmp=1 ; - struct canfifo_t *fifo=msgobj->fifo; - unsigned long msgbase=msgobj->obj_base_addr; - void (*write_reg)(unsigned char data, unsigned long address); - unsigned (*read_reg)(unsigned long address); - write_reg=chip->hostdevice->hwspecops->write_register; - read_reg=chip->hostdevice->hwspecops->read_register; - - while (tmp) { - (*write_reg)((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES), msgbase + - iMSGCTL1); - (*write_reg)((MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), msgbase + - iMSGCTL0); - - fifo->rx_writep->length =((*read_reg)(msgbase+iMSGCFG) & 0xf0) >> 4; - fifo->rx_writep->id = message_id; - for (i=0; i < fifo->rx_writep->length; i++) - fifo->rx_writep->data[i] = (*read_reg)(msgbase+iMSGDAT0+i); - -//FIXME: Add buffer overflow check, currently it's silently over written! - - fifo->rx_writep++; - if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) - fifo->rx_writep = fifo->buf_rx_entry; - - if (!((tmp=(*read_reg)(msgbase + iMSGCTL1)) & NEWD_SET)) { - break; - } - - if (tmp & MLST_SET) - CANMSG("Message lost!\n"); - - } - if (waitqueue_active(&fifo->readq)) { - wake_up_interruptible(&fifo->readq); - } -} - -void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - int id0=0, id1=0, id2=0, id3=0; - - unsigned irq_register; - unsigned object; - struct chip_t *chip=(struct chip_t *)dev_id; - struct msgobj_t *msgobj; - unsigned long msgbase; - unsigned long message_id; - struct rtr_id *rtr_search; - void (*write_reg)(unsigned char data, unsigned long address); - unsigned (*read_reg)(unsigned long address); - write_reg=chip->hostdevice->hwspecops->write_register; - read_reg=chip->hostdevice->hwspecops->read_register; - - /*put_reg=device->hwspecops->write_register;*/ - /*get_reg=device->hwspecops->read_register;*/ - - if ( (chip->flags & SEGMENTED) != 0) - irq_register = can_read_reg(chip, iIRQ+SPACING); - else - irq_register = can_read_reg(chip, iIRQ); - - while (irq_register) { - - if (irq_register == 0x01) { - DEBUGMSG("Status register: 0x%x\n",can_read_reg(chip, iSTAT)); - return; - } - - if (irq_register == 0x02) - object = 14; - else - object = irq_register-3; - - msgobj=chip->msgobj[object]; - msgbase=msgobj->obj_base_addr; - - if ((*read_reg)(msgbase+iMSGCFG) & MCFG_DIR) { - i82527_irq_write_handler(chip, msgobj); - } - else { - - if (extended) { - id0=(*read_reg)(msgbase+iMSGID3); - id1=(*read_reg)(msgbase+iMSGID2)<<8; - id2=(*read_reg)(msgbase+iMSGID1)<<16; - id3=(*read_reg)(msgbase+iMSGID0)<<24; - message_id=(id0|id1|id2|id3)>>3; - } - else { - id0=(*read_reg)(msgbase+iMSGID1); - id1=(*read_reg)(msgbase+iMSGID0)<<8; - message_id=(id0|id1)>>5; - } - spin_lock(&hardware_p->rtr_lock); - rtr_search=hardware_p->rtr_queue; - while (rtr_search != NULL) { - if (rtr_search->id == message_id) - break; - rtr_search=rtr_search->next; - } - spin_unlock(&hardware_p->rtr_lock); - if ((rtr_search!=NULL) && (rtr_search->id==message_id)) - i82527_irq_rtr_handler(chip, msgobj, rtr_search, message_id); - else - i82527_irq_read_handler(chip, msgobj, message_id); - } - - if ( (chip->flags & SEGMENTED) != 0) - irq_register=can_read_reg(chip, iIRQ+SPACING); - else - irq_register=can_read_reg(chip, iIRQ); - } - -} - -void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *msgobj, - struct rtr_id *rtr_search, unsigned long message_id) -{ - short int i=0; - unsigned long msgbase=msgobj->obj_base_addr; - void (*write_reg)(unsigned char data, unsigned long address); - unsigned (*read_reg)(unsigned long address); - write_reg=chip->hostdevice->hwspecops->write_register; - read_reg=chip->hostdevice->hwspecops->read_register; - - (*write_reg)((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase + iMSGCTL0); - (*write_reg)((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),msgbase + iMSGCTL1); - - spin_lock(&hardware_p->rtr_lock); - - rtr_search->rtr_message->id=message_id; - rtr_search->rtr_message->length=((*read_reg)(msgbase + iMSGCFG) & 0xf0)>>4; - for (i=0; irtr_message->length; i++) - rtr_search->rtr_message->data[i]=(*read_reg)(msgbase+iMSGDAT0+i); - - spin_unlock(&hardware_p->rtr_lock); - - if (waitqueue_active(&rtr_search->rtr_wq)) - wake_up_interruptible(&rtr_search->rtr_wq); -} - -void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned irq_register; - struct chip_t *chip=(struct chip_t *)dev_id; - struct msgobj_t *msgobj; - struct canfifo_t *fifo; - - 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 & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0) - return; - - msgobj=chip->msgobj[0]; - fifo=msgobj->fifo; - - if ((irq_register & IR_RI) != 0) - sja1000_irq_read_handler(chip, msgobj); - if ((irq_register & IR_TI) != 0) - sja1000_irq_write_handler(chip, msgobj); - if ((irq_register & (IR_EI|IR_DOI)) != 0) { - // Some error happened -// 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 - CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", - can_read_reg(chip, SJASR), irq_register); - chip->msgobj[0]->ret=-1; - if (waitqueue_active(&fifo->writeq)) - wake_up_interruptible(&fifo->writeq); - if (waitqueue_active(&fifo->readq)) - wake_up_interruptible(&fifo->readq); - } - - return; -} - -void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj) -{ - int i=0, id=0; - struct canfifo_t *fifo=msgobj->fifo; - - do { - id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); - fifo->rx_writep->length = id & 0x0f; - fifo->rx_writep->flags = id&ID0_RTR ? MSG_RTR : 0; - fifo->rx_writep->timestamp = 0; - fifo->rx_writep->cob = 0; - fifo->rx_writep->id = id>>5; - - for (i=0; irx_writep->length; i++) - fifo->rx_writep->data[i]=can_read_reg(chip, SJARXDAT0 + i); - - can_write_reg(chip, CMR_RRB, SJACMR); - - fifo->rx_writep++; - if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) - fifo->rx_writep = fifo->buf_rx_entry; - - } while(can_read_reg(chip, SJASR) & SR_RBS); - - if (waitqueue_active(&fifo->readq)) - wake_up_interruptible(&fifo->readq); -} - -void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj) -{ - struct canfifo_t *fifo=msgobj->fifo; - - fifo->tx_readp++; - if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH) - fifo->tx_readp = fifo->buf_tx_entry; - if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty - fifo->tx_in_progress = 0; - if (waitqueue_active(&fifo->writeq)) { - msgobj->ret = 0; - wake_up_interruptible(&fifo->writeq); - } - return; - } - if (chip->chipspecops->pre_write_config(chip, msgobj, fifo->tx_readp)) { - if (waitqueue_active(&fifo->writeq)) { - msgobj->ret = -1; - wake_up_interruptible(&fifo->writeq); - return; - } - } - if (chip->chipspecops->send_msg(chip, msgobj, fifo->tx_readp)) { - if (waitqueue_active(&fifo->writeq)) { - msgobj->ret = -1; - wake_up_interruptible(&fifo->writeq); - return; - } - } -} -void dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { +irqreturn_t dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { CANMSG("dummy_irq_handler called irq %d \n", irq); + return IRQ_NONE; } diff --git a/lincan/src/m437.c b/lincan/src/m437.c index 3be6f65..7405160 100644 --- a/lincan/src/m437.c +++ b/lincan/src/m437.c @@ -1,8 +1,10 @@ /* m437.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ /* @@ -21,13 +23,6 @@ */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#ifdef MODVERSIONS -#include -#endif #include #include @@ -62,15 +57,20 @@ static long base = 0L; * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/m437.c */ -int m437_request_io(unsigned long io_addr) +int m437_request_io(struct candevice_t *candev) { - if ( !( base = (long) ioremap( io_addr, IO_RANGE ) ) ) { - CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr); + if (!request_mem_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to request IO-memory: 0x%lx\n",candev->io_addr); + return -ENODEV; + } + + if ( !( base = (long) ioremap( candev->io_addr, IO_RANGE ) ) ) { + CANMSG("Unable to access I/O memory at: 0x%lx\n", candev->io_addr); return -ENODEV; } - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); return 0; } @@ -86,7 +86,7 @@ int m437_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/m437.c */ -int m437_release_io(unsigned long io_addr) +int m437_release_io(struct candevice_t *candev) { unsigned i; @@ -116,6 +116,8 @@ int m437_release_io(unsigned long io_addr) /* release I/O memory mapping */ iounmap((void*)base); + release_mem_region(candev->io_addr,IO_RANGE); + return 0; } @@ -129,7 +131,7 @@ int m437_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/m437.c */ -int m437_reset(int card) +int m437_reset(struct candevice_t *candev) { return 0; } @@ -152,13 +154,14 @@ int m437_reset(int card) * Return Value: The function always returns zero * File: src/m437.c */ -int m437_init_hw_data(int card) +int m437_init_hw_data(struct candevice_t *candev) { DEBUGMSG("m437_init_hw_data()\n"); - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=1; - candevices_p[card]->nr_sja1000_chips=0; - candevices_p[card]->flags &= ~PROGRAMMABLE_IRQ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=1; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=1; + candev->flags &= ~PROGRAMMABLE_IRQ; /* The M437 has no programmable IRQ */ return 0; @@ -197,15 +200,15 @@ int m437_init_hw_data(int card) * Return Value: The function always returns zero * File: src/m437.c */ -int m437_init_chip_data(int card, int chipnr) +int m437_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC | iCPU_CEN; - candevices_p[card]->chip[chipnr]->int_clk_reg = + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC | iCPU_CEN; + candev->chip[chipnr]->int_clk_reg = iCLK_CD0 | iCLK_CD1 | iCLK_CD2 | iCLK_SL0 | iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; return 0; } @@ -227,10 +230,10 @@ int m437_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/m437.c */ -int m437_init_obj_data(int chipnr, int objnr) +int m437_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } @@ -247,7 +250,7 @@ int m437_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/m437.c */ -int m437_program_irq(int card) +int m437_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/main.c b/lincan/src/main.c index f21e78f..d04c39c 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -1,32 +1,30 @@ /* main.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #define EXPORT_SYMTAB #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif #include -#if defined (MODVERSIONS) -#include -#endif - #include #include -#include #include #include #include #include #include +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,50)) +#include +#endif + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) #include #else @@ -40,12 +38,15 @@ #endif #endif +/*#undef CONFIG_DEVFS_FS*/ + #ifdef CONFIG_DEVFS_FS #include #endif #include "../include/main.h" #include "../include/modparms.h" +#include "../include/devcommon.h" #include "../include/setup.h" #include "../include/proc.h" #include "../include/open.h" @@ -97,7 +98,6 @@ MODULE_DESCRIPTION("Universal Linux CAN-bus device driver"); /* Global structures, used to describe the installed hardware. */ struct canhardware_t canhardware; struct canhardware_t *hardware_p=&canhardware; -struct candevice_t *candevices_p[MAX_HW_CARDS]; struct chip_t *chips_p[MAX_TOT_CHIPS]; struct msgobj_t *objects_p[MAX_TOT_MSGOBJS]; #ifdef CONFIG_DEVFS_FS @@ -142,6 +142,7 @@ EXPORT_SYMBOL(can_fops); int init_module(void) { int res=0,i=0; + struct candevice_t *candev; if (parse_mod_parms()) return -EINVAL; @@ -160,12 +161,14 @@ int init_module(void) } for (i=0; inr_boards; i++) { - if (candevices_p[i]->hwspecops->request_io(candevices_p[i]->io_addr)) - goto memory_error; + candev=hardware_p->candevice[i]; + if (candev->hwspecops->request_io(candev)) + goto memory_error; } for (i=0; inr_boards; i++) { - if (candevices_p[i]->hwspecops->reset(i)) + candev=hardware_p->candevice[i]; + if (candev->hwspecops->reset(candev)) goto reset_error; } @@ -174,16 +177,8 @@ int init_module(void) i=0; while ( (chips_p[i] != NULL) && (i < MAX_TOT_CHIPS) ) { - if (!strcmp(chips_p[i]->chip_type,"i82527")) { - if (request_irq(chips_p[i]->chip_irq,i82527_irq_handler,SA_SHIRQ,DEVICE_NAME,chips_p[i])) - goto interrupt_error; - else - DEBUGMSG("Registered interrupt %d\n",chips_p[i]->chip_irq); - } - if (!strcmp(chips_p[i]->chip_type,"sja1000p") || - !strcmp(chips_p[i]->chip_type,"sja1000")) { - if (request_irq(chips_p[i]->chip_irq, - chips_p[i]->chipspecops->irq_handler,SA_SHIRQ,DEVICE_NAME,chips_p[i])) + if (chips_p[i]->chipspecops->irq_handler) { + if (request_irq(chips_p[i]->chip_irq,chips_p[i]->chipspecops->irq_handler,SA_SHIRQ,DEVICE_NAME,chips_p[i])) goto interrupt_error; else DEBUGMSG("Registered interrupt %d\n",chips_p[i]->chip_irq); @@ -192,8 +187,9 @@ int init_module(void) } for (i=0; inr_boards; i++) { - if (candevices_p[i]->flags & PROGRAMMABLE_IRQ) - if (candevices_p[i]->hwspecops->program_irq(i)) + candev=hardware_p->candevice[i]; + if (candev->flags & PROGRAMMABLE_IRQ) + if (candev->hwspecops->program_irq(candev)) goto interrupt_error; } @@ -233,8 +229,10 @@ int init_module(void) goto memory_error; memory_error: ; - for (i=0; inr_boards; i++) - candevices_p[i]->hwspecops->release_io(candevices_p[i]->io_addr); + for (i=0; inr_boards; i++) { + candev=hardware_p->candevice[i]; + candev->hwspecops->release_io(candev); + } goto register_error; register_error: ; @@ -250,6 +248,7 @@ int init_module(void) void cleanup_module(void) { int res=0,i=0; + struct candevice_t *candev; #ifdef CONFIG_PROC_FS if (can_delete_procdir()) @@ -268,8 +267,10 @@ void cleanup_module(void) i++; } - for (i=0; inr_boards; i++) - candevices_p[i]->hwspecops->release_io(candevices_p[i]->io_addr); + for (i=0; inr_boards; i++){ + candev=hardware_p->candevice[i]; + candev->hwspecops->release_io(candev); + } if ( del_mem_list() ) CANMSG("Error deallocating memory\n"); diff --git a/lincan/src/modparms.c b/lincan/src/modparms.c index cf4a325..96d66d5 100644 --- a/lincan/src/modparms.c +++ b/lincan/src/modparms.c @@ -1,19 +1,14 @@ /* mod_parms.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include ".supported_cards.h" @@ -170,24 +165,17 @@ int list_hw(void) printk(KERN_ERR "\n"); DEBUGMSG("Hardware : %s\n",hardware_p->candevice[i]->hwname); DEBUGMSG("IO address : 0x%lx\n",hardware_p->candevice[i]->io_addr); + DEBUGMSG("Nr. all chips : %d\n",hardware_p->candevice[i]->nr_all_chips); DEBUGMSG("Nr. of i82527 : %d\n",hardware_p->candevice[i]->nr_82527_chips); DEBUGMSG("Nr. of sja1000 : %d\n",hardware_p->candevice[i]->nr_sja1000_chips); - for (j=0; jcandevice[i]->nr_82527_chips+hardware_p->candevice[i]->nr_sja1000_chips; j++) { + for (j=0; jcandevice[i]->nr_all_chips; j++) { DEBUGMSG("Chip%d type : %s\n", j+1, hardware_p->candevice[i]->chip[j]->chip_type); DEBUGMSG("Chip base : 0x%lx\n",hardware_p->candevice[i]->chip[j]->chip_base_addr); DEBUGMSG("Interrupt : %d\n",hardware_p->candevice[i]->chip[j]->chip_irq); - if (!strcmp(hardware_p->candevice[i]->chip[j]->chip_type,"i82527")) { - for (k=0; k<15; k++) - DEBUGMSG("Obj%d: minor: %d base: 0x%lx\n",k,hardware_p->candevice[i]->chip[j]->msgobj[k]->minor,hardware_p->candevice[i]->chip[j]->msgobj[k]->obj_base_addr); - } - - if (!strcmp(hardware_p->candevice[i]->chip[j]->chip_type,"sja1000")) { - for (k=0; k<1; k++) - DEBUGMSG("Obj%d: minor: %d base: 0x%lx\n",k,hardware_p->candevice[i]->chip[j]->msgobj[k]->minor,hardware_p->candevice[i]->chip[j]->msgobj[k]->obj_base_addr); - } - + for (k=0; kcandevice[i]->chip[j]->max_objects; k++) + DEBUGMSG("Obj%d: minor: %d base: 0x%lx\n",k,hardware_p->candevice[i]->chip[j]->msgobj[k]->minor,hardware_p->candevice[i]->chip[j]->msgobj[k]->obj_base_addr); } i++; diff --git a/lincan/src/nsi.c b/lincan/src/nsi.c index 3fefebc..289a1ed 100644 --- a/lincan/src/nsi.c +++ b/lincan/src/nsi.c @@ -1,18 +1,13 @@ /* nsi.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -36,19 +31,17 @@ unsigned long nsican_base=0x0; /* The function template_request_io is used to reserve the io-memory. If your * hardware uses a dedicated memory range as hardware control registers you * will have to add the code to reserve this memory as well. - * The reserved memory starts at io_addr, wich is the module parameter io. + * The reserved memory starts at candev->io_addr, wich is the module parameter io. */ -int nsi_request_io(unsigned long io_addr) +int nsi_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, - io_addr + IO_RANGE - 1); + } else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, + candev->io_addr + IO_RANGE - 1); } return 0; } @@ -56,10 +49,10 @@ int nsi_request_io(unsigned long io_addr) /* The function template_release_io is used to free the previously reserved * io-memory. In case you reserved more memory, don't forget to free it here. */ -int nsi_release_io(unsigned long io_addr) +int nsi_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -68,15 +61,15 @@ int nsi_release_io(unsigned long io_addr) * hardware specific so I haven't included example code. Don't forget to check * the reset status of the chip before returning. */ -int nsi_reset(int card) +int nsi_reset(struct candevice_t *candev) { int i; DEBUGMSG("Resetting nsi hardware ...\n"); /* we don't use template_write_register because we don't use the two first register of the card but the third in order to make a hard reset */ - outb (1, nsican_base + candevices_p[card]->res_addr); - outb (0, nsican_base + candevices_p[card]->res_addr); + outb (1, nsican_base + candev->res_addr); + outb (0, nsican_base + candev->res_addr); for (i = 1; i < 1000; i++) udelay (1000); @@ -110,12 +103,13 @@ int nsi_reset(int card) #define NR_82527 1 #define NR_SJA1000 0 -int nsi_init_hw_data(int card) +int nsi_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=1; - candevices_p[card]->nr_sja1000_chips=0; - candevices_p[card]->flags |= PROGRAMMABLE_IRQ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=1; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=1; + candev->flags |= PROGRAMMABLE_IRQ; return 0; } @@ -125,23 +119,23 @@ int nsi_init_hw_data(int card) * CHIP_TYPE represents the type of CAN chip. CHIP_TYPE can be "i82527" or * "sja1000". * The chip_base_addr entry represents the start of the 'official' memory map - * of the installed chip. It's likely that this is the same as the io_addr + * of the installed chip. It's likely that this is the same as the candev->io_addr * argument supplied at module loading time. * The clock argument holds the chip clock value in Hz. */ #define CHIP_TYPE "i82527" -int nsi_init_chip_data(int card, int chipnr) +int nsi_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr= - candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - nsican_irq=candevices_p[card]->chip[chipnr]->chip_irq; - nsican_base=candevices_p[card]->chip[chipnr]->chip_base_addr; - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC; - candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr= + candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + nsican_irq=candev->chip[chipnr]->chip_irq; + nsican_base=candev->chip[chipnr]->chip_base_addr; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; return 0; } @@ -156,12 +150,12 @@ int nsi_init_chip_data(int card, int chipnr) * base address. * Unless the hardware uses a segmented memory map, flags can be set zero. */ -int nsi_init_obj_data(int chipnr, int objnr) +int nsi_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr= - chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr= + chip->chip_base_addr+(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } @@ -172,7 +166,7 @@ int nsi_init_obj_data(int chipnr, int objnr) * function unedited. Again this function is hardware specific so there's no * example code. */ -int nsi_program_irq(int card) +int nsi_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/open.c b/lincan/src/open.c index f9ff108..e980f16 100644 --- a/lincan/src/open.c +++ b/lincan/src/open.c @@ -1,30 +1,24 @@ /* open.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #define __NO_VERSION__ #include #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) #include #else #include #endif -#include #include "../include/main.h" #include "../include/open.h" @@ -35,7 +29,8 @@ int can_open(struct inode *inode, struct file *file) { struct msgobj_t *obj; struct chip_t *chip; - struct canfifo_t *fifo; + struct canuser_t *canuser; + struct canque_ends_t *qends; if ( ((obj=objects_p[MINOR_NR]) == NULL) || ((chip=objects_p[MINOR_NR]->hostchip) == NULL) ) { @@ -43,64 +38,62 @@ int can_open(struct inode *inode, struct file *file) return -ENODEV; } - if (objects_p[MINOR_NR]->flags & OPENED) { - CANMSG("Sorry, only single open per device file.\n"); - return -EBUSY; - } - else - objects_p[MINOR_NR]->flags |= OPENED; + atomic_inc(&obj->obj_used); + DEBUGMSG("Device %d opened %d times.\n", MINOR_NR, atomic_read(&obj->obj_used)); + obj->flags |= OBJ_OPENED; - if (chip->flags & CONFIGURED) + if (chip->flags & CHIP_CONFIGURED) DEBUGMSG("Device is already configured.\n"); else { if (chip->chipspecops->chip_config(chip)) CANMSG("Error configuring chip.\n"); else - chip->flags |= CONFIGURED; + chip->flags |= CHIP_CONFIGURED; + + if (chip->chipspecops->pre_read_config(chip,obj)<0) + CANMSG("Error initializing chip for receiving\n"); + + /* chip->flags |= OBJ_BUFFERS_ALLOCATED; */ + } /* End of chip configuration */ - /* Allocate output buffer memory for the opened device */ - fifo = objects_p[MINOR_NR]->fifo; - fifo->buf_tx_entry=(struct canmsg_t *)kmalloc(MAX_BUF_LENGTH * sizeof(struct canmsg_t), GFP_KERNEL); - if (fifo->buf_tx_entry == NULL) - return -ENOMEM; - else - if ( add_mem_to_list(fifo->buf_tx_entry) ) - return -ENOMEM; - /* Allocate input buffer memory for the opened device */ - fifo->buf_rx_entry=(struct canmsg_t *)kmalloc(MAX_BUF_LENGTH * sizeof(struct canmsg_t), GFP_KERNEL); - if (fifo->buf_rx_entry == NULL) - return -ENOMEM; - else - if ( add_mem_to_list(fifo->buf_rx_entry) ) - return -ENOMEM; - - /* In- and output buffer initialization */ - fifo->tx_readp = fifo->buf_tx_entry; - fifo->tx_writep = fifo->buf_tx_entry; - fifo->rx_readp = fifo->buf_rx_entry; - fifo->rx_writep = fifo->buf_rx_entry; - fifo->rx_size = MAX_BUF_LENGTH * sizeof(struct canmsg_t); - fifo->tx_size = fifo->rx_size; - -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) - init_waitqueue(&fifo->readq); - init_waitqueue(&fifo->writeq); -#else - init_waitqueue_head(&fifo->readq); - init_waitqueue_head(&fifo->writeq); -#endif + canuser = (struct canuser_t *)kmalloc(sizeof(struct canuser_t), GFP_KERNEL); + if(canuser == NULL) goto no_canuser; + canuser->file = file; + canuser->msgobj = obj; + canuser->magic = CAN_USER_MAGIC; + file->private_data = canuser; - fifo->rx_in_progress = 0; - fifo->tx_in_progress = 0; + qends = (struct canque_ends_t *)kmalloc(sizeof(struct canque_ends_t), GFP_KERNEL); + if(qends == NULL) goto no_qends; + canqueue_ends_init_kern(qends); + canuser->qends = qends; + + list_add(&canuser->peers, &obj->obj_users); - chip->flags |= BUFFERS_ALLOCATED; + if(canqueue_connect_edge(canque_new_edge_kern(MAX_BUF_LENGTH), + canuser->qends, obj->qends)<0) goto no_qedge; + + if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_kern(MAX_BUF_LENGTH), + obj->qends, canuser->qends)<0) goto no_qedge; - if (chip->chipspecops->pre_read_config(chip,obj)<0) - CANMSG("Error initializing chip for receiving\n"); - #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50)) MOD_INC_USE_COUNT; #endif + return 0; + + no_qedge: + list_del(&canuser->peers); + canqueue_ends_done_kern(qends, 1); + canuser->qends = NULL; + kfree(qends); + obj->qends = NULL; + + no_qends: + kfree(canuser); + + no_canuser: + atomic_dec(&obj->obj_used); + return -ENOMEM; } diff --git a/lincan/src/pc_i03.c b/lincan/src/pc_i03.c index bf64ff6..0490fe6 100644 --- a/lincan/src/pc_i03.c +++ b/lincan/src/pc_i03.c @@ -1,18 +1,13 @@ /* pc-i03.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wnadoo.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 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -50,15 +45,13 @@ unsigned int pci03_base_addr; * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/pc-i03.c */ -int pci03_request_io(unsigned long io_addr) +int pci03_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + } else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); } return 0; } @@ -75,9 +68,9 @@ int pci03_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/pc-i03.c */ -int pci03_release_io(unsigned long io_addr) +int pci03_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -92,7 +85,7 @@ int pci03_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/pc-i03.c */ -int pci03_reset(int card) +int pci03_reset(struct candevice_t *candev) { int i=0; @@ -139,13 +132,12 @@ int pci03_reset(int card) * Return Value: The function always returns zero * File: src/pc-i03.c */ -int pci03_init_hw_data(int card) +int pci03_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=NR_82527; - candevices_p[card]->nr_sja1000_chips=NR_SJA1000; - candevices_p[card]->flags |= ~PROGRAMMABLE_IRQ; - + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=NR_SJA1000; + candev->nr_all_chips=NR_82527+NR_SJA1000; return 0; } @@ -179,14 +171,14 @@ int pci03_init_hw_data(int card) * Return Value: The function always returns zero * File: src/pc-i03.c */ -int pci03_init_chip_data(int card, int chipnr) +int pci03_init_chip_data(struct candevice_t *candev, int chipnr) { - pci03_base_addr = candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | + pci03_base_addr = candev->io_addr; + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_HL | OCR_TX1_LZ; return 0; @@ -209,10 +201,10 @@ int pci03_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/pc-i03.c */ -int pci03_init_obj_data(int chipnr, int objnr) +int pci03_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + chip->msgobj[objnr]->flags=0; return 0; } @@ -229,7 +221,7 @@ int pci03_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/pc-i03.c */ -int pci03_program_irq(int card) +int pci03_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/pccan.c b/lincan/src/pccan.c index bf5a8a8..06e9e05 100644 --- a/lincan/src/pccan.c +++ b/lincan/src/pccan.c @@ -1,170 +1,127 @@ /* pccan.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include -#include #include #include +#include #include "../include/main.h" #include "../include/pccan.h" #include "../include/i82527.h" #include "../include/sja1000.h" -int pccanf_request_io(unsigned long io_addr) +int pccanf_request_io(struct candevice_t *candev) { - if (check_region(io_addr+0x4000,0x20)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x4000); + if (!can_request_io_region(candev->io_addr+0x4000,0x20,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr+0x4000); return -ENODEV; } - else if (check_region(io_addr+0x6000,0x04)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x6000); + else if (!can_request_io_region(candev->io_addr+0x6000,0x04,DEVICE_NAME)) { + can_release_io_region(candev->io_addr+0x4000,0x20); + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr+0x6000); return -ENODEV; } else { - request_region(io_addr+0x4000,0x20,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x4000, io_addr+0x4000+0x20-1); - request_region(io_addr+0x6000,0x04,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x6000, io_addr+0x6000+0x04-1); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr+0x4000, candev->io_addr+0x4000+0x20-1); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr+0x6000, candev->io_addr+0x6000+0x04-1); } return 0; } -int pccand_request_io(unsigned long io_addr) +int pccand_request_io(struct candevice_t *candev) { - if (pccanf_request_io(io_addr)) + if (pccanf_request_io(candev)) return -ENODEV; - if (check_region(io_addr+0x5000,0x20)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x5000); + if (!can_request_io_region(candev->io_addr+0x5000,0x20,DEVICE_NAME)) { + pccanf_release_io(candev); + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr+0x5000); return -ENODEV; } else { - request_region(io_addr+0x5000,0x20,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x5000, io_addr+0x5000+0x20-1); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr+0x5000, candev->io_addr+0x5000+0x20-1); } return 0; } -int pccanq_request_io(unsigned long io_addr) +int pccanq_request_io(struct candevice_t *candev) { - if (pccand_request_io(io_addr)) + unsigned long io_addr; + int i; + + if (pccand_request_io(candev)) return -ENODEV; - if (check_region(io_addr+0x2000,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x2000); - return -ENODEV; - } - else if (check_region(io_addr+0x2400,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x2400); - return -ENODEV; - } - else if (check_region(io_addr+0x2800,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x2800); - return -ENODEV; - } - else if (check_region(io_addr+0x2C00,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x2C00); - return -ENODEV; - } - else if (check_region(io_addr+0x3000,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x3000); - return -ENODEV; - } - else if (check_region(io_addr+0x3400,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x3400); - return -ENODEV; - } - else if (check_region(io_addr+0x3800,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x3800); - return -ENODEV; - } - else if (check_region(io_addr+0x3C00,0x40)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x3C00); - return -ENODEV; - } - else { - request_region(io_addr+0x2000,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x2000, io_addr+0x2000+0x40-1); - request_region(io_addr+0x2400,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x2400, io_addr+0x2400+0x40-1); - request_region(io_addr+0x2800,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x2800, io_addr+0x2800+0x40-1); - request_region(io_addr+0x2C00,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x2C00, io_addr+0x2C00+0x40-1); - request_region(io_addr+0x3000,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x3000, io_addr+0x3000+0x40-1); - request_region(io_addr+0x3400,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x3400, io_addr+0x3400+0x40-1); - request_region(io_addr+0x3800,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x3800, io_addr+0x3800+0x40-1); - request_region(io_addr+0x3C00,0x40,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr+0x3C00, io_addr+0x3C00+0x40-1); + for(i=0, io_addr=candev->io_addr+0x2000; i<8; i++, io_addr+=0x400) { + if (!can_request_io_region(io_addr,0x40,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",io_addr); + while(i--){ + io_addr-=0x400; + can_release_io_region(io_addr,0x40); + } + pccand_release_io(candev); + return -ENODEV; + } + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr+0x40-1); } - return 0; } -int pccanf_release_io(unsigned long io_addr) +int pccanf_release_io(struct candevice_t *candev) { - release_region(io_addr+0x4000,0x20); - release_region(io_addr+0x6000,0x04); + can_release_io_region(candev->io_addr+0x4000,0x20); + can_release_io_region(candev->io_addr+0x6000,0x04); return 0; } -int pccand_release_io(unsigned long io_addr) +int pccand_release_io(struct candevice_t *candev) { - pccanf_release_io(io_addr); - release_region(io_addr+0x5000,0x20); + pccanf_release_io(candev); + can_release_io_region(candev->io_addr+0x5000,0x20); return 0; } -int pccanq_release_io(unsigned long io_addr) +int pccanq_release_io(struct candevice_t *candev) { - pccand_release_io(io_addr); - release_region(io_addr+0x2000,0x40); - release_region(io_addr+0x2400,0x40); - release_region(io_addr+0x2800,0x40); - release_region(io_addr+0x2C00,0x40); - release_region(io_addr+0x3000,0x40); - release_region(io_addr+0x3400,0x40); - release_region(io_addr+0x3800,0x40); - release_region(io_addr+0x3C00,0x40); + unsigned long io_addr; + int i; + + pccand_release_io(candev); + + for(i=0, io_addr=candev->io_addr+0x2000; i<8; i++, io_addr+=0x400) { + can_release_io_region(io_addr,0x40); + } return 0; } -int pccanf_reset(int card) +int pccanf_reset(struct candevice_t *candev) { int i=0; DEBUGMSG("Resetting pccanf/s hardware ...\n"); while (i < 1000000) { i++; - outb(0x00,candevices_p[card]->res_addr); + outb(0x00,candev->res_addr); } - outb(0x01,candevices_p[card]->res_addr); - outb(0x00,candevices_p[card]->chip[0]->chip_base_addr+SJACR); + outb(0x01,candev->res_addr); + outb(0x00,candev->chip[0]->chip_base_addr+SJACR); /* Check hardware reset status */ i=0; - while ( (inb(candevices_p[card]->chip[0]->chip_base_addr+SJACR) & CR_RR) + while ( (inb(candev->chip[0]->chip_base_addr+SJACR) & CR_RR) && (i<=15) ) { udelay(20000); i++; @@ -180,24 +137,24 @@ int pccanf_reset(int card) return 0; } -int pccand_reset(int card) +int pccand_reset(struct candevice_t *candev) { int i=0,chip_nr=0; DEBUGMSG("Resetting pccan-d hardware ...\n"); while (i < 1000000) { i++; - outb(0x00,candevices_p[card]->res_addr); + outb(0x00,candev->res_addr); } - outb(0x01,candevices_p[card]->res_addr); - outb(0x00,candevices_p[card]->chip[0]->chip_base_addr+SJACR); - outb(0x00,candevices_p[card]->chip[1]->chip_base_addr+SJACR); + outb(0x01,candev->res_addr); + outb(0x00,candev->chip[0]->chip_base_addr+SJACR); + outb(0x00,candev->chip[1]->chip_base_addr+SJACR); /* Check hardware reset status */ i=0; for (chip_nr=0; chip_nr<2; chip_nr++) { i=0; - while ( (inb(candevices_p[card]->chip[chip_nr]->chip_base_addr + + while ( (inb(candev->chip[chip_nr]->chip_base_addr + SJACR) & CR_RR) && (i<=15) ) { udelay(20000); i++; @@ -213,27 +170,27 @@ int pccand_reset(int card) return 0; } -int pccanq_reset(int card) +int pccanq_reset(struct candevice_t *candev) { int i=0,chip_nr=0; for (i=0; i<4; i++) - disable_irq(candevices_p[card]->chip[i]->chip_irq); + disable_irq(candev->chip[i]->chip_irq); DEBUGMSG("Resetting pccan-q hardware ...\n"); while (i < 100000) { i++; - outb(0x00,candevices_p[card]->res_addr); + outb(0x00,candev->res_addr); } - outb_p(0x01,candevices_p[card]->res_addr); + outb_p(0x01,candev->res_addr); - outb(0x00,candevices_p[card]->chip[2]->chip_base_addr+SJACR); - outb(0x00,candevices_p[card]->chip[3]->chip_base_addr+SJACR); + outb(0x00,candev->chip[2]->chip_base_addr+SJACR); + outb(0x00,candev->chip[3]->chip_base_addr+SJACR); /* Check hardware reset status */ for (chip_nr=0; chip_nr<2; chip_nr++) { i=0; - while( (inb(candevices_p[card]->chip[chip_nr]->chip_base_addr + + while( (inb(candev->chip[chip_nr]->chip_base_addr + iCPU) & iCPU_RST) && (i<=15) ) { udelay(20000); i++; @@ -248,7 +205,7 @@ int pccanq_reset(int card) } for (chip_nr=2; chip_nr<4; chip_nr++) { i=0; - while( (inb(candevices_p[card]->chip[chip_nr]->chip_base_addr + + while( (inb(candev->chip[chip_nr]->chip_base_addr + SJACR) & CR_RR) && (i<=15) ) { udelay(20000); i++; @@ -263,90 +220,93 @@ int pccanq_reset(int card) } for (i=0; i<4; i++) - enable_irq(candevices_p[card]->chip[i]->chip_irq); + enable_irq(candev->chip[i]->chip_irq); return 0; } -int pccan_init_hw_data(int card) +int pccan_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=candevices_p[card]->io_addr+0x6001; - candevices_p[card]->flags |= PROGRAMMABLE_IRQ; + candev->res_addr=candev->io_addr+0x6001; + candev->flags |= PROGRAMMABLE_IRQ; - if (!strcmp(candevices_p[card]->hwname,"pccan-q")) { - candevices_p[card]->nr_82527_chips=2; - candevices_p[card]->nr_sja1000_chips=2; + if (!strcmp(candev->hwname,"pccan-q")) { + candev->nr_82527_chips=2; + candev->nr_sja1000_chips=2; + candev->nr_all_chips=4; } - if (!strcmp(candevices_p[card]->hwname,"pccan-f") | - !strcmp(candevices_p[card]->hwname,"pccan-s")) { - candevices_p[card]->nr_82527_chips=0; - candevices_p[card]->nr_sja1000_chips=1; + if (!strcmp(candev->hwname,"pccan-f") | + !strcmp(candev->hwname,"pccan-s")) { + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=1; + candev->nr_all_chips=1; } - if (!strcmp(candevices_p[card]->hwname,"pccan-d")) { - candevices_p[card]->nr_82527_chips=0; - candevices_p[card]->nr_sja1000_chips=2; + if (!strcmp(candev->hwname,"pccan-d")) { + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=2; + candev->nr_all_chips=2; } return 0; } -int pccan_init_chip_data(int card, int chipnr) +int pccan_init_chip_data(struct candevice_t *candev, int chipnr) { - if (!strcmp(candevices_p[card]->hwname,"pccan-q")) { + if (!strcmp(candev->hwname,"pccan-q")) { if (chipnr<2) { - candevices_p[card]->chip[chipnr]->chip_type="i82527"; - candevices_p[card]->chip[chipnr]->flags = SEGMENTED; - candevices_p[card]->chip[chipnr]->int_cpu_reg=iCPU_DSC; - candevices_p[card]->chip[chipnr]->int_clk_reg=iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg=iBUS_CBY; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = 0; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = 0; + candev->chip[chipnr]->chip_type="i82527"; + candev->chip[chipnr]->flags = CHIP_SEGMENTED; + candev->chip[chipnr]->int_cpu_reg=iCPU_DSC; + candev->chip[chipnr]->int_clk_reg=iCLK_SL1; + candev->chip[chipnr]->int_bus_reg=iBUS_CBY; + candev->chip[chipnr]->sja_cdr_reg = 0; + candev->chip[chipnr]->sja_ocr_reg = 0; } else{ - candevices_p[card]->chip[chipnr]->chip_type="sja1000"; - candevices_p[card]->chip[chipnr]->flags = 0; - candevices_p[card]->chip[chipnr]->int_cpu_reg = 0; - candevices_p[card]->chip[chipnr]->int_clk_reg = 0; - candevices_p[card]->chip[chipnr]->int_bus_reg = 0; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = + candev->chip[chipnr]->chip_type="sja1000"; + candev->chip[chipnr]->flags = 0; + candev->chip[chipnr]->int_cpu_reg = 0; + candev->chip[chipnr]->int_clk_reg = 0; + candev->chip[chipnr]->int_bus_reg = 0; + candev->chip[chipnr]->sja_cdr_reg = CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_LH; } - candevices_p[card]->chip[chipnr]->chip_base_addr=0x1000*chipnr+0x2000+candevices_p[card]->io_addr; + candev->chip[chipnr]->chip_base_addr=0x1000*chipnr+0x2000+candev->io_addr; } else { - candevices_p[card]->chip[chipnr]->chip_type="sja1000"; - candevices_p[card]->chip[chipnr]->chip_base_addr=0x1000*chipnr+0x4000+candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->flags = 0; - candevices_p[card]->chip[chipnr]->int_cpu_reg = 0; - candevices_p[card]->chip[chipnr]->int_clk_reg = 0; - candevices_p[card]->chip[chipnr]->int_bus_reg = 0; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = + candev->chip[chipnr]->chip_type="sja1000"; + candev->chip[chipnr]->chip_base_addr=0x1000*chipnr+0x4000+candev->io_addr; + candev->chip[chipnr]->flags = 0; + candev->chip[chipnr]->int_cpu_reg = 0; + candev->chip[chipnr]->int_clk_reg = 0; + candev->chip[chipnr]->int_bus_reg = 0; + candev->chip[chipnr]->sja_cdr_reg = CDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_LH; } - candevices_p[card]->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->clock = 16000000; return 0; } -int pccan_init_obj_data(int chipnr, int objnr) +int pccan_init_obj_data(struct chip_t *chip, int objnr) { - if (!strcmp(chips_p[chipnr]->chip_type,"sja1000")) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr; - chips_p[chipnr]->msgobj[objnr]->flags=0; + if (!strcmp(chip->chip_type,"sja1000")) { + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + chip->msgobj[objnr]->flags=0; } - else { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10+(int)((objnr+1)/4)*0x3c0; - chips_p[chipnr]->msgobj[objnr]->flags=0; + else { /* The spacing for this card is 0x3c0 */ + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10+(int)((objnr+1)/4)*0x3c0; + chip->msgobj[objnr]->flags=0; } return 0; } -int pccan_program_irq(int card) +int pccan_program_irq(struct candevice_t *candev) { #define IRQ9 0x01 #define IRQ3 0x02 @@ -356,7 +316,7 @@ int pccan_program_irq(int card) int i; for (i=0; i<4; i++) { - switch (candevices_p[card]->chip[i]->chip_irq) { + switch (candev->chip[i]->chip_irq) { case 0: { break; } @@ -378,9 +338,9 @@ int pccan_program_irq(int card) } } } - outb(irq_reg_value,0x6000+candevices_p[card]->io_addr); + outb(irq_reg_value,0x6000+candev->io_addr); DEBUGMSG("Configured pccan hardware interrupts\n"); - outb(0x80,0x6000+candevices_p[card]->io_addr+0x02); + outb(0x80,0x6000+candev->io_addr+0x02); DEBUGMSG("Selected pccan on-board 16 MHz oscillator\n"); return 0; diff --git a/lincan/src/pcccan.c b/lincan/src/pcccan.c index e7b5b22..290a44a 100644 --- a/lincan/src/pcccan.c +++ b/lincan/src/pcccan.c @@ -1,8 +1,10 @@ /* pcccan.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ /* This file contains the low level functions for the pcccan-1 card from Gespac. @@ -10,13 +12,6 @@ */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -66,15 +61,13 @@ unsigned long pcccan_base=0x0; * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/pcccan.c */ -int pcccan_request_io(unsigned long io_addr) +int pcccan_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + } else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); } return 0; } @@ -91,9 +84,9 @@ int pcccan_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/pcccan.c */ -int pcccan_release_io(unsigned long io_addr) +int pcccan_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -108,20 +101,20 @@ int pcccan_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/pcccan.c */ -int pcccan_reset(int card) +int pcccan_reset(struct candevice_t *candev) { int i=0; DEBUGMSG("Resetting pcccan-1 hardware ...\n"); while (i < 1000000) { i++; - outb(0x0,candevices_p[card]->res_addr); + outb(0x0,candev->res_addr); } /* Check hardware reset status */ i=0; - outb(iCPU,candevices_p[card]->io_addr+0x1); - while ( (inb(candevices_p[card]->io_addr+0x2)&0x80) && (i<=15) ) { + outb(iCPU,candev->io_addr+0x1); + while ( (inb(candev->io_addr+0x2)&0x80) && (i<=15) ) { udelay(20000); i++; } @@ -153,12 +146,13 @@ int pcccan_reset(int card) * Return Value: The function always returns zero * File: src/pcccan.c */ -int pcccan_init_hw_data(int card) +int pcccan_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=candevices_p[card]->io_addr; - candevices_p[card]->nr_82527_chips=NR_82527; - candevices_p[card]->nr_sja1000_chips=NR_SJA1000; - candevices_p[card]->flags |= ~PROGRAMMABLE_IRQ; + candev->res_addr=candev->io_addr; + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=NR_SJA1000; + candev->nr_all_chips=NR_82527+NR_SJA1000; + candev->flags &= ~PROGRAMMABLE_IRQ; return 0; } @@ -196,18 +190,18 @@ int pcccan_init_hw_data(int card) * Return Value: The function always returns zero * File: src/pcccan.c */ -int pcccan_init_chip_data(int card, int chipnr) +int pcccan_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC | iCPU_DMC; - candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1 | iCLK_CD0; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY | iBUS_DR1; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = 0; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = 0; - pcccan_irq=candevices_p[card]->chip[chipnr]->chip_irq; - pcccan_base=candevices_p[card]->chip[chipnr]->chip_base_addr; + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC | iCPU_DMC; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1 | iCLK_CD0; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY | iBUS_DR1; + candev->chip[chipnr]->sja_cdr_reg = 0; + candev->chip[chipnr]->sja_ocr_reg = 0; + pcccan_irq=candev->chip[chipnr]->chip_irq; + pcccan_base=candev->chip[chipnr]->chip_base_addr; return 0; } @@ -229,10 +223,10 @@ int pcccan_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/pcccan.c */ -int pcccan_init_obj_data(int chipnr, int objnr) +int pcccan_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } @@ -249,7 +243,7 @@ int pcccan_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/pcccan.c */ -int pcccan_program_irq(int card) +int pcccan_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/pcm3680.c b/lincan/src/pcm3680.c index 853986a..2736035 100644 --- a/lincan/src/pcm3680.c +++ b/lincan/src/pcm3680.c @@ -1,18 +1,13 @@ /* pcm3680.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -31,13 +26,6 @@ #endif /*request_mem_region*/ #endif /* 2.4.0 */ -/* Basic hardware io address. This is also stored in the hardware structure but - * we need it global, else we have to change many internal functions. - * pcm3680_base_addr is initialized in pcm3680_init_chip_data(). - */ -unsigned long pcm3680_base_addr; -static unsigned long isa_base = 0L; - /* * IO_RANGE is the io-memory range that gets reserved, please adjust according * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or @@ -59,22 +47,21 @@ static unsigned long isa_base = 0L; * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int pcm3680_request_io(unsigned long io_addr) +int pcm3680_request_io(struct candevice_t *candev) { unsigned long remap_addr; - if (!request_mem_region(io_addr,IO_RANGE,DEVICE_NAME " - pcm3680")) { - CANMSG("Unable to request IO-memory: 0x%lx\n",io_addr); + if (!request_mem_region(candev->io_addr,IO_RANGE,DEVICE_NAME " - pcm3680")) { + CANMSG("Unable to request IO-memory: 0x%lx\n",candev->io_addr); return -ENODEV; } - if ( !( remap_addr = (long) ioremap( io_addr, IO_RANGE ) ) ) { - CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr); - release_mem_region(io_addr,IO_RANGE); + if ( !( remap_addr = (long) ioremap( candev->io_addr, IO_RANGE ) ) ) { + CANMSG("Unable to access I/O memory at: 0x%lx\n", candev->io_addr); + release_mem_region(candev->io_addr,IO_RANGE); return -ENODEV; } - isa_base=remap_addr-io_addr; - - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + can_base_addr_fixup(candev, remap_addr); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); return 0; } @@ -90,10 +77,10 @@ int pcm3680_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/template.c */ -int pcm3680_release_io(unsigned long io_addr) +int pcm3680_release_io(struct candevice_t *candev) { - iounmap((void*)isa_base); - release_mem_region(io_addr,IO_RANGE); + iounmap((void*)candev->dev_base_addr); + release_mem_region(candev->io_addr,IO_RANGE); return 0; } @@ -107,15 +94,15 @@ int pcm3680_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int pcm3680_reset(int card) +int pcm3680_reset(struct candevice_t *candev) { int i=0; struct chip_t *chip; int chipnr; DEBUGMSG("Resetting pcm3680 hardware ...\n"); - for(chipnr=0;chipnrnr_sja1000_chips;chipnr++) { - chip=candevices_p[card]->chip[chipnr]; + for(chipnr=0;chipnrnr_sja1000_chips;chipnr++) { + chip=candev->chip[chipnr]; pcm3680_write_register(MOD_RM, chip->chip_base_addr+SJAMOD); udelay(1000); pcm3680_write_register(0x00, chip->chip_base_addr + SJAIER); @@ -154,12 +141,13 @@ int pcm3680_reset(int card) * Return Value: The function always returns zero * File: src/template.c */ -int pcm3680_init_hw_data(int card) +int pcm3680_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=NR_82527; - candevices_p[card]->nr_sja1000_chips=NR_SJA1000; - candevices_p[card]->flags &= ~PROGRAMMABLE_IRQ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=NR_SJA1000; + candev->nr_all_chips=NR_82527+NR_SJA1000; + candev->flags &= ~PROGRAMMABLE_IRQ; return 0; } @@ -194,17 +182,16 @@ int pcm3680_init_hw_data(int card) * Return Value: The function always returns zero * File: src/template.c */ -int pcm3680_init_chip_data(int card, int chipnr) +int pcm3680_init_chip_data(struct candevice_t *candev, int chipnr) { - pcm3680_base_addr = candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr= - candevices_p[card]->io_addr + 0x200*chipnr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->int_clk_reg = 0x0; - candevices_p[card]->chip[chipnr]->int_bus_reg = 0x0; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr= + candev->io_addr + 0x200*chipnr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->int_clk_reg = 0x0; + candev->chip[chipnr]->int_bus_reg = 0x0; + candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_LH; return 0; @@ -227,10 +214,10 @@ int pcm3680_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/template.c */ -int pcm3680_init_obj_data(int chipnr, int objnr) +int pcm3680_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + chip->msgobj[objnr]->flags=0; return 0; } @@ -247,7 +234,7 @@ int pcm3680_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int pcm3680_program_irq(int card) +int pcm3680_program_irq(struct candevice_t *candev) { return 0; } @@ -265,7 +252,7 @@ int pcm3680_program_irq(int card) */ void pcm3680_write_register(unsigned char data, unsigned long address) { - writeb(data,isa_base+address); + writeb(data,address); } /** @@ -280,7 +267,7 @@ void pcm3680_write_register(unsigned char data, unsigned long address) */ unsigned pcm3680_read_register(unsigned long address) { - return readb(isa_base+address); + return readb(address); } /* !!! Don't change this function !!! */ diff --git a/lincan/src/pikronisa.c b/lincan/src/pikronisa.c index 104cbbc..fb6e3dc 100644 --- a/lincan/src/pikronisa.c +++ b/lincan/src/pikronisa.c @@ -1,18 +1,13 @@ /* pikronisa.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -31,8 +26,6 @@ */ #define IO_RANGE 0x100 -static long base = 0L; - /** * pikronisa_request_io: - reserve io memory * @io_addr: The reserved memory starts at @io_addr, wich is the module @@ -47,16 +40,22 @@ static long base = 0L; * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/pikronisa.c */ -int pikronisa_request_io(unsigned long io_addr) +int pikronisa_request_io(struct candevice_t *candev) { int remap_addr; - if ( !( remap_addr = (long) ioremap( io_addr, IO_RANGE ) ) ) { - CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr); + + if (!request_mem_region(candev->io_addr,IO_RANGE,DEVICE_NAME " - pikronisa")) { + CANMSG("Unable to request IO-memory: 0x%lx\n",candev->io_addr); + return -ENODEV; + } + if ( !( remap_addr = (long) ioremap( candev->io_addr, IO_RANGE ) ) ) { + CANMSG("Unable to access I/O memory at: 0x%lx\n", candev->io_addr); + release_mem_region(candev->io_addr,IO_RANGE); return -ENODEV; } - base=remap_addr-io_addr; - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + can_base_addr_fixup(candev, remap_addr); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); return 0; } @@ -72,10 +71,11 @@ int pikronisa_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/pikronisa.c */ -int pikronisa_release_io(unsigned long io_addr) +int pikronisa_release_io(struct candevice_t *candev) { /* release I/O memory mapping */ - iounmap((void*)base); + iounmap((void*)candev->dev_base_addr); + release_mem_region(candev->io_addr,IO_RANGE); return 0; } @@ -90,10 +90,10 @@ int pikronisa_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/pikronisa.c */ -int pikronisa_reset(int card) +int pikronisa_reset(struct candevice_t *candev) { int i; - struct chip_t *chip=candevices_p[card]->chip[0]; + struct chip_t *chip=candev->chip[0]; unsigned cdr; pikronisa_write_register(MOD_RM, chip->chip_base_addr+SJAMOD); @@ -138,12 +138,13 @@ int pikronisa_reset(int card) * Return Value: The function always returns zero * File: src/pikronisa.c */ -int pikronisa_init_hw_data(int card) +int pikronisa_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=0; - candevices_p[card]->nr_sja1000_chips=1; - candevices_p[card]->flags |= PROGRAMMABLE_IRQ*0; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=1; + candev->nr_all_chips=1; + candev->flags |= PROGRAMMABLE_IRQ*0; return 0; } @@ -183,17 +184,15 @@ int pikronisa_init_hw_data(int card) * Return Value: The function always returns zero * File: src/pikronisa.c */ -int pikronisa_init_chip_data(int card, int chipnr) +int pikronisa_init_chip_data(struct candevice_t *candev, int chipnr) { - /* pikronisa_base_addr = candevices_p[card]->io_addr; */ - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 24000000; - candevices_p[card]->chip[chipnr]->int_clk_reg = 0x0; - candevices_p[card]->chip[chipnr]->int_bus_reg = 0x0; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | - OCR_TX0_LH; + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 24000000; + candev->chip[chipnr]->int_clk_reg = 0x0; + candev->chip[chipnr]->int_bus_reg = 0x0; + candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_LH; return 0; } @@ -215,10 +214,10 @@ int pikronisa_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/pikronisa.c */ -int pikronisa_init_obj_data(int chipnr, int objnr) +int pikronisa_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + chip->msgobj[objnr]->flags=0; return 0; } @@ -234,7 +233,7 @@ int pikronisa_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/pikronisa.c */ -int pikronisa_program_irq(int card) +int pikronisa_program_irq(struct candevice_t *candev) { return 0; } @@ -252,9 +251,9 @@ int pikronisa_program_irq(int card) */ void pikronisa_write_register(unsigned char data, unsigned long address) { - /*DEBUGMSG("pikronisa_write_register: base=0x%lx addr=0x%lx data=0x%x", - base,address,data);*/ - writeb(data,base+address); + /*DEBUGMSG("pikronisa_write_register: addr=0x%lx data=0x%x", + address,data);*/ + writeb(data,address); } /** @@ -269,7 +268,7 @@ void pikronisa_write_register(unsigned char data, unsigned long address) */ unsigned pikronisa_read_register(unsigned long address) { - return readb(base+address); + return readb(address); } /* !!! Don't change this function !!! */ diff --git a/lincan/src/pip.c b/lincan/src/pip.c index 6bbfd8d..72ede89 100644 --- a/lincan/src/pip.c +++ b/lincan/src/pip.c @@ -1,18 +1,13 @@ /* pip.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -24,90 +19,88 @@ #include "../include/pip.h" #include "../include/i82527.h" -int pip5_request_io(unsigned long io_addr) +int pip5_request_io(struct candevice_t *candev) { - if (io_addr != 0x8000) { + if (candev->io_addr != 0x8000) { CANMSG("Invalid base io address\n"); CANMSG("The PIP5 uses a fixed base address of 0x8000,\n"); CANMSG("please consult your user manual.\n"); return -ENODEV; } - if (check_region(io_addr,0x100)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,0x100,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; } - else if(check_region(io_addr+0x102,0x01)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr+0x102); + else if(!can_request_io_region(candev->io_addr+0x102,0x01,DEVICE_NAME)) { + can_release_io_region(candev->io_addr,0x100); + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr+0x102); return -ENODEV; } else { - request_region(io_addr,0x100,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + 0x100 - 1); - request_region(io_addr+0x102,0x01,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx\n", io_addr+0x102); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + 0x100 - 1); + DEBUGMSG("Registered IO-memory: 0x%lx\n", candev->io_addr+0x102); } return 0; } -int pip6_request_io(unsigned long io_addr) +int pip6_request_io(struct candevice_t *candev) { - if ( (io_addr != 0x1000)&&(io_addr != 0x8000)&&(io_addr != 0xe000)) { + if ( (candev->io_addr != 0x1000)&&(candev->io_addr != 0x8000)&&(candev->io_addr != 0xe000)) { CANMSG("Invalid base io address\n"); CANMSG("Valid values for the PIP6 are: 0x1000, 0x8000 or 0xe000\n"); CANMSG("Please consult your user manual.\n"); return -ENODEV; } - if (check_region(io_addr,0x100)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,0x100, DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; } - else if (check_region(0x804, 0x02)) { + else if (!can_request_io_region(0x804,0x02,DEVICE_NAME)) { + can_release_io_region(candev->io_addr,0x100); CANMSG("Unable to open port: 0x%x\n", 0x804); return -ENODEV; } else { - request_region(io_addr,0x100, DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + 0x100 -1); - request_region(0x804,0x02,DEVICE_NAME); + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + 0x100 -1); DEBUGMSG("Registered IO-memory : 0x%x - 0x%x\n",0x804,0x805); } return 0; } -int pip5_release_io(unsigned long io_addr) +int pip5_release_io(struct candevice_t *candev) { - release_region(io_addr,0x100); - release_region(io_addr+0x102,0x01); + can_release_io_region(candev->io_addr,0x100); + can_release_io_region(candev->io_addr+0x102,0x01); return 0; } -int pip6_release_io(unsigned long io_addr) +int pip6_release_io(struct candevice_t *candev) { - release_region(io_addr,0x100); - release_region(0x804,0x02); + can_release_io_region(candev->io_addr,0x100); + can_release_io_region(0x804,0x02); return 0; } -int pip_reset(int card) +int pip_reset(struct candevice_t *candev) { int i=0, res_value=0; - DEBUGMSG("Resetting %s hardware ...\n", candevices_p[card]->hwname); - if (!strcmp(candevices_p[card]->hwname,"pip5")) + DEBUGMSG("Resetting %s hardware ...\n", candev->hwname); + if (!strcmp(candev->hwname,"pip5")) res_value = 0xcf; else res_value = 0x01; while (i < 1000000) { i++; - outb(res_value,candevices_p[card]->res_addr); + outb(res_value,candev->res_addr); } - outb(0x0,candevices_p[card]->res_addr); + outb(0x0,candev->res_addr); /* Check hardware reset status */ i=0; - while ( (inb(candevices_p[card]->io_addr+iCPU) & iCPU_RST) && (i<=15)) { + while ( (inb(candev->io_addr+iCPU) & iCPU_RST) && (i<=15)) { udelay(20000); i++; } @@ -123,70 +116,71 @@ int pip_reset(int card) return 0; } -int pip_init_hw_data(int card) +int pip_init_hw_data(struct candevice_t *candev) { - if (!strcmp(candevices_p[card]->hwname,"pip5")) - candevices_p[card]->res_addr=candevices_p[card]->io_addr+0x102; + if (!strcmp(candev->hwname,"pip5")) + candev->res_addr=candev->io_addr+0x102; else - candevices_p[card]->res_addr=0x805; - candevices_p[card]->nr_82527_chips=1; - candevices_p[card]->nr_sja1000_chips=0; - candevices_p[card]->flags |= PROGRAMMABLE_IRQ; + candev->res_addr=0x805; + candev->nr_82527_chips=1; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=1; + candev->flags |= PROGRAMMABLE_IRQ; return 0; } -int pip_init_chip_data(int card, int chipnr) +int pip_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type="i82527"; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - if (!strcmp(candevices_p[card]->hwname,"pip5")) - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC; + candev->chip[chipnr]->chip_type="i82527"; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + if (!strcmp(candev->hwname,"pip5")) + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC; else - candevices_p[card]->chip[chipnr]->int_cpu_reg = 0x0; - candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = 0; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = 0; + candev->chip[chipnr]->int_cpu_reg = 0x0; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->sja_cdr_reg = 0; + candev->chip[chipnr]->sja_ocr_reg = 0; return 0; } -int pip_init_obj_data(int chipnr, int objnr) +int pip_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } -int pip5_program_irq(int card) +int pip5_program_irq(struct candevice_t *candev) { - outb(0x01, candevices_p[card]->res_addr); - switch (candevices_p[card]->chip[0]->chip_irq) { - case 3: { outb(0x03, candevices_p[card]->res_addr); break; } - case 4: { outb(0x05, candevices_p[card]->res_addr); break; } - case 5: { outb(0x07, candevices_p[card]->res_addr); break; } - case 10: { outb(0x09, candevices_p[card]->res_addr); break; } - case 11: { outb(0x0c, candevices_p[card]->res_addr); break; } - case 15: { outb(0x0d, candevices_p[card]->res_addr); break; } + outb(0x01, candev->res_addr); + switch (candev->chip[0]->chip_irq) { + case 3: { outb(0x03, candev->res_addr); break; } + case 4: { outb(0x05, candev->res_addr); break; } + case 5: { outb(0x07, candev->res_addr); break; } + case 10: { outb(0x09, candev->res_addr); break; } + case 11: { outb(0x0c, candev->res_addr); break; } + case 15: { outb(0x0d, candev->res_addr); break; } default: { CANMSG("Supplied interrupt is not supported by the hardware\n"); CANMSG("Please consult your user manual.\n"); return -ENODEV; } } - outb(0x00, candevices_p[card]->res_addr); + outb(0x00, candev->res_addr); return 0; } -int pip6_program_irq(int card) +int pip6_program_irq(struct candevice_t *candev) { unsigned char can_int = 0, can_addr = 0; - can_int = candevices_p[card]->chip[0]->chip_irq; + can_int = candev->chip[0]->chip_irq; if ((can_int != 3) && (can_int != 4) && (can_int != 5) && (can_int != 6) && (can_int != 7) && (can_int != 9) && (can_int != 10) && (can_int != 11) && (can_int != 12) && (can_int != 14) && @@ -196,7 +190,7 @@ int pip6_program_irq(int card) CANMSG("Please consult your user manual.\n"); return -ENODEV; } - switch (candevices_p[card]->io_addr) { + switch (candev->io_addr) { case 0x1000: { can_addr = 0x01; break; } case 0x8000: { can_addr = 0x02; break; } case 0xe000: { can_addr = 0x03; break; } diff --git a/lincan/src/proc.c b/lincan/src/proc.c index 79309e0..fb573be 100644 --- a/lincan/src/proc.c +++ b/lincan/src/proc.c @@ -1,25 +1,20 @@ /* proc.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #define __NO_VERSION__ #include #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) #include #else #include @@ -31,18 +26,16 @@ #include "../include/proc.h" #include "../include/setup.h" -int add_channel_to_procdir(void); +int add_channel_to_procdir(struct candevice_t *candev); int remove_channel_from_procdir(void); -int add_object_to_procdir(void); +int add_object_to_procdir(int chip_nr); int remove_object_from_procdir(void); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) static int candev_readlink(struct proc_dir_entry *de, char *page); #endif -static int bc=0; /* static counter for each hardware board */ static int cc=0; /* static counter for each CAN chip */ -static int oc=0; /* static counter for each message object */ struct canproc_t can_proc_base; struct canproc_t *base=&can_proc_base; @@ -101,6 +94,8 @@ int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *par */ int can_init_procdir(void) { + int board; + struct candevice_t *candev; #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) base->can_proc_entry = new_can_proc_entry(0, "can", S_IFDIR | S_IRUGO | S_IXUGO, 0, &proc_root); @@ -111,8 +106,9 @@ int can_init_procdir(void) if (base->can_proc_entry == NULL) return -ENODEV; - for (bc=0; bcnr_boards; bc++) { - add_channel_to_procdir(); + for (board=0; boardnr_boards; board++) { + candev=hardware_p->candevice[board]; + if(candev) add_channel_to_procdir(candev); } return 0; @@ -133,12 +129,11 @@ int can_delete_procdir(void) return 0; } -int add_channel_to_procdir(void) +int add_channel_to_procdir(struct candevice_t *candev) { int i=0; - for (i=0; i < candevices_p[bc]->nr_82527_chips + - candevices_p[bc]->nr_sja1000_chips; i++) { + for (i=0; i < candev->nr_all_chips; i++) { base->channel[cc] = (struct channelproc_t *) kmalloc(sizeof(struct channelproc_t), GFP_KERNEL); @@ -163,7 +158,7 @@ int add_channel_to_procdir(void) if (base->channel[cc]->ch_entry == NULL) return -ENODEV; - add_object_to_procdir(); + add_object_to_procdir(cc); cc++; } @@ -192,60 +187,56 @@ int remove_channel_from_procdir(void) } -int add_object_to_procdir(void) +int add_object_to_procdir(int chip_nr) { - int i=0, obj=0; + int i, max_objects; - if (!strcmp(chips_p[cc]->chip_type,"i82527")) - obj=15; - if (!strcmp(chips_p[cc]->chip_type,"sja1000")) - obj=1; + max_objects=chips_p[chip_nr]->max_objects; - for (i=0; ichannel[cc]->object[i] = (struct objectproc_t *) + for (i=0; ichannel[chip_nr]->object[i] = (struct objectproc_t *) kmalloc(sizeof(struct objectproc_t),GFP_KERNEL); - if (base->channel[cc]->object[i] == NULL) + if (base->channel[chip_nr]->object[i] == NULL) return -ENOMEM; - else if (add_mem_to_list( base->channel[cc]->object[i])) + else if (add_mem_to_list( base->channel[chip_nr]->object[i])) return -ENOMEM; - sprintf(base->channel[cc]->object[i]->obj_name,"object%d",i); - sprintf(base->channel[cc]->object[i]->lnk_name,"dev"); + sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i); + sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev"); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) - base->channel[cc]->object[i]->obj_entry=new_can_proc_entry( - 0, base->channel[cc]->object[i]->obj_name, + base->channel[chip_nr]->object[i]->obj_entry=new_can_proc_entry( + 0, base->channel[chip_nr]->object[i]->obj_name, S_IFDIR | S_IRUGO | S_IXUGO, 0, - base->channel[cc]->ch_entry); - if (base->channel[cc]->object[i]->obj_entry == NULL) + base->channel[chip_nr]->ch_entry); + if (base->channel[chip_nr]->object[i]->obj_entry == NULL) return -ENODEV; - base->channel[cc]->object[i]->lnk = new_can_proc_entry( - 0, base->channel[cc]->object[i]->lnk_name, + base->channel[chip_nr]->object[i]->lnk = new_can_proc_entry( + 0, base->channel[chip_nr]->object[i]->lnk_name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, - 0, base->channel[cc]->object[i]->obj_entry); - if (base->channel[cc]->object[i]->lnk == NULL) + 0, base->channel[chip_nr]->object[i]->obj_entry); + if (base->channel[chip_nr]->object[i]->lnk == NULL) return -ENODEV; - sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/can"); - base->channel[cc]->object[i]->lnk->readlink_proc = + sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can"); + base->channel[chip_nr]->object[i]->lnk->readlink_proc = candev_readlink; #else - base->channel[cc]->object[i]->obj_entry = create_proc_entry( - base->channel[cc]->object[i]->obj_name, + base->channel[chip_nr]->object[i]->obj_entry = create_proc_entry( + base->channel[chip_nr]->object[i]->obj_name, S_IFDIR | S_IRUGO | S_IXUGO, - base->channel[cc]->ch_entry); - if (base->channel[cc]->object[i]->obj_entry == NULL) + base->channel[chip_nr]->ch_entry); + if (base->channel[chip_nr]->object[i]->obj_entry == NULL) return -ENODEV; - sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/can%d", - chips_p[cc]->msgobj[i]->minor); - base->channel[cc]->object[i]->lnk = proc_symlink( - base->channel[cc]->object[i]->lnk_name, - base->channel[cc]->object[i]->obj_entry, - base->channel[cc]->object[i]->lnk_dev); - if (base->channel[cc]->object[i]->lnk == NULL) + sprintf(base->channel[chip_nr]->object[i]->lnk_dev,"/dev/can%d", + chips_p[chip_nr]->msgobj[i]->minor); + base->channel[chip_nr]->object[i]->lnk = proc_symlink( + base->channel[chip_nr]->object[i]->lnk_name, + base->channel[chip_nr]->object[i]->obj_entry, + base->channel[chip_nr]->object[i]->lnk_dev); + if (base->channel[chip_nr]->object[i]->lnk == NULL) return -ENODEV; #endif @@ -257,10 +248,7 @@ int remove_object_from_procdir(void) { int i=0, obj=0; - if (!strcmp(chips_p[cc]->chip_type,"i82527")) - obj=15; - if (!strcmp(chips_p[cc]->chip_type,"sja1000")) - obj=1; + obj=chips_p[cc]->max_objects; for (i=0; i #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) #include #else #include @@ -32,65 +27,49 @@ #include "../include/ioctl.h" /* This is the 'Normal' read handler for normal transmission messages */ -inline ssize_t can_std_read(struct file *file, struct canfifo_t *fifo, +inline ssize_t can_std_read(struct file *file, struct canque_ends_t *qends, struct msgobj_t *obj, char *buffer, size_t length) { - int can_timeout, ret; - int bytes_avail = 0, bytes_to_copy = 0; - - cli(); - if (fifo->rx_readp == fifo->rx_writep) { // Buffer is empty + int ret; + int bytes_to_copy; + struct canque_edge_t *qedge; + struct canque_slot_t *slot; + + ret=canque_test_outslot(qends, &qedge, &slot); + if(ret<0){ if (file->f_flags & O_NONBLOCK) { - sti(); return -EAGAIN; } - obj->ret = 0; - can_timeout = interruptible_sleep_on_timeout(&fifo->readq, - CANTIMEOUT); - sti(); - if (signal_pending(current)) { - DEBUGMSG("Rx interrupted\n"); - return -EINTR; - } - if (!can_timeout) { - DEBUGMSG("no data received\n"); - return 0; + ret=canque_get_outslot_wait_kern(qends, &qedge, &slot); + if(ret<0){ + if (signal_pending(current)) { + DEBUGMSG("Rx interrupted\n"); + return -EINTR; + } + /*if (!can_timeout) { + DEBUGMSG("no data received\n"); + return 0; + }*/ + return -EIO; } - if (obj->ret < 0) - return obj->ret; } - /* Calculate available bytes in the buffer */ - cli(); - bytes_avail = ((int)fifo->rx_readp < (int)fifo->rx_writep) ? - ((int)fifo->rx_writep - (int)fifo->rx_readp) : - ((int)fifo->rx_writep - (int)fifo->rx_readp + - (int)fifo->rx_size); - sti(); - - bytes_to_copy = (length < bytes_avail) ? length : bytes_avail; - ret = bytes_to_copy; - - /* printk(KERN_CRIT "can RxFIFO b:%x e:%x bs:%x msg:%x rp:%x wp:%x btc:%x\n", - fifo->buf_rx_entry, fifo->buf_rx_entry+MAX_BUF_LENGTH, - fifo->rx_size, sizeof(struct canmsg_t), - fifo->rx_readp, fifo->rx_writep, bytes_to_copy); */ - - - /* Copy the data to user space */ + + copy_to_user(buffer, &slot->msg, sizeof(struct canmsg_t)); + canque_free_outslot(qends, qedge, slot); + buffer += sizeof(struct canmsg_t); + bytes_to_copy = length-sizeof(struct canmsg_t); + while (bytes_to_copy > 0) { - - - copy_to_user(buffer, fifo->rx_readp, sizeof(struct canmsg_t)); + ret=canque_test_outslot(qends, &qedge, &slot); + if(ret<0) + break; + copy_to_user(buffer, &slot->msg, sizeof(struct canmsg_t)); + canque_free_outslot(qends, qedge, slot); buffer += sizeof(struct canmsg_t); bytes_to_copy -= sizeof(struct canmsg_t); - fifo->rx_readp++; - if (fifo->rx_readp >= fifo->buf_rx_entry + MAX_BUF_LENGTH) - fifo->rx_readp = fifo->buf_rx_entry; - - /* printk(KERN_CRIT "can RxFIFO rp%x\n",fifo->rx_readp); */ } - return ret; + return length-bytes_to_copy; } /* This is the 'RTR' read handler for remote transmission request messages */ @@ -160,12 +139,18 @@ inline ssize_t can_rtr_read(struct chip_t *chip, struct msgobj_t *obj, ssize_t can_read(struct file *file, char *buffer, size_t length, loff_t *offset) { + struct canuser_t *canuser = (struct canuser_t*)(file->private_data); struct msgobj_t *obj; struct chip_t *chip; - struct canfifo_t *fifo; struct canmsg_t read_msg; + struct canque_ends_t *qends; int ret=0; + if(!canuser || (canuser->magic != CAN_USER_MAGIC)){ + CANMSG("can_close: bad canuser magic\n"); + return -ENODEV; + } + if (length < sizeof(struct canmsg_t)) { DEBUGMSG("Trying to read less bytes than a CAN message, \n"); DEBUGMSG("this will always return zero.\n"); @@ -177,25 +162,23 @@ ssize_t can_read(struct file *file, char *buffer, size_t length, loff_t *offset) length = 8 * sizeof(struct canmsg_t); } /* Initialize hardware pointers */ - if ( (obj = objects_p[MINOR_NR]) == NULL) { + obj = canuser->msgobj; + if (obj == NULL) { CANMSG("Could not assign buffer structure\n"); return -1; } + qends = canuser->qends; if ( (chip = obj->hostchip) == NULL) { CANMSG("Device is not correctly configured,\n"); CANMSG("please reload the driver.\n"); return -1; } - if ( (fifo = obj->fifo) == NULL) { - CANMSG("Could not assign buffer memory.\n"); - return -1; - } copy_from_user(&read_msg, buffer, sizeof(struct canmsg_t)); if (read_msg.flags & MSG_RTR) ret = can_rtr_read(chip, obj, buffer); else - ret = can_std_read(file, fifo, obj, buffer, length); + ret = can_std_read(file, qends, obj, buffer, length); return ret; } diff --git a/lincan/src/select.c b/lincan/src/select.c index 27b2d22..efdb212 100644 --- a/lincan/src/select.c +++ b/lincan/src/select.c @@ -1,20 +1,13 @@ /* select.c * Header file for the Linux CAN-bus driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Added by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7.1-pi2 15 Nov 2002 - * - * added by Pavel Pisa pisa@cmp.felk.cvut.cz + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -24,33 +17,60 @@ unsigned int can_poll(struct file *file, poll_table *wait) { - unsigned int mask = 0; + struct canuser_t *canuser = (struct canuser_t*)(file->private_data); + struct canque_ends_t *qends; struct msgobj_t *obj; - struct canfifo_t *fifo; + unsigned int mask = 0; + unsigned long flags; + struct canque_edge_t *edge; + struct list_head *entry; + int full=0; + int i; - /* Initialize hardware pointers */ - if ( (obj = objects_p[MINOR_NR]) == NULL) { - CANMSG("Could not assign buffer structure\n"); - return 0; - } - if ( (fifo = obj->fifo) == NULL) { - CANMSG("Could not assign buffer memory.\n"); - return 0; + if(!canuser || (canuser->magic != CAN_USER_MAGIC)){ + CANMSG("can_close: bad canuser magic\n"); + return -ENODEV; } + + obj = canuser->msgobj; + qends = canuser->qends; - if (file->f_mode & FMODE_WRITE) { - poll_wait(file, &fifo->writeq, wait); - } if (file->f_mode & FMODE_READ) { - poll_wait(file, &fifo->readq, wait); - } - if ((file->f_mode & FMODE_READ)&& - (fifo->rx_readp != fifo->rx_writep)) { - mask |= POLLIN | POLLRDNORM; + poll_wait(file, &qends->endinfo.fileinfo.readq, wait); + for(i=CANQUEUE_PRIO_NR;--i>=0;) { + if(!list_empty(&qends->active[i])) + mask |= POLLIN | POLLRDNORM; + } } - if ((file->f_mode & FMODE_WRITE)&& - (fifo->tx_readp == fifo->tx_writep)) { - mask |= POLLOUT | POLLWRNORM; + + if ((file->f_mode & FMODE_WRITE) && !(file->f_flags & O_SYNC)) { + poll_wait(file, &qends->endinfo.fileinfo.writeq, wait); + + spin_lock_irqsave(&qends->ends_lock, flags); + list_for_each(entry,&qends->inlist){ + edge=list_entry(entry,struct canque_edge_t,inpeers); + if(canque_fifo_test_fl(&edge->fifo,FULL)) + full=1; + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + + if(!full) + mask |= POLLOUT | POLLWRNORM; + } + + if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_SYNC)) { + poll_wait(file, &qends->endinfo.fileinfo.emptyq, wait); + + spin_lock_irqsave(&qends->ends_lock, flags); + list_for_each(entry,&qends->inlist){ + edge=list_entry(entry,struct canque_edge_t,inpeers); + if(!canque_fifo_test_fl(&edge->fifo,EMPTY)) + full=1; + } + spin_unlock_irqrestore(&qends->ends_lock, flags); + + if(!full) + mask |= POLLOUT | POLLWRNORM; } return mask; } diff --git a/lincan/src/setup.c b/lincan/src/setup.c index a8f76cc..d234eb9 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -1,33 +1,30 @@ /* setup.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #define __NO_VERSION__ #include #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) #include #else #include #endif #include +#include #include ".supported_cards.h" #include "../include/main.h" +#include "../include/devcommon.h" #include "../include/setup.h" #include "../include/pip.h" #include "../include/pccan.h" @@ -61,10 +58,10 @@ extern int bfadcan_register(struct hwspecops_t *hwspecops); extern int pikronisa_register(struct hwspecops_t *hwspecops); int init_device_struct(int card); -int init_hwspecops(int card); -int init_chip_struct(int card); -int init_obj_struct(int card, int chip); -int init_chipspecops(int card, int chipnr); +int init_hwspecops(struct candevice_t *candev); +int init_chip_struct(struct candevice_t *candev); +int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase); +int init_chipspecops(struct candevice_t *candev, int chipnr); int add_mem_to_list(void *address_p) { @@ -144,6 +141,39 @@ int del_mem_list(void) return 0; } +int can_request_io_region(unsigned long start, unsigned long n, const char *name) +{ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) + if(check_region(start,n)) return 0; + request_region(start,n,name); + return 1; + #else + return (request_region(start,n,name))?1:0; + #endif +} + +void can_release_io_region(unsigned long start, unsigned long n) +{ + release_region(start,n); +} + +/* This function shifts all base address structures acording to address + translation between physical and virtual address mappings */ +int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base) +{ + unsigned long offs; + int i, j; + + offs=new_base-candev->dev_base_addr; + candev->dev_base_addr=new_base; + for(i=0;inr_all_chips;i++){ + candev->chip[i]->chip_base_addr += offs; + for(j=0;jchip[i]->max_objects;j++) + candev->chip[i]->msgobj[j]->obj_base_addr += offs; + } + return 0; +} + /* The function init_hw_struct is used to initialize the hardware structure. */ int init_hw_struct(void) { @@ -168,32 +198,40 @@ int init_hw_struct(void) */ int init_device_struct(int card) { - hardware_p->candevice[card]=(struct candevice_t *)kmalloc(sizeof(struct candevice_t),GFP_KERNEL); - if (hardware_p->candevice[card]==NULL) + struct candevice_t *candev; + + candev=(struct candevice_t *)kmalloc(sizeof(struct candevice_t),GFP_KERNEL); + if (candev==NULL) return -ENOMEM; else - if ( add_mem_to_list(hardware_p->candevice[card]) ) + if ( add_mem_to_list(candev) ) return -ENOMEM; - candevices_p[card]=hardware_p->candevice[card]; + memset(candev, 0, sizeof(struct candevice_t)); + + hardware_p->candevice[card]=candev; + candev->candev_idx=card; + + candev=candev; - hardware_p->candevice[card]->hwname=hw[card]; - hardware_p->candevice[card]->io_addr=io[card]; + candev->hwname=hw[card]; + candev->io_addr=io[card]; + candev->dev_base_addr=io[card]; - hardware_p->candevice[card]->hwspecops=(struct hwspecops_t *)kmalloc(sizeof(struct hwspecops_t),GFP_KERNEL); - if (hardware_p->candevice[card]->hwspecops==NULL) + candev->hwspecops=(struct hwspecops_t *)kmalloc(sizeof(struct hwspecops_t),GFP_KERNEL); + if (candev->hwspecops==NULL) return -ENOMEM; else - if ( add_mem_to_list(hardware_p->candevice[card]->hwspecops) ) + if ( add_mem_to_list(candev->hwspecops) ) return -ENOMEM; - if (init_hwspecops(card)) + if (init_hwspecops(candev)) return -ENODEV; - if (candevices_p[card]->hwspecops->init_hw_data(card)) + if (candev->hwspecops->init_hw_data(candev)) return -ENODEV; - if (init_chip_struct(card)) + if (init_chip_struct(candev)) return -ENODEV; return 0; @@ -202,38 +240,44 @@ int init_device_struct(int card) /* The function init_chip_struct is used to initialize all chip_t structures * on one hardware board. */ -int init_chip_struct(int card) +int init_chip_struct(struct candevice_t *candev) { static int irq_count=0; int i=0; /* Alocate and initialize the chip structures */ - for (i=0; i < candevices_p[card]->nr_82527_chips+candevices_p[card]->nr_sja1000_chips; i++) { - candevices_p[card]->chip[i]=(struct chip_t *)kmalloc(sizeof(struct chip_t),GFP_KERNEL); - if (candevices_p[card]->chip[i]==NULL) + for (i=0; i < candev->nr_all_chips; i++) { + candev->chip[i]=(struct chip_t *)kmalloc(sizeof(struct chip_t),GFP_KERNEL); + if (candev->chip[i]==NULL) return -ENOMEM; else - if ( add_mem_to_list(candevices_p[card]->chip[i]) ) + if ( add_mem_to_list(candev->chip[i]) ) return -ENOMEM; - candevices_p[card]->chip[i]->chipspecops=(struct chipspecops_t *)kmalloc(sizeof(struct chipspecops_t),GFP_KERNEL); - if (candevices_p[card]->chip[i]->chipspecops==NULL) + memset(candev->chip[i], 0, sizeof(struct chip_t)); + + candev->chip[i]->write_register=candev->hwspecops->write_register; + candev->chip[i]->read_register=candev->hwspecops->read_register; + + candev->chip[i]->chipspecops=(struct chipspecops_t *)kmalloc(sizeof(struct chipspecops_t),GFP_KERNEL); + if (candev->chip[i]->chipspecops==NULL) return -ENOMEM; else - if ( add_mem_to_list(candevices_p[card]->chip[i]->chipspecops) ) + if ( add_mem_to_list(candev->chip[i]->chipspecops) ) return -ENOMEM; - chips_p[irq_count]=candevices_p[card]->chip[i]; - candevices_p[card]->chip[i]->hostdevice=candevices_p[card]; - candevices_p[card]->chip[i]->chip_irq=irq[irq_count]; - candevices_p[card]->chip[i]->flags=0x0; + chips_p[irq_count]=candev->chip[i]; + candev->chip[i]->chip_idx=i; + candev->chip[i]->hostdevice=candev; + candev->chip[i]->chip_irq=irq[irq_count]; + candev->chip[i]->flags=0x0; - candevices_p[card]->hwspecops->init_chip_data(card,i); + candev->hwspecops->init_chip_data(candev,i); - if (init_chipspecops(card,i)) + if (init_chipspecops(candev,i)) return -ENODEV; - init_obj_struct(card, irq_count); + init_obj_struct(candev, candev->chip[i], minor[irq_count]); irq_count++; } @@ -241,46 +285,47 @@ int init_chip_struct(int card) return 0; } -int init_obj_struct(int card, int chip) +int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase) { + struct canque_ends_t *qends; static int obj_count=0; - int i=0,max_objects=0; + int i,max_objects; + struct msgobj_t *obj; - if (!strcmp(chips_p[chip]->chip_type,"i82527")) - max_objects=15; - else - max_objects=1; + max_objects=hostchip->max_objects; for (i=0; imsgobj[i]=(struct msgobj_t *)kmalloc(sizeof(struct msgobj_t),GFP_KERNEL); - if (chips_p[chip]->msgobj[i] == NULL) + obj=(struct msgobj_t *)kmalloc(sizeof(struct msgobj_t),GFP_KERNEL); + hostchip->msgobj[i]=obj; + if (obj == NULL) return -ENOMEM; else - if ( add_mem_to_list(chips_p[chip]->msgobj[i]) ) + if ( add_mem_to_list(obj) ) return -ENOMEM; - chips_p[chip]->msgobj[i]->fifo=(struct canfifo_t *)kmalloc(sizeof(struct canfifo_t),GFP_KERNEL); - if (chips_p[chip]->msgobj[i]->fifo == NULL) - return -ENOMEM; - else - if ( add_mem_to_list(chips_p[chip]->msgobj[i]->fifo) ) - return -ENOMEM; + memset(obj, 0, sizeof(struct msgobj_t)); + + atomic_set(&obj->obj_used,0); + INIT_LIST_HEAD(&obj->obj_users); + qends = (struct canque_ends_t *)kmalloc(sizeof(struct canque_ends_t), GFP_KERNEL); + if(qends == NULL) return -ENOMEM; + if(add_mem_to_list(qends)) return -ENOMEM; + memset(qends, 0, sizeof(struct canque_ends_t)); + obj->hostchip=hostchip; + obj->object=i+1; + obj->qends=qends; + obj->tx_qedge=NULL; + obj->tx_slot=NULL; + obj->flags = 0x0; + + canqueue_ends_init_chip(qends, hostchip, obj); - if (minor[0] == -1) { - objects_p[obj_count]=chips_p[chip]->msgobj[i]; - objects_p[obj_count]->hostchip=chips_p[chip]; - objects_p[obj_count]->object=i+1; - objects_p[obj_count]->minor=obj_count; - } - else { - objects_p[minor[chip]+i]=chips_p[chip]->msgobj[i]; - objects_p[minor[chip]+i]->hostchip=chips_p[chip]; - objects_p[minor[chip]+i]->object=i+1; - objects_p[minor[chip]+i]->minor=minor[chip]+i; - } + if (minorbase == -1) minorbase=obj_count; + if ((minorbase >= 0) && (minorbase+iminor=minorbase+i; + } else obj->minor=-1; - chips_p[chip]->msgobj[i]->flags = 0x0; - - candevices_p[card]->hwspecops->init_obj_data(chip,i); + candev->hwspecops->init_obj_data(hostchip,i); obj_count++; } @@ -288,101 +333,106 @@ int init_obj_struct(int card, int chip) } -int init_hwspecops(int card) +int init_hwspecops(struct candevice_t *candev) { #ifdef ENABLE_CARD_template - if (!strcmp(candevices_p[card]->hwname,"template")) { - template_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"template")) { + template_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_pip - if (!strcmp(candevices_p[card]->hwname,"pip5")) { - pip5_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pip5")) { + pip5_register(candev->hwspecops); } - else if (!strcmp(candevices_p[card]->hwname,"pip6")) { - pip6_register(candevices_p[card]->hwspecops); + else if (!strcmp(candev->hwname,"pip6")) { + pip6_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_smartcan - if (!strcmp(candevices_p[card]->hwname,"smartcan")) { - smartcan_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"smartcan")) { + smartcan_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_nsi - if (!strcmp(candevices_p[card]->hwname,"nsican")) { - nsi_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"nsican")) { + nsi_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_cc_can104 - if (!strcmp(candevices_p[card]->hwname,"cc104")) { - cc104_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"cc104")) { + cc104_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_aim104 - if (!strcmp(candevices_p[card]->hwname,"aim104")) { - aim104_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"aim104")) { + aim104_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_pc_i03 - if (!strcmp(candevices_p[card]->hwname,"pc-i03")) { - pci03_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pc-i03")) { + pci03_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_pcm3680 - if (!strcmp(candevices_p[card]->hwname,"pcm3680")) { - pcm3680_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pcm3680")) { + pcm3680_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_pccan - if (!strcmp(candevices_p[card]->hwname,"pccan-f") | - !strcmp(candevices_p[card]->hwname,"pccan-s") ) { - pccanf_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pccan-f") | + !strcmp(candev->hwname,"pccan-s") ) { + pccanf_register(candev->hwspecops); } - if (!strcmp(candevices_p[card]->hwname,"pccan-d")) { - pccand_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pccan-d")) { + pccand_register(candev->hwspecops); } - if (!strcmp(candevices_p[card]->hwname,"pccan-q")) { - pccanq_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pccan-q")) { + pccanq_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_m437 - if (!strcmp(candevices_p[card]->hwname,"m437")) { - m437_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"m437")) { + m437_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_pcccan - if (!strcmp(candevices_p[card]->hwname,"pcccan")) { - pcccan_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pcccan")) { + pcccan_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_ssv - if (!strcmp(candevices_p[card]->hwname,"ssv")) { - ssv_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"ssv")) { + ssv_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_bfadcan - if (!strcmp(candevices_p[card]->hwname,"bfadcan")) { - bfadcan_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"bfadcan")) { + bfadcan_register(candev->hwspecops); } #endif #ifdef ENABLE_CARD_pikronisa - if (!strcmp(candevices_p[card]->hwname,"pikronisa")) { - pikronisa_register(candevices_p[card]->hwspecops); + if (!strcmp(candev->hwname,"pikronisa")) { + pikronisa_register(candev->hwspecops); } #endif return 0; } -int init_chipspecops(int card, int chipnr) +int init_chipspecops(struct candevice_t *candev, int chipnr) { - if (!strcmp(candevices_p[card]->chip[chipnr]->chip_type,"i82527")) { - i82527_register(candevices_p[card]->chip[chipnr]->chipspecops); + candev->chip[chipnr]->max_objects=0; + + if (!strcmp(candev->chip[chipnr]->chip_type,"i82527")) { + candev->chip[chipnr]->max_objects=15; + i82527_register(candev->chip[chipnr]->chipspecops); } - if (!strcmp(candevices_p[card]->chip[chipnr]->chip_type,"sja1000")) { - sja1000_register(candevices_p[card]->chip[chipnr]->chipspecops); + if (!strcmp(candev->chip[chipnr]->chip_type,"sja1000")) { + candev->chip[chipnr]->max_objects=1; + sja1000_register(candev->chip[chipnr]->chipspecops); } - if (!strcmp(candevices_p[card]->chip[chipnr]->chip_type,"sja1000p")) { - sja1000p_register(candevices_p[card]->chip[chipnr]->chipspecops); + if (!strcmp(candev->chip[chipnr]->chip_type,"sja1000p")) { + candev->chip[chipnr]->max_objects=1; + sja1000p_register(candev->chip[chipnr]->chipspecops); } return 0; diff --git a/lincan/src/sja1000.c b/lincan/src/sja1000.c index 0955c76..bca1fec 100644 --- a/lincan/src/sja1000.c +++ b/lincan/src/sja1000.c @@ -1,25 +1,24 @@ /* sja1000.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.6 18 Sept 2000 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif +#include #include #include #include "../include/main.h" #include "../include/sja1000.h" +void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj); +void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj); + int sja1000_enable_configuration(struct chip_t *chip) { int i=0; @@ -194,48 +193,31 @@ int sja1000_baud_rate(struct chip_t *chip, int rate, int clock, int sjw, int sja1000_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) { int i; - struct canfifo_t *fifo = chip->msgobj[0]->fifo; - int id; + i=can_read_reg(chip,SJASR); if (!(i&SR_RBS)) { //Temp - for (i=0; i<0x20; i++) - CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i)); - return 0; + for (i=0; i<0x20; i++) + CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i)); + return 0; } sja1000_start_chip(chip); - can_write_reg(chip, 0, SJACR); // disable interrupts for a moment -// TODO: this would be best sja1000_irq_read_handler(chip); -// now just duplicate the code. - do { - id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); - fifo->rx_writep->length = id & 0x0f; - fifo->rx_writep->flags = id&ID0_RTR ? MSG_RTR : 0; - fifo->rx_writep->timestamp = 0; - fifo->rx_writep->cob = 0; - fifo->rx_writep->id = id>>5; + // disable interrupts for a moment + can_write_reg(chip, 0, SJACR); - for (i=0; irx_writep->length; i++) - fifo->rx_writep->data[i]=can_read_reg(chip, SJARXDAT0 + i); + sja1000_irq_read_handler(chip, obj); - fifo->rx_writep++; - if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) - fifo->rx_writep = fifo->buf_rx_entry; - - can_write_reg(chip, CMR_RRB, SJACMR); - - } while (can_read_reg(chip, SJASR) & SR_RBS); - -// enable interrupts + // enable interrupts can_write_reg(chip, CR_OIE | CR_EIE | CR_TIE | CR_RIE, SJACR); return 1; } -#define MAX_TRANSMIT_WAIT_LOOPS 200 +#define MAX_TRANSMIT_WAIT_LOOPS 10 + int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { @@ -349,6 +331,138 @@ int sja1000_config_irqs(struct chip_t *chip, short irqs) return -ENOSYS; } + +irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned irq_register; + struct chip_t *chip=(struct chip_t *)dev_id; + struct msgobj_t *obj=chip->msgobj[0]; + + 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 & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0) + return IRQ_NONE; + + if ((irq_register & IR_RI) != 0) + sja1000_irq_read_handler(chip, obj); + + if ((irq_register & IR_TI) != 0) { + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if (can_read_reg(chip, SJASR) & SR_TBS) + sja1000_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + } + } + + if ((irq_register & (IR_EI|IR_DOI)) != 0) { + // Some error happened +// 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 + CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", + can_read_reg(chip, SJASR), irq_register); + obj->ret=-1; + + 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;*/ + } + } + + return IRQ_HANDLED; +} + +void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj) +{ + int i=0, id=0; + + do { + id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); + obj->rx_msg.length = id & 0x0f; + obj->rx_msg.flags = id&ID0_RTR ? MSG_RTR : 0; + obj->rx_msg.timestamp = 0; + obj->rx_msg.cob = 0; + obj->rx_msg.id = id>>5; + + for (i=0; irx_msg.length; i++) + obj->rx_msg.data[i]=can_read_reg(chip, SJARXDAT0 + i); + + can_write_reg(chip, CMR_RRB, SJACMR); + + canque_filter_msg2edges(obj->qends, &obj->rx_msg); + } while(can_read_reg(chip, SJASR) & SR_RBS); +} + +void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj) +{ + int cmd; + + if(obj->tx_slot){ + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + } + + cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot); + if(cmd<0) + return; + + 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; + } +} + +/** + * sja1000_wakeup_tx: - wakeups TX processing + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Return Value: negative value reports error. + * File: src/sja1000.c + */ +int sja1000_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj) +{ + /* dummy lock to prevent preemption fully portable way */ + spinlock_t dummy_lock; + + /* preempt_disable() */ + spin_lock_init(&dummy_lock); + spin_lock(&dummy_lock); + + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if (can_read_reg(chip, SJASR) & SR_TBS) + sja1000_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + } + + /* preempt_enable(); */ + spin_unlock(&dummy_lock); + return 0; +} + int sja1000_register(struct chipspecops_t *chipspecops) { chipspecops->chip_config = sja1000_chip_config; @@ -362,6 +476,7 @@ int sja1000_register(struct chipspecops_t *chipspecops) chipspecops->pre_write_config = sja1000_pre_write_config; chipspecops->send_msg = sja1000_send_msg; chipspecops->check_tx_stat = sja1000_check_tx_stat; + chipspecops->wakeup_tx=sja1000_wakeup_tx; chipspecops->remote_request = sja1000_remote_request; chipspecops->enable_configuration = sja1000_enable_configuration; chipspecops->disable_configuration = sja1000_disable_configuration; diff --git a/lincan/src/sja1000p.c b/lincan/src/sja1000p.c index deb1c89..19e2e57 100644 --- a/lincan/src/sja1000p.c +++ b/lincan/src/sja1000p.c @@ -1,20 +1,15 @@ /* sja1000.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl - * This software is released under the GPL-License. - * Version 0.6 18 Sept 2000 * 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.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -75,6 +70,18 @@ int sja1000p_disable_configuration(struct chip_t *chip) 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 chip_t *chip) { if (sja1000p_enable_configuration(chip)) @@ -101,6 +108,15 @@ int sja1000p_chip_config(struct chip_t *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 chip_t *chip, unsigned long code, unsigned long mask) { int i; @@ -124,12 +140,17 @@ int sja1000p_extended_mask(struct chip_t *chip, unsigned long code, unsigned lo return 0; } -/* Set communication parameters. - * param rate baud rate in Hz - * param clock frequency of sja1000 clock in Hz (ISA osc is 14318000) - * param sjw synchronization jump width (0-3) prescaled clock cycles - * param sampl_pt sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio - * param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP +/** + * 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 chip_t *chip, int rate, int clock, int sjw, int sampl_pt, int flags) @@ -191,42 +212,55 @@ int sja1000p_baud_rate(struct chip_t *chip, int rate, int clock, int sjw, return 0; } -void sja1000p_read(struct chip_t *chip, struct canfifo_t *fifo) { +/** + * 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 chip_t *chip, struct msgobj_t *obj) { int i, flags, len, datastart; do { flags = can_read_reg(chip,SJAFRM); if(flags&FRM_FF) { - fifo->rx_writep->id = + 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 { - fifo->rx_writep->id = + obj->rx_msg.id = (can_read_reg(chip,SJAID0)<<3) + (can_read_reg(chip,SJAID1)>>5); datastart = SJADATS; } - fifo->rx_writep->flags = + obj->rx_msg.flags = ((flags & FRM_RTR) ? MSG_RTR : 0) | ((flags & FRM_FF) ? MSG_EXT : 0); len = flags & FRM_DLC_M; for(i=0; i< len; i++) { - fifo->rx_writep->data[i]=can_read_reg(chip,datastart+i); + obj->rx_msg.data[i]=can_read_reg(chip,datastart+i); } - fifo->rx_writep->length = len; + obj->rx_msg.length = len; - fifo->rx_writep++; - if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) - fifo->rx_writep = fifo->buf_rx_entry; - -// FIXME: what if fifo->rx_writep == fifo->rx_readp again ? + canque_filter_msg2edges(obj->qends, &obj->rx_msg); can_write_reg(chip, CMR_RRB, SJACMR); + } while (can_read_reg(chip, SJASR) & SR_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 chip_t *chip, struct msgobj_t *obj) { int status; @@ -247,12 +281,25 @@ int sja1000p_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) } can_write_reg(chip, DISABLE_INTERRUPTS, SJAIER); //disable interrupts for a moment - sja1000p_read(chip, obj->fifo); + sja1000p_read(chip, obj); can_write_reg(chip, ENABLE_INTERRUPTS, SJAIER); //enable interrupts return 1; } -#define MAX_TRANSMIT_WAIT_LOOPS 200 +#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 chip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { @@ -319,6 +366,17 @@ int sja1000p_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, 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 chip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { @@ -327,6 +385,15 @@ int sja1000p_send_msg(struct chip_t *chip, struct msgobj_t *obj, 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 chip_t *chip) { if (can_read_reg(chip,SJASR) & SR_TCS) @@ -335,6 +402,15 @@ int sja1000p_check_tx_stat(struct chip_t *chip) 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 chip_t *chip, unsigned short btr0, unsigned short btr1) { @@ -349,6 +425,13 @@ int sja1000p_set_btregs(struct chip_t *chip, unsigned short btr0, return 0; } +/** + * sja1000p_stop_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 chip_t *chip) { enum sja1000_PeliCAN_MOD flags; @@ -359,6 +442,13 @@ int sja1000p_start_chip(struct chip_t *chip) 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 chip_t *chip) { enum sja1000_PeliCAN_MOD flags; @@ -370,12 +460,29 @@ int sja1000p_stop_chip(struct chip_t *chip) } +/** + * 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 chip_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 chip_t *chip, unsigned short code, unsigned short mask) { @@ -383,58 +490,97 @@ int sja1000p_standard_mask(struct chip_t *chip, unsigned short code, 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 chip_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 chip_t *chip, short irqs) { CANMSG("sja1000p_config_irqs not implemented\n"); return -ENOSYS; } -void sja1000p_irq_write_handler(struct chip_t *chip, struct canfifo_t *fifo) +/** + * 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 chip_t *chip, struct msgobj_t *obj) { - fifo->tx_readp++; - if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH) - fifo->tx_readp = fifo->buf_tx_entry; - if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty - fifo->tx_in_progress = 0; - if (waitqueue_active(&fifo->writeq)) { - chip->msgobj[0]->ret = 0; //CHECKME or 26? - wake_up_interruptible(&fifo->writeq); - } - return; + int cmd; + + if(obj->tx_slot){ + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; } - if (chip->chipspecops->pre_write_config(chip, chip->msgobj[0], - fifo->tx_readp)) { - if (waitqueue_active(&fifo->writeq)) { - chip->msgobj[0]->ret = -1; - wake_up_interruptible(&fifo->writeq); - return; - } + + cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot); + if(cmd<0) + return; + + 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, chip->msgobj[0], - fifo->tx_readp)) { - if (waitqueue_active(&fifo->writeq)) { - chip->msgobj[0]->ret = -1; - wake_up_interruptible(&fifo->writeq); - 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 -void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +/** + * sja1000p_irq_handler: - interrupt service routine + * @irq: interrupt vector number, this value is system specific + * @dev_id: driver private pointer registered at time of request_irq() call. + * The CAN driver uses this pointer to store relationship of interrupt + * to chip state structure - @struct chip_t + * @regs: system dependent value pointing to registers stored in exception frame + * + * 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 + */ +irqreturn_t sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { int irq_register, status, error_code; int static retransmitted=0; /* FIXME - should go into chip struct */ struct chip_t *chip=(struct chip_t *)dev_id; - struct canfifo_t *fifo; + struct msgobj_t *obj=chip->msgobj[0]; irq_register=can_read_reg(chip,SJAIR); // DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); @@ -442,23 +588,32 @@ void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs) // can_read_reg(chip,SJASR)); if ((irq_register & (IR_BEI|IR_EPI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0) - return; + return IRQ_NONE; - if(!chip->msgobj[0]->flags & BUFFERS_ALLOCATED) { + if(!obj->flags & OBJ_BUFFERS_ALLOCATED) { CANMSG("sja1000p_irq_handler: called with device closed, irq_register 0x%02x\n", irq_register); - return; + return IRQ_NONE; } - fifo=chip->msgobj[0]->fifo; if ((irq_register & IR_RI) != 0) { - sja1000p_read(chip,fifo); - chip->msgobj[0]->ret = 0; - if (waitqueue_active(&fifo->readq)) - wake_up_interruptible(&fifo->readq); + DEBUGMSG("sja1000_irq_handler: RI\n"); + sja1000p_read(chip,obj); + obj->ret = 0; } if ((irq_register & IR_TI) != 0) { - chip->msgobj[0]->ret = 0; - sja1000p_irq_write_handler(chip,fifo); + DEBUGMSG("sja1000_irq_handler: TI\n"); + obj->ret = 0; + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if (can_read_reg(chip, SJASR) & SR_TBS) + sja1000p_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + DEBUGMSG("TX looping in sja1000_irq_handler\n"); + } } if ((irq_register & (IR_EI|IR_BEI|IR_EPI|IR_DOI)) != 0) { // Some error happened @@ -468,10 +623,10 @@ void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs) 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 - chip->msgobj[0]->ret=-1; + obj->ret=-1; if(error_code == 0xd9) { - chip->msgobj[0]->ret= -ENXIO; + obj->ret= -ENXIO; /* no such device or address - no ACK received */ } if(retransmitted++>MAX_RETR) { @@ -483,15 +638,51 @@ void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs) can_write_reg(chip, 0, SJAMOD); } - if (waitqueue_active(&fifo->writeq)) - wake_up_interruptible(&fifo->writeq); - if (waitqueue_active(&fifo->readq)) - wake_up_interruptible(&fifo->readq); + 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 { retransmitted=0; } - return; + return IRQ_HANDLED; +} + +/** + * sja1000p_wakeup_tx: - wakeups TX processing + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Return Value: negative value reports error. + * File: src/sja1000p.c + */ +int sja1000p_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj) +{ + /* dummy lock to prevent preemption fully portable way */ + spinlock_t dummy_lock; + + /* preempt_disable() */ + spin_lock_init(&dummy_lock); + spin_lock(&dummy_lock); + + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if (can_read_reg(chip, SJASR) & SR_TBS) + sja1000p_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + DEBUGMSG("TX looping in sja1000p_wakeup_tx\n"); + } + + /* preempt_enable(); */ + spin_unlock(&dummy_lock); + return 0; } int sja1000p_register(struct chipspecops_t *chipspecops) @@ -508,6 +699,7 @@ int sja1000p_register(struct chipspecops_t *chipspecops) 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; diff --git a/lincan/src/smartcan.c b/lincan/src/smartcan.c index c41c2d6..731f657 100644 --- a/lincan/src/smartcan.c +++ b/lincan/src/smartcan.c @@ -1,18 +1,13 @@ /* smartcan.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -28,44 +23,40 @@ int smartcan_irq=-1; unsigned long smartcan_base=0x0; -int smartcan_request_io(unsigned long io_addr) +int smartcan_request_io(struct candevice_t *candev) { - int err=0; - - if ( (err=check_region(io_addr,0x04)) < 0 ) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,0x04,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,0x04,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + 0x04 - 1); + }else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + 0x04 - 1); } return 0; } -int smartcan_release_io(unsigned long io_addr) +int smartcan_release_io(struct candevice_t *candev) { - release_region(io_addr,0x04); + can_release_io_region(candev->io_addr,0x04); return 0; } -int smartcan_reset(int card) +int smartcan_reset(struct candevice_t *candev) { int i=0; DEBUGMSG("Resetting smartcan hardware ...\n"); - outb(0x00,candevices_p[card]->res_addr); + outb(0x00,candev->res_addr); while (i < 1000000) { i++; - outb(0x01,candevices_p[card]->res_addr); + outb(0x01,candev->res_addr); } - outb(0x00,candevices_p[card]->res_addr); + outb(0x00,candev->res_addr); /* Check hardware reset status */ i=0; - outb(candevices_p[card]->io_addr+iCPU,candevices_p[card]->io_addr); - while ( (inb(candevices_p[card]->io_addr+1)&0x80) && (i<=15) ) { + outb(candev->io_addr+iCPU,candev->io_addr); + while ( (inb(candev->io_addr+1)&0x80) && (i<=15) ) { udelay(20000); i++; } @@ -80,35 +71,36 @@ int smartcan_reset(int card) return 0; } -int smartcan_init_hw_data(int card) +int smartcan_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=candevices_p[card]->io_addr+0x02; - candevices_p[card]->nr_82527_chips=1; - candevices_p[card]->nr_sja1000_chips=0; - + candev->res_addr=candev->io_addr+0x02; + candev->nr_82527_chips=1; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=1; + return 0; } -int smartcan_init_chip_data(int card, int chipnr) +int smartcan_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type="i82527"; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC; - candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = 0; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = 0; - smartcan_irq=candevices_p[card]->chip[chipnr]->chip_irq; - smartcan_base=candevices_p[card]->chip[chipnr]->chip_base_addr; + candev->chip[chipnr]->chip_type="i82527"; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->sja_cdr_reg = 0; + candev->chip[chipnr]->sja_ocr_reg = 0; + smartcan_irq=candev->chip[chipnr]->chip_irq; + smartcan_base=candev->chip[chipnr]->chip_base_addr; return 0; } -int smartcan_init_obj_data(int chipnr, int objnr) +int smartcan_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } @@ -132,7 +124,7 @@ unsigned smartcan_read_register(unsigned long address) return ret; } -int smartcan_program_irq(int card) +int smartcan_program_irq(struct candevice_t *candev) { CANMSG("The 'smartcan' card doesn't have programmable interrupts\n"); return 0; diff --git a/lincan/src/ssv.c b/lincan/src/ssv.c index bc54d63..7cb10b9 100644 --- a/lincan/src/ssv.c +++ b/lincan/src/ssv.c @@ -6,13 +6,6 @@ */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#ifdef MODVERSIONS -#include -#endif #include #include @@ -38,17 +31,15 @@ unsigned long ssvcan_base=0x0; * will have to add the code to reserve this memory as well. * The reserved memory starts at io_addr, wich is the module parameter io. */ -int ssv_request_io(unsigned long io_addr) +int ssv_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, - io_addr + IO_RANGE - 1); + } else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, + candev->io_addr + IO_RANGE - 1); } return 0; } @@ -56,10 +47,10 @@ int ssv_request_io(unsigned long io_addr) /* The function template_release_io is used to free the previously reserved * io-memory. In case you reserved more memory, don't forget to free it here. */ -int ssv_release_io(unsigned long io_addr) +int ssv_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -68,7 +59,7 @@ int ssv_release_io(unsigned long io_addr) * hardware specific so I haven't included example code. Don't forget to check * the reset status of the chip before returning. */ -int ssv_reset(int card) +int ssv_reset(struct candevice_t *candev) { int i; @@ -126,12 +117,13 @@ int ssv_reset(int card) #define NR_82527 2 #define NR_SJA1000 0 -int ssv_init_hw_data(int card) +int ssv_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=NR_82527; - candevices_p[card]->nr_sja1000_chips=0; - candevices_p[card]->flags |= PROGRAMMABLE_IRQ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=NR_82527; + candev->flags |= PROGRAMMABLE_IRQ; return 0; } @@ -147,19 +139,19 @@ int ssv_init_hw_data(int card) */ #define CHIP_TYPE "i82527" -int ssv_init_chip_data(int card, int chipnr) +int ssv_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr= - candevices_p[card]->io_addr+0x100*chipnr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - ssvcan_irq[chipnr]=candevices_p[card]->chip[chipnr]->chip_irq; + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr= + candev->io_addr+0x100*chipnr; + candev->chip[chipnr]->clock = 16000000; + ssvcan_irq[chipnr]=candev->chip[chipnr]->chip_irq; - ssvcan_base=candevices_p[card]->io_addr; + ssvcan_base=candev->io_addr; - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC; - candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; return 0; } @@ -173,12 +165,12 @@ int ssv_init_chip_data(int card, int chipnr) * base address. * Unless the hardware uses a segmented memory map, flags can be set zero. */ -int ssv_init_obj_data(int chipnr, int objnr) +int ssv_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr= - chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr= + chip->chip_base_addr+(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } @@ -189,7 +181,7 @@ int ssv_init_obj_data(int chipnr, int objnr) * function unedited. Again this function is hardware specific so there's no * example code. */ -int ssv_program_irq(int card) +int ssv_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/template.c b/lincan/src/template.c index 1c638ae..3075ad5 100644 --- a/lincan/src/template.c +++ b/lincan/src/template.c @@ -1,8 +1,10 @@ /* template.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ /* This file is intended as a template file for currently unsupported hardware. @@ -11,13 +13,6 @@ */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #include #include @@ -50,15 +45,13 @@ * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int template_request_io(unsigned long io_addr) +int template_request_io(struct candevice_t *candev) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { + CANMSG("Unable to open port: 0x%lx\n",candev->io_addr); return -ENODEV; - } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + }else { + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); } return 0; } @@ -75,9 +68,9 @@ int template_request_io(unsigned long io_addr) * Return Value: The function always returns zero * File: src/template.c */ -int template_release_io(unsigned long io_addr) +int template_release_io(struct candevice_t *candev) { - release_region(io_addr,IO_RANGE); + can_release_io_region(candev->io_addr,IO_RANGE); return 0; } @@ -92,35 +85,36 @@ int template_release_io(unsigned long io_addr) * Return Value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int template_reset(int card) +int template_reset(struct candevice_t *candev) { return 0; } #define RESET_ADDR 0x0 -#define NR_82527 0 +#define NR_82527 1 #define NR_SJA1000 0 /** - * template_init_hw_data - Initialze hardware cards + * template_init_hw_data - Initialize hardware cards * @card: Number of the hardware card. * * The function template_init_hw_data() is used to initialize the hardware * structure containing information about the installed CAN-board. * %RESET_ADDR represents the io-address of the hardware reset register. - * %NR_82527 represents the number of intel 82527 chips on the board. - * %NR_SJA1000 represents the number of philips sja1000 chips on the board. + * %NR_82527 represents the number of Intel 82527 chips on the board. + * %NR_SJA1000 represents the number of Philips sja1000 chips on the board. * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that * the hardware uses programmable interrupts. * Return Value: The function always returns zero * File: src/template.c */ -int template_init_hw_data(int card) +int template_init_hw_data(struct candevice_t *candev) { - candevices_p[card]->res_addr=RESET_ADDR; - candevices_p[card]->nr_82527_chips=1; - candevices_p[card]->nr_sja1000_chips=0; - candevices_p[card]->flags |= PROGRAMMABLE_IRQ; + candev->res_addr=RESET_ADDR; + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=NR_SJA1000; + candev->nr_all_chips=NR_82527+NR_SJA1000; + candev->flags |= PROGRAMMABLE_IRQ; return 0; } @@ -158,16 +152,16 @@ int template_init_hw_data(int card) * Return Value: The function always returns zero * File: src/template.c */ -int template_init_chip_data(int card, int chipnr) +int template_init_chip_data(struct candevice_t *candev, int chipnr) { - candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; - candevices_p[card]->chip[chipnr]->clock = 16000000; - candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC; - candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1; - candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY; - candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; - candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->int_cpu_reg = iCPU_DSC; + candev->chip[chipnr]->int_clk_reg = iCLK_SL1; + candev->chip[chipnr]->int_bus_reg = iBUS_CBY; + candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | OCR_TX0_LH; return 0; @@ -190,10 +184,10 @@ int template_init_chip_data(int card, int chipnr) * Return Value: The function always returns zero * File: src/template.c */ -int template_init_obj_data(int chipnr, int objnr) +int template_init_obj_data(struct chip_t *chip, int objnr) { - chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10; - chips_p[chipnr]->msgobj[objnr]->flags=0; + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10; + chip->msgobj[objnr]->flags=0; return 0; } @@ -210,7 +204,7 @@ int template_init_obj_data(int chipnr, int objnr) * Return value: The function returns zero on success or %-ENODEV on failure * File: src/template.c */ -int template_program_irq(int card) +int template_program_irq(struct candevice_t *candev) { return 0; } diff --git a/lincan/src/write.c b/lincan/src/write.c index 98ad046..2874003 100644 --- a/lincan/src/write.c +++ b/lincan/src/write.c @@ -1,18 +1,13 @@ /* write.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. - * Version 0.7 6 Aug 2001 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif #define __NO_VERSION__ #include @@ -26,15 +21,19 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset) { + struct canuser_t *canuser = (struct canuser_t*)(file->private_data); struct msgobj_t *obj; - struct chip_t *chip; - struct canmsg_t *write_msg; - struct canfifo_t *fifo; + struct canmsg_t msg_buff; + struct canque_ends_t *qends; + struct canque_edge_t *qedge; + struct canque_slot_t *slot; int ret = 0; - int space = 0; - int written = 0; int bytes_to_copy = 0; - long can_timeout = 1; + + if(!canuser || (canuser->magic != CAN_USER_MAGIC)){ + CANMSG("can_close: bad canuser magic\n"); + return -ENODEV; + } if (length < sizeof(struct canmsg_t)) { DEBUGMSG("Trying to write less bytes than a CAN message,\n"); @@ -52,124 +51,59 @@ ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t * } /* Initialize hardware pointers */ - if ( (obj = objects_p[MINOR_NR]) == NULL) { + obj = canuser->msgobj; + if (obj == NULL) { CANMSG("Could not assign buffer structure\n"); return -1; } - if ( (chip = obj->hostchip) == NULL) { - CANMSG("Device is not correctly configured,\n"); - CANMSG("please reload the driver\n"); - return -1; - } - if ( (fifo = obj->fifo) == NULL) { - CANMSG("Could not assign buffer memory\n"); - return -1; - } + qends = canuser->qends; - /* Initialize pointer to the first message to be sent */ - write_msg = fifo->tx_writep; - /* Calculate free buffer space */ - cli(); - space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ? - ((int)fifo->tx_readp - (int)fifo->tx_writep) : - ((int)fifo->tx_readp - (int)fifo->tx_writep + - (int)fifo->tx_size); - sti(); + /* Prepare first message */ + copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t)); /* If the output buffer is full, return immediately in case O_NONBLOCK * has been specified or loop until space becomes available. */ - while (space < sizeof(struct canmsg_t)) { + if ((ret=canque_get_inslot4id(qends, &qedge, &slot, + 0, msg_buff.id, 0))<0){ DEBUGMSG("Buffer is full\n"); if (file->f_flags & O_NONBLOCK) return -EAGAIN; - can_timeout = interruptible_sleep_on_timeout(&fifo->writeq, - CANTIMEOUT); - if (signal_pending(current)) - return -EINTR; - if (!can_timeout) + if(ret < -1) + return -EIO; + + ret=canque_get_inslot4id_wait_kern(qends, &qedge, &slot, + 0, msg_buff.id, 0); + if(ret<0) { + if (signal_pending(current)) + return -EINTR; + /*if (!can_timeout)*/ return -EIO; - cli(); - space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ? - ((int)fifo->tx_readp - (int)fifo->tx_writep) : - ((int)fifo->tx_readp - (int)fifo->tx_writep + - (int)fifo->tx_size); - sti(); + } } + slot->msg=msg_buff; + canque_put_inslot(qends, qedge, slot); + buffer += sizeof(struct canmsg_t); + bytes_to_copy = length-sizeof(struct canmsg_t); - /* There's space available in the kernel output buffer. - * Find out wich is smaller: 'length', the number of bytes requested to - * be written or 'space', the number of bytes available in the kernel - * buffer. We copy the least of the two to kernel space. + /* + * Try to send more messages */ -// space = space - (space % sizeof(struct canmsg_t)); // round it - bytes_to_copy = space < length ? space : length; - copy_from_user(fifo->tx_writep, buffer, bytes_to_copy); - written = bytes_to_copy; while (bytes_to_copy > 0) { - fifo->tx_writep++; - if (fifo->tx_writep >= fifo->buf_tx_entry + MAX_BUF_LENGTH) - fifo->tx_writep = fifo->buf_tx_entry; + /* Prepare first message */ + copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t)); + /* Get slot */ + if(canque_get_inslot4id(qends, &qedge, &slot, + 0, msg_buff.id, 0) < 0) break; + slot->msg=msg_buff; + canque_put_inslot(qends, qedge, slot); + buffer += sizeof(struct canmsg_t); bytes_to_copy -= sizeof(struct canmsg_t); } - /* Copy the data to be transmitted into the output buffer */ -/* while ( (written < length) && (space >= sizeof(struct canmsg_t)) ) { - copy_from_user(fifo->tx_writep,buffer, sizeof(struct canmsg_t)); - cli(); - fifo->tx_writep++; - if (fifo->tx_writep >= fifo->buf_tx_entry + MAX_BUF_LENGTH) - fifo->tx_writep = fifo->buf_tx_entry; - buffer += sizeof(struct canmsg_t); - written += sizeof(struct canmsg_t); - space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ? - ((int)fifo->tx_readp - (int)fifo->tx_writep) : - ((int)fifo->tx_readp - (int)fifo->tx_writep + - (int)fifo->tx_size); - sti(); - } */ - - /* Initiate transmission in case we are not already transmitting */ - cli(); - if (!fifo->tx_in_progress) { - fifo->tx_in_progress = 1; - sti(); - if ( (ret = chip->chipspecops->pre_write_config(chip, obj, - write_msg)) < 0) { - CANMSG("Error initializing hardware for sending\n"); - return -EIO; - } - obj->ret = 0; - if ( (ret = chip->chipspecops->send_msg(chip, obj, - write_msg)) < 0) { - CANMSG("Error sending message\n"); - return -EIO; - } - /* If O_SYNC is specified wait for successfull transmission */ -/* while (1) { - cli(); - if ( (!file->f_flags & O_SYNC) || - (!fifo->tx_in_progress)) { - sti(); - if (obj->ret < 0) - return obj->ret; - else - return written; - } - cli(); - if (fifo->tx_in_progress) { - can_timeout = interruptible_sleep_on_timeout( - &fifo->writeq, CANTIMEOUT); - } - sti(); - if (signal_pending(current)) - return -EINTR; - if (!can_timeout) - return -EIO; - } */ + if(file->f_flags & O_SYNC) { + canque_sync_wait_kern(qends, qedge); } - sti(); - - return written; + return length-bytes_to_copy; } -- 2.39.2