X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/081fc75264b9a07fdaf6ad59744f48e6164154f1..04ac67cc3cac14cd601daacd0592121ec0b84012:/lincan/src/esdpci200.c diff --git a/lincan/src/esdpci200.c b/lincan/src/esdpci200.c index 1b62e7e..09c44fa 100644 --- a/lincan/src/esdpci200.c +++ b/lincan/src/esdpci200.c @@ -1,10 +1,37 @@ -/* esdpci200.c - support for ESD Electronics' CAN/PCI-200 cards - * Linux CAN-bus device driver. - * The card support was added by Manuel Bessler - * Based on adlink7841.c and nsi_canpci.c - * This software is released under the GPL-License. - * Version lincan-0.3.3 - */ +/**************************************************************************/ +/* File: esdpci200.c - support for ESD Electronics' CAN/PCI-200 cards */ +/* */ +/* LinCAN - (Not only) Linux CAN bus driver */ +/* Copyright (C) 2002-2009 DCE FEE CTU Prague */ +/* Copyright (C) 2002-2009 Pavel Pisa */ +/* Copyright (C) 2007 Manuel Bessler */ +/* Funded by OCERA and FRESCOR IST projects */ +/* Based on CAN driver code by Arnaud Westenberg */ +/* */ +/* LinCAN is free software; you can redistribute it and/or modify it */ +/* under terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2, or (at your option) any */ +/* later version. LinCAN is distributed in the hope that it will be */ +/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */ +/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* General Public License for more details. You should have received a */ +/* copy of the GNU General Public License along with LinCAN; see file */ +/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */ +/* Cambridge, MA 02139, USA. */ +/* */ +/* To allow use of LinCAN in the compact embedded systems firmware */ +/* and RT-executives (RTEMS for example), main authors agree with next */ +/* special exception: */ +/* */ +/* Including LinCAN header files in a file, instantiating LinCAN generics */ +/* or templates, or linking other files with LinCAN objects to produce */ +/* an application image/executable, does not by itself cause the */ +/* resulting application image/executable to be covered by */ +/* the GNU General Public License. */ +/* This exception does not however invalidate any other reasons */ +/* why the executable file might be covered by the GNU Public License. */ +/* Publication of enhanced or derived LinCAN files is required although. */ +/**************************************************************************/ #include "../include/can.h" #include "../include/can_sysdep.h" @@ -32,14 +59,14 @@ #define PLX9052_CNTRL 0x50 /* control register, for software reset */ /* The ESD PCI/200 uses (per default) just LINTi1 (Local Interrupt 1) - * on the PLX. This means that both CAN channels' (SJA1000's) /INT pins + * on the PLX. This means that both CAN channels' (SJA1000's) /INT pins * are OR'ed to the LINTi1 pin (actually ANDed in the 74HC08 since both * the SJA1000's /INT pins and the LINTi1 pin are active low). * * The board does have an option to route the 2nd channel to LINTi2, * apparently just one or two resistors need to be added. * - * LINTi2 is floating per default, so don't set its interrupt enable flag + * LINTi2 is floating per default, so don't set its interrupt enable flag * 'PLX9052_INTCSR_LI2EN', it'll just interrupt all the time. */ #define PLX9052_INTCSR_LI1EN 0x00000001 /* Local Interrupt 1 enable */ @@ -54,7 +81,7 @@ // Standard value: Pushpull (OCTP1|OCTN1|OCPOL1|OCTP0|OCTN0|OCM1) #define ESDPCI200_OCR_DEFAULT_STD 0xFA -/* Setting the OCR register to 0xFA is a good idea. +/* Setting the OCR register to 0xFA is a good idea. This means normal output mode , push-pull and the correct polarity. */ @@ -86,7 +113,7 @@ void esdpci200_connect_irq(struct candevice_t *candev) /* enable interrupts for the SJA1000's, enable PCI interrupts */ outl( PLX9052_INTCSR_LI1EN | PLX9052_INTCSR_PIEN, candev->res_addr+PLX9052_INTCSR); - DEBUGMSG("enabled interrupts on the PLX\n"); + DEBUGMSG("enabled interrupts on the PLX\n"); } int esdpci200_irq_handler(int irq, struct canchip_t *chip) @@ -99,8 +126,8 @@ int esdpci200_irq_handler(int irq, struct canchip_t *chip) //DEBUGMSG("Starting to handle an IRQ\n"); it_reg = inl(candev->res_addr+PLX9052_INTCSR); rmb(); - if((it_reg & (PLX9052_INTCSR_LI1S | PLX9052_INTCSR_LI1EN) ) - == (PLX9052_INTCSR_LI1S | PLX9052_INTCSR_LI1EN) ) + if((it_reg & (PLX9052_INTCSR_LI1S | PLX9052_INTCSR_LI1EN) ) + == (PLX9052_INTCSR_LI1S | PLX9052_INTCSR_LI1EN) ) { /*interrupt enabled and active */ int chipnum; for(chipnum=0; chipnum < candev->nr_sja1000_chips; chipnum++) @@ -117,7 +144,7 @@ int esdpci200_irq_handler(int irq, struct canchip_t *chip) } } if( retcode != CANCHIP_IRQ_HANDLED ) - {/* None of the chips felt they were responsible for this IRQ... + {/* None of the chips felt they were responsible for this IRQ... so it appears we have problems with the IRQ */ it_reg &= ~(PLX9052_INTCSR_LI1EN); //Either we have a problem with IRQ malfunctions, or our IRQ is shared with some other device. @@ -163,7 +190,7 @@ int esdpci200_request_io(struct candevice_t *candev) /*MEM window for SJA1000 chips*/ bar2_addr = pci_resource_start(pcidev,2); candev->io_addr = bar2_addr; - if( ! (remap_addr=ioremap(bar2_addr, + if( ! (remap_addr=ioremap(bar2_addr, pci_resource_len(pcidev,2)))) /*MEM window for SJA1000 chips*/ { CANMSG("Unable to access I/O memory at: 0x%lx\n", (unsigned long)bar2_addr); @@ -171,9 +198,9 @@ int esdpci200_request_io(struct candevice_t *candev) } can_base_addr_fixup(candev, remap_addr); - CANMSG("esdpci200_sja IO-memory: 0x%lx - 0x%lx (VMA 0x%lx)\n", + CANMSG("esdpci200_sja IO-memory: 0x%lx - 0x%lx (VMA 0x%lx)\n", (unsigned long) bar2_addr, - (unsigned long) bar2_addr + pci_resource_len(pcidev,2) - 1, + (unsigned long) (bar2_addr + pci_resource_len(pcidev,2) - 1), (long) remap_addr); return 0; @@ -208,13 +235,13 @@ int esdpci200_release_io(struct candevice_t *candev) void esdpci200_write_register(unsigned data, can_ioptr_t address) { - iowrite8((u8)data,(void*)address); + iowrite8((u8)data,address); wmb(); } unsigned esdpci200_read_register(can_ioptr_t address) { - return ioread8((void*)address); + return ioread8(address); } int esdpci200_reset(struct candevice_t *candev) @@ -251,27 +278,27 @@ int esdpci200_reset(struct candevice_t *candev) 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; + struct pci_dev *pcidev; + + pcidev = can_pci_get_next_untaken_device(ESDPCI200_PCI_VENDOR_ID, ESDPCI200_PCI_PRODUCT_ID); + if(pcidev == NULL) + return -ENODEV; - 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"); + can_pci_dev_put(pcidev); return -EIO; } candev->sysdevptr.pcidev=pcidev; @@ -281,17 +308,20 @@ int esdpci200_init_hw_data(struct candevice_t *candev) if(!(pci_resource_flags(pcidev, 0)&IORESOURCE_MEM)) { printk(KERN_CRIT "PCI200 region %d is not MEM\n",0); + can_pci_dev_put(pcidev); return -EIO; } if(!(pci_resource_flags(pcidev, 1)&IORESOURCE_IO)) { printk(KERN_CRIT "PCI200 region %d is not IO\n",1); + can_pci_dev_put(pcidev); return -EIO; } if(!(pci_resource_flags(pcidev,2)&IORESOURCE_MEM)) { printk(KERN_CRIT "PCI200 region %d is not MEM\n",2); + can_pci_dev_put(pcidev); return -EIO; } @@ -300,7 +330,7 @@ int esdpci200_init_hw_data(struct candevice_t *candev) /* Physical address of SJA1000 window, stored for debugging only */ candev->io_addr = pci_resource_start(pcidev,2); - + candev->aux_base_addr=NULL; /* mapped dynamically in esdpci200_request_io() */ candev->dev_base_addr=NULL; /* mapped dynamically in esdpci200_request_io() */ /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/ @@ -312,11 +342,17 @@ int esdpci200_init_hw_data(struct candevice_t *candev) return 0; } +void esdpci200_done_hw_data(struct candevice_t *candev) +{ + struct pci_dev *pcidev = candev->sysdevptr.pcidev; + can_pci_dev_put(pcidev); +} + int esdpci200_init_chip_data(struct candevice_t *candev, int chipnr) { if(candev->sysdevptr.pcidev==NULL) - return -ENODEV; + return -ENODEV; CANMSG("initializing esdpci200 chip operations\n"); @@ -336,13 +372,13 @@ int esdpci200_init_chip_data(struct candevice_t *candev, int chipnr) candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq; candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; if( chipnr > 0 ) /* only one IRQ used for both channels. - CHIP_IRQ_CUSTOM req'd for RTAI, since - registering two handlers for the same IRQ + CHIP_IRQ_CUSTOM req'd for RTAI, since + registering two handlers for the same IRQ returns an error */ candev->chip[chipnr]->flags |= CHIP_IRQ_CUSTOM; return 0; -} +} int esdpci200_init_obj_data(struct canchip_t *chip, int objnr) { @@ -362,6 +398,7 @@ int esdpci200_register(struct hwspecops_t *hwspecops) hwspecops->release_io = esdpci200_release_io; hwspecops->reset = esdpci200_reset; hwspecops->init_hw_data = esdpci200_init_hw_data; + hwspecops->done_hw_data = esdpci200_done_hw_data; hwspecops->init_chip_data = esdpci200_init_chip_data; hwspecops->init_obj_data = esdpci200_init_obj_data; hwspecops->write_register = esdpci200_write_register;