Rearranged setup to better support cards with irq count differing from chip count.
authorppisa <ppisa>
Sun, 18 Jan 2004 22:40:32 +0000 (22:40 +0000)
committerppisa <ppisa>
Sun, 18 Jan 2004 22:40:32 +0000 (22:40 +0000)
Checked compilation with 2.2.19 kernel. Functionality with 2.2.x not checked.

lincan/include/can_sysdep.h
lincan/include/constants.h
lincan/include/main.h
lincan/src/can_devrtl.c
lincan/src/kv_pcican.c
lincan/src/main.c
lincan/src/setup.c
lincan/src/virtual.c

index b719236..5b33971 100644 (file)
 #include <asm/uaccess.h>
 
 /*optional features*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
 #define CAN_ENABLE_KERN_FASYNC
 #define CAN_ENABLE_PCI_SUPPORT
+#endif
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
 #include <linux/malloc.h>
   #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
 #endif /* 2.2.19 */
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) && !defined(DECLARE_TASKLET)
+  #define tasklet_struct tq_struct
+  #define DECLARE_TASKLET(_name, _func, _data) \
+                struct tq_struct _name = { sync: 0, routine: _func, data: (void*)_data }
+
+  /* void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); */
+  #define tasklet_init(_tasklet, _func, _data) \
+    do{ \
+       /* (_tasklet)->next=NULL; */ \
+       /* Above not needed for 2.2.x and buggy for 2.4.x */ \
+       (_tasklet)->sync=0; \
+       (_tasklet)->routine=_func; \
+       (_tasklet)->data=(void*)_data; \
+    }while(0)
+
+  /* void tasklet_schedule(struct tasklet_struct *t) */
+  #define tasklet_schedule(_tasklet) \
+    do{ \
+       queue_task(_tasklet,&tq_immediate); \
+       mark_bh(IMMEDIATE_BH); \
+    }while(0)
+
+  /* void tasklet_kill(struct tasklet_struct *t); */
+  #define tasklet_kill(_tasklet) \
+                synchronize_irq()
+
+#endif /* 2.4.0 */
+
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
 
index df2909f..87863e8 100644 (file)
@@ -65,6 +65,7 @@
 #define CHIP_CONFIGURED  (1<<0)
 #define CHIP_SEGMENTED   (1<<1)
 #define CHIP_IRQ_SETUP   (1<<2)
+#define CHIP_IRQ_PCI     (1<<3)
 
 /* These flags can be used for the candevices_t structure flags data entry */
 #define CANDEV_PROGRAMMABLE_IRQ (1<<0)
index f73e967..b4a0b32 100644 (file)
@@ -404,3 +404,7 @@ struct boardtype_t {
 };
 
 const struct boardtype_t* boardtype_find(const char *str);
+
+#ifdef CAN_WITH_RTL
+extern int can_rtl_priority;
+#endif /*CAN_WITH_RTL*/
index 182eb42..812ea84 100644 (file)
@@ -22,6 +22,7 @@ unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r )
        struct candevice_t *candev;
        int board_nr;
        int chip_nr;
+       int irq2linux=0;
        pthread_t thread=NULL;
 
        DEBUGMSG("can_rtl_isr invoked for irq %d\n",irq_num);
@@ -37,14 +38,16 @@ unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r )
 
                        set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
                        set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
-                       
+                       if(chip->flags & CHIP_IRQ_PCI)
+                               irq2linux=1;
                        if(!chip->worker_thread) continue;
                        thread=chip->worker_thread;
                        pthread_kill(thread,RTL_SIGNAL_WAKEUP);
                }
        }
 
-       /*rtl_global_pend_irq(irq_num);*/
+       if(irq2linux)
+               rtl_global_pend_irq(irq_num);
 
        /*if(thread) rtl_reschedule_thread(thread);*/
 
