| 
 | 
 
驱动程序 (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 地址。 
 
以上,就是设备驱动程序的读写过程。 |   
 
 
 
 |