Deep rewrite of TSCAN1 and TS7KV boards support.
authorppisa <ppisa>
Wed, 18 Jan 2006 01:20:07 +0000 (01:20 +0000)
committerppisa <ppisa>
Wed, 18 Jan 2006 01:20:07 +0000 (01:20 +0000)
Result requires tests on real hardware and probability
of breakage is very likely. The main aim of the rewrite
is to simplify register access code. The LinCAN driver
does not require more than first 32 byte ports to control
SJA1000 in pelican mode. With this simplification, no windowing
is required for TSCAN1 and only minimal support for access
of SJACDR has been left for TS7KV. The boards lookup checks
for IO range availability and TSCAN1 window can be placed
automatically as well. The "canio" parameter changed to "tscanio".

lincan/include/tscan1.h
lincan/src/boardlist.c
lincan/src/tscan1.c

index ae87e83..97efdb6 100644 (file)
@@ -10,8 +10,8 @@
 //Ids SECTION
 #define TSCAN1_ID0             0xF6
 #define TSCAN1_ID1             0xB9
-#define TS7KV_ID0                      0x41
-#define TS7KV_ID1                      0x20
+#define TS7KV_ID0              0x41
+#define TS7KV_ID1              0x20
 
 //MEMORY SECTION
 #ifdef CONFIG_ARM
 #define TSXXX_BASE_IO  0x01E00000
 #endif
 
-#ifdef CONFIG_X86
-#define TSXXX_BASE_IO  0x00
-#define TS7XXX_IO8_BASE        0x00
-#endif
-
 #define TSCAN1_BASE_IO 0x150
 #define TS7KV_BASE_IO  0xE0
 #define TSXXX_IO_RANGE 0x8
index 276128d..6d2cd8b 100644 (file)
@@ -40,6 +40,7 @@ extern int pcan_dongle_register(struct hwspecops_t *hwspecops);
 extern int eb8245_register(struct hwspecops_t *hwspecops);
 extern int adlink7841_register(struct hwspecops_t *hwspecops);
 extern int tscan1_register(struct hwspecops_t *hwspecops);
+extern int ts7kv_register(struct hwspecops_t *hwspecops);
 extern int ns_dev_register(struct hwspecops_t *hwspecops);
 extern int hms30c7202_register(struct hwspecops_t *hwspecops);
 