@@ -134,9 +137,21 @@ void * can_chip_worker_thread(void *arg)
 int can_chip_setup_irq(struct chip_t *chip)
 {
        int ret;
+        struct sched_param sched_param;
+        pthread_attr_t attrib;
+       pthread_attr_t *attrib_p=NULL;
        
        if(chip==NULL)
                return -1;
+       
+       if(can_rtl_priority>=0){
+               pthread_attr_init(&attrib);
+               sched_param.sched_priority = can_rtl_priority;
+               pthread_attr_setschedparam(&attrib, &sched_param);
+               /* pthread_attr_setschedpolicy(&attrib, SCHED_FIFO); */
+               attrib_p=&attrib;
+       }
+       
        if(chip->chipspecops->irq_handler){
                if (rtl_request_irq(chip->chip_irq,can_rtl_isr))
                        return -1;
@@ -145,7 +160,7 @@ int can_chip_setup_irq(struct chip_t *chip)
                        chip->flags |= CHIP_IRQ_SETUP;
                }
        }
-        ret=pthread_create(&chip->worker_thread, NULL, can_chip_worker_thread, chip);
+        ret=pthread_create(&chip->worker_thread, attrib_p, can_chip_worker_thread, chip);
        if(ret<0) chip->worker_thread=NULL;
        
        return ret;
index eace091..c49a3de 100644 (file)
@@ -241,6 +241,7 @@ int kv_pcican_init_chip_data(struct candevice_t *candev, int chipnr)
        candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF;
        candev->chip[chipnr]->sja_ocr_reg = KV_PCICAN_OCR_DEFAULT_STD;
        candev->chip[chipnr]->clock = 16000000;
+       candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
 
        return 0;
 }      
index 817d678..f4edb79 100644 (file)
@@ -68,29 +68,48 @@ can_spinlock_t canuser_manipulation_lock;
 /* Module parameters, some must be supplied at module loading time */
 int major=CAN_MAJOR;
 MODULE_PARM(major,"1i");
+MODULE_PARM_DESC(major,"can be used to change default major [" __MODULE_STRING(CAN_MAJOR) "]");
 int minor[MAX_TOT_CHIPS]={-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};
 /*MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS)"i");*/
 MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i");
+MODULE_PARM_DESC(minor,"can be used to change default starting minor for each channel");
 int extended=0;
 MODULE_PARM(extended,"1i");
+MODULE_PARM_DESC(extended,"enables automatic switching to extended format if ID>2047,"
+                       " selects extended frames reception for i82527");
 int pelican=0;
 MODULE_PARM(pelican,"1i");
+MODULE_PARM_DESC(pelican,"unused parameter, PeliCAN used by default for sja1000p chips");
 int baudrate[MAX_TOT_CHIPS];
 MODULE_PARM(baudrate, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i");
+MODULE_PARM_DESC(baudrate,"baudrate for each channel in step of 1kHz");
 char *hw[MAX_HW_CARDS]={NULL,};
 MODULE_PARM(hw, "1-" __MODULE_STRING(MAX_HW_CARDS)"s");
+MODULE_PARM_DESC(hw,"list of boards types to initialize - virtual,pip5,...");
 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};
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_IRQ)"i");
+MODULE_PARM_DESC(irq,"list of iterrupt signal numbers, most ISA has one per chip, no value for PCI or virtual");
 unsigned long io[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HW_CARDS)"i");
+MODULE_PARM_DESC(io,"IO address for each board, use 0 for PCI or virtual");
 int stdmask=0;
 MODULE_PARM(stdmask, "1i");
+MODULE_PARM_DESC(stdmask,"default standard mask for i82527 chips");
 int extmask=0;
 MODULE_PARM(extmask, "1i");
+MODULE_PARM_DESC(extmask,"default extended mask for i82527 chips");
 int mo15mask=0;
 MODULE_PARM(mo15mask, "1i");
+MODULE_PARM_DESC(mo15mask,"mask for communication object 15 of i82527 chips");
 int processlocal=0;
 MODULE_PARM(processlocal, "1i");
