Commit 98a20b73 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-3.16-20140425' of git://gitorious.org/linux-can/linux-can-next

Marc Kleine-Budde says:

====================
this is a pull request of 10 patches for net-next/master.

It consists of three patches by Alexander Shiyan, which improve the
mcp251x driver. Stefano Babic's patch move the SPI driver into a sub
folder. The three patches by Olivier Sobrie add support for the Kvaser
Leaf v2 and usb mini PCIe hardware to the existing driver. Alexander
Stein contributes eg20t support to the c_can pci driver. Together with
the patches on the net-tree, we'll be able to remove the pch_can driver
soon. Kurt Van Dijck's two patches clean up the sysfs attributes of the
softing driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 16b46306 0f8dced5
...@@ -77,12 +77,6 @@ config CAN_TI_HECC ...@@ -77,12 +77,6 @@ config CAN_TI_HECC
Driver for TI HECC (High End CAN Controller) module found on many Driver for TI HECC (High End CAN Controller) module found on many
TI devices. The device specifications are available from www.ti.com TI devices. The device specifications are available from www.ti.com
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on SPI && HAS_DMA
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
config CAN_BFIN config CAN_BFIN
depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
tristate "Analog Devices Blackfin on-chip CAN" tristate "Analog Devices Blackfin on-chip CAN"
...@@ -133,6 +127,8 @@ source "drivers/net/can/c_can/Kconfig" ...@@ -133,6 +127,8 @@ source "drivers/net/can/c_can/Kconfig"
source "drivers/net/can/cc770/Kconfig" source "drivers/net/can/cc770/Kconfig"
source "drivers/net/can/spi/Kconfig"
source "drivers/net/can/usb/Kconfig" source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig" source "drivers/net/can/softing/Kconfig"
......
...@@ -10,6 +10,7 @@ can-dev-y := dev.o ...@@ -10,6 +10,7 @@ can-dev-y := dev.o
can-dev-$(CONFIG_CAN_LEDS) += led.o can-dev-$(CONFIG_CAN_LEDS) += led.o
obj-y += spi/
obj-y += usb/ obj-y += usb/
obj-y += softing/ obj-y += softing/
...@@ -19,7 +20,6 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/ ...@@ -19,7 +20,6 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_CC770) += cc770/ obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
......
...@@ -19,9 +19,13 @@ ...@@ -19,9 +19,13 @@
#include "c_can.h" #include "c_can.h"
#define PCI_DEVICE_ID_PCH_CAN 0x8818
#define PCH_PCI_SOFT_RESET 0x01fc
enum c_can_pci_reg_align { enum c_can_pci_reg_align {
C_CAN_REG_ALIGN_16, C_CAN_REG_ALIGN_16,
C_CAN_REG_ALIGN_32, C_CAN_REG_ALIGN_32,
C_CAN_REG_32,
}; };
struct c_can_pci_data { struct c_can_pci_data {
...@@ -31,6 +35,10 @@ struct c_can_pci_data { ...@@ -31,6 +35,10 @@ struct c_can_pci_data {
enum c_can_pci_reg_align reg_align; enum c_can_pci_reg_align reg_align;
/* Set the frequency */ /* Set the frequency */
unsigned int freq; unsigned int freq;
/* PCI bar number */
int bar;
/* Callback for reset */
void (*init)(const struct c_can_priv *priv, bool enable);
}; };
/* /*
...@@ -63,6 +71,29 @@ static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv, ...@@ -63,6 +71,29 @@ static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
writew(val, priv->base + 2 * priv->regs[index]); writew(val, priv->base + 2 * priv->regs[index]);
} }
static u16 c_can_pci_read_reg_32bit(struct c_can_priv *priv,
enum reg index)
{
return (u16)ioread32(priv->base + 2 * priv->regs[index]);
}
static void c_can_pci_write_reg_32bit(struct c_can_priv *priv,
enum reg index, u16 val)
{
iowrite32((u32)val, priv->base + 2 * priv->regs[index]);
}
static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable)
{
if (enable) {
u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET;
/* write to sw reset register */
iowrite32(1, addr);
iowrite32(0, addr);
}
}
static int c_can_pci_probe(struct pci_dev *pdev, static int c_can_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
...@@ -87,7 +118,8 @@ static int c_can_pci_probe(struct pci_dev *pdev, ...@@ -87,7 +118,8 @@ static int c_can_pci_probe(struct pci_dev *pdev,
pci_set_master(pdev); pci_set_master(pdev);
pci_enable_msi(pdev); pci_enable_msi(pdev);
addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); addr = pci_iomap(pdev, c_can_pci_data->bar,
pci_resource_len(pdev, c_can_pci_data->bar));
if (!addr) { if (!addr) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"device has no PCI memory resources, " "device has no PCI memory resources, "
...@@ -142,11 +174,17 @@ static int c_can_pci_probe(struct pci_dev *pdev, ...@@ -142,11 +174,17 @@ static int c_can_pci_probe(struct pci_dev *pdev,
priv->read_reg = c_can_pci_read_reg_aligned_to_16bit; priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
priv->write_reg = c_can_pci_write_reg_aligned_to_16bit; priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
break; break;
case C_CAN_REG_32:
priv->read_reg = c_can_pci_read_reg_32bit;
priv->write_reg = c_can_pci_write_reg_32bit;
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
goto out_free_c_can; goto out_free_c_can;
} }
priv->raminit = c_can_pci_data->init;
ret = register_c_can_dev(dev); ret = register_c_can_dev(dev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n", dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
...@@ -193,6 +231,15 @@ static struct c_can_pci_data c_can_sta2x11= { ...@@ -193,6 +231,15 @@ static struct c_can_pci_data c_can_sta2x11= {
.type = BOSCH_C_CAN, .type = BOSCH_C_CAN,
.reg_align = C_CAN_REG_ALIGN_32, .reg_align = C_CAN_REG_ALIGN_32,
.freq = 52000000, /* 52 Mhz */ .freq = 52000000, /* 52 Mhz */
.bar = 0,
};
static struct c_can_pci_data c_can_pch = {
.type = BOSCH_C_CAN,
.reg_align = C_CAN_REG_32,
.freq = 50000000, /* 50 MHz */
.init = c_can_pci_reset_pch,
.bar = 1,
}; };
#define C_CAN_ID(_vend, _dev, _driverdata) { \ #define C_CAN_ID(_vend, _dev, _driverdata) { \
...@@ -202,6 +249,8 @@ static struct c_can_pci_data c_can_sta2x11= { ...@@ -202,6 +249,8 @@ static struct c_can_pci_data c_can_sta2x11= {
static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = { static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN, C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
c_can_sta2x11), c_can_sta2x11),
C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN,
c_can_pch),
{}, {},
}; };
static struct pci_driver c_can_pci_driver = { static struct pci_driver c_can_pci_driver = {
......
...@@ -556,15 +556,6 @@ static int softing_card_boot(struct softing *card) ...@@ -556,15 +556,6 @@ static int softing_card_boot(struct softing *card)
/* /*
* netdev sysfs * netdev sysfs
*/ */
static ssize_t show_channel(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
return sprintf(buf, "%i\n", priv->index);
}
static ssize_t show_chip(struct device *dev, struct device_attribute *attr, static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -609,12 +600,10 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr, ...@@ -609,12 +600,10 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr,
return count; return count;
} }
static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL); static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL);
static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output); static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
static const struct attribute *const netdev_sysfs_attrs[] = { static const struct attribute *const netdev_sysfs_attrs[] = {
&dev_attr_channel.attr,
&dev_attr_chip.attr, &dev_attr_chip.attr,
&dev_attr_output.attr, &dev_attr_output.attr,
NULL, NULL,
...@@ -679,17 +668,20 @@ static int softing_netdev_register(struct net_device *netdev) ...@@ -679,17 +668,20 @@ static int softing_netdev_register(struct net_device *netdev)
{ {
int ret; int ret;
netdev->sysfs_groups[0] = &netdev_sysfs_group;
ret = register_candev(netdev); ret = register_candev(netdev);
if (ret) { if (ret) {
dev_alert(&netdev->dev, "register failed\n"); dev_alert(&netdev->dev, "register failed\n");
return ret; return ret;
} }
if (sysfs_create_group(&netdev->dev.kobj, &netdev_sysfs_group) < 0)
netdev_alert(netdev, "sysfs group failed\n");
return 0; return 0;
} }
static void softing_netdev_cleanup(struct net_device *netdev) static void softing_netdev_cleanup(struct net_device *netdev)
{ {
sysfs_remove_group(&netdev->dev.kobj, &netdev_sysfs_group);
unregister_candev(netdev); unregister_candev(netdev);
free_candev(netdev); free_candev(netdev);
} }
...@@ -721,8 +713,6 @@ DEV_ATTR_RO(firmware_version, id.fw_version); ...@@ -721,8 +713,6 @@ DEV_ATTR_RO(firmware_version, id.fw_version);
DEV_ATTR_RO_STR(hardware, pdat->name); DEV_ATTR_RO_STR(hardware, pdat->name);
DEV_ATTR_RO(hardware_version, id.hw_version); DEV_ATTR_RO(hardware_version, id.hw_version);
DEV_ATTR_RO(license, id.license); DEV_ATTR_RO(license, id.license);
DEV_ATTR_RO(frequency, id.freq);
DEV_ATTR_RO(txpending, tx.pending);
static struct attribute *softing_pdev_attrs[] = { static struct attribute *softing_pdev_attrs[] = {
&dev_attr_serial.attr, &dev_attr_serial.attr,
...@@ -731,8 +721,6 @@ static struct attribute *softing_pdev_attrs[] = { ...@@ -731,8 +721,6 @@ static struct attribute *softing_pdev_attrs[] = {
&dev_attr_hardware.attr, &dev_attr_hardware.attr,
&dev_attr_hardware_version.attr, &dev_attr_hardware_version.attr,
&dev_attr_license.attr, &dev_attr_license.attr,
&dev_attr_frequency.attr,
&dev_attr_txpending.attr,
NULL, NULL,
}; };
......
menu "CAN SPI interfaces"
depends on SPI
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on HAS_DMA
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
endmenu
#
# Makefile for the Linux Controller Area Network SPI drivers.
#
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
...@@ -214,6 +214,8 @@ ...@@ -214,6 +214,8 @@
#define TX_ECHO_SKB_MAX 1 #define TX_ECHO_SKB_MAX 1
#define MCP251X_OST_DELAY_MS (5)
#define DEVICE_NAME "mcp251x" #define DEVICE_NAME "mcp251x"
static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */ static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
...@@ -624,50 +626,45 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv, ...@@ -624,50 +626,45 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
static int mcp251x_hw_reset(struct spi_device *spi) static int mcp251x_hw_reset(struct spi_device *spi)
{ {
struct mcp251x_priv *priv = spi_get_drvdata(spi); struct mcp251x_priv *priv = spi_get_drvdata(spi);
u8 reg;
int ret; int ret;
unsigned long timeout;
/* Wait for oscillator startup timer after power up */
mdelay(MCP251X_OST_DELAY_MS);
priv->spi_tx_buf[0] = INSTRUCTION_RESET; priv->spi_tx_buf[0] = INSTRUCTION_RESET;
ret = spi_write(spi, priv->spi_tx_buf, 1); ret = mcp251x_spi_trans(spi, 1);
if (ret) { if (ret)
dev_err(&spi->dev, "reset failed: ret = %d\n", ret); return ret;
return -EIO;
} /* Wait for oscillator startup timer after reset */
mdelay(MCP251X_OST_DELAY_MS);
reg = mcp251x_read_reg(spi, CANSTAT);
if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
return -ENODEV;
/* Wait for reset to finish */
timeout = jiffies + HZ;
mdelay(10);
while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)
!= CANCTRL_REQOP_CONF) {
schedule();
if (time_after(jiffies, timeout)) {
dev_err(&spi->dev, "MCP251x didn't"
" enter in conf mode after reset\n");
return -EBUSY;
}
}
return 0; return 0;
} }
static int mcp251x_hw_probe(struct spi_device *spi) static int mcp251x_hw_probe(struct spi_device *spi)
{ {
int st1, st2; u8 ctrl;
int ret;
mcp251x_hw_reset(spi); ret = mcp251x_hw_reset(spi);
if (ret)
return ret;
/* ctrl = mcp251x_read_reg(spi, CANCTRL);
* Please note that these are "magic values" based on after
* reset defaults taken from data sheet which allows us to see dev_dbg(&spi->dev, "CANCTRL 0x%02x\n", ctrl);
* if we really have a chip on the bus (we avoid common all
* zeroes or all ones situations)
*/
st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2); /* Check for power up default value */
if ((ctrl & 0x17) != 0x07)
return -ENODEV;
/* Check for power up default values */ return 0;
return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
} }
static int mcp251x_power_enable(struct regulator *reg, int enable) static int mcp251x_power_enable(struct regulator *reg, int enable)
...@@ -776,7 +773,6 @@ static void mcp251x_restart_work_handler(struct work_struct *ws) ...@@ -776,7 +773,6 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
mutex_lock(&priv->mcp_lock); mutex_lock(&priv->mcp_lock);
if (priv->after_suspend) { if (priv->after_suspend) {
mdelay(10);
mcp251x_hw_reset(spi); mcp251x_hw_reset(spi);
mcp251x_setup(net, priv, spi); mcp251x_setup(net, priv, spi);
if (priv->after_suspend & AFTER_SUSPEND_RESTART) { if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
...@@ -1032,8 +1028,8 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1032,8 +1028,8 @@ static int mcp251x_can_probe(struct spi_device *spi)
struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev); struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev);
struct net_device *net; struct net_device *net;
struct mcp251x_priv *priv; struct mcp251x_priv *priv;
int freq, ret = -ENODEV;
struct clk *clk; struct clk *clk;
int freq, ret;
clk = devm_clk_get(&spi->dev, NULL); clk = devm_clk_get(&spi->dev, NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
...@@ -1076,6 +1072,18 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1076,6 +1072,18 @@ static int mcp251x_can_probe(struct spi_device *spi)
priv->net = net; priv->net = net;
priv->clk = clk; priv->clk = clk;
spi_set_drvdata(spi, priv);
/* Configure the SPI bus */
spi->bits_per_word = 8;
if (mcp251x_is_2510(spi))
spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
else
spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
ret = spi_setup(spi);
if (ret)
goto out_clk;
priv->power = devm_regulator_get(&spi->dev, "vdd"); priv->power = devm_regulator_get(&spi->dev, "vdd");
priv->transceiver = devm_regulator_get(&spi->dev, "xceiver"); priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
if ((PTR_ERR(priv->power) == -EPROBE_DEFER) || if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
...@@ -1088,8 +1096,6 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1088,8 +1096,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
if (ret) if (ret)
goto out_clk; goto out_clk;
spi_set_drvdata(spi, priv);
priv->spi = spi; priv->spi = spi;
mutex_init(&priv->mcp_lock); mutex_init(&priv->mcp_lock);
...@@ -1134,20 +1140,11 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1134,20 +1140,11 @@ static int mcp251x_can_probe(struct spi_device *spi)
SET_NETDEV_DEV(net, &spi->dev); SET_NETDEV_DEV(net, &spi->dev);
/* Configure the SPI bus */
spi->mode = spi->mode ? : SPI_MODE_0;
if (mcp251x_is_2510(spi))
spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
else
spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
spi->bits_per_word = 8;
spi_setup(spi);
/* Here is OK to not lock the MCP, no one knows about it yet */ /* Here is OK to not lock the MCP, no one knows about it yet */
if (!mcp251x_hw_probe(spi)) { ret = mcp251x_hw_probe(spi);
ret = -ENODEV; if (ret)
goto error_probe; goto error_probe;
}
mcp251x_hw_sleep(spi); mcp251x_hw_sleep(spi);
ret = register_candev(net); ret = register_candev(net);
...@@ -1156,7 +1153,7 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1156,7 +1153,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
devm_can_led_init(net); devm_can_led_init(net);
return ret; return 0;
error_probe: error_probe:
if (mcp251x_enable_dma) if (mcp251x_enable_dma)
......
...@@ -19,7 +19,7 @@ config CAN_KVASER_USB ...@@ -19,7 +19,7 @@ config CAN_KVASER_USB
This driver adds support for Kvaser CAN/USB devices like Kvaser This driver adds support for Kvaser CAN/USB devices like Kvaser
Leaf Light. Leaf Light.
The driver gives support for the following devices: The driver provides support for the following devices:
- Kvaser Leaf Light - Kvaser Leaf Light
- Kvaser Leaf Professional HS - Kvaser Leaf Professional HS
- Kvaser Leaf SemiPro HS - Kvaser Leaf SemiPro HS
...@@ -36,6 +36,8 @@ config CAN_KVASER_USB ...@@ -36,6 +36,8 @@ config CAN_KVASER_USB
- Kvaser Leaf Light "China" - Kvaser Leaf Light "China"
- Kvaser BlackBird SemiPro - Kvaser BlackBird SemiPro
- Kvaser USBcan R - Kvaser USBcan R
- Kvaser Leaf Light v2
- Kvaser Mini PCI Express HS
If unsure, say N. If unsure, say N.
......
...@@ -53,6 +53,8 @@ ...@@ -53,6 +53,8 @@
#define USB_OEM_MERCURY_PRODUCT_ID 34 #define USB_OEM_MERCURY_PRODUCT_ID 34
#define USB_OEM_LEAF_PRODUCT_ID 35 #define USB_OEM_LEAF_PRODUCT_ID 35
#define USB_CAN_R_PRODUCT_ID 39 #define USB_CAN_R_PRODUCT_ID 39
#define USB_LEAF_LITE_V2_PRODUCT_ID 288
#define USB_MINI_PCIE_HS_PRODUCT_ID 289
/* USB devices features */ /* USB devices features */
#define KVASER_HAS_SILENT_MODE BIT(0) #define KVASER_HAS_SILENT_MODE BIT(0)
...@@ -356,6 +358,8 @@ static const struct usb_device_id kvaser_usb_table[] = { ...@@ -356,6 +358,8 @@ static const struct usb_device_id kvaser_usb_table[] = {
.driver_info = KVASER_HAS_TXRX_ERRORS }, .driver_info = KVASER_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID), { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
.driver_info = KVASER_HAS_TXRX_ERRORS }, .driver_info = KVASER_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
{ } { }
}; };
MODULE_DEVICE_TABLE(usb, kvaser_usb_table); MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
...@@ -379,12 +383,14 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, ...@@ -379,12 +383,14 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
void *buf; void *buf;
int actual_len; int actual_len;
int err; int err;
int pos = 0; int pos;
unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT);
buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL); buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
do {
err = usb_bulk_msg(dev->udev, err = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, usb_rcvbulkpipe(dev->udev,
dev->bulk_in->bEndpointAddress), dev->bulk_in->bEndpointAddress),
...@@ -393,6 +399,7 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, ...@@ -393,6 +399,7 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
if (err < 0) if (err < 0)
goto end; goto end;
pos = 0;
while (pos <= actual_len - MSG_HEADER_LEN) { while (pos <= actual_len - MSG_HEADER_LEN) {
tmp = buf + pos; tmp = buf + pos;
...@@ -400,7 +407,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, ...@@ -400,7 +407,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
break; break;
if (pos + tmp->len > actual_len) { if (pos + tmp->len > actual_len) {
dev_err(dev->udev->dev.parent, "Format error\n"); dev_err(dev->udev->dev.parent,
"Format error\n");
break; break;
} }
...@@ -411,6 +419,7 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, ...@@ -411,6 +419,7 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
pos += tmp->len; pos += tmp->len;
} }
} while (time_before(jiffies, to));
err = -EINVAL; err = -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment