scull 代码

我的未来我决定 提交于 2020-01-19 13:34:53

//scull.h

/*
* scull.h -- definitions for the char module
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files.  The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates.   No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
* $Id: scull.h,v 1.15 2004/11/04 17:51:18 rubini Exp $
*/

#ifndef _SCULL_H_
#define _SCULL_H_

#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */

#ifndef SCULL_MAJOR
#define SCULL_MAJOR 0   /* dynamic major by default */
#endif
/*
struct cdev {
        struct kobject kobj;
        struct module *owner;   //ËùÊôÄ£¿é
        const struct file_operations *ops;  
                //Îļþ²Ù×÷½á¹¹£¬ÔÚдÇý¶¯Ê±£¬Æä½á¹¹ÌåÄڵĴ󲿷ֺ¯ÊýÒª±»ÊµÏÖ
        struct list_head list;
        dev_t dev;          //É豸ºÅ£¬int ÀàÐÍ£¬¸ß12λΪÖ÷É豸ºÅ£¬µÍ20λΪ´ÎÉ豸ºÅ
        unsigned int count;
};
*/
struct scull_dev {
        char data[4000];
        unsigned int data_size;
        struct cdev cdev;          /* Char device structure                */
};

extern int scull_major;     /* main.c */


ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
                   loff_t *f_pos);
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
                    loff_t *f_pos);

#endif

//scull.c

/*
* main.c -- the bare scull char module
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files.  The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates.   No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
*/

//#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>        /* printk() */
#include <linux/slab.h>                /* kmalloc() */
#include <linux/fs.h>                /* everything... */
#include <linux/errno.h>        /* error codes */
#include <linux/types.h>        /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>        /* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>

#include <asm/system.h>                /* cli(), *_flags */
#include <asm/uaccess.h>        /* copy_*_user */

#include "scull.h"                /* local definitions */

#define AUTO_CREATE_DEV_INODE

#ifdef AUTO_CREATE_DEV_INODE
#include <linux/device.h>
struct class *myclass =NULL;
dev_t dev_num;

#endif


/*
* Our parameters which can be set at load time.
*/
/*
MAJOR(dev_t dev)
MINOR(dev_t dev)
MKDEV(int major,int minor) //ͨ¹ýÖ÷´ÎÉ豸ºÅÀ´Éú³Édev_t
ÒÔÉϺêµ÷ÓÃÔÚÄÚºËÔ´ÂëÖÐÈç´Ë¶¨Ò壺

#define MINORBITS       20
#define MINORMASK       ((1U << MINORBITS) - 1)
        //(1<<20 -1) ´Ë²Ù×÷ºó£¬MINORMASKºêµÄµÍ20λΪ1£¬¸ß12λΪ0
#define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))
*/
int scull_major =   SCULL_MAJOR;
int scull_minor =   0;


module_param(scull_major, int, S_IRUGO);
module_param(scull_minor, int, S_IRUGO);

MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");

struct scull_dev *scull_devices;        /* allocated in scull_init_module */


int scull_open(struct inode *inode, struct file *filp)
{
        struct scull_dev *dev; /* device information */
/*container_of()Èý¸ö²ÎÊýΪ:1½á¹¹Ìå³ÉÔ±µÄµØÖ·£¬2ÊǽṹÌåÀàÐÍ£¬3ÊǽṹÌåµÄ³ÉÔ±£¬¼´2²ÎÊýÖеijÉÔ±*/
/*×îÖÕ»ñµÃinodeÖбäÁ¿cdevµÄµØÖ·*/
        dev = container_of(inode->i_cdev, struct scull_dev, cdev);
        filp->private_data = dev; /* for other methods */
/*
ÔÚsturct fileÖУ¬private_dataÊÇvoid *µÄÖ¸ÕëÀàÐÍ
scullÀïÃæ¾ÍÊÇÓÃÕâ¸öÖ¸ÕëÖ¸ÏòÓû§ÉêÇëµÄÄÚ´æÇøÓò
*/
        return 0;          /* success */
}

int scull_release(struct inode *inode, struct file *filp)
{
        return 0;
}


ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
                loff_t *f_pos)
{
        struct scull_dev *dev = filp->private_data;
 unsigned long ret;

        void *start;
        start = dev->data;
        if(dev->data_size < count)
                count = dev->data_size;
        ret =copy_to_user(buf, start, count);

        return count;
}

ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
        struct scull_dev *dev = filp->private_data;
        void *start;
 unsigned long ret;

        start = dev->data;
        if(count > 4000)
                count = 4000 - 1;
       ret = copy_from_user(start, buf, count);
        dev->data_size = count;
       
        return count;
}


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,
};

/*
* Finally, the module stuff
*/

/*
* The cleanup function is used to handle initialization failures as well.
* Thefore, it must be careful to work correctly even if some of the items
* have not been initialized
*/
void scull_cleanup_module(void)
{

        dev_t devno = MKDEV(scull_major, scull_minor);

/*
void cdev_del(struct cdev *);//×¢ÏúÉ豸£¬Í¨³£·¢ÉúÔÚÇý¶¯Ä£¿éµÄжÔغ¯ÊýÖÐ

*/
#ifdef AUTO_CREATE_DEV_INODE
  class_device_destroy(myclass,dev_num);
  class_destroy(myclass);
#endif

cdev_del(&scull_devices->cdev);
                        kfree(scull_devices);

        /* cleanup_module is never called if registering failed */
        unregister_chrdev_region(devno, 1);


}


