源碼位址
https://elixir.bootlin.com/linux/v3.10/source/drivers/scsi/sg.c
主裝置号
https://elixir.bootlin.com/linux/v3.10/source/include/uapi/linux/major.h#L40
file operations
此結構定義了sg的read write ioctl的具體實作
static const struct file_operations sg_fops = {
.owner = THIS_MODULE,
.read = sg_read,
.write = sg_write,
.poll = sg_poll,
.unlocked_ioctl = sg_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = sg_compat_ioctl,
#endif
.open = sg_open,
.mmap = sg_mmap,
.release = sg_release,
.fasync = sg_fasync,
.llseek = no_llseek,
};
子產品初始化 init_sg
将sg_fops和主裝置号關聯起來
static int __init
init_sg(void)
{
int rc;
if (scatter_elem_sz < PAGE_SIZE) {
scatter_elem_sz = PAGE_SIZE;
scatter_elem_sz_prev = scatter_elem_sz;
}
if (def_reserved_size >= )
sg_big_buff = def_reserved_size;
else
def_reserved_size = sg_big_buff;
/* 注冊一個字元裝置驅動 , 主裝置号為21 */
rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, ),
SG_MAX_DEVS, "sg");
if (rc)
return rc;
sg_sysfs_class = class_create(THIS_MODULE, "scsi_generic");
if ( IS_ERR(sg_sysfs_class) ) {
rc = PTR_ERR(sg_sysfs_class);
goto err_out;
}
sg_sysfs_valid = ;
rc = scsi_register_interface(&sg_interface);
if ( == rc) {
#ifdef CONFIG_SCSI_PROC_FS
sg_proc_init();
#endif /* CONFIG_SCSI_PROC_FS */
return ;
}
class_destroy(sg_sysfs_class);
err_out:
unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, ), SG_MAX_DEVS);
return rc;
}
sg為裝置建立的檔案/dev/sg0主裝置号為21, 當使用open打開/dev/sg0時,我們調用
ioctl(fd, SG_IO, &hdr)
最終會調用到
sg_ioctl
(通過主裝置号和fops結構體的關聯找到)