+MODULE_PARM_DESC(processlocal,"select postprocessing/loopback of transmitted messages - "
+               "0 .. disabled, 1 .. can be enabled by FIFO filter, 2 .. enabled by default");
+#ifdef CAN_WITH_RTL
+int can_rtl_priority=-1;
+MODULE_PARM(can_rtl_priority, "1i");
+MODULE_PARM_DESC(can_rtl_priority,"select priority of chip worker thread");
+#endif /*CAN_WITH_RTL*/
 
 /* Other module attributes */
 #ifdef MODULE_SUPPORTED_DEVICE
index acc7cac..72ef1a9 100644 (file)
@@ -18,10 +18,10 @@ extern int sja1000_register(struct chipspecops_t *chipspecops);
 extern int sja1000p_register(struct chipspecops_t *chipspecops);
 extern int i82527_register(struct chipspecops_t *chipspecops);
 
-int init_device_struct(int card);
-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_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_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int objnr);
 int init_chipspecops(struct candevice_t *candev, int chipnr);
 
 void *can_checked_malloc(size_t size)
@@ -153,16 +153,64 @@ int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base)
        return 0;
 }
 
+
+int register_obj_struct(struct msgobj_t *obj, int minorbase)
+{
+       static int next_minor=0;
+       int i;
+       
+       if(minorbase>=0)
+               next_minor=minorbase;
+       if(next_minor>=MAX_TOT_MSGOBJS)
+               next_minor=0;
+       i=next_minor;
+       do{
+               if(objects_p[i]==NULL){
+                       objects_p[i]=obj;
+                       obj->minor=i;
+                       next_minor=i+1;
+                       return 0;
+               }
+               if(++i >= MAX_TOT_MSGOBJS) i=0;
+       }while(i!=next_minor);
+       obj->minor=-1;
+       return -1;
+}
+
+
+int register_chip_struct(struct chip_t *chip, int minorbase)
+{
+       static int next_chip_slot=0;
+       int i;
+       
+       if(next_chip_slot>=MAX_TOT_CHIPS)
+               next_chip_slot=0;
+       i=next_chip_slot;
+       do{
+               if(chips_p[i]==NULL){
+                       chips_p[i]=chip;
+
+                       next_chip_slot=i+1;
+                       return 0;
+               }
+               if(++i >= MAX_TOT_CHIPS) i=0;
+       }while(i!=next_chip_slot);
+       return -1;
+}
+
+
 /* The function init_hw_struct is used to initialize the hardware structure. */
 int init_hw_struct(void)
 {
        int i=0;
+       int irq_param_idx=0;
+       int chan_param_idx=0;
 
        hardware_p->nr_boards=0;
        while ( (hw[i] != NULL) & (i < MAX_HW_CARDS) ) {
                hardware_p->nr_boards++;
 
-               if (init_device_struct(i)) {
+               if (init_device_struct(i, &chan_param_idx, &irq_param_idx)) {
                        CANMSG("Error initializing candevice_t structures.\n");
                        return -ENODEV;
                }
@@ -175,10 +223,14 @@ int init_hw_struct(void)
 /* The function init_device_struct is used to initialize a single device 
  * structure.
  */
-int init_device_struct(int card)
+int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p)
 {
        struct candevice_t *candev;
        int ret;
+       int irqnum;
+       int chipnr;
+       long bd;
+       int irqsig=-1;
        
        candev=(struct candevice_t *)can_checked_malloc(sizeof(struct candevice_t));
        if (candev==NULL)
@@ -201,14 +253,42 @@ int init_device_struct(int card)
 
        memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
 
-       if (init_hwspecops(candev))
+       if (init_hwspecops(candev, &irqnum))
                goto error_nodev;
 
        if (candev->hwspecops->init_hw_data(candev))
                goto error_nodev;
 
-       if ((ret=init_chip_struct(candev)))
-               goto error_chip;
+       /* Alocate and initialize the chip structures */
+       for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
+
+               if(chipnr<irqnum)
+                       irqsig=irq[*irq_param_idx_p+chipnr];
+               
+               bd=baudrate[*chan_param_idx_p+chipnr];
+               if(!bd) bd=baudrate[0];
+       
+               if ((ret=init_chip_struct(candev, chipnr, irqsig, bd*1000)))
+                       goto error_chip;
+       }
+       
+
+
+       for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
+               int m=minor[*chan_param_idx_p+chipnr];
+               struct chip_t *chip=candev->chip[chipnr];
+               int objnr;
+
+               register_chip_struct(chip, m);
+               
+               for (objnr=0; objnr<chip->max_objects; objnr++) {
+                       register_obj_struct(chip->msgobj[objnr], m);
+                       if(m>=0) m++;
+               }
+       }
+
+       *irq_param_idx_p += irqnum;
+       *chan_param_idx_p += candev->nr_all_chips;
 
        return 0;
 
@@ -231,96 +311,84 @@ int init_device_struct(int card)
 /* The function init_chip_struct is used to initialize all chip_t structures
  * on one hardware board.
  */
-int init_chip_struct(struct candevice_t *candev)
+int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate)
 {
        struct chip_t *chip;
-       static int irq_count=0;
-       int i=0;
+       int objnr;
+       int ret;
 
-       /* Alocate and initialize the chip structures */
-       for (i=0; i < candev->nr_all_chips; i++) {
-               candev->chip[i]=(struct chip_t *)can_checked_malloc(sizeof(struct chip_t));
-               if ((chip=candev->chip[i])==NULL)
-                       return -ENOMEM;
+       candev->chip[chipnr]=(struct chip_t *)can_checked_malloc(sizeof(struct chip_t));
+       if ((chip=candev->chip[chipnr])==NULL)
+               return -ENOMEM;
 
-               memset(chip, 0, sizeof(struct chip_t));
-               
-               chip->write_register=candev->hwspecops->write_register;
-               chip->read_register=candev->hwspecops->read_register;
+        memset(chip, 0, sizeof(struct chip_t));
 
-               chip->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t));
-               if (chip->chipspecops==NULL)
-                       return -ENOMEM;
-               
-                chips_p[irq_count]=chip;
-               chip->chip_idx=i;
-               chip->hostdevice=candev;
-               chip->chip_irq=irq[irq_count];
-               chip->baudrate=baudrate[irq_count]*1000;
-               if(!chip->baudrate)
-                       chip->baudrate=baudrate[0]*1000;
-               chip->flags=0x0;
-
-               candev->hwspecops->init_chip_data(candev,i);
-
-               if (init_chipspecops(candev,i))
-                       return -ENODEV;
-               
-               init_obj_struct(candev, chip, minor[irq_count]);
+       chip->write_register=candev->hwspecops->write_register;
+       chip->read_register=candev->hwspecops->read_register;
 