@@ -135,7 +136,7 @@ const struct boardtype_t can_boardtypes[]={
     #endif
     #if defined(CONFIG_OC_LINCAN_CARD_tscan1)
        {"tscan1", tscan1_register, 1},
-       {"ts7kv", tscan1_register, 1},
+       {"ts7kv",  ts7kv_register, 1},
     #endif
     #if defined(CONFIG_OC_LINCAN_CARD_ns_dev_can)
        {"ns_dev", ns_dev_register, 1},
index 049fb8d..313f041 100644 (file)
 
 #include "../include/tscan1.h"
 
-short clock[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
+static CAN_DEFINE_SPINLOCK(ts7kv_win_lock);
+
+long clock[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
 MODULE_PARM(clock, "1-" __MODULE_STRING(MAX_HW_CARDS)"i");
 MODULE_PARM_DESC(clock,"clock frequency for each board in step of 1kHz");
 
-long canio[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
-MODULE_PARM(canio, "1-" __MODULE_STRING(MAX_HW_CARDS)"i");
-MODULE_PARM_DESC(canio,"CAN controller IO address for each board");
+long tscanio[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
+MODULE_PARM(tscanio, "1-" __MODULE_STRING(MAX_HW_CARDS)"i");
+MODULE_PARM_DESC(tscanio,"TSCAN CAN controller IO address for each board");
 
-long remap_io_addr[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
-long remap_can_addr[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1};
+#if defined(TS7XXX_IO8_BASE)&&defined(TSXXX_BASE_IO)
+int tsxxx_base=TS7XXX_IO8_BASE+TSXXX_BASE_IO;
+#elif defined(TS7XXX_IO8_BASE)
+int tsxxx_base=TS7XXX_IO8_BASE;
+#else /*TS7XXX_IO8_BASE*/
+unsigned long tsxxx_base=0;
+#endif /*TS7XXX_IO8_BASE*/
+MODULE_PARM(tsxxx_base, "1i");
+MODULE_PARM_DESC(tsxxx_base,"The base of the ISA/8-bit IO space for TSxxx CAN peripherals in the system");
 
-unsigned short isused = 0x0;
+unsigned short ts7kv_isused = 0x0;
 
 /**
  * tscan1_request_io: - reserve io or memory range for can board
@@ -51,22 +60,94 @@ unsigned short isused = 0x0;
  */
 int tscan1_request_io(struct candevice_t *candev)
 {
-   unsigned long remap_can_io_addr;
+       unsigned long can_io_addr;
+       unsigned long remap_can_io_addr = 0;
+       unsigned char mode;
+       int i, j;
+
+
+       if (!can_request_io_region(candev->io_addr, TSXXX_IO_RANGE, "tscan1-base")) {
+               CANMSG("Unable to request base IO port: 0x%lx\n", candev->io_addr);
+               return -ENODEV;
+       } else {
+               DEBUGMSG("Registered base IO port: 0x%lx - 0x%lx\n",
+                       candev->io_addr, candev->io_addr+TSXXX_IO_RANGE-1);
+       }
+
+       can_io_addr = tscanio[candev->candev_idx];
+
+       if(can_io_addr && (can_io_addr != (unsigned long)-1)) {
+               remap_can_io_addr = tsxxx_base + can_io_addr;
+
+               if (!can_request_io_region(remap_can_io_addr, TSXXX_CAN_RANGE, "tscan1-can")) {
+                       CANMSG("Unable to request CAN IO port: 0x%lx\n", remap_can_io_addr);
+                       can_release_io_region(candev->io_addr, TSXXX_IO_RANGE);
+                       return -ENODEV;
+               } else {
+                       DEBUGMSG("Registered CAN IO port: 0x%lx - 0x%lx\n",
+                       remap_can_io_addr, remap_can_io_addr+TSXXX_CAN_RANGE-1);
+               }
+       } else {
+               for(i = 0; 1; i++) {
+
+                       if(i>=8) {
+                               CANMSG("Unable find range for CAN IO port\n");
+                               can_release_io_region(candev->io_addr, TSXXX_IO_RANGE);
+                               return -ENODEV;
+                       }
+
+                       can_io_addr = 0x100 + i * TSXXX_CAN_RANGE;
+                       for (j = 0; j < MAX_HW_CARDS; j++) {
+                               if(tscanio[j] == can_io_addr) {
+                                       j = -1;
+                                       break;
+                               }
+                       }
+                       if(j<0)
+                               continue;
+
+                       remap_can_io_addr = tsxxx_base + can_io_addr;
+
+                       if (can_request_io_region(remap_can_io_addr, TSXXX_CAN_RANGE, "tscan1-can"))
+                               break;
+               }
 
-       remap_io_addr[candev->candev_idx] = tscan1_getmappedaddr(candev->io_addr);
-       remap_can_io_addr = tscan1_getmappedaddr(canio[candev->candev_idx]);
+               tscanio[candev->candev_idx] = can_io_addr;
+
+               DEBUGMSG("Found free range and registered CAN IO port: 0x%lx - 0x%lx\n",
+                       remap_can_io_addr, remap_can_io_addr+TSXXX_CAN_RANGE-1);
+       }
 
-       candev->dev_base_addr = remap_can_io_addr;
        candev->chip[0]->chip_base_addr = remap_can_io_addr;
+       candev->chip[0]->msgobj[0]->obj_base_addr = remap_can_io_addr;
+
+       switch(can_io_addr) {
+               case 0x100:     mode=0x60; break;
+               case 0x120:     mode=0x61; break;
+               case 0x180:     mode=0x62; break;
+               case 0x1A0:     mode=0x63; break;
+               case 0x200:     mode=0x64; break;
+               case 0x240:     mode=0x65; break;
+               case 0x280:     mode=0x66; break;
+               case 0x320:     mode=0x67; break;
+               default:        mode=0x60; break;
+       }
+
+       outb(0x00, candev->io_addr+TSCAN1_WIN_REG);
+       outb(mode, candev->io_addr+TSCAN1_MOD_REG);
 
-       remap_can_addr[candev->candev_idx] = remap_can_io_addr;
+       return 0;
+}
 
-       DEBUGMSG("IO-mem for %s: 0x%lx - 0x%lx mapped to 0x%lx\n",
-               candev->hwname, candev->io_addr,
-               candev->io_addr + TSXXX_IO_RANGE - 1, remap_io_addr[candev->candev_idx]);
-       DEBUGMSG("CAN-IO-mem for %s: 0x%lx - 0x%lx mapped to 0x%lx\n",
-               candev->hwname, canio[candev->candev_idx],
-               canio[candev->candev_idx] + TSXXX_CAN_RANGE - 1, candev->dev_base_addr);
+int ts7kv_request_io(struct candevice_t *candev)
+{
+       if (!can_request_io_region(candev->io_addr, TSXXX_CAN_RANGE, "ts7kv-can")) {
+               CANMSG("Unable to request CAN IO port: 0x%lx\n", candev->io_addr);
+               return -ENODEV;
+       } else {
+               DEBUGMSG("Registered CAN IO port: 0x%lx - 0x%lx\n",
+                       candev->io_addr, candev->io_addr+TSXXX_CAN_RANGE-1);
+       }
 
        return 0;
 }
@@ -85,6 +166,23 @@ int tscan1_request_io(struct candevice_t *candev)
  */
 int tscan1_release_io(struct candevice_t *candev)
 {
+       unsigned long remap_can_io_addr;
+
+       if(candev->chip[0]){
+               remap_can_io_addr = candev->chip[0]->chip_base_addr;
+               if(remap_can_io_addr != (unsigned long)-1)
+                       can_release_io_region(remap_can_io_addr, TSXXX_CAN_RANGE);
+       }
+
+       outb(0x20, candev->io_addr+TSCAN1_MOD_REG);
+
+       can_release_io_region(candev->io_addr, TSXXX_IO_RANGE);
+       return 0;
+}
+
+int ts7kv_release_io(struct candevice_t *candev)
+{
+       can_release_io_region(candev->io_addr, TSXXX_CAN_RANGE);
        return 0;
 }
 
@@ -107,19 +205,19 @@ int tscan1_reset(struct candevice_t *candev)
 
        for(chipnr=0;chipnr<candev->nr_sja1000_chips;chipnr++) {
                chip=candev->chip[chipnr];
-               tscan1_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
+               can_write_reg(chip, sjaMOD_RM, SJAMOD);
                udelay(1000);
-               tscan1_write_register(0x00, chip->chip_base_addr + SJAIER);
+               can_write_reg(chip, 0x00, SJAIER);
                udelay(1000);
                i=20;
-               while (tscan1_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){
+               while (can_read_reg(chip, SJAMOD)&sjaMOD_RM){
                        if(!i--) return -ENODEV;
                        udelay(1000);
-                       tscan1_write_register(0, chip->chip_base_addr+SJAMOD);
+                       can_write_reg(chip, 0, SJAMOD);
                }
                udelay(1000);
-               tscan1_write_register(sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
-               tscan1_write_register(0x00, chip->chip_base_addr + SJAIER);
+               can_write_reg(chip, sjaCDR_PELICAN, SJACDR);
+               can_write_reg(chip, 0x00, SJAIER);
        }
 
        return 0;
@@ -129,6 +227,33 @@ int tscan1_reset(struct candevice_t *candev)
 #define NR_82527 0
 #define NR_SJA1000 1
 
+int tscan1_check_presence(unsigned long remap_io_addr, int *pjmp)
+{
+       int result = -ENODEV;
+
+       if (!can_request_io_region(remap_io_addr, TSXXX_IO_RANGE, "tscan1-probe"))
+               return -ENODEV;
+
+       do {
+               if (inb(remap_io_addr+TSXXX_ID0_REG)!=TSCAN1_ID0 ||
+                       inb(remap_io_addr+TSXXX_ID1_REG)!=TSCAN1_ID1)
+                       break;
+
+               outb(0x00, remap_io_addr+TSCAN1_WIN_REG);
+               outb(0x20, remap_io_addr+TSCAN1_MOD_REG);
+
+               if(pjmp)
+                       *pjmp = inb(remap_io_addr+TSCAN1_JMP_REG);
+
+               result = 0;
+       } while (0);
+
+       can_release_io_region(remap_io_addr, TSXXX_IO_RANGE);
+
+       return result;
+}
+
+
 /**
  * tscan1_init_hw_data - Initialize hardware cards
  * @candev: Pointer to candevice/board structure
@@ -146,139 +271,158 @@ int tscan1_reset(struct candevice_t *candev)
 
 int tscan1_init_hw_data(struct candevice_t *candev)
 {
-       short i, jmp;
-       unsigned long tsxxx_base_io = 0, io_mapped =0;
-       unsigned short mode;
+       int i, j, jmp;
+       unsigned long io_addr;
+       unsigned long remap_io_addr;
 
-       candev->io_addr = -1;
-       if (!strcmp(hw[candev->candev_idx],"tscan1"))
-       {
+       io_addr = candev->io_addr;
+
+       if(io_addr && (io_addr != (unsigned long)-1)) {
+               remap_io_addr = io_addr = tsxxx_base;
+
+               if(tscan1_check_presence(remap_io_addr, &jmp)){
+                       CANMSG("No TSCAN1 card found at address 0xlx\n");
+                       return -ENODEV;
+               }
+       } else {
                DEBUGMSG("Scanning bus for TS-CAN1 boards...\n");
-               for (i=0;i<4;i++)
+
+               for (i=0; 1;i++)
                {
-                       tsxxx_base_io = TSCAN1_BASE_IO + i*TSXXX_IO_RANGE;
-                       io_mapped = tscan1_getmappedaddr(TSXXX_BASE_IO + tsxxx_base_io);
-                       if (inb(io_mapped+TSXXX_ID0_REG)==TSCAN1_ID0 &&
-                               inb(io_mapped+TSXXX_ID1_REG)==TSCAN1_ID1)
-                       {
-                               if (isused & 1<<i)
-                                       continue;
-                               //if (check_mem_region(tsxxx_base_io, TSXXX_IO_RANGE)) continue;
-                               if (io[candev->candev_idx]!=-1 && io[candev->candev_idx]!=tsxxx_base_io)
-                                       continue;
-                               io[candev->candev_idx] = tsxxx_base_io;
-                               candev->io_addr = tsxxx_base_io;
-                               candev->hwname="tscan1";
-                               DEBUGMSG("TS-CAN1 board was found at 0x%lx for driver %d/%s\n", tsxxx_base_io,
-                                       candev->candev_idx, candev->hwname);
-                               isused |= 1<<i;
-                               break;
+                       if(i >= 4) {
+                               CANMSG("No TS-CAN1 boards found for slot %d\n", candev->candev_idx);
+                               return -ENODEV;
                        }
-               }
-       }
-       if (!strcmp(hw[candev->candev_idx],"ts7kv"))
-       {
-               DEBUGMSG("Scanning bus for TS-7KV boards...\n");
-               for (i=4;i<8;i++)
-               {
-                       tsxxx_base_io = TS7KV_BASE_IO + (i-4)*TSXXX_IO_RANGE;
-                       io_mapped = tscan1_getmappedaddr(TSXXX_BASE_IO + tsxxx_base_io);
-                       if (inb(io_mapped+TSXXX_ID0_REG)==TS7KV_ID0 &&
-                               inb(io_mapped+TSXXX_ID1_REG)==TS7KV_ID1)
-                       {
-                               if (isused & 1<<i)
-                                       continue;
-                               //if (check_mem_region(tsxxx_base_io, TSXXX_IO_RANGE)) continue;
-                               if (io[candev->candev_idx]!=-1 && io[candev->candev_idx]!=tsxxx_base_io)
-                                       continue;
-                               io[candev->candev_idx] = tsxxx_base_io;
-                               candev->io_addr = tsxxx_base_io;
-                               candev->hwname="ts7kv";
-                               DEBUGMSG("TS-7KV board was found at 0x%lx for driver %d/%s\n",
-                                       tsxxx_base_io,  candev->candev_idx, candev->hwname);
-                               isused |= 1<<i;
-                               break;
+
+                       io_addr = TSCAN1_BASE_IO + i*TSXXX_IO_RANGE;
+                       remap_io_addr = io_addr = tsxxx_base;
+
+                       for (j = 0; j < MAX_HW_CARDS; j++) {
+                               if(io[j] == io_addr){
+                                       j = -1;
+                                       break;
+                               }
                        }
+                       if(j<0)
+                               continue;
+
+                       if(!tscan1_check_presence(remap_io_addr, &jmp))
+                               break;
+
                }
-       }
+               DEBUGMSG("TS-CAN1 board was found at 0x%lx for driver slot %d\n",
+                                       io_addr, candev->candev_idx);
 
-       if (candev->io_addr==-1) {
-               DEBUGMSG("No board was found for driver %d/%s.\n", candev->candev_idx, candev->hwname);
-               return -1;
+               io[candev->candev_idx] = io_addr;
        }
 
-       if (!strcmp(candev->hwname,"tscan1"))
-       {
-               if (clock[candev->candev_idx] == -1)
-                       clock[candev->candev_idx] = 16000;
-               if (irq[candev->candev_idx] == -1)
-               {
-                       jmp = inb(io_mapped+TSCAN1_JMP_REG);
-                       irq[candev->candev_idx]=0;
-                       if (jmp&0x10 && jmp&0x20) irq[candev->candev_idx]=TSXXX_IRQ5;
-                       else if (jmp&0x10) irq[candev->candev_idx]=TSXXX_IRQ6;
-                       else if (jmp&0x20) irq[candev->candev_idx]=TSXXX_IRQ7;
+       candev->io_addr = remap_io_addr;
+       /* unused reset address is used to store jumper setting */
+       candev->res_addr = jmp;
+
+       candev->nr_82527_chips=NR_82527;
+       candev->nr_sja1000_chips=NR_SJA1000;
+       candev->nr_all_chips=NR_82527+NR_SJA1000;
+       candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
+
+       DEBUGMSG("Memory region at 0x%lx assigned to sja1000 of driver %d/%s\n",
+               candev->io_addr, candev->candev_idx, candev->hwname);
+
+       return 0;
+}
+
+
+int ts7kv_check_presence(unsigned long remap_io_addr, int *pjmp)
+{
+       int result = -ENODEV;
+
+       if (!can_request_io_region(remap_io_addr, TSXXX_IO_RANGE, "ts7kv-probe"))
+               return -ENODEV;
+
+       do {
+               if (inb(remap_io_addr+TSXXX_ID0_REG)!=TS7KV_ID0 ||
+                       inb(remap_io_addr+TSXXX_ID1_REG)!=TS7KV_ID1)
+                       break;
+
+               if(pjmp)
+                       *pjmp = inb(remap_io_addr+TS7KV_JMP_REG);
+
+               result = 0;
+       } while (0);
+
+       can_release_io_region(remap_io_addr, TSXXX_IO_RANGE);
+
+       return result;
+}
+
+int ts7kv_init_hw_data(struct candevice_t *candev)
+{
+       int i, j, jmp;
+       unsigned long io_addr;
+       unsigned long remap_io_addr;
+       unsigned long can_io_addr;
+
+       io_addr = candev->io_addr;
+
+       if(io_addr && (io_addr != (unsigned long)-1)) {
+               remap_io_addr = io_addr = tsxxx_base;
+
+               if(ts7kv_check_presence(remap_io_addr, &jmp)){
+                       CANMSG("No TS7KV card found at address 0xlx\n");
+                       return -ENODEV;
                }
-               if (canio[candev->candev_idx] == -1)
+       } else {
+               DEBUGMSG("Scanning bus for TS7KV boards...\n");
+
+               for (i=0; 1;i++)
                {
-                       switch(candev->io_addr) {
-                               case (TSCAN1_BASE_IO+0*TSXXX_IO_RANGE):
-                                       canio[candev->candev_idx] = 0x180; break;
-                               case (TSCAN1_BASE_IO+1*TSXXX_IO_RANGE):
-                                       canio[candev->candev_idx] = 0x1A0; break;
-                               case (TSCAN1_BASE_IO+2*TSXXX_IO_RANGE):
-                                       canio[candev->candev_idx] = 0x240; break;
-                               case (TSCAN1_BASE_IO+3*TSXXX_IO_RANGE):
-                                       canio[candev->candev_idx] = 0x280; break;
+                       if(i >= 4) {
+                               CANMSG("No TS7KV boards found for slot %d\n", candev->candev_idx);
+                               return -ENODEV;
                        }
-               }
 
-               //Reseting...
-               switch(canio[candev->candev_idx]) {
-                       case 0x100:     mode=0x60; break;
-                       case 0x120:     mode=0x61; break;
-                       case 0x180:     mode=0x62; break;
-                       case 0x1A0:     mode=0x63; break;
-                       case 0x200:     mode=0x64; break;
-                       case 0x240:     mode=0x65; break;
-                       case 0x280:     mode=0x66; break;
-                       case 0x320:     mode=0x67; break;
-                       default:        mode=0x60; break;
-               }
-               outb(0x00, io_mapped+TSCAN1_WIN_REG);
-               outb(mode, io_mapped+TSCAN1_MOD_REG);
-       }
+                       io_addr = TS7KV_BASE_IO + i*TSXXX_IO_RANGE;
+                       remap_io_addr = io_addr = tsxxx_base;
+
+                       for (j = 0; j < MAX_HW_CARDS; j++) {
+                               if(io[j] == io_addr){
+                                       j = -1;
+                                       break;
+                               }
+                       }
+                       if(j<0)
+                               continue;
+
+                       if(!ts7kv_check_presence(remap_io_addr, &jmp))
+                               break;
 
-       else if (!strcmp(candev->hwname,"ts7kv"))
-       {
-               if (clock[candev->candev_idx] == -1)
-                       clock[candev->candev_idx] = 24000;
-               if (irq[candev->candev_idx] == -1)
-               {
-                       jmp = inb(io_mapped+TS7KV_JMP_REG);
-                       irq[candev->candev_idx]=0;
-                       if (jmp&0x10) irq[candev->candev_idx]=TSXXX_IRQ6;
-                       if (jmp&0x20) irq[candev->candev_idx]=TSXXX_IRQ7;
                }
-               canio[candev->candev_idx] = ((candev->io_addr>>3)&0x03)*0x20;
+               DEBUGMSG("TS7KV board was found at 0x%lx for driver slot %d\n",
+                                       io_addr, candev->candev_idx);
+
+               io[candev->candev_idx] = io_addr;
        }
 
-       if (baudrate[candev->candev_idx] == -1)
-               baudrate[candev->candev_idx] = 1000;
+       can_io_addr = ((io_addr>>3)&0x03)*0x20;
+       tscanio[candev->candev_idx] = can_io_addr;
 
-       io[candev->candev_idx] += TSXXX_BASE_IO;
-       candev->io_addr = io[candev->candev_idx];
-       canio[candev->candev_idx] += TSXXX_BASE_IO;
+       /* dev_base_addr address is used to store remapped PLD base address */
+       candev->dev_base_addr = remap_io_addr;
 
-       DEBUGMSG("Memory region at 0x%lx assigned to sja1000 of driver %d/%s\n",
-               canio[candev->candev_idx], candev->candev_idx, candev->hwname);
+       /* dev_base_addr address is used to store remapped slave window address */
+       candev->io_addr = can_io_addr+tsxxx_base;
+
+       /* unused reset address is used to store jumper setting */
+       candev->res_addr = jmp;
 
-       candev->res_addr=RESET_ADDR;
        candev->nr_82527_chips=NR_82527;
        candev->nr_sja1000_chips=NR_SJA1000;
        candev->nr_all_chips=NR_82527+NR_SJA1000;
        candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
 
+       DEBUGMSG("Memory region at 0x%lx assigned to sja1000 of driver %d/%s\n",
+               candev->io_addr, candev->candev_idx, candev->hwname);
+
        return 0;
 }
 
@@ -313,13 +457,80 @@ int tscan1_init_hw_data(struct candevice_t *candev)
  */
 int tscan1_init_chip_data(struct candevice_t *candev, int chipnr)
 {
+       unsigned long clk;
+       int jmp;
+       int irq = -1;
+
+       clk = clock[candev->candev_idx];
+       if(!clk || (clk == -1))
+               clk = 16000 * 1000;
+       else
+               clk *= 1000;
+
+       /* unused reset address is used to store jumper setting */
+       jmp = candev->res_addr;
+
+       if (jmp&0x10 && jmp&0x20) irq=TSXXX_IRQ5;
+       else if (jmp&0x10) irq=TSXXX_IRQ6;
+       else if (jmp&0x20) irq=TSXXX_IRQ7;
+
+       if(irq<0) {
+               CANMSG("Jumpers select no IRQ for TSCAN1 at 0x%lx of driver %d/%s\n",
+                       candev->io_addr, candev->candev_idx, candev->hwname);
+               return -ENODEV;
+       }
+       candev->chip[chipnr]->chip_irq = irq;
+
        sja1000p_fill_chipspecops(candev->chip[chipnr]);
 
-       candev->chip[chipnr]->clock = clock[candev->candev_idx]*1000;
+       candev->chip[chipnr]->clock = clk;
        candev->chip[chipnr]->int_clk_reg = 0x0;
        candev->chip[chipnr]->int_bus_reg = 0x0;
        candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
-       candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL |        sjaOCR_TX0_LH;
+       candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
+       /* 
+        * The address is assigned during tscan1_request_io()
+        * according to found free ranges or tscanio option
+        */
+       candev->chip[chipnr]->chip_base_addr = (unsigned long)-1;
+
+       return 0;
+}
+
+int ts7kv_init_chip_data(struct candevice_t *candev, int chipnr)
+{
+       unsigned long clk;
+       int jmp;
+       int irq = -1;
+
+       clk = clock[candev->candev_idx];
+       if(!clk || (clk == -1))
+               clk = 24000 * 1000;
+       else
+               clk *= 1000;
+
+       /* unused reset address is used to store jumper setting */
+       jmp = candev->res_addr;
+
+       if (jmp&0x10 && jmp&0x20) irq=TSXXX_IRQ5;
+       else if (jmp&0x10) irq=TSXXX_IRQ6;
+       else if (jmp&0x20) irq=TSXXX_IRQ7;
+
+       if(irq<0) {
+               CANMSG("Jumpers select no IRQ for TS7KV CAN at 0x%lx of driver %d/%s\n",
+                       candev->io_addr, candev->candev_idx, candev->hwname);
+               return -ENODEV;
+       }
+
+       candev->chip[chipnr]->chip_irq = irq;
+
+       sja1000p_fill_chipspecops(candev->chip[chipnr]);
+
+       candev->chip[chipnr]->clock = clk;
+       candev->chip[chipnr]->int_clk_reg = 0x0;
+       candev->chip[chipnr]->int_bus_reg = 0x0;
+       candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
+       candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
        candev->chip[chipnr]->chip_base_addr = candev->io_addr;
 
        return 0;
@@ -378,15 +589,32 @@ int tscan1_program_irq(struct candevice_t *candev)
  */
 void tscan1_write_register(unsigned data, unsigned long address)
 {
-       signed short nwinbak=-1;
-       unsigned long winaddr;
-       address = tscan1_setpage_getaddr(address, &nwinbak, &winaddr);
-       DEBUGMSG("outb(0x%x,0x%lx)\n", data, address);
        outb(data, address);
-       if (nwinbak!=-1) {
-               DEBUGMSG("restore win outb(0x%x,0x%lx) \n", nwinbak, winaddr);
-               outb(nwinbak, winaddr);
+}
+
+void ts7kv_write_register(unsigned data, unsigned long address)
+{
+       unsigned long base = address & ~0x1f;
+       unsigned char nwin = 0x10;
+       unsigned char savewin;
+       
+       can_spin_irqflags_t flags;
+
+       if((address&0x1f) > 0x1d) {
+               nwin++;
+               address -= 0x10;
+       }
+
+       can_spin_lock_irqsave(&ts7kv_win_lock,flags);
+       savewin = inb(base+TS7KV_WIN_REG);
+       if(nwin == savewin) {
+               outb(data, address);
+       }else{
+               outb(nwin, base+TS7KV_WIN_REG);
+               outb(data, address);
+               outb(savewin, base+TS7KV_WIN_REG);
        }
+       can_spin_unlock_irqrestore(&ts7kv_win_lock,flags);
 }
 
 /**
@@ -401,20 +629,37 @@ void tscan1_write_register(unsigned data, unsigned long address)
  */
 unsigned tscan1_read_register(unsigned long address)
 {
-       unsigned short data;
-       signed short nwinbak=-1;
-       unsigned long winaddr;
-       address = tscan1_setpage_getaddr(address, &nwinbak, &winaddr);
-       data = inb(address);
-       DEBUGMSG("inb(0x%lx) = 0x%x\n", address, data);
-       if (nwinbak!=-1) {
-               DEBUGMSG("restore win outb(0x%x,0x%lx) \n", nwinbak, winaddr);
-               outb(nwinbak, winaddr);
+       return inb(address);
+}
+
+unsigned ts7kv_read_register(unsigned long address)
+{
+       unsigned long base = address & ~0x1f;
+       unsigned char nwin = 0x10;
+       unsigned char savewin;
+       unsigned val;
+       
+       can_spin_irqflags_t flags;
+
+       if((address&0x1f) > 0x1d) {
+               nwin++;
+               address -= 0x10;
        }
-       return data;
+
+       can_spin_lock_irqsave(&ts7kv_win_lock,flags);
+       savewin = inb(base+TS7KV_WIN_REG);
+       if(nwin == savewin) {
+               val = inb(address);
+       }else{
+               outb(nwin, base+TS7KV_WIN_REG);
+               val = inb(address);
+               outb(savewin, base+TS7KV_WIN_REG);
+       }
+       can_spin_unlock_irqrestore(&ts7kv_win_lock,flags);
+
+       return val;
 }
 
-/* !!! Don't change this function !!! */
 int tscan1_register(struct hwspecops_t *hwspecops)
 {
        hwspecops->request_io = tscan1_request_io;
@@ -429,64 +674,16 @@ int tscan1_register(struct hwspecops_t *hwspecops)
        return 0;
 }
 
-unsigned long tscan1_getmappedaddr(unsigned long address)
+extern int ts7kv_register(struct hwspecops_t *hwspecops)
 {
-       return (unsigned long)TS7XXX_IO8_BASE + address;
-}
-
-unsigned short tscan1_getcandevidx(unsigned long address)
-{
-       ///?FIXME Consider addresses beyond 32bytes range
-       unsigned short i;
-       for (i=0;i<MAX_HW_CARDS;i++)
-               if ( remap_can_addr[i]!=-1 &&
-                       (address >= remap_can_addr[i]) &&
-                       (address < remap_can_addr[i]+TSXXX_CAN_RANGE) )
-                       return i;
-       return -1;
-}
-
-unsigned long tscan1_setpage_getaddr(unsigned long address,
-       signed short *nwinbak, unsigned long *winaddr)
-{
-       unsigned long offset_addr;
-       unsigned short candev_idx;
-       char nwin;
-
-       if ((candev_idx = tscan1_getcandevidx(address)) < 0)
-               return address;
-
-       offset_addr = address;
-       nwin = 0x0;
-
-       if (!strcmp(hardware_p->candevice[candev_idx]->hwname,"tscan1")) {
-               while ((offset_addr - remap_can_addr[candev_idx]) > 0x1f) {
-                       offset_addr -= 0x20;
-                       nwin += 0x1;
-               }
-               DEBUGMSG("%s win outb(0x%x,0x%lx) of address 0x%lx\n",
-                       hardware_p->candevice[candev_idx]->hwname,
-               nwin, remap_io_addr[candev_idx]|TSCAN1_WIN_REG, address);
-               outb(nwin, remap_io_addr[candev_idx]|TSCAN1_WIN_REG);
-       }
-
-       else if (!strcmp(hardware_p->candevice[candev_idx]->hwname,"ts7kv")) {
-               while ((offset_addr - remap_can_addr[candev_idx]) > 0x1d) {
-                       offset_addr -= 0x10;
-                       nwin += 0x1;
-               }
-
-               *winaddr = (unsigned long)remap_can_addr[candev_idx]|TS7KV_WIN_REG;
-               *nwinbak = inb(*winaddr);
-               DEBUGMSG("inb(0x%lx)=0x%x bak\n", *winaddr, *nwinbak);
-               if (*nwinbak != (nwin|0x10)) {
-                       DEBUGMSG("%s win outb(0x%x,0x%lx) of address 0x%lx\n",
-                               hardware_p->candevice[candev_idx]->hwname,
-                               nwin|0x10, *winaddr, address);
-                       outb(nwin|0x10, *winaddr);
-                       }
-               if ( 0x10 == ((*nwinbak)&0xF0) )        *nwinbak = -1;
-       }
-
-       return offset_addr;
+       hwspecops->request_io = ts7kv_request_io;
+       hwspecops->release_io = ts7kv_release_io;
+       hwspecops->reset = tscan1_reset;
+       hwspecops->init_hw_data = ts7kv_init_hw_data;
+       hwspecops->init_chip_data = ts7kv_init_chip_data;
+       hwspecops->init_obj_data = tscan1_init_obj_data;
+       hwspecops->write_register = ts7kv_write_register;
+       hwspecops->read_register = ts7kv_read_register;
+       hwspecops->program_irq = tscan1_program_irq;
+       return 0;
 }