]> rtime.felk.cvut.cz Git - lincan.git/commitdiff
Added support for Unicontrols PCAN cards series and baudrate setting.
authorppisa <ppisa>
Mon, 5 Apr 2004 00:42:53 +0000 (00:42 +0000)
committerppisa <ppisa>
Mon, 5 Apr 2004 00:42:53 +0000 (00:42 +0000)
PCAN support has been tested on PCAN104 card for Linux only
and Linux/RT-Linux driver compilation mode. There are many
unimplemented features still.

lincan/include/can.h
lincan/include/main.h
lincan/src/ioctl.c
lincan/src/unican.c

index 0473dcc393ceb3a854f7a6994f4e56c03038a9ba..2521291f7c6a9f9c608f561c1d4d0ee6e1c98a08 100644 (file)
@@ -27,6 +27,23 @@ extern "C" {
 typedef unsigned long bittiming_t;
 typedef unsigned short channel_t;
 
+/**
+ * struct can_baudparams_t - datatype for calling CONF_BAUDPARAMS IOCTL 
+ * @flags: reserved for additional flags for chip configuration, should be written -1 or 0
+ * @baudrate: baud rate in Hz
+ * @sjw: synchronization jump width (0-3) prescaled clock cycles
+ * @sampl_pt: sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio
+ * 
+ * The structure is used to configure new set of parameters into CAN controller chip.
+ * If default value of some field should be preserved, fill field by value -1.
+ */
+struct can_baudparams_t {
+       long flags;
+       long baudrate;
+       long sjw;
+       long sample_pt;
+};
+
 /* CAN ioctl functions */
 #define CAN_DRV_QUERY _IO(CAN_IOC_MAGIC, 0)
 #define CAN_DRV_QRY_BRANCH    0        /* returns driver branch value - "LINC" for LinCAN driver */
@@ -50,6 +67,7 @@ typedef unsigned short channel_t;
 #define STAT _IO(CAN_IOC_MAGIC, 9)
 #define CANQUE_FILTER _IOW(CAN_IOC_MAGIC, 10, struct canfilt_t)
 #define CANQUE_FLUSH  _IO(CAN_IOC_MAGIC, 11)
+#define CONF_BAUDPARAMS  _IOW(CAN_IOC_MAGIC, 11, struct can_baudparams_t)
 
 #ifdef __cplusplus
 } /* extern "C"*/
index 52c7c6cd88e7e27d1190a04a6884f3ba205dbb28..78eace8ee71d4f02bfa2b22472025e72f5867d40 100644 (file)
@@ -105,8 +105,9 @@ struct candevice_t {
  *     %CHIP_SEGMENTED .. access to the chip is segmented (mainly for i82527 chips)
  * @clock: chip base clock frequency in Hz
  * @baudrate: selected chip baudrate in Hz
- * @write_register: write chip register function copy -
+ * @write_register: write chip register function copy
  * @read_register: read chip register function copy
+ * @chip_data: pointer for optional chip specific data extension
  * @sja_cdr_reg: SJA specific register -
  *     holds hardware specific options for the Clock Divider
  *     register. Options defined in the sja1000.h file:
@@ -159,7 +160,9 @@ struct chip_t {
 
        void (*write_register)(unsigned char data,unsigned long address);
        unsigned (*read_register)(unsigned long address);
-
+       
+       void *chip_data;
+       
        unsigned short sja_cdr_reg; /* sja1000 only! */
        unsigned short sja_ocr_reg; /* sja1000 only! */
        unsigned short int_cpu_reg; /* intel 82527 only! */
index 4cf3ca5249535d90552fbc27fbc8d68cf8508137..0c11ebdc198c49c1a5231a85659a6fb277f71609 100644 (file)
@@ -66,21 +66,6 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
                        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);
-                               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 */
                        
@@ -111,6 +96,25 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
                        }
                        break;
                }
