![[计算机软件及应用]基于高通MSM8x60的I2C驱动终极讲解.doc_第1页](http://file.renrendoc.com/FileRoot1/2019-1/10/92c33bff-f51a-46b3-9107-aefa063a437e/92c33bff-f51a-46b3-9107-aefa063a437e1.gif)
![[计算机软件及应用]基于高通MSM8x60的I2C驱动终极讲解.doc_第2页](http://file.renrendoc.com/FileRoot1/2019-1/10/92c33bff-f51a-46b3-9107-aefa063a437e/92c33bff-f51a-46b3-9107-aefa063a437e2.gif)
![[计算机软件及应用]基于高通MSM8x60的I2C驱动终极讲解.doc_第3页](http://file.renrendoc.com/FileRoot1/2019-1/10/92c33bff-f51a-46b3-9107-aefa063a437e/92c33bff-f51a-46b3-9107-aefa063a437e3.gif)
![[计算机软件及应用]基于高通MSM8x60的I2C驱动终极讲解.doc_第4页](http://file.renrendoc.com/FileRoot1/2019-1/10/92c33bff-f51a-46b3-9107-aefa063a437e/92c33bff-f51a-46b3-9107-aefa063a437e4.gif)
![[计算机软件及应用]基于高通MSM8x60的I2C驱动终极讲解.doc_第5页](http://file.renrendoc.com/FileRoot1/2019-1/10/92c33bff-f51a-46b3-9107-aefa063a437e/92c33bff-f51a-46b3-9107-aefa063a437e5.gif)
已阅读5页,还剩33页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于高通MSM 8x60的I2C驱动终极讲解(1)(2012-04-22 17:30)标签:转载 分类:linux driver study原文地址:基于高通MSM 8x60的I2C驱动终极讲解(1)作者:shangbaogen网上的I2C驱动讲解已经很多啦,我想不想画蛇添足,我想写一个完整的I2C驱动,包括系统启动,总线注册,驱动注册,设备注册,里面会贯穿Linux设备驱动模型,platform机制等等,基于高通MSM 8x60,I2C控制器为qup,下面开始进入正题:首先是平台设备的注册:源码位置:(msm/arch/arm/mach-msm/devices-msm8x60.c)首先说下平台设备,因为Linux所有的设备都是通过总线控制器连接到CPU的,但是还有一些设备不是通过总线控制器连接到CPU,所以就有了platform总线虚拟总线,把那些不是真正通过总线控制器相连的设备,比如:SOC的片内设备,片内控制器,这些都归为平台设备.把这些平台设备通过虚拟总线连接到cpu上,以便维护Linux设备模型中的,总线,设备,驱动之间的关系。首先注册BSP的平台设备驱动,其中I2C控制器的平台设备如下:先看下高通的8x60,靠,有6个控制器,所有接下来的事情就是淡定。下面的是6个控制器在I2C控制器的ID编号#define MSM_GSBI3_QUP_I2C_BUS_ID 0#define MSM_GSBI4_QUP_I2C_BUS_ID 1#define MSM_GSBI9_QUP_I2C_BUS_ID 2#define MSM_GSBI8_QUP_I2C_BUS_ID 3#define MSM_GSBI7_QUP_I2C_BUS_ID 4#define MSM_GSBI12_QUP_I2C_BUS_ID 5下面是六个控制器所用到的资源static struct resource gsbi3_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI3_QUP_PHYS,.end= MSM_GSBI3_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI3_PHYS,.end= MSM_GSBI3_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI3_QUP_IRQ,.end= GSBI3_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi4_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI4_QUP_PHYS,.end= MSM_GSBI4_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI4_PHYS,.end= MSM_GSBI4_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI4_QUP_IRQ,.end= GSBI4_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi7_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI7_QUP_PHYS,.end= MSM_GSBI7_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI7_PHYS,.end= MSM_GSBI7_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI7_QUP_IRQ,.end= GSBI7_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi8_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI8_QUP_PHYS,.end= MSM_GSBI8_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI8_PHYS,.end= MSM_GSBI8_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI8_QUP_IRQ,.end= GSBI8_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi9_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI9_QUP_PHYS,.end= MSM_GSBI9_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI9_PHYS,.end= MSM_GSBI9_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI9_QUP_IRQ,.end= GSBI9_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi12_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI12_QUP_PHYS,.end= MSM_GSBI12_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI12_PHYS,.end= MSM_GSBI12_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI12_QUP_IRQ,.end= GSBI12_QUP_IRQ,.flags= IORESOURCE_IRQ,;下面是为6个I2C控制器所注册平台设备驱动需要的结构体/* Use GSBI3 QUP for /dev/i2c-0 */struct platform_device msm_gsbi3_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI3_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi3_qup_i2c_resources),.resource= gsbi3_qup_i2c_resources,;/* Use GSBI4 QUP for /dev/i2c-1 */struct platform_device msm_gsbi4_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI4_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi4_qup_i2c_resources),.resource= gsbi4_qup_i2c_resources,;/* Use GSBI8 QUP for /dev/i2c-3 */struct platform_device msm_gsbi8_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI8_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi8_qup_i2c_resources),.resource= gsbi8_qup_i2c_resources,;/* Use GSBI9 QUP for /dev/i2c-2 */struct platform_device msm_gsbi9_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI9_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi9_qup_i2c_resources),.resource= gsbi9_qup_i2c_resources,;/* Use GSBI7 QUP for /dev/i2c-4 (Marimba) */struct platform_device msm_gsbi7_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI7_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi7_qup_i2c_resources),.resource= gsbi7_qup_i2c_resources,;/* Use GSBI12 QUP for /dev/i2c-5 (Sensors) */struct platform_device msm_gsbi12_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI12_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi12_qup_i2c_resources),.resource= gsbi12_qup_i2c_resources,;注意该6个平台设备结构体的name都是qup_i2c,下面这些平台设备将在BSP资源注册的时候给添加到系统。基于高通MSM 8x60的I2C驱动终极讲解(2)(2012-04-22 17:30)标签:转载 分类:linux driver study原文地址:基于高通MSM 8x60的I2C驱动终极讲解(2)作者:shangbaogen上一篇文章已经把I2C控制器所用的platform devices准备好啦,现在开始注册,该文件在板级支持文件中,board-xxx.c文件中。static struct platform_device *surf_devices _initdata = .#ifdef CONFIG_I2C_QUP&msm_gsbi3_qup_i2c_device,&msm_gsbi4_qup_i2c_device,&msm_gsbi7_qup_i2c_device,&msm_gsbi8_qup_i2c_device,&msm_gsbi9_qup_i2c_device,&msm_gsbi12_qup_i2c_device,#endif.;继续对该I2C平台设备结构体初始化static void _initmsm8x60_init_buses(void).#ifdef CONFIG_I2C_QUPmsm_gsbi3_qup_i2c_device.dev.platform_data = &msm_gsbi3_qup_i2c_pdata;msm_gsbi4_qup_i2c_device.dev.platform_data = &msm_gsbi4_qup_i2c_pdata;msm_gsbi7_qup_i2c_device.dev.platform_data = &msm_gsbi7_qup_i2c_pdata;msm_gsbi8_qup_i2c_device.dev.platform_data = &msm_gsbi8_qup_i2c_pdata;msm_gsbi9_qup_i2c_device.dev.platform_data = &msm_gsbi9_qup_i2c_pdata;msm_gsbi12_qup_i2c_device.dev.platform_data = &msm_gsbi12_qup_i2c_pdata;#endif.其中初始化的platform_data如下static struct msm_i2c_platform_data msm_gsbi3_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi4_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi7_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.pri_clk = 60,.pri_dat = 59,.msm_i2c_config_gpio = gsbi7_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi8_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi9_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi12_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.use_gsbi_shared_mode = 1,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;其中的msm_i2c_config_gpio赋值的值的定义如下static void gsbi7_qup_i2c_gpio_config(int adap_id, int config_type)if (config_type = 0) gpio_tlmm_config(gsbi7_gpio_table0, GPIO_CFG_ENABLE);gpio_tlmm_config(gsbi7_gpio_table1, GPIO_CFG_ENABLE); else gpio_tlmm_config(gsbi7_i2c_table0, GPIO_CFG_ENABLE);gpio_tlmm_config(gsbi7_i2c_table1, GPIO_CFG_ENABLE);下面的函数会注册该平台设备static void _initmsm8x60_init(struct msm_board_data *board_data) .msm8x60_init_buses(); .platform_add_devices(surf_devices,ARRAY_SIZE(surf_devices); .下面的函数会调用上面的初始化static void _initmsm8x60_ep680_init(void)msm8x60_init(&msm8x60_ep680_board_data);上面的函数会挂载到板级的结构中。MACHINE_START(MSM8X60_EP680, QCT MSM8X60 EP680).map_io = msm8x60_map_io,.init_irq = msm8x60_init_irq,.init_machine =msm8x60_ep680_init,/挂载的板级初始化函数.timer = &msm_timer,MACHINE_END以上就是对I2C控制器的注册。基于高通MSM 8x60的I2C驱动终极讲解(3)(2012-05-15 11:40)标签:转载 分类:高通I2C原文地址:基于高通MSM 8x60的I2C驱动终极讲解(3)作者:shangbaogen 上一节分解到平台设备已经注册,挂载到BSP板级结构体的.init_machine成员中啦,但是这个成员什么时间调用呢,也就是我们的驱动是在什么时候注册进系统的呢,现在就来跟踪下,看.init_machine函数什么时候调用的。要想知道整个流程是什么样的,这个还要从老掉牙的start_kernel()函数说起该函数是整个kernel的起始入口点:asmlinkage void _init start_kernel(void) . setup_arch(&command_line); .rest_init(); .其中的setup_arch()函数如下:void _init setup_arch(char *cmdline_p)struct machine_desc *mdesc;/*通过机器码获取板级结构体,这个结构体就是在BSP文件中的那个大的结构体*/mdesc = setup_machine(machine_arch_type); .init_machine = mdesc-init_machine;其中init_machine是一个函数指针,该函数指针的初始化如下static void (*init_machine)(void) _initdata;static int _init customize_machine(void)/* customizes platform devices, or adds new ones */if (init_machine)init_machine();return 0;arch_initcall(customize_machine);其中牵涉到arch_initcall宏,把该宏展开,如下#define arch_initcall(fn)_define_initcall(3,fn,3)#define _define_initcall(level,fn,id) static initcall_t _initcall_#fn#id _used _attribute_(_section_(.initcall level .init) = fn展开后的结果如下:static initcall_t _initcall_customize_machine3_used _attribute_(_section_(.initcall3.init) = customize_machine其中typedef int (*initcall_t)(void);把该函数放到.initcall3.init段内该段在如下函数中执行:static noinline void _init_refokrest_init(void) _releases(kernel_lock).kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);.其中kernel_init函数如下:static int _init kernel_init(void * unused).do_basic_setup();.其中的do_basic_setup()函数如下:static void _init do_basic_setup(void).do_initcalls();.其中do_initcalls()函数如下:static void _init do_initcalls(void)initcall_t *fn;for (fn = _early_initcall_end; fn .initcall1.initpostcore_initcall(fn) -.initcall2.initarch_initcall(fn) -.initcall3.initsubsys_initcall(fn) -.initcall4.initfs_initcall(fn) -.initcall5.initdevice_initcall(fn) -.initcall6.initlate_initcall(fn) -.initcall7.init而与2.4兼容的initcall(fn)则等价于device_initcall(fn)。各个子区段之间的顺序是确定的,即先调用.initcall1.init中的函数指针再调用.initcall2.init中的函数指针,等等.而在每个子区段中的函数指针的顺序是和链接顺序相关的,是不确定的。在内核中,不同的init函数被放在不同的子区段中,因此也就决定了它们的调用顺序.这样也就解决了一些init函数之间必须保证一定的调用顺序的问题。Uboot完成系统的引导并将Linux内核拷贝到内存之后,bootm - do_bootm_linux()跳转到kernel的起始位置;压缩过的kernel入口在arch/arm/boot/compressed/head.S,它将调用函数 decompress_kernel()解压,打印 “Uncompressing Linux.”,调用gunzip(),打印done, booting the kernel.然后call_kernel,执行解压后的kernel,经linux/arch/arm/kernel/head.S调用start_kernel转入体系结构无关的通用C代码,在start_kernel()中完成了一系列系统初始化,设备及驱动的注册即在此时完成:asmlinkage void _initstart_kernel(void) .rest_init();start_kernel()中的函数rest_init()将创建第一个核心线程kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND),调用init()函数:static intinit(void * unused)do_basic_setup();/判断在启动时是否指定了init参数,如果指定则执行用户init进程,成功将不会返回 if (execute_command) run_init_process(execute_command); printk(KERN_WARNING Failed to execute %s. Attempting defaults.n, execute_command);/*如果没有指定init启动参数,则查找下面的目录init进程,成功将不会返回,否则打印出错信息*/run_init_process(/sbin/init);run_init_process(/etc/init);run_init_process(/bin/init);run_init_process(/bin/sh);panic(No init found. Try passing init= option to kernel.);继而调用函数do_basic_setup()(此时与体系结构相关的部分已经初始化完了,现在开始初始化设备了):static void _initdo_basic_setup(void)/* drivers will send hotplug events */init_workqueues();usermodehelper_init();driver_init(); /建立设备模型子系统#ifdef CONFIG_SYSCTLsysctl_init();#endif/* Networking initialization needs a process context */sock_init();do_initcalls(); /系统初始化(包括设备,文件系统,内核模块等)/*driver_init - initialize driver model.*Call the driver model init functions to initialize their*subsystems. Called early from init/main.c.*/void _initdriver_init(void)/* These are the core pieces */devices_init(); int _init devices_init(void) return subsystem_register(&devices_subsys); buses_init();classes_init();firmware_init();/* These are also core pieces, but must come after the * core core pieces. */platform_bus_init();system_bus_init();cpu_dev_init();memory_dev_init();attribute_container_init();extern initcall_t _initcall_start, _initcall_end;static void _initdo_initcalls(void)initcall_t *call;int count = preempt_count();for (call = _initcall_start; call _initcall_end; call ) (*call)(); /调用一系列初始化函数 _initcall_start和_initcall_end界定了存放初始化函数指针区域的起始地址,即从_initcall_start开始到 _initcall_end结束的区域中存放了指向各个初始化函数的函数指针。由 (*call)()完成各个部分的初始化工作,且便于扩充。具体实现如下:_initcall_start = .;*(.initcall1.init)*(.initcall2.init)*(.initcall3.init)*(.initcall4.init)*(.initcall5.init)*(.initcall6.init)*(.initcall7.init)_initcall_end = .;#ifndef MODULE /*如果驱动模块静态编译进内核*/#define _define_initcall(level,fn) static initcall_t _initcall_#fn _attribute_used_ _attribute_(_section_(.initcall level .init) = fn#define core_initcall(fn)_define_initcall(1,fn)#define postcore_initcall(fn)_define_initcall(2,fn)#define arch_initcall(fn)_define_initcall(3,fn)#define subsys_initcall(fn)_define_initcall(4,fn)#define fs_initcall(fn)_define_initcall(5,fn)#define device_initcall(fn)_define_initcall(6,fn)/此处初始化了静态编译的驱动模块#define late_initcall(fn) _define_initcall(7,fn)#define _initcall(fn) device_initcall(fn)/*静态编译的驱动模块作为device_initcall在内核启动就被do_initcalls*/#define module_init(x)_initcall(x);#define module_exit(x)_exitcall(x);#else /* MODULE如果驱动模块动态加载入内核 */* Each module must use one module_init(), or one no_module_init */#define module_init(initfn)static inline initcall_t _inittest(void) return initfn; int init_module(void) _attribute_(alias(#initfn);/insmod 是通过系统调用sys_init_module(const char *name_user, struct module *mod_user)将动态驱动模块载入到内核空间/* This is only required if you want to be unloadable. */#define module_exit(exitfn)static inline exitcall_t _exittest(void) return exitfn; void cleanup_module(void) _attribute_(alias(#exitfn);基于高通MSM 8x60的I2C驱动终极讲解(5)(2012-04-22 17:31)标签:转载 分类:linux driver study原文地址:基于高通MSM 8x60的I2C驱动终极讲解(5)作者:shangbaogen 现在是初始化讲完啦,下面就看平台设备的注册啦,也就是咱们的I2C控制器的注册,注册函数为platform_add_devices(surf_devices,ARRAY_SIZE(surf_devices);该函数已经在第一讲中提到,但是没有进入分析,下面咱们就进入看下平台设备是怎么注册的。后面的代码只列出主要部分,以免其他代码干扰我们的视线。int platform_add_devices(struct platform_device *devs, int num)int i, ret = 0; for (i = 0; i dev);/初始化平台设备的dev结构体,为加入设备驱动模型做准备returnplatform_device_add(pdev);下面继续跟踪函数intplatform_device_add(struct platform_device *pdev)if (!pdev-dev.parent)pdev-dev.parent = &platform_bus;/如果pdev-dev.parent为空就赋值为platform_bus pdev-dev.bus = &platform_bus_type;/设置该设备的总线类型/*根据pdev-id的值设备pdev-dev的name*/if (pdev-id != -1)dev_set_name(&pdev-dev, %s.%d, pdev-name, pdev-id);elsedev_set_name(&pdev-dev, %s, pdev-name);/*下面是对资源的处理,把每个平台设备的资源插入相应的资源树中*/for (i = 0; i num_resources; i+) struct resource *p, *r = &pdev-resourcei;if (r-name = NULL)r-name = dev_name(&pdev-dev);p = r-parent;if (!p) if (resource_type(r) = IORESOURCE_MEM)p = &iomem_resource;else if (resource_type(r) = IORESOURCE_IO)p = &ioport_resource;if (p & insert_resource(p, r) printk(KERN_ERR %s: failed to claim resource %dn, dev_name(&pdev-dev), i);ret = -EBUSY;goto failed; ret =device_add(&pdev-dev);/把该设备注册到设备驱动模型中下面的函数处理就和一般的设备注册是一样的啦!在上述函数中用到的两个结构体定义如下struct device platform_bus = .init_name= platform,;struct bus_t
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 线路板智能工厂建设项目施工方案
- 交通运输行业数据集建设实施方案
- 高效管理:二人合资开设健身房的详细合同
- 离婚后双方人寿保险权益分割及责任转移协议
- 离婚协议书欠条范本:赡养费支付与债务偿还
- 离婚协议书中关于财产分割及债务处理的具体操作指南
- 离婚协议中婚内财产约定与婚后财产归属协议
- 惠养老服务中心建设项目施工方案
- 全球石油工程市场趋势及未来发展展望
- 2025年新能源汽车电池回收利用产业园区政策法规环境优化报告
- 《早读是需要激情的!》主题班会课件
- 2025年质量月知识竞赛题库(附答案)
- 生猪订购合同书范本3篇
- 2025年妇产科学科宫颈癌筛查常见问题考试答案及解析
- 培训部数据安全事项课件
- 保安部安全培训教学课件
- 软件人员外包合同
- 老年综合征与护理试题及答案
- 3.2《参与民主生活》教案 2025-2026学年度道德与法治九年级上册 统编版
- 研发投入工时管理办法
- 道路升降柱安装合同范本
评论
0/150
提交评论