首页 > 其他分享 >2023.7.17 字符设备驱动

2023.7.17 字符设备驱动

时间:2023-07-17 23:00:12浏览次数:29  
标签:字符 struct 17 int unsigned dev 2023.7 file device

Linux Device Driver Development - Everything You Need To Start With Device Driver Development For Linux Kernel  已经读到141页

4 Writing Character Device Drivers

linux一切文件的思想,每一个在系统注册了的设备都有一个对应的文件在 /dev 里,把硬件暴露在用户空间,对这个文件的操作会重定位到文件代表的设备的驱动

ll /dev

c开头的就是字符设备,character devices are slow and transfer data to or from user applications sequentially byte by byte;   include serial ports and input devices (keyboards, mouses, touchpads, video devices, and so on).

b开头的是块设备, block devices are fast, since they are accessed quite frequently and transfer data in blocks. Such devices are essentially storage devices (hard drives, CD-ROMs, solid-state drives, and so on). 

 The major number either identifies the type of device or can be bound to a driver. The minor number either identifies a device locally to the driver or devices of the same type;第五列和第六列的数字,前一个是设备种类编号称主号major,比如179代表disk,后一个是特定设备类型的设备编号 叫 minor

Character device data structure introduction

include   /linux/cdev.h

struct cdev {

  struct kobject kobj;

  struct module *owner;

  const struct file_operations *ops;

  dev_t dev;

  [...]

};

kobj: This is the underlying kernel object for this character device object, used to enforce the Linux device model. We will discuss this in Chapter 14, Introduction to the Linux Device Model. 

owner: This should be set with the THIS_MODULE macro.

ops: This is the set of file operations associated with this character device. 该字符设备支持的文件操作

dev: This is the character device identifier.

An introduction to device file operations

struct file_operations {

  struct module *owner;

  loff_t (*llseek) (struct file *, loff_t, int);

  ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

  ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

  unsigned int (*poll) (struct file *, struct poll_table_struct *);

  int (*mmap) (struct file *, struct vm_area_struct *);

  int (*open) (struct inode *, struct file *);

  int (*flush) (struct file *, fl_owner_t id);

  long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

   int (*release) (struct inode *, struct file *);

  int (*fsync) (struct file *, loff_t, loff_t, int datasync);

  int (*flock) (struct file *, int, struct file_lock *);

  [...]

};            #  /linux/ fs.h ;

• struct module *owner: This is a mandatory field that should point to the module owning this structure. It is used for proper reference counting. Most of the time, it is set to THIS_MODULE, a macro defined in .

• loff_t (*llseek) (struct file *, loff_t, int);: This method is used to move the current cursor position in the file given as the first parameter. On a successful move, the function must return the new position, or else a negative value must be returned. If this method is not implemented, then every seek performed on this file will succeed by modifying the position counter in the file structure (file->f_pos), except the seek relative to end-of-file, which will fail.

• ssize_t (*read) (struct file *, char *, size_t, loff_t *);: The role of this function is to retrieve data from the device. Since the return value is a "signed size" type, this function must return either the number (positive) of bytes successfully read, or else return an appropriate negative code on error. If this function is not implemented, then any read() system call on the device file will fail, returning with -EINVAL (an "invalid argument"). 

• ssize_t (*write) (struct file *, const char *, size_t, loff_t *);: The role of this function is to send data to the device. Like the read() function, it must return a positive number, which, in this case, represents the number of bytes that have been written successfully, or else return an appropriately negative code on error. In the same way, if it is not implemented in the driver, then the write() system call attempt will fail with -EINVAL.

• int (*flush) (struct file *, fl_owner_t id);: This operation is invoked when the file structure is being released. Like open, release can be NULL.

• unsigned int (*poll) (struct file *, struct poll_table_ struct *);: This file operation must return a bitmask describing the status of the device. It is the kernel backend for both poll() and select() system calls, both used to query whether the device is writable, readable, or in some special state. Any caller of this method will block until the device enters the requested state. If this file operation is not implemented, then the device is always assumed to be readable, writable, and in no special state.

• int (*mmap) (struct file *, struct vm_area_struct *);: This is used to request part or all of the device memory to be mapped to a process address space. If this file operation is not implemented, then any attempt to invoke the mmap() system call on the device file will fail, returning -ENODEV.

• int (*open) (struct inode *, struct file *); This file operation is the backend of the open() system call, which, if not implemented (if NULL), will result in the success of any attempt to open the device and the driver won't be notified of the operation.

