diff -Nur lincan-0.3.3/README lincan-0.3.3_patched/README --- lincan-0.3.3/README 2006-05-28 12:25:00.000000000 -0400 +++ lincan-0.3.3_patched/README 2007-06-06 10:34:55.000000000 -0400 @@ -266,6 +266,7 @@ - tscan1 for Technologic Systems' TS-CAN1 single SJA1000 based board - ts7kv for Technologic Systems' TS-7KV Multi-function board with SJA1000 both these cards require CONFIG_OC_LINCAN_CARD_tscan1=y +- esdpci200 for the CAN/PCI-200 card by ESD Electronics - template, for yet unsupported hardware (you need to edit src/template.c) - virtual, CAN channel for testing of software and driver without CAN hardware diff -Nur lincan-0.3.3/config.omk-default lincan-0.3.3_patched/config.omk-default --- lincan-0.3.3/config.omk-default 2006-02-10 10:04:03.000000000 -0500 +++ lincan-0.3.3_patched/config.omk-default 2007-06-06 10:34:55.000000000 -0400 @@ -29,6 +29,7 @@ CONFIG_OC_LINCAN_CARD_oscar=y CONFIG_OC_LINCAN_CARD_adlink7841=y CONFIG_OC_LINCAN_CARD_unican=y +CONFIG_OC_LINCAN_CARD_esdpci200=y CONFIG_OC_LINCAN_CARD_virtual=y CONFIG_OC_LINCAN_CARD_template=y CONFIG_OC_LINCAN_CARD_hms30c7202_can=n diff -Nur lincan-0.3.3/src/Makefile.omk lincan-0.3.3_patched/src/Makefile.omk --- lincan-0.3.3/src/Makefile.omk 2006-05-21 14:17:58.000000000 -0400 +++ lincan-0.3.3_patched/src/Makefile.omk 2007-06-06 10:34:55.000000000 -0400 @@ -1,6 +1,6 @@ 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 + kv_pcican msmcan oscar adlink7841 unican esdpci200 virtual template lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 nsi_canpci diff -Nur lincan-0.3.3/src/Makefile.std lincan-0.3.3_patched/src/Makefile.std --- lincan-0.3.3/src/Makefile.std 2005-11-17 06:57:47.000000000 -0500 +++ lincan-0.3.3_patched/src/Makefile.std 2007-06-06 10:34:55.000000000 -0400 @@ -63,7 +63,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 + unican unican_cl2 ems_cpcpci adlink7841 oscar esdpci200 # hms30c7202_can c_can c_can_irq tscan1 # pcan_dongle diff -Nur lincan-0.3.3/src/boardlist.c lincan-0.3.3_patched/src/boardlist.c --- lincan-0.3.3/src/boardlist.c 2006-04-12 03:34:00.000000000 -0400 +++ lincan-0.3.3_patched/src/boardlist.c 2007-06-06 10:34:56.000000000 -0400 @@ -44,6 +44,7 @@ extern int ns_dev_register(struct hwspecops_t *hwspecops); extern int hms30c7202_register(struct hwspecops_t *hwspecops); extern int nsi_canpci_register(struct hwspecops_t *hwspecops); +extern int esdpci200_register(struct hwspecops_t *hwspecops); const struct boardtype_t can_boardtypes[]={ #ifdef CONFIG_OC_LINCAN_CARD_template @@ -135,6 +136,9 @@ #if defined(CONFIG_OC_LINCAN_CARD_adlink7841) {"adlink7841", adlink7841_register, 0}, #endif + #if defined(CONFIG_OC_LINCAN_CARD_esdpci200) + {"esdpci200", esdpci200_register, 0}, + #endif #if defined(CONFIG_OC_LINCAN_CARD_tscan1) {"tscan1", tscan1_register, 1}, {"ts7kv", ts7kv_register, 1}, diff -Nur lincan-0.3.3/src/esdpci200.c lincan-0.3.3_patched/src/esdpci200.c --- lincan-0.3.3/src/esdpci200.c 1969-12-31 19:00:00.000000000 -0500 +++ lincan-0.3.3_patched/src/esdpci200.c 2007-06-06 14:45:34.000000000 -0400 @@ -0,0 +1,277 @@ +/* esdpci200.c - support for ESD Electronics' CAN/PCI-200 cards + * Linux CAN-bus device driver. + * The card support added by Manuel Bessler + * Based on adlink7841.c + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/sja1000p.h" + +#ifdef CAN_ENABLE_PCI_SUPPORT + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) + #define ioread32 readl + #define iowrite32 writel + #define ioread8 readb + #define iowrite8 writeb + #define wmb() + #define rmb() +#else +#endif + +#define ESDPCI200_PCI_VENDOR_ID 0x10B5 +#define ESDPCI200_PCI_PRODUCT_ID 0x9050 + +/* PCI to local bus bridge PLX9050 */ + +#define PLX9050_INTCSR 0x4c /* interrupt control register */ + +#define PLX9050_INTCSR_LI1EN 0x00000001 /* Local Interrupt 1 enable */ +#define PLX9050_INTCSR_LI1S 0x00000004 /* Local Interrupt 1 status */ +#define PLX9050_INTCSR_LI2EN 0x00000008 /* Local Interrupt 2 enable */ +#define PLX9050_INTCSR_LI2S 0x00000020 /* Local Interrupt 2 status */ +#define PLX9050_INTCSR_PIEN 0x00000040 /* PCI Interrupt enable */ + + +#define IO_RANGE 0x100 +#define RESET_ADDR 0x00 + +// Standard value: Pushpull (OCTP1|OCTN1|OCPOL1|OCTP0|OCTN0|OCM1) +#define ESDPCI200_OCR_DEFAULT_STD 0xFA + +/* + +You need to know the following: +" RX1 is connected to ground. +" TX1 is not connected. +" CLKO is not connected. +" Setting the OCR register to 0xFA is a good idea. + This means normal output mode , push-pull and the correct polarity. +" In the CDR register, you should set CBP to 1. + You will probably also want to set the clock divider value to 0 (meaning divide-by-2), + the Pelican bit, and the clock-off bit (you have no need for CLKOUT anyway.) + +*/ + + + +void esdpci200_disconnect_irq(struct candevice_t *candev) +{ + /* writing 0x0 into the PLX's INTCSR register disables interrupts */ + /* 0x0 is also the value in the register after a power-on reset */ + outl(0x0, candev->dev_base_addr + PLX9050_INTCSR); + DEBUGMSG("disabled interrupts on the PLX\n"); +} + +void esdpci200_connect_irq(struct candevice_t *candev) +{ + /* enable interrupts for chip 0 and 1, enable PCI interrupts */ + outl( PLX9050_INTCSR_LI1EN | + PLX9050_INTCSR_LI2EN | + PLX9050_INTCSR_PIEN, + candev->dev_base_addr+PLX9050_INTCSR); + DEBUGMSG("enabled interrupts on the PLX\n"); +} + + +int esdpci200_request_io(struct candevice_t *candev) +{ + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) + + if(pci_request_region(candev->sysdevptr.pcidev, 0, "esdpci200_plx9050") != 0){ + CANMSG("Request of esdpci200_plx9050 range failed\n"); + return -ENODEV; + }else if(pci_request_region(candev->sysdevptr.pcidev, 2, "esdpci200_io") != 0){ + CANMSG("Request of esdpci200_io range failed\n"); + goto error_io; + } + #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + + if(pci_request_regions(candev->sysdevptr.pcidev, "esdpci200") != 0){ + CANMSG("Request of esdpci200_plx9050 regions failed\n"); + return -ENODEV; + } + #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + + esdpci200_disconnect_irq(candev); + + return 0; + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) + error_io: + pci_release_region(candev->sysdevptr.pcidev, 0); + #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + + return -ENODEV; +} + +int esdpci200_release_io(struct candevice_t *candev) +{ + esdpci200_disconnect_irq(candev); + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) + pci_release_region(candev->sysdevptr.pcidev, 2); + pci_release_region(candev->sysdevptr.pcidev, 0); + #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + pci_release_regions(candev->sysdevptr.pcidev); + #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + + return 0; +} + + +void esdpci200_write_register(unsigned data, unsigned long address) +{ + writeb(data,address); +} + +unsigned esdpci200_read_register(unsigned long address) +{ + return readb(address); +} + +int esdpci200_reset(struct candevice_t *candev) +{ + int i=0,chip_nr; + struct canchip_t *chip; + unsigned cdr; + + DEBUGMSG("Resetting esdpci200 hardware ...\n"); + + esdpci200_disconnect_irq(candev); + + for(chip_nr=0;chip_nrnr_all_chips;chip_nr++){ + if(!candev->chip[chip_nr]) continue; + chip=candev->chip[chip_nr]; + + esdpci200_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD); + udelay(1000); + + cdr=esdpci200_read_register(chip->chip_base_addr+SJACDR); + esdpci200_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR); + + esdpci200_write_register(0, chip->chip_base_addr+SJAIER); + + i=20; + esdpci200_write_register(0, chip->chip_base_addr+SJAMOD); + while (esdpci200_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){ + if(!i--) return -ENODEV; + udelay(1000); + esdpci200_write_register(0, chip->chip_base_addr+SJAMOD); + } + + cdr=esdpci200_read_register(chip->chip_base_addr+SJACDR); + esdpci200_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR); + + esdpci200_write_register(0, chip->chip_base_addr+SJAIER); + + esdpci200_read_register(chip->chip_base_addr+SJAIR); + } + + + esdpci200_connect_irq(candev); + + return 0; +} + +int esdpci200_init_hw_data(struct candevice_t *candev) +{ + struct pci_dev *pcidev = NULL; + + do { + pcidev = pci_find_device(ESDPCI200_PCI_VENDOR_ID, ESDPCI200_PCI_PRODUCT_ID, pcidev); + if(pcidev == NULL) return -ENODEV; + } while(can_check_dev_taken(pcidev)); + + if (pci_enable_device (pcidev)){ + printk(KERN_CRIT "Setup of ESDPCI200 failed\n"); + return -EIO; + } + candev->sysdevptr.pcidev=pcidev; + + if(!(pci_resource_flags(pcidev, 0)&IORESOURCE_MEM)) + { + printk(KERN_CRIT "PCI200 region %d is not IO\n",0); + return -EIO; + } + + if(!(pci_resource_flags(pcidev,2)&IORESOURCE_MEM)) + { + printk(KERN_CRIT "PCI200 region %d is not MEM\n",2); + return -EIO; + } + + candev->res_addr=RESET_ADDR; /* ??? not sure about this */ + candev->dev_base_addr=pci_resource_start(pcidev,1); /* ioports, PLX local configuration registers */ + candev->io_addr=pci_resource_start(pcidev,2); /*MEM window for SJA1000 chips*/ + + /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/ + + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=2; + candev->nr_all_chips=2; + + return 0; +} + +int esdpci200_init_chip_data(struct candevice_t *candev, int chipnr) +{ + + if(candev->sysdevptr.pcidev==NULL) + return -ENODEV; + + CANMSG("initializing esdpci200 chip operations\n"); + + candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq; + + sja1000p_fill_chipspecops(candev->chip[chipnr]); +// candev->chip[chipnr]->chip_base_addr= candev->io_addr + chipnr*IO_RANGE; + candev->chip[chipnr]->chip_base_addr= (long)ioremap( candev->io_addr, IO_RANGE ) + chipnr * IO_RANGE; + + candev->chip[chipnr]->flags = 0; + candev->chip[chipnr]->int_cpu_reg = 0; + candev->chip[chipnr]->int_clk_reg = 0; + candev->chip[chipnr]->int_bus_reg = 0; + candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = ESDPCI200_OCR_DEFAULT_STD; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; + + /* irq_handler already taken care of by sja1000p.c */ + /* candev->chip[chipnr]->chipspecops->irq_handler = NULL; */ + + return 0; +} + +int esdpci200_init_obj_data(struct canchip_t *chip, int objnr) +{ + chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr; + return 0; +} + +int esdpci200_program_irq(struct candevice_t *candev) +{ + + return 0; +} + +int esdpci200_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = esdpci200_request_io; + hwspecops->release_io = esdpci200_release_io; + hwspecops->reset = esdpci200_reset; + hwspecops->init_hw_data = esdpci200_init_hw_data; + hwspecops->init_chip_data = esdpci200_init_chip_data; + hwspecops->init_obj_data = esdpci200_init_obj_data; + hwspecops->write_register = esdpci200_write_register; + hwspecops->read_register = esdpci200_read_register; + hwspecops->program_irq = esdpci200_program_irq; + return 0; +} + + +#endif /*CAN_ENABLE_PCI_SUPPORT*/