快速参考:

#include <linux/types.h>
dev_t
dev_t is the type used to represent device numbers within the kernel.
int MAJOR(dev_t dev);
int MINOR(dev_t dev);
Macros that extract the major and minor numbers from a device number.
dev_t MKDEV(unsigned int major, unsigned int minor);
Macro that builds a dev_t data item from the major and minor numbers.

#include <linux/fs.h>
The “filesystem” header is the header required for writing device drivers. Many important functions and data structures are declared in here.
int register_chrdev_region(dev_t first, unsigned int count, char *name)
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)
void unregister_chrdev_region(dev_t first, unsigned int count);
Functions that allow a driver to allocate and free ranges of device numbers. register_chrdev_region should be used when the desired major number is known in advance; for dynamic allocation, use alloc_chrdev_region instead.
int register_chrdev(unsigned int major, const char *name, struct file_operations
*fops);
The old (pre-2.6) char device registration routine. It is emulated in the 2.6 kernel but should not be used for new code. If the major number is not , it is used unchanged; otherwise a dynamic number is assigned for this device. int unregister_chrdev(unsigned int major, const char *name);
Function that undoes a registration made with register_chrdev. Both major and the name string must contain the same values that were used to register the driver.
struct file_operations;
struct file;
struct inode;
Three important data structures used by most device drivers. The file_operations structure holds a char driver’s methods; struct file represents an open file, and struct inode represents a file on disk.

#include <linux/cdev.h>
struct cdev *cdev_alloc(void);
void cdev_init(struct cdev *dev, struct file_operations *fops);
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
void cdev_del(struct cdev *dev);
Functions for the management of cdev structures, which represent char devices
within the kernel. #include <linux/kernel.h>
container_of(pointer, type, field);
A convenience macro that may be used to obtain a pointer to a structure from a pointer to some other structure contained within it.
#include <asm/uaccess.h>
This include file declares functions used by kernel code to move data to and from user space.
unsigned long copy_from_user (void *to, const void *from, unsigned long count);
unsigned long copy_to_user (void *to, const void *from, unsigned long count);
Copy data between user space and kernel space.

第一节的测试:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h> /* dev_t */
#include <linux/kdev_t.h> /* MAJOR(dev_t dev); MINOR(dev_t dev); */
#include <linux/fs.h> /* chrdev_region */ #include "my_scull.h" MODULE_AUTHOR("chen");
MODULE_LICENSE("Dual BSD/GPL"); int my_scull_major = MY_SCULL_MAJOR;
int my_scull_minor = ;
int my_scull_nr_devs = MY_SCULL_NR_DEVS; static int my_scull_init(void)
{
int result;
dev_t dev;
printk(KERN_ALERT "my scull init\n"); /*
* Get a range of minor numbers to work with, asking for a dynamic
* major unless directed otherwise at load time.
*/
if(my_scull_major) {
dev = MKDEV(my_scull_major, my_scull_minor);
result = register_chrdev_region(dev, my_scull_nr_devs, "my_scull");
} else {
result = alloc_chrdev_region(&dev, my_scull_minor, my_scull_nr_devs, "my_scull");
my_scull_major = MAJOR(dev);
}
if(result < ) {
printk(KERN_WARNING "my scull:can't get major %d\n", my_scull_major);
return result;
} printk(KERN_ALERT "myscull dev:%d, major:%d, minor:%d\n", dev, my_scull_major, my_scull_minor); return ;
} static void my_scull_cleanup(void)
{
dev_t devno = MKDEV(my_scull_major, my_scull_minor); /* my_scull_cleanup is never called if registering failed */
unregister_chrdev_region(devno, my_scull_nr_devs); printk(KERN_ALERT "my scull clean up\n");
} module_init(my_scull_init);
module_exit(my_scull_cleanup);

alloc_chrdev_region

my_scull_load:

#!/bin/sh
module="my_scull"
device="my_scull"
mode="" # invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in. by default
/sbin/insmod ./$module.ko $* || exit # remove stale nodes
rm -f /dev/${device}[-] major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
echo $major
#echo "/dev/${device}0 c $major 0"
mknod /dev/${device} c $major
mknod /dev/${device} c $major
mknod /dev/${device} c $major
mknod /dev/${device} c $major # give appropriate group/permissions, and change the group.
# Not all distributions have staff, some have "wheel" instead.
group="staff"
grep -q '^staff:' /etc/group || group="wheel" chgrp $group /dev/${device}[-]
chmod $mode /dev/${device}[-]

my_scull_load

my_scull_unload:

#!/bin/sh
module="my_scull"
device="my_scull" # invoke rmmod with all arguments we got
/sbin/rmmod $module $* || exit # Remove stale nodes
rm -f /dev/${device} /dev/${device}[-]

