demo.c:
#include <linux/errno.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/cdev.h> #include <linux/version.h> #include <linux/slab.h> #include <linux/ctype.h> #include <linux/pagemap.h> #include <linux/delay.h>
#include "demo.h"
MODULE_AUTHOR("fgj"); MODULE_LICENSE("Dual BSD/GPL");
struct simple_dev *simple_devices; static unsigned char simple_inc=0; static u8 demoBuffer[256];
static struct work_struct task; static struct workqueue_struct *my_workqueue; static int flag = 0;
static void DemoTask(void *p) { printk("DemoTask run...\n"); memset(demoBuffer,0x31,256); wake_up_interruptible(&simple_devices->wq); flag = 1; printk("DemoTask end...\n"); } int simple_open(struct inode *inode, struct file *filp) { struct simple_dev *dev; simple_inc++;
dev = container_of(inode->i_cdev, struct simple_dev, cdev); filp->private_data = dev; return 0; }
int simple_release(struct inode *inode, struct file *filp) { simple_inc--; return 0; }
ssize_t simple_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos) { struct simple_dev *dev = filp->private_data; //等待数据可获得 if(wait_event_interruptible(dev->wq, flag != 0)) { return - ERESTARTSYS; } flag = 0;
if (down_interruptible(&dev->sem)) return -ERESTARTSYS; if (copy_to_user(buf,demoBuffer,count)) { count=-EFAULT; /* 把数据写到应用程序空间 */ goto out; } out: up(&dev->sem); return count; }
ssize_t simple_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) { return 0; }
struct file_operations simple_fops = { .owner = THIS_MODULE, .read = simple_read, .write = simple_write, .open = simple_open, .release = simple_release, };
/******************************************************* MODULE ROUTINE *******************************************************/ void simple_cleanup_module(void) { dev_t devno = MKDEV(simple_MAJOR, simple_MINOR);
if (simple_devices) { cdev_del(&simple_devices->cdev); kfree(simple_devices); } destroy_workqueue(my_workqueue);
unregister_chrdev_region(devno,1); }
int simple_init_module(void) { int result; dev_t dev = 0;
dev = MKDEV(simple_MAJOR, simple_MINOR); result = register_chrdev_region(dev, 1, "DEMO"); if (result < 0) { printk(KERN_WARNING "DEMO: can't get major %d\n", simple_MAJOR); return result; }
simple_devices = kmalloc(sizeof(struct simple_dev), GFP_KERNEL); if (!simple_devices) { result = -ENOMEM; goto fail; } memset(simple_devices, 0, sizeof(struct simple_dev));
sema_init(&simple_devices->sem,1); cdev_init(&simple_devices->cdev, &simple_fops); simple_devices->cdev.owner = THIS_MODULE; simple_devices->cdev.ops = &simple_fops; result = cdev_add (&simple_devices->cdev, dev, 1); if(result) { printk(KERN_NOTICE "Error %d adding DEMO\n", result); goto fail; } init_waitqueue_head(&simple_devices->wq); my_workqueue = create_workqueue("MYQUENU"); INIT_WORK(&task,DemoTask); queue_work(my_workqueue, &task); return 0;
fail: simple_cleanup_module(); return result; }
module_init(simple_init_module); module_exit(simple_cleanup_module);
demo.h
#ifndef _simple_H_ #define _simple_H_
#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
/******************************************************** * Macros to help debugging ********************************************************/ #undef PDEBUG /* undef it, just in case */ #ifdef simple_DEBUG #ifdef __KERNEL__ # define PDEBUG(fmt, args...) printk( KERN_DEBUG "DEMO: " fmt, ## args) #else//usr space # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args) #endif #else # define PDEBUG(fmt, args...) /* not debugging: nothing */ #endif
#undef PDEBUGG #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
//设备号 #define simple_MAJOR 224 #define simple_MINOR 0 #define COMMAND1 1 #define COMMAND2 2
//设备结构 struct simple_dev { struct semaphore sem; /* mutual exclusion semaphore */ wait_queue_head_t wq; struct cdev cdev; /* Char device structure */ };
//函数申明 ssize_t simple_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); ssize_t simple_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); loff_t simple_llseek(struct file *filp, loff_t off, int whence); int simple_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
#endif /* _simple_H_ */
makefile:
ifneq ($(KERNELRELEASE),) obj-m := demo.o else KERNELDIR := /opt/FriendlyARM/mini6410/linux/linux-2.6.38 //这个地方需要根据自己的区改变 PWD:=$(shell pwd) all: make -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.ko *.o *.mod.c *.mod.o *.symvers endif 测试函数read.c
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <fcntl.h> void main() { int fd; char buf[2];
fd = open("/dev/fgj", O_RDWR, S_IRUSR | S_IWUSR); if (fd != - 1) { read(fd, &buf,2); buf[2]=0; printf("The data is %s\n", buf); } else { printf("device open failed\n"); } close(fd); }
运行结果:
[root@FriendlyARM /]# insmod demo.ko DemoTask run... DemoTask end... [root@FriendlyARM /]# mknod /dev/fgj c 224 0 [root@FriendlyARM /]# ./read The data is 11 [root@FriendlyARM /]# |