流程
修改方法:
根据设备节点的compatible属性,
在驱动程序中构造/注册 platform_driver,
在 platform_driver 的 probe 函数中获得中断资源
1.给dm9000网卡指定中断
/*bank4*/
srom-cs4@20000000 {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x20000000 0x8000000>;//起始地址 128M
ranges;
ethernet@20000000 {
compatible = "davicom,dm9000";
reg = <0x20000000 0x2 0x20000004 0x2>;
interrupt-parent = <&gpf>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
local-mac-address = [00 00 de ad be ef];
davicom,no-eeprom;
};
};
仿照设备树–按键中断程序,在原驱动程序中添加
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
static int dm9000drv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *dp_node = dev->of_node;
struct resource *res;
int i;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
irq = res->start;//获得中断号
printk("get dm9000 irq %d\n", irq);
}
else {
printk("can not get irq res for dm9000\n");
return -1;
}
return dm9000c_init();//调用原驱动程序的初始化函数
}
static int dm9000drv_remove(struct platform_device *pdev)
{
dm9000c_exit();//调用原驱动程序的退出函数
return 0;
}
static const struct of_device_id of_match_dm9000[] = {
{ .compatible = "davicom,dm9000", .data = NULL },
{ /* sentinel */ }
};
struct platform_driver dm9000_drv = {
.probe = dm9000drv_probe,
.remove = dm9000drv_remove,
.driver = {
.name = "dm9000",
.of_match_table = of_match_dm9000, /* 能支持哪些来自于dts的platform_device */
}
};
static int dm9000drv_init(void)
{
platform_driver_register(&dm9000_drv);
return 0;
}
static void dm9000drv_exit(void)
{
platform_driver_unregister(&dm9000_drv);
}
module_init(dm9000drv_init);
module_exit(dm9000drv_exit);
2.给触摸屏指定中断
jz2440ts@5800000 {
compatible = "jz2440,ts";
reg = <0x58000000 0x100>;
reg-names = "adc_ts_physical";
interrupts = <1 31 9 3>, <1 31 10 3>;
interrupt-names = "int_ts", "int_adc_s";
clocks = <&clocks PCLK_ADC>;
clock-names = "adc";
};
interrupts = <1 31 9 3>, <1 31 10 3>;
子中断控制器-1
上一级中断控制器-31
中断控制器-9
触发类型-3
s3c_ts.c
static int s3cts_drv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *dp_node = dev->of_node;
struct resource *res;
int i;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
irq_tc = res->start;//9
printk("get touchscreen's tc irq %d\n", irq_tc);
}
else {
printk("can not get irq res for touchscreen's tc\n");
return -1;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (res) {
irq_adc = res->start;//10
printk("get touchscreen's adc irq %d\n", irq_adc);
}
else {
printk("can not get irq res for touchscreen's adc\n");
return -1;
}
return s3c_ts_init();
}
static int s3cts_drv_remove(struct platform_device *pdev)
{
s3c_ts_exit();
return 0;
}
static const struct of_device_id of_match_s3cts[] = {
{ .compatible = "jz2440,ts", .data = NULL },
{ /* sentinel */ }
};
struct platform_driver s3cts_drv = {
.probe = s3cts_drv_probe,
.remove = s3cts_drv_remove,
.driver = {
.name = "s3c_ts",
.of_match_table = of_match_s3cts, /* 能支持哪些来自于dts的platform_device */
}
};
static int s3cts_drv_init(void)
{
platform_driver_register(&s3cts_drv);
return 0;
}
static void s3cts_drv_exit(void)
{
platform_driver_unregister(&s3cts_drv);
}
module_init(s3cts_drv_init);
module_exit(s3cts_drv_exit);
s3c2440中断控制器
实验方法:
以下是修改好的代码:
第6课第1节_网卡_触摸屏驱动\001th_dm9000\dm9dev9000c.c
第6课第1节_网卡_触摸屏驱动\002th_touchscreen\s3c_ts.c
分别上传到内核如下目录:
drivers/net/ethernet/davicom
drivers/input/touchscreen
a. 编译内核
b. 使用新的uImage启动
c. 测试网卡:
ifconfig eth0 192.168.1.101
ping 192.168.1.1
d. 测试触摸屏:
hexdump /dev/evetn0 // 然后点击触摸屏
dm9dev9000c.c
/*
dm9ks.c: Version 2.08 2007/02/12
A Davicom DM9000/DM9010 ISA NIC fast Ethernet driver for Linux.
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; either version 2
of the License, or (at your option) any later version.
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.
(C)Copyright 1997-2007 DAVICOM Semiconductor,Inc. All Rights Reserved.
V2.00 Spenser - 01/10/2005
- Modification for PXA270 MAINSTONE.
- Modified dmfe_tx_done().
- Add dmfe_timeout().
V2.01 10/07/2005 -Modified dmfe_timer()
-Dected network speed 10/100M
V2.02 10/12/2005 -Use link change to chage db->Speed
-dmfe_open() wait for Link OK
V2.03 11/22/2005 -Power-off and Power-on PHY in dmfe_init_dm9000()
-support IOL
V2.04 12/13/2005 -delay 1.6s between power-on and power-off in
dmfe_init_dm9000()
-set LED mode 1 in dmfe_init_dm9000()
-add data bus driving capability in dmfe_init_dm9000()
(optional)
10/3/2006 -Add DM8606 read/write function by MDC and MDIO
V2.06 01/03/2007 -CONT_RX_PKT_CNT=0xFFFF
-modify dmfe_tx_done function
-check RX FIFO pointer
-if using physical address, re-define I/O function
-add db->cont_rx_pkt_cnt=0 at the front of dmfe_packet_receive()
V2.08 02/12/2007 -module parameter macro
2.4 MODULE_PARM
2.6 module_param
-remove #include <linux/config>
-fix dmfe_interrupt for kernel 2.6.20
V2.09 05/24/2007 -support ethtool and mii-tool
05/30/2007 -fix the driver bug when ifconfig eth0 (-)promisc and (-)allmulti.
06/05/2007 -fix dm9000b issue(ex. 10M TX idle=65mA, 10M harmonic)
-add flow control function (option)
10/01/2007 -Add #include <asm/uaccess.h>
-Modyfy dmfe_do_ioctl for kernel 2.6.7
11/23/2007 -Add TDBUG to check TX FIFO pointer shift
- Remove check_rx_ready()
- Add #define CHECKSUM to modify CHECKSUM function
12/20/2007 -Modify TX timeout routine(+)check TCR&0x01
*/
//#define CHECKSUM
//#define TDBUG /* check TX FIFO pointer */
//#define RDBUG /* check RX FIFO pointer */
//#define DM8606
#define DRV_NAME "dm9KS"
#define DRV_VERSION "2.09"
#define DRV_RELDATE "2007-11-22"
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
//#include <linux/config.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <asm/dma.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#ifdef CONFIG_ARCH_MAINSTONE
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#endif
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>
//#include <asm/arch-s3c2410/regs-mem.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include "dm9000.h"
/* Board/System/Debug information/definition ---------------- */
#define DM9KS_ID 0x90000A46
#define DM9010_ID 0x90100A46
/*-------register name-----------------------*/
#define DM9KS_NCR 0x00 /* Network control Reg.*/
#define DM9KS_NSR 0x01 /* Network Status Reg.*/
#define DM9KS_TCR 0x02 /* TX control Reg.*/
#define DM9KS_RXCR 0x05 /* RX control Reg.*/
#define DM9KS_BPTR 0x08
#define DM9KS_FCTR 0x09
#define DM9KS_FCR 0x0a
#define DM9KS_EPCR 0x0b
#define DM9KS_EPAR 0x0c
#define DM9KS_EPDRL 0x0d
#define DM9KS_EPDRH 0x0e
#define DM9KS_GPR 0x1f /* General purpose register */
#define DM9KS_CHIPR 0x2c
#define DM9KS_TCR2 0x2d
#define DM9KS_SMCR 0x2f /* Special Mode Control Reg.*/
#define DM9KS_ETXCSR 0x30 /* Early Transmit control/status Reg.*/
#define DM9KS_TCCR 0x31 /* Checksum cntrol Reg. */
#define DM9KS_RCSR 0x32 /* Receive Checksum status Reg.*/
#define DM9KS_BUSCR 0x38
#define DM9KS_MRCMDX 0xf0
#define DM9KS_MRCMD 0xf2
#define DM9KS_MDRAL 0xf4
#define DM9KS_MDRAH 0xf5
#define DM9KS_MWCMD 0xf8
#define DM9KS_MDWAL 0xfa
#define DM9KS_MDWAH 0xfb
#define DM9KS_TXPLL 0xfc
#define DM9KS_TXPLH 0xfd
#define DM9KS_ISR 0xfe
#define DM9KS_IMR 0xff
/*---------------------------------------------*/
#define DM9KS_REG05 0x30 /* SKIP_CRC/SKIP_LONG */
#define DM9KS_REGFF 0xA3 /* IMR */
#define DM9KS_DISINTR 0x80
#define DM9KS_PHY 0x40 /* PHY address 0x01 */
#define DM9KS_PKT_RDY 0x01 /* Packet ready to receive */
/* Added for PXA of MAINSTONE */
#ifdef CONFIG_ARCH_MAINSTONE
#include <asm/arch/mainstone.h>
#define DM9KS_MIN_IO (MST_ETH_PHYS + 0x300)
#define DM9KS_MAX_IO (MST_ETH_PHYS + 0x370)
#define DM9K_IRQ MAINSTONE_IRQ(3)
#else
#define DM9KS_MIN_IO 0x300
#define DM9KS_MAX_IO 0x370
#define DM9KS_IRQ 3
#endif
#define DM9KS_VID_L 0x28
#define DM9KS_VID_H 0x29
#define DM9KS_PID_L 0x2A
#define DM9KS_PID_H 0x2B
#define DM9KS_RX_INTR 0x01
#define DM9KS_TX_INTR 0x02
#define DM9KS_LINK_INTR 0x20
#define DM9KS_DWORD_MODE 1
#define DM9KS_BYTE_MODE 2
#define DM9KS_WORD_MODE 0
#define TRUE 1
#define FALSE 0
/* Number of continuous Rx packets */
#define CONT_RX_PKT_CNT 0xFFFF
#define DMFE_TIMER_WUT jiffies+(HZ*5) /* timer wakeup time : 5 second */
#ifdef DM9KS_DEBUG
#define DMFE_DBUG(dbug_now, msg, vaule)\
if (dmfe_debug||dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
#else
#define DMFE_DBUG(dbug_now, msg, vaule)\
if (dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
#endif
#ifndef CONFIG_ARCH_MAINSTONE
#pragma pack(push, 1)
#endif
typedef struct _RX_DESC
{
u8 rxbyte;
u8 status;
u16 length;
}RX_DESC;
typedef union{
u8 buf[4];
RX_DESC desc;
} rx_t;
#ifndef CONFIG_ARCH_MAINSTONE
#pragma pack(pop)
#endif
enum DM9KS_PHY_mode {
DM9KS_10MHD = 0,
DM9KS_100MHD = 1,
DM9KS_10MFD = 4,
DM9KS_100MFD = 5,
DM9KS_AUTO = 8,
};
/* Structure/enum declaration ------------------------------- */
typedef struct board_info {
u32 io_addr;/* Register I/O base address */
u32 io_data;/* Data I/O address */
u8 op_mode;/* PHY operation mode */
u8 io_mode;/* 0:word, 2:byte */
u8 Speed; /* current speed */
u8 chip_revision;
int rx_csum;/* 0:disable, 1:enable */
u32 reset_counter;/* counter: RESET */
u32 reset_tx_timeout;/* RESET caused by TX Timeout */
int tx_pkt_cnt;
int cont_rx_pkt_cnt;/* current number of continuos rx packets */
struct net_device_stats stats;
struct timer_list timer;
unsigned long timer_data;
unsigned char srom[128];
spinlock_t lock;
struct mii_if_info mii;
} board_info_t;
/* Global variable declaration ----------------------------- */
/*static int dmfe_debug = 0;*/
static struct net_device * dmfe_dev = NULL;
static struct ethtool_ops dmfe_ethtool_ops;
/* For module input parameter */
static int mode = DM9KS_AUTO;
static int media_mode = DM9KS_AUTO;
static int irq = DM9KS_IRQ;
static int iobase = DM9KS_MIN_IO;
#if 0 // use physical address; Not virtual address
#ifdef outb
#undef outb
#endif
#ifdef outw
#undef outw
#endif
#ifdef outl
#undef outl
#endif
#ifdef inb
#undef inb
#endif
#ifdef inw
#undef inw
#endif
#ifdef inl
#undef inl
#endif
void outb(u8 reg, u32 ioaddr)
{
(*(volatile u8 *)(ioaddr)) = reg;
}
void outw(u16 reg, u32 ioaddr)
{
(*(volatile u16 *)(ioaddr)) = reg;
}
void outl(u32 reg, u32 ioaddr)
{
(*(volatile u32 *)(ioad