Linux 设备驱动程序(四)

这篇具有很好参考价值的文章主要介绍了Linux 设备驱动程序(四)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux 设备驱动程序(四),Linux内核,linux,驱动开发,运维

系列文章目录


Linux 内核设计与实现
深入理解 Linux 内核
Linux 设备驱动程序(一)
Linux 设备驱动程序(二)
Linux 设备驱动程序(三)
Linux 设备驱动程序(四)
Linux设备驱动开发详解
深入理解Linux虚拟内存管理



第十六章、块设备驱动程序

1、快速参考

#include <linux/fs.h>
int register_blkdev(unsigned iat major, const char *name);
int unregister_blkdev(unsigned int major, const char *name);
// register_blkdev 用来向内核注册一个块设备驱动程序,还可获得主设备号。一个驱
// 动程序可以使用 unregister_blkdev 函数注销。
struct block_device_operations
// 用来保存块设备驱动程序大多数方法的数据结构。

#include <linux/genhd.h>
struct gendisk;
// 用来描述内核中单个块设备的结构。
struct gendisk *alloc_disk(int minors);
void add_disk(struct gendisk *gd);
// 用来分配 gendisk 结构并将其返回给系统的函数。
void set_capacity(struct gendisk *gd, sector_t sectors);
// 在 gendisk 结构中保存设备容量(用 512 字节扇区为单位)。
void add_disk(struct gendisk *gd);
// 向内核添加一个磁盘。一且调用了该函数,内核就能调用磁盘方法了。
int check_disk_change(struct block_device *bdev);
// 用来对指定磁盘驱动器进行介质变化检查的内核函数,当介质改变被侦测到后,采
// 取必要的清除动作。

#include <linux/blkdev.h>
request_queue_t blk_init_queue(request_fn_proc *request, spinlock_t *lock);
void blk_cleanup_queue(request_queue_t *):
// 用来创建和删除块设备请求队列的函数。
struct request *elv_next_request(request_queue_t *queue);
void end_request(struct request *req, int success);
// elv_next_request获得请求队列中的下一个请求;end_request用在简单的驱动程序
// 中,以完成(或部分完成)一个请求。
void blkdev_dequeue_request(struct request *req);
void elv_requeue_request (request_queue_t *queue, struct request *req);
// 从队列中删除一个请求的函数、如果需要,还可以把该请求放回队列。
void blk_stop_queue(request_queue_t *queue);
void blk_start_queue(request_queue_t *queve);
// 如果不想让自己的请求函数被调用、blk_stop_queue 可以做到这点。为了能使请求
// 函数被调用,必须调用 blk_start_queue 的函数。
void blk_queue_bounce_limit(request_queue_t *queue, u64 dma_addr);
void blk_queue_max_sectors(request_queue_t *queue, unsigned short max);
void blk_queue_max_phys_segment.s (request_queue_t *queue, unsigned short max);
void blk_queue_max_hw_segments(request_queue_t *queue, unsigned short max);
void blk_queue_max_segment_size(request_queue_t *queue, unsigmed int max);
blk_queue_segment_boundary(request_queue_t *queue, unsigned long mask);
void blk_queue_dma_alignment(request_queue_t *queue, int mask);
void blk_queue_hardsect_size(request_queue_t *queue, unsigned short max);
// 用来设置队列参数的函数。这些参数控制了对一个特定设备请求的创建。参数的具
// 体解释在"队列控制函数"一节。

