




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、主题:,Linux设备驱动程序,主讲人:,徐文正,V1.0,大纲,1- 设备驱动程序入门 2- 中断处理 3- 等待队列 4- 定时处理 5- 实例分析字符设备驱动程序 6- 实例分析网络设备驱动程序 7- 用户与内核的接口,1 设备驱动程序入门,驱动程序分类 模块方式驱动程序 内核方式驱动程序 用户模块驱动程序,1.1 驱动程序分类,字符设备驱动程序 表现为文件,面向字节,即时收发数据 块设备驱动程序 表现为文件,面向块,通过缓存区进行缓冲 网络设备驱动程序 表现为net_device结构链表中的一项,面向流或数据 报,通过sk_buff结构进行收发,1.2 模块方式驱动程序,编写步骤 1)
2、 写入口函数 2) 写模块函数 3) 编译为.O文件 4) 插入模块 5) 创建设备文件 调试方式 实例,1.2 模块方式驱动程序,一、入口函数,Open() 打开设备 增加使用记数;分配内存空间;初始化变量、函数;申请中断、I/O空间 Release() 关闭设备 减少使用记数;释放内存空间;释放中断、 I/O空间 Write() 写设备 Copy_from_user() Read() 写设备 Copy_to_user() 其他函数如ioctl()和中断处理函数等,1.2 模块方式驱动程序,二、模块函数,Init_module() 模块初始化函数。在插入模块时执行 也可以用module_in
3、it(your_init_func) 主要执行设备的注册 Cleanup_module() 模块清理函数。在移除模块时执行 也可以用module_exit(your_cleanup_func) 主要执行设备的反注册,1.2 模块方式驱动程序,三、编译,用如下命令将mydriver.c编译为mydriver.o Ppc_8xx-gcc-DLINUX-DMODULE- D_KERNEL_-Wall-Wstrict-prototypes-fno- builtin-nostdinc -O2- I/opt/hardhat/devkit/lsp/embeddedplanet-cllf-ppc_8xx/li
4、nux-2.4.17_mvl21/include/-I/opt/hardhat/devkit/ppc/8xx/lib/lib/gcc- Lib/powerpc-hardhat-linux/2.95.3/include/-I /opt/hardhat/devkit/lsp/embeddedplanet-cllf- ppc_8xx/linux-2.4.17_mvl21/arch/ppc/-c Mydriver.c,1.2 模块方式驱动程序,四、插入模块,insmod mydriver.o 该命令将驱动程序模块插入到内核中,并执行init_module()函数。该命令也可以向驱动程序中传递一些参数。
5、 rmmod mydriver 该命令将驱动程序模块从内核中先移除,并执行cleanup_module()函数。 其它命令:modprobe、depmod、modinfo。,1.2 模块方式驱动程序,五、创建设备文件,Mknod/dev/mydriver c major minor 该命令创建一个字符设备文件mydriver,它的主设备号是major,次设备号是minor。设备号信息可以在/proc/devices文件中获得。 网络设备驱动程序不需要此步骤,因为它不出现在文件系统中。,1.2 模块方式驱动程序,模块驱动程序的调试,使用printk函数 在程序的开始加入 #define MY_d
6、ebug 在需要打印调试信息的位置加入 #ifdef MY_DEBUG printk(“my debug info”); #endif,1.2 模块方式驱动程序,模块驱动程序实例,Modexample.c #include #include #include #include #include #include unsigned int test_major=0 ssize_t read_test(struct file *file,char *buf,size_t count,loff_t *offset) int left; if(verify_area(VERIFY_WRITE,buf,
7、count)=-EFAULT) Return EFAULT; for(left=count;left0;left-) put_user(1,buf); buf+ Return count; ,1.2 模块方式驱动程序,ssize_t write_test(struct file *file,const char *buf,size_t count,loff_t *offset) Return count; Int open_test(struct inode *inode,strut file *file) MOD_INC_USE_COUNT; Return 0; Int release_te
8、st(struct inode *inode,struct file *file) MOD_DEC_USE_COUNT; Return 0; ,1.2 模块方式驱动程序,Static struct file_operations Test_fops= Read: read_test, write: write_test, open: open_test, release: release_test, ; Int my_init_module(void) Int result; Result=register_chrdev(test_major,”test”, ,1.2 模块方式驱动程序,Voi
9、d my_cleanup_module(void) Unregister_chrdev(test_major,”test”); Module_init(my_init_module); Module_exit(my_cleanup_module); 编译 Insmod modexample.o 如果安装成功,在/proc/devices文件中就可以看到设备test,并可以看到它的主设备号。 创建设备文件 Mknod/dev/test major minor 将minor设为0即可,1.3 内核方式驱动程序,编写步骤 1) 写入口函数 2) 写初始化函数 3) 修改Config.in文件 4)
10、修改Makefile文件 5) 配置初始化函数 6) 编译内核 7) 创建设备文件 调试方式 实例,1.3 内核方式驱动程序,一、入口函数,Open(), Release() 打开和关闭设备 Write(), Read() 读写设备 ioctl() 对设备的控制函数 其他函数,如和中断处理函数等,二、初始化函数,一般命名为mydriver_init() 其功能包括: 填充设备相关结构的信息域 实现入口函数指针与设备相 关结构的连接 探测可用的IRQ号 探测可用的IO基址 注册设备,1.3 内核方式驱动程序,三、修改Config.in文件,目的:在配置内核时要在相应菜单下出现my driver选
11、项 修改文件 linux-2.4.17_mv121/drivers/char/Config.in, 在相应位置添加如下语句 bool my driver CONFIG_MYDRIVER,四、修改Makefile文件,目的:使内核能够编译mydriver.c文件(在配置内核时选择了my driver) 修改文件 linux-2.4.17_mv121/drivers/char/Makefile,在相应位置添加如下语句 obj-$( CONFIG_MYDRIVER)+=mydriver.o 将mydriver.c等源文件拷贝到目录linux-2.4.17_mv121/drivers/char/下,1
12、.3 内核方式驱动程序,五、配置初始化函数,目的:使内核启动时执行mydriver_init()函数 在linux-2.4.17_mv121/drivers/block/genhd.c中device_init()函数外的适当位置添加: #ifdef CONFIG_MYDRIVER extern void mydriver_init(void); #endif 在linux-2.4.17_mv121/drivers/block/genhd.c中device_init()函数内的适当位置添加: #ifdef CONFIG_MYDRIVER mydriver_init(); #endif,1.3 内
13、核方式驱动程序,六、编译内核,在linux-2.4.17_mv121/下执行如下命令 make clean; make dep; make zImage 编译好的内核保存在linux-2.4.17_mv121/arch/ppc/boot/images/zImage.embedded中; 启动内核就可以在/proc/devices文件中看到mydriver设备,七、创建设备文件,Mknod/dev/mydriver c major minor 该命令创建了一个字符设备文件mydriver,它的主设备号是major,次设备号是minor。设备号信息可以在/proc/devices文件中获得。 也可
14、以在rc.sysinit文件中添加此命令,从而在启动时自动创建该设备文件,1.3 内核方式驱动程序,内核驱动程序调试,Printk Kgdb BDI2000,一.配置内核 1.Make menuconfig 2.在Kernel Hacking部分选中CONFIG_KGDB 3.将makefile中的CFLAGS变量修改为CFLAGS= -Wall-Wstrict-prototypes o2 g ggdb 二.重新编译内核并启动,内核会等待gdb连接 三.关闭minicom 四.在主机上执行ddd debugger /opt/hardhat/devkit/ppc/8xx/bin/ppc_8xx-
15、gdb gdb /opt/hardhat/devkip/lsp/embeddedpla Net-cllf-ppc_8xx/linux2.4.17_mv121/vmlinux 五.然后在ddd中输入 target remote /dev/ttyS0,1.3 内核方式驱动程序,BDI2000,一.配置内核 1.Make menuconfig 2.在Kernel Hacking部分选中CONFIG_KGDB 3.将makefile中的CFLAGS变量修改为变量修改为CFLAGS=-Wall-Wstrict-prototypes o2 g ggdb 二.配置BDI2000,ip设为192.168.1.
16、20 三.在主机上输入telnet 192.168.1.20 四.通过BDI2000下载并启动内核 BDIload Ox200000 nete860.bin BIN BDIti Ox200000 五.在主机上执行ddd debugger /opt/hardhat/devkit/ppc/8xx/bin/ppc_8xx-gdb gdb/opt/hardhat/devkip/lsp/embeddedplanet-cllf-8xx/linux2.4.17_mvl21/vmlinux 六.在ddd中输入:Target remote 192.168.1.20:2001,1.4 用户模式驱动程序,适用范围及
17、特点 I/O映射 内存映射 读写设备,1.4 用户模式驱动程序,适用范围及特点,测试新的硬件设备 测试一个新的设备是否可用 观察设备的工作情况 快速创建一个硬件应用 比如控制小马达的转动 点亮某个指示灯,范 围,特 点,优点: 1)可以连接完整的C库,编程容易 2)可以使用传统调试器,而不必调试内容 缺点: 1)不支持设备中断 2)不支持设备定时,1.4 用户模式驱动程序,I/O映射,ioperm() 为用户应用程序打开一块I/O空间 iopl() 为用户应用程序打开整个I/O地址空间 MontaVista Linux不支持,1.4 用户模式驱动程序,内存映射,通过设备/dev/mem来访问硬
18、件设备 使用mmap()函数来选择要访问的内存物理基址和块大小,它返回已经映射到物理基址的虚拟地址 void *mmap (void *start, size_t length, int prot, int flags,in fd,off_t offset) fd=open(“/dev/men”,O_WRONLY); ledptr=mmap(0,sizeof(LED_AREA),PROT_WRITE,MAP_SHARED,fd,LED_ADDRESS); *ledptr=value;,1.4 用户模式驱动程序,读写设备,使用函数inb(), inw(), inl() 或readb(), rea
19、dw(), readl()来读设备 使用函数outb(), outw(), outl()或writeb(), writew(),writel()来写设备 它们的头文件是,2 中断处理,基本概述 探测中断 安装中断 取消中断,2.1 基本概念,分类,硬件中断 由硬件设备产生的中断 执行相应的中断处理程序 可以产生软中断(tasklet)来实现耗时的中断处理任务,也就是下半部中断 软中断(softIRQ) 内核中共有32个softIRQ, 其中一个就是TASKLET_SOFTIRQ 在内核执行do_softirq()函数时,轮询这32个softirq,如果相应的softirq可以执行,就执行它指导
20、的函数 TASKLET_SOFTIRQ对应的函数是tasklet_action(),它会依次执行挂在TASKLET_SOFTIRQ上的tasklet,2.1 基本概念,Read执行流程,Process read(),Device Driver,Top Half (markbin),Dev_read() Initiate transfer Wait (time passes),Bottom Half/Task (resume),2.1 基本概念,中断处理程序举例,struct tasklet_struct my_tasklet; elsewhere, in some initialization
21、 section tasklet_init( /*record that an interrupt arrived*? ,2.2 探测中断,1. probe_irq_on(void),返回一个unsigned long 位掩码,2. 使设备发中断 3. probe_irq_oof(unsigned long),第一步返回的位掩码传给此函数 返回值即为探测到的中断号(如果为0或为负则没有可用中断),探测中断例子,unsigned long mask=probe_irq_on(); outb_p(0 x10,short_base+2); /*enable reporting*/ outb_p(0
22、x00,short_base); /*clear the bit*/ outb_p(0 xFF,short_base); /*set the bit:interrupt*/ outb_p(0 x00,short_base+2); /*disable reporting*/ irq=probe_irq_off(mask);,2.2 探测中断,安装SIU中断,SIU中断向量表16个(/include/asm-asm-ppc/irq.h) 外部中断 根据硬件连线确定IRQ号码,比如是IRQ3 调用函数request_8xxirq(SIU_IRQ3, my_handler, flag, devname
23、, devpointer) 内部中断 选择一个未用的LEVEL号码,比如是LEVEL3 调用函数request_8xxirq(SIU_LEVEL3, my_handler, flag, devname, NULL),2.2 探测中断,安装SIU中断例子,#define CPM_INTERRUPTSIU_LEVEL2 (在文件irq.h中定义) cpm_interrupt_init()函数中 *(arch/ppc/8xx_io/commproc.c) /* Set our interrup handler with the core CPU. */ If (request_8xxirq(CPM_
24、interrupt, cpm_interrupt, 0,”cpm”, NULL)!=0) Panic( “could not allocate CPM IRQ!”);,2.2 探测中断,安装CPM中断,CPM中断向量表32个(/arch/ppc/8xx_io/commproc.h) 确定相应的中断向量,比如是SCC1 调用函数 cpm_install_handler(CPMVEC_SCC1, scc1_handler, devpointer),2.2 探测中断,例子,cpm_interrupt_init() 函数中 *(/arch/ppc/8xx_io/commproc.c) /* Insta
25、ll our own error handler. */ cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);,取消中断,取消SIU中断 (do_free_irq(int irq,void* dev_id) 例:do_free_irq(SIU_IRQ3, devpointer) 取消CPM中断 cpm_free_handler(int vec) 例:cpm_free_handler(CPMVEC_ERROR),2.2 探测中断,中断处理程序任务,响应中断 查看中断状态寄存器,判断中断源 根据中断源进行相应处理,3 等待队列,
26、概述,使用时机 请求暂不可用的资源 版本相关(/linux/wait.h) 2.4版以前使用结构体 wait_queue 2.4版使用结构体 wait_queue_head_t,3 等待队列,主要函数,(/kernel/sched.c) sleep_on(wait_queue_head_t *q) interruptible_sleep_on(wait_queue_head_t *q) (/linux/sched.h) wake_up(wait_queue_head_t *q) wake_up_interruptible(wait_queue_head_t *q) (/inclued/linu
27、x/wait.h) DECLARE_wait_queue_head(name) DECLARE_waitqueue (name,tsk) add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old),3 等待队列,使用实例,情景:内核中有一块内存,在写时发现满了 首先在程序开始定义全局变量 strut wait_queue_head_t wqh; /struct wait_queue_t wq; 或者使用宏 DECL
28、ARE_WAIT_QUEUE_HEAD(wqh); /DECLARE_WAITQUEUE(wq,current); 在write函数中: while(is_full) interruptible_sleep_on(,3 等待队列,使用实例(续),write_to_buffer(); is_empty=0; 在read函数中: if(!is_empty) read_from_buffer(); if_full=0; wake_up_interruptible( ,4 定时处理,概述,数据结构 include/linux/timer.h struct timer_list struct timer
29、_list *next; struct timer_list *prev; unsigned long expires; unsigned long data; void(*function)(unsigned loing); ,4 定时处理,主要函数,初始化timer void init_timer(struct timer_list *timer); 添加timer void add_timer(struct timer_list *timer); 删除timer void del_timer(struct timer_list *timer);,4 定时处理,使用实例,struct ti
30、mer_list my_timer; init_timer(,4 定时处理,等待队列和定时器综合实例,init_timer_out; struct timer_list timer; void timeout_func(unsigned long who) timed_out = 1; debug(“Timing outn”) wake_up_interruptible(wait_queue_head_t*)who); int sleep_or_timerout(wait_queue_head_t*wait,int timeout) timed_out=0; timer.data=(unsig
31、ned long) wait; timer.function = timeout_func;,4 定时处理,等待队列和定时器综合实例,timer.expires= jiffies + timeout; add_timer( ,5 实例分析字符设备驱动程序,源程序:mydriver.c mydriver.h 该程序是一个典型的模块方式字符设备驱动程序 该程序包含了中断(上下半部),时钟,等待队列 的处理例程 其特点在于用时钟中断来模拟硬件中断,5 实例分析字符设备驱动程序,函数列表,my_init_module(); mydriver_init(); my_cleanup_module(); m
32、ydriver_stop(); mydriver_open(); mydriver_release(); mydriver_timer_expiration(); mydriver_interrupt(); mydriver_task(); mydriver_read(); mydriver_write(),5 实例分析字符设备驱动程序,程序分析,my_init_module(void 调用mydriver_init() my_cleanup_module(void) 调用mydriver_stop(),注册设备 if(rc=unregister_chrdev(mydriver_major,
33、mydriver_name, ,取消设备注册 If(rc=unregister_chrdev(mydriver_major, mydriver_name),5 实例分析字符设备驱动程序,mydriver_open(pinode,pfile),增加打开记数 mydriver_open_count+,; 为文件的缓存区分配内存空间 mydriver_buffer= (char *) kmalloc(MYDRIVER_BUFFERSIZE,GEP_KERNEL); 初始化所分配的内存空间 memset(mydriver_buffer, 0, MYDRIVER_BUFFERSIZE); 申请中断号 #
34、ifndef MYDRIVER_SIMULATE_INTERRUPT rc=request_irq(mydriver_irq,mydriver_interrupt, SA_SHIRQ, mydriver_name, NULL); 初始化定时器 init_timer(,5 实例分析字符设备驱动程序,mydriver_release(pinode,pfile),增加释放记数 mydriver_release_count+,; 删除定时器 if (rc=del_timer(,5 实例分析字符设备驱动程序,mydriver_timer_expiration(mydriver_data),说明 定义MY
35、DRIVER_SIMULATE_INTERRUPT时才编译,其作用是用定时器来模拟硬件中断 增加定时器超时记数 mydriver_timer_count+; 执行中断处理函数 mydriver_interupt( MYDRIVER_IRQ,(void*) mydriver_data,(NULL);,5 实例分析字符设备驱动程序,mydriver_interrupt(irq,dev_id,fp),增加中断记数 mydriver_interrup_count+; 设置I/O成功标志 mydriver_final_status=0; 初始化tasklet(下半部) tasklet_init(,myd
36、river_task(data),唤醒等待队列 wake_up_interruptible(,5 实例分析字符设备驱动程序,mydriver_read(pfile,user_buf,count,poffset),增加读记数 mydriver_read_count+; 给定时器赋值,并添加定时器 mydriver_timer.function=mydriver_timer_expiration; mydriver_timer.data=0; mydriver_timer.expires=jiffies+(MYDRIVER_IO_DURATION *HZ); add_timer(,5 实例分析字符
37、设备驱动程序,mydriver_read(pfile,user_buf,count,poffset)续,处理异常情况 if (signal_pending(current) del_timer(,5 实例分析字符设备驱动程序,mydriver_write(pfile,user_buf,count,poffset),增加写记数 mydriver_write_count+; 拷贝数据到文件缓存区 if (copy_from_user(mydriver_buffer, user_buf, count); 给定时器赋值,并添加定时器 与read中相同 睡眠在等待队列mydriver_zz上 inter
38、ruptible_sleep_on(,5 实例分析字符设备驱动程序,mydriver_write(pfile,user_buf,count,poffset)续,处理异常情况 if (signal_pending(current) del_timer(,5 实例分析字符设备驱动程序,思考,如何将此模块方式驱动程序修改为内核方式驱动程序?,6 实例分析网络设备驱动程序,源程序 enet.c commproc.h Motorola MPC8xx以太网驱动 在SCCx上实现以太网功能,6 实例分析网络设备驱动程序,函数列表,scc_enet_init(); scc_enet_open(); scc_e
39、net_start_xmit(); scc_enet_rx(); scc_enet_close(); scc_enet_interrupt(); scc_enet_get_stats(); scc_enet_timeout(): scc_enet_t,6.1 scc_enet_init(),调用路径 (/init/main.c)start_kernel()-init()-(do_basic_setup()-do_initcalls()- (/fs/partitions/check.c)_initcall(partition_setup)-partion_setup()- (/drivers/b
40、lock/genhd.c)device_init()-(/net/core/dev.c) net_dev_init()-network_probe(),使用pci_probes 初始化数组,其中包含scc_enet_init() 初始化net_device结构的各个域; dev=init_etherdev(0,0) 初始化MPC860的parameter ram; ep=(scc_enet_t *)(,6.1 scc_enet_init(),初始化MPC860的寄存器 immap=(immap_t*)(_get_IMMR(),6.1 scc_enet_init(),将函数指针赋给net_dev
41、ice结构中相应的入口 dev-open = scc_enet_open; dev-hard_star_xmit = scc_enet_start_xmit; dev-tx_timeout= scc_enet_timeout; dev-watchdog_timeo = TX_TIMEOUT; dev-stop = scc_enet_close; dev-get_stats = scc_enet_get_stats; dev-set_multicast_list = set_multicast_list;,6.2 实例分析网络设备驱动程序,scc_enet_open,更改dev-state域的指
42、示位 netif_start_queue(dev); 相当于下面的语句 clear_bit(_LINK_STATE_XOFF,scc_enet_close(dev),更改dev-state域的指示位 netif_stop_queue(dev); 相当于下面的语句 set_bit(_LINK_STATE_XOFF,6.3 scc_enet_start_xmit(skb,dev),当用户通过enet发送数据时,执行该函数 将skb中相应域的值赋给bdp(即cep-cur_tx)的相应域 包长度:bdp-cbd_datlen = skb-len; 包数据指针:bdp-cbd_vufaddr = _p
43、a(skb-data); 保存skb指针 cep-tx_skbuff cep-skb_cur = skb 增加统计域中的发送字节数 (cep-stats.tx_bytes+=skb-len;);,将cep-skb_cur域加一, 如果超过TX_RING_SIZE, 则置为0 cep-skb_cur = (cep-skb_cur+1) ,6.3 scc_enet_start_xmit(skb,dev),清理相应数据缓冲区中的内容 flush_dcache_range(unsigned long) (skb-data), (unsigned long) (skb-data+skb-len) 锁中断
44、 spin_lock_irq(,6.3 scc_enet_start_xmit(skb,dev),设定发送开始时间 dep-trans_start=jiffies; 调理BD指针:将BD的指针向下一个可用BD,并判断发送缓冲区是否满 设置cep-cur_tx指针 cep-cur_tx= (cbd_t*)bdp; 解锁中断 spin_unlock_irq(,6.4 scc_enet_rx(dev),当产生RXF中断,即收到帧后,执行 获取cep指针 cep=(struct scc_enet_private *)dev-priv; 获取bdp指针 bdp= cep-cur_rx; 检查收到的是否是完整帧 更新统计信息 为skb申请内存 skb= dev_alloc_skb(pkt_len-4); 将skb与设备相关连 skb-dev = dev;,6.4 scc_enet_rx(dev),在skb中分配pkt_len-4长度的空间 skb_put(skb,pkt_len-4); (skbuff.h中) 将数据拷贝到skb中 eht_copy_and_sum(skb,(unsigned char *)_va(bdp-cbd_bufaddr),pkt_len-
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 南充电影工业职业学院《Linux操作系统》2023-2024学年第二学期期末试卷
- 广东建设职业技术学院《艺术学概论》2023-2024学年第二学期期末试卷
- 2025年租赁合同样本下载
- 2025年江苏省张家港市高三下学期高考适应性测试(二模)物理试题含解析
- 河南省信阳市二中重点名校2025年初三下学期第一次模拟-物理试题试卷含解析
- 成都职业技术学院《应用时间序列分析Ⅰ》2023-2024学年第二学期期末试卷
- 2025年中国城委托经营管理合同
- 浙江省诸暨市同山中心学校2024-2025学年初三(寒假第4次)质量检测试题化学试题科含解析
- 2025年柴油垫资合同模板
- 吉林省长春市榆树市第一高级中学2024-2025学年高中毕业班5月模拟考试英语试题含解析
- 第22课《从局部抗战到全国抗战》 课件 统编版高中历史中外历史纲要上册
- 浙江省A9协作体2023-2024学年高二下学期4月期中英语试题
- 水电站110kV变电站接地电阻计算书
- 鼠疫的防治专题知识讲座课件
- GB/T 44013-2024应急避难场所分级及分类
- 影像进修汇报
- 2024年唐山市2024届高三二模英语试卷(含答案)
- 口腔科治疗台水路消毒
- 压力容器安全风险管控清单(日管控、周排查、月调度)
- 超声引导下的四肢神经阻滞
- 国家职业技术技能标准 4-02-05-01 装卸搬运工 2024年版
评论
0/150
提交评论