]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/ipci165.c
Actual driver code for directly mapped SJA1000 into PCI mem region 0.
[lincan.git] / lincan / src / ipci165.c
index 097523164e5bca6efb54458f3581716c569cdb50..bff48dd57618ad50892980d6c3c80aca1388aff4 100644 (file)
@@ -1,10 +1,37 @@
-/* ipci165.c
- * Linux CAN-bus device driver for IXXAT iPC-I 165 (PCI) compatible HW.
- * Written for new CAN driver version by Radim Kalas
- * email:kalas@unicontrols.cz
- * This software is released under the GPL-License.
- * Version lincan-0.3  17 Jun 2004
- */
+/**************************************************************************/
+/* File: ipci165.c - support for IXXAT iPC-I 165 (PCI) compatible HW      */
+/*                                                                        */
+/* 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>             */
+/* Copyright (C) 2004-2005 Radim Kalas <kalas@unicontrols.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"
 
 #include <ctype.h>
 
+#ifndef IRQF_SHARED
+#define IRQF_SHARED SA_SHIRQ
+#endif  /*IRQF_SHARED*/
+
 can_irqreturn_t ipci165_irq_handler(CAN_IRQ_HANDLER_ARGS(irq_number, dev_id));
 int ipci165_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
                       int sampl_pt, int flags);
@@ -321,7 +352,7 @@ int ipci165_connect_irq(struct candevice_t *candev)
   /* install interrupt routine */
   if (request_irq(candev->sysdevptr.pcidev->irq,
                   ipci165_irq_handler,
-                  SA_SHIRQ,
+                  IRQF_SHARED,
                   DEVICE_NAME,
                   candev))
     return -ENODEV;
