/* 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);
-}