-               irq_count++;
-       } 
+       chip->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t));
+       if (chip->chipspecops==NULL)
+               return -ENOMEM;
+
+       chip->chip_idx=chipnr;
+       chip->hostdevice=candev;
+       chip->chip_irq=irq;
+       chip->baudrate=baudrate;
+       chip->flags=0x0;
+
+       candev->hwspecops->init_chip_data(candev,chipnr);
+
+       if (init_chipspecops(candev,chipnr))
+               return -ENODEV;
+
+       for (objnr=0; objnr<chip->max_objects; objnr++) {
+               ret=init_obj_struct(candev, chip, objnr);
+               if(ret<0) return ret;
+       }
 
        return 0;
 }
 
-int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase)
+
+int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int objnr)
 {
        struct canque_ends_t *qends;
-       static int obj_count=0;
-       int i,max_objects;
        struct msgobj_t *obj;
+       int ret;
 
-       max_objects=hostchip->max_objects;
-       for (i=0; i<max_objects; i++) {
-               obj=(struct msgobj_t *)can_checked_malloc(sizeof(struct msgobj_t));
-               hostchip->msgobj[i]=obj;
-               if (obj == NULL) 
-                       return -ENOMEM;
-                       
-               memset(obj, 0, sizeof(struct msgobj_t));
+       obj=(struct msgobj_t *)can_checked_malloc(sizeof(struct msgobj_t));
+       hostchip->msgobj[objnr]=obj;
+       if (obj == NULL) 
+               return -ENOMEM;
 
-               atomic_set(&obj->obj_used,0);
-               INIT_LIST_HEAD(&obj->obj_users);
-               init_timer(&obj->tx_timeout);
-               
-               qends = (struct canque_ends_t *)can_checked_malloc(sizeof(struct canque_ends_t));
-               if(qends == NULL) 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->obj_flags = 0x0;
-
-               canqueue_ends_init_chip(qends, hostchip, obj);
-               
-               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;
+        memset(obj, 0, sizeof(struct msgobj_t));
+       obj->minor=-1;
 
-               candev->hwspecops->init_obj_data(hostchip,i);
+       atomic_set(&obj->obj_used,0);
+       INIT_LIST_HEAD(&obj->obj_users);
+       init_timer(&obj->tx_timeout);
 
-               obj_count++;
-       }
+       qends = (struct canque_ends_t *)can_checked_malloc(sizeof(struct canque_ends_t));
+       if(qends == NULL) return -ENOMEM;
+       memset(qends, 0, sizeof(struct canque_ends_t));
+       obj->hostchip=hostchip;
+       obj->object=objnr+1;
+       obj->qends=qends;
+       obj->tx_qedge=NULL;
+       obj->tx_slot=NULL;
+       obj->obj_flags = 0x0;
+
+       ret=canqueue_ends_init_chip(qends, hostchip, obj);
+       if(ret<0) return ret;
+
+       ret=candev->hwspecops->init_obj_data(hostchip,objnr);
+       if(ret<0) return ret;
+       
        return 0;
 }
 
 