#include <linux/bio.h>
struct bio;
// 表示部分块设备 I/O 请求的底层结构。
bio_sectors(struct bio *bio);
bio_data_dir(struct bio *bio);
// 这两个宏用来获得 bio 结构描述的大小和传输方向。
bio_for_each_segment (bvec, bio, segno);
// 用来遍历组成 bio 结构的段的伪控制结构。
char *__bio_kmap_atomic(struct bio *bio, int i, enum km_type type);
void __bio_kurmap_atomic(char *buffer, enum km_type type);
// __bio_kmap_atomic用来为bio结构中指定的段创建内核虚拟地址。取消该映射必
// 须使用 __bio_kunmap_atomic。
struct page *bio_page(struct bio *bio);
int bio_offset(struct bio *bio);
int bio_cur_sectors(struct bio *bio);
char *bio_data(struct bio *bio);
char *bio_kmap_irq(struct bio *bio, unsigned long *flags);
void bio_kunmap_irq(char *buffer, unsigned long *flags);
// 这是一组访问宏,用来访问 bio 结构中的"当前"段。
void blk_queue_ordered(request_queue_t *queue, int flag);
int blk_barrier_rq(struct request *req);
// 如果驱动程序实现了屏障请求,则调用 blk_queue_ordered。如果当前请求是一个。
// 屏障请求,则宏 blk_barrier_rq 返回非零值。
int blk_noretry_request(struct request *req);
// 该宏返回非零值表示指定的请求因错误不能再次被执行。
int end_that_request_first(struct request *req, int success, int count);
void end_that_request_last(struct request *req);
// 使用 end_that_request_first 表示完成一个块设备 I/O 请求的过程。如果该函数返回
// 0,则表示请求已经完成,应该被传递给 end_that_request_last。
rq_for_each_bio(bio, request)
// 另外一个以宏的形式实现的控制结构,它将遍历请求中的每个 bio 结构。
int blk_rq_map_sq(request_queue_t *queue, struct request *req, struct
scatterlist *list);
// 为DMA传输,需要将缓冲区映射到指定的 request 中,使用这些信息填充分散表。
typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);
// make_request 函数的原型。
void bio_endio(struct bio *bio, unsigned int bytes, int error);
// 指定的 bio 结构的信号完成函数。只有当驱动程序通过 make_request 函数直接从
// 块设备层获得 bio 结构时,才使用该函数。
request_queue_t *blk_alloc_queue(int flags);
void blk_queue_make_request (request_queue_t *queue, make_request_fn *func);
// 使用 blk_alloc_queue 来分配一个请求队列,以便为用户定义的 make_request 函数
// 所使用。该函数要用 blk_queue_make_request 设置。
typedef int (prep_rq_fn) (request_queue_t *queue, struct request *req);
void blk_queue_prep_rq(request_queue_t *queue, prep_rq_fn *func);
// 命令预处理函数的原型和设置,它可以在请求传递到请求处理函数前,为硬件准备
// 需要的命令。
int blk_queue_init_tags(request_queue_t *queue, int depth, struct
blk_queue_tag *tags);
int blk_queue_resize_tags(request_queue_t *queue, int new_depth);
int blk_queue_start_tag(request_queue_t *queue, struct request *req);
void blk_queue_end_tag(request_queue_t *queue, struct request *req);
struct request *blk_queue_find_tag(request_queue_t *qeue, int tag);
void blk_queue_invalidate_tags(request_queue_t *queue);
// 为了让驱动程序使用标记命令队列而提供的支持函数。

第十七章、块设备驱动程序

1、快速参考

