阅读的心得体会
这几天在看《》看到140页时,看到一个文件的定义:书中给出了文件的位置:/usr/src/linux/include/linux/fs.h
关于这个头文件的位置,由于原来的linux是可以直接下载kernel源码的,因此下载下来的源码直接在目录/usr/src下面,实际上下载的文件解压后,相当于直接进入到linux目录了。
1、为了查看该文件,我下载了最新版本和次新版本,甚至还下载了一个认为比较老的版本,分别是:linux-6.6.10,linux-4.19.99,linux-3.19.9,打开文件都是不对的。
2、看了书的出版日期是2000年,那我就下载了linux-1.2.13,后来发现还是不对,作者不是个保守主义,再说搞开发的一般都比较激进些
3、下载了1999.12.29日的linux-2.3.35版本,打开后文件为:
606 struct file_operations { 607 loff_t (*llseek) (struct file *, loff_t, int); 608 ssize_t (*read) (struct file *, char *, size_t, loff_t *); 609 ssize_t (*write) (struct file *, const char *, size_t, loff_t *); 610 int (*readdir) (struct file *, void *, filldir_t); 611 unsigned int (*poll) (struct file *, struct poll_table_struct *); 612 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long ); 613 int (*mmap) (struct file *, struct vm_area_struct *); 614 int (*open) (struct inode *, struct file *); 615 int (*flush) (struct file *); 616 int (*release) (struct inode *, struct file *); 617 int (*fsync) (struct file *, struct dentry *); 618 int (*fasync) (int, struct file *, int); 619 int (*check_media_change) (kdev_t dev); 620 int (*revalidate) (kdev_t dev); 621 int (*lock) (struct file *, int, struct file_lock *); 622 };
这才基本接近,由于书中并没有说明是内核的具体版本,因此,只能比较接近,再来看看,2.3.51版本的
658 struct file_operations { 659 loff_t (*llseek) (struct file *, loff_t, int); 660 ssize_t (*read) (struct file *, char *, size_t, loff_t *); 661 ssize_t (*write) (struct file *, const char *, size_t, loff_t *); 662 int (*readdir) (struct file *, void *, filldir_t); 663 unsigned int (*poll) (struct file *, struct poll_table_struct *); 664 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long ); 665 int (*mmap) (struct file *, struct vm_area_struct *); 666 int (*open) (struct inode *, struct file *); 667 int (*flush) (struct file *); 668 int (*release) (struct inode *, struct file *); 669 int (*fsync) (struct file *, struct dentry *); 670 int (*fasync) (int, struct file *, int); 671 int (*lock) (struct file *, int, struct file_lock *); 672 ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, lo ff_t *); 673 ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, l off_t *); 674 };
内容增加了两行,这就是更新的意义吧。内容就在那里,想找,努力总会找到的。
在linux下驱动开发,主要是把需要实现的功能借助内核调用实现,将不要实现的函数功能直接为NULL即可。
linux内核里的指针函数,linux-2.3.35中 /linux/arch/i386/kernel/irq.c
639 int request_irq(unsigned int irq, 640 void (*handler)(int, void *, struct pt_regs *), 641 unsigned long irqflags, 642 const char * devname, 643 void *dev_id) 644 { 645 int retval; 646 struct irqaction * action; 647 648 #if 1 649 /* 650 * Sanity-check: shared interrupts should REALLY pass in 651 * a real dev-ID, otherwise we'll have trouble later trying 652 * to figure out which interrupt is which (messes up the 653 * interrupt freeing logic etc). 654 */ 655 if (irqflags & SA_SHIRQ) { 656 if (!dev_id) 657 printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", dev name, (&irq)[-1]); 658 } 659 #endif 660 661 if (irq >= NR_IRQS) 662 return -EINVAL; 663 if (!handler) 664 return -EINVAL; 665 666 action = (struct irqaction *) 667 kmalloc(sizeof(struct irqaction), GFP_KERNEL); 668 if (!action) 669 return -ENOMEM; 670 671 action->handler = handler; 672 action->flags = irqflags; 673 action->mask = 0; 674 action->name = devname; 675 action->next = NULL; 676 action->dev_id = dev_id; 677 678 retval = setup_irq(irq, action); 679 if (retval) 680 kfree(action); 681 return retval; 682 }
第640行就是指针函数的应用,应用于函数传递参数中。
再看这个文件:/linux/fs/devices.c
107 /* 108 Return the function table of a device. 109 Load the driver if needed. 110 */ 111 struct file_operations * get_blkfops(unsigned int major) 112 { 113 return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs); 114 } 115 116 struct file_operations * get_chrfops(unsigned int major, unsigned int minor) 117 { 118 return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs); 119 } 120 121 int register_chrdev(unsigned int major, const char * name, struct file_operat ions *fops) 122 { 123 if (major == 0) { 124 for (major = MAX_CHRDEV-1; major > 0; major--) { 125 if (chrdevs[major].fops == NULL) { 126 chrdevs[major].name = name; 127 chrdevs[major].fops = fops; 128 return major; 129 } 130 } 131 return -EBUSY; 132 } 133 if (major >= MAX_CHRDEV) 134 return -EINVAL; 135 if (chrdevs[major].fops && chrdevs[major].fops != fops) 136 return -EBUSY; 137 chrdevs[major].name = name; 138 chrdevs[major].fops = fops; 139 return 0; 140 }
这个函数中真正有用的似乎只有137,138行,其他都是在做各种情况测试而已。
/linux/include/linux/major.h
127 #define UNIX98_PTY_MASTER_MAJOR 128 128 #define UNIX98_PTY_MAJOR_COUNT 8 129 #define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COU NT) 130 131 /* 132 * Tests for SCSI devices. 133 */ 134 135 #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ 136 ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) 137 138 #define SCSI_BLK_MAJOR(M) \ 139 (SCSI_DISK_MAJOR(M) \ 140 || (M) == SCSI_CDROM_MAJOR) 141 142 static __inline__ int scsi_blk_major(int m) { 143 return SCSI_BLK_MAJOR(m); 144 } 145 146 #endif
此头文件最大的作用就是定义各种宏,还有带参数的宏,138~140就是一个带参数的宏,而142~144行也是一个带参数的宏,和函数已经很接近了。