+               
+               case CONF_BAUDPARAMS: {
+                       struct can_baudparams_t params;
+                       copy_from_user(&params, (void*)arg, sizeof(struct can_baudparams_t));
+                       if(params.flags == -1) params.flags = 0;
+                       if(params.baudrate == -1) params.baudrate = chip->baudrate;
+                       if(params.sjw == -1) params.sjw = 0;
+                       if(params.sample_pt == -1) params.sample_pt = 75;
+                       i=chip->chipspecops->baud_rate(chip, params.baudrate, chip->clock, params.sjw,
+                                                        params.sample_pt, params.flags);
+                       if(i>=0) chip->baudrate = params.baudrate;
+                       else {
+                               CANMSG("Error setting baud parameters\n");
+                               return -1;
+                       }
+                       break;
+               }
+
+
                default: {
                        CANMSG("Not a valid ioctl command\n");
                        return -EINVAL;
index a64aeb3c4917a2bde70720a7d4f5afbb067b0a82..efc5ac276188294976bfabc658822bb714deb670 100644 (file)
 #include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/unican_cl2.h"
+#include "../include/setup.h"
+
+#ifdef CAN_WITH_RTL
+    
+#endif /*CAN_WITH_RTL*/
+
+
+static void unican_delay(long msdelay)
+{
+    #ifdef CAN_WITH_RTL
+       if(!rtl_rt_system_is_idle()) {
+               rtl_delay(1000000l*msdelay);
+       }else
+    #endif /*CAN_WITH_RTL*/
+       {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout((msdelay*HZ)/1000+1);
+       }
+
+}
 
 
 long unican_bus_latency(struct msgobj_t *obj)
@@ -44,6 +64,57 @@ int unican_disable_configuration(struct chip_t *chip)
  */
 int unican_chip_config(struct chip_t *chip)
 {
+       int ret;
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+
+       unican_delay(10);
+       
+       /* disable all card interrupts */
+       ret = cl2_int_mode(chipext, INT_MODE_ALL*0);
+       if(ret != CL2_OK) {
+               CANMSG("disable interrupts by cl2_iit_mode returned %d\n",ret);
+               return -ENODEV;
+       }
+       unican_delay(1);
+
+        if (chip->baudrate == 0)
+                chip->baudrate=1000000;
+               
+       ret = chip->chipspecops->baud_rate(chip,chip->baudrate,chip->clock,0,75,0);
+       if(ret < 0){
+               CANMSG("can not set baudrate\n");
+               return ret;
+       }
+       
+       unican_delay(2);
+       /* set interrupt inhibit time to 1 ms */
+       ret = cl2_set_iit(chipext, 10);
+       if(ret != CL2_OK) {
+               CANMSG("cl2_set_iit returned %d\n",ret);
+               return -ENODEV;
+       }
+       unican_delay(1);
+
+       /* enable start interrupt inhibit time command */
+       ret = cl2_iit_mode(chipext, 1);
+       if(ret != CL2_OK) {
+               CANMSG("cl2_iit_mode returned %d\n",ret);
+               return -ENODEV;
+       }
+       unican_delay(1);
+       
+       /* enable all card interrupts */
+       ret = cl2_int_mode(chipext, INT_MODE_ALL);
+       if(ret != CL2_OK) {
+               CANMSG("cl2_iit_mode returned %d\n",ret);
+               return -ENODEV;
+       }
+       unican_delay(1);
+
+       /* generate interrupt command */
+       cl2_gen_interrupt(chipext);
+
+
        return 0;
 }
 
@@ -76,6 +147,30 @@ int unican_extended_mask(struct chip_t *chip, unsigned long code, unsigned  long
 int unican_baud_rate(struct chip_t *chip, int rate, int clock, int sjw,
                                                        int sampl_pt, int flags)
 {
+       int ret;
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+       int bt_val;
+
+       switch (rate) {
+               case 5000:   bt_val = CL2_BITRATE_5K; break;
+               case 10000:  bt_val = CL2_BITRATE_10K; break;
+               case 20000:  bt_val = CL2_BITRATE_20K; break;
+               case 50000:  bt_val = CL2_BITRATE_50K; break;
+               case 100000: bt_val = CL2_BITRATE_100K; break;
+               case 125000: bt_val = CL2_BITRATE_125K; break;
+               case 200000: bt_val = CL2_BITRATE_200K; break;
+               case 250000: bt_val = CL2_BITRATE_250K; break;
+               case 500000: bt_val = CL2_BITRATE_500K; break;
+               case 800000: bt_val = CL2_BITRATE_800K; break;
+               case 1000000:bt_val = CL2_BITRATE_1M; break;
+               default: return -EINVAL;
+       }
+       
+       ret=cl2_set_bitrate(chipext,bt_val);
+       if(ret == CL2_COMMAND_BUSY) return -EBUSY;
+       if(ret != CL2_OK) return -EINVAL;
+       unican_delay(2);
+       
        return 0;
 }
 
@@ -84,10 +179,77 @@ int unican_baud_rate(struct chip_t *chip, int rate, int clock, int sjw,
  * @chip: pointer to chip state structure
  * @obj: pinter to CAN message queue information
  *
+ * This is rewritten cl2_receive_data function. The direct use of CL2
+ * function would require one more message data copy to reformat message
+ * data into different structure layout. Other way is to rewrite CL2 sources.
+ * No of these solutions is perfect.
+ *
  * File: src/unican.c
  */
 void unican_read(struct chip_t *chip, struct msgobj_t *obj) {
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+       __u16 *ptr16;
+       __u16 u;
+       unsigned long timestamp;
+       int i;
+
+       do {
+               ptr16 = (__u16*)chipext->rxBufPtr;
+               u = readw(ptr16++);
+               if ( !(u & CL2_MESSAGE_VALID) ) break; /* No more messages in the queue */
+
+               obj->rx_msg.id = ((__u32)(u & 0xFF00 )) << 16;
+               u = readw(ptr16++);
+               obj->rx_msg.id |= ((__u32)( u & 0x00FF )) << 16;
+               obj->rx_msg.id |= (__u32)( u & 0xFF00 );
+               u = readw(ptr16++);
+               obj->rx_msg.id |= (__u32)( u & 0x00FF );
+
+
+               u >>= 8;
+
+               if ( u & CL2_EXT_FRAME ) {      /* 2.0B frame */
+                       obj->rx_msg.id >>= 3;
+                       obj->rx_msg.flags = MSG_EXT;
+               } else {                        /* 2.0A frame */
+                       obj->rx_msg.id >>= 21;
+                       obj->rx_msg.flags = 0;
+               }
+
+               /*if ( !(u & (CL2_REMOTE_FRAME<<8)) ) 
+                       obj->rx_msg.flags |= MSG_RTR;*/
+
+               obj->rx_msg.length = ( (u >> 4) & 0x000F );
+               if(obj->rx_msg.length > CAN_MSG_LENGTH) obj->rx_msg.length = CAN_MSG_LENGTH;
+
+               for ( i = 0; i < obj->rx_msg.length; ) {
+                       u = readw(ptr16++);
+                       obj->rx_msg.data[i++] = (__u8)( u );
+                       obj->rx_msg.data[i++] = (__u8)( u >> 8 );
+               }
+               if ( obj->rx_msg.length & 0x01 ) {      /* odd */
+                       timestamp = ( (readw(ptr16++) & 0x00FF) | (u & 0xFF00) );
+               } else {                                /* even */
+                       u = readw(ptr16++);
+                       timestamp = (u << 8) | (u >> 8);
+               }
+               writew(0x000,(__u16*)chipext->rxBufPtr);
+
+              #ifdef CAN_MSG_VERSION_2
+               obj->rx_msg.timestamp.tv_sec = 0;
+               obj->rx_msg.timestamp.tv_usec = timestamp;
+               #else /* CAN_MSG_VERSION_2 */
+               obj->rx_msg.timestamp = timestamp;
+               #endif /* CAN_MSG_VERSION_2 */
+              
+               /* increment rx-buffer pointer */
+               if ( (chipext->rxBufBase + chipext->rxBufSize*16 ) <= (chipext->rxBufPtr += 16) ) {
+                       chipext->rxBufPtr = chipext->rxBufBase;
+               }
 
+               canque_filter_msg2edges(obj->qends, &obj->rx_msg);
+
+       } while (1);
 }
 
 /**
@@ -163,6 +325,15 @@ int unican_check_tx_stat(struct chip_t *chip)
 int unican_set_btregs(struct chip_t *chip, unsigned short btr0, 
                                                        unsigned short btr1)
 {
+       int ret;
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+       int bt_val;
+
+       bt_val=btr0 | (btr1<<8);
+       ret=cl2_set_bitrate(chipext,bt_val);
+       if(ret == CL2_COMMAND_BUSY) return -EBUSY;
+       if(ret != CL2_OK) return -EINVAL;
+
        return 0;
 }
 
@@ -244,6 +415,7 @@ int unican_clear_objects(struct chip_t *chip)
  */
 int unican_config_irqs(struct chip_t *chip, short irqs)
 {
+
        CANMSG("unican_config_irqs not implemented\n");
        return -ENOSYS;
 }
@@ -261,9 +433,128 @@ int unican_config_irqs(struct chip_t *chip, short irqs)
  */
 void unican_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
 {
+       int cmd;
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+       __u16 *ptr16 = (__u16*)chipext->rxBufPtr;
+       __u16 u;
+       unsigned long timestamp=0;
+       unsigned long cobid;
+       int i;
+       int len;
+
+       #if 0
+       if(obj->tx_slot){
+               /* Do local transmitted message distribution if enabled */
+               if (processlocal){
+                       obj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               }
+               /* Free transmitted slot */
+               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+               obj->tx_slot=NULL;
+       }
+       #endif
+
+       if ( chipext->asyncTxBufSize==0 ) {
+               canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP);
+               return; /* No asynchronous queue configured */
+       }
+
+       do {
+               ptr16 = (__u16*)chipext->asyncTxBufPtr;
+               if(readw(ptr16) & CL2_MESSAGE_VALID)
+                       return;         /* No free space in asynchronous Tx queue */
+
+               cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
+               if(cmd<0)
+                       return;         /* No more messages to send */
+               
+
+               cobid = obj->tx_slot->msg.id;
+               
+               if ( (obj->tx_slot->msg.flags & MSG_EXT) ) {    /* 2.0B frame */
+                       cobid <<= 3;
+               } else {                                        /* 2.0A frame */
+                       cobid <<= 5+16;
+               }
+               ptr16++;
+               u = ((cobid>>16) & 0x00FF ) + (cobid & 0xFF00);
+               writew(u,ptr16++);
+
+               len = obj->tx_slot->msg.length;
+               if(len > CAN_MSG_LENGTH)
+                       len = CAN_MSG_LENGTH;
+               u = (len << 12) | (cobid & 0x00FF);
+               
+               if ( !(obj->tx_slot->msg.flags & MSG_RTR) ) 
+                       u |= CL2_REMOTE_FRAME<<8;
+               if ( obj->tx_slot->msg.flags & MSG_EXT ) 
+                       u |= CL2_EXT_FRAME<<8;
+
+               writew(u,ptr16++);
+
+               for ( i = 0; i < len-1; )       {
+                       u = obj->tx_slot->msg.data[i++];
+                       u |= ((__u16)obj->tx_slot->msg.data[i]<<8); i++;
+                       writew(u,ptr16++);
+               }
+               if(i == len) {
+                       writew(timestamp,ptr16);
+               } else {
+                       u = obj->tx_slot->msg.data[i++];
+                       u |= ((timestamp & 0x00FF)<<8);
+                       writew(u,ptr16++);
+                       writew(timestamp & 0x00FF, ptr16);
+               }
+
+               u = ((cobid>>16) & 0xFF00) | CL2_MESSAGE_VALID;
+               writew(u,(__u16*)chipext->asyncTxBufPtr);
+
+               if ( (chipext->asyncTxBufBase + chipext->asyncTxBufSize*16) <= 
+                                               (chipext->asyncTxBufPtr += 16) ) {
+                       chipext->asyncTxBufPtr = chipext->asyncTxBufBase;
+               }
+
+
+               /* Do local transmitted message distribution if enabled. */
+               /* This code should not be called directly there, because it breaks strict
+                  behavior of queues if O_SYNC is set. */
+               if (processlocal){
+                       obj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               }
+               /* Free transmitted slot */
+               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+               obj->tx_slot=NULL;
+       
+       }while(1);
+       
+       return;
+
+}
+
+void unican_irq_sync_activities(struct chip_t *chip, struct msgobj_t *obj)
+{
+       while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)) {
+
+               if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST)) {
+                       unican_irq_write_handler(chip, obj);
+               }
+
+               /*if(can_msgobj_test_and_clear_fl(obj,FILTCH_REQUEST)) {
+                       unican_irq_update_filter(chip, obj);
+               }*/
 
