读Linux那些事儿之我是U盘笔记(五)

简介:
1、在Linux内核中,整个scsi 子系统被分为三层. upper level,mid level,lower level
解释:来说说这三层吧:
upper level,用伟大的汉语来讲,就是最上层,她是和操作系统打交道的,比如您要是有一块scsi 硬盘,那么您就需要使用sd_mod.o这么一个模块,她实际上是与硬件无关的,是纯粹的软件上的抽象出来的数据结构组建的模块.
mid level,中层,实际上这层才是真正的核心层,江湖上人称scsi-core,即scsi核心层,她提供了支持scsi的核心数据结构和函数,这一层对应的模块是scsi_mod.o,系统中要想使用scsi 设备,首先必须加载她,反过来,只有所有的scsi 设备的模块都被卸载了才能够卸载她.陆游就曾如此形容scsi 核心层,无意苦争春,一任群芳妒.
lower level,底层.很不幸,如果您要写驱动,八成就是写的底层,正如现实中的我们一样,生活在社会的最底层.因为upper level 和mid level都已经基本上确定了,她们和硬件没关系.能留给您做的事情只能是底层.现实就是这样,尤其对80后的来说,生存的压力让80后不可能再如70后那样,能做的只有面对现实.
2、__attribute__:这是gcc的关键字,是,描述函数,变量,类型的属性
通常__attribute__(单词attribute前后各两个 underscore,即下划线.)出现在定义一个变量/函数/类型的时候,她紧跟在变量/函数/类型定义的后面;
Eg:unsigned long hostdata[0]    __attribute__ ((aligned (sizeof(unsigned long))));
aligned属性和packed属性.这两个都是和字节对齐有关的属性,aligned 是按照定义的自己对齐,packed是紧凑型,表示节省空间
3、   现在要模拟scsi:需要用到scsi三个函数
     三个函数分别是:scsi_host_alloc(),scsi_add_host(),scsi_scan_host();
     scsi_host_alloc()中就会给咱们申请内存空间;
     scsi_add_host()scsi 核心层才知道有这么一个host的存在
     scsi_scan_host()函数被调用了之后,真正的设备才被发现
     scsi核心层是认struct Scsi_Host这个结构体的,而这个结构体在设计的时候就专门准备了一个unsigned long hostdata[0]来给别的设备驱动使用.
4、      kernel_thread()解释:
     就会有两个进程,一个是父进程,一个是子进程,子进程将会执usb_stor_control_thread(),而us是作为usb_stor_control_thread函数的参数(实参),CLONE_VM标志表征父子进程之间共享地址空间,执行完usb_stor_control_thread()之后,子进程就结束了,她会调用exit()函数退出.而父进程继续顺着usb_stor_acquire_resources()函数往下走,kernel_thread()函数对于父进程而言返回的是子进程的进程id,所以802行先判断,若是返回值p 小于0,则说明出错了,否则,那就把p赋给us 的元素pid;
5、       wait_event_interruptible_timeout():
解释:这个函数其实是一个宏,
#define wait_event_interruptible_timeout(wq, condition, timeout)        \
({                                                              \
long __ret = timeout;                                         \
if (!(condition))                                          \
        __wait_event_interruptible_timeout(wq, condition, __ret); \
__ret;                                                        \
})
它代表着Linux中的一种等待机制,等待某个事件的发生;
第一个参数是一个 等待队列头,即wait_queue_head_t定义的变量,在LK 2.6中使用init_waitqueue_head()函数初始化这个等待队列
第三个参数是 设置超时,比如咱们这里设了5s,这表示如果5秒到了,那么函数会返回0,不管其它条件如何
第二个参数是一种 等待的条件,或者说等待的事件,如果条件满足了,那么函数也会返回,条件要是不满足,那么这个进程会进入睡眠,不过interruptible表明了信号可以把她中断.一旦进入睡眠,那么 有三种情况,一种是wake_up或者wake_up_interruptible函数被另一个进程执行,从而唤醒她,第二种是信号中断她,第三种就是刚才讲的超时,时间到了,自然就会返回;
在内核2.6.18 montavista linux中有一个
unsigned long fastcall __sched wait_for_completion_interruptible_timeout(struct completion *x,
unsigned long timeout)函数,在schd.c中是个函数,同理
 
