|
驱动程序 (2.6 kernel) :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define RDWR_DEV_NAME "rdwrdev"
#define RDWR_DEV_MAJOR 240
#define RDWR_WRITE_ADDR 0x0378
#define RDWR_READ_ADDR 0x0379
int rdwr_open (struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t rdwr_read (struct file *filp, char *buf, size_t count, loff_t *f_ops)
{
unsigned char status;
int loop;
for (loop = 0; loop < count; loop++) {
status = inb (RDWR_READ_ADDR);
put_user (status, (char *) & buf [loop]);
}
return count;
}
ssize_t rdwr_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
unsigned char status;
int loop;
for (loop = 0; loop < count; loop++) {
get_user (status, (char *)buf);
outb (status, RDWR_WRITE_ADDR);
}
return count;
}
int rdwr_release (struct inode *inode, struct file *filp)
{
return 0;
}
struct file_operations rdwr_fops =
{
.owner = THIS_MODULE,
.read = rdwr_read,
.write = rdwr_write,
.open = rdwr_open,
.release = rdwr_release,
};
int rdwr_init (void)
{
int result;
result = register_chrdev (RDWR_DEV_MAJOR, RDWR_DEV_NAME, &rdwr_fops);
if (result < 0) return result;
return 0;
}
void rdwr_exit (void)
{
unregister_chrdev (RDWR_DEV_MAJOR, RDWR_DEV_NAME);
}
module_init (rdwr_init);
module_exit (rdwr_exit);
MODULE_LICENSE ("Dual BSD/GPL");
Makefile 文件:
obj-m := rdwrdev.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf *.ko
rm -rf *.mod.*
rm -rf .*.cmd
rm -rf *.o
测试用应用程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#define DEVICE_FILENAME "/dev/rdwrdev"
int main()
{
int dev;
char buff [128];
int loop;
dev = open (DEVICE_FILENAME, O_RDWR | O_NDELAY);
if (dev >= 0) {
printf ("waiting ... input\n");
while (1) {
if (read (dev, buff, 1) == 1) {
printf ("read data [%02X]\n", buff [0] & 0xFF);
if (!(buff [0] & 0x10))
break;
}
}
printf ("input ok ... \n");
printf ("led falshing ... \n");
for (loop = 0; loop < 5; loop++) {
buff [0] = 0xFF;
write (dev, buff, 1);
sleep (1);
buff [0] = 0x00;
write (dev, buff, 1);
sleep (1);
}
close (dev);
} else {
perror ("open device");
exit (1);
}
return (0);
}
创建设备文件:
mknod /dev/rdwrdev c 240 0
编译驱动模块:
make
加载模块:
insmod rdwrdev.ko
说明:
在并口上的 25 脚和 13 脚分别引出两根引线,25 脚接地,13 脚为输入脚;2 脚接 LED 灯的长脚,18 脚接 LED 灯的短脚。
在应用程序中,使用 read() 系统调用不断尝试读取设备 0x379 上的地址信息。如果第 13 脚和第 25 脚上的两根引线没有接触,那么会一直打印信息:
read data [7F]
表明第 13 脚上并没有检测到低电平输入。
在驱动程序中的 read() 函数里,使用 inb() 函数读取设备的 0x379 这个地址,一次读取一个字节,然后再通过 put_user() 函数把读到的这个字节发送回应用程序中。
当 13 和 25 引线接触时,13 引脚有低电平输入,这时应用程序中根据 buff[0] & 0x10 可得到这个状态的判断,然后应用程序跳出 while 的无限检测循环。这时候输出:read data [6F]
input ok ...
led falshing ... 接着,在 for 的 5 次循环中,通过调用 write() 函数写设备,使 LED 灯循环的每隔 1 秒闪烁,最后退出并结束设备文件。
驱动程序中的 write() 通过 get_user() 函数得到用户传送下来的写指令(0x00 或 0xff) ,然后把指令存入 status 变量中,最后通过 outb() 函数把这个指令发往设备的 0x378 地址。
以上,就是设备驱动程序的读写过程。 |
|