+               can_msgobj_clear_fl(obj,TX_LOCK);
+               if(can_msgobj_test_fl(obj,TX_REQUEST))
+                       continue;
+               if(can_msgobj_test_fl(obj,FILTCH_REQUEST) && !obj->tx_slot)
+                       continue;
+               break;
+       }
 }
 
+
 #define MAX_RETR 10
 
 /**
@@ -283,55 +574,52 @@ void unican_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
  */
 can_irqreturn_t unican_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-       return CAN_IRQ_HANDLED;
-}
+       struct chip_t *chip=(struct chip_t *)dev_id;
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+       struct msgobj_t *obj=chip->msgobj[0];
+       __u16 status;
+       __u16 error;
+
+       if(!(chip->flags&CHIP_CONFIGURED)) {
+               CANMSG("unican_irq_handler: called for non-configured device\n");
+               return CAN_IRQ_NONE;
+       }
 
+       if (cl2_get_status(chipext, &status) == CL2_NO_REQUEST)
+               return CAN_IRQ_NONE;
 
-void unican_schedule_next(struct msgobj_t *obj)
-{
-       int cmd;
+       cl2_clear_interrupt(chipext);
 
-       can_preempt_disable();
 
-       can_msgobj_set_fl(obj,TX_REQUEST);
-       
-       while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+       if(status & CL2_CARD_ERROR) {
+               cl2_get_error(chipext, &error);
+               CANMSG("unican_irq_handler: card status=0x%04x error=0x%04x \n",status,error);
+       }
+       if(status & CL2_ASYNC_QUEUE_EMPTY) {
 
-               can_msgobj_clear_fl(obj,TX_REQUEST);
-               
-               cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
-               if(cmd>=0) {
-                       mod_timer(&obj->tx_timeout,
-                               jiffies+unican_bus_latency(obj));
-                       DEBUGMSG("unican: scheduled delivery\n");
+       }
+       if(status & CL2_SYNC_QUEUE_EMPTY) {
+               can_msgobj_set_fl(obj,TX_REQUEST);
+
+               /* calls unican_irq_write_handler synchronized with other invocations */
+               unican_irq_sync_activities(chip, obj);
 
-               } else          
-                       can_msgobj_clear_fl(obj,TX_LOCK);
-               
-               if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
-               DEBUGMSG("TX looping in unican_schedule_next\n");
+       }
+       if(status & CL2_DATA_IN_RBUF) {
+               unican_read(chip, obj);
        }
 
-       can_preempt_enable();
+       cl2_gen_interrupt(chipext);
+
+       return CAN_IRQ_HANDLED;
 }
 
 