#include <linux/netdevice.h>
// 这个头文件保存有net_device和net_device_stats结构的定义,并包含了
// 网络驱动程序需要的其他几个头文件。
struct net_device *alloc_netdev(int sizeof_priv, char *name, void
(*setup)(struct net_device *);
struct net_device *alloc_etherdev(int sizeof_priv);
void free_netdev(struct net_device *dev);
// 分配和释放 net_device结构的函数。
int register_netdev(struct net_device *dev);
void unregister_netdev(struct net_device *dev);
// 注册和注销一个网络设备。
void *netdev_priv(struct net_device *dev);
// 获得指向网络设备结构中驱动程序私有数据区指针的函数。
struct net_device_stats;
// 保存设备统计信息的结构。
netif_start_queue(struct net_device *dev);
netif_stop_queue(struct net_device *dev);
netif_wake_queue(struct net_device *dev);
// 上述函数控制外发数据包向驱动程序的传递。在调用 netif_start_queue 之前,不会
// 传输任何数据包。netif_stop_queue 暂停传输,而 netif_wake_queue 重新启动队列
// 并通知网络层重新启动数据包的传输。
skb_shinfo(struct sk_buff *skb);
// 提供对数据包缓存区中"共享信息"访问的宏。
void netif_rx(struct sk_buff *skb);
// 调用(包括中断期间)这个函数可通知内核已经接收到一个数据包,并封装入一个
// 套接字缓冲区。
void netif_rx_schedule(dev);
// 调用该函数通知内核数据包已经存在,并且在接口上启动轮询机制;它只在NAPI
// 驱动程序中使用。
int netif_receive_skb(struct sk_buff *skb);
void netif_rx_complete(struct net_device *dev);
// 这两个函数只在NAPI驱动程序中使用。NAPI中的netif_receive_skb函数与netif_rx
// 等价;它将数据包发送给内核。当NAPI驱动程序耗尽了为接收数据包准备的内存,
// 则它将重新启动中断,然后调用 netif_rx_complete 终止轮询函数。

#include <linux/if.h>
// netdevice.h 中包含该头文件。在该文件中声明了接口标志(IFF_macros)和ifmap
// 结构、在网络驱动程序的 ioctl 实现中、其扮演了重要角色。
void netif_carrier_off(struct net_device *dev);
void netif_carrier_on(struct net_device *dev);
int netif_carrier_ok(struct net_device *dev);
// 前两个函数告诉内核在指定接口上是否存在载波信号。netif_carrier_ok检查载波状
// 态作为在 device 结构中的应答。

#include <linux/if_ether.h>
ETH_ALEN
ETH_P_IP
struct ethhdr;
// netdevice.h 中包含该头文件。if_ether.h 中定义了所有的 ETH_ 宏,用来表示 octet
// 的长度(比如地址长度)和网络协议(比如 IP)。它还定义了 ethhdr 结构。

#include <linux/skbuff.h>
// 定义了sk_buff 及其相关结构,同时定义了许多作用于缓冲区的内联函数。该头
// 文件包含在 netdevice.h 中。
struct sk_buff *alloc_skb(unsigned int ler, int priority);
struct sk_buff *dev_alloc_skb(unsigned int len);
void kfree_skb(struct sk_buff *skb);
void dev_kfree_skb(struct sk_buff *skb);
void dev_kfree_skb_irq(struct sk_buff *skb);
void dev_kfree_skb_any(struct sk_buff *skb);
// 分配和释放套接字缓冲区的函数。因此驱动程序通常使用具有 dev_ 前级的变种。
unsigned char *skb_put(struct sk_buff *skb, int len);
unsigned char *__skb_put(struct sk_buff *skb, int len);
unsigned char *skb_push(struct sk_buff *skb, int 1en);
_unsigned char *__skb_push(struct sk_buff *skb, int len);
// 将数据添加到 skb 的函数;skb_put 将数据放在 skb 的末尾,而 skb_push 将数据放
// 在开头。常用的版本还负责检查是否有足够的空间存放数据;而有双下划线前级的
// 版本不进行该项检查。
int skb_headroom(struct sk_buff *skb);
int skb_tailroom(struct sk_buff *skb);
void skb_reserve(struct sk_buff *skb, int len);
// 在 skb 中实现空间管理的函数。skb_headroom和 skb_tailroom分别返回在 skb 的
// 开头和结尾,还有多少空间可用。skb_reserve 用于在 skb 开头部分保留空间,保
// 留的空间必须为空。
unsigned char *skb_pull(struct sk_buff *skb, int len);
// skb_pull 通过调整内部指针而"删除"skb 内的数据。
int skb_is_nonlinear(struct sk_buff *skb);
// 如果使用分散 / 聚集 I/O, 并且skb 分离成多个数据片段,则该函数返回真实值。
int skb_headlen(struct sk_buff *skb);
// 返回 skb 中 skb->data 的第一个段的长度。
void *kmap_skb_frag(skb_frag_t *frag);
void kunmap_skb_frag(void *vaddr);
// 提供对非线性skb 中的数据片段的直接访问。

#include <linux/etherdevice.h>
void ether_setup(struct net_device *dev);
// 为以太网驱动程序设置大部分通用设备方法的函数。它还设置了 dev->flags。如
// 果设备名称的第一个字符为空,或者是空格的话,这个函数将把下一个可用的ethx
// 名称赋给 dev->name。
unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev);
// 当以太网接口接收到一个数据包时,调用该函数设置skb->pkt_type。返回值是
// 保存在 skb->protocol 中的协议号。

