宋宝华linux内核驱动代码,宋宝华 《Linux设备驱动开发详解》示例代码之fifo字符设备驱动...
驱动代码如下:
scull.c
#include
#include
#include
#include
#include
#include
#include
#include
#defineSCULL_MAJOR252
#define SCULL_NAME"scull"
#define MAX_DATA0x10
staticint scull_major = SCULL_MAJOR;
struct scull_dev {
struct cdev cdev;
unsigned char data[MAX_DATA];
struct semaphore sem;
unsigned int current_len;
wait_queue_head_t r_wait;
wait_queue_head_t w_wait;
};
MODULE_LICENSE("GPL");
MODULE_AUTHOR("BG2BKK");
structscull_dev *scull_devp;
intscull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev;
printk(KERN_ALERT "open the scull device\n");
return 0;
}
intscull_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "close the scull device\n");
return 0;
}
ssize_tscull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)
{
struct scull_dev *dev = filp->private_data;
int ret = 0;
DECLARE_WAITQUEUE(wait, current);
down(&dev->sem);
add_wait_queue(&dev->r_wait, &wait);
while(dev->current_len == 0)
{
if(filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);
up(&dev->sem);
schedule();
if(signal_pending(current)){
ret = -ERESTARTSYS;
goto out2;
}
down(&dev->sem);
}
if(count > dev->current_len)
count = dev->current_len;
if(copy_to_user(buf, dev->data,count)){
ret = -EFAULT;
goto out;
} else {
memcpy(dev->data, dev->data + count, dev->current_len - count);
dev->current_len -= count;
printk(KERN_ALERT "read %u bytes; current_len:%d\n",count, dev->current_len);
wake_up_interruptible(&dev->w_wait);
ret = count;
}
out:
up(&dev->sem);
out2:
remove_wait_queue(&dev->w_wait, &wait);
set_current_state(TASK_RUNNING);
return ret;
}
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{
struct scull_dev *dev = filp->private_data;
int ret = 0;
DECLARE_WAITQUEUE(wait, current);
down(&dev->sem);
add_wait_queue(&dev->w_wait, &wait);
while(dev->current_len == MAX_DATA){
if(filp->f_flags & O_NONBLOCK){
ret = -EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);
up(&dev->sem);
schedule();
if(signal_pending(current)){
ret = -ERESTARTSYS;
goto out2;
}
down(&dev->sem);
}
if(count > MAX_DATA - dev->current_len){
count = MAX_DATA - dev->current_len;
}
if(copy_from_user(dev->data + dev->current_len, buf, count)){
ret = -EFAULT;
goto out;
}
else {
dev->current_len += count;
printk(KERN_ALERT "written %d bytes, current_len:%d\n",count, dev->current_len);
wake_up_interruptible(&dev->r_wait);
ret = count;
}
out:
up(&dev->sem);
out2:
remove_wait_queue(&dev->w_wait, &wait);
set_current_state(TASK_RUNNING);
return ret;
}
staticunsigned int scull_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
struct scull_dev *dev = filp->private_data;
down(&dev->sem);
poll_wait(filp, &dev->r_wait, wait);
poll_wait(filp, &dev->w_wait, wait);
if(dev->current_len != 0)
mask |= POLLIN | POLLRDNORM;
if(dev->current_len != MAX_DATA)
mask |= POLLOUT | POLLWRNORM;
up(&dev->sem);
return mask;
}
static const structfile_operations scull_fops = {
.owner=THIS_MODULE,
.open=scull_open,
.release=scull_release,
.write=scull_write,
.read=scull_read,
.poll=scull_poll,
};
staticvoidscull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if(err)
printk(KERN_NOTICE "ERROR %d adding scull_dev %d", err, index);
}
intscull_init(void)
{
int result;
dev_tdevno = MKDEV(scull_major,0);
if(scull_major)
result = register_chrdev_region(devno, 1, "scull");
else {
result = alloc_chrdev_region(&devno, 0, 1, "scull");
scull_major = MAJOR(devno);
}
if(result < 0)
return result;
scull_devp = kmalloc(sizeof(struct scull_dev), GFP_KERNEL);
if(!scull_devp){
result = -ENOMEM;
goto fail_malloc;
}
memset(scull_devp, 0 , sizeof(struct scull_dev));
scull_setup_cdev(scull_devp, 0);
init_MUTEX(&scull_devp->sem);
init_waitqueue_head(&scull_devp->r_wait);
init_waitqueue_head(&scull_devp->w_wait);
printk(KERN_ALERT "init scull device\n");
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
voidscull_cleanup(void)
{
cdev_del(&scull_devp->cdev);
kfree(scull_devp);
unregister_chrdev_region(MKDEV(scull_major, 0), 1);
printk(KERN_ALERT "clean scull device\n");
}
module_init(scull_init);
module_exit(scull_cleanup);测试代码
/*************************************************************************
*fileName: test.c
*description: test the myscull.c
*author: Hzc
*create time: 2007-04-20
*modify info: -
*************************************************************************/
#include
#include
#include
#include
#include
#include
#define BUFFER_LEN 20
#define FIFO_CLEAR 0x01
#define device"/dev/scull"
int main()
{
int num;
fd_set rfds, wfds;
int fd = open(device, O_RDONLY| O_NONBLOCK);
if(fd != 0){
while(1){
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(fd, &rfds);
FD_SET(fd, &wfds);
select(fd+1, &rfds, &wfds, NULL, NULL);
if(FD_ISSET(fd, &rfds))
printf("poll monitor: can be read\n");
if(FD_ISSET(fd, &wfds))
printf("poll monitor: can be written\n");
}
} else{
printf("Device " device "open failer");
}
}
Makefile
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD:= $(shell pwd)
obj-m := scull.o
default:
$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
test: test.c
gcc $< -o $@.o -g
clean:
rm -rf *.o *.ko *~ *.order *.symvers *.markers *.mod.c
测试脚本
1 load_scull.sh
#!/bin/sh
/sbin/insmod scull.ko
mknod /dev/scull c 252 0
2 unload_scull.sh
#!/bin/sh
/sbin/rmmod scull.ko
rm /dev/scull -f
3 test.sh
#!/bin/sh
make clean
make
make test
sudo ./unload_scull
sudo ./load_scull
sudo ./test.o
测试时,执行./test.o,终端一直输出poll monitor: can be write,
在另一终端,以根用户模式,echo hello > /dev/scull,可以看到输出poll monitor: can be read和poll monitor: can be write
多echo hello > /dev/scull几次后,由于scull设备缓冲区仅16B,不再能写入,此时只输出poll monitor: can be read
宋宝华linux内核驱动代码,宋宝华 《Linux设备驱动开发详解》示例代码之fifo字符设备驱动...相关推荐
- linux svn 增量备份脚本,svn全量和增量备份详解(示例代码)
1.svn的安装: yum安装: yum install -y subversion mkdir /data/svn svnadmin create project-1 svnadmin create ...
- python哪个代码是正确的字典_Python - 字典(dict) 详解 及 代码
字典(dict) 详解 及 代码 本文地址: http://blog.csdn.net/caroline_wendy/article/details/17291329 字典(dict)是表示映射的数据 ...
- 贪心算法思想详解+示例代码
CSDN话题挑战赛第2期 参赛话题:学习笔记 文章目录 五大算法思想 贪心算法 举例说明 选择排序 删除数字 寻找数字最大和 买股票 最大回文字符串 背包问题 小结 五大算法思想 分治思想 贪心算法/ ...
- Linux内核中kzalloc分配内存时用的参数GFP_KERNEL详解
简介 GFP(Get Free Pages缩写)在include/linux/gfp.h中定义. GFP_KERNEL 是内核内存分配时最常用的,无内存可用时可引起休眠. GFP_ATOMIC 用来从 ...
- linux ps 代码,Linux ps命令详解(示例代码)
ps命令是Process Status的缩写, 用来列出系统中当前运行的那些进程. ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信息,就可以使用to ...
- linux中代码挂上n,Linux系统常用命令nl详解(示例代码)
nl命令在linux系统中用来计算文件中行号.nl可以将输出的文件内容自动的加上行号!其默认的结果与cat -n有点不太一样,nl可以将行号做比较多的显示设计,包括位数与是否自动补齐0等等的功能.本文 ...
- linux文件属性644到755,linux:644、755、777权限详解(示例代码)
第一位7等于4+2+1,rwx,所有者具有读取.写入.执行权限: 第二位5等于4+1+0,r-x,同组用户具有读取.执行权限但没有写入权限: 第三位5,同上,也是r-x,其他用户具有读取.执行权限但没 ...
- linux less 编码,Linux less命令详解(示例代码)
less 在Linux下查看文件内容的命令大致有以下几种: cat 由第一行开始显示内容,并将所有内容输出 tac 从最后一行倒序显示内容,并将所有内容输出 more 根据窗口大小,一页一页的现实文件 ...
- linux中expr的用法,linux expr命令参数及用法详解(示例代码)
expr用法 expr命令一般用于整数值,但也可用于字符串.一般格式为: #expr argument operator argument expr也是一个手工命令行计数器. #$expr 10 + ...
- linux .. 权限详解,Linux用户及权限详解(示例代码)
加密方法: 对称加密:加密和解密使用同一个密码 公钥加密:每个密码都成对儿出现,一个为私钥(secret key),一个为公钥(public key) 单向加密,散列加密:提取数据特征码,常用于数据完 ...
最新文章
- Google也开始弄开源平台,好事啊
- [javaEE] 三层架构案例-用户模块(二)
- CH - 0601 Genius ACM(倍增+归并排序)
- 在 Excel 中如何使用宏示例删除列表中的重复项
- 【C语言重点难点】数据类型、常量和变量
- 关于在vSphere环境中,安装WindowsServer2008_R2_x64系统,分区格式为GPT,隐藏分区为200M方法心得
- 【学习笔记】OSG 基本几何图元
- STC单片机 命名规则,最小系统 图示
- 修改mysql的authen_MySQL连接抛出Authentication Failed错误的分析与解决思路
- MySQL数据库高级SQL语句【进阶查询、null值、数据库正则、数据库运算符、连接查询(内连接、左外连接、右外连接)】
- 成就更好的自己,就是不停地做减法
- python 求x的 n次方
- 阿迪达斯携手麦当劳推出篮球明星鞋服;拜耳联合导师计划支持中国医药初创企业 | 美通企业日报...
- 【Kotlin 初学者】为什么要学Kotlin
- Python有趣应用之Python帮你潜伏侦查网聊美女
- Wow魔兽世界服务器搭建详细教程,魔兽世界服务器配置要求
- 2021-06-26
- PS切图工具retinize it actions的用法
- 机器学习:有监督算法之分类
- 13.Struts2_动态方法调用(了解)