Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
ffcb9738
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
ffcb9738
编写于
3月 04, 2012
作者:
D
David S. Miller
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of
git://gitorious.org/linux-can/linux-can-next
上级
4c1dc80a
d8a19935
变更
13
隐藏空白更改
内联
并排
Showing
13 changed file
with
4490 addition
and
18 deletion
+4490
-18
drivers/net/can/cc770/cc770.c
drivers/net/can/cc770/cc770.c
+0
-1
drivers/net/can/sja1000/Kconfig
drivers/net/can/sja1000/Kconfig
+24
-3
drivers/net/can/sja1000/Makefile
drivers/net/can/sja1000/Makefile
+1
-0
drivers/net/can/sja1000/peak_pci.c
drivers/net/can/sja1000/peak_pci.c
+491
-14
drivers/net/can/sja1000/peak_pcmcia.c
drivers/net/can/sja1000/peak_pcmcia.c
+753
-0
drivers/net/can/usb/Kconfig
drivers/net/can/usb/Kconfig
+6
-0
drivers/net/can/usb/Makefile
drivers/net/can/usb/Makefile
+1
-0
drivers/net/can/usb/peak_usb/Makefile
drivers/net/can/usb/peak_usb/Makefile
+2
-0
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/peak_usb/pcan_usb.c
+901
-0
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
+951
-0
drivers/net/can/usb/peak_usb/pcan_usb_core.h
drivers/net/can/usb/peak_usb/pcan_usb_core.h
+146
-0
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+1036
-0
drivers/net/can/usb/peak_usb/pcan_usb_pro.h
drivers/net/can/usb/peak_usb/pcan_usb_pro.h
+178
-0
未找到文件。
drivers/net/can/cc770/cc770.c
浏览文件 @
ffcb9738
...
@@ -34,7 +34,6 @@
...
@@ -34,7 +34,6 @@
#include <linux/can.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/error.h>
#include <linux/can/dev.h>
#include <linux/can/platform/cc770.h>
#include <linux/can/platform/cc770.h>
#include "cc770.h"
#include "cc770.h"
...
...
drivers/net/can/sja1000/Kconfig
浏览文件 @
ffcb9738
...
@@ -43,12 +43,33 @@ config CAN_EMS_PCI
...
@@ -43,12 +43,33 @@ config CAN_EMS_PCI
CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
(http://www.ems-wuensche.de).
(http://www.ems-wuensche.de).
config CAN_PEAK_PCMCIA
tristate "PEAK PCAN-PC Card"
depends on PCMCIA
---help---
This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels)
from PEAK-System (http://www.peak-system.com). To compile this
driver as a module, choose M here: the module will be called
peak_pcmcia.
config CAN_PEAK_PCI
config CAN_PEAK_PCI
tristate "PEAK PCAN
PCI/PCIe
Cards"
tristate "PEAK PCAN
-PCI/PCIe/miniPCI
Cards"
depends on PCI
depends on PCI
---help---
---help---
This driver is for the PCAN PCI/PCIe cards (1, 2, 3 or 4 channels)
This driver is for the PCAN-PCI/PCIe/miniPCI cards
from PEAK Systems (http://www.peak-system.com).
(1, 2, 3 or 4 channels) from PEAK-System Technik
(http://www.peak-system.com).
config CAN_PEAK_PCIEC
bool "PEAK PCAN-ExpressCard Cards"
depends on CAN_PEAK_PCI
select I2C
select I2C_ALGOBIT
default y
---help---
Say Y here if you want to use a PCAN-ExpressCard from PEAK-System
Technik. This will also automatically select I2C and I2C_ALGO
configuration options.
config CAN_KVASER_PCI
config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
...
...
drivers/net/can/sja1000/Makefile
浏览文件 @
ffcb9738
...
@@ -9,6 +9,7 @@ obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
...
@@ -9,6 +9,7 @@ obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
obj-$(CONFIG_CAN_EMS_PCMCIA)
+=
ems_pcmcia.o
obj-$(CONFIG_CAN_EMS_PCMCIA)
+=
ems_pcmcia.o
obj-$(CONFIG_CAN_EMS_PCI)
+=
ems_pci.o
obj-$(CONFIG_CAN_EMS_PCI)
+=
ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI)
+=
kvaser_pci.o
obj-$(CONFIG_CAN_KVASER_PCI)
+=
kvaser_pci.o
obj-$(CONFIG_CAN_PEAK_PCMCIA)
+=
peak_pcmcia.o
obj-$(CONFIG_CAN_PEAK_PCI)
+=
peak_pci.o
obj-$(CONFIG_CAN_PEAK_PCI)
+=
peak_pci.o
obj-$(CONFIG_CAN_PLX_PCI)
+=
plx_pci.o
obj-$(CONFIG_CAN_PLX_PCI)
+=
plx_pci.o
obj-$(CONFIG_CAN_TSCAN1)
+=
tscan1.o
obj-$(CONFIG_CAN_TSCAN1)
+=
tscan1.o
...
...
drivers/net/can/sja1000/peak_pci.c
浏览文件 @
ffcb9738
/*
/*
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
*
* Derived from the PCAN project file driver/src/pcan_pci.c:
* Derived from the PCAN project file driver/src/pcan_pci.c:
*
*
...
@@ -13,10 +14,6 @@
...
@@ -13,10 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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/kernel.h>
...
@@ -26,22 +23,26 @@
...
@@ -26,22 +23,26 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/can.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/dev.h>
#include "sja1000.h"
#include "sja1000.h"
MODULE_AUTHOR
(
"Wolfgang Grandegger <wg@grandegger.com>"
);
MODULE_AUTHOR
(
"Wolfgang Grandegger <wg@grandegger.com>"
);
MODULE_DESCRIPTION
(
"Socket-CAN driver for PEAK PCAN PCI
/PCIe
cards"
);
MODULE_DESCRIPTION
(
"Socket-CAN driver for PEAK PCAN PCI
family
cards"
);
MODULE_SUPPORTED_DEVICE
(
"PEAK PCAN PCI/PCIe
CAN card
"
);
MODULE_SUPPORTED_DEVICE
(
"PEAK PCAN PCI/PCIe
/PCIeC miniPCI CAN cards
"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_LICENSE
(
"GPL v2"
);
#define DRV_NAME "peak_pci"
#define DRV_NAME "peak_pci"
struct
peak_pciec_card
;
struct
peak_pci_chan
{
struct
peak_pci_chan
{
void
__iomem
*
cfg_base
;
/* Common for all channels */
void
__iomem
*
cfg_base
;
/* Common for all channels */
struct
net_device
*
prev_dev
;
/* Chain of network devices */
struct
net_device
*
prev_dev
;
/* Chain of network devices */
u16
icr_mask
;
/* Interrupt mask for fast ack */
u16
icr_mask
;
/* Interrupt mask for fast ack */
struct
peak_pciec_card
*
pciec_card
;
/* only for PCIeC LEDs */
};
};
#define PEAK_PCI_CAN_CLOCK (16000000 / 2)
#define PEAK_PCI_CAN_CLOCK (16000000 / 2)
...
@@ -61,16 +62,464 @@ struct peak_pci_chan {
...
@@ -61,16 +62,464 @@ struct peak_pci_chan {
#define PEAK_PCI_VENDOR_ID 0x001C
/* The PCI device and vendor IDs */
#define PEAK_PCI_VENDOR_ID 0x001C
/* The PCI device and vendor IDs */
#define PEAK_PCI_DEVICE_ID 0x0001
/* for PCI/PCIe slot cards */
#define PEAK_PCI_DEVICE_ID 0x0001
/* for PCI/PCIe slot cards */
#define PEAK_PCIEC_DEVICE_ID 0x0002
/* for ExpressCard slot cards */
#define PEAK_PCIE_DEVICE_ID 0x0003
/* for nextgen PCIe slot cards */
#define PEAK_MPCI_DEVICE_ID 0x0008
/* The miniPCI slot cards */
#define PEAK_PCI_CHAN_MAX 4
static
const
u16
peak_pci_icr_masks
[]
=
{
0x02
,
0x01
,
0x40
,
0x80
};
static
const
u16
peak_pci_icr_masks
[
PEAK_PCI_CHAN_MAX
]
=
{
0x02
,
0x01
,
0x40
,
0x80
};
static
DEFINE_PCI_DEVICE_TABLE
(
peak_pci_tbl
)
=
{
static
DEFINE_PCI_DEVICE_TABLE
(
peak_pci_tbl
)
=
{
{
PEAK_PCI_VENDOR_ID
,
PEAK_PCI_DEVICE_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,},
{
PEAK_PCI_VENDOR_ID
,
PEAK_PCI_DEVICE_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,},
{
PEAK_PCI_VENDOR_ID
,
PEAK_PCIE_DEVICE_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,},
{
PEAK_PCI_VENDOR_ID
,
PEAK_MPCI_DEVICE_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,},
#ifdef CONFIG_CAN_PEAK_PCIEC
{
PEAK_PCI_VENDOR_ID
,
PEAK_PCIEC_DEVICE_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,},
#endif
{
0
,}
{
0
,}
};
};
MODULE_DEVICE_TABLE
(
pci
,
peak_pci_tbl
);
MODULE_DEVICE_TABLE
(
pci
,
peak_pci_tbl
);
#ifdef CONFIG_CAN_PEAK_PCIEC
/*
* PCAN-ExpressCard needs I2C bit-banging configuration option.
*/
/* GPIOICR byte access offsets */
#define PITA_GPOUT 0x18
/* GPx output value */
#define PITA_GPIN 0x19
/* GPx input value */
#define PITA_GPOEN 0x1A
/* configure GPx as ouput pin */
/* I2C GP bits */
#define PITA_GPIN_SCL 0x01
/* Serial Clock Line */
#define PITA_GPIN_SDA 0x04
/* Serial DAta line */
#define PCA9553_1_SLAVEADDR (0xC4 >> 1)
/* PCA9553 LS0 fields values */
enum
{
PCA9553_LOW
,
PCA9553_HIGHZ
,
PCA9553_PWM0
,
PCA9553_PWM1
};
/* LEDs control */
#define PCA9553_ON PCA9553_LOW
#define PCA9553_OFF PCA9553_HIGHZ
#define PCA9553_SLOW PCA9553_PWM0
#define PCA9553_FAST PCA9553_PWM1
#define PCA9553_LED(c) (1 << (c))
#define PCA9553_LED_STATE(s, c) ((s) << ((c) << 1))
#define PCA9553_LED_ON(c) PCA9553_LED_STATE(PCA9553_ON, c)
#define PCA9553_LED_OFF(c) PCA9553_LED_STATE(PCA9553_OFF, c)
#define PCA9553_LED_SLOW(c) PCA9553_LED_STATE(PCA9553_SLOW, c)
#define PCA9553_LED_FAST(c) PCA9553_LED_STATE(PCA9553_FAST, c)
#define PCA9553_LED_MASK(c) PCA9553_LED_STATE(0x03, c)
#define PCA9553_LED_OFF_ALL (PCA9553_LED_OFF(0) | PCA9553_LED_OFF(1))
#define PCA9553_LS0_INIT 0x40
/* initial value (!= from 0x00) */
struct
peak_pciec_chan
{
struct
net_device
*
netdev
;
unsigned
long
prev_rx_bytes
;
unsigned
long
prev_tx_bytes
;
};
struct
peak_pciec_card
{
void
__iomem
*
cfg_base
;
/* Common for all channels */
void
__iomem
*
reg_base
;
/* first channel base address */
u8
led_cache
;
/* leds state cache */
/* PCIExpressCard i2c data */
struct
i2c_algo_bit_data
i2c_bit
;
struct
i2c_adapter
led_chip
;
struct
delayed_work
led_work
;
/* led delayed work */
int
chan_count
;
struct
peak_pciec_chan
channel
[
PEAK_PCI_CHAN_MAX
];
};
/* "normal" pci register write callback is overloaded for leds control */
static
void
peak_pci_write_reg
(
const
struct
sja1000_priv
*
priv
,
int
port
,
u8
val
);
static
inline
void
pita_set_scl_highz
(
struct
peak_pciec_card
*
card
)
{
u8
gp_outen
=
readb
(
card
->
cfg_base
+
PITA_GPOEN
)
&
~
PITA_GPIN_SCL
;
writeb
(
gp_outen
,
card
->
cfg_base
+
PITA_GPOEN
);
}
static
inline
void
pita_set_sda_highz
(
struct
peak_pciec_card
*
card
)
{
u8
gp_outen
=
readb
(
card
->
cfg_base
+
PITA_GPOEN
)
&
~
PITA_GPIN_SDA
;
writeb
(
gp_outen
,
card
->
cfg_base
+
PITA_GPOEN
);
}
static
void
peak_pciec_init_pita_gpio
(
struct
peak_pciec_card
*
card
)
{
/* raise SCL & SDA GPIOs to high-Z */
pita_set_scl_highz
(
card
);
pita_set_sda_highz
(
card
);
}
static
void
pita_setsda
(
void
*
data
,
int
state
)
{
struct
peak_pciec_card
*
card
=
(
struct
peak_pciec_card
*
)
data
;
u8
gp_out
,
gp_outen
;
/* set output sda always to 0 */
gp_out
=
readb
(
card
->
cfg_base
+
PITA_GPOUT
)
&
~
PITA_GPIN_SDA
;
writeb
(
gp_out
,
card
->
cfg_base
+
PITA_GPOUT
);
/* control output sda with GPOEN */
gp_outen
=
readb
(
card
->
cfg_base
+
PITA_GPOEN
);
if
(
state
)
gp_outen
&=
~
PITA_GPIN_SDA
;
else
gp_outen
|=
PITA_GPIN_SDA
;
writeb
(
gp_outen
,
card
->
cfg_base
+
PITA_GPOEN
);
}
static
void
pita_setscl
(
void
*
data
,
int
state
)
{
struct
peak_pciec_card
*
card
=
(
struct
peak_pciec_card
*
)
data
;
u8
gp_out
,
gp_outen
;
/* set output scl always to 0 */
gp_out
=
readb
(
card
->
cfg_base
+
PITA_GPOUT
)
&
~
PITA_GPIN_SCL
;
writeb
(
gp_out
,
card
->
cfg_base
+
PITA_GPOUT
);
/* control output scl with GPOEN */
gp_outen
=
readb
(
card
->
cfg_base
+
PITA_GPOEN
);
if
(
state
)
gp_outen
&=
~
PITA_GPIN_SCL
;
else
gp_outen
|=
PITA_GPIN_SCL
;
writeb
(
gp_outen
,
card
->
cfg_base
+
PITA_GPOEN
);
}
static
int
pita_getsda
(
void
*
data
)
{
struct
peak_pciec_card
*
card
=
(
struct
peak_pciec_card
*
)
data
;
/* set tristate */
pita_set_sda_highz
(
card
);
return
(
readb
(
card
->
cfg_base
+
PITA_GPIN
)
&
PITA_GPIN_SDA
)
?
1
:
0
;
}
static
int
pita_getscl
(
void
*
data
)
{
struct
peak_pciec_card
*
card
=
(
struct
peak_pciec_card
*
)
data
;
/* set tristate */
pita_set_scl_highz
(
card
);
return
(
readb
(
card
->
cfg_base
+
PITA_GPIN
)
&
PITA_GPIN_SCL
)
?
1
:
0
;
}
/*
* write commands to the LED chip though the I2C-bus of the PCAN-PCIeC
*/
static
int
peak_pciec_write_pca9553
(
struct
peak_pciec_card
*
card
,
u8
offset
,
u8
data
)
{
u8
buffer
[
2
]
=
{
offset
,
data
};
struct
i2c_msg
msg
=
{
.
addr
=
PCA9553_1_SLAVEADDR
,
.
len
=
2
,
.
buf
=
buffer
,
};
int
ret
;
/* cache led mask */
if
((
offset
==
5
)
&&
(
data
==
card
->
led_cache
))
return
0
;
ret
=
i2c_transfer
(
&
card
->
led_chip
,
&
msg
,
1
);
if
(
ret
<
0
)
return
ret
;
if
(
offset
==
5
)
card
->
led_cache
=
data
;
return
0
;
}
/*
* delayed work callback used to control the LEDs
*/
static
void
peak_pciec_led_work
(
struct
work_struct
*
work
)
{
struct
peak_pciec_card
*
card
=
container_of
(
work
,
struct
peak_pciec_card
,
led_work
.
work
);
struct
net_device
*
netdev
;
u8
new_led
=
card
->
led_cache
;
int
i
,
up_count
=
0
;
/* first check what is to do */
for
(
i
=
0
;
i
<
card
->
chan_count
;
i
++
)
{
/* default is: not configured */
new_led
&=
~
PCA9553_LED_MASK
(
i
);
new_led
|=
PCA9553_LED_ON
(
i
);
netdev
=
card
->
channel
[
i
].
netdev
;
if
(
!
netdev
||
!
(
netdev
->
flags
&
IFF_UP
))
continue
;
up_count
++
;
/* no activity (but configured) */
new_led
&=
~
PCA9553_LED_MASK
(
i
);
new_led
|=
PCA9553_LED_SLOW
(
i
);
/* if bytes counters changed, set fast blinking led */
if
(
netdev
->
stats
.
rx_bytes
!=
card
->
channel
[
i
].
prev_rx_bytes
)
{
card
->
channel
[
i
].
prev_rx_bytes
=
netdev
->
stats
.
rx_bytes
;
new_led
&=
~
PCA9553_LED_MASK
(
i
);
new_led
|=
PCA9553_LED_FAST
(
i
);
}
if
(
netdev
->
stats
.
tx_bytes
!=
card
->
channel
[
i
].
prev_tx_bytes
)
{
card
->
channel
[
i
].
prev_tx_bytes
=
netdev
->
stats
.
tx_bytes
;
new_led
&=
~
PCA9553_LED_MASK
(
i
);
new_led
|=
PCA9553_LED_FAST
(
i
);
}
}
/* check if LS0 settings changed, only update i2c if so */
peak_pciec_write_pca9553
(
card
,
5
,
new_led
);
/* restart timer (except if no more configured channels) */
if
(
up_count
)
schedule_delayed_work
(
&
card
->
led_work
,
HZ
);
}
/*
* set LEDs blinking state
*/
static
void
peak_pciec_set_leds
(
struct
peak_pciec_card
*
card
,
u8
led_mask
,
u8
s
)
{
u8
new_led
=
card
->
led_cache
;
int
i
;
/* first check what is to do */
for
(
i
=
0
;
i
<
card
->
chan_count
;
i
++
)
if
(
led_mask
&
PCA9553_LED
(
i
))
{
new_led
&=
~
PCA9553_LED_MASK
(
i
);
new_led
|=
PCA9553_LED_STATE
(
s
,
i
);
}
/* check if LS0 settings changed, only update i2c if so */
peak_pciec_write_pca9553
(
card
,
5
,
new_led
);
}
/*
* start one second delayed work to control LEDs
*/
static
void
peak_pciec_start_led_work
(
struct
peak_pciec_card
*
card
)
{
if
(
!
delayed_work_pending
(
&
card
->
led_work
))
schedule_delayed_work
(
&
card
->
led_work
,
HZ
);
}
/*
* stop LEDs delayed work
*/
static
void
peak_pciec_stop_led_work
(
struct
peak_pciec_card
*
card
)
{
cancel_delayed_work_sync
(
&
card
->
led_work
);
}
/*
* initialize the PCA9553 4-bit I2C-bus LED chip
*/
static
int
peak_pciec_init_leds
(
struct
peak_pciec_card
*
card
)
{
int
err
;
/* prescaler for frequency 0: "SLOW" = 1 Hz = "44" */
err
=
peak_pciec_write_pca9553
(
card
,
1
,
44
/
1
);
if
(
err
)
return
err
;
/* duty cycle 0: 50% */
err
=
peak_pciec_write_pca9553
(
card
,
2
,
0x80
);
if
(
err
)
return
err
;
/* prescaler for frequency 1: "FAST" = 5 Hz */
err
=
peak_pciec_write_pca9553
(
card
,
3
,
44
/
5
);
if
(
err
)
return
err
;
/* duty cycle 1: 50% */
err
=
peak_pciec_write_pca9553
(
card
,
4
,
0x80
);
if
(
err
)
return
err
;
/* switch LEDs to initial state */
return
peak_pciec_write_pca9553
(
card
,
5
,
PCA9553_LS0_INIT
);
}
/*
* restore LEDs state to off peak_pciec_leds_exit
*/
static
void
peak_pciec_leds_exit
(
struct
peak_pciec_card
*
card
)
{
/* switch LEDs to off */
peak_pciec_write_pca9553
(
card
,
5
,
PCA9553_LED_OFF_ALL
);
}
/*
* normal write sja1000 register method overloaded to catch when controller
* is started or stopped, to control leds
*/
static
void
peak_pciec_write_reg
(
const
struct
sja1000_priv
*
priv
,
int
port
,
u8
val
)
{
struct
peak_pci_chan
*
chan
=
priv
->
priv
;
struct
peak_pciec_card
*
card
=
chan
->
pciec_card
;
int
c
=
(
priv
->
reg_base
-
card
->
reg_base
)
/
PEAK_PCI_CHAN_SIZE
;
/* sja1000 register changes control the leds state */
if
(
port
==
REG_MOD
)
switch
(
val
)
{
case
MOD_RM
:
/* Reset Mode: set led on */
peak_pciec_set_leds
(
card
,
PCA9553_LED
(
c
),
PCA9553_ON
);
break
;
case
0x00
:
/* Normal Mode: led slow blinking and start led timer */
peak_pciec_set_leds
(
card
,
PCA9553_LED
(
c
),
PCA9553_SLOW
);
peak_pciec_start_led_work
(
card
);
break
;
default:
break
;
}
/* call base function */
peak_pci_write_reg
(
priv
,
port
,
val
);
}
static
struct
i2c_algo_bit_data
peak_pciec_i2c_bit_ops
=
{
.
setsda
=
pita_setsda
,
.
setscl
=
pita_setscl
,
.
getsda
=
pita_getsda
,
.
getscl
=
pita_getscl
,
.
udelay
=
10
,
.
timeout
=
HZ
,
};
static
int
peak_pciec_probe
(
struct
pci_dev
*
pdev
,
struct
net_device
*
dev
)
{
struct
sja1000_priv
*
priv
=
netdev_priv
(
dev
);
struct
peak_pci_chan
*
chan
=
priv
->
priv
;
struct
peak_pciec_card
*
card
;
int
err
;
/* copy i2c object address from 1st channel */
if
(
chan
->
prev_dev
)
{
struct
sja1000_priv
*
prev_priv
=
netdev_priv
(
chan
->
prev_dev
);
struct
peak_pci_chan
*
prev_chan
=
prev_priv
->
priv
;
card
=
prev_chan
->
pciec_card
;
if
(
!
card
)
return
-
ENODEV
;
/* channel is the first one: do the init part */
}
else
{
/* create the bit banging I2C adapter structure */
card
=
kzalloc
(
sizeof
(
struct
peak_pciec_card
),
GFP_KERNEL
);
if
(
!
card
)
{
dev_err
(
&
pdev
->
dev
,
"failed allocating memory for i2c chip
\n
"
);
return
-
ENOMEM
;
}
card
->
cfg_base
=
chan
->
cfg_base
;
card
->
reg_base
=
priv
->
reg_base
;
card
->
led_chip
.
owner
=
THIS_MODULE
;
card
->
led_chip
.
dev
.
parent
=
&
pdev
->
dev
;
card
->
led_chip
.
algo_data
=
&
card
->
i2c_bit
;
strncpy
(
card
->
led_chip
.
name
,
"peak_i2c"
,
sizeof
(
card
->
led_chip
.
name
));
card
->
i2c_bit
=
peak_pciec_i2c_bit_ops
;
card
->
i2c_bit
.
udelay
=
10
;
card
->
i2c_bit
.
timeout
=
HZ
;
card
->
i2c_bit
.
data
=
card
;
peak_pciec_init_pita_gpio
(
card
);
err
=
i2c_bit_add_bus
(
&
card
->
led_chip
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"i2c init failed
\n
"
);
goto
pciec_init_err_1
;
}
err
=
peak_pciec_init_leds
(
card
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"leds hardware init failed
\n
"
);
goto
pciec_init_err_2
;
}
INIT_DELAYED_WORK
(
&
card
->
led_work
,
peak_pciec_led_work
);
/* PCAN-ExpressCard needs its own callback for leds */
priv
->
write_reg
=
peak_pciec_write_reg
;
}
chan
->
pciec_card
=
card
;
card
->
channel
[
card
->
chan_count
++
].
netdev
=
dev
;
return
0
;
pciec_init_err_2:
i2c_del_adapter
(
&
card
->
led_chip
);
pciec_init_err_1:
peak_pciec_init_pita_gpio
(
card
);
kfree
(
card
);
return
err
;
}
static
void
peak_pciec_remove
(
struct
peak_pciec_card
*
card
)
{
peak_pciec_stop_led_work
(
card
);
peak_pciec_leds_exit
(
card
);
i2c_del_adapter
(
&
card
->
led_chip
);
peak_pciec_init_pita_gpio
(
card
);
kfree
(
card
);
}
#else
/* CONFIG_CAN_PEAK_PCIEC */
/*
* Placebo functions when PCAN-ExpressCard support is not selected
*/
static
inline
int
peak_pciec_probe
(
struct
pci_dev
*
pdev
,
struct
net_device
*
dev
)
{
return
-
ENODEV
;
}
static
inline
void
peak_pciec_remove
(
struct
peak_pciec_card
*
card
)
{
}
#endif
/* CONFIG_CAN_PEAK_PCIEC */
static
u8
peak_pci_read_reg
(
const
struct
sja1000_priv
*
priv
,
int
port
)
static
u8
peak_pci_read_reg
(
const
struct
sja1000_priv
*
priv
,
int
port
)
{
{
return
readb
(
priv
->
reg_base
+
(
port
<<
2
));
return
readb
(
priv
->
reg_base
+
(
port
<<
2
));
...
@@ -188,17 +637,31 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
...
@@ -188,17 +637,31 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
/* Create chain of SJA1000 devices */
chan
->
prev_dev
=
pci_get_drvdata
(
pdev
);
pci_set_drvdata
(
pdev
,
dev
);
/*
* PCAN-ExpressCard needs some additional i2c init.
* This must be done *before* register_sja1000dev() but
* *after* devices linkage
*/
if
(
pdev
->
device
==
PEAK_PCIEC_DEVICE_ID
)
{
err
=
peak_pciec_probe
(
pdev
,
dev
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed to probe device (err %d)
\n
"
,
err
);
goto
failure_free_dev
;
}
}
err
=
register_sja1000dev
(
dev
);
err
=
register_sja1000dev
(
dev
);
if
(
err
)
{
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register device
\n
"
);
dev_err
(
&
pdev
->
dev
,
"failed to register device
\n
"
);
free_sja1000dev
(
dev
);
goto
failure_free_dev
;
goto
failure_remove_channels
;
}
}
/* Create chain of SJA1000 devices */
chan
->
prev_dev
=
pci_get_drvdata
(
pdev
);
pci_set_drvdata
(
pdev
,
dev
);
dev_info
(
&
pdev
->
dev
,
dev_info
(
&
pdev
->
dev
,
"%s at reg_base=0x%p cfg_base=0x%p irq=%d
\n
"
,
"%s at reg_base=0x%p cfg_base=0x%p irq=%d
\n
"
,
dev
->
name
,
priv
->
reg_base
,
chan
->
cfg_base
,
dev
->
irq
);
dev
->
name
,
priv
->
reg_base
,
chan
->
cfg_base
,
dev
->
irq
);
...
@@ -209,10 +672,15 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
...
@@ -209,10 +672,15 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
return
0
;
return
0
;
failure_free_dev:
pci_set_drvdata
(
pdev
,
chan
->
prev_dev
);
free_sja1000dev
(
dev
);
failure_remove_channels:
failure_remove_channels:
/* Disable interrupts */
/* Disable interrupts */
writew
(
0x0
,
cfg_base
+
PITA_ICR
+
2
);
writew
(
0x0
,
cfg_base
+
PITA_ICR
+
2
);
chan
=
NULL
;
for
(
dev
=
pci_get_drvdata
(
pdev
);
dev
;
dev
=
chan
->
prev_dev
)
{
for
(
dev
=
pci_get_drvdata
(
pdev
);
dev
;
dev
=
chan
->
prev_dev
)
{
unregister_sja1000dev
(
dev
);
unregister_sja1000dev
(
dev
);
free_sja1000dev
(
dev
);
free_sja1000dev
(
dev
);
...
@@ -220,6 +688,10 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
...
@@ -220,6 +688,10 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
chan
=
priv
->
priv
;
chan
=
priv
->
priv
;
}
}
/* free any PCIeC resources too */
if
(
chan
&&
chan
->
pciec_card
)
peak_pciec_remove
(
chan
->
pciec_card
);
pci_iounmap
(
pdev
,
reg_base
);
pci_iounmap
(
pdev
,
reg_base
);
failure_unmap_cfg_base:
failure_unmap_cfg_base:
...
@@ -251,8 +723,13 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
...
@@ -251,8 +723,13 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
unregister_sja1000dev
(
dev
);
unregister_sja1000dev
(
dev
);
free_sja1000dev
(
dev
);
free_sja1000dev
(
dev
);
dev
=
chan
->
prev_dev
;
dev
=
chan
->
prev_dev
;
if
(
!
dev
)
if
(
!
dev
)
{
/* do that only for first channel */
if
(
chan
->
pciec_card
)
peak_pciec_remove
(
chan
->
pciec_card
);
break
;
break
;
}
priv
=
netdev_priv
(
dev
);
priv
=
netdev_priv
(
dev
);
chan
=
priv
->
priv
;
chan
=
priv
->
priv
;
}
}
...
...
drivers/net/can/sja1000/peak_pcmcia.c
0 → 100644
浏览文件 @
ffcb9738
/*
* Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* CAN driver for PEAK-System PCAN-PC Card
* Derived from the PCAN project file driver/src/pcan_pccard.c
* Copyright (C) 2006-2010 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include "sja1000.h"
MODULE_AUTHOR
(
"Stephane Grosjean <s.grosjean@peak-system.com>"
);
MODULE_DESCRIPTION
(
"CAN driver for PEAK-System PCAN-PC Cards"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_SUPPORTED_DEVICE
(
"PEAK PCAN-PC Card"
);
/* PEAK-System PCMCIA driver name */
#define PCC_NAME "peak_pcmcia"
#define PCC_CHAN_MAX 2
#define PCC_CAN_CLOCK (16000000 / 2)
#define PCC_MANF_ID 0x0377
#define PCC_CARD_ID 0x0001
#define PCC_CHAN_SIZE 0x20
#define PCC_CHAN_OFF(c) ((c) * PCC_CHAN_SIZE)
#define PCC_COMN_OFF (PCC_CHAN_OFF(PCC_CHAN_MAX))
#define PCC_COMN_SIZE 0x40
/* common area registers */
#define PCC_CCR 0x00
#define PCC_CSR 0x02
#define PCC_CPR 0x04
#define PCC_SPI_DIR 0x06
#define PCC_SPI_DOR 0x08
#define PCC_SPI_ADR 0x0a
#define PCC_SPI_IR 0x0c
#define PCC_FW_MAJOR 0x10
#define PCC_FW_MINOR 0x12
/* CCR bits */
#define PCC_CCR_CLK_16 0x00
#define PCC_CCR_CLK_10 0x01
#define PCC_CCR_CLK_21 0x02
#define PCC_CCR_CLK_8 0x03
#define PCC_CCR_CLK_MASK PCC_CCR_CLK_8
#define PCC_CCR_RST_CHAN(c) (0x01 << ((c) + 2))
#define PCC_CCR_RST_ALL (PCC_CCR_RST_CHAN(0) | PCC_CCR_RST_CHAN(1))
#define PCC_CCR_RST_MASK PCC_CCR_RST_ALL
/* led selection bits */
#define PCC_LED(c) (1 << (c))
#define PCC_LED_ALL (PCC_LED(0) | PCC_LED(1))
/* led state value */
#define PCC_LED_ON 0x00
#define PCC_LED_FAST 0x01
#define PCC_LED_SLOW 0x02
#define PCC_LED_OFF 0x03
#define PCC_CCR_LED_CHAN(s, c) ((s) << (((c) + 2) << 1))
#define PCC_CCR_LED_ON_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_ON, c)
#define PCC_CCR_LED_FAST_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_FAST, c)
#define PCC_CCR_LED_SLOW_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_SLOW, c)
#define PCC_CCR_LED_OFF_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_OFF, c)
#define PCC_CCR_LED_MASK_CHAN(c) PCC_CCR_LED_OFF_CHAN(c)
#define PCC_CCR_LED_OFF_ALL (PCC_CCR_LED_OFF_CHAN(0) | \
PCC_CCR_LED_OFF_CHAN(1))
#define PCC_CCR_LED_MASK PCC_CCR_LED_OFF_ALL
#define PCC_CCR_INIT (PCC_CCR_CLK_16 | PCC_CCR_RST_ALL | PCC_CCR_LED_OFF_ALL)
/* CSR bits */
#define PCC_CSR_SPI_BUSY 0x04
/* time waiting for SPI busy (prevent from infinite loop) */
#define PCC_SPI_MAX_BUSY_WAIT_MS 3
/* max count of reading the SPI status register waiting for a change */
/* (prevent from infinite loop) */
#define PCC_WRITE_MAX_LOOP 1000
/* max nb of int handled by that isr in one shot (prevent from infinite loop) */
#define PCC_ISR_MAX_LOOP 10
/* EEPROM chip instruction set */
/* note: EEPROM Read/Write instructions include A8 bit */
#define PCC_EEP_WRITE(a) (0x02 | (((a) & 0x100) >> 5))
#define PCC_EEP_READ(a) (0x03 | (((a) & 0x100) >> 5))
#define PCC_EEP_WRDI 0x04
/* EEPROM Write Disable */
#define PCC_EEP_RDSR 0x05
/* EEPROM Read Status Register */
#define PCC_EEP_WREN 0x06
/* EEPROM Write Enable */
/* EEPROM Status Register bits */
#define PCC_EEP_SR_WEN 0x02
/* EEPROM SR Write Enable bit */
#define PCC_EEP_SR_WIP 0x01
/* EEPROM SR Write In Progress bit */
/*
* 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 PCC_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 PCC_CDR (CDR_CBP | CDR_CLKOUT_MASK)
struct
pcan_channel
{
struct
net_device
*
netdev
;
unsigned
long
prev_rx_bytes
;
unsigned
long
prev_tx_bytes
;
};
/* PCAN-PC Card private structure */
struct
pcan_pccard
{
struct
pcmcia_device
*
pdev
;
int
chan_count
;
struct
pcan_channel
channel
[
PCC_CHAN_MAX
];
u8
ccr
;
u8
fw_major
;
u8
fw_minor
;
void
__iomem
*
ioport_addr
;
struct
timer_list
led_timer
;
};
static
struct
pcmcia_device_id
pcan_table
[]
=
{
PCMCIA_DEVICE_MANF_CARD
(
PCC_MANF_ID
,
PCC_CARD_ID
),
PCMCIA_DEVICE_NULL
,
};
MODULE_DEVICE_TABLE
(
pcmcia
,
pcan_table
);
static
void
pcan_set_leds
(
struct
pcan_pccard
*
card
,
u8
mask
,
u8
state
);
/*
* start timer which controls leds state
*/
static
void
pcan_start_led_timer
(
struct
pcan_pccard
*
card
)
{
if
(
!
timer_pending
(
&
card
->
led_timer
))
mod_timer
(
&
card
->
led_timer
,
jiffies
+
HZ
);
}
/*
* stop the timer which controls leds state
*/
static
void
pcan_stop_led_timer
(
struct
pcan_pccard
*
card
)
{
del_timer_sync
(
&
card
->
led_timer
);
}
/*
* read a sja1000 register
*/
static
u8
pcan_read_canreg
(
const
struct
sja1000_priv
*
priv
,
int
port
)
{
return
ioread8
(
priv
->
reg_base
+
port
);
}
/*
* write a sja1000 register
*/
static
void
pcan_write_canreg
(
const
struct
sja1000_priv
*
priv
,
int
port
,
u8
v
)
{
struct
pcan_pccard
*
card
=
priv
->
priv
;
int
c
=
(
priv
->
reg_base
-
card
->
ioport_addr
)
/
PCC_CHAN_SIZE
;
/* sja1000 register changes control the leds state */
if
(
port
==
REG_MOD
)
switch
(
v
)
{
case
MOD_RM
:
/* Reset Mode: set led on */
pcan_set_leds
(
card
,
PCC_LED
(
c
),
PCC_LED_ON
);
break
;
case
0x00
:
/* Normal Mode: led slow blinking and start led timer */
pcan_set_leds
(
card
,
PCC_LED
(
c
),
PCC_LED_SLOW
);
pcan_start_led_timer
(
card
);
break
;
default:
break
;
}
iowrite8
(
v
,
priv
->
reg_base
+
port
);
}
/*
* read a register from the common area
*/
static
u8
pcan_read_reg
(
struct
pcan_pccard
*
card
,
int
port
)
{
return
ioread8
(
card
->
ioport_addr
+
PCC_COMN_OFF
+
port
);
}
/*
* write a register into the common area
*/
static
void
pcan_write_reg
(
struct
pcan_pccard
*
card
,
int
port
,
u8
v
)
{
/* cache ccr value */
if
(
port
==
PCC_CCR
)
{
if
(
card
->
ccr
==
v
)
return
;
card
->
ccr
=
v
;
}
iowrite8
(
v
,
card
->
ioport_addr
+
PCC_COMN_OFF
+
port
);
}
/*
* check whether the card is present by checking its fw version numbers
* against values read at probing time.
*/
static
inline
int
pcan_pccard_present
(
struct
pcan_pccard
*
card
)
{
return
((
pcan_read_reg
(
card
,
PCC_FW_MAJOR
)
==
card
->
fw_major
)
&&
(
pcan_read_reg
(
card
,
PCC_FW_MINOR
)
==
card
->
fw_minor
));
}
/*
* wait for SPI engine while it is busy
*/
static
int
pcan_wait_spi_busy
(
struct
pcan_pccard
*
card
)
{
unsigned
long
timeout
=
jiffies
+
msecs_to_jiffies
(
PCC_SPI_MAX_BUSY_WAIT_MS
)
+
1
;
/* be sure to read status at least once after sleeping */
while
(
pcan_read_reg
(
card
,
PCC_CSR
)
&
PCC_CSR_SPI_BUSY
)
{
if
(
time_after
(
jiffies
,
timeout
))
return
-
EBUSY
;
schedule
();
}
return
0
;
}
/*
* write data in device eeprom
*/
static
int
pcan_write_eeprom
(
struct
pcan_pccard
*
card
,
u16
addr
,
u8
v
)
{
u8
status
;
int
err
,
i
;
/* write instruction enabling write */
pcan_write_reg
(
card
,
PCC_SPI_IR
,
PCC_EEP_WREN
);
err
=
pcan_wait_spi_busy
(
card
);
if
(
err
)
goto
we_spi_err
;
/* wait until write enabled */
for
(
i
=
0
;
i
<
PCC_WRITE_MAX_LOOP
;
i
++
)
{
/* write instruction reading the status register */
pcan_write_reg
(
card
,
PCC_SPI_IR
,
PCC_EEP_RDSR
);
err
=
pcan_wait_spi_busy
(
card
);
if
(
err
)
goto
we_spi_err
;
/* get status register value and check write enable bit */
status
=
pcan_read_reg
(
card
,
PCC_SPI_DIR
);
if
(
status
&
PCC_EEP_SR_WEN
)
break
;
}
if
(
i
>=
PCC_WRITE_MAX_LOOP
)
{
dev_err
(
&
card
->
pdev
->
dev
,
"stop waiting to be allowed to write in eeprom
\n
"
);
return
-
EIO
;
}
/* set address and data */
pcan_write_reg
(
card
,
PCC_SPI_ADR
,
addr
&
0xff
);
pcan_write_reg
(
card
,
PCC_SPI_DOR
,
v
);
/*
* write instruction with bit[3] set according to address value:
* if addr refers to upper half of the memory array: bit[3] = 1
*/
pcan_write_reg
(
card
,
PCC_SPI_IR
,
PCC_EEP_WRITE
(
addr
));
err
=
pcan_wait_spi_busy
(
card
);
if
(
err
)
goto
we_spi_err
;
/* wait while write in progress */
for
(
i
=
0
;
i
<
PCC_WRITE_MAX_LOOP
;
i
++
)
{
/* write instruction reading the status register */
pcan_write_reg
(
card
,
PCC_SPI_IR
,
PCC_EEP_RDSR
);
err
=
pcan_wait_spi_busy
(
card
);
if
(
err
)
goto
we_spi_err
;
/* get status register value and check write in progress bit */
status
=
pcan_read_reg
(
card
,
PCC_SPI_DIR
);
if
(
!
(
status
&
PCC_EEP_SR_WIP
))
break
;
}
if
(
i
>=
PCC_WRITE_MAX_LOOP
)
{
dev_err
(
&
card
->
pdev
->
dev
,
"stop waiting for write in eeprom to complete
\n
"
);
return
-
EIO
;
}
/* write instruction disabling write */
pcan_write_reg
(
card
,
PCC_SPI_IR
,
PCC_EEP_WRDI
);
err
=
pcan_wait_spi_busy
(
card
);
if
(
err
)
goto
we_spi_err
;
return
0
;
we_spi_err:
dev_err
(
&
card
->
pdev
->
dev
,
"stop waiting (spi engine always busy) err %d
\n
"
,
err
);
return
err
;
}
static
void
pcan_set_leds
(
struct
pcan_pccard
*
card
,
u8
led_mask
,
u8
state
)
{
u8
ccr
=
card
->
ccr
;
int
i
;
for
(
i
=
0
;
i
<
card
->
chan_count
;
i
++
)
if
(
led_mask
&
PCC_LED
(
i
))
{
/* clear corresponding led bits in ccr */
ccr
&=
~
PCC_CCR_LED_MASK_CHAN
(
i
);
/* then set new bits */
ccr
|=
PCC_CCR_LED_CHAN
(
state
,
i
);
}
/* real write only if something has changed in ccr */
pcan_write_reg
(
card
,
PCC_CCR
,
ccr
);
}
/*
* enable/disable CAN connectors power
*/
static
inline
void
pcan_set_can_power
(
struct
pcan_pccard
*
card
,
int
onoff
)
{
int
err
;
err
=
pcan_write_eeprom
(
card
,
0
,
!!
onoff
);
if
(
err
)
dev_err
(
&
card
->
pdev
->
dev
,
"failed setting power %s to can connectors (err %d)
\n
"
,
(
onoff
)
?
"on"
:
"off"
,
err
);
}
/*
* set leds state according to channel activity
*/
static
void
pcan_led_timer
(
unsigned
long
arg
)
{
struct
pcan_pccard
*
card
=
(
struct
pcan_pccard
*
)
arg
;
struct
net_device
*
netdev
;
int
i
,
up_count
=
0
;
u8
ccr
;
ccr
=
card
->
ccr
;
for
(
i
=
0
;
i
<
card
->
chan_count
;
i
++
)
{
/* default is: not configured */
ccr
&=
~
PCC_CCR_LED_MASK_CHAN
(
i
);
ccr
|=
PCC_CCR_LED_ON_CHAN
(
i
);
netdev
=
card
->
channel
[
i
].
netdev
;
if
(
!
netdev
||
!
(
netdev
->
flags
&
IFF_UP
))
continue
;
up_count
++
;
/* no activity (but configured) */
ccr
&=
~
PCC_CCR_LED_MASK_CHAN
(
i
);
ccr
|=
PCC_CCR_LED_SLOW_CHAN
(
i
);
/* if bytes counters changed, set fast blinking led */
if
(
netdev
->
stats
.
rx_bytes
!=
card
->
channel
[
i
].
prev_rx_bytes
)
{
card
->
channel
[
i
].
prev_rx_bytes
=
netdev
->
stats
.
rx_bytes
;
ccr
&=
~
PCC_CCR_LED_MASK_CHAN
(
i
);
ccr
|=
PCC_CCR_LED_FAST_CHAN
(
i
);
}
if
(
netdev
->
stats
.
tx_bytes
!=
card
->
channel
[
i
].
prev_tx_bytes
)
{
card
->
channel
[
i
].
prev_tx_bytes
=
netdev
->
stats
.
tx_bytes
;
ccr
&=
~
PCC_CCR_LED_MASK_CHAN
(
i
);
ccr
|=
PCC_CCR_LED_FAST_CHAN
(
i
);
}
}
/* write the new leds state */
pcan_write_reg
(
card
,
PCC_CCR
,
ccr
);
/* restart timer (except if no more configured channels) */
if
(
up_count
)
mod_timer
(
&
card
->
led_timer
,
jiffies
+
HZ
);
}
/*
* interrupt service routine
*/
static
irqreturn_t
pcan_isr
(
int
irq
,
void
*
dev_id
)
{
struct
pcan_pccard
*
card
=
dev_id
;
int
irq_handled
;
/* prevent from infinite loop */
for
(
irq_handled
=
0
;
irq_handled
<
PCC_ISR_MAX_LOOP
;
irq_handled
++
)
{
/* handle shared interrupt and next loop */
int
nothing_to_handle
=
1
;
int
i
;
/* check interrupt for each channel */
for
(
i
=
0
;
i
<
card
->
chan_count
;
i
++
)
{
struct
net_device
*
netdev
;
/*
* check whether the card is present before calling
* sja1000_interrupt() to speed up hotplug detection
*/
if
(
!
pcan_pccard_present
(
card
))
{
/* card unplugged during isr */
return
IRQ_NONE
;
}
/*
* should check whether all or SJA1000_MAX_IRQ
* interrupts have been handled: loop again to be sure.
*/
netdev
=
card
->
channel
[
i
].
netdev
;
if
(
netdev
&&
sja1000_interrupt
(
irq
,
netdev
)
==
IRQ_HANDLED
)
nothing_to_handle
=
0
;
}
if
(
nothing_to_handle
)
break
;
}
return
(
irq_handled
)
?
IRQ_HANDLED
:
IRQ_NONE
;
}
/*
* free all resources used by the channels and switch off leds and can power
*/
static
void
pcan_free_channels
(
struct
pcan_pccard
*
card
)
{
int
i
;
u8
led_mask
=
0
;
for
(
i
=
0
;
i
<
card
->
chan_count
;
i
++
)
{
struct
net_device
*
netdev
;
char
name
[
IFNAMSIZ
];
led_mask
|=
PCC_LED
(
i
);
netdev
=
card
->
channel
[
i
].
netdev
;
if
(
!
netdev
)
continue
;
strncpy
(
name
,
netdev
->
name
,
IFNAMSIZ
);
unregister_sja1000dev
(
netdev
);
free_sja1000dev
(
netdev
);
dev_info
(
&
card
->
pdev
->
dev
,
"%s removed
\n
"
,
name
);
}
/* do it only if device not removed */
if
(
pcan_pccard_present
(
card
))
{
pcan_set_leds
(
card
,
led_mask
,
PCC_LED_OFF
);
pcan_set_can_power
(
card
,
0
);
}
}
/*
* check if a CAN controller is present at the specified location
*/
static
inline
int
pcan_channel_present
(
struct
sja1000_priv
*
priv
)
{
/* make sure SJA1000 is in reset mode */
pcan_write_canreg
(
priv
,
REG_MOD
,
1
);
pcan_write_canreg
(
priv
,
REG_CDR
,
CDR_PELICAN
);
/* read reset-values */
if
(
pcan_read_canreg
(
priv
,
REG_CDR
)
==
CDR_PELICAN
)
return
1
;
return
0
;
}
static
int
pcan_add_channels
(
struct
pcan_pccard
*
card
)
{
struct
pcmcia_device
*
pdev
=
card
->
pdev
;
int
i
,
err
=
0
;
u8
ccr
=
PCC_CCR_INIT
;
/* init common registers (reset channels and leds off) */
card
->
ccr
=
~
ccr
;
pcan_write_reg
(
card
,
PCC_CCR
,
ccr
);
/* wait 2ms before unresetting channels */
mdelay
(
2
);
ccr
&=
~
PCC_CCR_RST_ALL
;
pcan_write_reg
(
card
,
PCC_CCR
,
ccr
);
/* create one network device per channel detected */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
card
->
channel
);
i
++
)
{
struct
net_device
*
netdev
;
struct
sja1000_priv
*
priv
;
netdev
=
alloc_sja1000dev
(
0
);
if
(
!
netdev
)
{
err
=
-
ENOMEM
;
break
;
}
/* update linkages */
priv
=
netdev_priv
(
netdev
);
priv
->
priv
=
card
;
SET_NETDEV_DEV
(
netdev
,
&
pdev
->
dev
);
priv
->
irq_flags
=
IRQF_SHARED
;
netdev
->
irq
=
pdev
->
irq
;
priv
->
reg_base
=
card
->
ioport_addr
+
PCC_CHAN_OFF
(
i
);
/* check if channel is present */
if
(
!
pcan_channel_present
(
priv
))
{
dev_err
(
&
pdev
->
dev
,
"channel %d not present
\n
"
,
i
);
free_sja1000dev
(
netdev
);
continue
;
}
priv
->
read_reg
=
pcan_read_canreg
;
priv
->
write_reg
=
pcan_write_canreg
;
priv
->
can
.
clock
.
freq
=
PCC_CAN_CLOCK
;
priv
->
ocr
=
PCC_OCR
;
priv
->
cdr
=
PCC_CDR
;
/* Neither a slave device distributes the clock */
if
(
i
>
0
)
priv
->
cdr
|=
CDR_CLK_OFF
;
priv
->
flags
|=
SJA1000_CUSTOM_IRQ_HANDLER
;
/* register SJA1000 device */
err
=
register_sja1000dev
(
netdev
);
if
(
err
)
{
free_sja1000dev
(
netdev
);
continue
;
}
card
->
channel
[
i
].
netdev
=
netdev
;
card
->
chan_count
++
;
/* set corresponding led on in the new ccr */
ccr
&=
~
PCC_CCR_LED_OFF_CHAN
(
i
);
dev_info
(
&
pdev
->
dev
,
"%s on channel %d at 0x%p irq %d
\n
"
,
netdev
->
name
,
i
,
priv
->
reg_base
,
pdev
->
irq
);
}
/* write new ccr (change leds state) */
pcan_write_reg
(
card
,
PCC_CCR
,
ccr
);
return
err
;
}
static
int
pcan_conf_check
(
struct
pcmcia_device
*
pdev
,
void
*
priv_data
)
{
pdev
->
resource
[
0
]
->
flags
&=
~
IO_DATA_PATH_WIDTH
;
pdev
->
resource
[
0
]
->
flags
|=
IO_DATA_PATH_WIDTH_8
;
/* only */
pdev
->
io_lines
=
10
;
/* This reserves IO space but doesn't actually enable it */
return
pcmcia_request_io
(
pdev
);
}
/*
* free all resources used by the device
*/
static
void
pcan_free
(
struct
pcmcia_device
*
pdev
)
{
struct
pcan_pccard
*
card
=
pdev
->
priv
;
if
(
!
card
)
return
;
free_irq
(
pdev
->
irq
,
card
);
pcan_stop_led_timer
(
card
);
pcan_free_channels
(
card
);
ioport_unmap
(
card
->
ioport_addr
);
kfree
(
card
);
pdev
->
priv
=
NULL
;
}
/*
* setup PCMCIA socket and probe for PEAK-System PC-CARD
*/
static
int
__devinit
pcan_probe
(
struct
pcmcia_device
*
pdev
)
{
struct
pcan_pccard
*
card
;
int
err
;
pdev
->
config_flags
|=
CONF_ENABLE_IRQ
|
CONF_AUTO_SET_IO
;
err
=
pcmcia_loop_config
(
pdev
,
pcan_conf_check
,
NULL
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"pcmcia_loop_config() error %d
\n
"
,
err
);
goto
probe_err_1
;
}
if
(
!
pdev
->
irq
)
{
dev_err
(
&
pdev
->
dev
,
"no irq assigned
\n
"
);
err
=
-
ENODEV
;
goto
probe_err_1
;
}
err
=
pcmcia_enable_device
(
pdev
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"pcmcia_enable_device failed err=%d
\n
"
,
err
);
goto
probe_err_1
;
}
card
=
kzalloc
(
sizeof
(
struct
pcan_pccard
),
GFP_KERNEL
);
if
(
!
card
)
{
dev_err
(
&
pdev
->
dev
,
"couldn't allocate card memory
\n
"
);
err
=
-
ENOMEM
;
goto
probe_err_2
;
}
card
->
pdev
=
pdev
;
pdev
->
priv
=
card
;
/* sja1000 api uses iomem */
card
->
ioport_addr
=
ioport_map
(
pdev
->
resource
[
0
]
->
start
,
resource_size
(
pdev
->
resource
[
0
]));
if
(
!
card
->
ioport_addr
)
{
dev_err
(
&
pdev
->
dev
,
"couldn't map io port into io memory
\n
"
);
err
=
-
ENOMEM
;
goto
probe_err_3
;
}
card
->
fw_major
=
pcan_read_reg
(
card
,
PCC_FW_MAJOR
);
card
->
fw_minor
=
pcan_read_reg
(
card
,
PCC_FW_MINOR
);
/* display board name and firware version */
dev_info
(
&
pdev
->
dev
,
"PEAK-System pcmcia card %s fw %d.%d
\n
"
,
pdev
->
prod_id
[
1
]
?
pdev
->
prod_id
[
1
]
:
"PCAN-PC Card"
,
card
->
fw_major
,
card
->
fw_minor
);
/* detect available channels */
pcan_add_channels
(
card
);
if
(
!
card
->
chan_count
)
goto
probe_err_4
;
/* init the timer which controls the leds */
init_timer
(
&
card
->
led_timer
);
card
->
led_timer
.
function
=
pcan_led_timer
;
card
->
led_timer
.
data
=
(
unsigned
long
)
card
;
/* request the given irq */
err
=
request_irq
(
pdev
->
irq
,
&
pcan_isr
,
IRQF_SHARED
,
PCC_NAME
,
card
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"couldn't request irq%d
\n
"
,
pdev
->
irq
);
goto
probe_err_5
;
}
/* power on the connectors */
pcan_set_can_power
(
card
,
1
);
return
0
;
probe_err_5:
/* unregister can devices from network */
pcan_free_channels
(
card
);
probe_err_4:
ioport_unmap
(
card
->
ioport_addr
);
probe_err_3:
kfree
(
card
);
pdev
->
priv
=
NULL
;
probe_err_2:
pcmcia_disable_device
(
pdev
);
probe_err_1:
return
err
;
}
/*
* release claimed resources
*/
static
void
pcan_remove
(
struct
pcmcia_device
*
pdev
)
{
pcan_free
(
pdev
);
pcmcia_disable_device
(
pdev
);
}
static
struct
pcmcia_driver
pcan_driver
=
{
.
name
=
PCC_NAME
,
.
probe
=
pcan_probe
,
.
remove
=
pcan_remove
,
.
id_table
=
pcan_table
,
};
static
int
__init
pcan_init
(
void
)
{
return
pcmcia_register_driver
(
&
pcan_driver
);
}
module_init
(
pcan_init
);
static
void
__exit
pcan_exit
(
void
)
{
pcmcia_unregister_driver
(
&
pcan_driver
);
}
module_exit
(
pcan_exit
);
drivers/net/can/usb/Kconfig
浏览文件 @
ffcb9738
...
@@ -13,4 +13,10 @@ config CAN_ESD_USB2
...
@@ -13,4 +13,10 @@ config CAN_ESD_USB2
This driver supports the CAN-USB/2 interface
This driver supports the CAN-USB/2 interface
from esd electronic system design gmbh (http://www.esd.eu).
from esd electronic system design gmbh (http://www.esd.eu).
config CAN_PEAK_USB
tristate "PEAK PCAN-USB/USB Pro interfaces"
---help---
This driver supports the PCAN-USB and PCAN-USB Pro adapters
from PEAK-System Technik (http://www.peak-system.com).
endmenu
endmenu
drivers/net/can/usb/Makefile
浏览文件 @
ffcb9738
...
@@ -4,5 +4,6 @@
...
@@ -4,5 +4,6 @@
obj-$(CONFIG_CAN_EMS_USB)
+=
ems_usb.o
obj-$(CONFIG_CAN_EMS_USB)
+=
ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2)
+=
esd_usb2.o
obj-$(CONFIG_CAN_ESD_USB2)
+=
esd_usb2.o
obj-$(CONFIG_CAN_PEAK_USB)
+=
peak_usb/
ccflags-$(CONFIG_CAN_DEBUG_DEVICES)
:=
-DDEBUG
ccflags-$(CONFIG_CAN_DEBUG_DEVICES)
:=
-DDEBUG
drivers/net/can/usb/peak_usb/Makefile
0 → 100644
浏览文件 @
ffcb9738
obj-$(CONFIG_CAN_PEAK_USB)
+=
peak_usb.o
peak_usb-y
=
pcan_usb_core.o pcan_usb.o pcan_usb_pro.o
drivers/net/can/usb/peak_usb/pcan_usb.c
0 → 100644
浏览文件 @
ffcb9738
/*
* CAN driver for PEAK System PCAN-USB adapter
* Derived from the PCAN project file driver/src/pcan_usb.c
*
* Copyright (C) 2003-2010 PEAK System-Technik GmbH
* Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* 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.
*/
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include "pcan_usb_core.h"
MODULE_SUPPORTED_DEVICE
(
"PEAK-System PCAN-USB adapter"
);
/* PCAN-USB Endpoints */
#define PCAN_USB_EP_CMDOUT 1
#define PCAN_USB_EP_CMDIN (PCAN_USB_EP_CMDOUT | USB_DIR_IN)
#define PCAN_USB_EP_MSGOUT 2
#define PCAN_USB_EP_MSGIN (PCAN_USB_EP_MSGOUT | USB_DIR_IN)
/* PCAN-USB command struct */
#define PCAN_USB_CMD_FUNC 0
#define PCAN_USB_CMD_NUM 1
#define PCAN_USB_CMD_ARGS 2
#define PCAN_USB_CMD_ARGS_LEN 14
#define PCAN_USB_CMD_LEN (PCAN_USB_CMD_ARGS + \
PCAN_USB_CMD_ARGS_LEN)
/* PCAN-USB command timeout (ms.) */
#define PCAN_USB_COMMAND_TIMEOUT 1000
/* PCAN-USB startup timeout (ms.) */
#define PCAN_USB_STARTUP_TIMEOUT 10
/* PCAN-USB rx/tx buffers size */
#define PCAN_USB_RX_BUFFER_SIZE 64
#define PCAN_USB_TX_BUFFER_SIZE 64
#define PCAN_USB_MSG_HEADER_LEN 2
/* PCAN-USB adapter internal clock (MHz) */
#define PCAN_USB_CRYSTAL_HZ 16000000
/* PCAN-USB USB message record status/len field */
#define PCAN_USB_STATUSLEN_TIMESTAMP (1 << 7)
#define PCAN_USB_STATUSLEN_INTERNAL (1 << 6)
#define PCAN_USB_STATUSLEN_EXT_ID (1 << 5)
#define PCAN_USB_STATUSLEN_RTR (1 << 4)
#define PCAN_USB_STATUSLEN_DLC (0xf)
/* PCAN-USB error flags */
#define PCAN_USB_ERROR_TXFULL 0x01
#define PCAN_USB_ERROR_RXQOVR 0x02
#define PCAN_USB_ERROR_BUS_LIGHT 0x04
#define PCAN_USB_ERROR_BUS_HEAVY 0x08
#define PCAN_USB_ERROR_BUS_OFF 0x10
#define PCAN_USB_ERROR_RXQEMPTY 0x20
#define PCAN_USB_ERROR_QOVR 0x40
#define PCAN_USB_ERROR_TXQFULL 0x80
/* SJA1000 modes */
#define SJA1000_MODE_NORMAL 0x00
#define SJA1000_MODE_INIT 0x01
/*
* tick duration = 42.666 us =>
* (tick_number * 44739243) >> 20 ~ (tick_number * 42666) / 1000
* accuracy = 10^-7
*/
#define PCAN_USB_TS_DIV_SHIFTER 20
#define PCAN_USB_TS_US_PER_TICK 44739243
/* PCAN-USB messages record types */
#define PCAN_USB_REC_ERROR 1
#define PCAN_USB_REC_ANALOG 2
#define PCAN_USB_REC_BUSLOAD 3
#define PCAN_USB_REC_TS 4
#define PCAN_USB_REC_BUSEVT 5
/* private to PCAN-USB adapter */
struct
pcan_usb
{
struct
peak_usb_device
dev
;
struct
peak_time_ref
time_ref
;
struct
timer_list
restart_timer
;
};
/* incoming message context for decoding */
struct
pcan_usb_msg_context
{
u16
ts16
;
u8
prev_ts8
;
u8
*
ptr
;
u8
*
end
;
u8
rec_cnt
;
u8
rec_idx
;
u8
rec_data_idx
;
struct
net_device
*
netdev
;
struct
pcan_usb
*
pdev
;
};
/*
* send a command
*/
static
int
pcan_usb_send_cmd
(
struct
peak_usb_device
*
dev
,
u8
f
,
u8
n
,
u8
*
p
)
{
int
err
;
int
actual_length
;
/* usb device unregistered? */
if
(
!
(
dev
->
state
&
PCAN_USB_STATE_CONNECTED
))
return
0
;
dev
->
cmd_buf
[
PCAN_USB_CMD_FUNC
]
=
f
;
dev
->
cmd_buf
[
PCAN_USB_CMD_NUM
]
=
n
;
if
(
p
)
memcpy
(
dev
->
cmd_buf
+
PCAN_USB_CMD_ARGS
,
p
,
PCAN_USB_CMD_ARGS_LEN
);
err
=
usb_bulk_msg
(
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
PCAN_USB_EP_CMDOUT
),
dev
->
cmd_buf
,
PCAN_USB_CMD_LEN
,
&
actual_length
,
PCAN_USB_COMMAND_TIMEOUT
);
if
(
err
)
netdev_err
(
dev
->
netdev
,
"sending cmd f=0x%x n=0x%x failure: %d
\n
"
,
f
,
n
,
err
);
return
err
;
}
/*
* send a command then wait for its response
*/
static
int
pcan_usb_wait_rsp
(
struct
peak_usb_device
*
dev
,
u8
f
,
u8
n
,
u8
*
p
)
{
int
err
;
int
actual_length
;
/* usb device unregistered? */
if
(
!
(
dev
->
state
&
PCAN_USB_STATE_CONNECTED
))
return
0
;
/* first, send command */
err
=
pcan_usb_send_cmd
(
dev
,
f
,
n
,
NULL
);
if
(
err
)
return
err
;
err
=
usb_bulk_msg
(
dev
->
udev
,
usb_rcvbulkpipe
(
dev
->
udev
,
PCAN_USB_EP_CMDIN
),
dev
->
cmd_buf
,
PCAN_USB_CMD_LEN
,
&
actual_length
,
PCAN_USB_COMMAND_TIMEOUT
);
if
(
err
)
netdev_err
(
dev
->
netdev
,
"waiting rsp f=0x%x n=0x%x failure: %d
\n
"
,
f
,
n
,
err
);
else
if
(
p
)
memcpy
(
p
,
dev
->
cmd_buf
+
PCAN_USB_CMD_ARGS
,
PCAN_USB_CMD_ARGS_LEN
);
return
err
;
}
static
int
pcan_usb_set_sja1000
(
struct
peak_usb_device
*
dev
,
u8
mode
)
{
u8
args
[
PCAN_USB_CMD_ARGS_LEN
]
=
{
[
1
]
=
mode
,
};
return
pcan_usb_send_cmd
(
dev
,
9
,
2
,
args
);
}
static
int
pcan_usb_set_bus
(
struct
peak_usb_device
*
dev
,
u8
onoff
)
{
u8
args
[
PCAN_USB_CMD_ARGS_LEN
]
=
{
[
0
]
=
!!
onoff
,
};
return
pcan_usb_send_cmd
(
dev
,
3
,
2
,
args
);
}
static
int
pcan_usb_set_silent
(
struct
peak_usb_device
*
dev
,
u8
onoff
)
{
u8
args
[
PCAN_USB_CMD_ARGS_LEN
]
=
{
[
0
]
=
!!
onoff
,
};
return
pcan_usb_send_cmd
(
dev
,
3
,
3
,
args
);
}
static
int
pcan_usb_set_ext_vcc
(
struct
peak_usb_device
*
dev
,
u8
onoff
)
{
u8
args
[
PCAN_USB_CMD_ARGS_LEN
]
=
{
[
0
]
=
!!
onoff
,
};
return
pcan_usb_send_cmd
(
dev
,
10
,
2
,
args
);
}
/*
* set bittiming value to can
*/
static
int
pcan_usb_set_bittiming
(
struct
peak_usb_device
*
dev
,
struct
can_bittiming
*
bt
)
{
u8
args
[
PCAN_USB_CMD_ARGS_LEN
];
u8
btr0
,
btr1
;
btr0
=
((
bt
->
brp
-
1
)
&
0x3f
)
|
(((
bt
->
sjw
-
1
)
&
0x3
)
<<
6
);
btr1
=
((
bt
->
prop_seg
+
bt
->
phase_seg1
-
1
)
&
0xf
)
|
(((
bt
->
phase_seg2
-
1
)
&
0x7
)
<<
4
);
if
(
dev
->
can
.
ctrlmode
&
CAN_CTRLMODE_3_SAMPLES
)
btr1
|=
0x80
;
netdev_info
(
dev
->
netdev
,
"setting BTR0=0x%02x BTR1=0x%02x
\n
"
,
btr0
,
btr1
);
args
[
0
]
=
btr1
;
args
[
1
]
=
btr0
;
return
pcan_usb_send_cmd
(
dev
,
1
,
2
,
args
);
}
/*
* init/reset can
*/
static
int
pcan_usb_write_mode
(
struct
peak_usb_device
*
dev
,
u8
onoff
)
{
int
err
;
err
=
pcan_usb_set_bus
(
dev
,
onoff
);
if
(
err
)
return
err
;
if
(
!
onoff
)
{
err
=
pcan_usb_set_sja1000
(
dev
,
SJA1000_MODE_INIT
);
}
else
{
/* the PCAN-USB needs time to init */
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
msecs_to_jiffies
(
PCAN_USB_STARTUP_TIMEOUT
));
}
return
err
;
}
/*
* handle end of waiting for the device to reset
*/
static
void
pcan_usb_restart
(
unsigned
long
arg
)
{
/* notify candev and netdev */
peak_usb_restart_complete
((
struct
peak_usb_device
*
)
arg
);
}
/*
* handle the submission of the restart urb
*/
static
void
pcan_usb_restart_pending
(
struct
urb
*
urb
)
{
struct
pcan_usb
*
pdev
=
urb
->
context
;
/* the PCAN-USB needs time to restart */
mod_timer
(
&
pdev
->
restart_timer
,
jiffies
+
msecs_to_jiffies
(
PCAN_USB_STARTUP_TIMEOUT
));
/* can delete usb resources */
peak_usb_async_complete
(
urb
);
}
/*
* handle asynchronous restart
*/
static
int
pcan_usb_restart_async
(
struct
peak_usb_device
*
dev
,
struct
urb
*
urb
,
u8
*
buf
)
{
struct
pcan_usb
*
pdev
=
container_of
(
dev
,
struct
pcan_usb
,
dev
);
if
(
timer_pending
(
&
pdev
->
restart_timer
))
return
-
EBUSY
;
/* set bus on */
buf
[
PCAN_USB_CMD_FUNC
]
=
3
;
buf
[
PCAN_USB_CMD_NUM
]
=
2
;
buf
[
PCAN_USB_CMD_ARGS
]
=
1
;
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
PCAN_USB_EP_CMDOUT
),
buf
,
PCAN_USB_CMD_LEN
,
pcan_usb_restart_pending
,
pdev
);
return
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
}
/*
* read serial number from device
*/
static
int
pcan_usb_get_serial
(
struct
peak_usb_device
*
dev
,
u32
*
serial_number
)
{
u8
args
[
PCAN_USB_CMD_ARGS_LEN
];
int
err
;
err
=
pcan_usb_wait_rsp
(
dev
,
6
,
1
,
args
);
if
(
err
)
{
netdev_err
(
dev
->
netdev
,
"getting serial failure: %d
\n
"
,
err
);
}
else
if
(
serial_number
)
{
u32
tmp32
;
memcpy
(
&
tmp32
,
args
,
4
);
*
serial_number
=
le32_to_cpu
(
tmp32
);
}
return
err
;
}
/*
* read device id from device
*/
static
int
pcan_usb_get_device_id
(
struct
peak_usb_device
*
dev
,
u32
*
device_id
)
{
u8
args
[
PCAN_USB_CMD_ARGS_LEN
];
int
err
;
err
=
pcan_usb_wait_rsp
(
dev
,
4
,
1
,
args
);
if
(
err
)
netdev_err
(
dev
->
netdev
,
"getting device id failure: %d
\n
"
,
err
);
else
if
(
device_id
)
*
device_id
=
args
[
0
];
return
err
;
}
/*
* update current time ref with received timestamp
*/
static
int
pcan_usb_update_ts
(
struct
pcan_usb_msg_context
*
mc
)
{
u16
tmp16
;
if
((
mc
->
ptr
+
2
)
>
mc
->
end
)
return
-
EINVAL
;
memcpy
(
&
tmp16
,
mc
->
ptr
,
2
);
mc
->
ts16
=
le16_to_cpu
(
tmp16
);
if
(
mc
->
rec_idx
>
0
)
peak_usb_update_ts_now
(
&
mc
->
pdev
->
time_ref
,
mc
->
ts16
);
else
peak_usb_set_ts_now
(
&
mc
->
pdev
->
time_ref
,
mc
->
ts16
);
return
0
;
}
/*
* decode received timestamp
*/
static
int
pcan_usb_decode_ts
(
struct
pcan_usb_msg_context
*
mc
,
u8
first_packet
)
{
/* only 1st packet supplies a word timestamp */
if
(
first_packet
)
{
u16
tmp16
;
if
((
mc
->
ptr
+
2
)
>
mc
->
end
)
return
-
EINVAL
;
memcpy
(
&
tmp16
,
mc
->
ptr
,
2
);
mc
->
ptr
+=
2
;
mc
->
ts16
=
le16_to_cpu
(
tmp16
);
mc
->
prev_ts8
=
mc
->
ts16
&
0x00ff
;
}
else
{
u8
ts8
;
if
((
mc
->
ptr
+
1
)
>
mc
->
end
)
return
-
EINVAL
;
ts8
=
*
mc
->
ptr
++
;
if
(
ts8
<
mc
->
prev_ts8
)
mc
->
ts16
+=
0x100
;
mc
->
ts16
&=
0xff00
;
mc
->
ts16
|=
ts8
;
mc
->
prev_ts8
=
ts8
;
}
return
0
;
}
static
int
pcan_usb_decode_error
(
struct
pcan_usb_msg_context
*
mc
,
u8
n
,
u8
status_len
)
{
struct
sk_buff
*
skb
;
struct
can_frame
*
cf
;
struct
timeval
tv
;
enum
can_state
new_state
;
/* ignore this error until 1st ts received */
if
(
n
==
PCAN_USB_ERROR_QOVR
)
if
(
!
mc
->
pdev
->
time_ref
.
tick_count
)
return
0
;
new_state
=
mc
->
pdev
->
dev
.
can
.
state
;
switch
(
mc
->
pdev
->
dev
.
can
.
state
)
{
case
CAN_STATE_ERROR_ACTIVE
:
if
(
n
&
PCAN_USB_ERROR_BUS_LIGHT
)
{
new_state
=
CAN_STATE_ERROR_WARNING
;
break
;
}
case
CAN_STATE_ERROR_WARNING
:
if
(
n
&
PCAN_USB_ERROR_BUS_HEAVY
)
{
new_state
=
CAN_STATE_ERROR_PASSIVE
;
break
;
}
if
(
n
&
PCAN_USB_ERROR_BUS_OFF
)
{
new_state
=
CAN_STATE_BUS_OFF
;
break
;
}
if
(
n
&
(
PCAN_USB_ERROR_RXQOVR
|
PCAN_USB_ERROR_QOVR
))
{
/*
* trick to bypass next comparison and process other
* errors
*/
new_state
=
CAN_STATE_MAX
;
break
;
}
if
((
n
&
PCAN_USB_ERROR_BUS_LIGHT
)
==
0
)
{
/* no error (back to active state) */
mc
->
pdev
->
dev
.
can
.
state
=
CAN_STATE_ERROR_ACTIVE
;
return
0
;
}
break
;
case
CAN_STATE_ERROR_PASSIVE
:
if
(
n
&
PCAN_USB_ERROR_BUS_OFF
)
{
new_state
=
CAN_STATE_BUS_OFF
;
break
;
}
if
(
n
&
PCAN_USB_ERROR_BUS_LIGHT
)
{
new_state
=
CAN_STATE_ERROR_WARNING
;
break
;
}
if
(
n
&
(
PCAN_USB_ERROR_RXQOVR
|
PCAN_USB_ERROR_QOVR
))
{
/*
* trick to bypass next comparison and process other
* errors
*/
new_state
=
CAN_STATE_MAX
;
break
;
}
if
((
n
&
PCAN_USB_ERROR_BUS_HEAVY
)
==
0
)
{
/* no error (back to active state) */
mc
->
pdev
->
dev
.
can
.
state
=
CAN_STATE_ERROR_ACTIVE
;
return
0
;
}
break
;
default:
/* do nothing waiting for restart */
return
0
;
}
/* donot post any error if current state didn't change */
if
(
mc
->
pdev
->
dev
.
can
.
state
==
new_state
)
return
0
;
/* allocate an skb to store the error frame */
skb
=
alloc_can_err_skb
(
mc
->
netdev
,
&
cf
);
if
(
!
skb
)
return
-
ENOMEM
;
switch
(
new_state
)
{
case
CAN_STATE_BUS_OFF
:
cf
->
can_id
|=
CAN_ERR_BUSOFF
;
can_bus_off
(
mc
->
netdev
);
break
;
case
CAN_STATE_ERROR_PASSIVE
:
cf
->
can_id
|=
CAN_ERR_CRTL
;
cf
->
data
[
1
]
|=
CAN_ERR_CRTL_TX_PASSIVE
|
CAN_ERR_CRTL_RX_PASSIVE
;
mc
->
pdev
->
dev
.
can
.
can_stats
.
error_passive
++
;
break
;
case
CAN_STATE_ERROR_WARNING
:
cf
->
can_id
|=
CAN_ERR_CRTL
;
cf
->
data
[
1
]
|=
CAN_ERR_CRTL_TX_WARNING
|
CAN_ERR_CRTL_RX_WARNING
;
mc
->
pdev
->
dev
.
can
.
can_stats
.
error_warning
++
;
break
;
default:
/* CAN_STATE_MAX (trick to handle other errors) */
cf
->
can_id
|=
CAN_ERR_CRTL
;
cf
->
data
[
1
]
|=
CAN_ERR_CRTL_RX_OVERFLOW
;
mc
->
netdev
->
stats
.
rx_over_errors
++
;
mc
->
netdev
->
stats
.
rx_errors
++
;
new_state
=
mc
->
pdev
->
dev
.
can
.
state
;
break
;
}
mc
->
pdev
->
dev
.
can
.
state
=
new_state
;
if
(
status_len
&
PCAN_USB_STATUSLEN_TIMESTAMP
)
{
peak_usb_get_ts_tv
(
&
mc
->
pdev
->
time_ref
,
mc
->
ts16
,
&
tv
);
skb
->
tstamp
=
timeval_to_ktime
(
tv
);
}
netif_rx
(
skb
);
mc
->
netdev
->
stats
.
rx_packets
++
;
mc
->
netdev
->
stats
.
rx_bytes
+=
cf
->
can_dlc
;
return
0
;
}
/*
* decode non-data usb message
*/
static
int
pcan_usb_decode_status
(
struct
pcan_usb_msg_context
*
mc
,
u8
status_len
)
{
u8
rec_len
=
status_len
&
PCAN_USB_STATUSLEN_DLC
;
u8
f
,
n
;
int
err
;
/* check whether function and number can be read */
if
((
mc
->
ptr
+
2
)
>
mc
->
end
)
return
-
EINVAL
;
f
=
mc
->
ptr
[
PCAN_USB_CMD_FUNC
];
n
=
mc
->
ptr
[
PCAN_USB_CMD_NUM
];
mc
->
ptr
+=
PCAN_USB_CMD_ARGS
;
if
(
status_len
&
PCAN_USB_STATUSLEN_TIMESTAMP
)
{
int
err
=
pcan_usb_decode_ts
(
mc
,
!
mc
->
rec_idx
);
if
(
err
)
return
err
;
}
switch
(
f
)
{
case
PCAN_USB_REC_ERROR
:
err
=
pcan_usb_decode_error
(
mc
,
n
,
status_len
);
if
(
err
)
return
err
;
break
;
case
PCAN_USB_REC_ANALOG
:
/* analog values (ignored) */
rec_len
=
2
;
break
;
case
PCAN_USB_REC_BUSLOAD
:
/* bus load (ignored) */
rec_len
=
1
;
break
;
case
PCAN_USB_REC_TS
:
/* only timestamp */
if
(
pcan_usb_update_ts
(
mc
))
return
-
EINVAL
;
break
;
case
PCAN_USB_REC_BUSEVT
:
/* error frame/bus event */
if
(
n
&
PCAN_USB_ERROR_TXQFULL
)
netdev_dbg
(
mc
->
netdev
,
"device Tx queue full)
\n
"
);
break
;
default:
netdev_err
(
mc
->
netdev
,
"unexpected function %u
\n
"
,
f
);
break
;
}
if
((
mc
->
ptr
+
rec_len
)
>
mc
->
end
)
return
-
EINVAL
;
mc
->
ptr
+=
rec_len
;
return
0
;
}
/*
* decode data usb message
*/
static
int
pcan_usb_decode_data
(
struct
pcan_usb_msg_context
*
mc
,
u8
status_len
)
{
u8
rec_len
=
status_len
&
PCAN_USB_STATUSLEN_DLC
;
struct
sk_buff
*
skb
;
struct
can_frame
*
cf
;
struct
timeval
tv
;
skb
=
alloc_can_skb
(
mc
->
netdev
,
&
cf
);
if
(
!
skb
)
return
-
ENOMEM
;
if
(
status_len
&
PCAN_USB_STATUSLEN_EXT_ID
)
{
u32
tmp32
;
if
((
mc
->
ptr
+
4
)
>
mc
->
end
)
goto
decode_failed
;
memcpy
(
&
tmp32
,
mc
->
ptr
,
4
);
mc
->
ptr
+=
4
;
cf
->
can_id
=
le32_to_cpu
(
tmp32
>>
3
)
|
CAN_EFF_FLAG
;
}
else
{
u16
tmp16
;
if
((
mc
->
ptr
+
2
)
>
mc
->
end
)
goto
decode_failed
;
memcpy
(
&
tmp16
,
mc
->
ptr
,
2
);
mc
->
ptr
+=
2
;
cf
->
can_id
=
le16_to_cpu
(
tmp16
>>
5
);
}
cf
->
can_dlc
=
get_can_dlc
(
rec_len
);
/* first data packet timestamp is a word */
if
(
pcan_usb_decode_ts
(
mc
,
!
mc
->
rec_data_idx
))
goto
decode_failed
;
/* read data */
memset
(
cf
->
data
,
0x0
,
sizeof
(
cf
->
data
));
if
(
status_len
&
PCAN_USB_STATUSLEN_RTR
)
{
cf
->
can_id
|=
CAN_RTR_FLAG
;
}
else
{
if
((
mc
->
ptr
+
rec_len
)
>
mc
->
end
)
goto
decode_failed
;
memcpy
(
cf
->
data
,
mc
->
ptr
,
rec_len
);
mc
->
ptr
+=
rec_len
;
}
/* convert timestamp into kernel time */
peak_usb_get_ts_tv
(
&
mc
->
pdev
->
time_ref
,
mc
->
ts16
,
&
tv
);
skb
->
tstamp
=
timeval_to_ktime
(
tv
);
/* push the skb */
netif_rx
(
skb
);
/* update statistics */
mc
->
netdev
->
stats
.
rx_packets
++
;
mc
->
netdev
->
stats
.
rx_bytes
+=
cf
->
can_dlc
;
return
0
;
decode_failed:
dev_kfree_skb
(
skb
);
return
-
EINVAL
;
}
/*
* process incoming message
*/
static
int
pcan_usb_decode_msg
(
struct
peak_usb_device
*
dev
,
u8
*
ibuf
,
u32
lbuf
)
{
struct
pcan_usb_msg_context
mc
=
{
.
rec_cnt
=
ibuf
[
1
],
.
ptr
=
ibuf
+
PCAN_USB_MSG_HEADER_LEN
,
.
end
=
ibuf
+
lbuf
,
.
netdev
=
dev
->
netdev
,
.
pdev
=
container_of
(
dev
,
struct
pcan_usb
,
dev
),
};
int
err
;
for
(
err
=
0
;
mc
.
rec_idx
<
mc
.
rec_cnt
&&
!
err
;
mc
.
rec_idx
++
)
{
u8
sl
=
*
mc
.
ptr
++
;
/* handle status and error frames here */
if
(
sl
&
PCAN_USB_STATUSLEN_INTERNAL
)
{
err
=
pcan_usb_decode_status
(
&
mc
,
sl
);
/* handle normal can frames here */
}
else
{
err
=
pcan_usb_decode_data
(
&
mc
,
sl
);
mc
.
rec_data_idx
++
;
}
}
return
err
;
}
/*
* process any incoming buffer
*/
static
int
pcan_usb_decode_buf
(
struct
peak_usb_device
*
dev
,
struct
urb
*
urb
)
{
int
err
=
0
;
if
(
urb
->
actual_length
>
PCAN_USB_MSG_HEADER_LEN
)
{
err
=
pcan_usb_decode_msg
(
dev
,
urb
->
transfer_buffer
,
urb
->
actual_length
);
}
else
if
(
urb
->
actual_length
>
0
)
{
netdev_err
(
dev
->
netdev
,
"usb message length error (%u)
\n
"
,
urb
->
actual_length
);
err
=
-
EINVAL
;
}
return
err
;
}
/*
* process outgoing packet
*/
static
int
pcan_usb_encode_msg
(
struct
peak_usb_device
*
dev
,
struct
sk_buff
*
skb
,
u8
*
obuf
,
size_t
*
size
)
{
struct
net_device
*
netdev
=
dev
->
netdev
;
struct
net_device_stats
*
stats
=
&
netdev
->
stats
;
struct
can_frame
*
cf
=
(
struct
can_frame
*
)
skb
->
data
;
u8
*
pc
;
obuf
[
0
]
=
2
;
obuf
[
1
]
=
1
;
pc
=
obuf
+
PCAN_USB_MSG_HEADER_LEN
;
/* status/len byte */
*
pc
=
cf
->
can_dlc
;
if
(
cf
->
can_id
&
CAN_RTR_FLAG
)
*
pc
|=
PCAN_USB_STATUSLEN_RTR
;
/* can id */
if
(
cf
->
can_id
&
CAN_EFF_FLAG
)
{
__le32
tmp32
=
cpu_to_le32
(
cf
->
can_id
&
CAN_ERR_MASK
);
tmp32
<<=
3
;
*
pc
|=
PCAN_USB_STATUSLEN_EXT_ID
;
memcpy
(
++
pc
,
&
tmp32
,
4
);
pc
+=
4
;
}
else
{
__le16
tmp16
=
cpu_to_le32
(
cf
->
can_id
&
CAN_ERR_MASK
);
tmp16
<<=
5
;
memcpy
(
++
pc
,
&
tmp16
,
2
);
pc
+=
2
;
}
/* can data */
if
(
!
(
cf
->
can_id
&
CAN_RTR_FLAG
))
{
memcpy
(
pc
,
cf
->
data
,
cf
->
can_dlc
);
pc
+=
cf
->
can_dlc
;
}
obuf
[(
*
size
)
-
1
]
=
(
u8
)(
stats
->
tx_packets
&
0xff
);
return
0
;
}
/*
* start interface
*/
static
int
pcan_usb_start
(
struct
peak_usb_device
*
dev
)
{
struct
pcan_usb
*
pdev
=
container_of
(
dev
,
struct
pcan_usb
,
dev
);
/* number of bits used in timestamps read from adapter struct */
peak_usb_init_time_ref
(
&
pdev
->
time_ref
,
&
pcan_usb
);
/* if revision greater than 3, can put silent mode on/off */
if
(
dev
->
device_rev
>
3
)
{
int
err
;
err
=
pcan_usb_set_silent
(
dev
,
dev
->
can
.
ctrlmode
&
CAN_CTRLMODE_LISTENONLY
);
if
(
err
)
return
err
;
}
return
pcan_usb_set_ext_vcc
(
dev
,
0
);
}
static
int
pcan_usb_init
(
struct
peak_usb_device
*
dev
)
{
struct
pcan_usb
*
pdev
=
container_of
(
dev
,
struct
pcan_usb
,
dev
);
u32
serial_number
;
int
err
;
/* initialize a timer needed to wait for hardware restart */
init_timer
(
&
pdev
->
restart_timer
);
pdev
->
restart_timer
.
function
=
pcan_usb_restart
;
pdev
->
restart_timer
.
data
=
(
unsigned
long
)
dev
;
/*
* explicit use of dev_xxx() instead of netdev_xxx() here:
* information displayed are related to the device itself, not
* to the canx netdevice.
*/
err
=
pcan_usb_get_serial
(
dev
,
&
serial_number
);
if
(
err
)
{
dev_err
(
dev
->
netdev
->
dev
.
parent
,
"unable to read %s serial number (err %d)
\n
"
,
pcan_usb
.
name
,
err
);
return
err
;
}
dev_info
(
dev
->
netdev
->
dev
.
parent
,
"PEAK-System %s adapter hwrev %u serial %08X (%u channel)
\n
"
,
pcan_usb
.
name
,
dev
->
device_rev
,
serial_number
,
pcan_usb
.
ctrl_count
);
return
0
;
}
/*
* probe function for new PCAN-USB usb interface
*/
static
int
pcan_usb_probe
(
struct
usb_interface
*
intf
)
{
struct
usb_host_interface
*
if_desc
;
int
i
;
if_desc
=
intf
->
altsetting
;
/* check interface endpoint addresses */
for
(
i
=
0
;
i
<
if_desc
->
desc
.
bNumEndpoints
;
i
++
)
{
struct
usb_endpoint_descriptor
*
ep
=
&
if_desc
->
endpoint
[
i
].
desc
;
switch
(
ep
->
bEndpointAddress
)
{
case
PCAN_USB_EP_CMDOUT
:
case
PCAN_USB_EP_CMDIN
:
case
PCAN_USB_EP_MSGOUT
:
case
PCAN_USB_EP_MSGIN
:
break
;
default:
return
-
ENODEV
;
}
}
return
0
;
}
/*
* describe the PCAN-USB adapter
*/
struct
peak_usb_adapter
pcan_usb
=
{
.
name
=
"PCAN-USB"
,
.
device_id
=
PCAN_USB_PRODUCT_ID
,
.
ctrl_count
=
1
,
.
clock
=
{
.
freq
=
PCAN_USB_CRYSTAL_HZ
/
2
,
},
.
bittiming_const
=
{
.
name
=
"pcan_usb"
,
.
tseg1_min
=
1
,
.
tseg1_max
=
16
,
.
tseg2_min
=
1
,
.
tseg2_max
=
8
,
.
sjw_max
=
4
,
.
brp_min
=
1
,
.
brp_max
=
64
,
.
brp_inc
=
1
,
},
/* size of device private data */
.
sizeof_dev_private
=
sizeof
(
struct
pcan_usb
),
/* timestamps usage */
.
ts_used_bits
=
16
,
.
ts_period
=
24575
,
/* calibration period in ts. */
.
us_per_ts_scale
=
PCAN_USB_TS_US_PER_TICK
,
/* us=(ts*scale) */
.
us_per_ts_shift
=
PCAN_USB_TS_DIV_SHIFTER
,
/* >> shift */
/* give here messages in/out endpoints */
.
ep_msg_in
=
PCAN_USB_EP_MSGIN
,
.
ep_msg_out
=
{
PCAN_USB_EP_MSGOUT
},
/* size of rx/tx usb buffers */
.
rx_buffer_size
=
PCAN_USB_RX_BUFFER_SIZE
,
.
tx_buffer_size
=
PCAN_USB_TX_BUFFER_SIZE
,
/* device callbacks */
.
intf_probe
=
pcan_usb_probe
,
.
dev_init
=
pcan_usb_init
,
.
dev_set_bus
=
pcan_usb_write_mode
,
.
dev_set_bittiming
=
pcan_usb_set_bittiming
,
.
dev_get_device_id
=
pcan_usb_get_device_id
,
.
dev_decode_buf
=
pcan_usb_decode_buf
,
.
dev_encode_msg
=
pcan_usb_encode_msg
,
.
dev_start
=
pcan_usb_start
,
.
dev_restart_async
=
pcan_usb_restart_async
,
};
drivers/net/can/usb/peak_usb/pcan_usb_core.c
0 → 100644
浏览文件 @
ffcb9738
/*
* CAN driver for PEAK System USB adapters
* Derived from the PCAN project file driver/src/pcan_usb_core.c
*
* Copyright (C) 2003-2010 PEAK System-Technik GmbH
* Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* 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.
*/
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include "pcan_usb_core.h"
MODULE_AUTHOR
(
"Stephane Grosjean <s.grosjean@peak-system.com>"
);
MODULE_DESCRIPTION
(
"CAN driver for PEAK-System USB adapters"
);
MODULE_LICENSE
(
"GPL v2"
);
/* Table of devices that work with this driver */
static
struct
usb_device_id
peak_usb_table
[]
=
{
{
USB_DEVICE
(
PCAN_USB_VENDOR_ID
,
PCAN_USB_PRODUCT_ID
)},
{
USB_DEVICE
(
PCAN_USB_VENDOR_ID
,
PCAN_USBPRO_PRODUCT_ID
)},
{}
/* Terminating entry */
};
MODULE_DEVICE_TABLE
(
usb
,
peak_usb_table
);
/* List of supported PCAN-USB adapters (NULL terminated list) */
static
struct
peak_usb_adapter
*
peak_usb_adapters_list
[]
=
{
&
pcan_usb
,
&
pcan_usb_pro
,
NULL
,
};
/*
* dump memory
*/
#define DUMP_WIDTH 16
void
dump_mem
(
char
*
prompt
,
void
*
p
,
int
l
)
{
pr_info
(
"%s dumping %s (%d bytes):
\n
"
,
PCAN_USB_DRIVER_NAME
,
prompt
?
prompt
:
"memory"
,
l
);
print_hex_dump
(
KERN_INFO
,
PCAN_USB_DRIVER_NAME
" "
,
DUMP_PREFIX_NONE
,
DUMP_WIDTH
,
1
,
p
,
l
,
false
);
}
/*
* initialize a time_ref object with usb adapter own settings
*/
void
peak_usb_init_time_ref
(
struct
peak_time_ref
*
time_ref
,
struct
peak_usb_adapter
*
adapter
)
{
if
(
time_ref
)
{
memset
(
time_ref
,
0
,
sizeof
(
struct
peak_time_ref
));
time_ref
->
adapter
=
adapter
;
}
}
static
void
peak_usb_add_us
(
struct
timeval
*
tv
,
u32
delta_us
)
{
/* number of s. to add to final time */
u32
delta_s
=
delta_us
/
1000000
;
delta_us
-=
delta_s
*
1000000
;
tv
->
tv_usec
+=
delta_us
;
if
(
tv
->
tv_usec
>=
1000000
)
{
tv
->
tv_usec
-=
1000000
;
delta_s
++
;
}
tv
->
tv_sec
+=
delta_s
;
}
/*
* sometimes, another now may be more recent than current one...
*/
void
peak_usb_update_ts_now
(
struct
peak_time_ref
*
time_ref
,
u32
ts_now
)
{
time_ref
->
ts_dev_2
=
ts_now
;
/* should wait at least two passes before computing */
if
(
time_ref
->
tv_host
.
tv_sec
>
0
)
{
u32
delta_ts
=
time_ref
->
ts_dev_2
-
time_ref
->
ts_dev_1
;
if
(
time_ref
->
ts_dev_2
<
time_ref
->
ts_dev_1
)
delta_ts
&=
(
1
<<
time_ref
->
adapter
->
ts_used_bits
)
-
1
;
time_ref
->
ts_total
+=
delta_ts
;
}
}
/*
* register device timestamp as now
*/
void
peak_usb_set_ts_now
(
struct
peak_time_ref
*
time_ref
,
u32
ts_now
)
{
if
(
time_ref
->
tv_host_0
.
tv_sec
==
0
)
{
/* use monotonic clock to correctly compute further deltas */
time_ref
->
tv_host_0
=
ktime_to_timeval
(
ktime_get
());
time_ref
->
tv_host
.
tv_sec
=
0
;
}
else
{
/*
* delta_us should not be >= 2^32 => delta_s should be < 4294
* handle 32-bits wrapping here: if count of s. reaches 4200,
* reset counters and change time base
*/
if
(
time_ref
->
tv_host
.
tv_sec
!=
0
)
{
u32
delta_s
=
time_ref
->
tv_host
.
tv_sec
-
time_ref
->
tv_host_0
.
tv_sec
;
if
(
delta_s
>
4200
)
{
time_ref
->
tv_host_0
=
time_ref
->
tv_host
;
time_ref
->
ts_total
=
0
;
}
}
time_ref
->
tv_host
=
ktime_to_timeval
(
ktime_get
());
time_ref
->
tick_count
++
;
}
time_ref
->
ts_dev_1
=
time_ref
->
ts_dev_2
;
peak_usb_update_ts_now
(
time_ref
,
ts_now
);
}
/*
* compute timeval according to current ts and time_ref data
*/
void
peak_usb_get_ts_tv
(
struct
peak_time_ref
*
time_ref
,
u32
ts
,
struct
timeval
*
tv
)
{
/* protect from getting timeval before setting now */
if
(
time_ref
->
tv_host
.
tv_sec
>
0
)
{
u64
delta_us
;
delta_us
=
ts
-
time_ref
->
ts_dev_2
;
if
(
ts
<
time_ref
->
ts_dev_2
)
delta_us
&=
(
1
<<
time_ref
->
adapter
->
ts_used_bits
)
-
1
;
delta_us
+=
time_ref
->
ts_total
;
delta_us
*=
time_ref
->
adapter
->
us_per_ts_scale
;
delta_us
>>=
time_ref
->
adapter
->
us_per_ts_shift
;
*
tv
=
time_ref
->
tv_host_0
;
peak_usb_add_us
(
tv
,
(
u32
)
delta_us
);
}
else
{
*
tv
=
ktime_to_timeval
(
ktime_get
());
}
}
/*
* callback for bulk Rx urb
*/
static
void
peak_usb_read_bulk_callback
(
struct
urb
*
urb
)
{
struct
peak_usb_device
*
dev
=
urb
->
context
;
struct
net_device
*
netdev
;
int
err
;
netdev
=
dev
->
netdev
;
if
(
!
netif_device_present
(
netdev
))
return
;
/* check reception status */
switch
(
urb
->
status
)
{
case
0
:
/* success */
break
;
case
-
EILSEQ
:
case
-
ENOENT
:
case
-
ECONNRESET
:
case
-
ESHUTDOWN
:
return
;
default:
if
(
net_ratelimit
())
netdev_err
(
netdev
,
"Rx urb aborted (%d)
\n
"
,
urb
->
status
);
goto
resubmit_urb
;
}
/* protect from any incoming empty msgs */
if
((
urb
->
actual_length
>
0
)
&&
(
dev
->
adapter
->
dev_decode_buf
))
{
/* handle these kinds of msgs only if _start callback called */
if
(
dev
->
state
&
PCAN_USB_STATE_STARTED
)
{
err
=
dev
->
adapter
->
dev_decode_buf
(
dev
,
urb
);
if
(
err
)
dump_mem
(
"received usb message"
,
urb
->
transfer_buffer
,
urb
->
transfer_buffer_length
);
}
}
resubmit_urb:
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_rcvbulkpipe
(
dev
->
udev
,
dev
->
ep_msg_in
),
urb
->
transfer_buffer
,
dev
->
adapter
->
rx_buffer_size
,
peak_usb_read_bulk_callback
,
dev
);
usb_anchor_urb
(
urb
,
&
dev
->
rx_submitted
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
!
err
)
return
;
usb_unanchor_urb
(
urb
);
if
(
err
==
-
ENODEV
)
netif_device_detach
(
netdev
);
else
netdev_err
(
netdev
,
"failed resubmitting read bulk urb: %d
\n
"
,
err
);
}
/*
* callback for bulk Tx urb
*/
static
void
peak_usb_write_bulk_callback
(
struct
urb
*
urb
)
{
struct
peak_tx_urb_context
*
context
=
urb
->
context
;
struct
peak_usb_device
*
dev
;
struct
net_device
*
netdev
;
BUG_ON
(
!
context
);
dev
=
context
->
dev
;
netdev
=
dev
->
netdev
;
atomic_dec
(
&
dev
->
active_tx_urbs
);
if
(
!
netif_device_present
(
netdev
))
return
;
/* check tx status */
switch
(
urb
->
status
)
{
case
0
:
/* transmission complete */
netdev
->
stats
.
tx_packets
++
;
netdev
->
stats
.
tx_bytes
+=
context
->
dlc
;
/* prevent tx timeout */
netdev
->
trans_start
=
jiffies
;
break
;
default:
if
(
net_ratelimit
())
netdev_err
(
netdev
,
"Tx urb aborted (%d)
\n
"
,
urb
->
status
);
case
-
EPROTO
:
case
-
ENOENT
:
case
-
ECONNRESET
:
case
-
ESHUTDOWN
:
break
;
}
/* should always release echo skb and corresponding context */
can_get_echo_skb
(
netdev
,
context
->
echo_index
);
context
->
echo_index
=
PCAN_USB_MAX_TX_URBS
;
/* do wakeup tx queue in case of success only */
if
(
!
urb
->
status
)
netif_wake_queue
(
netdev
);
}
/*
* called by netdev to send one skb on the CAN interface.
*/
static
netdev_tx_t
peak_usb_ndo_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
netdev
)
{
struct
peak_usb_device
*
dev
=
netdev_priv
(
netdev
);
struct
peak_tx_urb_context
*
context
=
NULL
;
struct
net_device_stats
*
stats
=
&
netdev
->
stats
;
struct
can_frame
*
cf
=
(
struct
can_frame
*
)
skb
->
data
;
struct
urb
*
urb
;
u8
*
obuf
;
int
i
,
err
;
size_t
size
=
dev
->
adapter
->
tx_buffer_size
;
if
(
can_dropped_invalid_skb
(
netdev
,
skb
))
return
NETDEV_TX_OK
;
for
(
i
=
0
;
i
<
PCAN_USB_MAX_TX_URBS
;
i
++
)
if
(
dev
->
tx_contexts
[
i
].
echo_index
==
PCAN_USB_MAX_TX_URBS
)
{
context
=
dev
->
tx_contexts
+
i
;
break
;
}
if
(
!
context
)
{
/* should not occur except during restart */
return
NETDEV_TX_BUSY
;
}
urb
=
context
->
urb
;
obuf
=
urb
->
transfer_buffer
;
err
=
dev
->
adapter
->
dev_encode_msg
(
dev
,
skb
,
obuf
,
&
size
);
if
(
err
)
{
if
(
net_ratelimit
())
netdev_err
(
netdev
,
"packet dropped
\n
"
);
dev_kfree_skb
(
skb
);
stats
->
tx_dropped
++
;
return
NETDEV_TX_OK
;
}
context
->
echo_index
=
i
;
context
->
dlc
=
cf
->
can_dlc
;
usb_anchor_urb
(
urb
,
&
dev
->
tx_submitted
);
can_put_echo_skb
(
skb
,
netdev
,
context
->
echo_index
);
atomic_inc
(
&
dev
->
active_tx_urbs
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
can_free_echo_skb
(
netdev
,
context
->
echo_index
);
usb_unanchor_urb
(
urb
);
/* this context is not used in fact */
context
->
echo_index
=
PCAN_USB_MAX_TX_URBS
;
atomic_dec
(
&
dev
->
active_tx_urbs
);
switch
(
err
)
{
case
-
ENODEV
:
netif_device_detach
(
netdev
);
break
;
default:
netdev_warn
(
netdev
,
"tx urb submitting failed err=%d
\n
"
,
err
);
case
-
ENOENT
:
/* cable unplugged */
stats
->
tx_dropped
++
;
}
}
else
{
netdev
->
trans_start
=
jiffies
;
/* slow down tx path */
if
(
atomic_read
(
&
dev
->
active_tx_urbs
)
>=
PCAN_USB_MAX_TX_URBS
)
netif_stop_queue
(
netdev
);
}
return
NETDEV_TX_OK
;
}
/*
* start the CAN interface.
* Rx and Tx urbs are allocated here. Rx urbs are submitted here.
*/
static
int
peak_usb_start
(
struct
peak_usb_device
*
dev
)
{
struct
net_device
*
netdev
=
dev
->
netdev
;
int
err
,
i
;
for
(
i
=
0
;
i
<
PCAN_USB_MAX_RX_URBS
;
i
++
)
{
struct
urb
*
urb
;
u8
*
buf
;
/* create a URB, and a buffer for it, to receive usb messages */
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
urb
)
{
netdev_err
(
netdev
,
"No memory left for URBs
\n
"
);
err
=
-
ENOMEM
;
break
;
}
buf
=
kmalloc
(
dev
->
adapter
->
rx_buffer_size
,
GFP_KERNEL
);
if
(
!
buf
)
{
netdev_err
(
netdev
,
"No memory left for USB buffer
\n
"
);
usb_free_urb
(
urb
);
err
=
-
ENOMEM
;
break
;
}
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_rcvbulkpipe
(
dev
->
udev
,
dev
->
ep_msg_in
),
buf
,
dev
->
adapter
->
rx_buffer_size
,
peak_usb_read_bulk_callback
,
dev
);
/* ask last usb_free_urb() to also kfree() transfer_buffer */
urb
->
transfer_flags
|=
URB_FREE_BUFFER
;
usb_anchor_urb
(
urb
,
&
dev
->
rx_submitted
);
err
=
usb_submit_urb
(
urb
,
GFP_KERNEL
);
if
(
err
)
{
if
(
err
==
-
ENODEV
)
netif_device_detach
(
dev
->
netdev
);
usb_unanchor_urb
(
urb
);
kfree
(
buf
);
usb_free_urb
(
urb
);
break
;
}
/* drop reference, USB core will take care of freeing it */
usb_free_urb
(
urb
);
}
/* did we submit any URBs? Warn if we was not able to submit all urbs */
if
(
i
<
PCAN_USB_MAX_RX_URBS
)
{
if
(
i
==
0
)
{
netdev_err
(
netdev
,
"couldn't setup any rx URB
\n
"
);
return
err
;
}
netdev_warn
(
netdev
,
"rx performance may be slow
\n
"
);
}
/* pre-alloc tx buffers and corresponding urbs */
for
(
i
=
0
;
i
<
PCAN_USB_MAX_TX_URBS
;
i
++
)
{
struct
peak_tx_urb_context
*
context
;
struct
urb
*
urb
;
u8
*
buf
;
/* create a URB and a buffer for it, to transmit usb messages */
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
urb
)
{
netdev_err
(
netdev
,
"No memory left for URBs
\n
"
);
err
=
-
ENOMEM
;
break
;
}
buf
=
kmalloc
(
dev
->
adapter
->
tx_buffer_size
,
GFP_KERNEL
);
if
(
!
buf
)
{
netdev_err
(
netdev
,
"No memory left for USB buffer
\n
"
);
usb_free_urb
(
urb
);
err
=
-
ENOMEM
;
break
;
}
context
=
dev
->
tx_contexts
+
i
;
context
->
dev
=
dev
;
context
->
urb
=
urb
;
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
dev
->
ep_msg_out
),
buf
,
dev
->
adapter
->
tx_buffer_size
,
peak_usb_write_bulk_callback
,
context
);
/* ask last usb_free_urb() to also kfree() transfer_buffer */
urb
->
transfer_flags
|=
URB_FREE_BUFFER
;
}
/* warn if we were not able to allocate enough tx contexts */
if
(
i
<
PCAN_USB_MAX_TX_URBS
)
{
if
(
i
==
0
)
{
netdev_err
(
netdev
,
"couldn't setup any tx URB
\n
"
);
return
err
;
}
netdev_warn
(
netdev
,
"tx performance may be slow
\n
"
);
}
if
(
dev
->
adapter
->
dev_start
)
{
err
=
dev
->
adapter
->
dev_start
(
dev
);
if
(
err
)
goto
failed
;
}
dev
->
state
|=
PCAN_USB_STATE_STARTED
;
/* can set bus on now */
if
(
dev
->
adapter
->
dev_set_bus
)
{
err
=
dev
->
adapter
->
dev_set_bus
(
dev
,
1
);
if
(
err
)
goto
failed
;
}
dev
->
can
.
state
=
CAN_STATE_ERROR_ACTIVE
;
return
0
;
failed:
if
(
err
==
-
ENODEV
)
netif_device_detach
(
dev
->
netdev
);
netdev_warn
(
netdev
,
"couldn't submit control: %d
\n
"
,
err
);
return
err
;
}
/*
* called by netdev to open the corresponding CAN interface.
*/
static
int
peak_usb_ndo_open
(
struct
net_device
*
netdev
)
{
struct
peak_usb_device
*
dev
=
netdev_priv
(
netdev
);
int
err
;
/* common open */
err
=
open_candev
(
netdev
);
if
(
err
)
return
err
;
/* finally start device */
err
=
peak_usb_start
(
dev
);
if
(
err
)
{
netdev_err
(
netdev
,
"couldn't start device: %d
\n
"
,
err
);
close_candev
(
netdev
);
return
err
;
}
dev
->
open_time
=
jiffies
;
netif_start_queue
(
netdev
);
return
0
;
}
/*
* unlink in-flight Rx and Tx urbs and free their memory.
*/
static
void
peak_usb_unlink_all_urbs
(
struct
peak_usb_device
*
dev
)
{
int
i
;
/* free all Rx (submitted) urbs */
usb_kill_anchored_urbs
(
&
dev
->
rx_submitted
);
/* free unsubmitted Tx urbs first */
for
(
i
=
0
;
i
<
PCAN_USB_MAX_TX_URBS
;
i
++
)
{
struct
urb
*
urb
=
dev
->
tx_contexts
[
i
].
urb
;
if
(
!
urb
||
dev
->
tx_contexts
[
i
].
echo_index
!=
PCAN_USB_MAX_TX_URBS
)
{
/*
* this urb is already released or always submitted,
* let usb core free by itself
*/
continue
;
}
usb_free_urb
(
urb
);
dev
->
tx_contexts
[
i
].
urb
=
NULL
;
}
/* then free all submitted Tx urbs */
usb_kill_anchored_urbs
(
&
dev
->
tx_submitted
);
atomic_set
(
&
dev
->
active_tx_urbs
,
0
);
}
/*
* called by netdev to close the corresponding CAN interface.
*/
static
int
peak_usb_ndo_stop
(
struct
net_device
*
netdev
)
{
struct
peak_usb_device
*
dev
=
netdev_priv
(
netdev
);
dev
->
state
&=
~
PCAN_USB_STATE_STARTED
;
netif_stop_queue
(
netdev
);
/* unlink all pending urbs and free used memory */
peak_usb_unlink_all_urbs
(
dev
);
if
(
dev
->
adapter
->
dev_stop
)
dev
->
adapter
->
dev_stop
(
dev
);
close_candev
(
netdev
);
dev
->
open_time
=
0
;
dev
->
can
.
state
=
CAN_STATE_STOPPED
;
/* can set bus off now */
if
(
dev
->
adapter
->
dev_set_bus
)
{
int
err
=
dev
->
adapter
->
dev_set_bus
(
dev
,
0
);
if
(
err
)
return
err
;
}
return
0
;
}
/*
* handle end of waiting for the device to reset
*/
void
peak_usb_restart_complete
(
struct
peak_usb_device
*
dev
)
{
/* finally MUST update can state */
dev
->
can
.
state
=
CAN_STATE_ERROR_ACTIVE
;
/* netdev queue can be awaken now */
netif_wake_queue
(
dev
->
netdev
);
}
void
peak_usb_async_complete
(
struct
urb
*
urb
)
{
kfree
(
urb
->
transfer_buffer
);
usb_free_urb
(
urb
);
}
/*
* device (auto-)restart mechanism runs in a timer context =>
* MUST handle restart with asynchronous usb transfers
*/
static
int
peak_usb_restart
(
struct
peak_usb_device
*
dev
)
{
struct
urb
*
urb
;
int
err
;
u8
*
buf
;
/*
* if device doesn't define any asynchronous restart handler, simply
* wake the netdev queue up
*/
if
(
!
dev
->
adapter
->
dev_restart_async
)
{
peak_usb_restart_complete
(
dev
);
return
0
;
}
/* first allocate a urb to handle the asynchronous steps */
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
);
if
(
!
urb
)
{
netdev_err
(
dev
->
netdev
,
"no memory left for urb
\n
"
);
return
-
ENOMEM
;
}
/* also allocate enough space for the commands to send */
buf
=
kmalloc
(
PCAN_USB_MAX_CMD_LEN
,
GFP_ATOMIC
);
if
(
!
buf
)
{
netdev_err
(
dev
->
netdev
,
"no memory left for async cmd
\n
"
);
usb_free_urb
(
urb
);
return
-
ENOMEM
;
}
/* call the device specific handler for the restart */
err
=
dev
->
adapter
->
dev_restart_async
(
dev
,
urb
,
buf
);
if
(
!
err
)
return
0
;
kfree
(
buf
);
usb_free_urb
(
urb
);
return
err
;
}
/*
* candev callback used to change CAN mode.
* Warning: this is called from a timer context!
*/
static
int
peak_usb_set_mode
(
struct
net_device
*
netdev
,
enum
can_mode
mode
)
{
struct
peak_usb_device
*
dev
=
netdev_priv
(
netdev
);
int
err
=
0
;
if
(
!
dev
->
open_time
)
return
-
EINVAL
;
switch
(
mode
)
{
case
CAN_MODE_START
:
err
=
peak_usb_restart
(
dev
);
if
(
err
)
netdev_err
(
netdev
,
"couldn't start device (err %d)
\n
"
,
err
);
break
;
default:
return
-
EOPNOTSUPP
;
}
return
err
;
}
/*
* candev callback used to set device bitrate.
*/
static
int
peak_usb_set_bittiming
(
struct
net_device
*
netdev
)
{
struct
peak_usb_device
*
dev
=
netdev_priv
(
netdev
);
struct
can_bittiming
*
bt
=
&
dev
->
can
.
bittiming
;
if
(
dev
->
adapter
->
dev_set_bittiming
)
{
int
err
=
dev
->
adapter
->
dev_set_bittiming
(
dev
,
bt
);
if
(
err
)
netdev_info
(
netdev
,
"couldn't set bitrate (err %d)
\n
"
,
err
);
return
err
;
}
return
0
;
}
static
const
struct
net_device_ops
peak_usb_netdev_ops
=
{
.
ndo_open
=
peak_usb_ndo_open
,
.
ndo_stop
=
peak_usb_ndo_stop
,
.
ndo_start_xmit
=
peak_usb_ndo_start_xmit
,
};
/*
* create one device which is attached to CAN controller #ctrl_idx of the
* usb adapter.
*/
static
int
peak_usb_create_dev
(
struct
peak_usb_adapter
*
peak_usb_adapter
,
struct
usb_interface
*
intf
,
int
ctrl_idx
)
{
struct
usb_device
*
usb_dev
=
interface_to_usbdev
(
intf
);
int
sizeof_candev
=
peak_usb_adapter
->
sizeof_dev_private
;
struct
peak_usb_device
*
dev
;
struct
net_device
*
netdev
;
int
i
,
err
;
u16
tmp16
;
if
(
sizeof_candev
<
sizeof
(
struct
peak_usb_device
))
sizeof_candev
=
sizeof
(
struct
peak_usb_device
);
netdev
=
alloc_candev
(
sizeof_candev
,
PCAN_USB_MAX_TX_URBS
);
if
(
!
netdev
)
{
dev_err
(
&
intf
->
dev
,
"%s: couldn't alloc candev
\n
"
,
PCAN_USB_DRIVER_NAME
);
return
-
ENOMEM
;
}
dev
=
netdev_priv
(
netdev
);
/* allocate a buffer large enough to send commands */
dev
->
cmd_buf
=
kmalloc
(
PCAN_USB_MAX_CMD_LEN
,
GFP_KERNEL
);
if
(
!
dev
->
cmd_buf
)
{
dev_err
(
&
intf
->
dev
,
"%s: couldn't alloc cmd buffer
\n
"
,
PCAN_USB_DRIVER_NAME
);
err
=
-
ENOMEM
;
goto
lbl_set_intf_data
;
}
dev
->
udev
=
usb_dev
;
dev
->
netdev
=
netdev
;
dev
->
adapter
=
peak_usb_adapter
;
dev
->
ctrl_idx
=
ctrl_idx
;
dev
->
state
=
PCAN_USB_STATE_CONNECTED
;
dev
->
ep_msg_in
=
peak_usb_adapter
->
ep_msg_in
;
dev
->
ep_msg_out
=
peak_usb_adapter
->
ep_msg_out
[
ctrl_idx
];
dev
->
can
.
clock
=
peak_usb_adapter
->
clock
;
dev
->
can
.
bittiming_const
=
&
peak_usb_adapter
->
bittiming_const
;
dev
->
can
.
do_set_bittiming
=
peak_usb_set_bittiming
;
dev
->
can
.
do_set_mode
=
peak_usb_set_mode
;
dev
->
can
.
ctrlmode_supported
=
CAN_CTRLMODE_3_SAMPLES
|
CAN_CTRLMODE_LISTENONLY
;
netdev
->
netdev_ops
=
&
peak_usb_netdev_ops
;
netdev
->
flags
|=
IFF_ECHO
;
/* we support local echo */
init_usb_anchor
(
&
dev
->
rx_submitted
);
init_usb_anchor
(
&
dev
->
tx_submitted
);
atomic_set
(
&
dev
->
active_tx_urbs
,
0
);
for
(
i
=
0
;
i
<
PCAN_USB_MAX_TX_URBS
;
i
++
)
dev
->
tx_contexts
[
i
].
echo_index
=
PCAN_USB_MAX_TX_URBS
;
dev
->
prev_siblings
=
usb_get_intfdata
(
intf
);
usb_set_intfdata
(
intf
,
dev
);
SET_NETDEV_DEV
(
netdev
,
&
intf
->
dev
);
err
=
register_candev
(
netdev
);
if
(
err
)
{
dev_err
(
&
intf
->
dev
,
"couldn't register CAN device: %d
\n
"
,
err
);
goto
lbl_free_cmd_buf
;
}
if
(
dev
->
prev_siblings
)
(
dev
->
prev_siblings
)
->
next_siblings
=
dev
;
/* keep hw revision into the netdevice */
tmp16
=
le16_to_cpu
(
usb_dev
->
descriptor
.
bcdDevice
);
dev
->
device_rev
=
tmp16
>>
8
;
if
(
dev
->
adapter
->
dev_init
)
{
err
=
dev
->
adapter
->
dev_init
(
dev
);
if
(
err
)
goto
lbl_free_cmd_buf
;
}
/* set bus off */
if
(
dev
->
adapter
->
dev_set_bus
)
{
err
=
dev
->
adapter
->
dev_set_bus
(
dev
,
0
);
if
(
err
)
goto
lbl_free_cmd_buf
;
}
/* get device number early */
if
(
dev
->
adapter
->
dev_get_device_id
)
dev
->
adapter
->
dev_get_device_id
(
dev
,
&
dev
->
device_number
);
netdev_info
(
netdev
,
"attached to %s channel %u (device %u)
\n
"
,
peak_usb_adapter
->
name
,
ctrl_idx
,
dev
->
device_number
);
return
0
;
lbl_free_cmd_buf:
kfree
(
dev
->
cmd_buf
);
lbl_set_intf_data:
usb_set_intfdata
(
intf
,
dev
->
prev_siblings
);
free_candev
(
netdev
);
return
err
;
}
/*
* called by the usb core when the device is unplugged from the system
*/
static
void
peak_usb_disconnect
(
struct
usb_interface
*
intf
)
{
struct
peak_usb_device
*
dev
;
/* unregister as many netdev devices as siblings */
for
(
dev
=
usb_get_intfdata
(
intf
);
dev
;
dev
=
dev
->
prev_siblings
)
{
struct
net_device
*
netdev
=
dev
->
netdev
;
char
name
[
IFNAMSIZ
];
dev
->
state
&=
~
PCAN_USB_STATE_CONNECTED
;
strncpy
(
name
,
netdev
->
name
,
IFNAMSIZ
);
unregister_netdev
(
netdev
);
free_candev
(
netdev
);
kfree
(
dev
->
cmd_buf
);
dev
->
next_siblings
=
NULL
;
if
(
dev
->
adapter
->
dev_free
)
dev
->
adapter
->
dev_free
(
dev
);
dev_info
(
&
intf
->
dev
,
"%s removed
\n
"
,
name
);
}
usb_set_intfdata
(
intf
,
NULL
);
}
/*
* probe function for new PEAK-System devices
*/
static
int
peak_usb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
usb_dev
=
interface_to_usbdev
(
intf
);
struct
peak_usb_adapter
*
peak_usb_adapter
,
**
pp
;
int
i
,
err
=
-
ENOMEM
;
usb_dev
=
interface_to_usbdev
(
intf
);
/* get corresponding PCAN-USB adapter */
for
(
pp
=
peak_usb_adapters_list
;
*
pp
;
pp
++
)
if
((
*
pp
)
->
device_id
==
usb_dev
->
descriptor
.
idProduct
)
break
;
peak_usb_adapter
=
*
pp
;
if
(
!
peak_usb_adapter
)
{
/* should never come except device_id bad usage in this file */
pr_err
(
"%s: didn't find device id. 0x%x in devices list
\n
"
,
PCAN_USB_DRIVER_NAME
,
usb_dev
->
descriptor
.
idProduct
);
return
-
ENODEV
;
}
/* got corresponding adapter: check if it handles current interface */
if
(
peak_usb_adapter
->
intf_probe
)
{
err
=
peak_usb_adapter
->
intf_probe
(
intf
);
if
(
err
)
return
err
;
}
for
(
i
=
0
;
i
<
peak_usb_adapter
->
ctrl_count
;
i
++
)
{
err
=
peak_usb_create_dev
(
peak_usb_adapter
,
intf
,
i
);
if
(
err
)
{
/* deregister already created devices */
peak_usb_disconnect
(
intf
);
break
;
}
}
return
err
;
}
/* usb specific object needed to register this driver with the usb subsystem */
static
struct
usb_driver
peak_usb_driver
=
{
.
name
=
PCAN_USB_DRIVER_NAME
,
.
disconnect
=
peak_usb_disconnect
,
.
probe
=
peak_usb_probe
,
.
id_table
=
peak_usb_table
,
};
static
int
__init
peak_usb_init
(
void
)
{
int
err
;
/* register this driver with the USB subsystem */
err
=
usb_register
(
&
peak_usb_driver
);
if
(
err
)
pr_err
(
"%s: usb_register failed (err %d)
\n
"
,
PCAN_USB_DRIVER_NAME
,
err
);
return
err
;
}
static
int
peak_usb_do_device_exit
(
struct
device
*
d
,
void
*
arg
)
{
struct
usb_interface
*
intf
=
to_usb_interface
(
d
);
struct
peak_usb_device
*
dev
;
/* stop as many netdev devices as siblings */
for
(
dev
=
usb_get_intfdata
(
intf
);
dev
;
dev
=
dev
->
prev_siblings
)
{
struct
net_device
*
netdev
=
dev
->
netdev
;
if
(
netif_device_present
(
netdev
))
if
(
dev
->
adapter
->
dev_exit
)
dev
->
adapter
->
dev_exit
(
dev
);
}
return
0
;
}
static
void
__exit
peak_usb_exit
(
void
)
{
int
err
;
/* last chance do send any synchronous commands here */
err
=
driver_for_each_device
(
&
peak_usb_driver
.
drvwrap
.
driver
,
NULL
,
NULL
,
peak_usb_do_device_exit
);
if
(
err
)
pr_err
(
"%s: failed to stop all can devices (err %d)
\n
"
,
PCAN_USB_DRIVER_NAME
,
err
);
/* deregister this driver with the USB subsystem */
usb_deregister
(
&
peak_usb_driver
);
pr_info
(
"%s: PCAN-USB interfaces driver unloaded
\n
"
,
PCAN_USB_DRIVER_NAME
);
}
module_init
(
peak_usb_init
);
module_exit
(
peak_usb_exit
);
drivers/net/can/usb/peak_usb/pcan_usb_core.h
0 → 100644
浏览文件 @
ffcb9738
/*
* CAN driver for PEAK System USB adapters
* Derived from the PCAN project file driver/src/pcan_usb_core.c
*
* Copyright (C) 2003-2010 PEAK System-Technik GmbH
* Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* 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.
*/
#ifndef PCAN_USB_CORE_H
#define PCAN_USB_CORE_H
/* PEAK-System vendor id. */
#define PCAN_USB_VENDOR_ID 0x0c72
/* supported device ids. */
#define PCAN_USB_PRODUCT_ID 0x000c
#define PCAN_USBPRO_PRODUCT_ID 0x000d
#define PCAN_USB_DRIVER_NAME "peak_usb"
/* number of urbs that are submitted for rx/tx per channel */
#define PCAN_USB_MAX_RX_URBS 4
#define PCAN_USB_MAX_TX_URBS 10
/* usb adapters maximum channels per usb interface */
#define PCAN_USB_MAX_CHANNEL 2
/* maximum length of the usb commands sent to/received from the devices */
#define PCAN_USB_MAX_CMD_LEN 32
struct
peak_usb_device
;
/* PEAK-System USB adapter descriptor */
struct
peak_usb_adapter
{
char
*
name
;
u32
device_id
;
struct
can_clock
clock
;
struct
can_bittiming_const
bittiming_const
;
unsigned
int
ctrl_count
;
int
(
*
intf_probe
)(
struct
usb_interface
*
intf
);
int
(
*
dev_init
)(
struct
peak_usb_device
*
dev
);
void
(
*
dev_exit
)(
struct
peak_usb_device
*
dev
);
void
(
*
dev_free
)(
struct
peak_usb_device
*
dev
);
int
(
*
dev_open
)(
struct
peak_usb_device
*
dev
);
int
(
*
dev_close
)(
struct
peak_usb_device
*
dev
);
int
(
*
dev_set_bittiming
)(
struct
peak_usb_device
*
dev
,
struct
can_bittiming
*
bt
);
int
(
*
dev_set_bus
)(
struct
peak_usb_device
*
dev
,
u8
onoff
);
int
(
*
dev_get_device_id
)(
struct
peak_usb_device
*
dev
,
u32
*
device_id
);
int
(
*
dev_decode_buf
)(
struct
peak_usb_device
*
dev
,
struct
urb
*
urb
);
int
(
*
dev_encode_msg
)(
struct
peak_usb_device
*
dev
,
struct
sk_buff
*
skb
,
u8
*
obuf
,
size_t
*
size
);
int
(
*
dev_start
)(
struct
peak_usb_device
*
dev
);
int
(
*
dev_stop
)(
struct
peak_usb_device
*
dev
);
int
(
*
dev_restart_async
)(
struct
peak_usb_device
*
dev
,
struct
urb
*
urb
,
u8
*
buf
);
u8
ep_msg_in
;
u8
ep_msg_out
[
PCAN_USB_MAX_CHANNEL
];
u8
ts_used_bits
;
u32
ts_period
;
u8
us_per_ts_shift
;
u32
us_per_ts_scale
;
int
rx_buffer_size
;
int
tx_buffer_size
;
int
sizeof_dev_private
;
};
extern
struct
peak_usb_adapter
pcan_usb
;
extern
struct
peak_usb_adapter
pcan_usb_pro
;
struct
peak_time_ref
{
struct
timeval
tv_host_0
,
tv_host
;
u32
ts_dev_1
,
ts_dev_2
;
u64
ts_total
;
u32
tick_count
;
struct
peak_usb_adapter
*
adapter
;
};
struct
peak_tx_urb_context
{
struct
peak_usb_device
*
dev
;
u32
echo_index
;
u8
dlc
;
struct
urb
*
urb
;
};
#define PCAN_USB_STATE_CONNECTED 0x00000001
#define PCAN_USB_STATE_STARTED 0x00000002
/* PEAK-System USB device */
struct
peak_usb_device
{
struct
can_priv
can
;
struct
peak_usb_adapter
*
adapter
;
unsigned
int
ctrl_idx
;
int
open_time
;
u32
state
;
struct
sk_buff
*
echo_skb
[
PCAN_USB_MAX_TX_URBS
];
struct
usb_device
*
udev
;
struct
net_device
*
netdev
;
atomic_t
active_tx_urbs
;
struct
usb_anchor
tx_submitted
;
struct
peak_tx_urb_context
tx_contexts
[
PCAN_USB_MAX_TX_URBS
];
u8
*
cmd_buf
;
struct
usb_anchor
rx_submitted
;
u32
device_number
;
u8
device_rev
;
u8
ep_msg_in
;
u8
ep_msg_out
;
u16
bus_load
;
struct
peak_usb_device
*
prev_siblings
;
struct
peak_usb_device
*
next_siblings
;
};
void
dump_mem
(
char
*
prompt
,
void
*
p
,
int
l
);
/* common timestamp management */
void
peak_usb_init_time_ref
(
struct
peak_time_ref
*
time_ref
,
struct
peak_usb_adapter
*
adapter
);
void
peak_usb_update_ts_now
(
struct
peak_time_ref
*
time_ref
,
u32
ts_now
);
void
peak_usb_set_ts_now
(
struct
peak_time_ref
*
time_ref
,
u32
ts_now
);
void
peak_usb_get_ts_tv
(
struct
peak_time_ref
*
time_ref
,
u32
ts
,
struct
timeval
*
tv
);
void
peak_usb_async_complete
(
struct
urb
*
urb
);
void
peak_usb_restart_complete
(
struct
peak_usb_device
*
dev
);
#endif
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
0 → 100644
浏览文件 @
ffcb9738
/*
* CAN driver for PEAK System PCAN-USB Pro adapter
* Derived from the PCAN project file driver/src/pcan_usbpro.c
*
* Copyright (C) 2003-2011 PEAK System-Technik GmbH
* Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* 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.
*/
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include "pcan_usb_core.h"
#include "pcan_usb_pro.h"
MODULE_SUPPORTED_DEVICE
(
"PEAK-System PCAN-USB Pro adapter"
);
/* PCAN-USB Pro Endpoints */
#define PCAN_USBPRO_EP_CMDOUT 1
#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN)
#define PCAN_USBPRO_EP_MSGOUT_0 2
#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN)
#define PCAN_USBPRO_EP_MSGOUT_1 3
#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN)
#define PCAN_USBPRO_CHANNEL_COUNT 2
/* PCAN-USB Pro adapter internal clock (MHz) */
#define PCAN_USBPRO_CRYSTAL_HZ 56000000
/* PCAN-USB Pro command timeout (ms.) */
#define PCAN_USBPRO_COMMAND_TIMEOUT 1000
/* PCAN-USB Pro rx/tx buffers size */
#define PCAN_USBPRO_RX_BUFFER_SIZE 1024
#define PCAN_USBPRO_TX_BUFFER_SIZE 64
#define PCAN_USBPRO_MSG_HEADER_LEN 4
/* some commands responses need to be re-submitted */
#define PCAN_USBPRO_RSP_SUBMIT_MAX 2
#define PCAN_USBPRO_RTR 0x01
#define PCAN_USBPRO_EXT 0x02
#define PCAN_USBPRO_CMD_BUFFER_SIZE 512
/* handle device specific info used by the netdevices */
struct
pcan_usb_pro_interface
{
struct
peak_usb_device
*
dev
[
PCAN_USBPRO_CHANNEL_COUNT
];
struct
peak_time_ref
time_ref
;
int
cm_ignore_count
;
int
dev_opened_count
;
};
/* device information */
struct
pcan_usb_pro_device
{
struct
peak_usb_device
dev
;
struct
pcan_usb_pro_interface
*
usb_if
;
u32
cached_ccbt
;
};
/* internal structure used to handle messages sent to bulk urb */
struct
pcan_usb_pro_msg
{
u8
*
rec_ptr
;
int
rec_buffer_size
;
int
rec_buffer_len
;
union
{
u16
*
rec_cnt_rd
;
u32
*
rec_cnt
;
u8
*
rec_buffer
;
}
u
;
};
/* records sizes table indexed on message id. (8-bits value) */
static
u16
pcan_usb_pro_sizeof_rec
[
256
]
=
{
[
PCAN_USBPRO_SETBTR
]
=
sizeof
(
struct
pcan_usb_pro_btr
),
[
PCAN_USBPRO_SETBUSACT
]
=
sizeof
(
struct
pcan_usb_pro_busact
),
[
PCAN_USBPRO_SETSILENT
]
=
sizeof
(
struct
pcan_usb_pro_silent
),
[
PCAN_USBPRO_SETFILTR
]
=
sizeof
(
struct
pcan_usb_pro_filter
),
[
PCAN_USBPRO_SETTS
]
=
sizeof
(
struct
pcan_usb_pro_setts
),
[
PCAN_USBPRO_GETDEVID
]
=
sizeof
(
struct
pcan_usb_pro_devid
),
[
PCAN_USBPRO_SETLED
]
=
sizeof
(
struct
pcan_usb_pro_setled
),
[
PCAN_USBPRO_RXMSG8
]
=
sizeof
(
struct
pcan_usb_pro_rxmsg
),
[
PCAN_USBPRO_RXMSG4
]
=
sizeof
(
struct
pcan_usb_pro_rxmsg
)
-
4
,
[
PCAN_USBPRO_RXMSG0
]
=
sizeof
(
struct
pcan_usb_pro_rxmsg
)
-
8
,
[
PCAN_USBPRO_RXRTR
]
=
sizeof
(
struct
pcan_usb_pro_rxmsg
)
-
8
,
[
PCAN_USBPRO_RXSTATUS
]
=
sizeof
(
struct
pcan_usb_pro_rxstatus
),
[
PCAN_USBPRO_RXTS
]
=
sizeof
(
struct
pcan_usb_pro_rxts
),
[
PCAN_USBPRO_TXMSG8
]
=
sizeof
(
struct
pcan_usb_pro_txmsg
),
[
PCAN_USBPRO_TXMSG4
]
=
sizeof
(
struct
pcan_usb_pro_txmsg
)
-
4
,
[
PCAN_USBPRO_TXMSG0
]
=
sizeof
(
struct
pcan_usb_pro_txmsg
)
-
8
,
};
/*
* initialize PCAN-USB Pro message data structure
*/
static
u8
*
pcan_msg_init
(
struct
pcan_usb_pro_msg
*
pm
,
void
*
buffer_addr
,
int
buffer_size
)
{
if
(
buffer_size
<
PCAN_USBPRO_MSG_HEADER_LEN
)
return
NULL
;
pm
->
u
.
rec_buffer
=
(
u8
*
)
buffer_addr
;
pm
->
rec_buffer_size
=
pm
->
rec_buffer_len
=
buffer_size
;
pm
->
rec_ptr
=
pm
->
u
.
rec_buffer
+
PCAN_USBPRO_MSG_HEADER_LEN
;
return
pm
->
rec_ptr
;
}
static
u8
*
pcan_msg_init_empty
(
struct
pcan_usb_pro_msg
*
pm
,
void
*
buffer_addr
,
int
buffer_size
)
{
u8
*
pr
=
pcan_msg_init
(
pm
,
buffer_addr
,
buffer_size
);
if
(
pr
)
{
pm
->
rec_buffer_len
=
PCAN_USBPRO_MSG_HEADER_LEN
;
*
pm
->
u
.
rec_cnt
=
0
;
}
return
pr
;
}
/*
* add one record to a message being built
*/
static
int
pcan_msg_add_rec
(
struct
pcan_usb_pro_msg
*
pm
,
u8
id
,
...)
{
int
len
,
i
;
u8
*
pc
;
va_list
ap
;
va_start
(
ap
,
id
);
pc
=
pm
->
rec_ptr
+
1
;
i
=
0
;
switch
(
id
)
{
case
PCAN_USBPRO_TXMSG8
:
i
+=
4
;
case
PCAN_USBPRO_TXMSG4
:
i
+=
4
;
case
PCAN_USBPRO_TXMSG0
:
*
pc
++
=
va_arg
(
ap
,
int
);
*
pc
++
=
va_arg
(
ap
,
int
);
*
pc
++
=
va_arg
(
ap
,
int
);
*
(
u32
*
)
pc
=
cpu_to_le32
(
va_arg
(
ap
,
u32
));
pc
+=
4
;
memcpy
(
pc
,
va_arg
(
ap
,
int
*
),
i
);
pc
+=
i
;
break
;
case
PCAN_USBPRO_SETBTR
:
case
PCAN_USBPRO_GETDEVID
:
*
pc
++
=
va_arg
(
ap
,
int
);
pc
+=
2
;
*
(
u32
*
)
pc
=
cpu_to_le32
(
va_arg
(
ap
,
u32
));
pc
+=
4
;
break
;
case
PCAN_USBPRO_SETFILTR
:
case
PCAN_USBPRO_SETBUSACT
:
case
PCAN_USBPRO_SETSILENT
:
*
pc
++
=
va_arg
(
ap
,
int
);
*
(
u16
*
)
pc
=
cpu_to_le16
(
va_arg
(
ap
,
int
));
pc
+=
2
;
break
;
case
PCAN_USBPRO_SETLED
:
*
pc
++
=
va_arg
(
ap
,
int
);
*
(
u16
*
)
pc
=
cpu_to_le16
(
va_arg
(
ap
,
int
));
pc
+=
2
;
*
(
u32
*
)
pc
=
cpu_to_le32
(
va_arg
(
ap
,
u32
));
pc
+=
4
;
break
;
case
PCAN_USBPRO_SETTS
:
pc
++
;
*
(
u16
*
)
pc
=
cpu_to_le16
(
va_arg
(
ap
,
int
));
pc
+=
2
;
break
;
default:
pr_err
(
"%s: %s(): unknown data type %02Xh (%d)
\n
"
,
PCAN_USB_DRIVER_NAME
,
__func__
,
id
,
id
);
pc
--
;
break
;
}
len
=
pc
-
pm
->
rec_ptr
;
if
(
len
>
0
)
{
*
pm
->
u
.
rec_cnt
=
cpu_to_le32
(
*
pm
->
u
.
rec_cnt
+
1
);
*
pm
->
rec_ptr
=
id
;
pm
->
rec_ptr
=
pc
;
pm
->
rec_buffer_len
+=
len
;
}
va_end
(
ap
);
return
len
;
}
/*
* send PCAN-USB Pro command synchronously
*/
static
int
pcan_usb_pro_send_cmd
(
struct
peak_usb_device
*
dev
,
struct
pcan_usb_pro_msg
*
pum
)
{
int
actual_length
;
int
err
;
/* usb device unregistered? */
if
(
!
(
dev
->
state
&
PCAN_USB_STATE_CONNECTED
))
return
0
;
err
=
usb_bulk_msg
(
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
PCAN_USBPRO_EP_CMDOUT
),
pum
->
u
.
rec_buffer
,
pum
->
rec_buffer_len
,
&
actual_length
,
PCAN_USBPRO_COMMAND_TIMEOUT
);
if
(
err
)
netdev_err
(
dev
->
netdev
,
"sending command failure: %d
\n
"
,
err
);
return
err
;
}
/*
* wait for PCAN-USB Pro command response
*/
static
int
pcan_usb_pro_wait_rsp
(
struct
peak_usb_device
*
dev
,
struct
pcan_usb_pro_msg
*
pum
)
{
u8
req_data_type
,
req_channel
;
int
actual_length
;
int
i
,
err
=
0
;
/* usb device unregistered? */
if
(
!
(
dev
->
state
&
PCAN_USB_STATE_CONNECTED
))
return
0
;
req_data_type
=
pum
->
u
.
rec_buffer
[
4
];
req_channel
=
pum
->
u
.
rec_buffer
[
5
];
*
pum
->
u
.
rec_cnt
=
0
;
for
(
i
=
0
;
!
err
&&
i
<
PCAN_USBPRO_RSP_SUBMIT_MAX
;
i
++
)
{
struct
pcan_usb_pro_msg
rsp
;
union
pcan_usb_pro_rec
*
pr
;
u32
r
,
rec_cnt
;
u16
rec_len
;
u8
*
pc
;
err
=
usb_bulk_msg
(
dev
->
udev
,
usb_rcvbulkpipe
(
dev
->
udev
,
PCAN_USBPRO_EP_CMDIN
),
pum
->
u
.
rec_buffer
,
pum
->
rec_buffer_len
,
&
actual_length
,
PCAN_USBPRO_COMMAND_TIMEOUT
);
if
(
err
)
{
netdev_err
(
dev
->
netdev
,
"waiting rsp error %d
\n
"
,
err
);
break
;
}
if
(
actual_length
==
0
)
continue
;
err
=
-
EBADMSG
;
if
(
actual_length
<
PCAN_USBPRO_MSG_HEADER_LEN
)
{
netdev_err
(
dev
->
netdev
,
"got abnormal too small rsp (len=%d)
\n
"
,
actual_length
);
break
;
}
pc
=
pcan_msg_init
(
&
rsp
,
pum
->
u
.
rec_buffer
,
actual_length
);
rec_cnt
=
le32_to_cpu
(
*
rsp
.
u
.
rec_cnt
);
/* loop on records stored into message */
for
(
r
=
0
;
r
<
rec_cnt
;
r
++
)
{
pr
=
(
union
pcan_usb_pro_rec
*
)
pc
;
rec_len
=
pcan_usb_pro_sizeof_rec
[
pr
->
data_type
];
if
(
!
rec_len
)
{
netdev_err
(
dev
->
netdev
,
"got unprocessed record in msg
\n
"
);
dump_mem
(
"rcvd rsp msg"
,
pum
->
u
.
rec_buffer
,
actual_length
);
break
;
}
/* check if response corresponds to request */
if
(
pr
->
data_type
!=
req_data_type
)
netdev_err
(
dev
->
netdev
,
"got unwanted rsp %xh: ignored
\n
"
,
pr
->
data_type
);
/* check if channel in response corresponds too */
else
if
((
req_channel
!=
0xff
)
&&
\
(
pr
->
bus_act
.
channel
!=
req_channel
))
netdev_err
(
dev
->
netdev
,
"got rsp %xh but on chan%u: ignored
\n
"
,
req_data_type
,
pr
->
bus_act
.
channel
);
/* got the response */
else
return
0
;
/* otherwise, go on with next record in message */
pc
+=
rec_len
;
}
}
return
(
i
>=
PCAN_USBPRO_RSP_SUBMIT_MAX
)
?
-
ERANGE
:
err
;
}
static
int
pcan_usb_pro_send_req
(
struct
peak_usb_device
*
dev
,
int
req_id
,
int
req_value
,
void
*
req_addr
,
int
req_size
)
{
int
err
;
u8
req_type
;
unsigned
int
p
;
/* usb device unregistered? */
if
(
!
(
dev
->
state
&
PCAN_USB_STATE_CONNECTED
))
return
0
;
memset
(
req_addr
,
'\0'
,
req_size
);
req_type
=
USB_TYPE_VENDOR
|
USB_RECIP_OTHER
;
switch
(
req_id
)
{
case
PCAN_USBPRO_REQ_FCT
:
p
=
usb_sndctrlpipe
(
dev
->
udev
,
0
);
break
;
default:
p
=
usb_rcvctrlpipe
(
dev
->
udev
,
0
);
req_type
|=
USB_DIR_IN
;
break
;
}
err
=
usb_control_msg
(
dev
->
udev
,
p
,
req_id
,
req_type
,
req_value
,
0
,
req_addr
,
req_size
,
2
*
USB_CTRL_GET_TIMEOUT
);
if
(
err
<
0
)
{
netdev_info
(
dev
->
netdev
,
"unable to request usb[type=%d value=%d] err=%d
\n
"
,
req_id
,
req_value
,
err
);
return
err
;
}
return
0
;
}
static
int
pcan_usb_pro_set_ts
(
struct
peak_usb_device
*
dev
,
u16
onoff
)
{
struct
pcan_usb_pro_msg
um
;
pcan_msg_init_empty
(
&
um
,
dev
->
cmd_buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_SETTS
,
onoff
);
return
pcan_usb_pro_send_cmd
(
dev
,
&
um
);
}
static
int
pcan_usb_pro_set_bitrate
(
struct
peak_usb_device
*
dev
,
u32
ccbt
)
{
struct
pcan_usb_pro_device
*
pdev
=
container_of
(
dev
,
struct
pcan_usb_pro_device
,
dev
);
struct
pcan_usb_pro_msg
um
;
pcan_msg_init_empty
(
&
um
,
dev
->
cmd_buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_SETBTR
,
dev
->
ctrl_idx
,
ccbt
);
/* cache the CCBT value to reuse it before next buson */
pdev
->
cached_ccbt
=
ccbt
;
return
pcan_usb_pro_send_cmd
(
dev
,
&
um
);
}
static
int
pcan_usb_pro_set_bus
(
struct
peak_usb_device
*
dev
,
u8
onoff
)
{
struct
pcan_usb_pro_msg
um
;
/* if bus=on, be sure the bitrate being set before! */
if
(
onoff
)
{
struct
pcan_usb_pro_device
*
pdev
=
container_of
(
dev
,
struct
pcan_usb_pro_device
,
dev
);
pcan_usb_pro_set_bitrate
(
dev
,
pdev
->
cached_ccbt
);
}
pcan_msg_init_empty
(
&
um
,
dev
->
cmd_buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_SETBUSACT
,
dev
->
ctrl_idx
,
onoff
);
return
pcan_usb_pro_send_cmd
(
dev
,
&
um
);
}
static
int
pcan_usb_pro_set_silent
(
struct
peak_usb_device
*
dev
,
u8
onoff
)
{
struct
pcan_usb_pro_msg
um
;
pcan_msg_init_empty
(
&
um
,
dev
->
cmd_buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_SETSILENT
,
dev
->
ctrl_idx
,
onoff
);
return
pcan_usb_pro_send_cmd
(
dev
,
&
um
);
}
static
int
pcan_usb_pro_set_filter
(
struct
peak_usb_device
*
dev
,
u16
filter_mode
)
{
struct
pcan_usb_pro_msg
um
;
pcan_msg_init_empty
(
&
um
,
dev
->
cmd_buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_SETFILTR
,
dev
->
ctrl_idx
,
filter_mode
);
return
pcan_usb_pro_send_cmd
(
dev
,
&
um
);
}
static
int
pcan_usb_pro_set_led
(
struct
peak_usb_device
*
dev
,
u8
mode
,
u32
timeout
)
{
struct
pcan_usb_pro_msg
um
;
pcan_msg_init_empty
(
&
um
,
dev
->
cmd_buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_SETLED
,
dev
->
ctrl_idx
,
mode
,
timeout
);
return
pcan_usb_pro_send_cmd
(
dev
,
&
um
);
}
static
int
pcan_usb_pro_get_device_id
(
struct
peak_usb_device
*
dev
,
u32
*
device_id
)
{
struct
pcan_usb_pro_devid
*
pdn
;
struct
pcan_usb_pro_msg
um
;
int
err
;
u8
*
pc
;
pc
=
pcan_msg_init_empty
(
&
um
,
dev
->
cmd_buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_GETDEVID
,
dev
->
ctrl_idx
);
err
=
pcan_usb_pro_send_cmd
(
dev
,
&
um
);
if
(
err
)
return
err
;
err
=
pcan_usb_pro_wait_rsp
(
dev
,
&
um
);
if
(
err
)
return
err
;
pdn
=
(
struct
pcan_usb_pro_devid
*
)
pc
;
if
(
device_id
)
*
device_id
=
le32_to_cpu
(
pdn
->
serial_num
);
return
err
;
}
static
int
pcan_usb_pro_set_bittiming
(
struct
peak_usb_device
*
dev
,
struct
can_bittiming
*
bt
)
{
u32
ccbt
;
ccbt
=
(
dev
->
can
.
ctrlmode
&
CAN_CTRLMODE_3_SAMPLES
)
?
0x00800000
:
0
;
ccbt
|=
(
bt
->
sjw
-
1
)
<<
24
;
ccbt
|=
(
bt
->
phase_seg2
-
1
)
<<
20
;
ccbt
|=
(
bt
->
prop_seg
+
bt
->
phase_seg1
-
1
)
<<
16
;
/* = tseg1 */
ccbt
|=
bt
->
brp
-
1
;
netdev_info
(
dev
->
netdev
,
"setting ccbt=0x%08x
\n
"
,
ccbt
);
return
pcan_usb_pro_set_bitrate
(
dev
,
ccbt
);
}
static
void
pcan_usb_pro_restart_complete
(
struct
urb
*
urb
)
{
/* can delete usb resources */
peak_usb_async_complete
(
urb
);
/* notify candev and netdev */
peak_usb_restart_complete
(
urb
->
context
);
}
/*
* handle restart but in asynchronously way
*/
static
int
pcan_usb_pro_restart_async
(
struct
peak_usb_device
*
dev
,
struct
urb
*
urb
,
u8
*
buf
)
{
struct
pcan_usb_pro_msg
um
;
pcan_msg_init_empty
(
&
um
,
buf
,
PCAN_USB_MAX_CMD_LEN
);
pcan_msg_add_rec
(
&
um
,
PCAN_USBPRO_SETBUSACT
,
dev
->
ctrl_idx
,
1
);
usb_fill_bulk_urb
(
urb
,
dev
->
udev
,
usb_sndbulkpipe
(
dev
->
udev
,
PCAN_USBPRO_EP_CMDOUT
),
buf
,
PCAN_USB_MAX_CMD_LEN
,
pcan_usb_pro_restart_complete
,
dev
);
return
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
}
static
void
pcan_usb_pro_drv_loaded
(
struct
peak_usb_device
*
dev
,
int
loaded
)
{
u8
buffer
[
16
];
buffer
[
0
]
=
0
;
buffer
[
1
]
=
!!
loaded
;
pcan_usb_pro_send_req
(
dev
,
PCAN_USBPRO_REQ_FCT
,
PCAN_USBPRO_FCT_DRVLD
,
buffer
,
sizeof
(
buffer
));
}
static
inline
struct
pcan_usb_pro_interface
*
pcan_usb_pro_dev_if
(
struct
peak_usb_device
*
dev
)
{
struct
pcan_usb_pro_device
*
pdev
=
container_of
(
dev
,
struct
pcan_usb_pro_device
,
dev
);
return
pdev
->
usb_if
;
}
static
int
pcan_usb_pro_handle_canmsg
(
struct
pcan_usb_pro_interface
*
usb_if
,
struct
pcan_usb_pro_rxmsg
*
rx
)
{
const
unsigned
int
ctrl_idx
=
(
rx
->
len
>>
4
)
&
0x0f
;
struct
peak_usb_device
*
dev
=
usb_if
->
dev
[
ctrl_idx
];
struct
net_device
*
netdev
=
dev
->
netdev
;
struct
can_frame
*
can_frame
;
struct
sk_buff
*
skb
;
struct
timeval
tv
;
skb
=
alloc_can_skb
(
netdev
,
&
can_frame
);
if
(
!
skb
)
return
-
ENOMEM
;
can_frame
->
can_id
=
le32_to_cpu
(
rx
->
id
);
can_frame
->
can_dlc
=
rx
->
len
&
0x0f
;
if
(
rx
->
flags
&
PCAN_USBPRO_EXT
)
can_frame
->
can_id
|=
CAN_EFF_FLAG
;
if
(
rx
->
flags
&
PCAN_USBPRO_RTR
)
can_frame
->
can_id
|=
CAN_RTR_FLAG
;
else
memcpy
(
can_frame
->
data
,
rx
->
data
,
can_frame
->
can_dlc
);
peak_usb_get_ts_tv
(
&
usb_if
->
time_ref
,
le32_to_cpu
(
rx
->
ts32
),
&
tv
);
skb
->
tstamp
=
timeval_to_ktime
(
tv
);
netif_rx
(
skb
);
netdev
->
stats
.
rx_packets
++
;
netdev
->
stats
.
rx_bytes
+=
can_frame
->
can_dlc
;
return
0
;
}
static
int
pcan_usb_pro_handle_error
(
struct
pcan_usb_pro_interface
*
usb_if
,
struct
pcan_usb_pro_rxstatus
*
er
)
{
const
u32
raw_status
=
le32_to_cpu
(
er
->
status
);
const
unsigned
int
ctrl_idx
=
(
er
->
channel
>>
4
)
&
0x0f
;
struct
peak_usb_device
*
dev
=
usb_if
->
dev
[
ctrl_idx
];
struct
net_device
*
netdev
=
dev
->
netdev
;
struct
can_frame
*
can_frame
;
enum
can_state
new_state
=
CAN_STATE_ERROR_ACTIVE
;
u8
err_mask
=
0
;
struct
sk_buff
*
skb
;
struct
timeval
tv
;
/* nothing should be sent while in BUS_OFF state */
if
(
dev
->
can
.
state
==
CAN_STATE_BUS_OFF
)
return
0
;
if
(
!
raw_status
)
{
/* no error bit (back to active state) */
dev
->
can
.
state
=
CAN_STATE_ERROR_ACTIVE
;
return
0
;
}
if
(
raw_status
&
(
PCAN_USBPRO_STATUS_OVERRUN
|
PCAN_USBPRO_STATUS_QOVERRUN
))
{
/* trick to bypass next comparison and process other errors */
new_state
=
CAN_STATE_MAX
;
}
if
(
raw_status
&
PCAN_USBPRO_STATUS_BUS
)
{
new_state
=
CAN_STATE_BUS_OFF
;
}
else
if
(
raw_status
&
PCAN_USBPRO_STATUS_ERROR
)
{
u32
rx_err_cnt
=
(
le32_to_cpu
(
er
->
err_frm
)
&
0x00ff0000
)
>>
16
;
u32
tx_err_cnt
=
(
le32_to_cpu
(
er
->
err_frm
)
&
0xff000000
)
>>
24
;
if
(
rx_err_cnt
>
127
)
err_mask
|=
CAN_ERR_CRTL_RX_PASSIVE
;
else
if
(
rx_err_cnt
>
96
)
err_mask
|=
CAN_ERR_CRTL_RX_WARNING
;
if
(
tx_err_cnt
>
127
)
err_mask
|=
CAN_ERR_CRTL_TX_PASSIVE
;
else
if
(
tx_err_cnt
>
96
)
err_mask
|=
CAN_ERR_CRTL_TX_WARNING
;
if
(
err_mask
&
(
CAN_ERR_CRTL_RX_WARNING
|
CAN_ERR_CRTL_TX_WARNING
))
new_state
=
CAN_STATE_ERROR_WARNING
;
else
if
(
err_mask
&
(
CAN_ERR_CRTL_RX_PASSIVE
|
CAN_ERR_CRTL_TX_PASSIVE
))
new_state
=
CAN_STATE_ERROR_PASSIVE
;
}
/* donot post any error if current state didn't change */
if
(
dev
->
can
.
state
==
new_state
)
return
0
;
/* allocate an skb to store the error frame */
skb
=
alloc_can_err_skb
(
netdev
,
&
can_frame
);
if
(
!
skb
)
return
-
ENOMEM
;
switch
(
new_state
)
{
case
CAN_STATE_BUS_OFF
:
can_frame
->
can_id
|=
CAN_ERR_BUSOFF
;
can_bus_off
(
netdev
);
break
;
case
CAN_STATE_ERROR_PASSIVE
:
can_frame
->
can_id
|=
CAN_ERR_CRTL
;
can_frame
->
data
[
1
]
|=
err_mask
;
dev
->
can
.
can_stats
.
error_passive
++
;
break
;
case
CAN_STATE_ERROR_WARNING
:
can_frame
->
can_id
|=
CAN_ERR_CRTL
;
can_frame
->
data
[
1
]
|=
err_mask
;
dev
->
can
.
can_stats
.
error_warning
++
;
break
;
case
CAN_STATE_ERROR_ACTIVE
:
break
;
default:
/* CAN_STATE_MAX (trick to handle other errors) */
if
(
raw_status
&
PCAN_USBPRO_STATUS_OVERRUN
)
{
can_frame
->
can_id
|=
CAN_ERR_PROT
;
can_frame
->
data
[
2
]
|=
CAN_ERR_PROT_OVERLOAD
;
netdev
->
stats
.
rx_over_errors
++
;
netdev
->
stats
.
rx_errors
++
;
}
if
(
raw_status
&
PCAN_USBPRO_STATUS_QOVERRUN
)
{
can_frame
->
can_id
|=
CAN_ERR_CRTL
;
can_frame
->
data
[
1
]
|=
CAN_ERR_CRTL_RX_OVERFLOW
;
netdev
->
stats
.
rx_over_errors
++
;
netdev
->
stats
.
rx_errors
++
;
}
new_state
=
CAN_STATE_ERROR_ACTIVE
;
break
;
}
dev
->
can
.
state
=
new_state
;
peak_usb_get_ts_tv
(
&
usb_if
->
time_ref
,
le32_to_cpu
(
er
->
ts32
),
&
tv
);
skb
->
tstamp
=
timeval_to_ktime
(
tv
);
netif_rx
(
skb
);
netdev
->
stats
.
rx_packets
++
;
netdev
->
stats
.
rx_bytes
+=
can_frame
->
can_dlc
;
return
0
;
}
static
void
pcan_usb_pro_handle_ts
(
struct
pcan_usb_pro_interface
*
usb_if
,
struct
pcan_usb_pro_rxts
*
ts
)
{
/* should wait until clock is stabilized */
if
(
usb_if
->
cm_ignore_count
>
0
)
usb_if
->
cm_ignore_count
--
;
else
peak_usb_set_ts_now
(
&
usb_if
->
time_ref
,
le32_to_cpu
(
ts
->
ts64
[
1
]));
}
/*
* callback for bulk IN urb
*/
static
int
pcan_usb_pro_decode_buf
(
struct
peak_usb_device
*
dev
,
struct
urb
*
urb
)
{
struct
pcan_usb_pro_interface
*
usb_if
=
pcan_usb_pro_dev_if
(
dev
);
struct
net_device
*
netdev
=
dev
->
netdev
;
struct
pcan_usb_pro_msg
usb_msg
;
u8
*
rec_ptr
,
*
msg_end
;
u16
rec_cnt
;
int
err
=
0
;
rec_ptr
=
pcan_msg_init
(
&
usb_msg
,
urb
->
transfer_buffer
,
urb
->
actual_length
);
if
(
!
rec_ptr
)
{
netdev_err
(
netdev
,
"bad msg hdr len %d
\n
"
,
urb
->
actual_length
);
return
-
EINVAL
;
}
/* loop reading all the records from the incoming message */
msg_end
=
urb
->
transfer_buffer
+
urb
->
actual_length
;
rec_cnt
=
le16_to_cpu
(
*
usb_msg
.
u
.
rec_cnt_rd
);
for
(;
rec_cnt
>
0
;
rec_cnt
--
)
{
union
pcan_usb_pro_rec
*
pr
=
(
union
pcan_usb_pro_rec
*
)
rec_ptr
;
u16
sizeof_rec
=
pcan_usb_pro_sizeof_rec
[
pr
->
data_type
];
if
(
!
sizeof_rec
)
{
netdev_err
(
netdev
,
"got unsupported rec in usb msg:
\n
"
);
err
=
-
ENOTSUPP
;
break
;
}
/* check if the record goes out of current packet */
if
(
rec_ptr
+
sizeof_rec
>
msg_end
)
{
netdev_err
(
netdev
,
"got frag rec: should inc usb rx buf size
\n
"
);
err
=
-
EBADMSG
;
break
;
}
switch
(
pr
->
data_type
)
{
case
PCAN_USBPRO_RXMSG8
:
case
PCAN_USBPRO_RXMSG4
:
case
PCAN_USBPRO_RXMSG0
:
case
PCAN_USBPRO_RXRTR
:
err
=
pcan_usb_pro_handle_canmsg
(
usb_if
,
&
pr
->
rx_msg
);
if
(
err
<
0
)
goto
fail
;
break
;
case
PCAN_USBPRO_RXSTATUS
:
err
=
pcan_usb_pro_handle_error
(
usb_if
,
&
pr
->
rx_status
);
if
(
err
<
0
)
goto
fail
;
break
;
case
PCAN_USBPRO_RXTS
:
pcan_usb_pro_handle_ts
(
usb_if
,
&
pr
->
rx_ts
);
break
;
default:
netdev_err
(
netdev
,
"unhandled rec type 0x%02x (%d): ignored
\n
"
,
pr
->
data_type
,
pr
->
data_type
);
break
;
}
rec_ptr
+=
sizeof_rec
;
}
fail:
if
(
err
)
dump_mem
(
"received msg"
,
urb
->
transfer_buffer
,
urb
->
actual_length
);
return
err
;
}
static
int
pcan_usb_pro_encode_msg
(
struct
peak_usb_device
*
dev
,
struct
sk_buff
*
skb
,
u8
*
obuf
,
size_t
*
size
)
{
struct
can_frame
*
cf
=
(
struct
can_frame
*
)
skb
->
data
;
u8
data_type
,
len
,
flags
;
struct
pcan_usb_pro_msg
usb_msg
;
pcan_msg_init_empty
(
&
usb_msg
,
obuf
,
*
size
);
if
((
cf
->
can_id
&
CAN_RTR_FLAG
)
||
(
cf
->
can_dlc
==
0
))
data_type
=
PCAN_USBPRO_TXMSG0
;
else
if
(
cf
->
can_dlc
<=
4
)
data_type
=
PCAN_USBPRO_TXMSG4
;
else
data_type
=
PCAN_USBPRO_TXMSG8
;
len
=
(
dev
->
ctrl_idx
<<
4
)
|
(
cf
->
can_dlc
&
0x0f
);
flags
=
0
;
if
(
cf
->
can_id
&
CAN_EFF_FLAG
)
flags
|=
0x02
;
if
(
cf
->
can_id
&
CAN_RTR_FLAG
)
flags
|=
0x01
;
pcan_msg_add_rec
(
&
usb_msg
,
data_type
,
0
,
flags
,
len
,
cf
->
can_id
,
cf
->
data
);
*
size
=
usb_msg
.
rec_buffer_len
;
return
0
;
}
static
int
pcan_usb_pro_start
(
struct
peak_usb_device
*
dev
)
{
struct
pcan_usb_pro_device
*
pdev
=
container_of
(
dev
,
struct
pcan_usb_pro_device
,
dev
);
int
err
;
err
=
pcan_usb_pro_set_silent
(
dev
,
dev
->
can
.
ctrlmode
&
CAN_CTRLMODE_LISTENONLY
);
if
(
err
)
return
err
;
/* filter mode: 0-> All OFF; 1->bypass */
err
=
pcan_usb_pro_set_filter
(
dev
,
1
);
if
(
err
)
return
err
;
/* opening first device: */
if
(
pdev
->
usb_if
->
dev_opened_count
==
0
)
{
/* reset time_ref */
peak_usb_init_time_ref
(
&
pdev
->
usb_if
->
time_ref
,
&
pcan_usb_pro
);
/* ask device to send ts messages */
err
=
pcan_usb_pro_set_ts
(
dev
,
1
);
}
pdev
->
usb_if
->
dev_opened_count
++
;
return
err
;
}
/*
* stop interface
* (last chance before set bus off)
*/
static
int
pcan_usb_pro_stop
(
struct
peak_usb_device
*
dev
)
{
struct
pcan_usb_pro_device
*
pdev
=
container_of
(
dev
,
struct
pcan_usb_pro_device
,
dev
);
/* turn off ts msgs for that interface if no other dev opened */
if
(
pdev
->
usb_if
->
dev_opened_count
==
1
)
pcan_usb_pro_set_ts
(
dev
,
0
);
pdev
->
usb_if
->
dev_opened_count
--
;
return
0
;
}
/*
* called when probing to initialize a device object.
*/
static
int
pcan_usb_pro_init
(
struct
peak_usb_device
*
dev
)
{
struct
pcan_usb_pro_interface
*
usb_if
;
struct
pcan_usb_pro_device
*
pdev
=
container_of
(
dev
,
struct
pcan_usb_pro_device
,
dev
);
/* do this for 1st channel only */
if
(
!
dev
->
prev_siblings
)
{
struct
pcan_usb_pro_fwinfo
fi
;
struct
pcan_usb_pro_blinfo
bi
;
int
err
;
/* allocate netdevices common structure attached to first one */
usb_if
=
kzalloc
(
sizeof
(
struct
pcan_usb_pro_interface
),
GFP_KERNEL
);
if
(
!
usb_if
)
return
-
ENOMEM
;
/* number of ts msgs to ignore before taking one into account */
usb_if
->
cm_ignore_count
=
5
;
/*
* explicit use of dev_xxx() instead of netdev_xxx() here:
* information displayed are related to the device itself, not
* to the canx netdevices.
*/
err
=
pcan_usb_pro_send_req
(
dev
,
PCAN_USBPRO_REQ_INFO
,
PCAN_USBPRO_INFO_FW
,
&
fi
,
sizeof
(
fi
));
if
(
err
)
{
dev_err
(
dev
->
netdev
->
dev
.
parent
,
"unable to read %s firmware info (err %d)
\n
"
,
pcan_usb_pro
.
name
,
err
);
return
err
;
}
err
=
pcan_usb_pro_send_req
(
dev
,
PCAN_USBPRO_REQ_INFO
,
PCAN_USBPRO_INFO_BL
,
&
bi
,
sizeof
(
bi
));
if
(
err
)
{
dev_err
(
dev
->
netdev
->
dev
.
parent
,
"unable to read %s bootloader info (err %d)
\n
"
,
pcan_usb_pro
.
name
,
err
);
return
err
;
}
dev_info
(
dev
->
netdev
->
dev
.
parent
,
"PEAK-System %s hwrev %u serial %08X.%08X (%u channels)
\n
"
,
pcan_usb_pro
.
name
,
bi
.
hw_rev
,
bi
.
serial_num_hi
,
bi
.
serial_num_lo
,
pcan_usb_pro
.
ctrl_count
);
/* tell the device the can driver is running */
pcan_usb_pro_drv_loaded
(
dev
,
1
);
}
else
{
usb_if
=
pcan_usb_pro_dev_if
(
dev
->
prev_siblings
);
}
pdev
->
usb_if
=
usb_if
;
usb_if
->
dev
[
dev
->
ctrl_idx
]
=
dev
;
/* set LED in default state (end of init phase) */
pcan_usb_pro_set_led
(
dev
,
0
,
1
);
return
0
;
}
static
void
pcan_usb_pro_exit
(
struct
peak_usb_device
*
dev
)
{
struct
pcan_usb_pro_device
*
pdev
=
container_of
(
dev
,
struct
pcan_usb_pro_device
,
dev
);
/*
* when rmmod called before unplug and if down, should reset things
* before leaving
*/
if
(
dev
->
can
.
state
!=
CAN_STATE_STOPPED
)
{
/* set bus off on the corresponding channel */
pcan_usb_pro_set_bus
(
dev
,
0
);
}
/* if channel #0 (only) */
if
(
dev
->
ctrl_idx
==
0
)
{
/* turn off calibration message if any device were opened */
if
(
pdev
->
usb_if
->
dev_opened_count
>
0
)
pcan_usb_pro_set_ts
(
dev
,
0
);
/* tell the PCAN-USB Pro device the driver is being unloaded */
pcan_usb_pro_drv_loaded
(
dev
,
0
);
}
}
/*
* called when PCAN-USB Pro adapter is unplugged
*/
static
void
pcan_usb_pro_free
(
struct
peak_usb_device
*
dev
)
{
/* last device: can free pcan_usb_pro_interface object now */
if
(
!
dev
->
prev_siblings
&&
!
dev
->
next_siblings
)
kfree
(
pcan_usb_pro_dev_if
(
dev
));
}
/*
* probe function for new PCAN-USB Pro usb interface
*/
static
int
pcan_usb_pro_probe
(
struct
usb_interface
*
intf
)
{
struct
usb_host_interface
*
if_desc
;
int
i
;
if_desc
=
intf
->
altsetting
;
/* check interface endpoint addresses */
for
(
i
=
0
;
i
<
if_desc
->
desc
.
bNumEndpoints
;
i
++
)
{
struct
usb_endpoint_descriptor
*
ep
=
&
if_desc
->
endpoint
[
i
].
desc
;
/*
* below is the list of valid ep addreses. Any other ep address
* is considered as not-CAN interface address => no dev created
*/
switch
(
ep
->
bEndpointAddress
)
{
case
PCAN_USBPRO_EP_CMDOUT
:
case
PCAN_USBPRO_EP_CMDIN
:
case
PCAN_USBPRO_EP_MSGOUT_0
:
case
PCAN_USBPRO_EP_MSGOUT_1
:
case
PCAN_USBPRO_EP_MSGIN
:
case
PCAN_USBPRO_EP_UNUSED
:
break
;
default:
return
-
ENODEV
;
}
}
return
0
;
}
/*
* describe the PCAN-USB Pro adapter
*/
struct
peak_usb_adapter
pcan_usb_pro
=
{
.
name
=
"PCAN-USB Pro"
,
.
device_id
=
PCAN_USBPRO_PRODUCT_ID
,
.
ctrl_count
=
PCAN_USBPRO_CHANNEL_COUNT
,
.
clock
=
{
.
freq
=
PCAN_USBPRO_CRYSTAL_HZ
,
},
.
bittiming_const
=
{
.
name
=
"pcan_usb_pro"
,
.
tseg1_min
=
1
,
.
tseg1_max
=
16
,
.
tseg2_min
=
1
,
.
tseg2_max
=
8
,
.
sjw_max
=
4
,
.
brp_min
=
1
,
.
brp_max
=
1024
,
.
brp_inc
=
1
,
},
/* size of device private data */
.
sizeof_dev_private
=
sizeof
(
struct
pcan_usb_pro_device
),
/* timestamps usage */
.
ts_used_bits
=
32
,
.
ts_period
=
1000000
,
/* calibration period in ts. */
.
us_per_ts_scale
=
1
,
/* us = (ts * scale) >> shift */
.
us_per_ts_shift
=
0
,
/* give here messages in/out endpoints */
.
ep_msg_in
=
PCAN_USBPRO_EP_MSGIN
,
.
ep_msg_out
=
{
PCAN_USBPRO_EP_MSGOUT_0
,
PCAN_USBPRO_EP_MSGOUT_1
},
/* size of rx/tx usb buffers */
.
rx_buffer_size
=
PCAN_USBPRO_RX_BUFFER_SIZE
,
.
tx_buffer_size
=
PCAN_USBPRO_TX_BUFFER_SIZE
,
/* device callbacks */
.
intf_probe
=
pcan_usb_pro_probe
,
.
dev_init
=
pcan_usb_pro_init
,
.
dev_exit
=
pcan_usb_pro_exit
,
.
dev_free
=
pcan_usb_pro_free
,
.
dev_set_bus
=
pcan_usb_pro_set_bus
,
.
dev_set_bittiming
=
pcan_usb_pro_set_bittiming
,
.
dev_get_device_id
=
pcan_usb_pro_get_device_id
,
.
dev_decode_buf
=
pcan_usb_pro_decode_buf
,
.
dev_encode_msg
=
pcan_usb_pro_encode_msg
,
.
dev_start
=
pcan_usb_pro_start
,
.
dev_stop
=
pcan_usb_pro_stop
,
.
dev_restart_async
=
pcan_usb_pro_restart_async
,
};
drivers/net/can/usb/peak_usb/pcan_usb_pro.h
0 → 100644
浏览文件 @
ffcb9738
/*
* CAN driver for PEAK System PCAN-USB Pro adapter
* Derived from the PCAN project file driver/src/pcan_usbpro_fw.h
*
* Copyright (C) 2003-2011 PEAK System-Technik GmbH
* Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* 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.
*/
#ifndef PCAN_USB_PRO_H
#define PCAN_USB_PRO_H
/*
* USB Vendor request data types
*/
#define PCAN_USBPRO_REQ_INFO 0
#define PCAN_USBPRO_REQ_FCT 2
/* Vendor Request value for XXX_INFO */
#define PCAN_USBPRO_INFO_BL 0
#define PCAN_USBPRO_INFO_FW 1
/* Vendor Request value for XXX_FCT */
#define PCAN_USBPRO_FCT_DRVLD 5
/* tell device driver is loaded */
/* PCAN_USBPRO_INFO_BL vendor request record type */
struct
__packed
pcan_usb_pro_blinfo
{
u32
ctrl_type
;
u8
version
[
4
];
u8
day
;
u8
month
;
u8
year
;
u8
dummy
;
u32
serial_num_hi
;
u32
serial_num_lo
;
u32
hw_type
;
u32
hw_rev
;
};
/* PCAN_USBPRO_INFO_FW vendor request record type */
struct
__packed
pcan_usb_pro_fwinfo
{
u32
ctrl_type
;
u8
version
[
4
];
u8
day
;
u8
month
;
u8
year
;
u8
dummy
;
u32
fw_type
;
};
/*
* USB Command record types
*/
#define PCAN_USBPRO_SETBTR 0x02
#define PCAN_USBPRO_SETBUSACT 0x04
#define PCAN_USBPRO_SETSILENT 0x05
#define PCAN_USBPRO_SETFILTR 0x0a
#define PCAN_USBPRO_SETTS 0x10
#define PCAN_USBPRO_GETDEVID 0x12
#define PCAN_USBPRO_SETLED 0x1C
#define PCAN_USBPRO_RXMSG8 0x80
#define PCAN_USBPRO_RXMSG4 0x81
#define PCAN_USBPRO_RXMSG0 0x82
#define PCAN_USBPRO_RXRTR 0x83
#define PCAN_USBPRO_RXSTATUS 0x84
#define PCAN_USBPRO_RXTS 0x85
#define PCAN_USBPRO_TXMSG8 0x41
#define PCAN_USBPRO_TXMSG4 0x42
#define PCAN_USBPRO_TXMSG0 0x43
/* record structures */
struct
__packed
pcan_usb_pro_btr
{
u8
data_type
;
u8
channel
;
u16
dummy
;
u32
CCBT
;
};
struct
__packed
pcan_usb_pro_busact
{
u8
data_type
;
u8
channel
;
u16
onoff
;
};
struct
__packed
pcan_usb_pro_silent
{
u8
data_type
;
u8
channel
;
u16
onoff
;
};
struct
__packed
pcan_usb_pro_filter
{
u8
data_type
;
u8
dummy
;
u16
filter_mode
;
};
struct
__packed
pcan_usb_pro_setts
{
u8
data_type
;
u8
dummy
;
u16
mode
;
};
struct
__packed
pcan_usb_pro_devid
{
u8
data_type
;
u8
channel
;
u16
dummy
;
u32
serial_num
;
};
struct
__packed
pcan_usb_pro_setled
{
u8
data_type
;
u8
channel
;
u16
mode
;
u32
timeout
;
};
struct
__packed
pcan_usb_pro_rxmsg
{
u8
data_type
;
u8
client
;
u8
flags
;
u8
len
;
u32
ts32
;
u32
id
;
u8
data
[
8
];
};
#define PCAN_USBPRO_STATUS_ERROR 0x0001
#define PCAN_USBPRO_STATUS_BUS 0x0002
#define PCAN_USBPRO_STATUS_OVERRUN 0x0004
#define PCAN_USBPRO_STATUS_QOVERRUN 0x0008
struct
__packed
pcan_usb_pro_rxstatus
{
u8
data_type
;
u8
channel
;
u16
status
;
u32
ts32
;
u32
err_frm
;
};
struct
__packed
pcan_usb_pro_rxts
{
u8
data_type
;
u8
dummy
[
3
];
u32
ts64
[
2
];
};
struct
__packed
pcan_usb_pro_txmsg
{
u8
data_type
;
u8
client
;
u8
flags
;
u8
len
;
u32
id
;
u8
data
[
8
];
};
union
pcan_usb_pro_rec
{
u8
data_type
;
struct
pcan_usb_pro_btr
btr
;
struct
pcan_usb_pro_busact
bus_act
;
struct
pcan_usb_pro_silent
silent_mode
;
struct
pcan_usb_pro_filter
filter_mode
;
struct
pcan_usb_pro_setts
ts
;
struct
pcan_usb_pro_devid
dev_id
;
struct
pcan_usb_pro_setled
set_led
;
struct
pcan_usb_pro_rxmsg
rx_msg
;
struct
pcan_usb_pro_rxstatus
rx_status
;
struct
pcan_usb_pro_rxts
rx_ts
;
struct
pcan_usb_pro_txmsg
tx_msg
;
};
#endif
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录