#include <linux/sockios.h>
SIOCDEVPRIVATE
// 16 个ioctl 命令中的第一个,每个驱动程序都能够出于自身的考虑实现它。在
// sockios.h 中定义了所有的网络 ioctl 命令。

#include <linux/mii.h>
struct mii_if_info;
// 支持实现 MII 标准的设备驱动程序的声明和结构。
#include <linux/ethtool.h>
struct ethtool_ops;
// 让设备可使用 ethtool 工具的声明和结构。

第十八章、TTY驱动程序

1、快速参考

#include <linux/tty_driver.h>
// 包含 tty_driver 结构定义,以及在该结构中一些不同标志位的声明。

#include <linux/tty.h>
// 该头文件包含了tty_struct结构的定义以及许多不同的宏定义,使得对termios
// 结构各成员值的访问更简单。它还包含了 tty 驱动程序核心的函数声明。

#include <linux/tty_flip.h>
// 包含了一些 tty 交替缓冲区 inline 函数的 头文件,这些 inline 通数能简化对交替缓
// 冲区结构的操作。

#include <asm/termios.h>
// 特定硬件平台创建内核时,使用的是包含 termio 结构定义的头文件。
struct tty_driver *alloc_tty_driver(int 1ines);
// 创建 tty_driver 结构的函数,该结构以后将被传递给 tty_register_driver 和
// tty_unregister_driver 函数。
void put_tty_driver(struct tty_driver *driver);
// 如果使用tty_driver结构向tty核心的注册没有成功,该函数负责清空 tty_driver
// 结构。
void tty_set_operations(struct tty_driver *driver, struct tty_operations *op);
// 负责初始化结构 tty_driver 中的回调函数的函数。在调用 tty_register_driver 前
// 必须调用它。
int tty_register_driver(struct tty_driver *driver);
int tty_unregister_driver(struct tty_driver *driver);
// 从 tty 核心注册和注销一个 tty 驱动程序的函数。
void tty_register_device(struct tty_driver *driver, unsigned minor, struct
device *device);
void tty_unregister_device(struct tty_driver *driver, unsigned minor);
// 向 tty 核心注册和注销一个 tty 设备的函数。
void tty_insert_flip_char(struct tty_struct *tty, unsigned char ch,
char flag);
// 将字符插入到 ty 设备的交替缓冲区使用户能够读到的函数。
TTY_NORMAL
TTY_BREAK
TTY_FRAME
TTY_PARITY
TTY_OVERRUN
// 在 tty_insert_flip_char 函数中使用的不同的标志位。
int tty_get_baud_rate(struct tty_struct *tty);
// 获得指定 tty 设备当前波特率的函数。
void tty_flip_buffer_push(struct tty_struct *tty);
// 把数据放入当前交替缓冲区并传递给用户的函数。
tty_std_termios
// 用常见的默认线路设置初始化 termios 结构的变量。

符号

   
⇐ ⇒ ⇔ ⇆ ⇒ ⟺
①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿
⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑿⒀⒁⒂⒃⒄⒅⒆⒇
➊➋➌➍➎➏➐➑➒➓⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴
⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵
ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ
ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ
🅐🅑🅒🅓🅔🅕🅖🅗🅘🅙🅚🅛🅜🅝🅞🅟🅠🅡🅢🅣🅤🅥🅦🅧🅨🅩

123

y = x 2 + z 3 y = x^2 + z_3 y=x2+z3

y = x 2 + z 3 + a b + b a y = x^2 + z_3 + \frac {a}{b} + \sqrt[a]{b} y=x2+z3+ba+ab

y = x 2 + z 3 (1) y = x^2 + z^3 \tag{1} y=x2+z3(1)文章来源地址https://www.toymoban.com/news/detail-562651.html

