将普通字符设备驱动改造成misc设备,misc设备没有字符设备那么麻烦,以后自己写的驱动尽量用misc设备来代替 scull.c
#include <linux/fs.h>
#include <linux/kernel.h> #include <linux/cdev.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/gfp.h> #include <asm/uaccess.h> #include <linux/miscdevice.h> #define SCULL_NAME "scull" #define MAX_DATA 0x1000 struct scull_dev { struct miscdevice misc_scull; char data[MAX_DATA]; struct semaphore sem; }; MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("BG2BKK"); struct scull_dev *scull_devp; int scull_open(struct inode *inode, struct file *filp) { printk(KERN_ALERT "open the scull device\n"); return 0; } int scull_release(struct inode *inode, struct file *filp) { printk(KERN_ALERT "close the scull device\n"); return 0; } ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops) { unsigned long p = *f_ops; unsigned int cnt = count; int ret = 0; if(down_interruptible(&scull_devp->sem)) return -ERESTARTSYS; if(copy_to_user(buf, scull_devp->data,cnt)){ ret = -EFAULT; } else { *f_ops += cnt; ret = cnt; printk(KERN_ALERT "read %u bytes from %lu\n",cnt, p); } up(&scull_devp->sem); printk(KERN_ALERT "read %d bytes\n",count); return ret; } ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops) { unsigned long p = *f_ops; unsigned int cnt = count; int ret = 0; if(down_interruptible(&scull_devp->sem)) return -ERESTARTSYS; if(copy_from_user(scull_devp->data,buf, cnt)) ret = -EFAULT; else { *f_ops += cnt; ret = cnt; printk(KERN_ALERT "written %u bytes from %lu\n",cnt, p); } up(&scull_devp->sem); printk(KERN_ALERT "write %d bytes\n",count); return ret; } struct file_operations scull_fops = { .owner = THIS_MODULE, .open = scull_open, .release= scull_release, .write = scull_write, .read = scull_read, }; int scull_init(void) { int result; scull_devp = kmalloc(sizeof(struct scull_dev), GFP_KERNEL); if(!scull_devp){ printk(KERN_ALERT "fialed to malloc a device\n"); result = -ENOMEM; goto fail_malloc; } memset(scull_devp, 0 , sizeof(struct scull_dev)); scull_devp->misc_scull.name = SCULL_NAME; scull_devp->misc_scull.minor = MISC_DYNAMIC_MINOR; scull_devp->misc_scull.fops = &scull_fops; result = misc_register(&scull_devp->misc_scull); if(result){ printk(KERN_ALERT "failed to register a misc device\n"); result = -1; goto fail_register; } init_MUTEX(&scull_devp->sem); printk(KERN_ALERT "init scull device\n"); return 0; fail_register: kfree(scull_devp); scull_devp = NULL; fail_malloc: return result; } void scull_cleanup(void) { misc_deregister(&scull_devp->misc_scull); kfree(scull_devp); scull_devp = NULL; printk(KERN_ALERT "clean scull device\n"); } module_init(scull_init); module_exit(scull_cleanup);
测试代码
test.c
/************************************************************************* *fileName: test.c *description: test the myscull.c *author: Hzc *create time: 2007-04-20 *modify info: - *************************************************************************/ #include <stdio.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/types.h> /* device path */ char path[] = "/dev/scull"; char buf[10]; char rbuf[10]; int i; int t = 1; int main () { int f = open (path, O_RDWR); for (i = 0; i < 10; i++) { buf[i] = i; printf("buf[%d] = %d\n",i,buf[i]); } printf("write %d bytes\n",write (f, buf, 10)); // close (f); // // // f = open (path, O_RDONLY); // if (f == -1) // { // printf ("device open error 2!\n"); // return 1; // } printf ("Read the string from device...\n"); printf("read %d bytes\n",read (f, rbuf, 10)); for (i = 0; i < 10; i++) { printf ("%d\n", rbuf[i]); } close (f); }
#KERNEL_DIR := /home/huang/linux-2.6.18/ KERNEL_DIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) obj-m := scull.o default: $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules test: test.c gcc $< -o [email protected] -g clean: rm -rf *.o *.ko *~ *.order *.symvers *.markers *.mod.c测试脚本
1 load_scull.sh
#!/bin/sh /sbin/insmod scull.ko
2 unload_scull.sh
#!/bin/sh /sbin/rmmod scull.ko
3 test.sh
#!/bin/sh make clean make make test sudo ./unload_scull sudo ./load_scull sudo ./test.o