ldd3 编写scull尝试
快速参考:
#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
ldd3 编写scull尝试的更多相关文章
- 《Linux设备驱动程序》编译LDD3的scull驱动问题总结***
由于Linux内核版本更新的原因,LDD3(v2.6.10)提供的源码无法直接使用,下面是本人编译scull源码时出现的一些问题及解决方法.编译环境:Ubuntu 10.04 LTS(kernel v ...
- Visual Studio Code 使用 Typings 实现智能提示功能
前言 我们知道在IDE中代码的智能提示几乎都是标配,虽然一些文本编辑器也有一些简单的提示,但这是通过代码片段提供的.功能上远不能和IDE相比.不过最近兴起的文本编辑器的新锐 Visual Studio ...
- JWS-webservice 与Axis2-webservice的高速实现
在详细介绍这两种框架下的webservice之前,先跟大家交流一下SOA认识,也就是面向服务的体系结构.SOA所要解决的主要问题是在现有基础环境的前提下,通过对现有应用程序和基础结构进行又一次的组合以 ...
- Typings实现智能
在Visual Studio Code中通过Typings实现智能提示功能 前言 我们知道在IDE中代码的智能提示几乎都是标配,虽然一些文本编辑器也有一些简单的提示,但这是通过代码片段提供的.功能 ...
- Windows Nodejs 安装教程
Windows Nodejs 安装教程 1: 访问官方地址 https://nodejs.org/en/download/ 2: 解压压缩包文件到指定目录 我直接把压缩包解压到C盘根目录下,并将文件夹 ...
- python异常(概念、捕获、传递、抛出)
异常 目标 异常的概念 捕获异常 异常的传递 抛出异常 01. 异常的概念 程序在运行时,如果 Python 解释器 遇到 到一个错误,会停止程序的执行,并且提示一些错误信息,这就是 异常 程序停止执 ...
- 单例、异常、eval函数
一.单例 01. 单例设计模式 设计模式 设计模式 是 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案 使用 设计模式 是为了可重用代码.让代码更容易被他 ...
- Python之IO编程——文件读写、StringIO/BytesIO、操作文件和目录、序列化
IO编程 IO在计算机中指Input/Output,也就是输入和输出.由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口.从 ...
- Effective Java 第三版——79. 避免过度同步
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
随机推荐
- GoldenGate—日常管理
Classic Replicat Mode (一)源端和目标端新增加复制表 根据需求将生产库中PROCESS_LOG表通过ogg同步到测试库中:操作步骤: 当GoldenGate仅打开DML复制时,源 ...
- JAVA数组的toString()方法不能直接输出数组内容?
问题描述:我定义了一个类,类名是Job,当我输出Job.toString()是可以按我重载的toString方法输出的,但是如果输出jobs[]这个数组时,只会输出[Lmodel.Job;@45e22 ...
- Vagrant 官网文档翻译汇总
入门 Vagrant 入门 - 项目设置 Vagrant 入门 - box Vagrant 入门 - 启动 vagrant 及 通过 ssh 登录虚拟机 Vagrant 入门 - 同步目录(synce ...
- python 爬虫之requests爬取页面图片的url,并将图片下载到本地
大家好我叫hardy 需求:爬取某个页面,并把该页面的图片下载到本地 思考: img标签一个有多少种类型的src值?四种:1.以http开头的网络链接.2.以“//”开头网络地址.3.以“/”开头绝对 ...
- 15.队列Queue的特点以及使用,优先级等
#生产者与消费者模式,模式解释:比如MVC设计模式 ''' 1.队列 (1)特点:先进先出 (2)python2 VS python3 python2:from Queue import queue ...
- package和import语句_5
J2SDK中主要的包介绍 java.lang—包含一些Java语言的核心类,如String.Math.Integer.System和 Thread,提供常用功能. java.awt—包含了构成抽象 ...
- java.lang.NumberFormatException: For input string: "title"异常
java.lang.NumberFormatException: For input string: "title" at java.lang.NumberFormatExcept ...
- [Linux] 003 分区
1. 磁盘分区 使用分区编辑器再磁盘上划分几个逻辑部分 不用类的目录与文件可以存储进不同的分区 2. 分区类型 主分区 最多只能有 4 个 扩展分区 最多只能有 1 个 主分区加扩展分区最多为 4 个 ...
- 转义BABEL的POLYFILL和RUNTIME的区别
babel-polyfill 使用场景 Babel 默认只转换新的 JavaScript 语法,而不转换新的 API.例如,Iterator.Generator.Set.Maps.Proxy.Refl ...
- dp(不连续和)
I - I HDU - 2845 Bean-eating is an interesting game, everyone owns an M*N matrix, which is fille ...