在徐老师的指导下移植了一个通过Plx9030 PCI-localbus桥片扩展的两片sja1000 CAN控制器的驱动。现整理如下:
首先,内核drivers/net/can/sja1000/plx_pci.c是移植的初始文件,适当修改该文件即可为我所用。
<1>首先把各个声明换成自己公司板卡的相关信息,不换也可以,这点无关紧要。主要先看代码开头部分的各种宏
定义,里边有关于最大支持设备,CAN时钟等关键信息,根据自身情况修改。
<2> 重点来了,在 static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata={
"esd CAN-PCI/CPCI/PCI104/200",2 ,
PLX_PCI_CAN_CLOCK,PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00,0x00},{{2, 0x00, 0x80},{2, 0x100,0x80}},
&plx_pci_reset_common
/*based on PLX9030/9050*/
注意,在代码里有数个类似的结构体,主要是为了支持不同的设备,一个结构体就是一个对应的设备的描述。
该结构体定义如下:
struct plx_pci_card_info {
const char *name;
int channel_count;
u32 can_clock;
u8 ocr; /* output control register */
u8 cdr; /* clock divider register */
/* Parameters for mapping local configuration space */
struct plx_pci_channel_map conf_map;
/* Parameters for mapping the SJA1000 chips */
struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
/* Pointer to device-dependent reset function */
void (*reset_func)(struct pci_dev *pdev);
};
从上述结构体定义可知,主要是最后三个元素,conf_map这个元素对应配置寄存器信息,
即plx9030的配置控制寄存器的位置大小描述,chan_map_tbl[PLX_PCI_MAX_CHAN]该结构体对应各个sja1000寄存器地址。
若想真正了解需要再看下一个结构体定义:
struct plx_pci_channel_map {
u32 bar;
u32 offset;
u32 size; /* 0x00 - auto, e.g. length of entire bar */
};
看到这明白了吧,第一个是对应的bar,第二个是你自己的旗舰寄存器在该bar上对应的偏移,第三个是映射空间的大小。
这样就可以理解最初的那个填写的结构体{0, 0x00,0x00},{{2, 0x00, 0x80},{2, 0x100,0x80}}的具体意义了,既该plx9030配置
寄存器对应该PCI设备的bar0,偏移0,大小为0,大小无关紧要,主要是通过前两个参数获得配置寄存器的地址,而后两个
参数意思是在bar2上有两个SJA1000,一个偏移0,一个偏移0x100,映射大小都为0x80.
<3>上边都修改完了就该修改
static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
{
0xebed, 0xc303,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
(kernel_ulong_t)&plx_pci_card_info_tews
},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
把自己的PCI的厂商ID和设备ID填写上,主要红色代码的结构体变量要和上边你修改的那个对应上。
这基本上就可以了。
当然对于你的设备可能还不够,看上述代码之后,还有两个读写的包装函数
static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
{
return ioread8(priv->reg_base + port);
}
static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
{
iowrite8(val, priv->reg_base + port);
}
可以根据自己板子的实际情况更改读写方式。
最后,把自己板卡的一些初始化配置放进函数
/*
* Probe PLX90xx based device for the SJA1000 chips and register each
* available CAN channel to SJA1000 Socket-CAN subsystem.
*/
static int __devinit plx_pci_add_card(struct pci_dev *pdev,
const struct pci_device_id *ent)
即可。