看完第三章后和参考例程后的数据

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h> /* dev_t */
#include <linux/kdev_t.h> /* MAJOR(dev_t dev); MINOR(dev_t dev); */
#include <linux/fs.h> /* chrdev_region */
#include <asm/uaccess.h> #include "my_scull.h" MODULE_AUTHOR("chen");
MODULE_LICENSE("Dual BSD/GPL"); int my_scull_major = MY_SCULL_MAJOR;
int my_scull_minor = ;
int my_scull_nr_devs = MY_SCULL_NR_DEVS;
int my_scull_quantum = MY_SCULL_QUANTUM;
int my_scull_qset = MY_SCULL_QSET; struct my_scull_dev *scull_devices; /* allocated in my_scull_init */ static struct file_operations my_scull_fops = {
.owner = THIS_MODULE,
.open = my_scull_open,
.release = my_scull_release,
.write = my_scull_write,
.read = my_scull_read,
// .llseek = my_scull_llseek,
// .ioctl = my_scull_ioctl,
}; /*
* Empty out the scull device; must be called with the device
* semaphore held.
*/
int my_scull_trim(struct my_scull_dev *dev)
{
struct scull_qset *next, *dptr;
int qset = dev->qset; /* "dev" is not-null */
int i; for(dptr = dev->data;dptr;dptr = next) { /* all the list items */
if(dptr->data) {
for(i=;i<qset;i++)
kfree(dptr->data[i]);
kfree(dptr->data);
dptr->data = NULL;
}
next = dptr->next;
kfree(dptr);
}
dev->size = ;
dev->quantum = my_scull_quantum;
dev->qset = my_scull_qset;
dev->data = NULL;
return ;
} /*
* Set up the char dev structure for this device.
*/
static void my_scull_setup_cdev(struct my_scull_dev *dev, int index)
{
int err, devno = MKDEV(my_scull_major, my_scull_minor+index); cdev_init(&dev->cdev, &my_scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &my_scull_fops;
err = cdev_add(&dev->cdev, devno, );
/* Fail gracefully if need be */
if(err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
} /*
* Open and close
*/
int my_scull_open(struct inode *inode, struct file *filp)
{
struct my_scull_dev *dev; /* device information */ dev = container_of(inode->i_cdev, struct my_scull_dev, cdev); /* from dev_t get my_scull_dev pointer */
filp->private_data = dev; /* for other methods */ /* now trim to 0 the length of the device if open was write-only */
if((filp->f_flags & O_ACCMODE) == O_WRONLY) {
my_scull_trim(dev); /* ignore errors */
}
return ; /* success */
} int my_scull_release(struct inode *inode, struct file *filp)
{
return ;
} /*
* Follow the list
*/
struct scull_qset *my_scull_follow(struct my_scull_dev *dev, int n)
{
struct scull_qset *qs = dev->data; /* Allocate first qset explicitly if need be */
if(! qs) {
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if(qs == NULL)
return NULL; /* Nerver mind */
memset(qs, , sizeof(struct scull_qset));
} /* Then follow the list */
while(n--) {
if(!qs->next) {
qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if(qs->next == NULL)
return NULL; /* Nerver mind */
memset(qs->next, , sizeof(struct scull_qset));
}
qs = qs->next;
continue;
}
return qs;
}
/*
* Data management: read and write
*/
ssize_t my_scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct my_scull_dev *dev = filp->private_data;
struct scull_qset *dptr; /* the first listitem */
int quantum = dev->quantum, qset = dev->qset;
int itemsize = quantum * qset; /* how many bytes in the listitem */
int item, s_pos, q_pos, rest;
ssize_t retval = ; 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; /* find listitem, qset index, and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum; /* follow the list up to the right position (defined elsewhere) */
dptr = my_scull_follow(dev, item); if(dptr == NULL || !dptr->data || !dptr->data[s_pos])
goto out; /* don't fill holes */ /* read only up to the end of this quantum */
if(count > quantum - q_pos)
count = quantum - q_pos; if(copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count; out:
up(&dev->sem);
return retval;
} ssize_t my_scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct my_scull_dev *dev = filp->private_data;
struct scull_qset *dptr;
int quantum = dev->quantum, qset = dev->qset;
int itemsize = quantum * qset;
int item, s_pos, q_pos, rest;
ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
if(down_interruptible(&dev->sem))
return -ERESTARTSYS; /* find listitem, qset index and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum;
/* follow the list up to the right position */
dptr = my_scull_follow(dev, item);
if(dptr == NULL)
goto out;
if(!dptr->data) {
dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
if(!dptr->data)
goto out;
memset(dptr->data, , qset * sizeof(char *));
} if(!dptr->data[s_pos]) {
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
if(!dptr->data[s_pos])
goto out;
}
/* write only up to the end of this quantum */
if(count > quantum - q_pos)
count = quantum - q_pos;
if(copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count; /* update the size */
if(dev->size < *f_pos)
dev->size = *f_pos;
out:
up(&dev->sem);
return retval;
} static int my_scull_init(void)
{
int result, i;
dev_t dev;
printk(KERN_ALERT "my scull init\n"); /*
* Get a range of minor numbers to work with, asking for a dynamic
* major unless directed otherwise at load time.
*/
if(my_scull_major) {
dev = MKDEV(my_scull_major, my_scull_minor);
result = register_chrdev_region(dev, my_scull_nr_devs, "my_scull");
} else {
result = alloc_chrdev_region(&dev, my_scull_minor, my_scull_nr_devs, "my_scull");
my_scull_major = MAJOR(dev);
}
if(result < ) {
printk(KERN_WARNING "my scull:can't get major %d\n", my_scull_major);
return result;
} printk(KERN_ALERT "myscull dev:%d, major:%d, minor:%d\n", dev, my_scull_major, my_scull_minor); /*
* allocate the device -- we can't have them static, as the number
* can be specified at load time
*/
scull_devices = kmalloc(my_scull_nr_devs*sizeof(struct my_scull_dev), GFP_KERNEL);
if(!scull_devices) {
result = -ENOMEM;
goto fail; /* Make this more graceful */
}
memset(scull_devices, , my_scull_nr_devs * sizeof(struct my_scull_dev)); /* Initialize each device */
for(i=;i<my_scull_nr_devs;i++) {
scull_devices[i].quantum = my_scull_quantum;
scull_devices[i].qset = my_scull_qset;
init_MUTEX(&scull_devices[i].sem);
my_scull_setup_cdev(&scull_devices[i], i);
} dev = MKDEV(my_scull_major, my_scull_minor+my_scull_nr_devs);
// dev += my_scull_p_init(dev);
// dev += my_scull_access_init(dev); return ; /* succees */
fail:
my_scull_cleanup();
} static void my_scull_cleanup(void)
{
dev_t devno = MKDEV(my_scull_major, my_scull_minor);
int i; if(scull_devices) {
for(i=;i<my_scull_nr_devs;i++) {
my_scull_trim(scull_devices + i);
cdev_del(&scull_devices[i].cdev);
}
kfree(scull_devices);
} /* my_scull_cleanup is never called if registering failed */
unregister_chrdev_region(devno, my_scull_nr_devs); printk(KERN_ALERT "my scull clean up\n");
} module_init(my_scull_init);
module_exit(my_scull_cleanup);

my_scull.c

头文件

#ifndef __MY_SCULL_H_
#define __MY_SCULL_H_ #include <linux/ioctl.h>
#include <linux/cdev.h> #ifndef MY_SCULL_MAJOR
#define MY_SCULL_MAJOR 0 /* dynamic major by default */
#endif #ifndef MY_SCULL_NR_DEVS
#define MY_SCULL_NR_DEVS 4 /* scull0 through scull3 */
#endif #ifndef MY_SCULL_QUANTUM
#define MY_SCULL_QUANTUM 4000
#endif #ifndef MY_SCULL_QSET
#define MY_SCULL_QSET 1000
#endif /*
* Representation of scull quantum sets.
*/
struct scull_qset {
void **data;
struct scull_qset *next;
}; struct my_scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current arry size */
unsigned long size; /* amount of data sotred here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
}; int my_scull_trim(struct my_scull_dev *dev);
static void my_scull_setup_cdev(struct my_scull_dev *dev, int index);
int my_scull_open(struct inode *inode, struct file *filp);
int my_scull_release(struct inode *inode, struct file *filp);
struct scull_qset *my_scull_follow(struct my_scull_dev *dev, int n);
ssize_t my_scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t my_scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
static int my_scull_init(void);
static void my_scull_cleanup(void); #endif

my_scull.h

最新文章

  1. 窥探Swift之别具一格的Struct和Class
  2. [CUDA] CUDA to DL
  3. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q69-Q71)
  4. ppa安装php版本
  5. eclipse中的Console控制台视图脱离主窗口解决办法
  6. 腾讯PK微软 王者之战一触即发
  7. 命令行BASH
  8. linux下解压缩jar包
  9. eclipse下将普通的java工程转换成web工程
  10. DLL与EXE之间的通讯调用 以及 回调函数的线程执行空间
  11. 关于Python3中venv虚拟环境
  12. susmote个人网站博客论坛(TexTec | 关注互联网技术,传播极客精神)
  13. 八皇后问题(C#)
  14. java 实现文件上传下载以及查看
  15. IP通信基础学习第八周
  16. ELK收集Nginx自定义日志格式输出
  17. Linux发展历史
  18. vs实现数据库数据迁移
  19. Eclipse导出WAR包
  20. artTemplate--使用artTemplate时,由于json对象属性有特殊格式 导致调用报错artTemplate,syntax error,Template Error

热门文章

  1. nginxUbuntu安装Nginx和正确卸载Nginx Nginx相关 与Nginx报错:nginx: [error] invalid PID number &quot;&quot; in &quot;/run/nginx.pid&quot; 解决方法
  2. day35—JavaScript操作元素(创建、删除)
  3. vue搭建项目之设置代理
  4. rpm --qf 命令
  5. php json_encode的问题
  6. Java8默认方法
  7. JS跨域:jsonp、跨域资源共享、iframe+window.name
  8. 【五一qbxt】day6 OI中的stl
  9. [暑假集训Day2T1]种树
  10. hdu4734 F(x)(数位dp)