第十六章、块设备驱动程序
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