From 92b76dca553a98a228f368f8ff6eedc25e33b870 Mon Sep 17 00:00:00 2001 From: ppisa Date: Mon, 5 Apr 2004 00:42:53 +0000 Subject: [PATCH] Added support for Unicontrols PCAN cards series and baudrate setting. 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 | 18 ++ lincan/include/main.h | 7 +- lincan/src/ioctl.c | 34 ++-- lincan/src/unican.c | 455 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 436 insertions(+), 78 deletions(-) diff --git a/lincan/include/can.h b/lincan/include/can.h index 0473dcc..2521291 100644 --- a/lincan/include/can.h +++ b/lincan/include/can.h @@ -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"*/ diff --git a/lincan/include/main.h b/lincan/include/main.h index 52c7c6c..78eace8 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -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! */ diff --git a/lincan/src/ioctl.c b/lincan/src/ioctl.c index 4cf3ca5..0c11ebd 100644 --- a/lincan/src/ioctl.c +++ b/lincan/src/ioctl.c @@ -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(¶ms, (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; diff --git a/lincan/src/unican.c b/lincan/src/unican.c index a64aeb3..efc5ac2 100644 --- a/lincan/src/unican.c +++ b/lincan/src/unican.c @@ -10,6 +10,26 @@ #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; } -- 2.39.2