/*
* Set up the char_dev structure for this device.
*/
static void scull_setup_cdev(struct scull_dev *dev)
{
        int err, devno = MKDEV(scull_major, scull_minor);
/*
void cdev_init(struct cdev *, const struct file_operations *);
        //³õʼ»¯£¬½¨Á¢cdevºÍfile_operation Ö®¼äµÄÁ¬½Ó
*/   
        cdev_init(&dev->cdev, &scull_fops);
        dev->cdev.owner = THIS_MODULE;
        dev->cdev.ops = &scull_fops;
        err = cdev_add (&dev->cdev, devno, 1);
        /* Fail gracefully if need be */
        if (err)
                printk(KERN_NOTICE "Error %d adding scull", err);
}


int scull_init_module(void)
{
        int result;
        dev_t dev = 0;

/*
* Get a range of minor numbers to work with, asking for a dynamic
* major unless directed otherwise at load time.
*/
/*
ÔÚ×¢²áʱӦ¸ÃÏȵ÷Óãºint register_chrdev_region(dev_t from,unsigned count,const char *name)º¯ÊýΪÆä·ÖÅäÉ豸ºÅ£¬´Ëº¯Êý¿ÉÓãº
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)º¯Êý´úÌ棬ËûÃÇÖ®¼äµÄÇø±ðÔÚÓÚ£º
register_chrdev_region()ÓÃÓÚÒÑÖªÉ豸ºÅʱ£¬ÁíÒ»¸öÓÃÓÚ¶¯Ì¬ÉêÇ룬ÆäÓŵãÔÚÓÚ²»»áÔì³ÉÉ豸ºÅÖظ´µÄ³åÍ»¡£
ÔÚ×¢ÏúÖ®ºó£¬Ó¦µ÷Óãºvoid unregister_chrdev_region(dev_t from,unsigned count)º¯ÊýÊÍ·ÅÔ­ÏÈÉêÇëµÄÉ豸ºÅ¡£
ËûÃÇÖ®¼äµÄ˳Ðò¹ØϵÈçÏ£º
register_chrdev_region()£­£­>cdev_add()     //´Ë¹ý³ÌÔÚ¼ÓÔØÄ£¿éÖÐ
cdev_del()-->unregister_chrdev_region()     //´Ë¹ý³ÌÔÚжÔØÄ£¿éÖÐ
*/
        if (scull_major) {
                dev = MKDEV(scull_major, scull_minor);
                result = register_chrdev_region(dev, 1, "scull");
        } else {
/*
¶¯Ì¬·ÖÅä:
Int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
Firstminor : ͨ³£Îª0;
*dev:´æ·Å·µ»ØµÄÉ豸ºÅ;

*/
    result = alloc_chrdev_region(&dev, scull_minor, 1,
                                "scull");
                scull_major = MAJOR(dev);
        }
        if (result < 0) {
                printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
                return result;
        }

        /*
         * allocate the devices -- we can't have them static, as the number
         * can be specified at load time
         */
        scull_devices = kmalloc(sizeof(struct scull_dev), GFP_KERNEL);
        if (!scull_devices) {
                result = -ENOMEM;
                goto fail;  /* Make this more graceful */
        }
        memset(scull_devices, 0, sizeof(struct scull_dev));

        /* Initialize each device. */

#ifdef AUTO_CREATE_DEV_INODE
  dev_num = dev;
  myclass = class_create(THIS_MODULE,"scull");
  class_device_create(myclass,NULL,dev_num,NULL,"scull0");
#endif
                scull_setup_cdev(scull_devices);


        return 0; /* succeed */

  fail:
        scull_cleanup_module();
        return result;
}

module_init(scull_init_module);
module_exit(scull_cleanup_module);

//makefile

obj-m := scull.o
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
 $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
 rm -f *.o *.ko *.mod.c .hello*

//test sample

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>

#define MAXLEN 100
#define DEV_PATH "/dev/scull0"
int main(void)
{
 int fd,len;
 char inbuf[MAXLEN];
 char outbuf[MAXLEN]="scull dev test";
 char tmp_buf[MAXLEN];
 int i;
 for(i=0;i<10;i++)
 {
  fd=open(DEV_PATH,O_WRONLY);

  if(fd < 0)
  {
   perror("open device");
   exit(EXIT_FAILURE);
  }
  memset(tmp_buf,0,MAXLEN);
  sprintf(tmp_buf,"%d",i);
  strcat(outbuf, tmp_buf);
  
  len = write(fd,outbuf,strlen(outbuf)+1);

  if(len < 0)
  {
   perror("write device");
   close(fd);
   exit(EXIT_FAILURE);  
  }

  printf("write device %d bytes ok\n",len);

  close(fd);
  sleep(1);

  fd=open(DEV_PATH,O_RDONLY);

  if(fd < 0)
  {
   perror("open device");
   exit(EXIT_FAILURE);
  } 
  memset(inbuf,0,MAXLEN);
  len = read(fd,inbuf,len);

  if(len < 0)
  {
   perror("read device");
   close(fd);
   exit(EXIT_FAILURE);  
  } 

  printf("read device ok\n");
  printf("%s\n",inbuf);
 } 
}

//gcc -o scull_test scull_test.c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!