@@ -461,12 +492,12 @@ int ipci165_set_btregs(struct canchip_t *chip, unsigned short btr0,
 
   DEBUGMSG ("ipci165_set_btregs[%i]: btr0=%02x, btr1=%02x\n",chip->chip_idx,
             (unsigned)btr0,(unsigned)btr1);
-  
+
   /* configure the chip */
   data[0] = chip->chip_idx;
   data[1] = btr0;
   data[2] = btr1;
-  
+
   size = 1;
   if (bci_command(chip->hostdevice, CMD_INIT_CAN, 3, data) ||
       bci_response(chip->hostdevice, CMD_INIT_CAN, &size, data) ||
@@ -491,10 +522,10 @@ int ipci165_start_chip(struct canchip_t *chip)
   int size;
 
   DEBUGMSG ("ipci165_start_chip[%i]\n",chip->chip_idx);
-  
+
   /* start CAN */
   data[0] = chip->chip_idx;
-  
+
   size = 1;
   if (bci_command(chip->hostdevice, CMD_START_CAN, 1, data) ||
       bci_response(chip->hostdevice, CMD_START_CAN, &size, data) ||
@@ -519,10 +550,10 @@ int ipci165_stop_chip(struct canchip_t *chip)
   int size;
 
   DEBUGMSG ("ipci165_stop_chip[%i]\n",chip->chip_idx);
-  
+
   /* configure the chip */
   data[0] = chip->chip_idx;
-  
+
   size = 1;
   if (bci_command(chip->hostdevice, CMD_STOP_CAN, 1, data) ||
       bci_response(chip->hostdevice, CMD_STOP_CAN, &size, data) ||
@@ -638,7 +669,7 @@ void ipci165_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
       obj->rx_msg.flags  = (frame_info & BCI_MSG_FRAME_RTR ? MSG_RTR : 0);
       obj->rx_msg.cob    = 0;
       obj->rx_msg.timestamp.tv_sec = 0;
-      obj->rx_msg.timestamp.tv_usec = 
+      obj->rx_msg.timestamp.tv_usec =
           BCI_TIMESTAMP_RES * can_readl(msg_addr + BCI_MSG_TIMESTAMP);
       /*  BCI_TIMESTAMP_RES * le32_to_cpu(can_readl(msg_addr + BCI_MSG_TIMESTAMP)); */
 
@@ -674,7 +705,7 @@ void ipci165_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
       DEBUGMSG ("ipci165_irq_read_handler[%i]: CAN status=%04x\n",chip->chip_idx, status);
 
       /* wake up the reset thread if the CAN is in bus off */
-      if (status & BCI_CAN_STATUS_BUS_OFF) 
+      if (status & BCI_CAN_STATUS_BUS_OFF)
       {
         CANMSG ("BUS-OFF detected! Restarting\n");
         set_bit(CHIP_FLAG_BUS_OFF,&chip_data->flags);
@@ -814,9 +845,9 @@ void ipci165_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
  */
 void ipci165_irq_sync_activities(struct canchip_t *chip, struct msgobj_t *obj)
 {
-  while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)) 
+  while(!can_msgobj_test_and_set_fl(obj,TX_LOCK))
   {
-    if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST)) 
+    if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST))
     {
       ipci165_irq_write_handler(chip, obj);
     }
@@ -835,14 +866,14 @@ void ipci165_irq_sync_activities(struct canchip_t *chip, struct msgobj_t *obj)
  * @chip: pointer to chip state structure
  *
  * The main purpose of this function is to perform all necessary channel
- * operations as a reaction on signalled interrupt. 
+ * operations as a reaction on signalled interrupt.
  * File: src/ipci165.c
  */
 void ipci165_irq_chip_handler(struct canchip_t *chip)
 {
   struct msgobj_t       *obj = chip->msgobj[0];
   struct ipci165_chip_t *chip_data = chip->chip_data;
-  struct bci_queue_t    *queue; 
+  struct bci_queue_t    *queue;
 
   DEBUGMSG ("ipci165_irq_chip_handler[%i]\n",chip->chip_idx);
 
@@ -873,7 +904,7 @@ void ipci165_irq_chip_handler(struct canchip_t *chip)
  *     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
- * 
+ *
  * The interrupt handler is activated when the ipci165 controller generates
  * an interrupt as a reaction an internal state change. The interrupt is
  * acknowledged and ipci165_irq_chip_handler is called for every channel.
@@ -1058,12 +1089,12 @@ int ipci165_request_io(struct candevice_t *candev)
   {
 #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
 
-      if ((candev->dev_base_addr = ioremap(dpram_addr, 
+      if ((candev->dev_base_addr = ioremap(dpram_addr,
            pci_resource_len(candev->sysdevptr.pcidev,2))))
       {
         DEBUGMSG ("ipci165_request_io: dpram remapped to 0x%lx\n", candev->dev_base_addr);
 
-        if ((candev->aux_base_addr = ioremap(crm_addr, 
+        if ((candev->aux_base_addr = ioremap(crm_addr,
              pci_resource_len(candev->sysdevptr.pcidev,0))))
         {
           DEBUGMSG ("ipci165_request_io: crm remapped to 0x%lx\n", can_ioptr2ulong(candev->aux_base_addr));
@@ -1112,7 +1143,7 @@ int ipci165_release_io(struct candevice_t *candev)
 {
   struct ipci165_chip_t *chip_data;
   int i;
-  
+
   /* disable irq on HW */
   ipci165_disconnect_irq(candev);
 
@@ -1157,7 +1188,7 @@ int ipci165_download_fw(struct candevice_t *candev)
 
   DEBUGMSG ("ipci165_download_fw\n");
 
-  /* read name and version */  
+  /* read name and version */
   memcpy_fromio (board_name, dpram_addr + BOARD_NAME_OFS, BOARD_NAME_LEN);
   board_name[BOARD_NAME_LEN] = 0;
 
@@ -1327,7 +1358,7 @@ int ipci165_reset(struct candevice_t *candev)
     candev->nr_all_chips = chips;
     canchip_done(candev->chip[1]);
 
-  } else CANMSG ("Chip 2 Type: %s\n",buffer+OF_BOARD_INFO_CHIP2_TYPE); 
+  } else CANMSG ("Chip 2 Type: %s\n",buffer+OF_BOARD_INFO_CHIP2_TYPE);
 
   /* start kernel threads */
   for (i = 0 ; i < chips ; i++)
@@ -1352,21 +1383,20 @@ int ipci165_reset(struct candevice_t *candev)
 int ipci165_init_hw_data(struct candevice_t *candev)
 {
   struct pci_dev *pcidev = NULL;
-  unsigned short SubsystemID;
 
   DEBUGMSG ("ipci165_init_hw_data\n");
 
   /* find iPC-I 165 on PCI bus */
   do
   {
-    pcidev = pci_find_device(IPCI165_VENDOR_ID, IPCI165_DEVICE_ID, pcidev);
-    if(pcidev == NULL) return -ENODEV;
+    pcidev = can_pci_get_device(IPCI165_VENDOR_ID, IPCI165_DEVICE_ID, pcidev);
+    if(pcidev == NULL)
+      return -ENODEV;
 
     /* check subvendor ID */
-    pci_read_config_word (pcidev, PCI_SUBSYSTEM_ID, &SubsystemID);
-    if ((SubsystemID != IPCI165_SUBSYSTEM_ID) &&
-        (SubsystemID != CP350_SUBSYSTEM_ID))
-      break;
+    if ((pcidev->subsystem_vendor != IPCI165_SUBSYSTEM_ID) &&
+        (pcidev->subsystem_vendor != CP350_SUBSYSTEM_ID))
+      continue;
   }
   while(can_check_dev_taken(pcidev));
 
@@ -1374,6 +1404,7 @@ int ipci165_init_hw_data(struct candevice_t *candev)
   if (pci_enable_device (pcidev))
   {
     CANMSG ("Cannot enable PCI device\n");
+    can_pci_dev_put(pcidev);
     return -EIO;
   }
 
@@ -1384,7 +1415,7 @@ int ipci165_init_hw_data(struct candevice_t *candev)
   /* we do not know yet, whether our HW has one or two chan chips. Let's
      prepare configuration for maximal configuration = 2. This will be
      corrected later on */
-  candev->nr_all_chips=2; 
+  candev->nr_all_chips=2;
   candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
   /* initialize device spinlock */
   can_spin_lock_init(&candev->device_lock);
@@ -1392,6 +1423,12 @@ int ipci165_init_hw_data(struct candevice_t *candev)
   return 0;
 }
 
+void ipci165_done_hw_data(struct candevice_t *candev)
+{
+  struct pci_dev *pcidev = candev->sysdevptr.pcidev;
+  can_pci_dev_put(pcidev);
+}
+
 #define CHIP_TYPE "ipci165"
 
 /**
@@ -1482,9 +1519,9 @@ int ipci165_init_chip_data(struct candevice_t *candev, int chipnr)
 int ipci165_init_obj_data(struct canchip_t *chip, int objnr)
 {
   struct msgobj_t *obj=chip->msgobj[objnr];
-  
+
   DEBUGMSG ("ipci165_init_obj_data\n");
-  
+
   obj->obj_base_addr = 0; /* not known yet */
   obj->tx_timeout.function = ipci165_do_tx_timeout;
   obj->tx_timeout.data = (unsigned long)obj;
@@ -1516,6 +1553,7 @@ int ipci165_register(struct hwspecops_t *hwspecops)
   hwspecops->release_io = ipci165_release_io;
   hwspecops->reset = ipci165_reset;
   hwspecops->init_hw_data = ipci165_init_hw_data;
+  hwspecops->done_hw_data = ipci165_done_hw_data;
   hwspecops->init_chip_data = ipci165_init_chip_data;
   hwspecops->init_obj_data = ipci165_init_obj_data;
   hwspecops->write_register = NULL;
@@ -1538,7 +1576,7 @@ void dump_mem(char *ptr, int size)
     strp = str;
     for (j = 0; j < to ; j++)
       strp += sprintf(strp, "%02x ",buf[j]);
-    for (; j < 16 ; j++) 
+    for (; j < 16 ; j++)
       strp += sprintf(strp, "   ");
     for (j = 0; j < to ; j++)
       *strp++= isprint(buf[j]) ? buf[j] : '.';