]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/unican.c
LinCAN sources go through big white-space cleanup.
[lincan.git] / lincan / src / unican.c
index d93063ab7e92bceb4f668852b08e8b259407ffb7..ae2934a1cb1a0465201c4c618c3eaa2c8d006f1d 100644 (file)
@@ -1,10 +1,36 @@
-/* unican.c
- * Linux CAN-bus device driver.
- * Written for new CAN driver version 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
- */ 
+/**************************************************************************/
+/* File: unican.c - Unicontrols PCAN,PCAN-PCI, VCAN boards support        */
+/*                                                                        */
+/* LinCAN - (Not only) Linux CAN bus driver                               */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
+/* Funded by OCERA and FRESCOR IST projects                               */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
+/*                                                                        */
+/* 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"
@@ -29,18 +55,6 @@ static void unican_delay(long msdelay)
 
 }
 
-
-long unican_bus_latency(struct msgobj_t *obj)
-{
-       long latency;
-       latency=obj->hostchip->baudrate;
-       if(latency){
-               latency=(long)HZ*1000/latency;
-       }
-       return latency;
-}
-
-
 /* * * unican Chip Functionality * * */
 
 int unican_enable_configuration(struct canchip_t *chip)
@@ -66,7 +80,7 @@ int unican_chip_config(struct canchip_t *chip)
        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) {
@@ -77,13 +91,13 @@ int unican_chip_config(struct canchip_t *chip)
 
         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);
@@ -100,7 +114,7 @@ int unican_chip_config(struct canchip_t *chip)
                return -ENODEV;
        }
        unican_delay(1);
-       
+
        /* enable all card interrupts */
        ret = cl2_int_mode(chipext, INT_MODE_ALL);
        if(ret != CL2_OK) {
@@ -163,12 +177,12 @@ int unican_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
                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;
 }
 
@@ -214,7 +228,7 @@ void unican_read(struct canchip_t *chip, struct msgobj_t *obj) {
                        obj->rx_msg.flags = 0;
                }
 
-               /*if ( !(u & (CL2_REMOTE_FRAME<<8)) ) 
+               /*if ( !(u & (CL2_REMOTE_FRAME<<8)) )
                        obj->rx_msg.flags |= MSG_RTR;*/
 
                obj->rx_msg.length = ( (u >> 4) & 0x000F );
@@ -239,7 +253,7 @@ void unican_read(struct canchip_t *chip, struct msgobj_t *obj) {
                #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;
@@ -274,7 +288,7 @@ int unican_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
  * Return Value: negative value reports error.
  * File: src/unican.c
  */
-int unican_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, 
+int unican_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
        return 0;
@@ -291,7 +305,7 @@ int unican_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
  * Return Value: negative value reports error.
  * File: src/unican.c
  */
-int unican_send_msg(struct canchip_t *chip, struct msgobj_t *obj, 
+int unican_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
        return 0;
@@ -320,7 +334,7 @@ int unican_check_tx_stat(struct canchip_t *chip)
  * Return Value: negative value reports error.
  * File: src/unican.c
  */
-int unican_set_btregs(struct canchip_t *chip, unsigned short btr0, 
+int unican_set_btregs(struct canchip_t *chip, unsigned short btr0,
                                                        unsigned short btr1)
 {
        int ret;
@@ -359,6 +373,34 @@ int unican_stop_chip(struct canchip_t *chip)
        return 0;
 }
 
+/**
+ * unican_attach_to_chip: - attaches to the chip, setups registers and state
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int unican_attach_to_chip(struct canchip_t *chip)
+{
+       return 0;
+}
+
+/**
+ * unican_release_chip: - called before chip structure removal if %CHIP_ATTACHED is set
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int unican_release_chip(struct canchip_t *chip)
+{
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+
+       unican_stop_chip(chip);
+       cl2_clear_interrupt(chipext);
+
+       return 0;
+}
 
 /**
  * unican_remote_request: - configures message object and asks for RTR message
@@ -466,10 +508,10 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
                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 */
@@ -483,10 +525,10 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
                if(len > CAN_MSG_LENGTH)
                        len = CAN_MSG_LENGTH;
                u = (len << 12) | (cobid & 0x00FF);
-               
-               if ( !(obj->tx_slot->msg.flags & MSG_RTR) ) 
+
+               if ( !(obj->tx_slot->msg.flags & MSG_RTR) )
                        u |= CL2_REMOTE_FRAME<<8;
-               if ( obj->tx_slot->msg.flags & MSG_EXT ) 
+               if ( obj->tx_slot->msg.flags & MSG_EXT )
                        u |= CL2_EXT_FRAME<<8;
 
                unican_writew(u,ptr16++);
@@ -508,7 +550,7 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
                u = ((cobid>>16) & 0xFF00) | CL2_MESSAGE_VALID;
                unican_writew(u,(__u16*)chipext->asyncTxBufPtr);
 
-               if ( (chipext->asyncTxBufBase + chipext->asyncTxBufSize*16) <= 
+               if ( (chipext->asyncTxBufBase + chipext->asyncTxBufSize*16) <=
                                                (chipext->asyncTxBufPtr += 16) ) {
                        chipext->asyncTxBufPtr = chipext->asyncTxBufBase;
                }
@@ -524,9 +566,9 @@ void unican_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
                /* Free transmitted slot */
                canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
                obj->tx_slot=NULL;
-       
+
        }while(1);
-       
+
        return;
 
 }
@@ -558,11 +600,8 @@ void unican_irq_sync_activities(struct canchip_t *chip, struct msgobj_t *obj)
 /**
  * unican_irq_handler: - interrupt service routine
  * @irq: interrupt vector number, this value is system specific
- * @dev_id: driver private pointer registered at time of request_irq() call.
- *     The CAN driver uses this pointer to store relationship of interrupt
- *     to chip state structure - @struct canchip_t
- * @regs: system dependent value pointing to registers stored in exception frame
- * 
+ * @chip: pointer to chip state structure
+ *
  * Interrupt handler is activated when state of CAN controller chip changes,
  * there is message to be read or there is more space for new messages or
  * error occurs. The receive events results in reading of the message from
@@ -582,8 +621,13 @@ int unican_irq_handler(int irq, struct canchip_t *chip)
                return CANCHIP_IRQ_NONE;
        }
 
-       if (cl2_get_status(chipext, &status) == CL2_NO_REQUEST)
+       if (cl2_get_status(chipext, &status) == CL2_NO_REQUEST) {
+               /* Reenable interrupts generation, this has to be even there,
+                * because irq_accept disables interrupts
+                */
+               cl2_gen_interrupt(chipext);
                return CANCHIP_IRQ_NONE;
+       }
 
        cl2_clear_interrupt(chipext);
 
@@ -606,16 +650,35 @@ int unican_irq_handler(int irq, struct canchip_t *chip)
                unican_read(chip, obj);
        }
 