到了这里,关于Linux 设备驱动程序(四)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux 内核 ASoC DMA 引擎驱动程序

    Linux 内核 ASoC 框架,在概念上将嵌入式音频系统拆分为多个可复用的组件驱动程序,包括 Codec 类驱动程序、平台类驱动程序和机器类驱动程序。在实现上,机器类驱动程序用 struct snd_soc_card 和 struct snd_soc_dai_link 结构描述,属于平台类驱动程序的 DMA 引擎驱动程序由 struct snd

    2024年02月11日
    浏览(29)
  • Linux驱动实践:带你一步一步编译内核驱动程序

    记得以前我在开始学习驱动开发的时候,找来很多文章、资料来学习,但是总是觉得缺少了点全局视角。 就好像:我想看清一座山的全貌,但总是被困在一个、又一个山谷中一样。 主要的困惑有 3 点: 每一篇文章的介绍都是正确的,但是如果把很多文章放在一起看,就会

    2023年04月24日
    浏览(39)
  • Linux 设备驱动程序(四)

    Linux 内核设计与实现 深入理解 Linux 内核 Linux 设备驱动程序(一) Linux 设备驱动程序(二) Linux 设备驱动程序(三) Linux 设备驱动程序(四) Linux设备驱动开发详解 深入理解Linux虚拟内存管理     ⇐ ⇒ ⇔ ⇆ ⇒ ⟺ ①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕

    2024年02月16日
    浏览(25)
  • linux的SPI设备驱动程序

            串行外设接口(SPI)是四线总线:MOSI、MISO、串行时钟SCK和片选CS。它常用于连接闪存、AD/DA转换器。主设备生成时钟和管理片选CS,速度可达80MB,远超I2C总线。         SPI设备在内核中表示为struct spi_device{},管理他们的驱动程序的实例是struct spi_driver{}。spi的拓扑结构

    2024年02月13日
    浏览(30)
  • 【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

    创建自定义的IOCTL(输入/输出控制)或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。 1. 定义IOCTL命令 在内核模块中,需要使用宏定义你的IOCTL命令。通常情况下,IOCTL命令包括了一个命令编号、请求类型的方向(读/写/两者)以及数

    2024年01月20日
    浏览(27)
  • Linux驱动开发—最详细应用程序调用驱动程序解析

    Linux下进行驱动开发,完全将驱动程序与应用程序隔开,中间通过 C标准库函数 以及 系统调用 完成驱动层和应用层的数据交换。 驱动加载成功以后会在“/dev”目录下生成一个相应的文件,应用程序通过 对“/dev/xxx” (xxx 是具体的驱动文件名字) 的文件进行相应的操作 即可实

    2024年02月16日
    浏览(34)
  • 【linux驱动开发】在linux内核中注册一个杂项设备与字符设备以及内核传参的详细教程

    开发环境: windows + ubuntu18.04 + 迅为rk3568开发板 相较于字符设备,杂项设备有以下两个优点: 节省主设备号:杂项设备的主设备号固定为 10,在系统中注册多个 misc 设备驱动时,只需使用子设备号进行区分即可。 使用简单:相比如普通的字符设备驱动, misc驱动只需要将基本信

    2024年01月21日
    浏览(35)
  • Linux 驱动开发基础知识——Hello驱动程序(一)

     个人名片: 🦁作者简介:一名喜欢分享和记录学习的在校大学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755@qq.com 🦉个人WeChat:Vir2021GKBS 🐼 本文由妄北y原创,首发CSDN 🎊🎊🎊 🐨座右铭:大多数人想要改造这个世界,但却罕有人想改造自己。 专栏导

    2024年01月19日
    浏览(32)
  • Linux 驱动开发基础知识——认识LED驱动程序 (二)

     个人名片: 🦁作者简介:一名喜欢分享和记录学习的在校大学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755@qq.com 🦉个人WeChat:Vir2021GKBS 🐼 本文由妄北y原创,首发CSDN 🎊🎊🎊 🐨座右铭:大多数人想要改造这个世界,但却罕有人想改造自己。 专栏导

    2024年01月21日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包