6、内核休眠另一方法,电源管理方面
对于usb 设备,它可以进入suspend状态,如果flgs设置了PF_FREEZE这个标记,内核将调用refrigerator();函数让该进程休眠
7、U盘能够工作所需要的模块:usbcore,scsi_mod,sd_mod,usb-storage
其中:sd_mod是scsi disk的驱动程序
8、struct scsi_cmnd *srb很重要的结构,是scsi用来发命令的结构,如usb 使用的urb
    U盘驱动这里使用,是为了唤醒usb_stor_control_thread 线程,这个线程开始的时候:
 
           if(down_interruptible(&us->sema))    //等待scsi queuecommand来唤醒
break;
    该线程休眠了,现在除了usb退出,就修要别人去唤醒这个线程,当然使用配套的
 up(&(us->sema));了,这个函数定义在queuecommand里面;这个命令是scsi发送的,这个函数定义在usb_stor_host_template里边;
9、确定一个scsi设备的三个元素:unsigned int id, lun, channel
关系: 一个scsi 卡所控制的设备被划分为几层,先是若干个channel,然后每个channel 上有若干个target,每个target用一个target id来表征,然后一个target可以有若干个lun,而咱们这里判断的是target id.对于不支持多个target的设备,她必须为0.对于绝大多数usb mass storage设备来说,它们的target id肯定为0,
但是世界上总是有那么多怪事,有些设备厂家就是要标新立异,它就是要让你个设备支持多个target,于是它就可以设置US_FL_SCM_MULT_TARG这么一个flag



本文转自 曾永刚 51CTO博客,原文链接:http://blog.51cto.com/zyg0227/551487
相关文章
|
20天前
|
Linux
Linux(5)WIFI/BT调试笔记
Linux(5)WIFI/BT调试笔记
36 0
|
21天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
2月前
|
人工智能 安全 Unix
Linux常用命令笔记大全(建议收藏!!)
Linux常用命令笔记大全(建议收藏!!)
74 0
|
22天前
|
Unix Linux Shell
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
在Linux环境下交叉编译Android所需的FFmpeg so库,首先下载`android-ndk-r21e`,然后解压。接着,上传FFmpeg及相关库(如x264、freetype、lame)源码,修改相关sh文件,将`SYSTEM=windows-x86_64`改为`SYSTEM=linux-x86_64`并删除回车符。对x264的configure文件进行修改,然后编译x264。同样编译其他第三方库。设置环境变量`PKG_CONFIG_PATH`,最后在FFmpeg源码目录执行配置、编译和安装命令,生成的so文件复制到App工程指定目录。
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
|
2月前
|
算法 Linux
【Linux笔记】压缩、解压文件的 4 种方式。tar、gzip、gunzip、zip、unzip、7z命令使用方法
【Linux笔记】压缩、解压文件的 4 种方式。tar、gzip、gunzip、zip、unzip、7z命令使用方法
|
2天前
|
NoSQL Java Linux
linux笔记
linux笔记
8 0
|
6天前
|
存储 运维 Java
Linux笔记02 —— Shell补充
Linux笔记02 —— Shell补充
31 2
|
6天前
|
安全 Linux Shell
Linux笔记01 —— Linux初识与Shell汇总(请配合另一篇《Linux笔记02》一起使用)
Linux笔记01 —— Linux初识与Shell汇总(请配合另一篇《Linux笔记02》一起使用)
19 1
|
7天前
|
安全 Linux Android开发
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
该文介绍了如何在Linux服务器上交叉编译Android的FFmpeg库以支持HTTPS视频播放。首先,从GitHub下载openssl源码,解压后通过编译脚本`build_openssl.sh`生成64位静态库。接着,更新环境变量加载openssl,并编辑FFmpeg配置脚本`config_ffmpeg_openssl.sh`启用openssl支持。然后,编译安装FFmpeg。最后,将编译好的库文件导入App工程的相应目录,修改视频链接为HTTPS,App即可播放HTTPS在线视频。
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
|
15天前
|
编解码 Linux
FFmpeg开发笔记(十二)Linux环境给FFmpeg集成libopus和libvpx
在《FFmpeg开发实战》一书中,介绍了如何在Linux环境下为FFmpeg集成libopus和libvpx,以支持WebM格式的Opus和VP8/VP9编码。首先,下载并安装libopus。接着,下载并安装libvpx。最后,在FFmpeg源码目录下,重新配置FFmpeg,启用libopus和libvpx,编译并安装。通过`ffmpeg -version`检查版本信息,确认libopus和libvpx已启用。
FFmpeg开发笔记(十二)Linux环境给FFmpeg集成libopus和libvpx