-int init_hwspecops(struct candevice_t *candev)
+int init_hwspecops(struct candevice_t *candev, int *irqnum_p)
 {
        const struct boardtype_t *brp;
        
@@ -331,11 +399,14 @@ int init_hwspecops(struct candevice_t *candev)
                return -EINVAL;
        }
        
+       if(irqnum_p)
+               *irqnum_p=brp->irqnum;
        brp->board_register(candev->hwspecops);
 
        return 0;
 }
 
+
 int init_chipspecops(struct candevice_t *candev, int chipnr)
 {
        if (!strcmp(candev->chip[chipnr]->chip_type,"i82527")) {
index 80ce0fb..d8818ab 100644 (file)
@@ -302,7 +302,7 @@ void virtual_schedule_next(struct msgobj_t *obj)
                if(cmd>=0) {
                        mod_timer(&obj->tx_timeout,
                                jiffies+virtual_bus_latency(obj));
-                       CANMSG("virtual: scheduled delivery\n");
+                       DEBUGMSG("virtual: scheduled delivery\n");
 
                } else          
                        can_msgobj_clear_fl(obj,TX_LOCK);
@@ -325,7 +325,7 @@ void virtual_do_tx_timeout(unsigned long data)
                /* Free transmitted slot */
                canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
                obj->tx_slot=NULL;
-               CANMSG("virtual: delayed delivery\n");
+               DEBUGMSG("virtual: delayed delivery\n");
        }
        can_msgobj_clear_fl(obj,TX_LOCK);
 
@@ -355,7 +355,7 @@ int virtual_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
                while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
                        if(cmd==0) {
                                canque_filter_msg2edges(obj->qends, &slot->msg);
-                               CANMSG("virtual: direct delivery\n");
+                               DEBUGMSG("virtual: direct delivery\n");
                        }
                        canque_free_outslot(obj->qends, qedge, slot);
                }