[Armadeus-commitlog] SF.net SVN: armadeus:[927] trunk/buildroot/target/device/armadeus/linux/ kerne
Brought to you by:
sszy
|
From: <th...@us...> - 2008-12-06 13:07:49
|
Revision: 927
http://armadeus.svn.sourceforge.net/armadeus/?rev=927&view=rev
Author: thom25
Date: 2008-12-06 13:07:44 +0000 (Sat, 06 Dec 2008)
Log Message:
-----------
[LINUX] make mcp2515 working again
Modified Paths:
--------------
trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-021-armadeus-apf9328.patch
trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-088-can-mcp2515.patch
Modified: trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-021-armadeus-apf9328.patch
===================================================================
--- trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-021-armadeus-apf9328.patch 2008-12-06 12:32:07 UTC (rev 926)
+++ trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-021-armadeus-apf9328.patch 2008-12-06 13:07:44 UTC (rev 927)
@@ -263,7 +263,7 @@
+};
+
+static struct spi_imx_master imx_spi2_master_info = {
-+ .num_chipselect = 1,
++ .num_chipselect = 2,
+ .enable_dma = 0,
+};
+
@@ -473,7 +473,7 @@
+ .controller_data = &mcp251X_hw,
+ .bus_num = 2,
+ .mode = SPI_MODE_0,
-+ .chip_select = 0,
++ .chip_select = 1,
+ .irq = IRQ_GPIOC( CAN_MPC251X_INT_GPIOC ),
+ .platform_data = &apf9328_mcp251x_config,
+ },
Modified: trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-088-can-mcp2515.patch
===================================================================
--- trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-088-can-mcp2515.patch 2008-12-06 12:32:07 UTC (rev 926)
+++ trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.27.2/linux-2.6.27.2-088-can-mcp2515.patch 2008-12-06 13:07:44 UTC (rev 927)
@@ -1,43 +1,50 @@
-[linux-2.6.19.2-mx-can-mcp2515-driver.patch]
-Index: linux-2.6.19.2/drivers/net/can/Kconfig
-===================================================================
---- linux-2.6.19.2.orig/drivers/net/can/Kconfig
-+++ linux-2.6.19.2/drivers/net/can/Kconfig
-@@ -22,4 +22,12 @@
- a problem with CAN support and want to see more of what is going
- on.
+diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
+index 57def0d..723f043 100644
+--- a/drivers/net/can/Kconfig
++++ b/drivers/net/can/Kconfig
+@@ -22,4 +22,12 @@ config CAN_DEBUG_DEVICES
+ a problem with CAN support and want to see more of what is going
+ on.
+config CAN_MCP251X
-+ tristate "Microchip 251x series SPI CAN Controller"
-+ depends on CAN && SPI
-+ default N
-+ ---help---
-+ Say Y here if you want support for the Microchip 251x series of
-+ SPI based CAN controllers.
++ tristate "Microchip 251x series SPI CAN Controller"
++ depends on CAN && SPI
++ default N
++ ---help---
++ Say Y here if you want support for the Microchip 251x series of
++ SPI based CAN controllers.
+
endmenu
---- /dev/null
-+++ linux-2.6.19.2/drivers/net/can/Makefile 2008-10-06 10:51:17.000000000 +0200
-@@ -3,3 +3,8 @@
+diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
+index c4bead7..0d86a8a 100644
+--- a/drivers/net/can/Makefile
++++ b/drivers/net/can/Makefile
+@@ -3,3 +3,4 @@
#
obj-$(CONFIG_CAN_VCAN) += vcan.o
-+obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
-+
-+ifdef CONFIG_CAN_DEBUG_DEVICES
-+EXTRA_CFLAGS += -DDEBUG
-+endif
-Index: linux-2.6.19.2/drivers/net/can/mcp251x.c
-===================================================================
++obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
+diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
+new file mode 100644
+index 0000000..43be336
--- /dev/null
-+++ linux-2.6.19.2/drivers/net/can/mcp251x.c
-@@ -0,0 +1,964 @@
-+/*
++++ b/drivers/net/can/mcp251x.c
+@@ -0,0 +1,1000 @@
++/* drivers/net/can/mcp251x.c
++ *
++ * Driver for Microchip MCP251x CAN Controller with SPI Interface
++ *
++ * Integrated into Linux 2.6.27 under contract by:
++ * Claudio Scordino <cl...@ev...>
++ *
+ * Copyright 2007 Raymarine UK, Ltd. All Rights Reserved.
-+ * Written under contract by Katalix Systems, Ltd.
-+ */
-+
-+/*
++ * Written under contract by:
++ * Chris Elston, Katalix Systems, Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
+ * Based on Microchip MCP251x CAN controller driver written by
+ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
+ *
@@ -48,19 +55,6 @@
+ */
+
+/*
-+ * The code contained herein is licensed under the GNU General Public
-+ * License. You may obtain a copy of the GNU General Public License
-+ * Version 2 or later at the following locations:
-+ *
-+ * http://www.opensource.org/licenses/gpl-license.html
-+ * http://www.gnu.org/copyleft/gpl.html
-+ */
-+
-+/*
-+ * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
-+ */
-+
-+/*
+ * Notes:
+ * This driver interacts with 2 subsystems.
+ * - To the SPI subsystem it is a 'protocol driver'
@@ -71,6 +65,30 @@
+ *
+ */
+
++/*
++ * Platform file must specify something like:
++ *
++ * static struct mcp251x_platform_data mcp251x_info = {
++ * .oscillator_frequency = 19000000,
++ * .board_specific_setup = myboard_mcp251x_initfunc,
++ * .device_reset = myboard_mcp251x_reset,
++ * .transceiver_enable = NULL,
++ * };
++ *
++ * static struct spi_board_info spi_board_info[] __initdata = {
++ * {
++ * .modalias = "mcp251x",
++ * .platform_data = &mcp251x_info,
++ * .irq = 10,
++ * .max_speed_hz = 8000000,
++ * .bus_num = 1,
++ * .chip_select = 0
++ * },
++ * };
++ *
++ * (See Documentation/spi/spi-summary for more info)
++ */
++
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
@@ -80,74 +98,80 @@
+#include <linux/can.h>
+#include <linux/spi/spi.h>
+#include <linux/can/dev.h>
++#include <linux/can/core.h>
+#include <linux/if_arp.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
++#include <linux/completion.h>
++#include <asm/uaccess.h>
+#include <asm/io.h>
-+#include <asm/uaccess.h>
+#include "mcp251x.h"
+
+/* SPI interface instruction set */
-+#define INSTRUCTION_WRITE 0x02
-+#define INSTRUCTION_READ 0x03
-+#define INSTRUCTION_BIT_MODIFY 0x05
-+#define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n))
-+#define INSTRUCTION_READ_RXB(n) (0x90 + 2 * (n))
-+#define INSTRUCTION_RESET 0xC0
++#define INSTRUCTION_WRITE 0x02
++#define INSTRUCTION_READ 0x03
++#define INSTRUCTION_BIT_MODIFY 0x05
++#define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n))
++#define INSTRUCTION_READ_RXB(n) (((n) == 0) ? 0x90 : 0x94)
++#define INSTRUCTION_RESET 0xC0
+
+/* MPC251x registers */
+#define CANSTAT 0x0e
+#define CANCTRL 0x0f
-+#define CANCTRL_REQOP_MASK 0xe0
-+#define CANCTRL_REQOP_CONF 0x80
-+#define CANCTRL_REQOP_LISTEN_ONLY 0x60
-+#define CANCTRL_REQOP_LOOPBACK 0x40
-+#define CANCTRL_REQOP_SLEEP 0x20
-+#define CANCTRL_REQOP_NORMAL 0x00
-+#define CANCTRL_OSM 0x08
++# define CANCTRL_REQOP_MASK 0xe0
++# define CANCTRL_REQOP_CONF 0x80
++# define CANCTRL_REQOP_LISTEN_ONLY 0x60
++# define CANCTRL_REQOP_LOOPBACK 0x40
++# define CANCTRL_REQOP_SLEEP 0x20
++# define CANCTRL_REQOP_NORMAL 0x00
++# define CANCTRL_OSM 0x08
++# define CANCTRL_ABAT 0x10
+#define TEC 0x1c
+#define REC 0x1d
+#define CNF1 0x2a
+#define CNF2 0x29
-+#define CNF2_BTLMODE 0x80
++# define CNF2_BTLMODE 0x80
+#define CNF3 0x28
-+#define CNF3_SOF 0x08
-+#define CNF3_WAKFIL 0x04
-+#define CNF3_PHSEG2_MASK 0x07
++# define CNF3_SOF 0x08
++# define CNF3_WAKFIL 0x04
++# define CNF3_PHSEG2_MASK 0x07
+#define CANINTE 0x2b
-+#define CANINTE_MERRE 0x80
-+#define CANINTE_WAKIE 0x40
-+#define CANINTE_ERRIE 0x20
-+#define CANINTE_TX2IE 0x10
-+#define CANINTE_TX1IE 0x08
-+#define CANINTE_TX0IE 0x04
-+#define CANINTE_RX1IE 0x02
-+#define CANINTE_RX0IE 0x01
++# define CANINTE_MERRE 0x80
++# define CANINTE_WAKIE 0x40
++# define CANINTE_ERRIE 0x20
++# define CANINTE_TX2IE 0x10
++# define CANINTE_TX1IE 0x08
++# define CANINTE_TX0IE 0x04
++# define CANINTE_RX1IE 0x02
++# define CANINTE_RX0IE 0x01
+#define CANINTF 0x2c
-+#define CANINTF_MERRF 0x80
-+#define CANINTF_WAKIF 0x40
-+#define CANINTF_ERRIF 0x20
-+#define CANINTF_TX2IF 0x10
-+#define CANINTF_TX1IF 0x08
-+#define CANINTF_TX0IF 0x04
-+#define CANINTF_RX1IF 0x02
-+#define CANINTF_RX0IF 0x01
++# define CANINTF_MERRF 0x80
++# define CANINTF_WAKIF 0x40
++# define CANINTF_ERRIF 0x20
++# define CANINTF_TX2IF 0x10
++# define CANINTF_TX1IF 0x08
++# define CANINTF_TX0IF 0x04
++# define CANINTF_RX1IF 0x02
++# define CANINTF_RX0IF 0x01
+#define EFLG 0x2d
-+#define EFLG_EWARN 0x01
-+#define EFLG_RXWAR 0x02
-+#define EFLG_TXWAR 0x04
-+#define EFLG_RXEP 0x08
-+#define EFLG_TXEP 0x10
-+#define EFLG_TXBO 0x20
-+#define EFLG_RX0OVR 0x40
-+#define EFLG_RX1OVR 0x80
++# define EFLG_EWARN 0x01
++# define EFLG_RXWAR 0x02
++# define EFLG_TXWAR 0x04
++# define EFLG_RXEP 0x08
++# define EFLG_TXEP 0x10
++# define EFLG_TXBO 0x20
++# define EFLG_RX0OVR 0x40
++# define EFLG_RX1OVR 0x80
+#define TXBCTRL(n) ((n * 0x10) + 0x30)
-+#define TXBCTRL_TXREQ 0x08
++# define TXBCTRL_TXREQ 0x08
++#define RXBCTRL(n) ((n * 0x10) + 0x60)
++# define RXBCTRL_BUKT 0x04
+
+/* Buffer size required for the largest SPI transfer (i.e., reading a
+ * frame). */
-+#define CAN_FRAME_MAX_DATA_LEN 8
-+#define SPI_TRANSFER_BUF_LEN (2*(6 + CAN_FRAME_MAX_DATA_LEN))
++#define CAN_FRAME_MAX_DATA_LEN 8
++#define SPI_TRANSFER_BUF_LEN (2*(6 + CAN_FRAME_MAX_DATA_LEN))
++#define CAN_FRAME_MAX_BITS 128
+
+#define DEVICE_NAME "mcp251x"
+
@@ -160,856 +184,1380 @@
+MODULE_PARM_DESC(loopback, "Loop back frames (for testing). Default: 0 (Off)");
+
+struct mcp251x_priv {
-+ struct can_priv can;
-+ struct net_device *net;
-+ struct spi_device *spi;
++ struct can_priv can;
++ struct net_device *net;
++ struct spi_device *spi;
+
-+ struct semaphore spi_lock; /* SPI buffer lock */
-+ uint8_t *spi_tx_buf;
-+ uint8_t *spi_rx_buf;
-+ dma_addr_t spi_tx_dma;
-+ dma_addr_t spi_rx_dma;
++ struct semaphore spi_lock; /* SPI buffer lock */
++ u8 *spi_tx_buf;
++ u8 *spi_rx_buf;
++ dma_addr_t spi_tx_dma;
++ dma_addr_t spi_rx_dma;
+
-+ struct sk_buff *tx_skb;
-+ struct work_struct tx_work;
-+ struct work_struct irq_work;
++ struct sk_buff *tx_skb;
++ struct workqueue_struct *wq;
++ struct work_struct tx_work;
++ struct work_struct irq_work;
++ struct completion awake;
++ int wake;
+};
+
-+
-+static uint8_t mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
++static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+{
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct spi_transfer t = {
-+ .tx_buf = priv->spi_tx_buf,
-+ .rx_buf = priv->spi_rx_buf,
-+ .len = 3,
-+ .cs_change = 0,
-+ };
-+ struct spi_message m;
-+ uint8_t val = 0;
-+ int ret;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct spi_transfer t = {
++ .tx_buf = priv->spi_tx_buf,
++ .rx_buf = priv->spi_rx_buf,
++ .len = 3,
++ .cs_change = 0,
++ };
++ struct spi_message m;
++ u8 val = 0;
++ int ret;
+
-+ down(&priv->spi_lock);
++ down(&priv->spi_lock);
+
-+ priv->spi_tx_buf[0] = INSTRUCTION_READ;
-+ priv->spi_tx_buf[1] = reg;
++ priv->spi_tx_buf[0] = INSTRUCTION_READ;
++ priv->spi_tx_buf[1] = reg;
+
-+ spi_message_init(&m);
++ spi_message_init(&m);
+
-+ if (enable_dma) {
-+ t.tx_dma = priv->spi_tx_dma;
-+ t.rx_dma = priv->spi_rx_dma;
-+ m.is_dma_mapped = 1;
-+ }
++ if (enable_dma) {
++ t.tx_dma = priv->spi_tx_dma;
++ t.rx_dma = priv->spi_rx_dma;
++ m.is_dma_mapped = 1;
++ }
+
-+ spi_message_add_tail(&t, &m);
++ spi_message_add_tail(&t, &m);
+
-+ ret = spi_sync(spi, &m);
-+ if (ret < 0) {
-+ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
-+ } else
-+ val = priv->spi_rx_buf[2];
++ ret = spi_sync(spi, &m);
++ if (ret < 0) {
++ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
++ } else
++ val = priv->spi_rx_buf[2];
+
-+ up(&priv->spi_lock);
++ up(&priv->spi_lock);
+
-+ /*dev_dbg(&spi->dev, "%s: reg 0x%02X val 0x%02X\n", __FUNCTION__, reg, val);*/
-+
-+ return val;
++ return val;
+}
+
+
-+static void mcp251x_write_reg(struct spi_device *spi, uint8_t reg, uint8_t val)
++static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
+{
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct spi_transfer t = {
-+ .tx_buf = priv->spi_tx_buf,
-+ .rx_buf = priv->spi_rx_buf,
-+ .len = 3,
-+ .cs_change = 0,
-+ };
-+ struct spi_message m;
-+ int ret;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct spi_transfer t = {
++ .tx_buf = priv->spi_tx_buf,
++ .rx_buf = priv->spi_rx_buf,
++ .len = 3,
++ .cs_change = 0,
++ };
++ struct spi_message m;
++ int ret;
+
-+ /*dev_dbg(&spi->dev, "%s: reg 0x%02X val 0x%02X\n", __FUNCTION__, reg, val);*/
++ down(&priv->spi_lock);
+
-+ down(&priv->spi_lock);
++ priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
++ priv->spi_tx_buf[1] = reg;
++ priv->spi_tx_buf[2] = val;
+
-+ priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
-+ priv->spi_tx_buf[1] = reg;
-+ priv->spi_tx_buf[2] = val;
++ spi_message_init(&m);
+
-+ spi_message_init(&m);
++ if (enable_dma) {
++ t.tx_dma = priv->spi_tx_dma;
++ t.rx_dma = priv->spi_rx_dma;
++ m.is_dma_mapped = 1;
++ }
+
-+ if (enable_dma) {
-+ t.tx_dma = priv->spi_tx_dma;
-+ t.rx_dma = priv->spi_rx_dma;
-+ m.is_dma_mapped = 1;
-+ }
++ spi_message_add_tail(&t, &m);
+
-+ spi_message_add_tail(&t, &m);
++ ret = spi_sync(spi, &m);
+
-+ ret = spi_sync(spi, &m);
++ up(&priv->spi_lock);
+
-+ up(&priv->spi_lock);
-+
-+ if (ret < 0)
-+ dev_dbg(&spi->dev, "%s: failed\n", __FUNCTION__);
-+
-+ return;
++ if (ret < 0)
++ dev_dbg(&spi->dev, "%s: failed\n", __FUNCTION__);
+}
+
+
-+static void mcp251x_write_bits(struct spi_device *spi, uint8_t reg,
-+ uint8_t mask, uint8_t val)
++static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
++ u8 mask, uint8_t val)
+{
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct spi_transfer t = {
-+ .tx_buf = priv->spi_tx_buf,
-+ .rx_buf = priv->spi_rx_buf,
-+ .len = 4,
-+ .cs_change = 0,
-+ };
-+ struct spi_message m;
-+ int ret;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct spi_transfer t = {
++ .tx_buf = priv->spi_tx_buf,
++ .rx_buf = priv->spi_rx_buf,
++ .len = 4,
++ .cs_change = 0,
++ };
++ struct spi_message m;
++ int ret;
+
-+ down(&priv->spi_lock);
++ down(&priv->spi_lock);
+
-+ priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
-+ priv->spi_tx_buf[1] = reg;
-+ priv->spi_tx_buf[2] = mask;
-+ priv->spi_tx_buf[3] = val;
++ priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
++ priv->spi_tx_buf[1] = reg;
++ priv->spi_tx_buf[2] = mask;
++ priv->spi_tx_buf[3] = val;
+
-+ spi_message_init(&m);
++ spi_message_init(&m);
+
-+ if (enable_dma) {
-+ t.tx_dma = priv->spi_tx_dma;
-+ t.rx_dma = priv->spi_rx_dma;
-+ m.is_dma_mapped = 1;
-+ }
++ if (enable_dma) {
++ t.tx_dma = priv->spi_tx_dma;
++ t.rx_dma = priv->spi_rx_dma;
++ m.is_dma_mapped = 1;
++ }
+
-+ spi_message_add_tail(&t, &m);
++ spi_message_add_tail(&t, &m);
+
-+ ret = spi_sync(spi, &m);
-+ if (ret < 0)
-+ dev_dbg(&spi->dev, "%s: failed\n", __FUNCTION__);
++ ret = spi_sync(spi, &m);
+
-+ up(&priv->spi_lock);
++ up(&priv->spi_lock);
+
-+ return;
++ if (ret < 0)
++ dev_dbg(&spi->dev, "%s: failed\n", __FUNCTION__);
+}
+
+
+static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
-+ int tx_buf_idx)
++int tx_buf_idx)
+{
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct spi_transfer t = {
-+ .tx_buf = priv->spi_tx_buf,
-+ .rx_buf = priv->spi_rx_buf,
-+ .cs_change = 0,
-+ .len = 6 + CAN_FRAME_MAX_DATA_LEN,
-+ };
-+ uint8_t *tx_buf = priv->spi_tx_buf;
-+ struct spi_message m;
-+ int ret;
-+ uint32_t sid, eid, exide, rtr;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct spi_transfer t = {
++ .tx_buf = priv->spi_tx_buf,
++ .rx_buf = priv->spi_rx_buf,
++ .cs_change = 0,
++ .len = 6 + CAN_FRAME_MAX_DATA_LEN,
++ };
++ u8 *tx_buf = priv->spi_tx_buf;
++ struct spi_message m;
++ int ret;
++ u32 sid, eid, exide, rtr;
+
-+ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
++ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
+
-+ sid = frame->can_id & CAN_SFF_MASK; /* Standard ID */
-+ eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */
-+ exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
-+ rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */
++ sid = frame->can_id & CAN_SFF_MASK; /* Standard ID */
++ eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */
++ exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
++ rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */
+
-+ mcp251x_read_reg(spi, CANSTAT);
++ down(&priv->spi_lock);
+
-+ down(&priv->spi_lock);
++ tx_buf[0] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
++ tx_buf[1] = sid >> 3;
++ tx_buf[2] = (sid << 5) | (exide << 3) | (eid >> 16);
++ tx_buf[3] = eid >> 8;
++ tx_buf[4] = eid;
++ tx_buf[5] = (rtr << 6) | frame->can_dlc;
+
-+ tx_buf[0] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
-+ tx_buf[1] = sid >> 3;
-+ tx_buf[2] = (sid << 5) | (exide << 3) | (eid >> 16);
-+ tx_buf[3] = eid >> 8;
-+ tx_buf[4] = eid;
-+ tx_buf[5] = (rtr << 6) | frame->can_dlc;
++ memcpy(tx_buf + 6, frame->data, frame->can_dlc);
+
-+ memcpy(tx_buf + 6, frame->data, frame->can_dlc);
++ spi_message_init(&m);
+
-+ spi_message_init(&m);
++ if (enable_dma) {
++ t.tx_dma = priv->spi_tx_dma;
++ t.rx_dma = priv->spi_rx_dma;
++ m.is_dma_mapped = 1;
++ }
+
-+ if (enable_dma) {
-+ t.tx_dma = priv->spi_tx_dma;
-+ t.rx_dma = priv->spi_rx_dma;
-+ m.is_dma_mapped = 1;
-+ }
++ spi_message_add_tail(&t, &m);
+
-+ spi_message_add_tail(&t, &m);
++ ret = spi_sync(spi, &m);
+
-+ ret = spi_sync(spi, &m);
-+ if (ret < 0)
-+ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
++ up(&priv->spi_lock);
+
-+ /* FIXME: Should we exit with an error here? */
++ if (ret < 0)
++ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
+
-+ up(&priv->spi_lock);
++ /* FIXME: Should we exit with an error here? */
+
-+ mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
-+
-+ return;
++ mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
+}
+
+
+static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
+{
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct spi_transfer t = {
-+ .tx_buf = priv->spi_tx_buf,
-+ .rx_buf = priv->spi_rx_buf,
-+ .cs_change = 0,
-+ .len = 14,
-+ };
-+ uint8_t *tx_buf = priv->spi_tx_buf;
-+ uint8_t *rx_buf = priv->spi_rx_buf;
-+ struct spi_message m;
-+ struct sk_buff *skb;
-+ struct can_frame *frame;
-+ int ret;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct spi_transfer t = {
++ .tx_buf = priv->spi_tx_buf,
++ .rx_buf = priv->spi_rx_buf,
++ .cs_change = 0,
++ .len = 14, /* RX buffer: RXBnCTRL to RXBnD7 */
++ };
++ u8 *tx_buf = priv->spi_tx_buf;
++ u8 *rx_buf = priv->spi_rx_buf;
++ struct spi_message m;
++ struct sk_buff *skb;
++ struct can_frame *frame;
++ int ret;
+
-+ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
++ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
+
-+ skb = dev_alloc_skb(sizeof(struct can_frame));
-+ if (!skb) {
-+ dev_dbg(&spi->dev, "%s: out of memory for Rx'd frame\n", __FUNCTION__);
-+ priv->can.net_stats.rx_dropped++;
-+ return;
-+ }
-+ skb->dev = priv->net;
-+ frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
++ skb = dev_alloc_skb(sizeof(struct can_frame));
++ if (!skb) {
++ dev_dbg(&spi->dev, "%s: out of memory for Rx'd frame\n", __FUNCTION__);
++ priv->net->stats.rx_dropped++;
++ return;
++ }
++ skb->dev = priv->net;
++ frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+
-+ down(&priv->spi_lock);
++ down(&priv->spi_lock);
+
-+ tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx);
++ tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx);
+
-+ spi_message_init(&m);
++ spi_message_init(&m);
+
-+ if (enable_dma) {
-+ t.tx_dma = priv->spi_tx_dma;
-+ t.rx_dma = priv->spi_rx_dma;
-+ m.is_dma_mapped = 1;
-+ }
++ if (enable_dma) {
++ t.tx_dma = priv->spi_tx_dma;
++ t.rx_dma = priv->spi_rx_dma;
++ m.is_dma_mapped = 1;
++ }
+
-+ spi_message_add_tail(&t, &m);
++ spi_message_add_tail(&t, &m);
+
-+ ret = spi_sync(spi, &m);
-+ if (ret < 0)
-+ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
-+ /* FIXME: Should we exit with an error here? */
++ ret = spi_sync(spi, &m);
++ if (ret < 0)
++ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
++ /* FIXME: Should we exit with an error here? */
+
-+ if ((rx_buf[2] >> 3) & 0x1) {
-+ /* Extended ID format */
-+ frame->can_id = CAN_EFF_FLAG;
-+ frame->can_id |= (rx_buf[2] << 16) | (rx_buf[3] << 8) | rx_buf[4];
-+ } else {
-+ /* Standard ID format */
-+ frame->can_id = (rx_buf[1] << 3) | (rx_buf[2] >> 5);
-+ }
++ if ((rx_buf[2] >> 3) & 0x1) {
++ /* Extended ID format */
++ frame->can_id = CAN_EFF_FLAG;
++ frame->can_id |= (rx_buf[2] << 16) | (rx_buf[3] << 8) | rx_buf[4];
++ } else {
++ /* Standard ID format */
++ frame->can_id = (rx_buf[1] << 3) | (rx_buf[2] >> 5);
++ }
+
-+ if ((rx_buf[5] >> 6) & 0x1) {
-+ /* Remote transmission request */
-+ frame->can_id |= CAN_RTR_FLAG;
-+ }
++ if ((rx_buf[5] >> 6) & 0x1) {
++ /* Remote transmission request */
++ frame->can_id |= CAN_RTR_FLAG;
++ }
+
-+ dev_dbg(&spi->dev, "%s: can_id rec'd 0x%08X\n", __FUNCTION__, frame->can_id);
++ /* Data length */
++ frame->can_dlc = rx_buf[5] & 0x0f;
++ memcpy(frame->data, rx_buf + 6, CAN_FRAME_MAX_DATA_LEN);
+
-+ /* Data length */
-+ frame->can_dlc = rx_buf[5] & 0x0f;
-+ memcpy(frame->data, rx_buf + 6, CAN_FRAME_MAX_DATA_LEN);
++ up(&priv->spi_lock);
+
-+ up(&priv->spi_lock);
++ priv->net->stats.rx_packets++;
++ priv->net->stats.rx_bytes += frame->can_dlc;
+
-+ priv->can.net_stats.rx_packets++;
-+ priv->can.net_stats.rx_bytes += frame->can_dlc;
-+
-+ skb->protocol = __constant_htons(ETH_P_CAN);
-+ skb->pkt_type = PACKET_BROADCAST;
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+ netif_rx(skb);
-+
-+ return;
++ skb->protocol = __constant_htons(ETH_P_CAN);
++ skb->pkt_type = PACKET_BROADCAST;
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ netif_rx(skb);
+}
+
+
+static void mcp251x_hw_sleep(struct spi_device *spi)
+{
-+ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
++ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
+}
+
+static void mcp251x_hw_wakeup(struct spi_device *spi)
+{
-+ /* Can only wake up by generating a wake-up interrupt. */
-+ mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE);
-+ mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF);
-+}
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
-+/* FIXME: modes of operation CONFIG, NORMAL, SLEEP, LISTEN, LOOPBACK */
-+static int mcp251x_set_mode(struct net_device *net, uint8_t mode)
-+{
-+ return 0;
++ priv->wake = 1;
++
++ /* Can only wake up by generating a wake-up interrupt. */
++ mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE);
++ mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF);
++
++ /* Wait until the device is awake */
++ wait_for_completion(&priv->awake);
+}
+
++
+static int mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
-+ struct mcp251x_priv *priv = netdev_priv(net);
-+ struct spi_device *spi = priv->spi;
-+ struct can_frame *frame;
++ struct mcp251x_priv *priv = netdev_priv(net);
++ struct spi_device *spi = priv->spi;
+
-+ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
++ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
+
-+ if (skb->len != sizeof(struct can_frame)) {
-+ dev_dbg(&spi->dev, "dropping packet - bad length\n");
-+ dev_kfree_skb(skb);
-+ priv->can.net_stats.tx_dropped++;
-+ return 0;
-+ }
++ if (skb->len != sizeof(struct can_frame)) {
++ dev_dbg(&spi->dev, "dropping packet - bad length\n");
++ dev_kfree_skb(skb);
++ net->stats.tx_dropped++;
++ return 0;
++ }
+
-+ netif_stop_queue(net);
++ netif_stop_queue(net);
++ priv->tx_skb = skb;
++ net->trans_start = jiffies;
++ queue_work(priv->wq, &priv->tx_work);
+
-+ frame = (struct can_frame *)skb->data;
-+
-+ priv->tx_skb = skb;
-+ schedule_work(&priv->tx_work);
-+
-+ return 0;
++ return NETDEV_TX_OK;
+}
+
+
+static int mcp251x_do_set_mode(struct net_device *net, can_mode_t mode)
+{
-+ struct mcp251x_priv *priv = netdev_priv(net);
-+ struct spi_device *spi = priv->spi;
++ struct mcp251x_priv *priv = netdev_priv(net);
++ struct spi_device *spi = priv->spi;
+
-+ dev_dbg(&spi->dev, "%s (unimplemented)\n", __FUNCTION__);
++ dev_dbg(&spi->dev, "%s (unimplemented)\n", __FUNCTION__);
+
-+ switch (mode) {
-+ default:
-+ return -EOPNOTSUPP;
-+ }
++ switch (mode) {
++ default:
++ return -EOPNOTSUPP;
++ }
+
-+ return 0;
++ return 0;
+}
+
+
+static int mcp251x_open(struct net_device *net)
+{
-+ struct mcp251x_priv *priv = netdev_priv(net);
-+ struct spi_device *spi = priv->spi;
-+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
++ struct mcp251x_priv *priv = netdev_priv(net);
++ struct spi_device *spi = priv->spi;
++ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+
-+ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
++ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
+
-+ if (pdata->transceiver_enable)
-+ pdata->transceiver_enable(1);
++ if (pdata->transceiver_enable)
++ pdata->transceiver_enable(1);
+
-+ mcp251x_hw_wakeup(spi);
++ mcp251x_hw_wakeup(spi);
+
-+ /* Enable interrupts */
-+ mcp251x_write_reg(spi, CANINTE,
-+ CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
-+ CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE );
++ /* Enable interrupts */
++ mcp251x_write_reg(spi, CANINTE,
++ CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
++ CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE );
+
-+ if (loopback) {
-+ /* Put device into loopback mode */
-+ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK);
-+ } else {
-+ /* Put device into normal mode */
-+ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);
++ if (loopback) {
++ /* Put device into loopback mode */
++ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK);
++ } else {
++ /* Put device into normal mode */
++ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);
+
-+ /* Wait for the device to enter normal mode */
-+ while (mcp251x_read_reg(spi, CANSTAT) & 0xE0)
-+ udelay(10);
-+ }
++ /* Wait for the device to enter normal mode */
++ while (mcp251x_read_reg(spi, CANSTAT) & 0xE0)
++ udelay(10);
++ }
+
-+ return 0;
++ return 0;
+}
+
+static int mcp251x_stop(struct net_device *net)
+{
-+ struct mcp251x_priv *priv = netdev_priv(net);
-+ struct spi_device *spi = priv->spi;
-+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
++ struct mcp251x_priv *priv = netdev_priv(net);
++ struct spi_device *spi = priv->spi;
++ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+
-+ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
++ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
+
-+ /* Disable and clear pending interrupts */
-+ mcp251x_write_reg(spi, CANINTE, 0x00);
-+ mcp251x_write_reg(spi, CANINTF, 0x00);
++ /* Disable and clear pending interrupts */
++ mcp251x_write_reg(spi, CANINTE, 0x00);
++ mcp251x_write_reg(spi, CANINTF, 0x00);
+
-+ mcp251x_hw_sleep(spi);
++ mcp251x_hw_sleep(spi);
+
-+ if (pdata->transceiver_enable)
-+ pdata->transceiver_enable(0);
++ if (pdata->transceiver_enable)
++ pdata->transceiver_enable(0);
+
-+ return 0;
++ return 0;
+}
+
+static int mcp251x_do_set_bit_time(struct net_device *net, struct can_bittime *bt)
+{
-+ struct mcp251x_priv *priv = netdev_priv(net);
-+ struct spi_device *spi = priv->spi;
-+ uint8_t state;
++ struct mcp251x_priv *priv = netdev_priv(net);
++ struct spi_device *spi = priv->spi;
++ u8 state;
+
-+ dev_dbg(&spi->dev, "%s: BRP = %d, PropSeg = %d, PS1 = %d,"
-+ " PS2 = %d, SJW = %d\n", __FUNCTION__, bt->std.brp,
-+ bt->std.prop_seg, bt->std.phase_seg1, bt->std.phase_seg2,
-+ bt->std.sjw);
++ dev_dbg(&spi->dev, "%s: BRP = %d, PropSeg = %d, PS1 = %d,"
++ " PS2 = %d, SJW = %d\n", __FUNCTION__, bt->std.brp,
++ bt->std.prop_seg, bt->std.phase_seg1, bt->std.phase_seg2,
++ bt->std.sjw);
+
-+ /* Store original mode and set mode to config */
-+ state = mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK;
-+ mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_CONF);
++ /* Store original mode and set mode to config */
++ state = mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK;
++ mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_CONF);
+
-+ mcp251x_write_reg(spi, CNF1, ((bt->std.sjw - 1) << 6) | bt->std.brp);
-+ mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE | ((bt->std.phase_seg1 - 1) << 3) |
-+ (bt->std.prop_seg - 1));
-+ mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK, (bt->std.phase_seg2 - 1));
++ mcp251x_write_reg(spi, CNF1, ((bt->std.sjw - 1) << 6) | (bt->std.brp-1));
++ mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE | ((bt->std.phase_seg1 - 1) << 3) | (bt->std.prop_seg - 1));
++ mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK, (bt->std.phase_seg2 - 1));
+
-+ /* Restore original state */
-+ mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, state);
++ /* Restore original state */
++ mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, state);
+
-+ return 0;
++ return 0;
+}
+
+
+static int mcp251x_do_get_state(struct net_device *net, can_state_t *state)
+{
-+ struct mcp251x_priv *priv = netdev_priv(net);
-+ struct spi_device *spi = priv->spi;
-+ uint8_t eflag;
++ struct mcp251x_priv *priv = netdev_priv(net);
++ struct spi_device *spi = priv->spi;
++ u8 eflag;
+
-+ eflag = mcp251x_read_reg(spi, EFLG);
++ eflag = mcp251x_read_reg(spi, EFLG);
+
-+ if (eflag & EFLG_TXBO) {
-+ *state = CAN_STATE_BUS_OFF;
-+ } else if (eflag & (EFLG_RXEP | EFLG_TXEP)) {
-+ *state = CAN_STATE_BUS_PASSIVE;
-+ } else if (eflag & EFLG_EWARN) {
-+ *state = CAN_STATE_BUS_WARNING;
-+ } else {
-+ *state = CAN_STATE_ACTIVE;
-+ }
++ if (eflag & EFLG_TXBO) {
++ *state = CAN_STATE_BUS_OFF;
++ } else if (eflag & (EFLG_RXEP | EFLG_TXEP)) {
++ *state = CAN_STATE_BUS_PASSIVE;
++ } else if (eflag & EFLG_EWARN) {
++ *state = CAN_STATE_BUS_WARNING;
++ } else {
++ *state = CAN_STATE_ACTIVE;
++ }
+
-+ return 0;
++ return 0;
+}
+
+
-+static void mcp251x_tx_work_handler(struct work_struct *work)
++static void mcp251x_tx_work_handler(struct work_struct *ws)
+{
-+ struct mcp251x_priv *priv = container_of(work, struct mcp251x_priv, tx_work);
-+ struct spi_device *spi = priv->spi;
-+ struct can_frame *frame = (struct can_frame *)priv->tx_skb->data;
++ struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv, tx_work);
++ struct spi_device *spi = priv->spi;
++ struct can_frame *frame = (struct can_frame *)priv->tx_skb->data;
+
-+ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
++ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
+
-+ if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
-+ frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
++ if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
++ frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
+
-+ /* FIXME: use all 3 Tx buffers */
-+ mcp251x_hw_tx(spi, frame, 0);
-+
-+ return;
++ /* FIXME: use all 3 Tx buffers */
++ mcp251x_hw_tx(spi, frame, 0);
+}
+
+
-+static void mcp251x_irq_work_handler(struct work_struct *work)
++static void mcp251x_irq_work_handler(struct work_struct *ws)
+{
-+ struct mcp251x_priv *priv = container_of(work, struct mcp251x_priv, irq_work);
-+ struct spi_device *spi = priv->spi;
-+ struct net_device *net = priv->net;
-+ uint8_t intf;
++ struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv, irq_work);
++ struct spi_device *spi = priv->spi;
++ struct net_device *net = priv->net;
++ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
++ u8 intf;
+
-+ for (;;) {
-+ intf = mcp251x_read_reg(spi, CANINTF);
-+ if (intf == 0x00)
-+ break;
++ for (;;) {
++ if (priv->wake) {
++ /* Wait whilst the device wakes up */
++ udelay(200 * (128 * USEC_PER_SEC / pdata->oscillator_frequency));
++ priv->wake = 0;
++ }
+
-+ dev_dbg(&spi->dev, "interrupt:%s%s%s%s%s%s%s%s\n",
-+ (intf & CANINTF_MERRF) ? " MERR":"",
-+ (intf & CANINTF_WAKIF) ? " WAK":"",
-+ (intf & CANINTF_ERRIF) ? " ERR":"",
-+ (intf & CANINTF_TX2IF) ? " TX2":"",
-+ (intf & CANINTF_TX1IF) ? " TX1":"",
-+ (intf & CANINTF_TX0IF) ? " TX0":"",
-+ (intf & CANINTF_RX1IF) ? " RX1":"",
-+ (intf & CANINTF_RX0IF) ? " RX0":"");
++ intf = mcp251x_read_reg(spi, CANINTF);
++ if (intf == 0x00)
++ break;
+
-+ if (intf & CANINTF_MERRF) {
-+ uint8_t txbnctrl;
-+ /* if there are no pending Tx buffers, restart queue */
-+ txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
-+ if (!(txbnctrl & TXBCTRL_TXREQ))
-+ netif_wake_queue(net);
-+ }
++ dev_dbg(&spi->dev, "interrupt:%s%s%s%s%s%s%s%s\n",
++ (intf & CANINTF_MERRF) ? " MERR":"",
++ (intf & CANINTF_WAKIF) ? " WAK":"",
++ (intf & CANINTF_ERRIF) ? " ERR":"",
++ (intf & CANINTF_TX2IF) ? " TX2":"",
++ (intf & CANINTF_TX1IF) ? " TX1":"",
++ (intf & CANINTF_TX0IF) ? " TX0":"",
++ (intf & CANINTF_RX1IF) ? " RX1":"",
++ (intf & CANINTF_RX0IF) ? " RX0":"");
+
-+ if (intf & CANINTF_ERRIF) {
-+ uint8_t eflg = mcp251x_read_reg(spi, EFLG);
++ if (intf & CANINTF_WAKIF) {
++ complete(&priv->awake);
++ }
+
-+ dev_dbg(&spi->dev, "EFLG = 0x%02x\n", eflg);
++ if (intf & CANINTF_MERRF) {
++ u8 txbnctrl;
++ /* if there are no pending Tx buffers, restart queue */
++ txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
++ if (!(txbnctrl & TXBCTRL_TXREQ))
++ netif_wake_queue(net);
++ }
+
-+ if (eflg & (EFLG_RX0OVR | EFLG_RX1OVR)) {
-+ if (eflg & EFLG_RX0OVR)
-+ priv->can.net_stats.rx_over_errors++;
-+ if (eflg & EFLG_RX1OVR)
-+ priv->can.net_stats.rx_over_errors++;
-+ mcp251x_write_reg(spi, EFLG, 0x00);
-+ }
-+ }
++ if (intf & CANINTF_ERRIF) {
++ struct sk_buff *skb;
++ struct can_frame *frame = 0;
++ u8 eflag = mcp251x_read_reg(spi, EFLG);
+
-+ if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
-+ priv->can.net_stats.tx_packets++;
-+ priv->can.net_stats.tx_bytes += ((struct can_frame *)(priv->tx_skb->data))->can_dlc;
-+ dev_kfree_skb(priv->tx_skb);
-+ netif_wake_queue(net);
-+ }
++ dev_dbg(&spi->dev, "EFLG = 0x%02x\n", eflag);
+
-+ if (intf & CANINTF_RX0IF)
-+ mcp251x_hw_rx(spi, 0);
++ /* Create error frame */
++ skb = dev_alloc_skb(sizeof(struct can_frame));
++ if (skb) {
++ frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
++ frame->can_id = CAN_ERR_FLAG;
++ frame->can_dlc = CAN_ERR_DLC;
+
-+ if (intf & CANINTF_RX1IF)
-+ mcp251x_hw_rx(spi, 1);
++ skb->dev = net;
++ skb->protocol = __constant_htons(ETH_P_CAN);
++ skb->pkt_type = PACKET_BROADCAST;
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
-+ mcp251x_write_bits(spi, CANINTF, intf, 0x00);
-+ }
++ /* Set error frame flags according to bus state */
++ if (eflag & EFLG_TXBO) {
++ frame->can_id |= CAN_ERR_BUSOFF;
++ } else if (eflag & EFLG_TXEP) {
++ frame->can_id |= CAN_ERR_CRTL;
++ frame->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
++ } else if (eflag & EFLG_RXEP) {
++ frame->can_id |= CAN_ERR_CRTL;
++ frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
++ } else if (eflag & EFLG_TXWAR) {
++ frame->can_id |= CAN_ERR_CRTL;
++ frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
++ } else if (eflag & EFLG_RXWAR) {
++ frame->can_id |= CAN_ERR_CRTL;
++ frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
++ }
++ }
+
-+ mcp251x_read_reg(spi, CANSTAT);
++ if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
++ if (eflag & EFLG_RX0OVR) {
++ net->stats.rx_over_errors++;
++ } if (eflag & EFLG_RX1OVR) {
++ net->stats.rx_over_errors++;
++ } if (frame) {
++ frame->can_id |= CAN_ERR_CRTL;
++ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
++ }
++ mcp251x_write_reg(spi, EFLG, 0x00);
++ }
+
-+ dev_dbg(&spi->dev, "interrupt ended\n");
++ if (skb)
++ netif_rx(skb);
++ }
+
-+ return;
++ if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
++ net->stats.tx_packets++;
++ net->stats.tx_bytes +=
++ ((struct can_frame *)(priv->tx_skb->data))->can_dlc;
++ dev_kfree_skb(priv->tx_skb);
++ netif_wake_queue(net);
++ }
++
++ if (intf & CANINTF_RX0IF)
++ mcp251x_hw_rx(spi, 0);
++
++ if (intf & CANINTF_RX1IF)
++ mcp251x_hw_rx(spi, 1);
++
++ /* Clear everything except RX bits, don't want to miss any */
++ mcp251x_write_bits(spi, CANINTF, intf & ~(CANINTF_RX0IF | CANINTF_RX1IF), 0x00);
++ }
++
++ mcp251x_read_reg(spi, CANSTAT);
++
++ dev_dbg(&spi->dev, "interrupt ended\n");
+}
+
+
+static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
+{
-+ struct net_device *net = (struct net_device *)dev_id;
-+ struct mcp251x_priv *priv = netdev_priv(net);
-+ struct spi_device *spi = priv->spi;
++ struct net_device *net = (struct net_device *)dev_id;
++ struct mcp251x_priv *priv = netdev_priv(net);
+
-+ dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
++ /* Schedule bottom half */
++ queue_work(priv->wq, &priv->irq_work);
+
-+ /* Schedule bottom half */
-+ schedule_work(&priv->irq_work);
-+
-+ return IRQ_HANDLED;
++ return IRQ_HANDLED;
+}
+
++
+static void mcp251x_hw_reset(struct spi_device *spi)
+{
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ int ret;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ int ret;
+
-+ down(&priv->spi_lock);
++ down(&priv->spi_lock);
+
-+ priv->spi_tx_buf[0] = INSTRUCTION_RESET;
++ priv->spi_tx_buf[0] = INSTRUCTION_RESET;
+
-+ ret = spi_write(spi, priv->spi_tx_buf, 1);
-+ if (ret < 0)
-+ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
++ ret = spi_write(spi, priv->spi_tx_buf, 1);
+
-+ up(&priv->spi_lock);
++ up(&priv->spi_lock);
+
-+ return;
++ if (ret < 0)
++ dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
+}
+
+static struct net_device *alloc_mcp251x_netdev(int sizeof_priv)
+{
-+ struct net_device *net;
-+ struct mcp251x_priv *priv;
++ struct net_device *net;
++ struct mcp251x_priv *priv;
+
-+ net = alloc_candev(sizeof_priv);
-+ if (!net) {
-+ return NULL;
-+ }
++ net = alloc_candev(sizeof_priv);
++ if (!net) {
++ return NULL;
++ }
+
-+ priv = netdev_priv(net);
++ priv = netdev_priv(net);
+
-+ net->open = mcp251x_open;
-+ net->stop = mcp251x_stop;
-+ net->hard_start_xmit = mcp251x_hard_start_xmit;
++ net->open = mcp251x_open;
++ net->stop = mcp251x_stop;
++ net->hard_start_xmit = mcp251x_hard_start_xmit;
+
-+ /* Set loopback if module parameter was specified */
-+ if (loopback)
-+ net->flags |= IFF_LOOPBACK;
++ priv->can.baudrate = 250000;
++ priv->can.do_set_bit_time = mcp251x_do_set_bit_time;
++ priv->can.do_get_state = mcp251x_do_get_state;
++ priv->can.do_set_mode = mcp251x_do_set_mode;
+
-+ priv->can.baudrate = 250000;
-+ priv->can.do_set_bit_time = mcp251x_do_set_bit_time;
-+ priv->can.do_get_state = mcp251x_do_get_state;
-+ priv->can.do_set_mode = mcp251x_do_set_mode;
++ priv->net = net;
+
-+ priv->net = net;
-+
-+ return net;
++ return net;
+}
+
-+/* Platform file will specify something like:
-+ *
-+ * static struct mcp251x_platform_data mcp251x_info = {
-+ * .board_specific_setup = myboard_mcp251x_initfunc,
-+ * };
-+ *
-+ * static struct spi_board_info spi_board_info[] __initdata = {
-+ * {
-+ * .modalias = "mcp251x",
-+ * .platform_data = &mcp251x_info,
-+ * .irq = 10,
-+ * .max_speed_hz = 8000000,
-+ * .bus_num = 1,
-+ * .chip_select = 0
-+ * },
-+ * };
-+ *
-+ * (See Documentation/spi/spi-summary for more info)
-+ */
+
+static int __devinit mcp251x_can_probe(struct spi_device *spi)
+{
-+ struct net_device *net;
-+ struct mcp251x_priv *priv;
-+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
-+ struct can_bittime bit_time;
-+ int ret = -ENODEV;
-+ printk("mcp251x probe\n");
-+ if (!pdata) {
-+ /* Platform data is required for osc freq */
-+ goto error_out;
-+ }
++ struct net_device *net;
++ struct mcp251x_priv *priv;
++ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
++ struct can_bittime bit_time;
++ int ret = -ENODEV;
+
-+ /* Allocate can/net device */
-+ net = alloc_mcp251x_netdev(sizeof(struct mcp251x_priv));
-+ if (!net) {
-+ ret = -ENOMEM;
-+ goto error_alloc;
-+ }
++ if (!pdata) {
++ /* Platform data is required for osc freq */
++ goto error_out;
++ }
+
-+ priv = netdev_priv(net);
-+ dev_set_drvdata(&spi->dev, priv);
++ /* Allocate can/net device */
++ net = alloc_mcp251x_netdev(sizeof(struct mcp251x_priv));
++ if (!net) {
++ ret = -ENOMEM;
++ goto error_alloc;
++ }
+
-+ priv->spi = spi;
-+ init_MUTEX(&priv->spi_lock);
++ priv = netdev_priv(net);
++ dev_set_drvdata(&spi->dev, priv);
+
-+ /* Not sure why / 4... mcp251x pre-divides by 2 */
-+ priv->can.can_sys_clock = pdata->oscillator_frequency / 4;
++ priv->spi = spi;
++ init_MUTEX(&priv->spi_lock);
+
-+ /* If requested, allocate DMA buffers */
-+ if (enable_dma) {
-+ spi->dev.coherent_dma_mask = DMA_32BIT_MASK;
++ /* Not sure why / 4... mcp251x pre-divides by 2 */
++ priv->can.can_sys_clock = pdata->oscillator_frequency / 2;
+
-+ /* Minimum coherent DMA allocation is PAGE_SIZE, so allocate
++ /* If requested, allocate DMA buffers */
++ if (enable_dma) {
++ spi->dev.coherent_dma_mask = DMA_32BIT_MASK;
++
++ /* Minimum coherent DMA allocation is PAGE_SIZE, so allocate
+ that much and share it between Tx and Rx DMA buffers. */
-+ priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
-+ PAGE_SIZE, &priv->spi_tx_dma, GFP_DMA);
++ priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
++ PAGE_SIZE, &priv->spi_tx_dma, GFP_DMA);
+
-+ if (priv->spi_tx_buf) {
-+ priv->spi_rx_buf = (uint8_t *)(priv->spi_tx_buf +
-+ (PAGE_SIZE / 2));
-+ priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
-+ (PAGE_SIZE / 2));
-+ } else {
-+ /* Fall back to non-DMA */
-+ enable_dma = 0;
-+ }
-+ }
++ if (priv->spi_tx_buf) {
++ priv->spi_rx_buf = (u8 *)(priv->spi_tx_buf +
++ (PAGE_SIZE / 2));
++ priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
++ (PAGE_SIZE / 2));
++ } else {
++ /* Fall back to non-DMA */
++ enable_dma = 0;
++ }
++ }
+
-+ /* Allocate non-DMA buffers */
-+ if (!enable_dma) {
-+ priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
-+ if (!priv->spi_tx_buf) {
-+ ret = -ENOMEM;
-+ goto error_tx_buf;
-+ }
-+ priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
-+ if (!priv->spi_tx_buf) {
-+ ret = -ENOMEM;
-+ goto error_rx_buf;
-+ }
-+ }
++ /* Allocate non-DMA buffers */
++ if (!enable_dma) {
++ priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
++ if (!priv->spi_tx_buf) {
++ ret = -ENOMEM;
++ goto error_tx_buf;
++ }
++ priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
++ if (!priv->spi_tx_buf) {
++ ret = -ENOMEM;
++ goto error_rx_buf;
++ }
++ }
+
-+ /* Call out to platform specific setup */
-+ if (pdata->board_specific_setup)
-+ pdata->board_specific_setup(spi);
++ /* Call out to platform specific setup */
++ if (pdata->board_specific_setup)
++ pdata->board_specific_setup(spi);
+
-+ /* Call out to platform specific hardware reset */
-+ if (pdata->device_reset)
-+ pdata->device_reset(spi);
++ /* Call out to platform specific hardware reset */
++ if (pdata->device_reset)
++ pdata->device_reset(spi);
+
-+ /* Register IRQ */
-+ if (spi->irq >= 0) {
-+ if (request_irq(spi->irq, mcp251x_can_isr, IRQF_TRIGGER_FALLING, DEVICE_NAME, net) < 0) {
-+ dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
-+ goto error_irq;
-+ }
-+ }
++ /* Register IRQ */
++ if (spi->irq >= 0) {
++ if (request_irq(spi->irq, mcp251x_can_isr, IRQF_TRIGGER_FALLING, DEVICE_NAME, net) < 0) {
++ dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
++ goto error_irq;
++ }
++ }
+
-+ SET_NETDEV_DEV(net, &spi->dev);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-+ SET_MODULE_OWNER(THIS_MODULE);
-+#endif
++ SET_NETDEV_DEV(net, &spi->dev);
+
-+ INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
-+ INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler);
++ priv->wq = create_singlethread_workqueue("mcp251x_wq");
+
-+ /* Configure the SPI bus */
-+ spi->mode = SPI_MODE_0;
-+ spi->bits_per_word = 8;
-+ spi_setup(spi);
++ INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
++ INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler);
+
-+ mcp251x_hw_reset(spi);
++ init_completion(&priv->awake);
+
-+ /* Set initial baudrate */
-+ ret = can_calc_bit_time(&priv->can, priv->can.baudrate, &bit_time.std);
-+ if (ret != 0)
-+ dev_err(&spi->dev, "unable to calculate initial baudrate!\n");
-+ else {
-+ bit_time.type = CAN_BITTIME_STD;
-+ ret = priv->can.do_set_bit_time(net, &bit_time);
-+ if (ret)
-+ dev_err(&spi->dev, "unable to set initial baudrate!\n");
-+ }
++ /* Configure the SPI bus */
++ spi->mode = SPI_MODE_0;
++ spi->bits_per_word = 8;
++ spi_setup(spi);
+
-+ mcp251x_hw_sleep(spi);
++ mcp251x_hw_reset(spi);
+
-+ ret = register_netdev(net);
-+ if (ret >= 0) {
-+ dev_info(&spi->dev, "probed%s\n", (loopback) ? " (loopback)" : "");
-+ return ret;
-+ }
++ /* Set initial baudrate */
++ ret = can_calc_bit_time(&priv->can, priv->can.baudrate, &bit_time.std);
++ if (ret != 0)
++ dev_err(&spi->dev, "unable to calculate initial baudrate!\n");
++ else {
++ bit_time.type = CAN_BITTIME_STD;
++ ret = priv->can.do_set_bit_time(net, &bit_time);
++ if (ret)
++ dev_err(&spi->dev, "unable to set initial baudrate!\n");
++ }
+
-+ free_irq(spi->irq, net);
++ /* Enable RX0->RX1 buffer roll over */
++ mcp251x_write_bits(spi, RXBCTRL(0), RXBCTRL_BUKT, RXBCTRL_BUKT);
++
++ mcp251x_hw_sleep(spi);
++
++ ret = register_netdev(net);
++ if (ret >= 0) {
++ dev_info(&spi->dev, "probed%s\n",
++ (loopback) ? " (loopback)" : "");
++ return ret;
++ }
++
++ free_irq(spi->irq, net);
+error_irq:
-+ if (!enable_dma)
-+ kfree(priv->spi_rx_buf);
++ if (!enable_dma)
++ kfree(priv->spi_rx_buf);
+error_rx_buf:
-+ if (!enable_dma)
-+ kfree(priv->spi_tx_buf);
++ if (!enable_dma)
++ kfree(priv->spi_tx_buf);
+error_tx_buf:
-+ free_candev(net);
-+ if (enable_dma) {
-+ dma_free_coherent(&spi->dev, PAGE_SIZE,
-+ priv->spi_tx_buf, priv->spi_tx_dma);
-+ }
++ free_candev(net);
++ if (enable_dma) {
++ dma_free_coherent(&spi->dev, PAGE_SIZE,
++ priv->spi_tx_buf, priv->spi_tx_dma);
++ }
+error_alloc:
-+ dev_err(&spi->dev, "probe failed\n");
++ dev_err(&spi->dev, "probe failed\n");
+error_out:
-+ return ret;
++ return ret;
+}
+
+static int __devexit mcp251x_can_remove(struct spi_device *spi)
+{
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct net_device *net = priv->net;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct net_device *net = priv->net;
+
-+ work_clear_pending(&priv->tx_work);
++ free_irq(spi->irq, net);
+
-+ free_irq(spi->irq, net);
-+ work_clear_pending(&priv->irq_work);
++ flush_scheduled_work();
+
-+ flush_scheduled_work();
++ if (enable_dma) {
++ dma_free_coherent(&spi->dev, PAGE_SIZE,
++ priv->spi_tx_buf, priv->spi_tx_dma);
++ } else {
++ kfree(priv->spi_tx_buf);
++ kfree(priv->spi_rx_buf);
++ }
+
-+ if (enable_dma) {
-+ dma_free_coherent(&spi->dev, PAGE_SIZE,
-+ priv->spi_tx_buf, priv->spi_tx_dma);
-+ } else {
-+ kfree(priv->spi_tx_buf);
-+ kfree(priv->spi_rx_buf);
-+ }
++ unregister_netdev(net);
++ free_candev(net);
+
-+ unregister_netdev(net);
-+ free_candev(net);
-+
-+ return 0;
++ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
+{
-+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct net_device *net = priv->net;
++ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct net_device *net = priv->net;
+
-+ if (!netif_running(net))
-+ return 0;
++ if (!netif_running(net))
++ return 0;
+
-+ netif_device_detach(net);
++ netif_device_detach(net);
+
-+ mcp251x_hw_sleep(spi);
-+ if (pdata->transceiver_enable)
-+ pdata->transceiver_enable(0);
++ mcp251x_hw_sleep(spi);
++ if (pdata->transceiver_enable)
++ pdata->transceiver_enable(0);
+
-+ return 0;
++ return 0;
+}
+
+static int mcp251x_can_resume(struct spi_device *spi)
+{
-+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
-+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-+ struct net_device *net = priv->net;
++ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
++ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
++ struct net_device *net = priv->net;
+
-+ if (!netif_running(net))
-+ return 0;
++ if (!netif_running(net))
++ return 0;
+
-+ if (pdata->transceiver_enable)
-+ pdata->transceiver_enable(1);
-+ mcp251x_hw_wakeup(spi);
++ if (pdata->transceiver_enable)
++ pdata->transceiver_enable(1);
++ mcp251x_hw_wakeup(spi);
+
-+ netif_device_attach(net);
++ netif_device_attach(net);
+
-+ return 0;
++ return 0;
+}
++#else
++#define mcp251x_can_suspend NULL
++#define mcp251x_can_resume NULL
+#endif
+
+static struct spi_driver mcp251x_can_driver = {
-+ .driver = {
-+ .name = DEVICE_NAME,
-+ .bus = &spi_bus_type,
-+ .owner = THIS_MODULE,
-+ },
++ .driver = {
++ .name = DEVICE_NAME,
++ .bus = &spi_bus_type,
++ .owner = THIS_MODULE,
++ },
+
-+ .probe = mcp251x_can_probe,
-+ .remove = __devexit_p(mcp251x_can_remove),
-+#ifdef CONFIG_PM
-+ .suspend = mcp251x_can_suspend,
-+ .resume = mcp251x_can_resume,
-+#endif
++ .probe = mcp251x_can_probe,
++ .remove = __devexit_p(mcp251x_can_remove),
++ .suspend = mcp251x_can_suspend,
++ .resume = mcp251x_can_resume,
+};
+
+static int __init mcp251x_can_init(void)
+{
-+ printk("mcp251x init\n");
-+ return spi_register_driver(&mcp251x_can_driver);
++ return spi_register_driver(&mcp251x_can_driver);
+}
+
+static void __exit mcp251x_can_exit(void)
+{
-+ spi_unregister_driver(&mcp251x_can_driver);
++ spi_unregister_driver(&mcp251x_can_driver);
+}
+
+module_init(mcp251x_can_init);
+module_exit(mcp251x_can_exit);
+
-+MODULE_AUTHOR("Chris Elston <celston@...>");
++MODULE_AUTHOR("Claudio Scordino <cl...@ev...");
+MODULE_DESCRIPTION("Microchip 251x CAN driver");
+MODULE_LICENSE("GPL v2");
-Index: linux-2.6.19.2/drivers/net/can/mcp251x.h
-===================================================================
+diff --git a/drivers/net/can/mcp251x.h b/drivers/net/can/mcp251x.h
+new file mode 100644
+index 0000000..acdf4ea
--- /dev/null
-+++ linux-2.6.19.2/drivers/net/can/mcp251x.h
++++ b/drivers/net/can/mcp251x.h
@@ -0,0 +1,11 @@
+#ifndef __MCP251X_H__
+#define __MCP251X_H__
+
+struct mcp251x_platform_data {
-+ unsigned long oscillator_frequency;
-+ int (*board_specific_setup)(struct spi_device *spi);
-+ int (*device_reset)(struct spi_device *spi);
-+ int (*transceiver_enable)(int enable);
++ unsigned long oscillator_frequency;
++ int (*board_specific_setup)(struct spi_device *spi);
++ int (*device_reset)(struct spi_device *spi);
++ int (*transceiver_enable)(int enable);
+};
+
+#endif /* __MCP251X_H__ */
+diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
+new file mode 100644
+index 0000000..9c4bee7
+--- /dev/null
++++ b/include/linux/can/dev.h
+@@ -0,0 +1,60 @@
++/*
++ * linux/can/dev.h
++ *
++ * Definitions for CAN controller network devices lib (work in progress)
++ *
++ * Author: Andrey Volkov <av...@va...>
++ * Copyright (c) 2006 Varma Electronics Oy
++ *
++ */
++
++#ifndef CAN_DEVICE_H
++#define CAN_DEVICE_H
++
++#include <linux/version.h>
++#include <linux/can/error.h>
++#include <linux/can/ioctl.h>
++
++struct can_priv {
++ struct can_device_stats can_stats;
++
++ /* can-bus oscillator frequency, in Hz,
++ BE CAREFUL! SOME CONTROLLERS (LIKE SJA1000)
++ FOOLISH ABOUT THIS FRQ (for sja1000 as ex. this
++ clock must be xtal clock divided by 2). */
++ u32 can_sys_clock;
++
++ /* by default max_brp is equal 64,
++ but for a Freescale TouCAN, as ex., it can be 255*/
++ u32 max_brp;
++ /* For the mostly all controllers, max_sjw is equal 4, but
++ some, hmm, CAN implementations hardwared it to 1 */
++ u8 max_sjw;
++
++ u32 baudrate; /* in bauds */
++ struct can_bittime bit_time;
++
++ spinlock_t irq_lock;
++ /* Please hold this lock when touching net_stats/can_stats*/
++ spinlock_t stats_lock;
++
++ can_state_t state;
++ can_mode_t mode;
++ can_ctrlmode_t ctrlmode;
++
++ int (*do_set_bit_time)(struct net_device *dev, struct can_bittime *br);
++ int (*do_get_state) (struct net_device *dev, can_state_t *state);
++ int (*do_set_mode) (struct net_device *dev, can_mode_t mode);
++ int (*do_set_ctrlmode)(struct net_device *dev, can_ctrlmode_t ctrlmode);
++ int (*do_get_ctrlmode)(struct net_device *dev, can_ctrlmode_t *ctrlmode);
++};
++
++#define ND2D(_ndev) (_ndev->dev.parent)
++
++struct net_device *alloc_candev(int sizeof_priv);
++void free_candev(struct net_device *dev);
++
++int can_calc_bit_time(struct can_priv *can, u32 baudrate,
++ struct can_bittime_std *bit_time);
++
++#endif /* CAN_DEVICE_H */
+diff --git a/include/linux/can/ioctl.h b/include/linux/can/ioctl.h
+new file mode 100644
+index 0000000..30f2dad
+--- /dev/null
++++ b/include/linux/can/ioctl.h
+@@ -0,0 +1,149 @@
++/*
++ * linux/can/ioctl.h
++ *
++ * Definitions for CAN controller setup (work in progress)
++ *
++ * Send feedback to <soc...@li...>
++ *
++ */
++
++#ifndef CAN_IOCTL_H
++#define CAN_IOCTL_H
++
++#include <linux/sockios.h>
++
++
++/* max. 16 private ioctls */
++
++#define SIOCSCANBAUDRATE (SIOCDEVPRIVATE+0)
++#define SIOCGCANBAUDRATE (SIOCDEVPRIVATE+1)
++
++#define SIOCSCANCUSTOMBITTIME (SIOCDEVPRIVATE+2)
++#define SIOCGCANCUSTOMBITTIME (SIOCDEVPRIVATE+3)
++
++#define SIOCSCANMODE (SIOCDEVPRIVATE+4)
++#define SIOCGCANMODE (SIOCDEVPRIVATE+5)
++
++#define SIOCSCANCTRLMODE (SIOCDEVPRIVATE+6)
++#define SIOCGCANCTRLMODE (SIOCDEVPRIVATE+7)
++
++#define SIOCSCANFILTER (SIOCDEVPRIVATE+8)
++#define SIOCGCANFILTER (SIOCDEVPRIVATE+9)
++
++#define SIOCGCANSTATE (SIOCDEVPRIVATE+10)
++#define SIOCGCANSTATS (SIOCDEVPRIVATE+11)
++
++#define SIOCSCANERRORCONFIG (SIOCDEVPRIVATE+12)
++#define SIOCGCANERRORCONFIG (SIOCDEVPRIVATE+13)
++
++/* parameters for ioctls */
++
++/* SIOC[SG]CANBAUDRATE */
++/* baudrate for CAN-controller in bits per second. */
++/* 0 = Scan for baudrate (Autobaud) */
++
++typedef __u32 can_baudrate_t;
++
++
++/* SIOC[SG]CANCUSTOMBITTIME */
++
++typedef enum CAN_BITTIME_TYPE {
++ CAN_BITTIME_STD,
++ CAN_BITTIME_BTR
++} can_bittime_type_t;
++
++/* TSEG1 of controllers usually is a sum of synch_seg (always 1),
++ * prop_seg and phase_seg1, TSEG2 = phase_seg2 */
++
++struct can_bittime_std {
++ __u32 brp; /* baud rate prescaler */
++ __u8 prop_seg; /* from 1 to 8 */
++ __u8 phase_seg1; /* from 1 to 8 */
++ __u8 phase_seg2; /* from 1 to 8 */
++ __u8 sjw:7; /* from 1 to 4 */
++ __u8 sam:1; /* 1 - enable triple sampling */
++};
++
++struct can_bittime_btr {
++ __u8 btr0;
++ __u8 btr1;
++};
++
++struct can_bittime {
++ can_bittime_type_t type;
++ union {
++ struct can_bittime_std std;
++ struct can_bittime_btr btr;
++ };
++};
++
++#define CAN_BAUDRATE_UNCONFIGURED ((__u32) 0xFFFFFFFFU)
++#define CAN_BAUDRATE_UNKNOWN 0
++
++/* SIOC[SG]CANMODE */
++
++typedef __u32 can_mode_t;
++
++#define CAN_MODE_STOP 0
++#define CAN_MODE_START 1
++#define CAN_MODE_SLEEP 2
++
++
++/* SIOC[SG]CANCTRLMODE */
++
++typedef __u32 can_ctrlmode_t;
++
++#define CAN_CTRLMODE_LOOPBACK 0x1
++#define CAN_CTRLMODE_LISTENONLY 0x2
++
++
++/* SIOCGCANFILTER */
++
++typedef __u32 can_filter_t;
++
++/* filter modes (may vary due to controller specific capabilities) */
++#define CAN_FILTER_CAPAB 0 /* get filter type capabilities (32 Bit value) */
++#define CAN_FILTER_MASK_VALUE 1 /* easy bit filter (see struct can_filter) */
++#define CAN_FILTER_SFF_BITMASK 2 /* bitfield with 2048 bit SFF filter */
++ /* filters 3 - 31 currently undefined */
++
++#define CAN_FILTER_MAX 31 /* max. filter type value */
++
++
++/* SIOCGCANSTATE */
++
++typedef __u32 can_state_t;
++
++#define CAN_STATE_ACTIVE 0
++#define CAN_STATE_BUS_WARNING 1
++#define CAN_STATE_BUS_PASSIVE 2
++#define CAN_STATE_BUS_OFF 3
++#define CAN_STATE_SCANNING_BAUDRATE 4
++#define CAN_STATE_STOPPED 5
++#define CAN_STATE_SLEEPING 6
++
++
++/* SIOCGCANSTATS */
++
++struct can_device_stats {
++ int error_warning;
++ int data_overrun;
++ int wakeup;
++ int bus_error;
++ int error_passive;
++ int arbitration_lost;
++ int restarts;
++ int bus_error_at_init;
++};
++
++/* SIOC[SG]CANERRORCONFIG */
++
++typedef enum CAN_ERRCFG_TYPE {
++ CAN_ERRCFG_MASK,
++ CAN_ERRCFG_BUSERR,
++ CAN_ERRCFG_BUSOFF
++} can_errcfg_type_t;
++
++/* tbd */
++
++#endif /* CAN_IOCTL_H */
+diff --git a/net/can/Makefile b/net/can/Makefile
+index 9cd3c4b..11e8903 100644
+--- a/net/can/Makefile
++++ b/net/can/Makefile
+@@ -10,3 +10,6 @@ can-raw-objs := raw.o
+
+ obj-$(CONFIG_CAN_BCM) += can-bcm.o
+ can-bcm-objs := bcm.o
++
++obj-$(CONFIG_CAN) += candev.o
++candev-objs := dev.o
+diff --git a/net/can/dev.c b/net/can/dev.c
+new file mode 100644
+index 0000000..493ba39
+--- /dev/null
++++ b/net/can/dev.c
+@@ -0,0 +1,275 @@
++/*
++ * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
++ * Copyright (C) 2006 Andrey Volkov, Varma Electronics
++ *
++ * 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 ...
[truncated message content] |