• int (*release) (struct inode *, struct file *);: This is invoked when the file is being released, in response to the close() system call. Like open, release is not mandatory and can be NULL.

• int (*fsync) (struct file *, loff_t, loff_t, int datasync);: This operation is the backend of the fsync() system call, whose purpose is to flush any pending data. If it is not implemented, any call to fsync() on the device file will fail, returning -EINVAL.

• long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);: This is the backend of the ioctl system call, whose purpose is to extend the commands that can be sent to the device (such as formatting a track of a floppy disk, which is neither reading nor writing). The commands defined by this function will extend a set of predefined commands that are already recognized by the kernel without referring to this file operation. Thus, for any command that is not defined (either because this function is not implemented or because it does not support the specified command), the system call will return -ENOTTY, to say "No such ioctl for device". Any non-negative value returned by this function is passed back to the calling program to indicate successful completion.

File representation in the kernel

 inode refers to a file on the disk  #struct inode * 指向disk中的文件

  struct file structure associated with a file descriptor within a process    #struct file * 指向进程中打开的文件描述符

 

Creating a device node  

Device identification                      

 include/linux/kdev_t.h

 a 32-bit unsigned integer in which the major is represented by the first 12 bits, and the minor is coded on the 20 remaining bits.

#define MINORBITS 20

#define MINORMASK ((1U << MINORBITS) - 1)

#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))

#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))

#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))      #accepts a minor and a major number and returns a dev_t type identifier, 

 

Registration and deregistration of character device numbers

int register_chrdev_region(dev_t first, unsigned int count, char *name);    #知道主号major ,静态注册

This method returns 0 on success, or a negative error code when it fails. The first parameter is the identifier you must have built using the major number and the first minor of the desired range. You can use the MKDEV(maj, min) macro to achieve that. count is the number of consecutive device minors required, and name should be the name of the associated device or driver

int alloc_chrdev_region( dev_t *dev, unsigned int firstminor, unsigned int count, char *name);  #由系统分配 major ,跟 firstminor 生成 dev。推荐使用

This method returns 0 on success, or a negative error code on failure. dev is the only output parameter. It represents the first number (built using the allocated major and the first minor requested) that the kernel assigned. firstminor is the first of the requested range of minor numbers, count is the number of consecutive minors you need, and name should be the name of the associated device or driver.

 

Initializing and registering a character device on the system

initialize the character device and add it to the system using cdev_init() and cdev_add(), respectively:

void cdev_init(struct cdev *cdev, const struct file_operations *fops);    #初始化字符设备

int cdev_add (struct cdev * p, dev_t dev, unsigned count);    #把字符设备加入系统中

In cdev_init(), cdev is the structure to initialize, and fops the file_operations instance for this device, making it ready to add to the system. In cdev_add(), p is the cdev structure for the device, dev is the first device number for which this device is responsible (obtained dynamically), and count is the number of consecutive minor numbers corresponding to this device. When it succeeds, cdev_add() returns 0, or else it returns a negative error code.

删除字符设备:

void cdev_del(struct cdev *);

cdev add之后 /dev 并不会出现 使用下面的device_create创建 node:

struct device * device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)

 class 创建后将出现在  /sys/class ;

 

 Implementing file operations 实现文件操作

unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)

unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)

 __user point to the user space (untrusted) memory;Each of these returns the number of bytes that could not be copied, if any, while they return 0 on success. Note that these routines may sleep as they run in a user context and do not need to be invoked in an atomic context. 

 

Implementing the open file operation

int (*open) (struct inode *inode, struct file *filp);

 

Per-device data

 

Implementing the release file operation

free所有 open 里面占用的资源

 

Implementing the write file operation

 ssize_t(*write)(struct file *filp, const char __user *buf, size_t count, loff_t *pos);

 

 

 

Implementing the read file operation

ssize_t (*read) (struct file *filp, char __user *buf, size_t count, loff_t *pos);

 

 

Implementing the llseek file operation

loff_t(*llseek) (struct file *filp, loff_t offset, int whence);

 

 The poll method

unsigned int (*poll) (struct file *, struct poll_table_struct *);

The kernel function at the heart of this method implementation is poll_wait(), defined in <linux/poll.h> , which is the header you must include in the driver code. It has the following declaration:

void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)

 

The ioctl method

long ioctl(struct file *f, unsigned int cmd, unsigned long arg);

