]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
Copy new created files from cannetdriver26 into trunk.
authorhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Wed, 21 May 2008 17:47:29 +0000 (17:47 +0000)
committerhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Wed, 21 May 2008 17:47:29 +0000 (17:47 +0000)
git-svn-id: svn://svn.berlios.de//socketcan/trunk@734 030b6a49-0b11-0410-94ab-b0dab22257f2

kernel/2.6/drivers/net/can/sja1000/Makefile [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/ems_pci.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/ixxat_pci.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/kvaser_pci.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/pcm027.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/peak_pci.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/sja1000.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/sja1000.h [new file with mode: 0644]
kernel/2.6/net/can/sysfs.c [new file with mode: 0644]
kernel/2.6/net/can/sysfs.h [new file with mode: 0644]

diff --git a/kernel/2.6/drivers/net/can/sja1000/Makefile b/kernel/2.6/drivers/net/can/sja1000/Makefile
new file mode 100644 (file)
index 0000000..d32c2e1
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#  $Id: Makefile 443 2007-07-25 11:41:27Z hartkopp $
+#
+#  Copyright (c) 2002-2005 Volkswagen Group Electronic Research
+#  All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#  1. Redistributions of source code must retain the above copyright
+#     notice, this list of conditions, the following disclaimer and
+#     the referenced file 'COPYING'.
+#  2. Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#  3. Neither the name of Volkswagen nor the names of its contributors
+#     may be used to endorse or promote products derived from this software
+#     without specific prior written permission.
+#
+#  Alternatively, provided that this notice is retained in full, this
+#  software may be distributed under the terms of the GNU General
+#  Public License ("GPL") version 2 as distributed in the 'COPYING'
+#  file from the main directory of the linux kernel source.
+#
+#  The provided data structures and external interfaces from this code
+#  are not restricted to be used by modules with a GPL compatible license.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+#  DAMAGE.
+#
+#  Send feedback to <socketcan-users@lists.berlios.de>
+
+
+ifeq ($(KERNELRELEASE),)
+
+KERNELDIR := /lib/modules/$(shell uname -r)/build
+PWD       := $(shell pwd)
+TOPDIR    := $(PWD)/../../../..
+
+modules modules_install clean:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) $@ TOPDIR=$(TOPDIR)
+
+else
+
+-include $(TOPDIR)/Makefile.common
+#EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/can/hal
+
+obj-$(CONFIG_CAN_SJA1000) += sja1000.o
+obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
+obj-$(CONFIG_CAN_IXXAT_PCI) += ixxat_pci.o
+obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
+obj-$(CONFIG_CAN_PCM027) += pcm027.o
+obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+
+endif
diff --git a/kernel/2.6/drivers/net/can/sja1000/ems_pci.c b/kernel/2.6/drivers/net/can/sja1000/ems_pci.c
new file mode 100644 (file)
index 0000000..02ea190
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ * Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
+ * Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <asm/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME  "can-ems-pci"
+
+MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
+MODULE_LICENSE("GPL v2");
+
+#define EMS_PCI_MAX_CHAN 2
+
+struct ems_pci_card {
+       int channels;
+
+       struct pci_dev *pci_dev;
+       struct net_device *net_dev[EMS_PCI_MAX_CHAN];
+
+       void __iomem *conf_addr;
+       void __iomem *base_addr;
+};
+
+#define EMS_PCI_CAN_CLOCK (16000000 / 2)
+
+/*
+ * Register definitions and descriptions are from LinCAN 0.3.3.
+ *
+ * PSB4610 PITA-2 bridge control registers
+ */
+#define PITA2_ICR           0x00       /* Interrupt Control Register */
+#define PITA2_ICR_INT0      0x00000002 /* [RC] INT0 Active/Clear */
+#define PITA2_ICR_INT0_EN   0x00020000 /* [RW] Enable INT0 */
+
+#define PITA2_MISC          0x1c       /* Miscellaneous Register */
+#define PITA2_MISC_CONFIG   0x04000000 /* Multiplexed parallel interface */
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means  normal output mode , push-pull and the correct polarity.
+ */
+#define EMS_PCI_OCR         (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define EMS_PCI_CDR             (CDR_CBP | CDR_CLKOUT_MASK)
+#define EMS_PCI_MEM_SIZE        4096  /* Size of the remapped io-memory */
+#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
+#define EMS_PCI_CAN_CTRL_SIZE   0x200 /* memory size for each controller */
+
+#define EMS_PCI_PORT_BYTES  0x4     /* Each register occupies 4 bytes */
+
+#define EMS_PCI_VENDOR_ID   0x110a  /* PCI device and vendor ID */
+#define EMS_PCI_DEVICE_ID   0x2104
+
+static struct pci_device_id ems_pci_tbl[] = {
+       {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       { 0,}
+};
+MODULE_DEVICE_TABLE (pci, ems_pci_tbl);
+
+/*
+ * Helper to read internal registers from card logic (not CAN)
+ */
+static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
+{
+       return readb((void __iomem *)card->base_addr
+                       + (port * EMS_PCI_PORT_BYTES));
+}
+
+static u8 ems_pci_read_reg(struct net_device *dev, int port)
+{
+       return readb((void __iomem *)dev->base_addr
+                       + (port * EMS_PCI_PORT_BYTES));
+}
+
+static void ems_pci_write_reg(struct net_device *dev, int port, u8 val)
+{
+       writeb(val, (void __iomem *)dev->base_addr
+               + (port * EMS_PCI_PORT_BYTES));
+}
+
+static void ems_pci_post_irq(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+
+       /* reset int flag of pita */
+       writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr
+               + PITA2_ICR);
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to set 'em into the PeliCAN mode
+ */
+static inline int ems_pci_check_chan(struct net_device *dev)
+{
+       unsigned char res;
+
+       /* Make sure SJA1000 is in reset mode */
+       ems_pci_write_reg(dev, REG_MOD, 1);
+
+       ems_pci_write_reg(dev, REG_CDR, CDR_PELICAN);
+
+       /* read reset-values */
+       res = ems_pci_read_reg(dev, REG_CDR);
+
+       if (res == CDR_PELICAN)
+               return 1;
+
+       return 0;
+}
+
+static void ems_pci_del_card(struct pci_dev *pdev)
+{
+       struct ems_pci_card *card = pci_get_drvdata(pdev);
+       struct net_device *dev;
+       int i = 0;
+
+       for (i = 0; i < card->channels; i++) {
+               dev = card->net_dev[i];
+
+               if (!dev)
+                       continue;
+
+               dev_info(&pdev->dev, "Removing %s.\n", dev->name);
+               unregister_sja1000dev(dev);
+               free_sja1000dev(dev);
+       }
+
+       if (card->base_addr != NULL )
+               pci_iounmap(card->pci_dev, card->base_addr);
+
+       if (card->conf_addr != NULL)
+               pci_iounmap(card->pci_dev, card->conf_addr);
+
+       kfree(card);
+
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static void ems_pci_card_reset(struct ems_pci_card *card)
+{
+       /* Request board reset */
+       writeb(0, card->base_addr);
+}
+
+/*
+ * Probe PCI device for EMS CAN signature and register each available
+ * CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit ems_pci_add_card(struct pci_dev *pdev,
+                                       const struct pci_device_id *ent)
+{
+       struct sja1000_priv *priv;
+       struct net_device *dev;
+       struct ems_pci_card *card;
+       int err, i;
+
+       /* Enabling PCI device */
+       if (pci_enable_device(pdev) < 0) {
+               dev_err(&pdev->dev, "Enabling PCI device failed\n");
+               return -ENODEV;
+       }
+
+       /* Allocating card structures to hold addresses, ... */
+       card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL);
+       if (card == NULL) {
+               dev_err(&pdev->dev, "Unable to allocate memory\n");
+               pci_disable_device(pdev);
+               return -ENOMEM;
+       }
+
+       pci_set_drvdata(pdev, card);
+
+       card->pci_dev = pdev;
+
+       card->channels = 0;
+
+       /* Remap PITA configuration space, and controller memory area */
+       card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
+       if (card->conf_addr == NULL) {
+               err = -ENOMEM;
+
+               goto failure_cleanup;
+       }
+
+       card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
+       if (card->base_addr == NULL) {
+               err = -ENOMEM;
+
+               goto failure_cleanup;
+       }
+
+       /* Configure PITA-2 parallel interface (enable MUX) */
+       writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
+
+       /* Check for unique EMS CAN signature */
+       if (ems_pci_readb(card, 0) != 0x55 ||
+           ems_pci_readb(card, 1) != 0xAA ||
+           ems_pci_readb(card, 2) != 0x01 ||
+           ems_pci_readb(card, 3) != 0xCB ||
+           ems_pci_readb(card, 4) != 0x11) {
+               dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n");
+
+               err = -ENODEV;
+               goto failure_cleanup;
+       }
+
+       ems_pci_card_reset(card);
+
+       /* Detect available channels */
+       for (i = 0; i < EMS_PCI_MAX_CHAN; i++) {
+               dev = alloc_sja1000dev(0);
+               if (dev == NULL) {
+                       err = -ENOMEM;
+                       goto failure_cleanup;
+               }
+
+               card->net_dev[i] = dev;
+               priv = netdev_priv(dev);
+               priv->priv = card;
+
+               dev->irq = pdev->irq;
+               dev->base_addr = (unsigned long)(card->base_addr
+                                               + EMS_PCI_CAN_BASE_OFFSET
+                                               + (i * EMS_PCI_CAN_CTRL_SIZE));
+
+               /* Check if channel is present */
+               if (ems_pci_check_chan(dev)) {
+                       priv->read_reg  = ems_pci_read_reg;
+                       priv->write_reg = ems_pci_write_reg;
+                       priv->post_irq  = ems_pci_post_irq;
+                       priv->can.can_sys_clock = EMS_PCI_CAN_CLOCK;
+                       priv->ocr = EMS_PCI_OCR;
+                       priv->cdr = EMS_PCI_CDR;
+
+                       SET_NETDEV_DEV(dev, &pdev->dev);
+
+                       /* Enable interrupts from card */
+                       writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR);
+
+                       /* Register SJA1000 device */
+                       err = register_sja1000dev(dev);
+                       if (err) {
+                               dev_err(&pdev->dev, "Registering device failed "
+                                                       "(err=%d)\n", err);
+                               free_sja1000dev(dev);
+                               goto failure_cleanup;
+                       }
+
+                       card->channels++;
+
+                       dev_info(&pdev->dev, "Channel #%d at %lX, irq %d\n",
+                                               i + 1, dev->base_addr,
+                                               dev->irq);
+               } else {
+                       free_sja1000dev(dev);
+               }
+       }
+
+       return 0;
+
+failure_cleanup:
+       dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
+
+       ems_pci_del_card(pdev);
+
+       return err;
+}
+
+static struct pci_driver ems_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = ems_pci_tbl,
+       .probe = ems_pci_add_card,
+       .remove = ems_pci_del_card,
+};
+
+static int __init ems_pci_init(void)
+{
+       return pci_register_driver(&ems_pci_driver);
+}
+
+static void __exit ems_pci_exit(void)
+{
+       pci_unregister_driver(&ems_pci_driver);
+}
+
+module_init(ems_pci_init);
+module_exit(ems_pci_exit);
+
diff --git a/kernel/2.6/drivers/net/can/sja1000/ixxat_pci.c b/kernel/2.6/drivers/net/can/sja1000/ixxat_pci.c
new file mode 100644 (file)
index 0000000..f9691b3
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <asm/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME  "can-ixxat-pci"
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
+MODULE_DESCRIPTION("Socket-CAN driver for IXXAT PC-I 04/PCI PCI cards");
+MODULE_SUPPORTED_DEVICE("IXXAT PC-I 04/PCI card");
+MODULE_LICENSE("GPL v2");
+
+/* Maximum number of interfaces supported on one card. Currently
+ * we only support a maximum of two interfaces, which is the maximum
+ * of what Ixxat sells anyway.
+ */
+#define IXXAT_PCI_MAX_CAN 2
+
+struct ixxat_pci {
+       struct pci_dev *pci_dev;
+       struct net_device *dev[IXXAT_PCI_MAX_CAN];
+       int conf_addr;
+       void __iomem *base_addr;
+};
+
+#define IXXAT_PCI_CAN_CLOCK  (16000000 / 2)
+
+#define IXXAT_PCI_OCR       (OCR_TX0_PUSHPULL | OCR_TX0_INVERT | \
+                             OCR_TX1_PUSHPULL)
+#define IXXAT_PCI_CDR       0
+
+#define CHANNEL_RESET_OFFSET 0x110
+#define CHANNEL_OFFSET      0x200
+
+#define INTCSR_OFFSET        0x4c /* Offset in PLX9050 conf registers */
+#define INTCSR_LINTI1        (1 << 0)
+#define INTCSR_LINTI2        (1 << 3)
+#define INTCSR_PCI           (1 << 6)
+
+/* PCI vender, device and sub-device ID */
+#define IXXAT_PCI_VENDOR_ID  0x10b5
+#define IXXAT_PCI_DEVICE_ID  0x9050
+#define IXXAT_PCI_SUB_SYS_ID 0x2540
+
+#define IXXAT_PCI_BASE_SIZE  0x400
+
+static struct pci_device_id ixxat_pci_tbl[] = {
+       {IXXAT_PCI_VENDOR_ID, IXXAT_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+        { 0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ixxat_pci_tbl);
+
+static u8 ixxat_pci_read_reg(struct net_device *ndev, int port)
+{
+       u8 val;
+       val = readb((void __iomem *)(ndev->base_addr + port));
+       return val;
+}
+
+static void ixxat_pci_write_reg(struct net_device *ndev, int port, u8 val)
+{
+       writeb(val, (void __iomem *)(ndev->base_addr + port));
+}
+
+static void ixxat_pci_del_chan(struct pci_dev *pdev, struct net_device *ndev)
+{
+       dev_info(&pdev->dev, "Removing device %s\n", ndev->name);
+
+       unregister_sja1000dev(ndev);
+
+       free_sja1000dev(ndev);
+}
+
+static struct net_device *ixxat_pci_add_chan(struct pci_dev *pdev,
+               void __iomem *base_addr)
+{
+       struct net_device *ndev;
+       struct sja1000_priv *priv;
+       int err;
+
+       ndev = alloc_sja1000dev(0);
+       if (ndev == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       priv = netdev_priv(ndev);
+
+       ndev->base_addr = (unsigned long)base_addr;
+
+       priv->read_reg = ixxat_pci_read_reg;
+       priv->write_reg = ixxat_pci_write_reg;
+
+       priv->can.can_sys_clock = IXXAT_PCI_CAN_CLOCK;
+
+       priv->ocr = IXXAT_PCI_OCR;
+       priv->cdr = IXXAT_PCI_CDR;
+
+       /* Set and enable PCI interrupts */
+       ndev->irq = pdev->irq;
+
+       dev_dbg(&pdev->dev, "base_addr=%#lx irq=%d\n",
+                       ndev->base_addr, ndev->irq);
+
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+
+       err = register_sja1000dev(ndev);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to register (err=%d)\n", err);
+               goto failure;
+       }
+
+       return ndev;
+
+failure:
+       free_sja1000dev(ndev);
+       return ERR_PTR(err);
+}
+
+static int __devinit ixxat_pci_init_one(struct pci_dev *pdev,
+                                      const struct pci_device_id *ent)
+{
+       struct ixxat_pci *board;
+       int err, intcsr = INTCSR_LINTI1 | INTCSR_PCI;
+       u16 sub_sys_id;
+       void __iomem *base_addr;
+
+       dev_info(&pdev->dev, "Initializing device %04x:%04x\n",
+              pdev->vendor, pdev->device);
+
+       board = kzalloc(sizeof(*board), GFP_KERNEL);
+       if (!board)
+               return -ENOMEM;
+
+       if ((err = pci_enable_device(pdev)))
+               goto failure;
+
+       if ((err = pci_request_regions(pdev, DRV_NAME)))
+               goto failure;
+
+       if ((err = pci_read_config_word(pdev, 0x2e, &sub_sys_id)))
+               goto failure_release_pci;
+
+       if (sub_sys_id != IXXAT_PCI_SUB_SYS_ID)
+               return -ENODEV;
+
+       /* Enable memory and I/O space */
+       if ((err = pci_write_config_word(pdev, 0x04, 0x3)))
+               goto failure_release_pci;
+
+       board->conf_addr = pci_resource_start(pdev, 1);
+
+       base_addr = pci_iomap(pdev, 2, IXXAT_PCI_BASE_SIZE);
+       if (base_addr == 0) {
+               err = -ENODEV;
+               goto failure_release_pci;
+       }
+
+       board->base_addr = base_addr;
+
+       writeb(0x1, base_addr + CHANNEL_RESET_OFFSET);
+       writeb(0x1, base_addr + CHANNEL_OFFSET + CHANNEL_RESET_OFFSET);
+       udelay(100);
+
+       board->dev[0] = ixxat_pci_add_chan(pdev, base_addr);
+       if (IS_ERR(board->dev[0]))
+               goto failure_iounmap;
+
+       /* Check if second channel is available */
+       if (readb(base_addr + CHANNEL_OFFSET + REG_MOD) == 0x21 &&
+           readb(base_addr + CHANNEL_OFFSET + REG_SR) == 0x0c &&
+           readb(base_addr + CHANNEL_OFFSET + REG_IR) == 0xe0) {
+               board->dev[1] = ixxat_pci_add_chan(pdev,
+                               base_addr + CHANNEL_OFFSET);
+               if (IS_ERR(board->dev[1]))
+                       goto failure_unreg_dev0;
+
+               intcsr |= INTCSR_LINTI2;
+       }
+
+       /* enable interrupt(s) in PLX9050 */
+       outb(intcsr, board->conf_addr + INTCSR_OFFSET);
+
+       pci_set_drvdata(pdev, board);
+
+       return 0;
+
+failure_unreg_dev0:
+       ixxat_pci_del_chan(pdev, board->dev[0]);
+
+failure_iounmap:
+       pci_iounmap(pdev, board->base_addr);
+
+failure_release_pci:
+       pci_release_regions(pdev);
+
+failure:
+       kfree(board);
+
+       return err;
+}
+
+static void __devexit ixxat_pci_remove_one(struct pci_dev *pdev)
+{
+       struct ixxat_pci *board = pci_get_drvdata(pdev);
+       int i;
+
+       /* Disable interrupts in PLX9050*/
+       outb(0, board->conf_addr + INTCSR_OFFSET);
+
+       for (i = 0; i < IXXAT_PCI_MAX_CAN; i++) {
+               if (!board->dev[i])
+                       break;
+               ixxat_pci_del_chan(pdev, board->dev[i]);
+       }
+
+       pci_iounmap(pdev, board->base_addr);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+
+       kfree(board);
+}
+
+static struct pci_driver ixxat_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = ixxat_pci_tbl,
+       .probe = ixxat_pci_init_one,
+       .remove = __devexit_p(ixxat_pci_remove_one),
+};
+
+static int __init ixxat_pci_init(void)
+{
+       return pci_register_driver(&ixxat_pci_driver);
+}
+
+static void __exit ixxat_pci_exit(void)
+{
+       pci_unregister_driver(&ixxat_pci_driver);
+}
+
+module_init(ixxat_pci_init);
+module_exit(ixxat_pci_exit);
diff --git a/kernel/2.6/drivers/net/can/sja1000/kvaser_pci.c b/kernel/2.6/drivers/net/can/sja1000/kvaser_pci.c
new file mode 100644 (file)
index 0000000..a7e375b
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2008 Per Dalen <per.dalen@cnw.se>
+ *
+ * Parts of this software are based on (derived) the following:
+ *
+ * - Kvaser linux driver, version 4.72 BETA
+ *   Copyright (C) 2002-2007 KVASER AB
+ *
+ * - Lincan driver, version 0.3.3, OCERA project
+ *   Copyright (C) 2004 Pavel Pisa
+ *   Copyright (C) 2001 Arnaud Westenberg
+ *
+ * - Socketcan SJA1000 drivers
+ *   Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ *   Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ *   Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
+ *   38106 Braunschweig, GERMANY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <asm/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME  "can-kvaser-pci"
+
+MODULE_AUTHOR("Per Dalen <per.dalen@cnw.se>");
+MODULE_DESCRIPTION("Socket-CAN driver for KVASER PCAN PCI cards");
+MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card");
+MODULE_LICENSE("GPL v2");
+
+#define MAX_NO_OF_CHANNELS        4 /* max no of channels on
+                                      a single card */
+
+struct kvaser_pci {
+       int channel;
+       struct pci_dev *pci_dev;
+       struct net_device *slave_dev[MAX_NO_OF_CHANNELS-1];
+       void __iomem *conf_addr;
+       void __iomem *res_addr;
+       int no_channels;
+       u8 xilinx_ver;
+};
+
+#define KVASER_PCI_CAN_CLOCK      (16000000 / 2)
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means  normal output mode , push-pull and the correct polarity.
+ */
+#define KVASER_PCI_OCR            (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * 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 will have no need for CLKOUT anyway).
+ */
+#define KVASER_PCI_CDR            (CDR_CBP | CDR_CLKOUT_MASK)
+
+/*
+ * These register values are valid for revision 14 of the Xilinx logic.
+ */
+#define XILINX_VERINT             7   /* Lower nibble simulate interrupts,
+                                        high nibble version number. */
+
+#define XILINX_PRESUMED_VERSION   14
+
+/*
+ * Important S5920 registers
+ */
+#define S5920_INTCSR              0x38
+#define S5920_PTCR                0x60
+#define INTCSR_ADDON_INTENABLE_M  0x2000
+
+
+#define KVASER_PCI_PORT_BYTES     0x20
+
+#define PCI_CONFIG_PORT_SIZE      0x80      /* size of the config io-memory */
+#define PCI_PORT_SIZE             0x80      /* size of a channel io-memory */
+#define PCI_PORT_XILINX_SIZE      0x08      /* size of a xilinx io-memory */
+
+#define KVASER_PCI_VENDOR_ID1     0x10e8    /* the PCI device and vendor IDs */
+#define KVASER_PCI_DEVICE_ID1     0x8406
+
+#define KVASER_PCI_VENDOR_ID2     0x1a07    /* the PCI device and vendor IDs */
+#define KVASER_PCI_DEVICE_ID2     0x0008
+
+static struct pci_device_id kvaser_pci_tbl[] = {
+       {KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,},
+       {KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,},
+       { 0,}
+};
+
+MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl);
+
+static u8 kvaser_pci_read_reg(struct net_device *dev, int port)
+{
+       return ioread8((void __iomem *)(dev->base_addr + port));
+}
+
+static void kvaser_pci_write_reg(struct net_device *dev, int port, u8 val)
+{
+       iowrite8(val, (void __iomem *)(dev->base_addr + port));
+}
+
+static void kvaser_pci_disable_irq(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct kvaser_pci *board = priv->priv;
+       u32 tmp;
+
+       /* Disable interrupts from card */
+       tmp = ioread32(board->conf_addr + S5920_INTCSR);
+       tmp &= ~INTCSR_ADDON_INTENABLE_M;
+       iowrite32(tmp, board->conf_addr + S5920_INTCSR);
+}
+
+static void kvaser_pci_enable_irq(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct kvaser_pci *board = priv->priv;
+       u32 tmp;
+
+       /* Enable interrupts from card */
+       tmp = ioread32(board->conf_addr + S5920_INTCSR);
+       tmp |= INTCSR_ADDON_INTENABLE_M;
+       iowrite32(tmp, board->conf_addr + S5920_INTCSR);
+}
+
+static int number_of_sja1000_chip(void __iomem *base_addr)
+{
+       u8 status;
+       int i;
+
+       for (i = 0; i < MAX_NO_OF_CHANNELS; i++) {
+               /* reset chip */
+               iowrite8(MOD_RM, base_addr +
+                        (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+               status = ioread8(base_addr +
+                                (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+               udelay(10);
+               /* check reset bit */
+               if (!(status & MOD_RM))
+                       break;
+       }
+
+       return i;
+}
+
+static void kvaser_pci_del_chan(struct net_device *dev)
+{
+       struct sja1000_priv *priv;
+       struct kvaser_pci *board;
+       int i;
+
+       if (!dev)
+               return;
+       priv = netdev_priv(dev);
+       if (!priv)
+               return;
+       board = priv->priv;
+       if (!board)
+               return;
+
+       dev_info(&board->pci_dev->dev, "Removing device %s\n",
+                dev->name);
+
+       for (i = 0; i < board->no_channels - 1; i++) {
+               if (board->slave_dev[i]) {
+                       dev_info(&board->pci_dev->dev, "Removing device %s\n",
+                                board->slave_dev[i]->name);
+                       unregister_sja1000dev(board->slave_dev[i]);
+                       free_sja1000dev(board->slave_dev[i]);
+               }
+       }
+       unregister_sja1000dev(dev);
+
+       /* Disable PCI interrupts */
+       kvaser_pci_disable_irq(dev);
+
+       pci_iounmap(board->pci_dev, (void __iomem *)dev->base_addr);
+       pci_iounmap(board->pci_dev, board->conf_addr);
+       pci_iounmap(board->pci_dev, board->res_addr);
+
+       free_sja1000dev(dev);
+}
+
+static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
+                              struct net_device **master_dev,
+                              void __iomem *conf_addr,
+                              void __iomem *res_addr,
+                              unsigned long base_addr)
+{
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+       struct kvaser_pci *board;
+       int err, init_step;
+
+       dev = alloc_sja1000dev(sizeof(struct kvaser_pci));
+       if (dev == NULL)
+               return -ENOMEM;
+
+       priv = netdev_priv(dev);
+       board = priv->priv;
+
+       board->pci_dev = pdev;
+       board->channel = channel;
+
+       /*S5920*/
+       board->conf_addr = conf_addr;
+
+       /*XILINX board wide address*/
+       board->res_addr = res_addr;
+
+       if (channel == 0) {
+               board->xilinx_ver =
+                       ioread8(board->res_addr + XILINX_VERINT) >> 4;
+               init_step = 2;
+
+               /* Assert PTADR# - we're in passive mode so the other bits are
+                  not important */
+               iowrite32(0x80808080UL, board->conf_addr + S5920_PTCR);
+
+               /* Disable interrupts from card */
+               kvaser_pci_disable_irq(dev);
+               /* Enable interrupts from card */
+               kvaser_pci_enable_irq(dev);
+       } else {
+               struct sja1000_priv *master_priv = netdev_priv(*master_dev);
+               struct kvaser_pci *master_board = master_priv->priv;
+               master_board->slave_dev[channel - 1] = dev;
+               master_board->no_channels = channel + 1;
+               board->xilinx_ver = master_board->xilinx_ver;
+       }
+
+       dev->base_addr = base_addr + channel * KVASER_PCI_PORT_BYTES;
+
+       priv->read_reg = kvaser_pci_read_reg;
+       priv->write_reg = kvaser_pci_write_reg;
+
+       priv->can.can_sys_clock = KVASER_PCI_CAN_CLOCK;
+
+       priv->ocr = KVASER_PCI_OCR;
+       priv->cdr = KVASER_PCI_CDR;
+
+       /* Register and setup interrupt handling */
+       dev->irq = pdev->irq;
+       init_step = 4;
+
+       dev_info(&pdev->dev, "base_addr=%#lx conf_addr=%p irq=%d\n",
+                dev->base_addr, board->conf_addr, dev->irq);
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       /* Register SJA1000 device */
+       err = register_sja1000dev(dev);
+       if (err) {
+               dev_err(&pdev->dev, "Registering device failed (err=%d)\n",
+                       err);
+               goto failure;
+       }
+
+       if (channel == 0)
+               *master_dev = dev;
+
+       return 0;
+
+failure:
+       kvaser_pci_del_chan(dev);
+       return err;
+}
+
+static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
+                                        const struct pci_device_id *ent)
+{
+       int err;
+       struct net_device *master_dev = NULL;
+       struct sja1000_priv *priv;
+       struct kvaser_pci *board;
+       int no_channels;
+       void __iomem *base_addr = NULL;
+       void __iomem *conf_addr = NULL;
+       void __iomem *res_addr = NULL;
+       int i;
+
+       dev_info(&pdev->dev, "initializing device %04x:%04x\n",
+                pdev->vendor, pdev->device);
+
+       err = pci_enable_device(pdev);
+       if (err)
+               goto failure;
+
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err)
+               goto failure_release_pci;
+
+       /*S5920*/
+       conf_addr = pci_iomap(pdev, 0, PCI_CONFIG_PORT_SIZE);
+       if (conf_addr == 0) {
+               err = -ENODEV;
+               goto failure_iounmap;
+       }
+
+       /*XILINX board wide address*/
+       res_addr = pci_iomap(pdev, 2, PCI_PORT_XILINX_SIZE);
+       if (res_addr == 0) {
+               err = -ENOMEM;
+               goto failure_iounmap;
+       }
+
+       base_addr = pci_iomap(pdev, 1, PCI_PORT_SIZE);
+       if (base_addr == 0) {
+               err = -ENOMEM;
+               goto failure_iounmap;
+       }
+
+       no_channels = number_of_sja1000_chip(base_addr);
+       if (no_channels == 0) {
+               err = -ENOMEM;
+               goto failure_iounmap;
+       }
+
+       for (i = 0; i < no_channels; i++) {
+               err = kvaser_pci_add_chan(pdev, i, &master_dev,
+                                         conf_addr, res_addr,
+                                         (unsigned long)base_addr);
+               if (err)
+                       goto failure_cleanup;
+       }
+
+       priv = netdev_priv(master_dev);
+       board = priv->priv;
+
+       dev_info(&pdev->dev, "xilinx version=%d number of channels=%d\n",
+                board->xilinx_ver, board->no_channels);
+
+       pci_set_drvdata(pdev, master_dev);
+       return 0;
+
+failure_cleanup:
+       kvaser_pci_del_chan(master_dev);
+
+failure_iounmap:
+       if (conf_addr == 0)
+               pci_iounmap(pdev, conf_addr);
+       if (res_addr == 0)
+               pci_iounmap(pdev, res_addr);
+       if (base_addr == 0)
+               pci_iounmap(pdev, base_addr);
+
+       pci_release_regions(pdev);
+
+failure_release_pci:
+       pci_disable_device(pdev);
+
+failure:
+       return err;
+
+}
+
+static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       kvaser_pci_del_chan(dev);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver kvaser_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = kvaser_pci_tbl,
+       .probe = kvaser_pci_init_one,
+       .remove = __devexit_p(kvaser_pci_remove_one),
+};
+
+static int __init kvaser_pci_init(void)
+{
+       return pci_register_driver(&kvaser_pci_driver);
+}
+
+static void __exit kvaser_pci_exit(void)
+{
+       pci_unregister_driver(&kvaser_pci_driver);
+}
+
+module_init(kvaser_pci_init);
+module_exit(kvaser_pci_exit);
diff --git a/kernel/2.6/drivers/net/can/sja1000/pcm027.c b/kernel/2.6/drivers/net/can/sja1000/pcm027.c
new file mode 100644 (file)
index 0000000..efd768f
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Copyright (C) 2005 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+
+#include <asm/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME "can-pcm027"
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("Socket-CAN driver for Phytec PCM027 board");
+MODULE_SUPPORTED_DEVICE("Phytec PCM027 board");
+MODULE_LICENSE("GPL v2");
+
+#define PCM027_CAN_CLOCK  (16000000 / 2)
+
+#define PCM027_OCR       (OCR_TX1_PULLDOWN | OCR_TX0_PUSHPULL)
+#define PCM027_CDR       CDR_CBP
+
+static u8 pcm027_read_reg(struct net_device *dev, int reg)
+{
+       return ioread8(dev->base_addr + reg);
+}
+
+static void pcm027_write_reg(struct net_device *dev, int reg, u8 val)
+{
+       iowrite8(val, dev->base_addr + reg);
+}
+
+static int pcm027_probe(struct platform_device *pdev)
+{
+       int err, irq;
+       void __iomem *addr = 0;
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+       struct resource *res;
+
+       err = -ENODEV;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (!res || !irq)
+               goto exit;
+
+       err = -EBUSY;
+       if (!request_mem_region(res->start, res->end - res->start + 1,
+                               DRV_NAME)) {
+               goto exit;
+       }
+
+       err = -ENOMEM;
+       addr = ioremap_nocache(res->start, res->end - res->start + 1);
+       if (!addr) {
+               goto exit_release;
+       }
+
+       dev = alloc_sja1000dev(0);
+       if (!dev)
+               goto exit_iounmap;
+
+       priv = netdev_priv(dev);
+
+       priv->read_reg = pcm027_read_reg;
+       priv->write_reg = pcm027_write_reg;
+       priv->can.can_sys_clock = PCM027_CAN_CLOCK;
+       priv->ocr = PCM027_OCR;
+       priv->cdr = PCM027_CDR;
+
+       dev->irq = irq;
+       dev->base_addr = (unsigned long)addr;
+
+       dev_set_drvdata(&pdev->dev, dev);
+
+       err = register_sja1000dev(dev);
+       if (err) {
+               dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+                       DRV_NAME, err);
+               goto exit_free;
+       }
+
+       printk("%s: %s device registered (base_addr=%#lx, irq=%d)\n",
+              dev->name, DRV_NAME, dev->base_addr, dev->irq);
+       return 0;
+
+exit_free:
+       free_sja1000dev(dev);
+exit_iounmap:
+       iounmap(addr);
+exit_release:
+       release_mem_region(res->start, res->end - res->start + 1);
+exit:
+       return err;
+}
+
+static int pcm027_remove (struct platform_device *pdev)
+{
+       struct net_device *dev = dev_get_drvdata(&pdev->dev);
+       struct resource *res;
+
+       dev_set_drvdata(&pdev->dev, NULL);
+       unregister_sja1000dev(dev);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, res->end - res->start + 1);
+
+       if (dev->base_addr)
+               iounmap ((void *)dev->base_addr);
+
+       free_sja1000dev(dev);
+
+       return 0;
+}
+
+static int pcm027_suspend (struct platform_device *pdev,
+                                  pm_message_t state)
+{
+       dev_err(&pdev->dev, "suspend not implented\n");
+       return 0;
+}
+
+
+static int pcm027_resume (struct platform_device *pdev)
+{
+        dev_err(&pdev->dev, "resume not implemented\n");
+       return 0;
+}
+
+static struct platform_driver pcm027_driver = {
+       .probe = pcm027_probe,
+       .remove = pcm027_remove,
+       .suspend = pcm027_suspend,
+       .resume = pcm027_resume,
+       .driver = {
+               .name = "pcm027can",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init pcm027_init(void)
+{
+       return platform_driver_register(&pcm027_driver);
+}
+
+static void __exit pcm027_exit(void)
+{
+       platform_driver_unregister(&pcm027_driver);
+}
+
+module_init(pcm027_init);
+module_exit(pcm027_exit);
diff --git a/kernel/2.6/drivers/net/can/sja1000/peak_pci.c b/kernel/2.6/drivers/net/can/sja1000/peak_pci.c
new file mode 100644 (file)
index 0000000..4b1510b
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Derived from the PCAN project file driver/src/pcan_pci.c:
+ *
+ * Copyright (C) 2001-2006  PEAK System-Technik GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <asm/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME  "can-peak-pci"
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI cards");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI CAN card");
+MODULE_LICENSE("GPL v2");
+
+struct peak_pci {
+       int channel;
+       struct pci_dev *pci_dev;
+       struct net_device *slave_dev;
+       volatile void __iomem *conf_addr;
+};
+
+#define PEAK_PCI_SINGLE             0  /* single channel device */
+#define PEAK_PCI_MASTER             1  /* multi channel master device */
+#define PEAK_PCI_SLAVE      2  /* multi channel slave device */
+
+#define PEAK_PCI_CAN_CLOCK   (16000000 / 2)
+
+#define PEAK_PCI_CDR_SINGLE  (CDR_CBP | CDR_CLKOUT_MASK | CDR_CLK_OFF)
+#define PEAK_PCI_CDR_MASTER  (CDR_CBP | CDR_CLKOUT_MASK)
+
+#define PEAK_PCI_OCR        OCR_TX0_PUSHPULL
+
+/*
+ * Important PITA registers
+ */
+#define PITA_ICR            0x00       /* interrupt control register */
+#define PITA_GPIOICR        0x18       /* general purpose I/O interface
+                                          control register */
+#define PITA_MISC           0x1C       /* miscellanoes register */
+
+#define PCI_CONFIG_PORT_SIZE 0x1000    /* size of the config io-memory */
+#define PCI_PORT_SIZE        0x0400    /* size of a channel io-memory */
+
+#define PEAK_PCI_VENDOR_ID   0x001C    /* the PCI device and vendor IDs */
+#define PEAK_PCI_DEVICE_ID   0x0001
+
+static struct pci_device_id peak_pci_tbl[] = {
+       {PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+        { 0,}
+};
+
+MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
+
+static u8 peak_pci_read_reg(struct net_device *dev, int port)
+{
+       u8 val;
+       val = readb((const volatile void __iomem *)
+                   (dev->base_addr + (port << 2)));
+       return val;
+}
+
+static void peak_pci_write_reg(struct net_device *dev, int port, u8 val)
+{
+       writeb(val, (volatile void __iomem *)
+              (dev->base_addr + (port << 2)));
+}
+
+static void peak_pci_post_irq(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct peak_pci *board = priv->priv;
+       u16 icr_low;
+
+       /* Select and clear in Pita stored interrupt */
+       icr_low = readw(board->conf_addr + PITA_ICR);
+       if (board->channel == PEAK_PCI_SLAVE) {
+               if (icr_low & 0x0001)
+                       writew(0x0001, board->conf_addr + PITA_ICR);
+       } else {
+               if (icr_low & 0x0002)
+                       writew(0x0002, board->conf_addr + PITA_ICR);
+       }
+}
+
+static void peak_pci_del_chan(struct net_device *dev, int init_step)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct peak_pci *board;
+       u16 icr_high;
+
+       if (!dev || !(priv = netdev_priv(dev)) || !(board = priv->priv))
+               return;
+
+       switch (init_step) {
+       case 0:         /* Full cleanup */
+               printk("Removing %s device %s\n", DRV_NAME, dev->name);
+               unregister_sja1000dev(dev);
+       case 4:
+               icr_high = readw(board->conf_addr + PITA_ICR + 2);
+               if (board->channel == PEAK_PCI_SLAVE) {
+                       icr_high &= ~0x0001;
+               } else {
+                       icr_high &= ~0x0002;
+               }
+               writew(icr_high, board->conf_addr + PITA_ICR + 2);
+       case 3:
+               iounmap((void *)dev->base_addr);
+       case 2:
+               if (board->channel != PEAK_PCI_SLAVE)
+                       iounmap((void *)board->conf_addr);
+       case 1:
+               free_sja1000dev(dev);
+               break;
+       }
+
+}
+
+static int peak_pci_add_chan(struct pci_dev *pdev, int channel,
+                            struct net_device **master_dev)
+{
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+       struct peak_pci *board;
+       u16 icr_high;
+       unsigned long addr;
+       int err, init_step;
+
+       dev = alloc_sja1000dev(sizeof(struct peak_pci));
+       if (dev == NULL)
+               return -ENOMEM;
+       init_step = 1;
+
+       priv = netdev_priv(dev);
+       board = priv->priv;
+
+       board->pci_dev = pdev;
+       board->channel = channel;
+
+       if (channel != PEAK_PCI_SLAVE) {
+
+               addr = pci_resource_start(pdev, 0);
+               board->conf_addr = ioremap(addr, PCI_CONFIG_PORT_SIZE);
+               if (board->conf_addr == 0) {
+                       err = -ENODEV;
+                       goto failure;
+               }
+               init_step = 2;
+
+               /* Set GPIO control register */
+               writew(0x0005, board->conf_addr + PITA_GPIOICR + 2);
+
+               /* Enable single or dual channel */
+               if (channel == PEAK_PCI_MASTER)
+                       writeb(0x00, board->conf_addr + PITA_GPIOICR);
+               else
+                       writeb(0x04, board->conf_addr + PITA_GPIOICR);
+               /* Toggle reset */
+               writeb(0x05, board->conf_addr + PITA_MISC + 3);
+               mdelay(5);
+               /* Leave parport mux mode */
+               writeb(0x04, board->conf_addr + PITA_MISC + 3);
+       } else {
+               struct sja1000_priv *master_priv = netdev_priv(*master_dev);
+               struct peak_pci *master_board = master_priv->priv;
+               master_board->slave_dev = dev;
+               board->conf_addr = master_board->conf_addr;
+       }
+
+       addr = pci_resource_start(pdev, 1);
+       if (channel == PEAK_PCI_SLAVE)
+               addr += PCI_PORT_SIZE;
+
+       dev->base_addr = (unsigned long)ioremap(addr, PCI_PORT_SIZE);
+       if (dev->base_addr == 0) {
+               err = -ENOMEM;
+               goto failure;
+       }
+       init_step = 3;
+
+       priv->read_reg = peak_pci_read_reg;
+       priv->write_reg = peak_pci_write_reg;
+       priv->post_irq = peak_pci_post_irq;
+
+       priv->can.can_sys_clock = PEAK_PCI_CAN_CLOCK;
+
+       priv->ocr = PEAK_PCI_OCR;
+
+       if (channel == PEAK_PCI_MASTER)
+               priv->cdr = PEAK_PCI_CDR_MASTER;
+       else
+               priv->cdr = PEAK_PCI_CDR_SINGLE;
+
+       /* Register and setup interrupt handling */
+       dev->irq = pdev->irq;
+       icr_high = readw(board->conf_addr + PITA_ICR + 2);
+       if (channel == PEAK_PCI_SLAVE) {
+               icr_high |= 0x0001;
+       } else {
+               icr_high |= 0x0002;
+       }
+       writew(icr_high, board->conf_addr + PITA_ICR + 2);
+       init_step = 4;
+
+       printk("%s: base_addr=%#lx conf_addr=%p irq=%d\n", DRV_NAME,
+              dev->base_addr, board->conf_addr, dev->irq);
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       /* Register SJA1000 device */
+       err = register_sja1000dev(dev);
+       if (err) {
+               printk(KERN_ERR "Registering %s device failed (err=%d)\n",
+                      DRV_NAME, err);
+               goto failure;
+       }
+
+       if (channel != PEAK_PCI_SLAVE)
+               *master_dev = dev;
+
+       return 0;
+
+failure:
+       peak_pci_del_chan(dev, init_step);
+       return err;
+}
+
+static int __devinit peak_pci_init_one(struct pci_dev *pdev,
+                                      const struct pci_device_id *ent)
+{
+       int err;
+       u16 sub_sys_id;
+       struct net_device *master_dev = NULL;
+
+       printk("%s: initializing device %04x:%04x\n",
+              DRV_NAME, pdev->vendor, pdev->device);
+
+       if ((err = pci_enable_device(pdev)))
+               goto failure;
+
+       if ((err = pci_request_regions(pdev, DRV_NAME)))
+               goto failure;
+
+       if ((err = pci_read_config_word(pdev, 0x2e, &sub_sys_id)))
+               goto failure_cleanup;
+
+       if ((err = pci_write_config_word(pdev, 0x44, 0)))
+               goto failure_cleanup;
+
+       if (sub_sys_id > 3) {
+               if ((err = peak_pci_add_chan(pdev, PEAK_PCI_MASTER,
+                                            &master_dev)))
+                       goto failure_cleanup;
+               if ((err = peak_pci_add_chan(pdev, PEAK_PCI_SLAVE,
+                                            &master_dev)))
+                       goto failure_cleanup;
+       } else {
+               if ((err = peak_pci_add_chan(pdev, PEAK_PCI_SINGLE,
+                                            &master_dev)))
+                       goto failure_cleanup;
+       }
+
+       pci_set_drvdata(pdev, master_dev);
+       return 0;
+
+failure_cleanup:
+       if (master_dev)
+               peak_pci_del_chan(master_dev, 0);
+
+       pci_release_regions(pdev);
+
+failure:
+       return err;
+
+}
+
+static void __devexit peak_pci_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct peak_pci *board = priv->priv;
+
+       if (board->slave_dev)
+               peak_pci_del_chan(board->slave_dev, 0);
+       peak_pci_del_chan(dev, 0);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver peak_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = peak_pci_tbl,
+       .probe = peak_pci_init_one,
+       .remove = __devexit_p(peak_pci_remove_one),
+};
+
+static int __init peak_pci_init(void)
+{
+       return pci_register_driver(&peak_pci_driver);
+}
+
+static void __exit peak_pci_exit(void)
+{
+       pci_unregister_driver(&peak_pci_driver);
+}
+
+module_init(peak_pci_init);
+module_exit(peak_pci_exit);
diff --git a/kernel/2.6/drivers/net/can/sja1000/sja1000.c b/kernel/2.6/drivers/net/can/sja1000/sja1000.c
new file mode 100644 (file)
index 0000000..6374020
--- /dev/null
@@ -0,0 +1,809 @@
+/*
+ * sja1000.c -  Philips SJA1000 network device driver
+ *
+ * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
+ * 38106 Braunschweig, GERMANY
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/dev.h>
+#include <linux/can/ioctl.h>   /* for struct can_device_stats */
+
+#include "sja1000.h"
+
+#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+RCSID("$Id: sja1000.c 531 2007-10-19 07:38:29Z hartkopp $");
+
+MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("Socketcan " CHIP_NAME " network device driver");
+
+#define CONFIG_CAN_DEBUG_DEVICES
+#ifdef CONFIG_CAN_DEBUG_DEVICES
+#define DBG(args...)   ((debug > 0) ? printk(args) : 0)
+/* logging in interrupt context! */
+#define iDBG(args...)  ((debug > 1) ? printk(args) : 0)
+#define iiDBG(args...) ((debug > 2) ? printk(args) : 0)
+#else
+#define DBG(args...)
+#define iDBG(args...)
+#define iiDBG(args...)
+#endif
+
+/* driver and version information */
+static const char *drv_name = "SJA1000";
+static const char *drv_version = "0.2.0";
+static const char *drv_reldate = "2007-10-25";
+
+#ifdef CONFIG_CAN_DEBUG_DEVICES
+static const char *ecc_errors[] = {
+       NULL,
+       NULL,
+       "ID.28 to ID.28",
+       "start of frame",
+       "bit SRTR",
+       "bit IDE",
+       "ID.20 to ID.18",
+       "ID.17 to ID.13",
+       "CRC sequence",
+       "reserved bit 0",
+       "data field",
+       "data length code",
+       "bit RTR",
+       "reserved bit 1",
+       "ID.4 to ID.0",
+       "ID.12 to ID.5",
+       NULL,
+       "active error flag",
+       "intermission",
+       "tolerate dominant bits",
+       NULL,
+       NULL,
+       "passive error flag",
+       "error delimiter",
+       "CRC delimiter",
+       "acknowledge slot",
+       "end of frame",
+       "acknowledge delimiter",
+       "overload flag",
+       NULL,
+       NULL,
+       NULL
+};
+
+static const char *ecc_types[] = {
+       "bit error",
+       "form error",
+       "stuff error",
+       "other type of error"
+};
+#endif
+
+static int debug = 0;
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(debug, "Set debug mask (default: 0)");
+
+
+static int sja1000_probe_chip(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       if (dev->base_addr && (priv->read_reg(dev, 0) == 0xFF)) {
+               printk(KERN_INFO "%s: probing @0x%lX failed\n",
+                      drv_name, dev->base_addr);
+               return 0;
+       }
+       return 1;
+}
+
+int set_reset_mode(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       unsigned char status = priv->read_reg(dev, REG_MOD);
+       int i;
+
+       /* disable interrupts */
+       priv->write_reg(dev, REG_IER, IRQ_OFF);
+
+       for (i = 0; i < 100; i++) {
+               /* check reset bit */
+               if (status & MOD_RM) {
+                       if (i > 1) {
+                               iDBG(KERN_INFO "%s: %s looped %d times\n",
+                                    dev->name, __FUNCTION__, i);
+                       }
+                       priv->can.state = CAN_STATE_STOPPED;
+                       return 0;
+               }
+
+               priv->write_reg(dev, REG_MOD, MOD_RM);  /* reset chip */
+               status = priv->read_reg(dev, REG_MOD);
+               udelay(10);
+       }
+
+       dev_err(ND2D(dev), "setting SJA1000 into reset mode failed!\n");
+       return 1;
+
+}
+
+static int set_normal_mode(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       unsigned char status = priv->read_reg(dev, REG_MOD);
+       int i;
+
+       for (i = 0; i < 100; i++) {
+               /* check reset bit */
+               if ((status & MOD_RM) == 0) {
+#ifdef CONFIG_CAN_DEBUG_DEVICES
+                       if (i > 1) {
+                               iDBG(KERN_INFO "%s: %s looped %d times\n",
+                                    dev->name, __FUNCTION__, i);
+                       }
+#endif
+                       priv->can.state = CAN_STATE_ACTIVE;
+                       /* enable all interrupts */
+                       priv->write_reg(dev, REG_IER, IRQ_ALL);
+
+                       return 0;
+               }
+
+               /* set chip to normal mode */
+               priv->write_reg(dev, REG_MOD, 0x00);
+               status = priv->read_reg(dev, REG_MOD);
+               udelay(10);
+       }
+
+       dev_err(ND2D(dev), "setting SJA1000 into normal mode failed!\n");
+       return 1;
+
+}
+
+static void sja1000_start(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       iDBG(KERN_INFO "%s: %s()\n", dev->name, __FUNCTION__);
+
+       /* leave reset mode */
+       if (priv->can.state != CAN_STATE_STOPPED)
+               set_reset_mode(dev);
+
+       /* Clear error counters and error code capture */
+       priv->write_reg(dev, REG_TXERR, 0x0);
+       priv->write_reg(dev, REG_RXERR, 0x0);
+       priv->read_reg(dev, REG_ECC);
+
+       /* leave reset mode */
+       set_normal_mode(dev);
+}
+
+static int sja1000_set_mode(struct net_device *dev, can_mode_t mode)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       switch (mode) {
+       case CAN_MODE_START:
+               DBG("%s: CAN_MODE_START requested\n", __FUNCTION__);
+               if (!priv->open_time)
+                       return -EINVAL;
+
+               sja1000_start(dev);
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int sja1000_get_state(struct net_device *dev, can_state_t *state)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       u8 status;
+
+       /* FIXME: inspecting the status register to get the current state
+        * is not really necessary, because state changes are handled by
+        * in the ISR and the variable priv->can.state gets updated. The
+        * CAN devicde interface needs fixing!
+        */
+
+       spin_lock_irq(&priv->can.irq_lock);
+
+       if (priv->can.state == CAN_STATE_STOPPED) {
+               *state =  CAN_STATE_STOPPED;
+       } else {
+               status = priv->read_reg(dev, REG_SR);
+               if (status & SR_BS)
+                       *state = CAN_STATE_BUS_OFF;
+               else if (status & SR_ES) {
+                       if (priv->read_reg(dev, REG_TXERR) > 127 ||
+                           priv->read_reg(dev, REG_RXERR) > 127 )
+                               *state = CAN_STATE_BUS_PASSIVE;
+                       else
+                               *state = CAN_STATE_BUS_WARNING;
+               }
+               else
+                       *state = CAN_STATE_ACTIVE;
+       }
+#ifdef CONFIG_CAN_DEBUG_DEVICES
+       /* Check state */
+       if (*state != priv->can.state)
+               dev_err(ND2D(dev),
+                       "Oops, state mismatch: hard %d != soft %d\n",
+                       *state, priv->can.state);
+#endif
+       spin_unlock_irq(&priv->can.irq_lock);
+       return 0;
+}
+
+static int sja1000_set_bittime(struct net_device *dev, struct can_bittime *bt)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       u8 btr0, btr1;
+
+       switch (bt->type) {
+       case CAN_BITTIME_BTR:
+               btr0 = bt->btr.btr0;
+               btr1 = bt->btr.btr1;
+               break;
+
+       case CAN_BITTIME_STD:
+               btr0 = ((bt->std.brp - 1) & 0x3f) |
+                   (((bt->std.sjw - 1) & 0x3) << 6);
+               btr1 = ((bt->std.prop_seg +
+                        bt->std.phase_seg1 - 1) & 0xf) |
+                   (((bt->std.phase_seg2 - 1) & 0x7) << 4) |
+                   ((bt->std.sam & 1) << 7);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       DBG("%s: BTR0 0x%02x BTR1 0x%02x\n", dev->name, btr0, btr1);
+
+       priv->write_reg(dev, REG_BTR0, btr0);
+       priv->write_reg(dev, REG_BTR1, btr1);
+
+       return 0;
+}
+
+/*
+ * initialize SJA1000 chip:
+ *   - reset chip
+ *   - set output mode
+ *   - set baudrate
+ *   - enable interrupts
+ *   - start operating mode
+ */
+static void chipset_init(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       /* set clock divider and output control register */
+       priv->write_reg(dev, REG_CDR, priv->cdr | CDR_PELICAN);
+
+       /* set acceptance filter (accept all) */
+       priv->write_reg(dev, REG_ACCC0, 0x00);
+       priv->write_reg(dev, REG_ACCC1, 0x00);
+       priv->write_reg(dev, REG_ACCC2, 0x00);
+       priv->write_reg(dev, REG_ACCC3, 0x00);
+
+       priv->write_reg(dev, REG_ACCM0, 0xFF);
+       priv->write_reg(dev, REG_ACCM1, 0xFF);
+       priv->write_reg(dev, REG_ACCM2, 0xFF);
+       priv->write_reg(dev, REG_ACCM3, 0xFF);
+
+       priv->write_reg(dev, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
+}
+
+/*
+ * transmit a CAN message
+ * message layout in the sk_buff should be like this:
+ * xx xx xx xx  ff      ll   00 11 22 33 44 55 66 77
+ * [  can-id ] [flags] [len] [can data (up to 8 bytes]
+ */
+static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = dev->get_stats(dev);
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       uint8_t fi;
+       uint8_t dlc;
+       canid_t id;
+       uint8_t dreg;
+       int i;
+
+       netif_stop_queue(dev);
+
+       fi = dlc = cf->can_dlc;
+       id = cf->can_id;
+
+       if (id & CAN_RTR_FLAG)
+               fi |= FI_RTR;
+
+       if (id & CAN_EFF_FLAG) {
+               fi |= FI_FF;
+               dreg = EFF_BUF;
+               priv->write_reg(dev, REG_FI, fi);
+               priv->write_reg(dev, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
+               priv->write_reg(dev, REG_ID2, (id & 0x001fe000) >> (5 + 8));
+               priv->write_reg(dev, REG_ID3, (id & 0x00001fe0) >> 5);
+               priv->write_reg(dev, REG_ID4, (id & 0x0000001f) << 3);
+       } else {
+               dreg = SFF_BUF;
+               priv->write_reg(dev, REG_FI, fi);
+               priv->write_reg(dev, REG_ID1, (id & 0x000007f8) >> 3);
+               priv->write_reg(dev, REG_ID2, (id & 0x00000007) << 5);
+       }
+
+       for (i = 0; i < dlc; i++) {
+               priv->write_reg(dev, dreg++, cf->data[i]);
+       }
+
+       stats->tx_bytes += dlc;
+       dev->trans_start = jiffies;
+
+       can_put_echo_skb(skb, dev, 0);
+
+       priv->write_reg(dev, REG_CMR, CMD_TR);
+
+       return 0;
+}
+
+static void sja1000_rx(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = dev->get_stats(dev);
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       uint8_t fi;
+       uint8_t dreg;
+       canid_t id;
+       uint8_t dlc;
+       int i;
+
+       skb = dev_alloc_skb(sizeof(struct can_frame));
+       if (skb == NULL)
+               return;
+       skb->dev = dev;
+       skb->protocol = htons(ETH_P_CAN);
+
+       fi = priv->read_reg(dev, REG_FI);
+       dlc = fi & 0x0F;
+
+       if (fi & FI_FF) {
+               /* extended frame format (EFF) */
+               dreg = EFF_BUF;
+               id = (priv->read_reg(dev, REG_ID1) << (5 + 16))
+                   | (priv->read_reg(dev, REG_ID2) << (5 + 8))
+                   | (priv->read_reg(dev, REG_ID3) << 5)
+                   | (priv->read_reg(dev, REG_ID4) >> 3);
+               id |= CAN_EFF_FLAG;
+       } else {
+               /* standard frame format (SFF) */
+               dreg = SFF_BUF;
+               id = (priv->read_reg(dev, REG_ID1) << 3)
+                   | (priv->read_reg(dev, REG_ID2) >> 5);
+       }
+
+       if (fi & FI_RTR)
+               id |= CAN_RTR_FLAG;
+
+       cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+       memset(cf, 0, sizeof(struct can_frame));
+       cf->can_id = id;
+       cf->can_dlc = dlc;
+       for (i = 0; i < dlc; i++) {
+               cf->data[i] = priv->read_reg(dev, dreg++);
+       }
+       while (i < 8)
+               cf->data[i++] = 0;
+
+       /* release receive buffer */
+       priv->write_reg(dev, REG_CMR, CMD_RRB);
+
+       netif_rx(skb);
+
+       dev->last_rx = jiffies;
+       stats->rx_packets++;
+       stats->rx_bytes += dlc;
+}
+
+static int sja1000_err(struct net_device *dev,
+                      uint8_t isrc, uint8_t status, int n)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = dev->get_stats(dev);
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       can_state_t state = priv->can.state;
+       uint8_t ecc, alc;
+
+       skb = dev_alloc_skb(sizeof(struct can_frame));
+       if (skb == NULL)
+               return -ENOMEM;
+       skb->dev = dev;
+       skb->protocol = htons(ETH_P_CAN);
+       cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+       memset(cf, 0, sizeof(struct can_frame));
+       cf->can_id = CAN_ERR_FLAG;
+       cf->can_dlc = CAN_ERR_DLC;
+
+       if (isrc & IRQ_DOI) {
+               /* data overrun interrupt */
+               iiDBG(KERN_INFO "%s: data overrun isrc=0x%02X "
+                     "status=0x%02X\n", dev->name, isrc, status);
+               iDBG(KERN_INFO "%s: DOI #%d#\n", dev->name, n);
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+               priv->can.can_stats.data_overrun++;
+               priv->write_reg(dev, REG_CMR, CMD_CDO); /* clear bit */
+       }
+
+       if (isrc & IRQ_EI) {
+               /* error warning interrupt */
+               iiDBG(KERN_INFO "%s: error warning isrc=0x%02X "
+                     "status=0x%02X\n", dev->name, isrc, status);
+               iDBG(KERN_INFO "%s: EI #%d#\n", dev->name, n);
+               priv->can.can_stats.error_warning++;
+
+               if (status & SR_BS) {
+                       state = CAN_STATE_BUS_OFF;
+                       cf->can_id |= CAN_ERR_BUSOFF;
+                       can_bus_off(dev);
+                       iDBG(KERN_INFO "%s: BUS OFF\n", dev->name);
+               } else if (status & SR_ES) {
+                       state = CAN_STATE_BUS_WARNING;
+                       iDBG(KERN_INFO "%s: error\n", dev->name);
+               } else
+                       state = CAN_STATE_ACTIVE;
+       }
+       if (isrc & IRQ_BEI) {
+               /* bus error interrupt */
+               iiDBG(KERN_INFO "%s: bus error isrc=0x%02X "
+                     "status=0x%02X\n", dev->name, isrc, status);
+               iDBG(KERN_INFO "%s: BEI #%d# [%d]\n", dev->name, n,
+                    priv->can.can_stats.bus_error);
+               priv->can.can_stats.bus_error++;
+               ecc = priv->read_reg(dev, REG_ECC);
+               iDBG(KERN_INFO "%s: ECC = 0x%02X (%s, %s, %s)\n",
+                    dev->name, ecc,
+                    (ecc & ECC_DIR) ? "RX" : "TX",
+                    ecc_types[ecc >> ECC_ERR],
+                    ecc_errors[ecc & ECC_SEG]);
+
+               cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+               switch (ecc & ECC_MASK) {
+               case ECC_BIT:
+                       cf->data[2] |= CAN_ERR_PROT_BIT;
+                       break;
+               case ECC_FORM:
+                       cf->data[2] |= CAN_ERR_PROT_FORM;
+                       break;
+               case ECC_STUFF:
+                       cf->data[2] |= CAN_ERR_PROT_STUFF;
+                       break;
+               default:
+                       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+                       cf->data[3] = ecc & ECC_SEG;
+                       break;
+               }
+               /* Error occured during transmission? */
+               if ((ecc & ECC_DIR) == 0)
+                       cf->data[2] |= CAN_ERR_PROT_TX;
+       }
+       if (isrc & IRQ_EPI) {
+               /* error passive interrupt */
+               iiDBG(KERN_INFO "%s: error passive isrc=0x%02X"
+                     " status=0x%02X\n", dev->name, isrc, status);
+               iDBG(KERN_INFO "%s: EPI #%d#\n", dev->name, n);
+               priv->can.can_stats.error_passive++;
+               if (status & SR_ES) {
+                       iDBG(KERN_INFO "%s: ERROR PASSIVE\n", dev->name);
+                       state = CAN_STATE_BUS_PASSIVE;
+               } else {
+                       iDBG(KERN_INFO "%s: ERROR ACTIVE\n", dev->name);
+                       state = CAN_STATE_ACTIVE;
+               }
+       }
+       if (isrc & IRQ_ALI) {
+               /* arbitration lost interrupt */
+               iiDBG(KERN_INFO "%s: error arbitration lost "
+                     "isrc=0x%02X status=0x%02X\n",
+                     dev->name, isrc, status);
+               iDBG(KERN_INFO "%s: ALI #%d#\n", dev->name, n);
+               alc = priv->read_reg(dev, REG_ALC);
+               iDBG(KERN_INFO "%s: ALC = 0x%02X\n", dev->name, alc);
+               priv->can.can_stats.arbitration_lost++;
+               cf->can_id |= CAN_ERR_LOSTARB;
+               cf->data[0] = alc & 0x1f;
+       }
+
+       if (state != priv->can.state && (state == CAN_STATE_BUS_WARNING ||
+                                        state == CAN_STATE_BUS_PASSIVE)) {
+               uint8_t rxerr = priv->read_reg(dev, REG_RXERR);
+               uint8_t txerr = priv->read_reg(dev, REG_TXERR);
+               cf->can_id |= CAN_ERR_CRTL;
+               if (state == CAN_STATE_BUS_WARNING)
+                       cf->data[1] = (txerr > rxerr) ?
+                               CAN_ERR_CRTL_TX_WARNING :
+                               CAN_ERR_CRTL_RX_WARNING;
+               else
+                       cf->data[1] = (txerr > rxerr) ?
+                               CAN_ERR_CRTL_TX_PASSIVE :
+                               CAN_ERR_CRTL_RX_PASSIVE;
+       }
+
+       priv->can.state = state;
+
+       netif_rx(skb);
+
+       dev->last_rx = jiffies;
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+
+       return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static irqreturn_t sja1000_interrupt(int irq, void *dev_id,
+                                    struct pt_regs *regs)
+#else
+static irqreturn_t sja1000_interrupt(int irq, void *dev_id)
+#endif
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = dev->get_stats(dev);
+       uint8_t isrc, status;
+       int n = 0;
+
+       if (priv->pre_irq)
+               priv->pre_irq(dev);
+
+       iiDBG(KERN_INFO "%s: interrupt\n", dev->name);
+
+       if (priv->can.state == CAN_STATE_STOPPED) {
+               iiDBG(KERN_ERR "%s: %s: controller is in reset mode! "
+                     "MOD=0x%02X IER=0x%02X IR=0x%02X SR=0x%02X!\n",
+                     dev->name, __FUNCTION__, priv->read_reg(dev, REG_MOD),
+                     priv->read_reg(dev, REG_IER), priv->read_reg(dev, REG_IR),
+                     priv->read_reg(dev, REG_SR));
+               goto out;
+       }
+
+       while ((isrc = priv->read_reg(dev, REG_IR)) && (n < 20)) {
+               n++;
+               status = priv->read_reg(dev, REG_SR);
+
+               if (isrc & IRQ_WUI) {
+                       /* wake-up interrupt */
+                       priv->can.can_stats.wakeup++;
+               }
+               if (isrc & IRQ_TI) {
+                       /* transmission complete interrupt */
+                       stats->tx_packets++;
+                       can_get_echo_skb(dev, 0);
+                       netif_wake_queue(dev);
+               }
+               if (isrc & IRQ_RI) {
+                       /* receive interrupt */
+                       while (status & SR_RBS) {
+                               sja1000_rx(dev);
+                               status = priv->read_reg(dev, REG_SR);
+                       }
+               }
+               if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
+                       /* error interrupt */
+                       if (sja1000_err(dev, isrc, status, n))
+                               break;
+               }
+       }
+       if (n > 1) {
+               iDBG(KERN_INFO "%s: handled %d IRQs\n", dev->name, n);
+       }
+
+out:
+       if (priv->post_irq)
+               priv->post_irq(dev);
+
+       return n == 0 ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static int sja1000_open(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       int err;
+
+       /* set chip into reset mode */
+       set_reset_mode(dev);
+
+       /* register interrupt handler */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       err = request_irq(dev->irq, &sja1000_interrupt, SA_SHIRQ,
+                         dev->name, (void *)dev);
+#else
+       err = request_irq(dev->irq, &sja1000_interrupt, IRQF_SHARED,
+                         dev->name, (void *)dev);
+#endif
+       if (err)
+               return -EAGAIN;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       /* clear statistics */
+       memset(&priv->can.net_stats, 0, sizeof(priv->can.net_stats));
+#endif
+
+       /* init and start chi */
+       sja1000_start(dev);
+       priv->open_time = jiffies;
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static int sja1000_close(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       set_reset_mode(dev);
+       netif_stop_queue(dev);
+       priv->open_time = 0;
+       can_close_cleanup(dev);
+       free_irq(dev->irq, (void *)dev);
+
+       return 0;
+}
+
+struct net_device *alloc_sja1000dev(int sizeof_priv)
+{
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+
+       dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv);
+       if (!dev)
+               return NULL;
+
+       priv = netdev_priv(dev);
+       priv->dev = dev;
+
+       if (sizeof_priv)
+               priv->priv = (void *)priv + sizeof(struct sja1000_priv);
+
+       return dev;
+}
+
+EXPORT_SYMBOL_GPL(alloc_sja1000dev);
+
+void free_sja1000dev(struct net_device *dev)
+{
+       free_candev(dev);
+}
+EXPORT_SYMBOL(free_sja1000dev);
+
+int register_sja1000dev(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+       int err;
+
+       if (!sja1000_probe_chip(dev))
+               return -ENODEV;
+
+       dev->flags |= IFF_ECHO; /* we support local echo */
+
+       dev->open = sja1000_open;
+       dev->stop = sja1000_close;
+
+       dev->hard_start_xmit = sja1000_start_xmit;
+
+       priv->can.do_set_bittime = sja1000_set_bittime;
+       priv->can.do_get_state = sja1000_get_state;
+       priv->can.do_set_mode = sja1000_set_mode;
+       priv->dev = dev;
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_INFO
+                      "%s: registering netdev failed\n", CHIP_NAME);
+               free_netdev(dev);
+               return err;
+       }
+
+       set_reset_mode(dev);
+       chipset_init(dev);
+       return 0;
+}
+EXPORT_SYMBOL(register_sja1000dev);
+
+void unregister_sja1000dev(struct net_device *dev)
+{
+       set_reset_mode(dev);
+       unregister_netdev(dev);
+}
+EXPORT_SYMBOL(unregister_sja1000dev);
+
+static __init int sja1000_init(void)
+{
+       printk(KERN_INFO "%s driver v%s (%s)\n",
+              drv_name, drv_version, drv_reldate);
+       printk(KERN_INFO "%s - options [debug %d]\n", drv_name, debug);
+
+       printk("%s driver %s %s loaded\n", drv_name, drv_version, drv_reldate);
+       return 0;
+}
+
+module_init(sja1000_init);
+
+static __exit void sja1000_exit(void)
+{
+       printk("%s driver %s %s unloaded\n",
+              drv_name, drv_version, drv_reldate);
+}
+
+module_exit(sja1000_exit);
diff --git a/kernel/2.6/drivers/net/can/sja1000/sja1000.h b/kernel/2.6/drivers/net/can/sja1000/sja1000.h
new file mode 100644 (file)
index 0000000..e50a03c
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * $Id: sja1000.h 505 2007-09-30 13:32:41Z hartkopp $
+ *
+ * sja1000.h -  Philips SJA1000 network device driver
+ *
+ * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
+ * 38106 Braunschweig, GERMANY
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef SJA1000DEV_H
+#define SJA1000DEV_H
+
+#include <linux/can/dev.h>
+
+#define CHIP_NAME      "SJA1000"
+
+#define TX_TIMEOUT      (50*HZ/1000)   /* 50ms */
+#define RESTART_MS      100    /* restart chip on persistent errors in 100ms */
+#define MAX_BUS_ERRORS  200    /* prevent from flooding bus error interrupts */
+
+/* SJA1000 registers - manual section 6.4 (Pelican Mode) */
+#define REG_MOD                0x00
+#define REG_CMR                0x01
+#define REG_SR         0x02
+#define REG_IR         0x03
+#define REG_IER                0x04
+#define REG_ALC                0x0B
+#define REG_ECC                0x0C
+#define REG_EWL                0x0D
+#define REG_RXERR      0x0E
+#define REG_TXERR      0x0F
+#define REG_ACCC0      0x10
+#define REG_ACCC1      0x11
+#define REG_ACCC2      0x12
+#define REG_ACCC3      0x13
+#define REG_ACCM0      0x14
+#define REG_ACCM1      0x15
+#define REG_ACCM2      0x16
+#define REG_ACCM3      0x17
+#define REG_RMC                0x1D
+#define REG_RBSA       0x1E
+
+/* Common registers - manual section 6.5 */
+#define REG_BTR0       0x06
+#define REG_BTR1       0x07
+#define REG_OCR                0x08
+#define REG_CDR                0x1F
+
+#define REG_FI         0x10
+#define SFF_BUF                0x13
+#define EFF_BUF                0x15
+
+#define FI_FF          0x80
+#define FI_RTR         0x40
+
+#define REG_ID1                0x11
+#define REG_ID2                0x12
+#define REG_ID3                0x13
+#define REG_ID4                0x14
+
+#define CAN_RAM                0x20
+
+/* mode register */
+#define MOD_RM         0x01
+#define MOD_LOM                0x02
+#define MOD_STM                0x04
+#define MOD_AFM                0x08
+#define MOD_SM         0x10
+
+/* commands */
+#define CMD_SRR                0x10
+#define CMD_CDO                0x08
+#define CMD_RRB                0x04
+#define CMD_AT         0x02
+#define CMD_TR         0x01
+
+/* interrupt sources */
+#define IRQ_BEI                0x80
+#define IRQ_ALI                0x40
+#define IRQ_EPI                0x20
+#define IRQ_WUI                0x10
+#define IRQ_DOI                0x08
+#define IRQ_EI         0x04
+#define IRQ_TI         0x02
+#define IRQ_RI         0x01
+#define IRQ_ALL                0xFF
+#define IRQ_OFF                0x00
+
+/* status register content */
+#define SR_BS          0x80
+#define SR_ES          0x40
+#define SR_TS          0x20
+#define SR_RS          0x10
+#define SR_TCS         0x08
+#define SR_TBS         0x04
+#define SR_DOS         0x02
+#define SR_RBS         0x01
+
+#define SR_CRIT (SR_BS|SR_ES)
+
+/* ECC register */
+#define ECC_SEG                0x1F
+#define ECC_DIR                0x20
+#define ECC_ERR                6
+#define ECC_BIT                0x00
+#define ECC_FORM       0x40
+#define ECC_STUFF      0x80
+#define ECC_MASK       0xc0
+
+/* clock divider register */
+#define CDR_CLKOUT_MASK 0x07
+#define CDR_CLK_OFF    0x08 /* Clock off (CLKOUT pin) */
+#define CDR_RXINPEN    0x20 /* TX1 output is RX irq output */
+#define CDR_CBP                0x40 /* CAN input comparator bypass */
+#define CDR_PELICAN    0x80 /* PeliCAN mode */
+
+/* output control register */
+#define OCR_MODE_BIPHASE  0x00
+#define OCR_MODE_TEST     0x01
+#define OCR_MODE_NORMAL   0x02
+#define OCR_MODE_CLOCK    0x03
+#define OCR_TX0_INVERT    0x04
+#define OCR_TX0_PULLDOWN  0x08
+#define OCR_TX0_PULLUP    0x10
+#define OCR_TX0_PUSHPULL  0x18
+#define OCR_TX1_INVERT    0x20
+#define OCR_TX1_PULLDOWN  0x40
+#define OCR_TX1_PULLUP    0x80
+#define OCR_TX1_PUSHPULL  0xc0
+
+/*
+ * SJA1000 private data structure
+ */
+struct sja1000_priv {
+       struct can_priv can;    /* must be the first member! */
+       long open_time;
+       struct sk_buff *echo_skb;
+       u8 (*read_reg) (struct net_device * dev, int reg);
+       void (*write_reg) (struct net_device * dev, int reg, u8 val);
+       void (*pre_irq) (struct net_device * dev);
+       void (*post_irq) (struct net_device * dev);
+       void *priv;             /* for board-specific data */
+       struct net_device *dev;
+       u8 ocr;
+       u8 cdr;
+};
+
+struct net_device *alloc_sja1000dev(int sizeof_priv);
+void free_sja1000dev(struct net_device *dev);
+int register_sja1000dev(struct net_device *dev);
+void unregister_sja1000dev(struct net_device *dev);
+
+#if 0
+void can_proc_create(const char *drv_name);
+void can_proc_remove(const char *drv_name);
+#endif
+
+#endif /* SJA1000_DEV_H */
diff --git a/kernel/2.6/net/can/sysfs.c b/kernel/2.6/net/can/sysfs.c
new file mode 100644 (file)
index 0000000..09ad7e0
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ * $Id: dev.c 542 2007-11-07 13:57:16Z thuermann $
+ *
+ * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <net/sock.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+
+#include "sysfs.h"
+
+#ifdef CONFIG_SYSFS
+/*
+ * Functions to set/get CAN properties used by SYSFS
+ *
+ * FIXME: we may want to check for capabilities!
+ *
+ *        if (!capable(CAP_NET_ADMIN))
+ *             return -EPERM;
+ */
+static int can_get_bitrate(struct net_device *dev, u32 *bitrate)
+{
+       struct can_priv *priv = netdev_priv(dev);
+       *bitrate = priv->bitrate;
+
+       return 0;
+}
+
+static int can_set_custombittime(struct net_device *dev,
+                                struct can_bittime *bt)
+{
+       struct can_priv *priv = netdev_priv(dev);
+       int err = -ENOTSUPP;
+
+       if (priv->state != CAN_STATE_STOPPED)
+               return -EBUSY;
+
+       if (priv->do_set_bittime) {
+               err = priv->do_set_bittime(dev, bt);
+               if (err)
+                       goto out;
+               priv->bittime = *bt;
+               if (bt->type == CAN_BITTIME_STD && bt->std.brp) {
+                       priv->bitrate = priv->can_sys_clock /
+                               (bt->std.brp * (1 + bt->std.prop_seg +
+                                               bt->std.phase_seg1 +
+                                               bt->std.phase_seg2));
+               } else
+                       priv->bitrate = CAN_BITRATE_UNKNOWN;
+       }
+out:
+       return err;
+}
+
+static int can_get_custombittime(struct net_device *dev,
+                                struct can_bittime *bt)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       *bt = priv->bittime;
+       return 0;
+}
+
+static int can_set_ctrlmode(struct net_device *dev, u32 ctrlmode)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       if (!priv->do_set_ctrlmode)
+               return -ENOTSUPP;
+       if (priv->state != CAN_STATE_STOPPED)
+               return -EBUSY;
+
+       return priv->do_set_ctrlmode(dev, ctrlmode);
+}
+
+static int can_get_ctrlmode(struct net_device *dev, u32 *ctrlmode)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       *ctrlmode = priv->ctrlmode;
+       return 0;
+}
+
+static int can_get_state(struct net_device *dev, can_state_t *state)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       if (priv->do_get_state) {
+               int err = priv->do_get_state(dev, state);
+               if (err)
+                       return err;
+               priv->state = *state;
+       } else
+               *state = priv->state;
+       return 0;
+}
+
+static int can_set_clock(struct net_device *dev, u32 clock)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       if (priv->state != CAN_STATE_STOPPED)
+               return -EBUSY;
+
+       priv->can_sys_clock = clock;
+       return 0;
+}
+
+static int can_get_clock(struct net_device *dev, u32 *clock)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       *clock = priv->can_sys_clock;
+       return 0;
+}
+
+static int can_set_restart_ms(struct net_device *dev, int ms)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       if (priv->restart_ms < 0)
+               return -EOPNOTSUPP;
+       priv->restart_ms = ms;
+       return 0;
+}
+
+static int can_get_restart_ms(struct net_device *dev, int *ms)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       *ms = priv->restart_ms;
+       return 0;
+}
+
+static int can_set_echo(struct net_device *dev, int on)
+{
+       if (on)
+               dev->flags |= IFF_ECHO;
+       else
+               dev->flags &= ~IFF_ECHO;
+       return 0;
+}
+
+static int can_get_echo(struct net_device *dev, int *on)
+{
+       *on = dev->flags & IFF_ECHO ? 1 : 0;
+       return 0;
+}
+
+/*
+ * SYSFS access functions and attributes.
+ * Use same locking as net/core/net-sysfs.c
+ */
+static inline int dev_isalive(const struct net_device *dev)
+{
+       return dev->reg_state <= NETREG_REGISTERED;
+}
+
+#define CAN_ATTR(_name, _func, _type, _fmt)                            \
+static ssize_t can_show_##_func(struct device *dev,                    \
+                               struct device_attribute *attr,          \
+                               char *buf)                              \
+{                                                                      \
+       struct net_device *ndev = to_net_dev(dev);                      \
+       _type val;                                                      \
+       int ret = -EINVAL;                                              \
+       read_lock(&dev_base_lock);                                      \
+       if (dev_isalive(ndev)) {                                        \
+               can_get_##_func(ndev, &val);                            \
+               ret = snprintf(buf, PAGE_SIZE, _fmt "\n", val);         \
+       }                                                               \
+       read_unlock(&dev_base_lock);                                    \
+       return ret;                                                     \
+}                                                                      \
+static ssize_t can_store_##_func(struct device *dev,                   \
+                                struct device_attribute *attr,         \
+                                const char *buf, size_t count)         \
+{                                                                      \
+       struct net_device *ndev = to_net_dev(dev);                      \
+       char *endp;                                                     \
+       _type val;                                                      \
+       int ret = -EINVAL;                                              \
+       val = simple_strtoul(buf, &endp, 0);                            \
+       if (endp == buf)                                                \
+               return ret;                                             \
+       rtnl_lock();                                                    \
+       if (dev_isalive(ndev)) {                                        \
+               if ((ret = can_set_##_func(ndev, val)) == 0)            \
+                       ret = count;                                    \
+       }                                                               \
+       rtnl_unlock();                                                  \
+       return ret;                                                     \
+}                                                                      \
+static DEVICE_ATTR(_name, S_IRUGO | S_IWUSR,                           \
+                  can_show_##_func, can_store_##_func)
+
+CAN_ATTR(can_bitrate, bitrate, u32, "%d");
+CAN_ATTR(can_restart_ms, restart_ms, int, "%d");
+CAN_ATTR(can_clock, clock, u32, "%d");
+CAN_ATTR(can_echo, echo, int, "%d");
+
+#define CAN_STATS_ATTR(_name)                                          \
+static ssize_t can_stats_show_##_name(struct device *dev,              \
+                                     struct device_attribute *attr,    \
+                                     char *buf)                        \
+{                                                                      \
+       struct net_device *ndev = to_net_dev(dev);                      \
+       struct can_priv *priv = netdev_priv(ndev);                      \
+       int ret = -EINVAL;                                              \
+       read_lock(&dev_base_lock);                                      \
+       if (dev_isalive(ndev)) {                                        \
+               ret= snprintf(buf, PAGE_SIZE, "%d\n",                   \
+                             priv->can_stats._name);                   \
+       }                                                               \
+       read_unlock(&dev_base_lock);                                    \
+       return ret;                                                     \
+}                                                                      \
+static DEVICE_ATTR(_name, S_IRUGO, can_stats_show_##_name, NULL)
+
+#define CAN_CREATE_FILE(_dev, _name)                                   \
+        if (device_create_file(&_dev->dev, &dev_attr_##_name))         \
+               dev_err(ND2D(_dev),                                     \
+                       "Couldn't create device file for ##_name\n")
+
+#define CAN_REMOVE_FILE(_dev, _name)                                   \
+        device_remove_file(&_dev->dev, &dev_attr_##_name)              \
+
+CAN_STATS_ATTR(error_warning);
+CAN_STATS_ATTR(error_passive);
+CAN_STATS_ATTR(bus_error);
+CAN_STATS_ATTR(arbitration_lost);
+CAN_STATS_ATTR(data_overrun);
+CAN_STATS_ATTR(wakeup);
+CAN_STATS_ATTR(restarts);
+
+static ssize_t can_store_restart(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       int ret = -EINVAL;
+
+       rtnl_lock();
+       if (dev_isalive(ndev)) {
+               if (!(ret = can_restart_now(ndev)))
+                       ret = count;
+       }
+       rtnl_unlock();
+       return ret;
+}
+
+static DEVICE_ATTR(can_restart, S_IWUSR, NULL, can_store_restart);
+
+static const char *can_state_names[] = {
+       "active", "bus-warn", "bus-pass" , "bus-off",
+       "stopped", "sleeping", "unkown"
+};
+
+static ssize_t can_show_state(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       can_state_t state;
+       int ret = -EINVAL;
+
+       read_lock(&dev_base_lock);
+       if (dev_isalive(ndev)) {
+               can_get_state(ndev, &state);
+
+               if (state >= ARRAY_SIZE(can_state_names))
+                       state = ARRAY_SIZE(can_state_names) - 1;
+               ret = snprintf(buf, PAGE_SIZE, "%s\n", can_state_names[state]);
+       }
+       read_unlock(&dev_base_lock);
+       return ret;
+}
+
+static DEVICE_ATTR(can_state, S_IRUGO, can_show_state, NULL);
+
+static ssize_t can_show_ctrlmode(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       u32 ctrlmode;
+       int ret = -EINVAL;
+
+       read_lock(&dev_base_lock);
+       if (dev_isalive(ndev)) {
+               can_get_ctrlmode(ndev, &ctrlmode);
+               ret = 0;
+               if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+                       ret += sprintf(buf + ret, "listenonly");
+               if (ret)
+                       ret += sprintf(buf + ret, " ");
+               if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
+                       ret += sprintf(buf + ret, "loopback");
+               if (ret)
+                       ret += sprintf(buf + ret, "\n");
+       }
+       read_unlock(&dev_base_lock);
+        return ret;
+}
+
+static ssize_t can_store_ctrlmode(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       u32 ctrlmode = 0;
+       int ret = -EINVAL;
+
+       if (strstr(buf, "listenonly"))
+               ctrlmode |= CAN_CTRLMODE_LISTENONLY;
+       if (strstr(buf, "loopback"))
+               ctrlmode |= CAN_CTRLMODE_LOOPBACK;
+
+       rtnl_lock();
+       if (dev_isalive(ndev) && count) {
+               if (!(ret = can_set_ctrlmode(ndev, ctrlmode)))
+                       ret = count;
+       }
+       rtnl_unlock();
+       return ret;
+}
+
+static DEVICE_ATTR(can_ctrlmode, S_IRUGO | S_IWUSR,
+                  can_show_ctrlmode, can_store_ctrlmode);
+
+static ssize_t can_show_custombittime(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct can_bittime bt;
+       int ret = -EINVAL;
+
+       read_lock(&dev_base_lock);
+       if (dev_isalive(ndev)) {
+               can_get_custombittime(ndev, &bt);
+
+               if (bt.type == CAN_BITTIME_STD)
+                       ret = snprintf(buf, PAGE_SIZE,
+                                      "std %#x %#x %#x %#x %#x %#x\n",
+                                      bt.std.brp, bt.std.prop_seg,
+                                      bt.std.phase_seg1, bt.std.phase_seg2,
+                                      bt.std.sjw, bt.std.sam);
+               else if (bt.type == CAN_BITTIME_BTR)
+                       ret = snprintf(buf, PAGE_SIZE,
+                                       "btr %#x %#x\n",
+                                       bt.btr.btr0, bt.btr.btr1);
+               else
+                       ret = snprintf(buf, PAGE_SIZE, "undefined\n");
+       }
+       read_unlock(&dev_base_lock);
+        return ret;
+}
+
+static ssize_t can_store_custombittime(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct can_bittime bt;
+       u32 val[6];
+       int ret = -EINVAL;
+
+       if (!strncmp(buf, "std", 3)) {
+               if (sscanf(buf + 4, "%i %i %i %i %i %i",
+                          val, val + 1, val + 2, val + 3,
+                          val + 4, val + 5) == 6) {
+                       bt.type = CAN_BITTIME_STD;
+                       bt.std.brp = val[0];
+                       bt.std.prop_seg = val[1];
+                       bt.std.phase_seg1 = val[2];
+                       bt.std.phase_seg2 = val[3];
+                       bt.std.sjw = val[4];
+                       bt.std.sam = val[5];
+               }
+       }
+       else if (!strncmp(buf, "btr", 3)) {
+               if (sscanf(buf + 4, "%i %i", val, val + 1) == 2) {
+                       bt.type = CAN_BITTIME_BTR;
+                       bt.btr.btr0 = val[0];
+                       bt.btr.btr1 = val[1];
+               }
+       } else
+               goto out;
+
+       rtnl_lock();
+       if (dev_isalive(ndev)) {
+               if (!(ret = can_set_custombittime(ndev, &bt)))
+                       ret = count;
+       }
+       rtnl_unlock();
+out:
+       return ret;
+}
+
+static DEVICE_ATTR(can_custombittime, S_IRUGO | S_IWUSR,
+                  can_show_custombittime, can_store_custombittime);
+
+static struct attribute *can_stats_attrs[] = {
+        &dev_attr_error_warning.attr,
+        &dev_attr_error_passive.attr,
+        &dev_attr_bus_error.attr,
+        &dev_attr_arbitration_lost.attr,
+        &dev_attr_data_overrun.attr,
+        &dev_attr_wakeup.attr,
+        &dev_attr_restarts.attr,
+       NULL
+};
+
+static struct attribute_group can_stats_group = {
+        .name = "can_statistics",
+        .attrs = can_stats_attrs,
+};
+
+void can_create_sysfs(struct net_device *dev)
+{
+       int err;
+
+       CAN_CREATE_FILE(dev, can_bitrate);
+       CAN_CREATE_FILE(dev, can_custombittime);
+       CAN_CREATE_FILE(dev, can_restart);
+       CAN_CREATE_FILE(dev, can_ctrlmode);
+       CAN_CREATE_FILE(dev, can_state);
+       CAN_CREATE_FILE(dev, can_restart_ms);
+       CAN_CREATE_FILE(dev, can_clock);
+       CAN_CREATE_FILE(dev, can_echo);
+
+        err = sysfs_create_group(&(dev->dev.kobj), &can_stats_group);
+        if (err) {
+               printk(KERN_EMERG
+                      "couldn't create sysfs group for CAN stats\n");
+        }
+}
+
+void can_remove_sysfs(struct net_device *dev)
+{
+       CAN_REMOVE_FILE(dev, can_bitrate);
+       CAN_REMOVE_FILE(dev, can_custombittime);
+       CAN_REMOVE_FILE(dev, can_restart);
+       CAN_REMOVE_FILE(dev, can_ctrlmode);
+       CAN_REMOVE_FILE(dev, can_state);
+       CAN_REMOVE_FILE(dev, can_clock);
+       CAN_REMOVE_FILE(dev, can_echo);
+
+        sysfs_remove_group(&(dev->dev.kobj), &can_stats_group);
+}
+
+#endif /* CONFIG_SYSFS */
+
+
+
diff --git a/kernel/2.6/net/can/sysfs.h b/kernel/2.6/net/can/sysfs.h
new file mode 100644 (file)
index 0000000..059ec4c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * $Id: dev.c 542 2007-11-07 13:57:16Z thuermann $
+ *
+ * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef CAN_SYSFS_H
+#define CAN_SYSFS_H
+
+void can_create_sysfs(struct net_device *dev);
+void can_remove_sysfs(struct net_device *dev);
+
+#endif /* CAN_SYSFS_H */