From bab3604638338226c816d432a768c23726cd918e Mon Sep 17 00:00:00 2001 From: ppisa Date: Thu, 17 Nov 2005 15:36:37 +0000 Subject: [PATCH] Ronald Gomes from Technologic Systemscontributed support for TS-CAN1 and TS-7KV cards. This is initial version and would require more cleanups and optimizations. --- lincan/CREDITS | 4 + lincan/include/tscan1.h | 72 ++++++ lincan/src/Makefile.omk | 2 +- lincan/src/Makefile.std | 2 +- lincan/src/boardlist.c | 5 + lincan/src/tscan1.c | 492 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 575 insertions(+), 2 deletions(-) create mode 100644 lincan/include/tscan1.h create mode 100644 lincan/src/tscan1.c diff --git a/lincan/CREDITS b/lincan/CREDITS index f8bcb33..e16a913 100644 --- a/lincan/CREDITS +++ b/lincan/CREDITS @@ -37,6 +37,10 @@ http://www.unicontrols.cz/ contributed support for series of IXXAT iPC-I 165 (PCI) boards +Ronald Gomes, Technologic Systems +http://www.embeddedarm.com/ + contributed support for TS-CAN1 and TS-7KV + ======================================== List of companies and subjects who donated hardware to LinCAN project diff --git a/lincan/include/tscan1.h b/lincan/include/tscan1.h new file mode 100644 index 0000000..ae87e83 --- /dev/null +++ b/lincan/include/tscan1.h @@ -0,0 +1,72 @@ +/* template.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +//Ids SECTION +#define TSCAN1_ID0 0xF6 +#define TSCAN1_ID1 0xB9 +#define TS7KV_ID0 0x41 +#define TS7KV_ID1 0x20 + +//MEMORY SECTION +#ifdef CONFIG_ARM +#include +#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 +#define TSXXX_CAN_RANGE 0x20 + +#define TSXXX_ID0_REG 0x0 +#define TSXXX_ID1_REG 0x1 +#define TSXXX_PLD_REG 0x2 + +#define TSCAN1_WIN_REG 0x4 +#define TSCAN1_MOD_REG 0x5 +#define TSCAN1_JMP_REG 0x6 + +#define TS7KV_CTR1_REG 0x4 +#define TS7KV_CTR2_REG 0x5 +#define TS7KV_FPGA_REG 0x6 +#define TS7KV_JMP_REG 0x7 +#define TS7KV_WIN_REG 0x1E + +//IRQs +#ifdef CONFIG_ARM +#define TSXXX_IRQ5 5 +#define TSXXX_IRQ6 33 +#define TSXXX_IRQ7 40 +#endif + +#ifdef CONFIG_X86 +#define TSXXX_IRQ5 5 +#define TSXXX_IRQ6 6 +#define TSXXX_IRQ7 7 +#endif + + +int tscan1_request_io(struct candevice_t *candev); +int tscan1_release_io(struct candevice_t *candev); +int tscan1_reset(struct candevice_t *candev); +int tscan1_init_hw_data(struct candevice_t *candev); +int tscan1_init_chip_data(struct candevice_t *candev, int chipnr); +int tscan1_init_obj_data(struct canchip_t *chip, int objnr); +void tscan1_write_register(unsigned data, unsigned long address); +unsigned tscan1_read_register(unsigned long address); +int tscan1_program_irq(struct candevice_t *candev); + +unsigned long tscan1_getmappedaddr(unsigned long address); +unsigned short tscan1_getcandevidx(unsigned long address); +unsigned long tscan1_setpage_getaddr(unsigned long address, signed short *nwinbak, unsigned long *winaddr); diff --git a/lincan/src/Makefile.omk b/lincan/src/Makefile.omk index 0a355c9..ebc45ca 100644 --- a/lincan/src/Makefile.omk +++ b/lincan/src/Makefile.omk @@ -2,7 +2,7 @@ lincan_cards_NAMES = pip pccan smartcan nsi cc_can104 ems_cpcpci \ pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan pikronisa eb8245 \ kv_pcican msmcan oscar adlink7841 unican virtual template -lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 +lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 default_CONFIG = CONFIG_OC_LINCAN=y CONFIG_OC_LINCANRTL=n CONFIG_OC_LINCANVME=n default_CONFIG += CONFIG_OC_LINCAN_PORTIO_ONLY=n CONFIG_OC_LINCAN_MEMIO_ONLY=n diff --git a/lincan/src/Makefile.std b/lincan/src/Makefile.std index 9444337..b71ca95 100644 --- a/lincan/src/Makefile.std +++ b/lincan/src/Makefile.std @@ -64,7 +64,7 @@ SUPPORTED_CARDS = pip pccan smartcan nsi cc_can104 \ pc_i03 pcm3680 aim104 m437 pcccan ssv \ bfadcan pikronisa kv_pcican msmcan virtual template \ unican unican_cl2 ems_cpcpci adlink7841 oscar -# hms30c7202_can c_can c_can_irq +# hms30c7202_can c_can c_can_irq tscan1 # pcan_dongle #SUPPORTED_CARDS = pcm3680 bfadcan pikronisa template diff --git a/lincan/src/boardlist.c b/lincan/src/boardlist.c index 56ab55d..276128d 100644 --- a/lincan/src/boardlist.c +++ b/lincan/src/boardlist.c @@ -39,6 +39,7 @@ extern int ipci165_register(struct hwspecops_t *hwspecops); 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 ns_dev_register(struct hwspecops_t *hwspecops); extern int hms30c7202_register(struct hwspecops_t *hwspecops); @@ -132,6 +133,10 @@ const struct boardtype_t can_boardtypes[]={ #if defined(CONFIG_OC_LINCAN_CARD_adlink7841) {"adlink7841", adlink7841_register, 0}, #endif + #if defined(CONFIG_OC_LINCAN_CARD_tscan1) + {"tscan1", tscan1_register, 1}, + {"ts7kv", tscan1_register, 1}, + #endif #if defined(CONFIG_OC_LINCAN_CARD_ns_dev_can) {"ns_dev", ns_dev_register, 1}, #endif diff --git a/lincan/src/tscan1.c b/lincan/src/tscan1.c new file mode 100644 index 0000000..049fb8d --- /dev/null +++ b/lincan/src/tscan1.c @@ -0,0 +1,492 @@ +/* tscan1.c + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + * + * The support for TS-CAN1 and TS-7KV provided by Ronald Gomes + * from Technologic Systems + */ + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/pcm3680.h" +#include "../include/sja1000p.h" + +#include +#include "../include/modparms.h" +#include "../include/devcommon.h" + +#include "../include/tscan1.h" + +short 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 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}; + +unsigned short isused = 0x0; + +/** + * tscan1_request_io: - reserve io or memory range for can board + * @candev: pointer to candevice/board which asks for io. Field @io_addr + * of @candev is used in most cases to define start of the range + * + * The function tscan1_request_io() is used to reserve the io-memory. If your + * hardware uses a dedicated memory range as hardware control registers you + * will have to add the code to reserve this memory as well. + * %IO_RANGE is the io-memory range that gets reserved, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/tscan1.c + */ +int tscan1_request_io(struct candevice_t *candev) +{ + unsigned long remap_can_io_addr; + + remap_io_addr[candev->candev_idx] = tscan1_getmappedaddr(candev->io_addr); + remap_can_io_addr = tscan1_getmappedaddr(canio[candev->candev_idx]); + + candev->dev_base_addr = remap_can_io_addr; + candev->chip[0]->chip_base_addr = remap_can_io_addr; + + remap_can_addr[candev->candev_idx] = remap_can_io_addr; + + 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); + + return 0; +} + +/** + * tscan1_release_io - free reserved io memory range + * @candev: pointer to candevice/board which releases io + * + * The function tscan1_release_io() is used to free reserved io-memory. + * In case you have reserved more io memory, don't forget to free it here. + * IO_RANGE is the io-memory range that gets released, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function always returns zero + * File: src/tscan1.c + */ +int tscan1_release_io(struct candevice_t *candev) +{ + return 0; +} + +/** + * tscan1_reset - hardware reset routine + * @candev: Pointer to candevice/board structure + * + * The function tscan1_reset() is used to give a hardware reset. This is + * rather hardware specific so I haven't included example code. Don't forget to + * check the reset status of the chip before returning. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/tscan1.c + */ +int tscan1_reset(struct candevice_t *candev) +{ + unsigned short i=0, chipnr; + struct canchip_t *chip; + + DEBUGMSG("Resetting %s hardware ...\n", candev->hwname); + + for(chipnr=0;chipnrnr_sja1000_chips;chipnr++) { + chip=candev->chip[chipnr]; + tscan1_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD); + udelay(1000); + tscan1_write_register(0x00, chip->chip_base_addr + SJAIER); + udelay(1000); + i=20; + while (tscan1_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){ + if(!i--) return -ENODEV; + udelay(1000); + tscan1_write_register(0, chip->chip_base_addr+SJAMOD); + } + udelay(1000); + tscan1_write_register(sjaCDR_PELICAN, chip->chip_base_addr+SJACDR); + tscan1_write_register(0x00, chip->chip_base_addr + SJAIER); + } + + return 0; +} + +#define RESET_ADDR 0x100 +#define NR_82527 0 +#define NR_SJA1000 1 + +/** + * tscan1_init_hw_data - Initialize hardware cards + * @candev: Pointer to candevice/board structure + * + * The function tscan1_init_hw_data() is used to initialize the hardware + * structure containing information about the installed CAN-board. + * %RESET_ADDR represents the io-address of the hardware reset register. + * %NR_82527 represents the number of intel 82527 chips on the board. + * %NR_SJA1000 represents the number of philips sja1000 chips on the board. + * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that + * the hardware uses programmable interrupts. + * Return Value: The function always returns zero + * File: src/tscan1.c + */ + +int tscan1_init_hw_data(struct candevice_t *candev) +{ + short i, jmp; + unsigned long tsxxx_base_io = 0, io_mapped =0; + unsigned short mode; + + candev->io_addr = -1; + if (!strcmp(hw[candev->candev_idx],"tscan1")) + { + DEBUGMSG("Scanning bus for TS-CAN1 boards...\n"); + for (i=0;i<4;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<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<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<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<io_addr==-1) { + DEBUGMSG("No board was found for driver %d/%s.\n", candev->candev_idx, candev->hwname); + return -1; + } + + 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; + } + if (canio[candev->candev_idx] == -1) + { + 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; + } + } + + //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); + } + + 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; + } + + if (baudrate[candev->candev_idx] == -1) + baudrate[candev->candev_idx] = 1000; + + io[candev->candev_idx] += TSXXX_BASE_IO; + candev->io_addr = io[candev->candev_idx]; + canio[candev->candev_idx] += TSXXX_BASE_IO; + + DEBUGMSG("Memory region at 0x%lx assigned to sja1000 of driver %d/%s\n", + canio[candev->candev_idx], candev->candev_idx, candev->hwname); + + 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; + + return 0; +} + +/** + * tscan1_init_chip_data - Initialize chips + * @candev: Pointer to candevice/board structure + * @chipnr: Number of the CAN chip on the hardware card + * + * The function tscan1_init_chip_data() is used to initialize the hardware + * structure containing information about the CAN chips. + * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or + * "sja1000". + * The @chip_base_addr entry represents the start of the 'official' memory map + * of the installed chip. It's likely that this is the same as the @io_addr + * argument supplied at module loading time. + * The @clock entry holds the chip clock value in Hz. + * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider + * register. Options defined in the %sja1000.h file: + * %sjaCDR_CLKOUT_MASK, %sjaCDR_CLK_OFF, %sjaCDR_RXINPEN, %sjaCDR_CBP, %sjaCDR_PELICAN + * The entry @sja_ocr_reg holds hardware specific options for the Output Control + * register. Options defined in the %sja1000.h file: + * %sjaOCR_MODE_BIPHASE, %sjaOCR_MODE_TEST, %sjaOCR_MODE_NORMAL, %sjaOCR_MODE_CLOCK, + * %sjaOCR_TX0_LH, %sjaOCR_TX1_ZZ. + * The entry @int_clk_reg holds hardware specific options for the Clock Out + * register. Options defined in the %i82527.h file: + * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1. + * The entry @int_bus_reg holds hardware specific options for the Bus + * Configuration register. Options defined in the %i82527.h file: + * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY. + * Return Value: The function always returns zero + * File: src/tscan1.c + */ +int tscan1_init_chip_data(struct candevice_t *candev, int chipnr) +{ + sja1000p_fill_chipspecops(candev->chip[chipnr]); + + candev->chip[chipnr]->clock = clock[candev->candev_idx]*1000; + 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; +} + +/** + * tscan1_init_obj_data - Initialize message buffers + * @chip: Pointer to chip specific structure + * @objnr: Number of the message buffer + * + * The function tscan1_init_obj_data() is used to initialize the hardware + * structure containing information about the different message objects on the + * CAN chip. In case of the sja1000 there's only one message object but on the + * i82527 chip there are 15. + * The code below is for a i82527 chip and initializes the object base addresses + * The entry @obj_base_addr represents the first memory address of the message + * object. In case of the sja1000 @obj_base_addr is taken the same as the chips + * base address. + * Unless the hardware uses a segmented memory map, flags can be set zero. + * Return Value: The function always returns zero + * File: src/tscan1.c + */ +int tscan1_init_obj_data(struct canchip_t *chip, int objnr) +{ + chip->msgobj[objnr]->obj_base_addr = chip->chip_base_addr; + return 0; +} + +/** + * tscan1_program_irq - program interrupts + * @candev: Pointer to candevice/board structure + * + * The function tscan1_program_irq() is used for hardware that uses + * programmable interrupts. If your hardware doesn't use programmable interrupts + * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and + * leave this function unedited. Again this function is hardware specific so + * there's no example code. + * Return value: The function returns zero on success or %-ENODEV on failure + * File: src/tscan1.c + */ +int tscan1_program_irq(struct candevice_t *candev) +{ + return 0; +} + +/** + * tscan1_write_register - Low level write register routine + * @data: data to be written + * @address: memory address to write to + * + * The function tscan1_write_register() is used to write to hardware registers + * on the CAN chip. You should only have to edit this function if your hardware + * uses some specific write process. + * Return Value: The function does not return a value + * File: src/tscan1.c + */ +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); + } +} + +/** + * tscan1_read_register - Low level read register routine + * @address: memory address to read from + * + * The function tscan1_read_register() is used to read from hardware registers + * on the CAN chip. You should only have to edit this function if your hardware + * uses some specific read process. + * Return Value: The function returns the value stored in @address + * File: src/tscan1.c + */ +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 data; +} + +/* !!! Don't change this function !!! */ +int tscan1_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = tscan1_request_io; + hwspecops->release_io = tscan1_release_io; + hwspecops->reset = tscan1_reset; + hwspecops->init_hw_data = tscan1_init_hw_data; + hwspecops->init_chip_data = tscan1_init_chip_data; + hwspecops->init_obj_data = tscan1_init_obj_data; + hwspecops->write_register = tscan1_write_register; + hwspecops->read_register = tscan1_read_register; + hwspecops->program_irq = tscan1_program_irq; + return 0; +} + +unsigned long tscan1_getmappedaddr(unsigned long address) +{ + 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= 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; +} -- 2.39.2