_IO(MAGIC, SEQ_NO)

_IOR(MAGIC, SEQ_NO, TYPE)

_IOW(MAGIC, SEQ_NO, TYPE)

_IORW(MAGIC, SEQ_NO, TYPE)

This is well documented in Documentation/ioctl/ioctl-decoding.txt in the kernel sources, and existing IOCTL commands are listed in Documentation/ioctl/ ioctl-number.txt, a good place to start when you need to create your own IOCTL commands.

 

Generating an IOCTL number (a command)

 

标签:字符,struct,17,int,unsigned,dev,2023.7,file,device
From: https://www.cnblogs.com/yangdinshan/p/17561539.html

相关文章

  • 7月17号周一
    今天早上五点半起床去附近公园跑了半个小时步,然后洗完澡后中午和几个初中同学一起见面聚了个餐,下午和他们一起看了茶啊二中大电影,在六点左右回到家后,我完成了pta固定题目集的51到54题,并观看了黑马程序员的一节Java课程。......
  • 7.17日
    今个八点出头就起了,简单收拾一下,洗漱过后先去了狮子林游玩,里面的石林像迷宫一样弯弯绕绕,后面的园林则是建立在池塘之上,池中还有三处荷花,但是只开了两朵。园林不是很大,惊喜却是密密麻麻。狮子林逛完回到酒店收起晾干的衣服,退房,开始往西园寺赶。西园寺,全名为西园戒律寺,里面有很多流......
  • 2023.7.17打卡
    2023.7.17(1)、今天没学车,教练带学员考试去了,今天学了Java,看了《大道至简》,记了单词,晚上打了会球,好久没打球了,强度跟不上。(2)、明天要学车,学Java,看《大道至简》,记单词。(3)、今天没遇到什么问题。......
  • Python中哈哈哈字符串的简单使用
    1defget_string(string,key):2chars=['。',',','.',',','\\n']3print("oldstr:"+string)4match=re.search(key,string)5ifmatch:6start=match.star......
  • 题解 CF417D
    \(m\le20\),状压DP。首先可以根据每个人的\(k\)从小到大排序。定义\(f_{i,j}\)表示考虑到第\(i\)个人,完成了\(j\)状态的题目,不考虑显示器所需的最小价格。转移显然为\(f_{i,j|s_i}=\min(f_{i-1,j}+x_i)\)。最终答案为\(ans=\min\limits_{i=1}^{n}f_{i,S}+b\cdotk_......
  • 7.17
        一、  一个正整数 N 的因子中可能存在若干连续的数字。例如630可以分解为3×5×6×7,其中5、6、7就是3个连续的数字。给定任一正整数 N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。思路:1、首先我们要输入n值;2、然后确定这道题我们要......
  • 2023.7.17小结
    前排碎碎念今天是去if楼的第二天,昨晚开了好久好久的会,小狮子要来湘潭找我了,有些开心。但是好好学习比较重要捏,那就让他先独守空房一阵子叭,诶嘿今天我值日,虽然我早上起不来但是可以晚上晚点走,主打一个新加坡作息。浅浅看一下今天的任务清单好咯。任务清单高精度快速幂并查集......
  • 暑假周记(7.17)
    周一三年级的小孩一如既往的听话,四年级的小孩一如既往的让我心烦下午给小孩上完课,去剪头发,然后就被另一个补课的老师(大姨)请吃饭,这个大姨的闺女是北大学语文的,见到真人根本没有想象中的北大高材生的样子,不问学历,你就会以为她是个普通的大学生。......
  • 7月17日 附文
    1.我们将会在明天发布最近一系列博客《海岛韵律闽南奇遇》的标志2.展示之前没有发布的诗:某中不放假日光满地撒,人往地上趴。鸭子叫嘎嘎,学生哭哇哇。热气把人压,就是不放假。校长被人骂,热线忙着打。不怕救护拉,惟恐成绩差。学生把汗擦,主任笑哈哈。宿舍快要塌,这钱不能花。空......
  • 7月17日
    7月17日今天我家里有人去世,我妈要去老家一趟,我要在家里看孩子,上午准备了准备东西,给我弟弄的作业,然后打了会儿游戏,等中午把午饭搞定之后就开始歇了会儿,然后看了看科目一的题,然后就开始看了看黑马程序员的视频,下午睡了一觉,醒了之后就给我弟把作业检查完,晚上吃完晚饭就开始写今天的......