#define CAN_IRQ_HANDLED IRQ_HANDLED
#define CAN_IRQ_RETVAL IRQ_RETVAL
#endif /* <=2.5.67 */
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+ #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \
+ int irq_number, void *dev_id, struct pt_regs *regs
+ #else /* < 2.6.19 */
+ #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \
+ int irq_number, void *dev_id
+ #endif /* < 2.6.19 */
#else /*CAN_WITH_RTL*/
typedef int can_irqreturn_t;
#define CAN_IRQ_NONE 0
#define CAN_IRQ_HANDLED 1
#define CAN_IRQ_RETVAL(x) ((x) != 0)
+ #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \
+ int irq_number, void *dev_id, struct pt_regs *regs
#endif /*CAN_WITH_RTL*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33))
#define del_timer_sync del_timer
#endif /* <2.4.0 */
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
+ typedef unsigned long can_ioptr_t;
+ #define can_ioptr2ulong(ioaddr) ((unsigned long)(ioaddr))
+ #define can_ulong2ioptr(addr) ((unsigned long)(addr))
+ #define can_inb(ioaddr) inb(ioaddr)
+ #define can_outb(data,ioaddr) outb(data,ioaddr)
+ #define can_inw(ioaddr) inb(ioaddr)
+ #define can_outw(data,ioaddr) outb(data,ioaddr)
+ #define can_inl(ioaddr) inb(ioaddr)
+ #define can_outl(data,ioaddr) outb(data,ioaddr)
+ #else /* >=2.6.9 */
+ typedef void __iomem * can_ioptr_t;
+ #define can_ioptr2ulong(ioaddr) ((unsigned long __force)(ioaddr))
+ #define can_ulong2ioptr(addr) ((can_ioptr_t)(addr))
+ #define can_inb(ioaddr) inb(can_ioptr2ulong(ioaddr))
+ #define can_outb(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr))
+ #define can_inw(ioaddr) inb(can_ioptr2ulong(ioaddr))
+ #define can_outw(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr))
+ #define can_inl(ioaddr) inb(can_ioptr2ulong(ioaddr))
+ #define can_outl(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr))
+ #endif
+
+ #define can_readb readb
+ #define can_writeb writeb
+ #define can_readw readw
+ #define can_writew writew
+ #define can_readl readl
+ #define can_writel writel
+
+ #define can_ioport2ioptr can_ulong2ioptr
+
#ifdef __HAVE_ARCH_CMPXCHG
#define CAN_HAVE_ARCH_CMPXCHG
#endif
#define CAN_DEFINE_SPINLOCK DEFINE_SPINLOCK
#endif /*DEFINE_SPINLOCK*/
- #if defined(CONFIG_PREEMPT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+ #if !defined(CONFIG_PREEMPT_RT) && ( defined(CONFIG_PREEMPT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) )
#define can_preempt_disable preempt_disable
#define can_preempt_enable preempt_enable
#else /*CONFIG_PREEMPT*/
#endif /*CAN_WITH_RTL*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4))
+ #include <linux/kthread.h>
+ #define can_kthread_create kthread_create
+ #define can_kthread_run kthread_run
+ #define can_kthread_bind kthread_bind
+ #define can_kthread_stop kthread_stop
+ #define can_kthread_should_stop kthread_should_stop
+#else
+ #define can_kthread_create
+ #define can_kthread_run
+ #define can_kthread_bind
+ #define can_kthread_stop
+ #define can_kthread_should_stop
+#endif
+
+
#endif /*_CAN_SYSDEP_H*/
#include "./can_queue.h"
#ifdef CAN_DEBUG
- #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "can.o (debug): " fmt,\
+ #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "lincan (debug): " fmt,\
##args)
#else
#define DEBUGMSG(fmt,args...)
#endif
- #define CANMSG(fmt,args...) can_printk(KERN_ERR "can.o: " fmt,##args)
+ #define CANMSG(fmt,args...) can_printk(KERN_ERR "lincan: " fmt,##args)
extern can_spinlock_t canuser_manipulation_lock;
int candev_idx; /* board index in canhardware_t.candevice[] */
unsigned long io_addr; /* IO/physical MEM address */
unsigned long res_addr; /* optional reset register port */
- unsigned long dev_base_addr; /* CPU translated IO/virtual MEM address */
+ can_ioptr_t dev_base_addr; /* CPU translated IO/virtual MEM address */
+ can_ioptr_t aux_base_addr; /* CPU translated IO/virtual MEM address */
unsigned int flags;
int nr_all_chips;
int nr_82527_chips;
char *chip_type;
int chip_idx; /* chip index in candevice_t.chip[] */
int chip_irq;
- unsigned long chip_base_addr;
+ can_ioptr_t chip_base_addr;
unsigned int flags;
long clock; /* Chip clock in Hz */
long baudrate;
- void (*write_register)(unsigned data,unsigned long address);
- unsigned (*read_register)(unsigned long address);
+ void (*write_register)(unsigned data, can_ioptr_t address);
+ unsigned (*read_register)(can_ioptr_t address);
void *chip_data;
* that reuse same object for TX
*/
struct msgobj_t {
- unsigned long obj_base_addr;
+ can_ioptr_t obj_base_addr;
unsigned int minor; /* associated device minor number */
unsigned int object; /* object number in canchip_t +1 for debug printk */
unsigned long obj_flags;
int (*init_chip_data)(struct candevice_t *candev, int chipnr);
int (*init_obj_data)(struct canchip_t *chip, int objnr);
int (*program_irq)(struct candevice_t *candev);
- void (*write_register)(unsigned data,unsigned long address);
- unsigned (*read_register)(unsigned long address);
+ void (*write_register)(unsigned data, can_ioptr_t address);
+ unsigned (*read_register)(can_ioptr_t address);
};
/**
extern int minor[MAX_TOT_CHIPS];
extern int extended;
extern int baudrate[MAX_TOT_CHIPS];
- extern char *hw[MAX_HW_CARDS];
extern int irq[MAX_IRQ];
+ extern char *hw[MAX_HW_CARDS];
extern unsigned long io[MAX_HW_CARDS];
+ extern long clockfreq[MAX_HW_CARDS];
extern int processlocal;
extern struct canhardware_t *hardware_p;
#if defined(CONFIG_OC_LINCAN_PORTIO_ONLY)
- extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address)
+ extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned reg_offs)
{
- outb(data, chip->chip_base_addr+address);
+ can_outb(data, chip->chip_base_addr+reg_offs);
}
- extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address)
+ extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned reg_offs)
{
- return inb(chip->chip_base_addr+address);
+ return can_inb(chip->chip_base_addr+reg_offs);
}
extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
- unsigned char data, unsigned address)
+ unsigned char data, unsigned reg_offs)
{
- outb(data, obj->obj_base_addr+address);
+ can_outb(data, obj->obj_base_addr+reg_offs);
}
extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
- unsigned address)
+ unsigned reg_offs)
{
- return inb(obj->obj_base_addr+address);
+ return can_inb(obj->obj_base_addr+reg_offs);
}
#elif defined(CONFIG_OC_LINCAN_MEMIO_ONLY)
- extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address)
+ extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned reg_offs)
{
- writeb(data, chip->chip_base_addr+address);
+ can_writeb(data, chip->chip_base_addr+reg_offs);
}
- extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address)
+ extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned reg_offs)
{
- return readb(chip->chip_base_addr+address);
+ return can_readb(chip->chip_base_addr+reg_offs);
}
extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
- unsigned char data, unsigned address)
+ unsigned char data, unsigned reg_offs)
{
- writeb(data, obj->obj_base_addr+address);
+ can_writeb(data, obj->obj_base_addr+reg_offs);
}
extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
- unsigned address)
+ unsigned reg_offs)
{
- return readb(obj->obj_base_addr+address);
+ return can_readb(obj->obj_base_addr+reg_offs);
}
#else /*CONFIG_OC_LINCAN_DYNAMICIO*/
#define CONFIG_OC_LINCAN_DYNAMICIO
#endif
- /* Inline function to write to the hardware registers. The argument address is
- * relative to the memory map of the chip and not the absolute memory address.
+ /* Inline function to write to the hardware registers. The argument reg_offs is
+ * relative to the memory map of the chip and not the absolute memory reg_offs.
*/
- extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address)
+ extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned reg_offs)
{
- unsigned long address_to_write;
- address_to_write = chip->chip_base_addr+address;
+ can_ioptr_t address_to_write;
+ address_to_write = chip->chip_base_addr+reg_offs;
chip->write_register(data, address_to_write);
}
- extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address)
+ extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned reg_offs)
{
- unsigned long address_to_read;
- address_to_read = chip->chip_base_addr+address;
+ can_ioptr_t address_to_read;
+ address_to_read = chip->chip_base_addr+reg_offs;
return chip->read_register(address_to_read);
}
extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
- unsigned char data, unsigned address)
+ unsigned char data, unsigned reg_offs)
{
- unsigned long address_to_write;
- address_to_write = obj->obj_base_addr+address;
+ can_ioptr_t address_to_write;
+ address_to_write = obj->obj_base_addr+reg_offs;
chip->write_register(data, address_to_write);
}
extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
- unsigned address)
+ unsigned reg_offs)
{
- unsigned long address_to_read;
- address_to_read = obj->obj_base_addr+address;
+ can_ioptr_t address_to_read;
+ address_to_read = obj->obj_base_addr+reg_offs;
return chip->read_register(address_to_read);
}
#endif /*CONFIG_OC_LINCAN_DYNAMICIO*/
- int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base);
+ int can_base_addr_fixup(struct candevice_t *candev, can_ioptr_t new_base);
int can_request_io_region(unsigned long start, unsigned long n, const char *name);
void can_release_io_region(unsigned long start, unsigned long n);
int can_request_mem_region(unsigned long start, unsigned long n, const char *name);
#ifdef CAN_WITH_RTL
extern int can_rtl_priority;
#endif /*CAN_WITH_RTL*/
+
+extern struct candevice_t* register_usbdev(const char *hwname,void *devdata,void (*chipdataregfnc)(struct canchip_t *chip,void *data));
+extern void cleanup_usbdev(struct candevice_t *dev);
lincan_cards_NAMES = pip pccan smartcan nsi cc_can104 ems_cpcpci \
- pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan pikronisa eb8245 \
- kv_pcican msmcan oscar adlink7841 unican virtual template usbcan
+ pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan gensja1000io pikronisa eb8245 \
- kv_pcican msmcan oscar adlink7841 pcan_pci esdpci200 unican virtual template
++ kv_pcican msmcan oscar adlink7841 pcan_pci esdpci200 unican usbcan virtual template
- lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 nsi_canpci
+ lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 nsi_canpci sh7760
default_CONFIG = CONFIG_OC_LINCAN=y CONFIG_OC_LINCANRTL=n CONFIG_OC_LINCANVME=n
default_CONFIG += CONFIG_OC_LINCAN_PORTIO_ONLY=n CONFIG_OC_LINCAN_MEMIO_ONLY=n
rtlinux_INCLUDES = -I $(srcdir)/../include -I .
kernel_INCLUDES = -I $(srcdir)/../include -I .
#kernel_INCLUDES += -DCAN_DEBUG
- kernel_INCLUDES += -DWITH_DEVFS_FS -DKBUILD_MODNAME
+ kernel_INCLUDES += -DWITH_DEVFS_FS
lincan_cards_SOURCES = $(lincan_cards_SELECTED:%=%.c)
lincan_cards_SOURCES += ipci165_fw.c kthread.c
endif
+ ifeq ($(CONFIG_OC_LINCAN_CARD_sh7760),y)
+ lincan_cards_SOURCES += sh7760.c
+ endif
+
+ifeq ($(CONFIG_OC_LINCAN_CARD_usbcan),y)
+lincan_cards_SOURCES += kthread.c
+endif
+
ifneq ($(filter hms30c7202_can ns_dev_can,$(lincan_cards_SELECTED)),)
$(warning Not finished C_CAN support requested)
lincan_cards_SOURCES += c_can.c c_can_irq.c
lincan_SOURCES = can_queue.c can_quekern.c main.c modparms.c \
devcommon.c setup.c finish.c irq.c sysdep_lnx.c boardlist.c \
- sja1000p.c sja1000.c i82527.c \
+ sja1000p.c sja1000.c i82527.c hcan2.c \
open.c close.c read.c write.c ioctl.c select.c fasync.c \
proc.c ioctl_query.c ioctl_remote.c \
$(lincan_cards_SOURCES) $(lincan_rtl_SOURCES)
extern int ssv_register(struct hwspecops_t *hwspecops);
extern int bfadcan_register(struct hwspecops_t *hwspecops);
extern int pikronisa_register(struct hwspecops_t *hwspecops);
+ extern int gensja1000io_register(struct hwspecops_t *hwspecops);
extern int pimx1_register(struct hwspecops_t *hwspecops);
extern int msmcan_register(struct hwspecops_t *hwspecops);
extern int unican_register(struct hwspecops_t *hwspecops);
extern int ns_dev_register(struct hwspecops_t *hwspecops);
extern int hms30c7202_register(struct hwspecops_t *hwspecops);
extern int nsi_canpci_register(struct hwspecops_t *hwspecops);
+extern int usbcan_register(struct hwspecops_t *hwspecops);
+ extern int pcan_pci_register(struct hwspecops_t *hwspecops);
+ extern int esdpci200_register(struct hwspecops_t *hwspecops);
+ extern int sh7760_register(struct hwspecops_t *hwspecops);
const struct boardtype_t can_boardtypes[]={
#ifdef CONFIG_OC_LINCAN_CARD_template
#ifdef CONFIG_OC_LINCAN_CARD_pikronisa
{"pikronisa", pikronisa_register, 1},
#endif
+ #ifdef CONFIG_OC_LINCAN_CARD_gensja1000io
+ {"gensja1000io", gensja1000io_register, 1},
+ #endif
#ifdef CONFIG_OC_LINCAN_CARD_pimx1
{"pimx1", pimx1_register, 0},
#endif
#if defined(CONFIG_OC_LINCAN_CARD_adlink7841)
{"adlink7841", adlink7841_register, 0},
#endif
+ #if defined(CONFIG_OC_LINCAN_CARD_esdpci200)
+ {"esdpci200", esdpci200_register, 0},
+ #endif
#if defined(CONFIG_OC_LINCAN_CARD_tscan1)
{"tscan1", tscan1_register, 1},
{"ts7kv", ts7kv_register, 1},
#if defined(CONFIG_OC_LINCAN_CARD_ns_dev_can)
{"ns_dev", ns_dev_register, 1},
#endif
+ #if defined(CONFIG_OC_LINCAN_CARD_sh7760)
+ {"sh7760", sh7760_register, 2},
+ #endif
#if defined(CONFIG_OC_LINCAN_CARD_hms30c7202_can)
{"hms30c7202", hms30c7202_register, 1},
#endif
#if defined(CONFIG_OC_LINCAN_CARD_nsi_canpci)&&defined(CAN_ENABLE_PCI_SUPPORT)
{"nsicanpci", nsi_canpci_register, 1},
#endif
+ #if defined(CONFIG_OC_LINCAN_CARD_pcan_pci)&&defined(CAN_ENABLE_PCI_SUPPORT)
+ {"pcan_pci", pcan_pci_register, 0},
++ #endif
+ #if defined(CONFIG_OC_LINCAN_CARD_usbcan)
+ {"usbcan", usbcan_register, 0},
#endif
{NULL}
};
#include "../include/can_iortl.h"
#endif /*CAN_WITH_RTL*/
+#if defined(CONFIG_OC_LINCAN_CARD_usbcan)
+ #include "../include/usbcan.h"
+#endif
+
can_spinlock_t canuser_manipulation_lock;
int major=CAN_MAJOR;
char *hw[MAX_HW_CARDS]={NULL,};
int irq[MAX_IRQ]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
unsigned long io[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
+ long clockfreq[MAX_HW_CARDS];
int stdmask=0;
int extmask=0;
int mo15mask=0;
unsigned int hw_specified;
unsigned int irq_specified;
unsigned int io_specified;
+ unsigned int clockfreq_specified;
- #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12))
/* Module parameters, some must be supplied at module loading time */
MODULE_PARM(major,"1i");
/*MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS)"i");*/
MODULE_PARM(hw, "1-" __MODULE_STRING(MAX_HW_CARDS)"s");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_IRQ)"i");
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HW_CARDS)"i");
+ MODULE_PARM(clockfreq, "1-" __MODULE_STRING(MAX_HW_CARDS)"i");
MODULE_PARM(stdmask, "1i");
MODULE_PARM(extmask, "1i");
MODULE_PARM(mo15mask, "1i");
MODULE_PARM(processlocal, "1i");
- #else /* LINUX_VERSION_CODE >= 2,6,0 */
+ #else /* LINUX_VERSION_CODE >= 2,6,12 */
module_param(major, int, 0);
module_param_array(minor, int, &minor_specified, 0);
module_param(extended, int, 0);
module_param_array(baudrate, int, &baudrate_specified, 0);
module_param_array(hw, charp, &hw_specified, 0);
module_param_array(irq, int, &irq_specified, 0);
- module_param_array(io, int, &io_specified, 0);
+ module_param_array(io, ulong, &io_specified, 0);
+ module_param_array(clockfreq, long, &clockfreq_specified, 0);
module_param(stdmask, int, 0);
module_param(extmask, int, 0);
module_param(mo15mask, int, 0);
module_param(processlocal, int, 0);
- #endif /* LINUX_VERSION_CODE >= 2,6,0 */
+ #endif /* LINUX_VERSION_CODE >= 2,6,12 */
MODULE_PARM_DESC(major,"can be used to change default major [" __MODULE_STRING(CAN_MAJOR) "]");
MODULE_PARM_DESC(minor,"can be used to change default starting minor for each channel");
MODULE_PARM_DESC(hw,"list of boards types to initialize - virtual,pip5,...");
MODULE_PARM_DESC(irq,"list of iterrupt signal numbers, most ISA has one per chip, no value for PCI or virtual");
MODULE_PARM_DESC(io,"IO address for each board, use 0 for PCI or virtual");
+ MODULE_PARM_DESC(clockfreq,"base board clock source frequency in step of 1kHz");
MODULE_PARM_DESC(stdmask,"default standard mask for i82527 chips");
MODULE_PARM_DESC(extmask,"default extended mask for i82527 chips");
MODULE_PARM_DESC(mo15mask,"mask for communication object 15 of i82527 chips");
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0))
char dev_name[32];
- #else
+ #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) /* >= 2.6.15 */
struct class_device *this_dev;
+ #else
+ struct device *this_dev;
#endif
int dev_minor;
for(i=0;i<MAX_TOT_MSGOBJS;i++) {
#else
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14))
this_dev=class_device_create(can_class, MKDEV(major, dev_minor), NULL, "can%d", dev_minor);
- #else /* >= 2.6.15 */
+ #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) /* >= 2.6.15 */
this_dev=class_device_create(can_class, NULL, MKDEV(major, dev_minor), NULL, "can%d", dev_minor);
- #endif /* >= 2.6.15 */
+ #else /* >= 2.6.26 */
+ this_dev=device_create_drvdata(can_class, NULL, MKDEV(major, dev_minor), objects_p[i], "can%d", dev_minor);
+ #endif /* >= 2.6.26 */
if(IS_ERR(this_dev)){
CANMSG("problem to create device \"can%d\" in the class \"can\"\n", dev_minor);
+ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
}else{
/*this_dev->class_data=objects_p[i];*/
class_set_devdata(this_dev,objects_p[i]);
+ #endif /* <= 2.6.25 */
}
#ifdef CONFIG_DEVFS_FS
devfs_mk_cdev(MKDEV(major, dev_minor), S_IFCHR | S_IRUGO | S_IWUGO, "can%d", dev_minor);
}
}
#endif
+
+#if defined(CONFIG_OC_LINCAN_CARD_usbcan)
+ res = usbcan_init();
+ if (res){
+ CANMSG("usb_register for usbcan failed. Error number %d.\n", res);
+ return -ENODEV;
+ }
+#endif
+
return 0;
#ifdef CONFIG_PROC_FS
canqueue_rtl_done();
#endif /*CAN_WITH_RTL*/
- #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
unregister_chrdev(major,DEVICE_NAME);
- #else /*LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)*/
- res=unregister_chrdev(major,DEVICE_NAME);
- if (res<0)
- CANMSG("Error unloading CAN driver, error: %d\n",res);
- else
- CANMSG("No CAN devices or driver setup error.\n");
- #endif /*LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)*/
+ CANMSG("No CAN devices or driver setup error.\n");
register_error:
if ( can_del_mem_list() )
return -ENODEV;
}
- #else /* >= 2.6.15 */
+
+
+
+
+struct candevice_t* register_usbdev(const char *hwname,void *devdata,void (*chipdataregfnc)(struct canchip_t *ch,void *data)){
+ int i=0, j, board=0;
+ struct candevice_t *candev;
+ struct canchip_t *chip;
+ struct boardtype_t *brp;
+
+ while ( (hw[board] != NULL) && (board < MAX_HW_CARDS) )
+ board++;
+ if (board>=MAX_HW_CARDS){
+ CANMSG("Maximum number of devices has been reached, no space for new device");
+ return NULL;
+ }
+ brp = boardtype_find(hwname);
+ if(!brp) {
+ CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",hw[board]);
+ return NULL;
+ }
+ if (board==MAX_HW_CARDS){
+ CANMSG("Device \"%s\" could not be registered due to internal limits.\n",hw[board]);
+ return NULL;
+ }
+ hw[board]=brp->boardtype;
+
+ if (init_new_hw_struct(board))
+ return NULL;
+
+ #ifdef CAN_DEBUG
+ list_hw();
+ #endif
+
+ candev=hardware_p->candevice[board];
+
+ /* Adding link to usb device structure into can device */
+ candev->sysdevptr.anydev=devdata;
+
+ if (candev->hwspecops->request_io(candev))
+ goto request_io_error;
+ candev->flags|=CANDEV_IO_RESERVED;
+
+ if (candev->hwspecops->reset(candev))
+ goto reset_error;
+
+ for(j=0; j<candev->nr_all_chips; j++) {
+ if((chip=candev->chip[j])==NULL)
+ continue;
+
+ chipdataregfnc(chip,devdata);
+
+ if(chip->chipspecops->attach_to_chip(chip)<0) {
+ CANMSG("Initial attach to the chip HW failed\n");
+ goto interrupt_error;
+ }
+
+ chip->flags |= CHIP_ATTACHED;
+
+ if(can_chip_setup_irq(chip)<0) {
+ CANMSG("Error to setup chip IRQ\n");
+ goto interrupt_error;
+ }
+ }
+
+ if (candev->flags & CANDEV_PROGRAMMABLE_IRQ)
+ if (candev->hwspecops->program_irq(candev)){
+ CANMSG("Error to program board interrupt\n");
+ goto interrupt_error;
+ }
+
+#ifdef CONFIG_PROC_FS
+ if (can_init_procentry(board))
+ goto proc_error;
+#endif
+
+#if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+ {
+ #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0))
+ char dev_name[32];
+ #else
+ struct class_device *this_dev;
+ #endif
+ int dev_minor;
+ for(i=0;i<MAX_TOT_MSGOBJS;i++) {
+ if(!objects_p[i]) continue;
+ if(objects_p[i]->hostchip->hostdevice != candev) continue;
+
+ dev_minor=objects_p[i]->minor;
+ #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0))
+ sprintf (dev_name, "can%d", dev_minor);
+ devfs_handles[i]=devfs_register(NULL, dev_name,
+ DEVFS_FL_DEFAULT, major, dev_minor,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+ &can_fops, (void*)objects_p[i]);
+ #else
+ #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14))
+ this_dev=class_device_create(can_class, MKDEV(major, dev_minor), NULL, "can%d", dev_minor);
- #endif /* >= 2.6.15 */
++ #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) /* >= 2.6.15 */
+ this_dev=class_device_create(can_class, NULL, MKDEV(major, dev_minor), NULL, "can%d", dev_minor);
++ #else /* >= 2.6.26 */
++ this_dev=device_create_drvdata(can_class, NULL, MKDEV(major, dev_minor), objects_p[i], "can%d", dev_minor);
++ #endif /* >= 2.6.26 */
+ if(IS_ERR(this_dev)){
+ CANMSG("problem to create device \"can%d\" in the class \"can\"\n", dev_minor);
++ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
+ }else{
+ /*this_dev->class_data=objects_p[i];*/
+ class_set_devdata(this_dev,objects_p[i]);
++ #endif /* <= 2.6.25 */
+ }
+ #ifdef CONFIG_DEVFS_FS
+ devfs_mk_cdev(MKDEV(major, dev_minor), S_IFCHR | S_IRUGO | S_IWUGO, "can%d", dev_minor);
+ #endif
+ #endif
+ }
+ }
+#endif
+ return candev;
+
+#ifdef CONFIG_PROC_FS
+ proc_error: ;
+ CANMSG("Error registering /proc entry.\n");
+ goto memory_error;
+#endif
+
+ interrupt_error: ;
+ goto memory_error;
+
+ reset_error: ;
+ CANMSG("Error resetting device.\n");
+ goto memory_error;
+
+ request_io_error: ;
+ CANMSG("Error to request IO resources for device.\n");
+ goto memory_error;
+
+ memory_error: ;
+
+ #ifdef CAN_WITH_RTL
+ rtldev_error:
+ #endif /*CAN_WITH_RTL*/
+
+// register_error:
+ if ( can_del_mem_list() )
+ CANMSG("Error deallocating memory\n");
+
+ return NULL;
+}
+
+
+
+
+
+
+
+void cleanup_usbdev(struct candevice_t *dev)
+{
+ int i=0;
+ int dev_minor;
+
+ if (!dev)
+ return;
+
+#ifdef CONFIG_PROC_FS
+ if (can_delete_procentry(dev))
+ CANMSG("Error unregistering /proc/can entry.\n");
+#endif
+
+#if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+ for(i=0;i<MAX_TOT_MSGOBJS;i++) {
+ if(!objects_p[i]) continue;
+ if(objects_p[i]->hostchip->hostdevice != dev) continue;
+ #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0))
+ if(devfs_handles[i])
+ devfs_unregister(devfs_handles[i]);
+ #else
+ dev_minor=objects_p[i]->minor;
+ if(dev_minor>=0){
+ #ifdef CONFIG_DEVFS_FS
+ devfs_remove("can%d", dev_minor);
+ #endif
++ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
+ class_device_destroy(can_class, MKDEV(major, dev_minor));
++ #else /* >= 2.6.26 */
++ device_destroy(can_class, MKDEV(major, dev_minor));
++ #endif /* >= 2.6.26 */
+ }
+ #endif
+ }
+#endif
+
+ for(i=0;i<MAX_TOT_CHIPS;i++){
+ if(!chips_p[i]) continue;
+ if(chips_p[i]->hostdevice != dev) continue;
+ chips_p[i]=NULL;
+ }
+
+ hardware_p->candevice[dev->candev_idx]=NULL;
+ hardware_p->nr_boards--;
+ hw[dev->candev_idx]=NULL;
+
+ candevice_done(dev);
+ can_checked_free(dev);
+}
+
+
+
+
void cleanup_module(void)
{
- int res=0,i=0;
+ #if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+ int i=0;
+ #endif
+#if defined(CONFIG_OC_LINCAN_CARD_usbcan)
+ usbcan_exit();
+#endif
+
#ifdef CONFIG_PROC_FS
if (can_delete_procdir())
CANMSG("Error unregistering /proc/can entry.\n");
#ifdef CONFIG_DEVFS_FS
devfs_remove("can%d", dev_minor);
#endif
+ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
class_device_destroy(can_class, MKDEV(major, dev_minor));
+ #else /* >= 2.6.26 */
+ device_destroy(can_class, MKDEV(major, dev_minor));
+ #endif /* >= 2.6.26 */
}
#endif
}
if ( can_del_mem_list() )
CANMSG("Error deallocating memory\n");
- #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
unregister_chrdev(major,DEVICE_NAME);
- #else /*LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)*/
- res=unregister_chrdev(major,DEVICE_NAME);
- if (res<0)
- CANMSG("Error unregistering CAN driver, error: %d\n",res);
- #endif /*LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)*/
}
const struct boardtype_t *brp;
if ( (hw[0] == NULL) | (io[0] == -1) ) {
- CANMSG("You must supply your type of hardware, interrupt numbers and io address.\n");
+ //CANMSG("You must supply your type of hardware, interrupt numbers and io address.\n");
+ CANMSG("Autodetection works only for USB devices, supply your type of hardware for PCI devices \n");
- CANMSG("Example: # insmod can.o hw=pip5 irq=4 io=0x8000\n");
+ CANMSG("Example: # insmod lincan.ko hw=pip5 irq=4 io=0x8000\n");
- return -ENODEV;
+ //return -ENODEV;
}
while ( (hw[i] != NULL) && (i < MAX_HW_CARDS) ) {
#define __NO_VERSION__
#include <linux/module.h>
+#include <linux/mutex.h>
int add_channel_to_procdir(struct candevice_t *candev);
-int remove_channel_from_procdir(void);
+int remove_channels_from_procdir(void);
+int remove_channel_from_procdir(struct candevice_t *candev);
int add_object_to_procdir(int chip_nr);
int remove_object_from_procdir(int chip_nr);
static int can_proc_readlink(struct proc_dir_entry *ent, char *page);
#endif
+ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
+ #define CAN_PROC_ROOT (&proc_root)
+ #else /* >= 2.6.26 */
+ #define CAN_PROC_ROOT (NULL)
+ #endif /* >= 2.6.26 */
+
static int cc=0; /* static counter for each CAN chip */
static struct canproc_t can_proc_base;
static struct canproc_t *base=&can_proc_base;
+DEFINE_MUTEX(proc_mutex); /* synchronize access to canproc_t array */
/* The following functions are needed only for kernel version 2.2. Kernel
* version 2.4 already defines them for us.
{
int board;
struct candevice_t *candev;
+
+ mutex_init(&proc_mutex);
+
base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO |
- S_IXUGO, &proc_root);
+ S_IXUGO, CAN_PROC_ROOT);
if (base->can_proc_entry == NULL)
return -ENODEV;
return 0;
}
+/* can_init_procentry registers entry of a new board in CAN directory tree at
+ * the proc system.
+ */
+int can_init_procentry(int board)
+{
+ struct candevice_t *candev;
+ candev=hardware_p->candevice[board];
+ if(candev)
+ return add_channel_to_procdir(candev);
+ return -ENODEV;
+}
+
/* can_delete_procdir removes the entire CAN tree from the proc system */
int can_delete_procdir(void)
{
- if (remove_channel_from_procdir())
+ if (remove_channels_from_procdir())
return -ENODEV;
/* name: "can" */
- if (can_remove_proc_entry(base->can_proc_entry, &proc_root))
- if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT))
++ if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT))
+ return -ENODEV;
+
+ return 0;
+}
+
+/* can_delete_procentry removes device entries from CAN tree in the proc system */
+int can_delete_procentry(struct candevice_t *candev)
+{
+ if (remove_channel_from_procdir(candev))
return -ENODEV;
return 0;
len += sprintf(buf+len,"type : %s\n",chip->chip_type);
len += sprintf(buf+len,"index : %d\n",chip->chip_idx);
len += sprintf(buf+len,"irq : %d\n",chip->chip_irq);
- len += sprintf(buf+len,"addr : %lu\n",chip->chip_base_addr);
+ len += sprintf(buf+len,"addr : %lu\n",
+ can_ioptr2ulong(chip->chip_base_addr));
len += sprintf(buf+len,"config : %s\n",
- (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
+ (chip->flags & CHIP_CONFIGURED) ? "yes":"no");
len += sprintf(buf+len,"clock : %ld Hz\n",chip->clock);
len += sprintf(buf+len,"baud : %ld\n",chip->baudrate);
len += sprintf(buf+len,"num obj : %d\n",chip->max_objects);
{
int i=0;
- for (i=0; i < candev->nr_all_chips; i++) {
+ mutex_lock(&proc_mutex);
+ for (i=0; i < MAX_TOT_CHIPS; i++){
+ if (!chips_p[i]) continue;
+ if (chips_p[i]->hostdevice != candev) continue;
- base->channel[cc] = (struct channelproc_t *)
+ base->channel[i] = (struct channelproc_t *)
can_checked_malloc(sizeof(struct channelproc_t));
- if (base->channel[cc] == NULL)
+ if (base->channel[i] == NULL){
+ mutex_unlock(&proc_mutex);
return -ENOMEM;
+ }
- sprintf(base->channel[cc]->ch_name, "channel%d",cc);
+ sprintf(base->channel[i]->ch_name, "channel%d",i);
- base->channel[cc]->ch_entry = can_create_proc_entry(
- base->channel[cc]->ch_name,
+ base->channel[i]->ch_entry = can_create_proc_entry(
+ base->channel[i]->ch_name,
S_IFDIR | S_IRUGO |S_IXUGO,
base->can_proc_entry);
- if (base->channel[cc]->ch_entry == NULL)
+ if (base->channel[i]->ch_entry == NULL){
+ mutex_unlock(&proc_mutex);
return -ENODEV;
+ }
- add_object_to_procdir(cc);
+ add_object_to_procdir(i);
create_proc_read_entry("chip_info", /* proc entry name */
0, /* protection mask, 0->default */
- base->channel[cc]->ch_entry, /* parent dir, NULL->/proc */
+ base->channel[i]->ch_entry, /* parent dir, NULL->/proc */
can_chip_procinfo,
- candev->chip[i]);
-
+ chips_p[i]);
cc++;
}
+ mutex_unlock(&proc_mutex);
return 0;
}
-int remove_channel_from_procdir(void)
+int remove_channels_from_procdir(void)
{
+ int i=0;
+
+ mutex_lock(&proc_mutex);
+ for (i=0; i < MAX_TOT_CHIPS; i++){
+ if (!chips_p[i]) continue;
- while (cc != 0) {
cc--;
- if(!base->channel[cc]) continue;
+ if(!base->channel[i]) continue;
- remove_proc_entry("chip_info", base->channel[cc]->ch_entry);
+ remove_proc_entry("chip_info", base->channel[i]->ch_entry);
- if (remove_object_from_procdir(cc))
+ if (remove_object_from_procdir(i)){
+ mutex_unlock(&proc_mutex);
return -ENODEV;
+ }
/* name: base->channel[cc]->ch_name */
- if (can_remove_proc_entry(base->channel[cc]->ch_entry,
- base->can_proc_entry))
+ if (can_remove_proc_entry(base->channel[i]->ch_entry,
+ base->can_proc_entry)){
+ mutex_unlock(&proc_mutex);
return -ENODEV;
+ }
- can_checked_free(base->channel[cc]);
- base->channel[cc] = NULL;
+ can_checked_free(base->channel[i]);
+ base->channel[i] = NULL;
+ }
+ mutex_unlock(&proc_mutex);
+
+ return 0;
+}
+
+int remove_channel_from_procdir(struct candevice_t *candev)
+{
+ int i=0,j=0;
+
+ mutex_lock(&proc_mutex);
+ for (i=0; i < MAX_TOT_CHIPS; i++){
+ if (!chips_p[i]) continue;
+ if (chips_p[i]->hostdevice != candev) continue;
+ if (!base->channel[i]) continue;
+
+ remove_proc_entry("chip_info", base->channel[i]->ch_entry);
+
+ if (remove_object_from_procdir(i)){
+ mutex_unlock(&proc_mutex);
+ return -ENODEV;
+ }
+
+ /* name: base->channel[cc]->ch_name */
+ if (can_remove_proc_entry(base->channel[i]->ch_entry,
+ base->can_proc_entry)){
+ mutex_unlock(&proc_mutex);
+ return -ENODEV;
+ }
+
+ can_checked_free(base->channel[i]);
+ base->channel[i] = NULL;
+
+ cc--;
}
+ mutex_unlock(&proc_mutex);
return 0;
}
int init_hwspecops(struct candevice_t *candev, int *irqnum_p);
int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p);
- int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate);
+ int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate, long clock);
int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int objnr);
+int next_minor=0;
+
/**
* can_base_addr_fixup - relocates board physical memory addresses to the CPU accessible ones
* @candev: pointer to the previously filled device/board, chips and message objects structures
* This function is prepared to simplify board specific xxx_request_io() function
* for memory mapped devices.
*/
- int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base)
+ int can_base_addr_fixup(struct candevice_t *candev, can_ioptr_t new_base)
{
- unsigned long offs;
+ long offs;
int i, j;
offs=new_base-candev->dev_base_addr;
*/
int register_obj_struct(struct msgobj_t *obj, int minorbase)
{
- static int next_minor=0;
int i;
if(minorbase>=0)
return 0;
}
+/**
+ * init_new_hw_struct - initializes driver description structures for new hardware
+ *
+ * The function init_new_hw_struct() is used to initialize the hardware structure.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+int init_new_hw_struct(int devnr)
+{
+ int irq_param_idx=0;
+ int chan_param_idx=0;
+
+ if ( (hw[devnr] != NULL) & (devnr < MAX_HW_CARDS) ) {
+ hardware_p->nr_boards++;
+
+ if (init_device_struct(devnr, &chan_param_idx, &irq_param_idx)) {
+ CANMSG("Error initializing candevice_t structures.\n");
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
/**
* init_device_struct - initializes single CAN device/board
* @card: index into @hardware_p HW description
int chipnr;
long bd;
int irqsig=-1;
+ long clock;
candev=(struct candevice_t *)can_checked_malloc(sizeof(struct candevice_t));
if (candev==NULL)
candev->hwname=hw[card];
candev->io_addr=io[card];
candev->dev_base_addr=io[card];
+ clock=clockfreq[card];
candev->hwspecops=(struct hwspecops_t *)can_checked_malloc(sizeof(struct hwspecops_t));
if (candev->hwspecops==NULL)
bd=baudrate[*chan_param_idx_p+chipnr];
if(!bd) bd=baudrate[0];
- if ((ret=init_chip_struct(candev, chipnr, irqsig, bd*1000)))
+ if ((ret=init_chip_struct(candev, chipnr, irqsig, bd*1000, clock*1000)))
goto error_chip;
}
* @chipnr: index of the chip in the corresponding device/board structure
* @irq: chip IRQ number or (-1) if not appropriate
* @baudrate: baudrate in the units of 1Bd
+ * @clock: optional chip base clock frequency in 1Hz step
*
* Chip structure is allocated and chip specific operations are filled by
* call to board specific init_chip_data() which calls chip specific
*
* Return Value: returns negative number in the case of fail
*/
- int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate)
+ int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate, long clock)
{
struct canchip_t *chip;
int objnr;
chip->hostdevice=candev;
chip->chip_irq=irq;
chip->baudrate=baudrate;
+ chip->clock=clock;
chip->flags=0x0;
if(candev->hwspecops->init_chip_data(candev,chipnr)<0)