-void unican_do_tx_timeout(unsigned long data)
+/*void unican_do_tx_timeout(unsigned long data)
 {
        struct msgobj_t *obj=(struct msgobj_t *)data;
        
-       if(obj->tx_slot) {
-               /* Deliver message to edges */
-               canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
-               /* Free transmitted slot */
-               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
-               obj->tx_slot=NULL;
-               DEBUGMSG("unican: delayed delivery\n");
-       }
-       can_msgobj_clear_fl(obj,TX_LOCK);
-
-       unican_schedule_next(obj);
-}
+}*/
 
 /**
  * unican_wakeup_tx: - wakeups TX processing
@@ -343,30 +631,15 @@ void unican_do_tx_timeout(unsigned long data)
  */
 int unican_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
 {
-       /* can_msgobj_set_fl(obj,TX_REQUEST); */
-       
-       struct canque_edge_t *qedge;
-       struct canque_slot_t *slot;
-       int cmd;
+       can_preempt_disable();
 
-       can_msgobj_clear_fl(obj,TX_REQUEST);
+       can_msgobj_set_fl(obj,TX_REQUEST);
 
-    #ifndef CAN_WITH_RTL
-       if(!unican_bus_latency(obj)) {
-    #endif /*CAN_WITH_RTL*/
-               /* Ensure delivery of all ready slots */
-               while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){
-                       if(cmd==0) {
-                               canque_filter_msg2edges(obj->qends, &slot->msg);
-                               DEBUGMSG("unican: direct delivery\n");
-                       }
-                       canque_free_outslot(obj->qends, qedge, slot);
-               }
-    #ifndef CAN_WITH_RTL
-       } else {
-               unican_schedule_next(obj);
-       }
-    #endif /*CAN_WITH_RTL*/
+       /* calls unican_irq_write_handler synchronized with other invocations
+         from kernel and IRQ context */
+       unican_irq_sync_activities(chip, obj);
+
+       can_preempt_enable();
 
        return 0;
 }
