|
实验内容:
分别在 PC 并口的 13 脚和 25 脚引出两条引线,LED 灯长脚(+)接 PC 并口第 2 脚,短脚(-)接 PC 并口 18 脚 。当加载驱动程序后,启动测试应用程序,一开始会启动开启 LED 然后弹出等待输入信息并等待输入。这时接触两根金属引脚,1s 后 LED 关闭,然后再弹出第二次等待输入信息。再一次接触金属引脚,LED 灯以 0.5s 为周期开关 5 次。接着,弹出第三次等待输入信息,在金属引脚接触后,LED 以 0.2s 为间隔开关。此时,如果再次接触金属引线,那么程序终止。
实验目的主要是熟悉 ioctl() 函数的使用方法以及相关宏的使用。代码由 3 部分组成,一个公用头文件,一个设备驱程序,一个应用测试程序。
头文件 ioctl_test.h 内容:
#ifndef _IOCTLTEST_H_
#define _IOCTLTEST_H_
#define IOCTLTEST_MAGIC 't'
typedef struct {
unsigned long size;
unsigned char buff [128];
}__attribute__((packed)) ioctl_test_info;
#define IOCTLTEST_LEDOFF _IO (IOCTLTEST_MAGIC, 0)
#define IOCTLTEST_LEDON _IO (IOCTLTEST_MAGIC, 1)
#define IOCTLTEST_GETSTATE _IO (IOCTLTEST_MAGIC, 2)
#define IOCTLTEST_READ _IOR (IOCTLTEST_MAGIC, 3, ioctl_test_info)
#define IOCTLTEST_WRITE _IOW (IOCTLTEST_MAGIC, 4, ioctl_test_info)
#define IOCTLTEST_WRITE_READ _IOWR (IOCTLTEST_MAGIC, 5, ioctl_test_info)
#define IOCTLTEST_MAXNR 6
#endif
上面所用到的宏 _IO, _IOR, _IOW, IOWR 见:http://www.groad.net/bbs/read.php?tid-1212.html
驱动程序代码:
#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>
#include "ioctl_test.h"
#define IOCTLTEST_DEV_NAME "ioctldev"
#define IOCTLTEST_DEV_MAJOR 240
#define IOCTLTEST_WRITE_ADDR 0x378
#define IOCTLTEST_READ_ADDR 0X379
int ioctltest_open (struct inode *inode, struct file *filp)
{
return 0;
}
int ioctltest_release (struct inode *inode, struct file *filp)
{
return 0;
}
int ioctltest_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
ioctl_test_info ctrl_info;
int err, size;
int loop;
if (_IOC_TYPE(cmd) != IOCTLTEST_MAGIC) /*魔数不一致则出错*/
return -EINVAL;
if (_IOC_NR(cmd) >= IOCTLTEST_MAXNR) /*魔数相同时判断命令的基数是否大于定义的值*/
return -EINVAL;
size = _IOC_SIZE (cmd);
if (size) {
err = 0;
if (_IOC_DIR (cmd) & _IOC_READ )
err = access_ok (VERIFY_WRITE, (void *)arg, size);
else if (_IOC_DIR (cmd) & _IOC_WRITE)
err = access_ok (VERIFY_READ, (void *) arg, size);
if (!err)
return err;
}
switch (cmd) {
case IOCTLTEST_LEDOFF:
outb (0x00, IOCTLTEST_WRITE_ADDR);
break;
case IOCTLTEST_LEDON:
outb (0xff, IOCTLTEST_WRITE_ADDR);
break;
case IOCTLTEST_GETSTATE:
return (inb (IOCTLTEST_READ_ADDR));
case IOCTLTEST_READ:
ctrl_info.buff[0] = inb (IOCTLTEST_READ_ADDR);
ctrl_info.size = 1;
copy_to_user ((void *)arg, (const void *)&ctrl_info, (unsigned long)size);
break;
case IOCTLTEST_WRITE:
copy_from_user ((void *)&ctrl_info, (const void *)arg, size);
for (loop = 0; loop < ctrl_info.size; loop++)
outb (ctrl_info.buff[loop], IOCTLTEST_WRITE_ADDR);
break;
case IOCTLTEST_WRITE_READ:
copy_from_user ((void *)&ctrl_info, (const void *)arg, size);
for (loop = 0; loop < ctrl_info.size; loop++)
outb (ctrl_info.buff[loop], IOCTLTEST_WRITE_ADDR);
ctrl_info.buff[0] = inb (IOCTLTEST_READ_ADDR);
ctrl_info.size = 1;
copy_to_user ((void *)arg, (const void *)&ctrl_info, (unsigned long)size);
break;
}
return 0;
}
struct file_operations ioctltest_fops = {
.owner = THIS_MODULE,
.ioctl = ioctltest_ioctl,
.open = ioctltest_open,
.release = ioctltest_release,
};
int ioctltest_init (void)
{
int result;
result = register_chrdev (IOCTLTEST_DEV_MAJOR, IOCTLTEST_DEV_NAME, &ioctltest_fops);
if (result < 0) return result;
return 0;
}
void ioctltest_exit (void)
{
unregister_chrdev (IOCTLTEST_DEV_MAJOR, IOCTLTEST_DEV_NAME);
}
module_init (ioctltest_init);
module_exit (ioctltest_exit);
MODULE_LICENSE ("Dual BSD/GPL");
Makefile 文件:
obj-m := ioctl_dev.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>
#include "ioctl_test.h"
#define DEVICE_FILENAME "/dev/ioctl_dev"
int main()
{
ioctl_test_info info;
int dev;
int state;
int cnt;
dev = open (DEVICE_FILENAME, O_RDWR | O_NDELAY);
if (dev >= 0) {
printf ("wait...input\n");
ioctl (dev, IOCTLTEST_LEDON);
while (1) {
state = ioctl (dev, IOCTLTEST_GETSTATE);
if (!(state & 0x10)) break;
}
sleep (1);
ioctl (dev, IOCTLTEST_LEDOFF);
printf ("wait... input\n");
while (1) {
info.size = 0;
ioctl (dev, IOCTLTEST_READ, &info);
if (info.size > 0) {
if (!(info.buff[0] & 0x10)) break;
}
}
printf ("IOCTLTEST_READ OK!\n");
info.size = 1;
info.buff[0] = 0xFF;
for (cnt = 0; cnt < 10; cnt++) {
ioctl (dev, IOCTLTEST_WRITE, &info);
info.buff[0] = ~info.buff[0];
usleep (500000);
}
printf ("wait... input\n");
cnt = 0;
state = 0xFF;
while (1) {
info.size = 1;
info.buff[0] = state;
ioctl (dev, IOCTLTEST_WRITE_READ, &info);
if (info.size > 0) {
if (!(info.buff[0] & 0x10)) break;
}
cnt++;
if (cnt >= 2) {
cnt = 0;
state = ~state;
}
usleep (100000);
}
ioctl (dev, IOCTLTEST_LEDOFF);
close (dev);
}
return 0;
} |
|