+       /* Reenable interrupts generation */
        cl2_gen_interrupt(chipext);
 
        return CANCHIP_IRQ_HANDLED;
 }
 
 
+/**
+ * unican_irq_accept: - fast irq accept routine, blocks further interrupts
+ * @irq: interrupt vector number, this value is system specific
+ * @chip: pointer to chip state structure
+ *
+ * This routine only accepts interrupt reception and stops further
+ * incoming interrupts, but does not handle situation causing interrupt.
+ * File: src/unican.c
+ */
+int unican_irq_accept(int irq, struct canchip_t *chip)
+{
+       sCAN_CARD *chipext = (sCAN_CARD *)chip->chip_data;
+
+       cl2_clear_interrupt(chipext);
+
+       return CANCHIP_IRQ_ACCEPTED;
+}
+
 /*void unican_do_tx_timeout(unsigned long data)
 {
        struct msgobj_t *obj=(struct msgobj_t *)data;
-       
+
 }*/
 
 /**
@@ -656,16 +719,16 @@ int unican_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
  */
 int unican_request_io(struct candevice_t *candev)
 {
-        unsigned long remap_addr;
+        can_ioptr_t 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 ) ) ) {
+       if ( !( remap_addr = 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);
@@ -681,7 +744,7 @@ int unican_request_io(struct candevice_t *candev)
  */
 int unican_release_io(struct candevice_t *candev)
 {
-       iounmap((void*)candev->dev_base_addr);
+       iounmap(candev->dev_base_addr);
        can_release_mem_region(candev->io_addr,IO_RANGE);
        return 0;
 }
@@ -699,7 +762,7 @@ int unican_reset(struct candevice_t *candev)
        int i;
        struct canchip_t *chip = candev->chip[0];
        sCAN_CARD *chipext;
-       
+
 
        if(chip->chip_data == NULL) {
                chip->chip_data = can_checked_malloc(sizeof(sCAN_CARD));
@@ -711,9 +774,9 @@ int unican_reset(struct candevice_t *candev)
                        return -ENODEV;
                }
        }
-       
+
        chipext = (sCAN_CARD *)chip->chip_data;
-               
+
        i = 0;
        /* reset and test whether the card is present */
        do {
@@ -727,14 +790,14 @@ int unican_reset(struct candevice_t *candev)
                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;
@@ -747,7 +810,7 @@ int unican_reset(struct candevice_t *candev)
  * Return Value: The function always returns zero
  * File: src/unican.c
  */
-int unican_init_hw_data(struct candevice_t *candev) 
+int unican_init_hw_data(struct candevice_t *candev)
 {
        candev->res_addr=0;
        candev->nr_82527_chips=0;
@@ -775,8 +838,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;
-                       
+       chip->chip_base_addr=candev->dev_base_addr;
+
        CANMSG("initializing unican chip operations\n");
        chip->chipspecops->chip_config=unican_chip_config;
        chip->chipspecops->baud_rate=unican_baud_rate;
@@ -794,9 +857,12 @@ int unican_init_chip_data(struct candevice_t *candev, int chipnr)
        chip->chipspecops->enable_configuration=unican_enable_configuration;
        chip->chipspecops->disable_configuration=unican_disable_configuration;
        chip->chipspecops->set_btregs=unican_set_btregs;
+       chip->chipspecops->attach_to_chip=unican_attach_to_chip;
+       chip->chipspecops->release_chip=unican_release_chip;
        chip->chipspecops->start_chip=unican_start_chip;
        chip->chipspecops->stop_chip=unican_stop_chip;
        chip->chipspecops->irq_handler=unican_irq_handler;
+       chip->chipspecops->irq_accept=unican_irq_accept;
 
        return 0;
 }
@@ -851,7 +917,7 @@ int unican_register(struct hwspecops_t *hwspecops)
 
 int unican_pci_request_io(struct candevice_t *candev)
 {
-        unsigned long remap_addr;
+        can_ioptr_t remap_addr;
 
     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
        if(pci_request_region(candev->sysdevptr.pcidev, 0, "unican_pci") != 0){
@@ -865,11 +931,10 @@ int unican_pci_request_io(struct candevice_t *candev)
        }
     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
 
-       candev->dev_base_addr=pci_resource_start(candev->sysdevptr.pcidev,0);
-       candev->io_addr=candev->dev_base_addr;
-       candev->res_addr=candev->dev_base_addr;
+       candev->io_addr=pci_resource_start(candev->sysdevptr.pcidev,0);
+       candev->res_addr=candev->io_addr;
 
-       if ( !( remap_addr = (long) ioremap( candev->io_addr, IO_RANGE ) ) ) {
+       if ( !( remap_addr = ioremap( candev->io_addr, IO_RANGE ) ) ) {
                CANMSG("Unable to access I/O memory at: 0x%lx\n", candev->io_addr);
            #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
                pci_release_region(candev->sysdevptr.pcidev, 0);
@@ -877,12 +942,13 @@ int unican_pci_request_io(struct candevice_t *candev)
                pci_release_regions(candev->sysdevptr.pcidev);
            #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
                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);
-       DEBUGMSG("VMA: dev_base_addr: 0x%lx chip_base_addr: 0x%lx\n", 
-               candev->dev_base_addr, candev->chip[0]->chip_base_addr);
+       DEBUGMSG("VMA: dev_base_addr: 0x%lx chip_base_addr: 0x%lx\n",
+               can_ioptr2ulong(candev->dev_base_addr),
+               can_ioptr2ulong(candev->chip[0]->chip_base_addr));
 
        return 0;
 }
@@ -890,7 +956,7 @@ int unican_pci_request_io(struct candevice_t *candev)
 
 int unican_pci_release_io(struct candevice_t *candev)
 {
-       iounmap((void*)candev->dev_base_addr);
+       iounmap(candev->dev_base_addr);
     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
        pci_release_region(candev->sysdevptr.pcidev, 0);
     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
@@ -904,25 +970,26 @@ int unican_pci_init_hw_data(struct candevice_t *candev)
 {
        struct pci_dev *pcidev = NULL;
 
-       do {
-               pcidev = pci_find_device(UNICAN_PCI_VENDOR, UNICAN_PCI_ID, pcidev);
-               if(pcidev == NULL) return -ENODEV;
-       } while(can_check_dev_taken(pcidev));
-       
+       pcidev = can_pci_get_next_untaken_device(UNICAN_PCI_VENDOR, UNICAN_PCI_ID);
+       if(pcidev == NULL)
+               return -ENODEV;
+
        if (pci_enable_device (pcidev)){
                printk(KERN_CRIT "Setup of Unican PCI failed\n");
+               can_pci_dev_put(pcidev);
                return -EIO;
        }
        candev->sysdevptr.pcidev=pcidev;
-       
+
        if(!(pci_resource_flags(pcidev,0)&IORESOURCE_MEM)){
                printk(KERN_CRIT "Unican PCI region 0 is not MEM\n");
+               can_pci_dev_put(pcidev);
                return -EIO;
        }
-       candev->dev_base_addr=pci_resource_start(pcidev,0);
-       candev->io_addr=candev->dev_base_addr;
-       candev->res_addr=candev->dev_base_addr;
-       
+       candev->io_addr=pci_resource_start(pcidev,0);
+       candev->res_addr=candev->io_addr;
+       candev->dev_base_addr=NULL;
+
        /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/
 
        candev->nr_82527_chips=0;
@@ -932,6 +999,11 @@ int unican_pci_init_hw_data(struct candevice_t *candev)
        return 0;
 }
 
+void unican_pci_done_hw_data(struct candevice_t *candev)
+{
+       struct pci_dev *pcidev = candev->sysdevptr.pcidev;
+       can_pci_dev_put(pcidev);
+}
 
 int unican_pci_init_chip_data(struct candevice_t *candev, int chipnr)
 {
@@ -948,6 +1020,7 @@ int unican_pci_register(struct hwspecops_t *hwspecops)
        hwspecops->release_io = unican_pci_release_io;
        hwspecops->reset = unican_reset;
        hwspecops->init_hw_data = unican_pci_init_hw_data;
+       hwspecops->done_hw_data = unican_pci_done_hw_data;
        hwspecops->init_chip_data = unican_pci_init_chip_data;
        hwspecops->init_obj_data = unican_init_obj_data;
        hwspecops->write_register = NULL;