@@ -374,6 +647,8 @@ int unican_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
 
 /* * * unican Board Functionality * * */
 
+#define IO_RANGE 0x1000
+
 /**
  * unican_request_io: - reserve io or memory range for can board
  * @candev: pointer to candevice/board which asks for io. Field @io_addr
@@ -384,6 +659,19 @@ int unican_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
  */
 int unican_request_io(struct candevice_t *candev)
 {
+        unsigned long remap_addr;
+       if (!can_request_mem_region(candev->io_addr,IO_RANGE,DEVICE_NAME " - unican")) {
+               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);
+               can_release_mem_region(candev->io_addr,IO_RANGE);
+               return -ENODEV;
+       
+       }
+       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;
 }
 
@@ -396,6 +684,8 @@ int unican_request_io(struct candevice_t *candev)
  */
 int unican_release_io(struct candevice_t *candev)
 {
+       iounmap((void*)candev->dev_base_addr);
+       can_release_mem_region(candev->io_addr,IO_RANGE);
        return 0;
 }
 
@@ -408,6 +698,48 @@ int unican_release_io(struct candevice_t *candev)
  */
 int unican_reset(struct candevice_t *candev)
 {
+       int ret;
+       int i;
+       struct chip_t *chip = candev->chip[0];
+       sCAN_CARD *chipext;
+       
+
+       if(chip->chip_data == NULL) {
+               chip->chip_data = can_checked_malloc(sizeof(sCAN_CARD));
+               if(!chip->chip_data) return -ENOMEM;
+               memset(chip->chip_data,0,sizeof(sCAN_CARD));
+               ret = cl2_init_card(chip->chip_data,(void*)chip->chip_base_addr,chip->chip_irq);
+               if(ret != CL2_OK){
+                       CANMSG("cl2_init_card returned %d\n",ret);
+                       return -ENODEV;
+               }
+       }
+       
+       chipext = (sCAN_CARD *)chip->chip_data;
+               
+       i = 0;
+       /* reset and test whether the card is present */
+       do {
+               cl2_reset_card(chipext);
+               unican_delay(10);
+               i++;
+               ret = cl2_test_card(chipext);
+       } while((ret != CL2_OK)&&(i<10));
+
+       if(ret != CL2_OK) {
+               CANMSG("card check failed %d\n",ret);
+               return -ENODEV;
+       }
+       
+       /* start card firmware */
+       ret = cl2_start_firmware(chipext);
+       if(ret != CL2_OK){
+               CANMSG("cl2_start_firmware returned %d\n",ret);
+               return -ENODEV;
+       }
+       
+        unican_delay(100);
+
        return 0;
 }
 
