将以前实现的字符设备改进一点点,添加了ioctl,但没有seek功能,也没有自动创建设备文件功能。

/*************************************************************************
简单的字符型设备驱动
从应用层获取一数据,再复制到应用层(在前面添加字符串)。
注册设备号及设备号的几个宏,均系ldd3例子scull。2011-04-29
log
2013-11-09 late lee
固定2个64KB缓冲区,默认使用缓冲区1,提供ioctl选择缓冲区,填充缓冲区
每个缓冲区使用前缀作区别,并将前缀传递到应用程序
*************************************************************************/#include <linux/module.h>
#include <linux/kernel.h>       /**< printk() */
#include <linux/init.h>#include <linux/cdev.h>         /**< cdev_* */
#include <linux/fs.h>
#include <asm/uaccess.h>        /**< copy_*_user */#include <linux/types.h>        /**< size_t */
#include <linux/errno.h>        /**< error codes */
#include <linux/string.h>#define DEBUG#ifdef DEBUG
/* KERN_INFO */
#define debug(fmt, ...) printk(KERN_NOTICE fmt, ##__VA_ARGS__)
#else
#define debug(fmt, ...)
#endif#define DEV_NAME "foo"#define HAVE_MAJOR
#ifdef HAVE_MAJOR
#define DEVICE_MAJOR 248
#else
#define DEVICE_MAJOR 0
#endif#define FOO_NR_DEVS 1enum {CMD_BUFF1 = 0,CMD_BUFF2,CMD_CLEAR,CMD_SET,
};struct cdev foo_cdev;
int foo_major = DEVICE_MAJOR;
int foo_minor = 0;
int foo_nr_devs = FOO_NR_DEVS;
dev_t devno;// 保留数量
#define NUM_RES 0
#define NUM_PREFIX 9
#define g_size (1024*64 + NUM_RES)
#define g_real_size (1024*64  - NUM_RES)
// 设置2个缓冲区,可设置读取哪一个
char g_buffer1[g_size] = {0};
char g_buffer2[g_size] = {0};
char* g_ptr = NULL;
char* g_tmp = NULL;static int foo_open(struct inode *inode, struct file *filp)
{debug("in %s()\n", __func__);debug("%s() inode: %x\n", __func__, inode->i_rdev);/memset(g_buffer1, '\0', g_size);memset(g_buffer2, '\0', g_size);strcpy(g_buffer1, "buffer1: ");strcpy(g_buffer2, "buffer2: ");g_ptr = g_buffer1;  // 默认指向第一个缓冲区g_tmp = g_ptr + NUM_PREFIX;return 0;
}// close时调用此函数
static int foo_release(struct inode *inode, struct file *filp)
{debug("in %s()\n", __func__);return 0;
}static ssize_t foo_read(struct file *filp, char *buf, size_t count, loff_t *f_ops)
{int len;char *tmp;int ret = 0;if (count < 0)return -EINVAL;else if (count > g_real_size){printk(KERN_ERR "read count can't be bigger than %d\n", g_real_size);return -EINVAL;}tmp = (char *)kmalloc(sizeof(char) * (g_size+1), GFP_KERNEL);sprintf(tmp, "%s", g_ptr);len = strlen(tmp);if (len < count)count = len;if ( copy_to_user(buf, tmp, count) )return -EFAULT;*f_ops += count;ret = count;debug("f_pos: %d", filp->f_pos);    // 递增//debug("in %s() buffer: %s\n", __func__, g_buffer1);//debug("in %s() tmp: %s\n", __func__, tmp);//debug("in %s() buf: %s\n", __func__, buf);//debug("in %s() data: %s\n", __func__, g_ptr);kfree(tmp);return ret;
}static ssize_t foo_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops)
{int ret = 0;if (count < 0)return -EINVAL;else if (count > g_real_size){printk(KERN_ERR "write count can't be bigger than %d\n", g_real_size);return -EINVAL;}if (copy_from_user(g_tmp, buf, count+1))return -EFAULT;*(g_tmp+count) = '\0';*f_ops += count;ret = count;//debug("in %s() buffer: %s\n", __func__, g_buffer1);debug("in %s() buff: %s\n", __func__, buf);debug("in %s() data: %s\n", __func__, g_tmp);return ret;
}static int foo_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{char tmp = arg;switch (cmd){case CMD_BUFF1:g_ptr = g_buffer1;g_tmp = g_ptr + NUM_PREFIX;break;case CMD_BUFF2:g_ptr = g_buffer2;g_tmp = g_ptr + NUM_PREFIX;break;case CMD_CLEAR:memset(g_buffer1, '\0', g_size);memset(g_buffer2, '\0', g_size);break;case CMD_SET:memset(g_buffer1, tmp, g_size);memset(g_buffer2, tmp, g_size);break;default:return -EINVAL;}return 0;
}static struct file_operations foo_fops = {.owner   = THIS_MODULE,.open    = foo_open,.release = foo_release,.read    = foo_read,.write   = foo_write,.ioctl   = foo_ioctl,
};static int __init foo_init(void)
{int ret = -1;cdev_init(&foo_cdev, &foo_fops);foo_cdev.owner = THIS_MODULE;/* register to who? */if (foo_major){devno = MKDEV(foo_major, foo_minor);ret = register_chrdev_region(devno, foo_nr_devs, DEV_NAME);}else{ret = alloc_chrdev_region(&devno, foo_minor, foo_nr_devs, DEV_NAME); /* get devno */foo_major = MAJOR(devno); /* get major */}if (ret < 0){debug(" %s can't get major %d\n", DEV_NAME, foo_major);return -EINVAL;}ret = cdev_add(&foo_cdev, devno, 1);if (ret < 0){debug(" %s cdev_add failure!\n", DEV_NAME);return -EINVAL;}debug("%s init ok! devno: %x\n", DEV_NAME, devno);return 0;
}static void __exit foo_exit(void)
{unregister_chrdev_region(devno, 1);cdev_del(&foo_cdev);debug("%s exit ok!\n", DEV_NAME);
}module_init(foo_init);
module_exit(foo_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Chiangchin Li");

用户层测试代码:

/*************************************************************这里的设备名称须与/dev一致,与/proc/device可以不一致
设备号可在驱动中指定,也可以在/proc/device中查看
*************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>enum {CMD_BUFF1 = 0,CMD_BUFF2,CMD_CLEAR,CMD_SET,
};#define device "/dev/foo"int main(void)
{int fd;char buf[] = "THis is the voice from www.latelee.org";char buf2[128]={0};char buf3[128] = {0};int len;fd = open(device, O_RDWR);if (fd < 0){perror("Open device faile!");return -1;}len = write(fd, buf, sizeof(buf));printf("buf: %s %d\n", buf, len);len = read(fd, buf2, 32); // 由此指定读取数据,可大可小,但是驱动只读取这个指定的(大者读实际值),并返回printf("buf2: %s %d\n", buf2, len);// 使用buffer2ioctl(fd, CMD_BUFF2, NULL);len = write(fd, "fxxk the world!", sizeof("fxxk the world!"));len = read(fd, buf3, 32);printf("buf2: %s %d\n", buf3, len);// 填充//ioctl(fd, CMD_SET, 'c');//len = read(fd, buf2, 32);//printf("buf2: %s %d\n", buf2, len);close(fd);return 0;
}

我的内核学习笔记1:字符设备完善相关推荐

  1. Windows x64内核学习笔记(五)—— KPTI(未完待续)

    Windows x64内核学习笔记(五)-- KPTI(未完待续) KPTI 实验一:构造IDT后门并读取Cr3 参考资料 KPTI 描述:KPTI(Kernel page-table isolati ...

  2. Windows x64内核学习笔记(四)—— 9-9-9-9-12分页

    Windows x64内核学习笔记(四)-- 9-9-9-9-12分页 前言 9-9-9-9-12分页 实验一:线性地址转物理地址 页表基址 定位基址 PTE to PXE 实验二:通过页表基址定位各 ...

  3. 《寒江独钓》内核学习笔记

    <寒江独钓>内核学习笔记(1)-- IRP - .Little Hann 时间 2013-11-30 15:40:00  博客园_.Little Hann原文  http://www.cn ...

  4. Windows x64内核学习笔记(三)—— SMEP SMAP

    Windows x64内核学习笔记(三)-- SMEP & SMAP SMEP & SMAP 实验:构造IDT后门 第一步:编译以下代码 第二步:构造IDT后门 第三步:运行程序 第四 ...

  5. Windows x64内核学习笔记(一)—— 环境与配置

    Windows x64内核学习笔记(一)-- 环境与配置 前言 新特性 基础要求 实验环境 Guest Win10配置 问题解决 参考资料 前言 之前,跟着海哥学习了windows内核的一些机制,包括 ...

  6. 操作系统进程学习(Linux 内核学习笔记)

    操作系统进程学习(Linux 内核学习笔记) 进程优先级 并非所有进程都具有相同的重要性.除了大多数我们所熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求.首先进程比较粗糙的划分,进程可 ...

  7. 我的内核学习笔记5:proc目录文件创建及读写

    上一篇内核学习笔记<我的内核学习笔记4:sysfs学习>是2013年写的,彼时至今,随着工作的展开和安排,内核方面的知识可谓突飞猛进,当然,其它方面亦是如此.关于内核方面,积累的笔记大大小 ...

  8. 正则表达式学习笔记005--脱字符和美元符的认识与应用

    正则表达式学习笔记005--脱字符和美元符的认识与应用 以前写的课程都没有附上源码,很抱歉! 交流群1:251572072 交流群2:170933152 也可以自己下载: 正则表达式学习笔记005-- ...

  9. 正则表达式学习笔记004--连字符和范围描述符的认识与应用

    正则表达式学习笔记004--连字符和范围描述符的认识与应用 以前写的课程都没有附上源码,很抱歉! 交流群1:251572072 交流群2:170933152 也可以自己下载: 正则表达式学习笔记004 ...

  10. v67.03 鸿蒙内核源码分析(字符设备) | 绝大多数设备都是这类 | 百篇博客分析OpenHarmony源码

    曾子曰:"君子以文会友,以友辅仁." <论语>:颜渊篇 百篇博客系列篇.本篇为: v67.xx 鸿蒙内核源码分析(字符设备篇) | 绝大多数设备都是这类 文件系统相关篇 ...

最新文章

  1. 【UIKit】UILabel使用
  2. java HashMap的实现原理
  3. Java8 Date API 详解 - LocalDate,LocalDateTime,Instant
  4. private关键字
  5. 我:一个女孩从软件测试工程师到主管的成长
  6. JavaScript 常用数组函数方法专题
  7. Linux文件系统的创建与管理(上)
  8. 大数据最佳实践-spark
  9. html表格里面嵌入按钮,bootstarp-table表格中嵌套多个BUTON按钮实现
  10. BestCoder Round #16
  11. 《开端》里的循环,人工智能每天都在进行
  12. 【WIFI专题】Wifi 2.4G及5G频段各信道的中心频率及主要国家的分布情况
  13. Android 判断当前设备是手机还是平板
  14. Windows系统设置多账户步骤
  15. 成绩不好的穷孩子,该做出选择了
  16. Mini-CEX在神经内科住院医师临床能力培养中的应用
  17. 解密微信小程序加密的微信运动数据(java)
  18. 西安公交车路线汇总(2)
  19. 多个等式束的拉格朗日乘子问题(详细证明)
  20. 索引、单列索引、复合索引、主键、唯一索引、聚簇索引、非聚簇索引、唯一聚簇索引 的区别与联系

热门文章

  1. python入门之函数调用第二关_Python入门之函数调用——第2关:函数正确调用 - 得到想要的结果...
  2. 光标是停在文本框文字的最后
  3. 爱奇艺CEO龚宇呼吁网络电影涨价:6块钱太低了
  4. 酷派COOL 20 Pro影像大升级:搭载5000万AI三摄 主攻夜景
  5. 博通2021财年第三季度营收67.8亿美元,半导体业务营收50亿美元
  6. 三家快递公司涨派费:9月1日起每票上调0.1元
  7. 又一家公司被吃到上市了,每天卖出490吨辣条
  8. iPhone 12s Pro渲染图曝光:屏幕和相机将成升级重点
  9. “东哥”之后,京东再申请“强东”商标
  10. 华为HarmonyOS 2.0 手机开发者Beta版发布