Linux设备驱动程序--与硬件通信(2)
但这并不表示I/O端口的指令在s3c24x0中不可用。但是只要你注意其源码,你就会发现:其实I/O端口的指令只是一个外壳,内部还是使用和I/O内存一样的代码。以下列出一些:
I/O端口
#define outb(v,p) __raw_writeb(v,__io(p))
#define outw(v,p) __raw_writew((__force __u16) \
cpu_to_le16(v),__io(p))
#define outl(v,p) __raw_writel((__force __u32) \
cpu_to_le32(v),__io(p))
#define inb(p) ({ __u8 __v = __raw_readb(__io(p)); __v; })
#define inw(p) ({ __u16 __v = le16_to_cpu((__force __le16) \
__raw_r
eadw(__io(p))); __v; })#define inl(p) ({ __u32 __v = le32_to_cpu((__force __le32) \
__raw_readl(__io(p))); __v; })
I/O内存
#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __v; })
#define ioread16(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; })
#define ioread32(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
#define iowrite8(v,p) __raw_writeb(v, p)
#define iowrite16(v,p) __raw_writew(cpu_to_le16(v), p)
#define iowrite32(v,p) __raw_writel(cpu_to_le32(v), p)
我对I/O端口的指令和I/O内存的指令都写了相应的驱动程序,都通过了测试。在这里值得注意的有4点:
(1)所有的读写指令所赋的地址必须都是虚拟地址,你有两种选择:使用内核已经定
义好的地址,如
S3C2440_GPJCON等等,这些都是内核定义好的虚拟地址,有兴趣的可以看源码。还有一种方法就是使用自己用ioremap映射的虚拟地址。绝对
不能使用实际的物理地址,否则会因为内核无法处理地址而出现oops。
(2)在使用I/O指令时,可以不使用request_region和request_mem_region,而直接使用outb、ioread等指令。因为request的功能只是告诉内核端口被谁占用了,如再次request,内核会制止。
(3)在使用I/O指令时,所赋的地址数据有时必须通过强制类型转换为 unsigned long ,不然会有警告(具体原因请看
Linux设备驱动程序学习(7)-内核的数据类型
) 。虽然你的程序可能也可以使用,但是最好还是不要有警告为妙。
(4)在include\asm-arm\arch-s3c2410\hardware.h中定义了很多io口的操作函数,有需要可以在驱动中直接使用,很方便。
实验源码:
IO_port.tar.gz
IO_port_test.tar.gz
IO_mem.tar.gz
IO_mem_test.tar.gz
两个模块都实现了阻塞型独享设备的访问控制,并通知内核不支持llseek。具体的测试在IO_port中。
测试现象如下:
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#insmod IO_port.ko
[Tekkaman2440@SBC2440V4]#insmod IO_mem.ko
[Tekkaman2440@SBC2440V4]#cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
153 spi
180 usb
189 usb_device
204 s3c2410_serial
251 IO_mem
252 IO_port
253 usb_endpoint
254 rtc
Block devices:
1 ramdisk
256 rfd
7 loop
31 mtdblock
93 nftl
96 inftl
179 mmc
[Tekkaman2440@SBC2440V4]#mknod -m 666 /dev/IO_port c 252 0
[Tekkaman2440@SBC2440V4]#mknod -m 666 /dev/IO_mem c 251 0
[Tekkaman2440@SBC2440V4]#cd /tmp/
[Tekkaman2440@SBC2440V4]#./IO_mem_test
io_addr : c485e0d0
IO_mem: the module can not lseek!
please input the command :1
IO_mem: ioctl 1 ok!
please input the command :8
IO_mem: ioctl STATUS ok!current_status=0X1
please input the command :3
IO_mem: ioctl 3 ok!
please input the command :q[Tekkaman2440@SBC2440V4]#./IO_porttest_sleep &
[Tekkaman2440@SBC2440V4]#./IO_porttest_sleep &
[Tekkaman2440@SBC2440V4]#./IO_porttest_sleep &
[Tekkaman2440@SBC2440V4]#./IO_port_test
IO_port: the module can not lseek!
please input the command :1
IO_port: ioctl 1 ok!
please input the command :8
IO_port: ioctl STATUS ok!current_status=0X1
please input the command :3
IO_port: ioctl 3 ok!
please input the command :8
IO_port: ioctl STATUS ok! current_status=0X3
please input the command :q
[1] Done ./IO_porttest_sleep
[Tekkaman2440@SBC2440V4]#ps
PID Uid VSZ Stat Command
1 root 1744 S init
2 root SW [kthreadd]
3 root SWN [ksoftirqd/0]
4 root SW [watchdog/0]
5 root SW [events/0]
6 root SW [khelper]
61 root SW [kblockd/0]
62 root SW [ksuspend_usbd]
65 root SW [khubd]
67 root SW [kseriod]
79 root SW [pdflush]
80 root SW [pdflush]
81 root SW [kswapd0]
82 root SW [aio/0]
709 root SW [mtdblockd]
710 root SW [nftld]
711 root SW [inftld]
712 root SW [rfdd]
746 root SW [kpsmoused]
755 root SW [kmmcd]
773 root SW [rpciod/0]
782 root 1752 S -sh
783 root 1744 S init
785 root 1744 S init
787 root 1744 S init
790 root 1744 S init
843 root 1336 S ./IO_porttest_sleep
844 root 1336 S ./IO_porttest_sleep
846 root 1744 R ps
[Tekkaman2440@SBC2440V4]#ps
PID Uid VSZ Stat Command
1 root 1744 S init
2 root SW [kthreadd]
3 root SWN [ksoftirqd/0]
4 root SW [watchdog/0]
5 root SW [events/0]
6 root SW [khelper]
61 root SW [kblockd/0]
62 root SW [ksuspend_usbd]
65 root SW [khubd]
67 root SW [kseriod]
79 root SW [pdflush]
80 root SW [pdflush]
81 root SW [kswapd0]
82 root SW [aio/0]
709 root SW [mtdblockd]
710 root SW [nftld]
711 root SW [inftld]
712 root SW [rfdd]
746 root SW [kpsmoused]
755 root SW [kmmcd]
773 root SW [rpciod/0]
782 root 1752 S -sh
783 root 1744 S init
785 root 1744 S init
787 root 1744 S init
790 root 1744 S init
847 root 1744 R ps
[3] + Done ./IO_porttest_sleep
[2] + Done ./IO_porttest_sleep
程序是针对2440的,若是用2410只需要改改测试的io口就好了
- 最新评论