@@ -448,7 +780,8 @@ int unican_init_chip_data(struct candevice_t *candev, int chipnr)
        chip->int_clk_reg = 0x0;
        chip->int_bus_reg = 0x0;
        chip->max_objects = 1;
-
+       chip->chip_base_addr=candev->io_addr;
+                       
        CANMSG("initializing unican chip operations\n");
        chip->chipspecops->chip_config=unican_chip_config;
        chip->chipspecops->baud_rate=unican_baud_rate;
@@ -468,7 +801,7 @@ int unican_init_chip_data(struct candevice_t *candev, int chipnr)
        chip->chipspecops->set_btregs=unican_set_btregs;
        chip->chipspecops->start_chip=unican_start_chip;
        chip->chipspecops->stop_chip=unican_stop_chip;
-       chip->chipspecops->irq_handler=NULL;
+       chip->chipspecops->irq_handler=unican_irq_handler;
 
        return 0;
 }
@@ -485,8 +818,8 @@ int unican_init_obj_data(struct chip_t *chip, int objnr)
 {
        struct msgobj_t *obj=chip->msgobj[objnr];
        obj->obj_base_addr=chip->chip_base_addr;
-       obj->tx_timeout.function=unican_do_tx_timeout;
-       obj->tx_timeout.data=(unsigned long)obj;
+       /*obj->tx_timeout.function=unican_do_tx_timeout;
+       obj->tx_timeout.data=(unsigned long)obj;*/
        return 0;
 }