- 论坛徽章:
- 0
|
附上直观的代码,望高手方便赐教。。
Makefile- obj-m := scull.o
- scull-objs := scull_fops.o
- KERNELDIR ?= /lib/modules/$(shell uname -r)/build
- PWD := $(shell pwd)
- default:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
- clean:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
- rm -fr *.o *.ko *.symvers *.mod.c
复制代码 scull_fops.h- #ifndef _SCULL_FOPS_H_
- #define _SCULL_FOPS_H_
- #include <linux/sched.h>
- #include <linux/types.h>
- //file file_operations etc.
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/cdev.h>
- //copy
- #include <asm/uaccess.h>
- MODULE_LICENSE("Dual BSD/GPL");
- loff_t scull_llseek(struct file *, loff_t, int);
- ssize_t scull_read(struct file *, char __user *, size_t, loff_t *);
- ssize_t scull_write(struct file *, const char __user *, size_t, loff_t *);
- int scull_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
- int scull_open(struct inode *, struct file *);
- int scull_release(struct inode *, struct file *);
- struct scull_qset {
- void **data;
- struct scull_qset *next;
- };
- struct scull_dev {
- struct scull_qset *data; /* Pointer to first quantum set */
- int quantum; /* the current quantum size */
- int qset; /* the current array size */
- unsigned long size; /* amount of data stored here */
- unsigned int access_key; /* used by sculluid and scullpriv */
- struct semaphore sem; /* mutual exclusion semaphore */
- struct cdev cdev; /* Char device structure */
- };
- int scull_trim(struct scull_dev *dev);
- struct scull_qset *scull_follow(struct scull_dev *dev, int item);
- #endif
复制代码 scull_fops.c- #include "scull_fops.h"
- struct scull_dev dev;
- //EXPORT_SYMBOL(dev);
- struct file_operations scull_fops = {
- .owner = THIS_MODULE,
- .llseek = scull_llseek,
- .read = scull_read,
- .write = scull_write,
- .ioctl = scull_ioctl,
- .open = scull_open,
- .release = scull_release
- };
- //EXPORT_SYMBOL(scull_fops);
- loff_t
- scull_llseek(struct file *filp, loff_t offp, int count) {
- return 0;
- }
- ssize_t
- scull_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos) {
- printk("scull, scull_read() buff=%p, count=%i, *f_pos=%i\n", buff, count, *f_pos);
- struct scull_dev *dev = (struct scull_dev*)filp->private_data;
- struct scull_qset *p;
- int quantum = dev->quantum;
- int qset = dev->qset;
- int itemsize = qset * quantum;
- ssize_t retval = 0;
- if (down_interruptible(&dev->sem))
- return -ERESTARTSYS;
- if (*f_pos >= dev->size)
- goto out;
- if (*f_pos + count > dev->size)
- count = dev->size - *f_pos;
- int item = (long)*f_pos / itemsize;
- int rest = (long)*f_pos % itemsize;
- int s_pos = rest / quantum;
- int q_pos = rest % quantum;
- //follow the list up to the right qset
- p = scull_follow(dev, item);
- //printk("p = %p \n", p);
- //printk("p->data = %p \n", p->data);
- //printk("p->data[s_pos] = %p \n", p->data[s_pos]);
-
- if (p == NULL || p->data == NULL || p->data[s_pos] == NULL ) {
- printk("something is wrong\n");
- goto out;
- }
-
- char *str = p->data[s_pos] + q_pos;
- //read only up to the end of this quantum
- if (count > quantum - q_pos)
- count = quantum - q_pos;
-
- if (copy_to_user(buff, p->data[s_pos] + q_pos, count) != 0) {
- retval = -EFAULT;
- goto out;
- }
-
- printk("scull, success read %i bytes\n", count);
- *f_pos += count;
- retval = count;
- out:
- up(&dev->sem);
- return retval;
- }
- ssize_t
- scull_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos) {
- printk("scull, scull_write() start, buff=%p, count=%i, *f_pos=%i\n", buff, count, *f_pos);
- struct scull_dev *dev = filp->private_data;
- int itemsize = dev->qset * dev->quantum;
- ssize_t retval = 0;
- if (down_interruptible(&dev->sem)) {
- return -ERESTARTSYS;
- }
-
- int item = (long)*f_pos / itemsize;
- int rest = (long)*f_pos % itemsize;
- int s_pos = rest / dev->quantum;
- int q_pos = rest % dev->quantum;
-
- struct scull_qset *p = scull_follow(dev, item);
- if (p == NULL) {
- printk("scull_follow() failed\n");
- goto out;
- }
- if (p->data == NULL) {
- p->data = kmalloc(sizeof(char*) * dev->qset, GFP_KERNEL);
- if (p->data == NULL)
- goto out;
- memset(p->data, 0, sizeof(char*) * dev->qset);
- }
- if ((p->data)[s_pos] == NULL) {
- (p->data)[s_pos] = kmalloc(dev->quantum, GFP_KERNEL);
- if ((p->data)[s_pos] == NULL)
- goto out;
- }
- if (count > dev->quantum - q_pos)
- count = dev->quantum - q_pos;
- //printk("p = %p \n", p);
- //printk("p->data = %p \n", p->data);
- //printk("p->data[s_pos] = %p \n", p->data[s_pos]);
- if (copy_from_user(p->data[s_pos] + q_pos, buff, count) != 0) {
- retval = -EFAULT;
- goto out;
- }
- retval = count;
- *f_pos += count;
-
- if (dev->size < *f_pos) {
- dev->size = *f_pos;
- }
- printk("scull, copy_from_user %i bytes\n", count);
- out:
- up(&dev->sem);
- return retval;
- }
- int
- scull_ioctl(struct inode *indoe, struct file *filp, unsigned int flag, unsigned long num) {
- return 0;
- }
- int
- scull_open(struct inode *inode, struct file *filp) {
- printk("scull, scull_open() start\n");
- struct scull_dev *dev;
- dev = container_of(inode->i_cdev, struct scull_dev, cdev);
- filp->private_data = dev;
- if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
- scull_trim(dev);
- }
- return 0;
- }
- int
- scull_release(struct inode *inode, struct file *filp) {
- printk("scull, scull_release() start\n");
- return 0;
- }
- int
- scull_trim(struct scull_dev *dev) {
- printk("scull, scull_trim() start\n");
- struct scull_qset *p = dev->data;
- while (p != NULL) {
- int i;
- for (i=0; i<dev->qset; i++) {
- kfree((p->data)[i]);
- }
- kfree(p->data);
- struct scull_qset *next = p->next;
- kfree(p);
- p = next;
- }
- dev->size = 0;
- dev->data = NULL;
- return 0;
- }
- struct scull_qset *
- scull_follow(struct scull_dev *dev, int item) {
- printk("scull, scull_follow() start\n");
- struct scull_qset *p = dev->data;
- if (dev->data == NULL) {
- dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
- if (dev->data == NULL)
- return NULL;
- p = dev->data;
- p->next = NULL;
- p->data = NULL;
- }
- while (item-- != 0) {
- if (p->next == NULL) {
- p->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
- if (p->next == NULL)
- return NULL;
- p->next->data = NULL;
- p->next->next = NULL;
- }
- p = p->next;
- }
- return p;
- }
复制代码 scull.c- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/types.h>
- #include <linux/cdev.h>
- #include "scull_fops.h"
- extern struct scull_dev dev;
- extern struct file_operations scull_fops;
- dev_t devno;
- int major = 0;
- int minor = 0;
- int nr_devs = 4;
- //init
- int scull_init(void);
- //exit
- void scull_exit(void);
- //分配设备
- int alloc_dev(void);
- //注册设备
- int register_dev(void);
- int
- scull_init(void) {
- printk("hello, scull\n");
- printk("The process is \"%s\" (pid %i)\n", current->comm, current->pid);
- if (alloc_dev() == -1) {
- printk("scull: can't alloc devno, %i\n", major);
- return -1;
- }
- if (register_dev() == -1) {
- printk("scull, register_dev() failed\n");
- return -1;
- }
- return 0;
- }
- void
- scull_exit(void) {
- printk("Goodbye, scull %i,%i\n", major, minor);
- unregister_chrdev_region(devno, nr_devs);
- cdev_del(&dev.cdev);
- }
- int
- alloc_dev(void) {
- int result = 0;
- printk("scull, alloc_dev() start\n");
- if (major == 0) {
- result = alloc_chrdev_region(&devno, minor, nr_devs, "scull");
- major = MAJOR(devno);
- } else {
- devno = MKDEV(major, minor);
- result = register_chrdev_region(devno, nr_devs, "scull");
- }
- return result;
- }
- int
- register_dev(void) {
- printk("scull, register_dev() start\n");
- dev.data = NULL;
- dev.quantum = 4000;
- dev.qset = 1000;
- dev.size = 0;
- init_MUTEX(&dev.sem);
-
- cdev_init(&dev.cdev, &scull_fops);
- dev.cdev.owner = THIS_MODULE;
- dev.cdev.ops = &scull_fops;
- return cdev_add(&dev.cdev, devno, 1);
- }
- module_init(scull_init);
- module_exit(scull_exit);
复制代码 |
|