-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 <pisa@cmp.felk.cvut.cz>
+ OCERA team member
+ <http://www.ocera.org>
- 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 <T.Motylewski@bfad.de>
+
+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 <pisa@cmp.felk.cvut.cz>) or to OCERA discussion
+forum <https://sourceforge.net/forum/forum.php?forum_id=170893>
+and lists <ocera-development@lists.sourceforge.net>
-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' <options>
Example: # insmod can.o hw=pip5 irq=4 io=0x8000
options can be one of:
- major=<nr>, major specifies the major number of the driver.
-- minor=<nr>, you can specify wich minor numbers the driver should use for your
+- minor=<nr>, 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.
- 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
/* 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);
+#ifndef _CANMSG_T_H
+#define _CANMSG_T_H
+
#include <linux/types.h>
#include <linux/ioctl.h>
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)
//#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*/
--- /dev/null
+#ifndef _CAN_QUEUE_H
+#define _CAN_QUEUE_H
+
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#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<<CAN_FIFOF_DESTROY_b)
+#define CAN_FIFOF_ERROR (1<<CAN_FIFOF_ERROR_b)
+#define CAN_FIFOF_ERR2BLOCK (1<<CAN_FIFOF_ERR2BLOCK_b)
+#define CAN_FIFOF_BLOCK (1<<CAN_FIFOF_BLOCK_b)
+#define CAN_FIFOF_OVERRUN (1<<CAN_FIFOF_OVERRUN_b)
+#define CAN_FIFOF_FULL (1<<CAN_FIFOF_FULL_b)
+#define CAN_FIFOF_EMPTY (1<<CAN_FIFOF_EMPTY_b)
+#define CAN_FIFOF_DEAD (1<<CAN_FIFOF_DEAD_b)
+
+#define canque_fifo_test_fl(fifo,fifo_fl) \
+ test_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->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*/
/* 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);
/* 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);
/* 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__
#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)
--- /dev/null
+/* 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 <linux/fs.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#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);
/* 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);
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
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);
/* 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);
/* 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);
/* 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);
/* 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 <asm/io.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/wait.h>
-#include <asm/io.h>
+#include <linux/interrupt.h>
#include "./can.h"
#include "./constants.h"
+#include "./can_queue.h"
#ifdef CAN_DEBUG
#define DEBUGMSG(fmt,args...) printk(KERN_ERR "can.o (debug): " fmt,\
(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;
};
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];
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
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 {
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 {
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;
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];
/* 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);
-}
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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);
/* 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 <linux/proc_fs.h>
/* 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);
/* 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);
/* 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);
/* 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);
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 */
/* 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);
* 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);
/* 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);
# 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
#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
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
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 =
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
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
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
* 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;
}
* 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;
}
* 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++;
* 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;
}
* 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;
}
* 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;
}
* 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;
}
/* 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.
#define __NO_VERSION__ /* this is not a main module, do not include module info */
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/module.h>
#include <linux/version.h>
* 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;
}
* 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;
}
* 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);
* 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;
}
* 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);
* 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;
}
* 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;
}
--- /dev/null
+/* 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 <linux/module.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+#include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+#include <linux/wait.h>
+#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_prio<edge->edge_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;
+}
+
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
* 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;
}
* 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;
}
* 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;
}
* 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;
}
* 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;
* 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;
}
* 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;
}
/* 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 <linux/module.h>
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/fs.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+#include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
#include "../include/main.h"
#include "../include/close.h"
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
--- /dev/null
+/* 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 <linux/module.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+#include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+#include <linux/wait.h>
+#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;
+}
+
+
/* 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 <linux/module.h>
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
+#include <linux/sched.h>
#include <linux/fs.h>
#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;
{
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;
(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));
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)
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; i<msg->length; 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;
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;
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;
}
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);
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; i<rtr_search->rtr_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;
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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/string.h>
+#include <asm/uaccess.h>
#include "../include/main.h"
#include "../include/ioctl.h"
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;
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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/sched.h>
#include <linux/version.h>
#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; i<rtr_search->rtr_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; i<fifo->rx_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;
}
/* 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
*/
/*
*/
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
* 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;
}
* 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;
/* release I/O memory mapping */
iounmap((void*)base);
+ release_mem_region(candev->io_addr,IO_RANGE);
+
return 0;
}
* 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;
}
* 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;
* 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;
}
* 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;
}
* 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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
#include <linux/module.h>
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
-
#include <linux/kernel.h>
#include <linux/fs.h>
-#include <linux/wrapper.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/version.h>
#include <linux/autoconf.h>
#include <linux/interrupt.h>
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,50))
+#include <linux/wrapper.h>
+#endif
+
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
#include <asm/spinlock.h>
#else
#endif
#endif
+/*#undef CONFIG_DEVFS_FS*/
+
#ifdef CONFIG_DEVFS_FS
#include <linux/miscdevice.h>
#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"
/* 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
int init_module(void)
{
int res=0,i=0;
+ struct candevice_t *candev;
if (parse_mod_parms())
return -EINVAL;
}
for (i=0; i<hardware_p->nr_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; i<hardware_p->nr_boards; i++) {
- if (candevices_p[i]->hwspecops->reset(i))
+ candev=hardware_p->candevice[i];
+ if (candev->hwspecops->reset(candev))
goto reset_error;
}
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);
}
for (i=0; i<hardware_p->nr_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;
}
goto memory_error;
memory_error: ;
- for (i=0; i<hardware_p->nr_boards; i++)
- candevices_p[i]->hwspecops->release_io(candevices_p[i]->io_addr);
+ for (i=0; i<hardware_p->nr_boards; i++) {
+ candev=hardware_p->candevice[i];
+ candev->hwspecops->release_io(candev);
+ }
goto register_error;
register_error: ;
void cleanup_module(void)
{
int res=0,i=0;
+ struct candevice_t *candev;
#ifdef CONFIG_PROC_FS
if (can_delete_procdir())
i++;
}
- for (i=0; i<hardware_p->nr_boards; i++)
- candevices_p[i]->hwspecops->release_io(candevices_p[i]->io_addr);
+ for (i=0; i<hardware_p->nr_boards; i++){
+ candev=hardware_p->candevice[i];
+ candev->hwspecops->release_io(candev);
+ }
if ( del_mem_list() )
CANMSG("Error deallocating memory\n");
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include ".supported_cards.h"
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; j<hardware_p->candevice[i]->nr_82527_chips+hardware_p->candevice[i]->nr_sja1000_chips; j++) {
+ for (j=0; j<hardware_p->candevice[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; k<hardware_p->candevice[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++;
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
/* 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;
}
/* 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;
}
* 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);
#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;
}
* 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;
}
* 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;
}
* 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;
}
/* 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 <linux/module.h>
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/fs.h>
#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
#include <linux/malloc.h>
#else
#include <linux/slab.h>
#endif
-#include <linux/version.h>
#include "../include/main.h"
#include "../include/open.h"
{
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) ) {
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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
* 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;
}
* 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;
}
* 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;
* 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;
}
* 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;
* 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;
}
* 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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
-#include <asm/irq.h>
#include <asm/errno.h>
#include <asm/io.h>
+#include <asm/irq.h>
#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++;
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++;
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++;
}
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++;
}
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
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;
}
}
}
}
- 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;
/* 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.
*/
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
* 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;
}
* 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;
}
* 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++;
}
* 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;
}
* 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;
}
* 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;
}
* 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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
#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
* 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;
}
* 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;
}
* 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;chipnr<candevices_p[card]->nr_sja1000_chips;chipnr++) {
- chip=candevices_p[card]->chip[chipnr];
+ for(chipnr=0;chipnr<candev->nr_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);
* 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;
}
* 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;
* 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;
}
* 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;
}
*/
void pcm3680_write_register(unsigned char data, unsigned long address)
{
- writeb(data,isa_base+address);
+ writeb(data,address);
}
/**
*/
unsigned pcm3680_read_register(unsigned long address)
{
- return readb(isa_base+address);
+ return readb(address);
}
/* !!! Don't change this function !!! */
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
*/
#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
* 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;
}
* 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;
}
* 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);
* 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;
}
* 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;
}
* 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;
}
* 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;
}
*/
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);
}
/**
*/
unsigned pikronisa_read_register(unsigned long address)
{
- return readb(base+address);
+ return readb(address);
}
/* !!! Don't change this function !!! */
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
#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++;
}
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) &&
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; }
/* 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 <linux/module.h>
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/version.h>
#include <linux/kernel.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
#include <linux/malloc.h>
#else
#include <linux/slab.h>
#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;
*/
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);
if (base->can_proc_entry == NULL)
return -ENODEV;
- for (bc=0; bc<hardware_p->nr_boards; bc++) {
- add_channel_to_procdir();
+ for (board=0; board<hardware_p->nr_boards; board++) {
+ candev=hardware_p->candevice[board];
+ if(candev) add_channel_to_procdir(candev);
}
return 0;
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);
if (base->channel[cc]->ch_entry == NULL)
return -ENODEV;
- add_object_to_procdir();
+ add_object_to_procdir(cc);
cc++;
}
}
-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; i<obj; i++) {
- oc=i;
- base->channel[cc]->object[i] = (struct objectproc_t *)
+ for (i=0; i<max_objects; i++) {
+ base->channel[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
{
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<obj; i++) {
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
/* read.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 <linux/module.h>
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
#include <linux/malloc.h>
#else
#include <linux/slab.h>
#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 */
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");
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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/version.h>
#include <linux/poll.h>
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;
}
/* 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 <linux/module.h>
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
#include <linux/malloc.h>
#else
#include <linux/slab.h>
#endif
#include <linux/fs.h>
+#include <linux/ioport.h>
#include ".supported_cards.h"
#include "../include/main.h"
+#include "../include/devcommon.h"
#include "../include/setup.h"
#include "../include/pip.h"
#include "../include/pccan.h"
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)
{
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;i<candev->nr_all_chips;i++){
+ candev->chip[i]->chip_base_addr += offs;
+ for(j=0;j<candev->chip[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)
{
*/
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;
/* 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++;
}
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; i<max_objects; i++) {
- chips_p[chip]->msgobj[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+i<MAX_TOT_MSGOBJS)){
+ objects_p[minorbase+i]=obj;
+ obj->minor=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++;
}
}
-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;
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
+#include <linux/sched.h>
#include <linux/delay.h>
#include <asm/irq.h>
#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;
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; i<fifo->rx_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)
{
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; i<obj->rx_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;
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;
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/sched.h>
#include <linux/delay.h>
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))
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;
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)
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;
}
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)
{
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)
{
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)
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)
{
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;
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;
}
+/**
+ * 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)
{
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);
// 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
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) {
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)
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;
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
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++;
}
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;
}
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;
*/
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
* 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;
}
/* 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;
}
* 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;
#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;
}
*/
#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;
}
* 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;
}
* 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;
}
/* 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.
*/
#include <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <linux/ioport.h>
#include <linux/delay.h>
* 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;
}
* 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;
}
* 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;
}
* 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;
* 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;
}
* 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;
}
/* 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 <linux/autoconf.h>
-#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
-#define MODVERSIONS
-#endif
-
-#if defined (MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#define __NO_VERSION__
#include <linux/module.h>
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");
}
/* 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;
}