版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、The successs roadLinux設(shè)備(shbi)驅(qū)動(dòng)高級(jí)開發(fā)共五十六頁(yè)今天(jntin)的內(nèi)容Linux驅(qū)動(dòng)程序基礎(chǔ)知識(shí)字符設(shè)備驅(qū)動(dòng)程序用戶與驅(qū)動(dòng)程序同步阻塞(zs)I/O用ioctl控制驅(qū)動(dòng)程序典型的字符設(shè)備驅(qū)動(dòng)程序分析共五十六頁(yè)Linux設(shè)備(shbi)驅(qū)動(dòng)的概念驅(qū)動(dòng)程序?yàn)橛布峁┮粋€(gè)定義良好(lingho)的內(nèi)部接口驅(qū)動(dòng)程序封裝了硬件細(xì)節(jié)驅(qū)動(dòng)程序?yàn)閼?yīng)用程序提供了訪問設(shè)備的機(jī)制共五十六頁(yè)Linux設(shè)備和模塊(m kui)的分類設(shè)備和模塊的分類:字符設(shè)備,塊設(shè)備,網(wǎng)絡(luò)接口以及(yj)提供公共服務(wù)的特定類型設(shè)備另外有一些設(shè)備驅(qū)動(dòng)比較特殊,比如 frame buffer, 共五十六頁(yè)
2、設(shè)備(shbi)驅(qū)動(dòng)健壯性和安全性驅(qū)動(dòng)程序是內(nèi)核的一部分驅(qū)動(dòng)程序的漏洞和缺陷直接危及內(nèi)核留心未初始化的指針(zhzhn),惡意用戶程序,緩沖區(qū)溢出共五十六頁(yè)驅(qū)動(dòng)程序與內(nèi)核(ni h)版本號(hào)Linux內(nèi)核版本號(hào)簡(jiǎn)述 2.0.x 2.2.x 2.4.x 2.6.x版本號(hào)在內(nèi)核編譯過程中的影響(yngxing)模塊加載時(shí)的版本號(hào)檢查共五十六頁(yè)Linux下構(gòu)建(u jin)和運(yùn)行模塊為什么用模塊?模塊和應(yīng)用程序有什么(shn me)不同#ifdef _KERNEL_#ifdef MODULEKernel 和 user space共五十六頁(yè)Linux內(nèi)核與模塊(m kui)中的并發(fā)可重入簡(jiǎn)介(jin j
3、i)共享資源帶來的問題并發(fā)與同步問題搶占式內(nèi)核對(duì)并發(fā)的影響共五十六頁(yè)模塊的編譯(biny)和裝載編譯模塊(m kui)都需要什么編譯模塊相關(guān)的宏模塊工具insmod,rmmod共五十六頁(yè)Linux驅(qū)動(dòng)程序模塊(m kui)加載共五十六頁(yè)模塊(m kui)的版本依賴內(nèi)核中定義_module_kernel_version符號(hào)版本號(hào)定義可以區(qū)分不同(b tn)版本內(nèi)核的接口函數(shù)可以在include/linux/version.h找到版本定義KERNEL_VERSION共五十六頁(yè)模塊的平臺(tái)(pngti)相關(guān)平臺(tái)相關(guān)的實(shí)現(xiàn)條件編譯平臺(tái)開關(guān)與Makefile,Makefile里面會(huì)定義與平臺(tái)相關(guān)的開關(guān),驅(qū)
4、動(dòng)程序開發(fā)者通過編寫和配置(pizh)config文件實(shí)現(xiàn)對(duì)開關(guān)的控制一個(gè)實(shí)例分析 core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/共五十六頁(yè)內(nèi)核(ni h)符號(hào)表內(nèi)核符號(hào)簡(jiǎn)介模塊之間用符號(hào)連接(linji)在一起符號(hào)導(dǎo)出內(nèi)核符號(hào)表 /proc/ksyms System.map共五十六頁(yè)模塊(m kui)初始化和關(guān)閉模塊加載調(diào)用的第一個(gè)函數(shù)init_module模塊所使用資源的分配與釋放使用計(jì)數(shù)模塊卸載和cleanup_module顯式指定(zhdng)初始化和清除函數(shù)共五十六頁(yè)驅(qū)動(dòng)程序使用(shyng)的資源獲取內(nèi)存區(qū)域 kmallocIoport和io
5、mem資源的使用運(yùn)行時(shí)動(dòng)態(tài)分配iomem,ioport靜態(tài)分配存儲(chǔ)器和端口映射我該如何(rh)選擇資源分配方式共五十六頁(yè)典型的嵌入式設(shè)備(shbi)存儲(chǔ)器映射共五十六頁(yè)字符(z f)設(shè)備驅(qū)動(dòng)程序分析主設(shè)備號(hào)和次設(shè)備號(hào)設(shè)備文件節(jié)點(diǎn)操作file operation結(jié)構(gòu)驅(qū)動(dòng)程序例子(l zi)scull的內(nèi)存使用熟悉kmalloc,kfree共五十六頁(yè)主設(shè)備(shbi)號(hào)和次設(shè)備(shbi)號(hào)mknod 創(chuàng)建設(shè)備文件字符(z f)設(shè)備文件例子crw-rw- 1 root uucp 4, 64 2005-03-20 03:36 /dev/ttyS0主設(shè)備號(hào)區(qū)分設(shè)備驅(qū)動(dòng)程序用戶程序調(diào)用open clos
6、e等操作,內(nèi)核根據(jù)主設(shè)備號(hào)找到對(duì)應(yīng)的驅(qū)動(dòng)程序共五十六頁(yè)主設(shè)備(shbi)號(hào)和次設(shè)備(shbi)號(hào)(2)次設(shè)備號(hào)區(qū)分同一個(gè)驅(qū)動(dòng)程序創(chuàng)建的多個(gè)(du )設(shè)備常見于多個(gè)串口,硬盤分區(qū)等次設(shè)備號(hào)通常依次對(duì)應(yīng)同類型多個(gè)設(shè)備主設(shè)備號(hào)次設(shè)備號(hào)hda131hda232hda333共五十六頁(yè)動(dòng)態(tài)分配主設(shè)備(shbi)號(hào)register_chrdev注冊(cè)動(dòng)態(tài)主設(shè)備號(hào)動(dòng)態(tài)分配主設(shè)備號(hào)的優(yōu)缺點(diǎn)/proc/devices和lsmod動(dòng)態(tài)生成(shn chn)設(shè)備文件系統(tǒng)節(jié)點(diǎn)dev_t和kdev_t共五十六頁(yè)file_opration結(jié)構(gòu)(jigu)分析file_opration在內(nèi)核(ni h)中定義linux/fs.
7、hstruct filemode_t f_modeloff_t f_posunsigned int f_flagsstruct file_operations *f_opvoid *private_datastruct dentry *f_dentry共五十六頁(yè)file_operationsint(*open)(struct inode*,struct file *)增加使用計(jì)數(shù),檢查錯(cuò)誤如果未初始化,則調(diào)用初始化識(shí)別次設(shè)備號(hào),如果必要,更新f_op指針(zhzhn)分配并填寫被置于filp-private_data的數(shù)據(jù)結(jié)構(gòu)int(*realse)(struct inode*,struct
8、file*)進(jìn)行open的逆操作共五十六頁(yè)例子(l zi)驅(qū)動(dòng)scull的內(nèi)存使用scull采用kmalloc和kfree另一種分配內(nèi)存的方法(fngf)使用面向頁(yè)的函數(shù)共五十六頁(yè)例子驅(qū)動(dòng)scull的訪問(fngwn)競(jìng)爭(zhēng)分析Copy on write競(jìng)爭(zhēng)(jngzhng)Write on write競(jìng)爭(zhēng)同步手段信號(hào)量和互斥量PV up() down()共五十六頁(yè)file_operationsssize_t (*read)(struct file*,char *,size_t,loff_t*)size_t(*write)(struct file*,const char*,size_t,loff
9、_t*)用戶空間(kngjin)指針和內(nèi)核指針向量化的readv,writev共五十六頁(yè)file_operationsSsize_t (*llseek)(struct file *, loff_t*, int )該方法執(zhí)行seeking操作,移動(dòng)當(dāng)前(dngqin)的文件讀寫指針loff_t是64位量共五十六頁(yè)file_operationsunsigned int (*poll) (struct file*, struct poll_table_struct *)poll方法用來查詢?cè)O(shè)備是否可讀,可寫或出于某種特殊狀態(tài)(ready or not)該系統(tǒng)調(diào)用是可阻塞的poll 和 select系
10、統(tǒng)調(diào)用的后端實(shí)現(xiàn)(shxin)依賴該該方法共五十六頁(yè)file_operationsint(*ioctl)(struct inode*,struct file*,unsigned int,unsigned long)ioctl實(shí)現(xiàn)了除標(biāo)準(zhǔn)(biozhn)io操作外其他各種操作的方法Ioctl定義依不同驅(qū)動(dòng)程序而異共五十六頁(yè)file_operationsint(*flush)(struct file*)flush執(zhí)行設(shè)備(shbi)上為完成的操作flush用于NFS代碼中一般的設(shè)備驅(qū)動(dòng)可以不實(shí)現(xiàn)該方法,(flush=NULL)共五十六頁(yè)file_operationsint (*mmap)(stru
11、ct file*, struct vm_area_struct*)該方法用于將設(shè)備內(nèi)存區(qū)映射到進(jìn)程(jnchng)的地址空間framebuffer,sound,capture等驅(qū)動(dòng)是典型的例子共五十六頁(yè)file_operationsint (*fsync)(struct file*, struct dentry *, int)fsync是fsync系統(tǒng)調(diào)用的后端實(shí)現(xiàn)應(yīng)用程序用它來刷新(shu xn)待處理的數(shù)據(jù)共五十六頁(yè)訪問(fngwn)設(shè)備驅(qū)動(dòng)程序的方法devfs簡(jiǎn)介devfs的兼容性動(dòng)態(tài)設(shè)備(shbi)文件節(jié)點(diǎn)的另一種實(shí)現(xiàn)方法自動(dòng)腳本proc簡(jiǎn)介sysfs簡(jiǎn)介共五十六頁(yè)阻塞(zs)型I/O
12、簡(jiǎn)介用戶程序和硬件設(shè)備需要同步軟件要知道什么時(shí)候數(shù)據(jù)(shj)會(huì)到來通常的實(shí)現(xiàn)方法是軟件處于睡眠狀態(tài),有數(shù)據(jù)到來時(shí)進(jìn)行處理,然后繼續(xù)睡眠Linux通過等待隊(duì)列wait queue,實(shí)現(xiàn)了幾總不同的睡眠方式共五十六頁(yè)阻塞(zs)進(jìn)程的睡眠sleep_on(wait_queue_head_t *queue);將當(dāng)前進(jìn)程置入等待隊(duì)列(duli),并且處于睡眠狀態(tài)中的進(jìn)程不能被killinterruptible_sleep_on(wait_queue_head_t *queue);將當(dāng)前進(jìn)程置入等待隊(duì)列并且可中斷,處于睡眠狀態(tài)中的進(jìn)程可以被killsleep_on_timeout(wait_queue
13、_head_t *queue, long timeout);interruptible_sleep_on_timeout(wait_queue_head_t *queue,long timeout);這兩個(gè)函數(shù)與前兩個(gè)類似,只是多加了超時(shí)機(jī)制。即進(jìn)程的睡眠時(shí)間不超過timeout中指定的“jiffy”值。共五十六頁(yè)阻塞進(jìn)程(jnchng)的睡眠(2)void wait_event(wait_queue_head_t queue, int condition);int wait_event_interruptible(wait_queue_head_t queue, int condition)
14、;這兩個(gè)宏用來讓進(jìn)程進(jìn)入睡眠直到condition條件(tiojin)到來。Condition可以是任意條件表達(dá)式共五十六頁(yè)阻塞(zs)進(jìn)程的喚醒wake_up(wait_queue_head_t *queue);喚醒所有等queue隊(duì)列的進(jìn)程(jnchng)wake_up_interruptible(wait_queue_head_t *queue);只喚醒可等待隊(duì)列里可中斷進(jìn)程wake_up_sync(wait_queue_head_t *queue);wake_up_interruptible_sync(wait_queue_head_t *queue);這兩個(gè)函數(shù)與前兩個(gè)類似,只是他們
15、讓等待進(jìn)程置入可運(yùn)行隊(duì)列,而不是立刻重新調(diào)度共五十六頁(yè)深入(shnr)等待隊(duì)列驅(qū)動(dòng)程序可以直接操作wait queue簡(jiǎn)單的流程如下:初始化一個(gè)wait_queque_t wait將進(jìn)程當(dāng)前狀態(tài)置為睡眠狀態(tài)將wait加入到等待隊(duì)列中調(diào)用shedule()并開始睡眠當(dāng)前進(jìn)程會(huì)一直睡眠直到外部(wib)改變了當(dāng)前進(jìn)程的運(yùn)行狀態(tài)喚醒后中隊(duì)列中刪除wait共五十六頁(yè)阻塞I/O驅(qū)動(dòng)(q dn)的可重入編寫技巧當(dāng)驅(qū)動(dòng)程序被訪問,并且用戶進(jìn)程進(jìn)入睡眠狀態(tài)以后,我們要求別的進(jìn)程可以繼續(xù)訪問驅(qū)動(dòng)程序在此情況下,我們可以編寫可重入驅(qū)動(dòng)主要的思想是將狀態(tài)量保存在驅(qū)動(dòng)程序?qū)嵗木植孔兞坷?,而非全局變量不?b tn)
16、進(jìn)程訪問驅(qū)動(dòng)程序,其中的局部變量保存在該進(jìn)程的棧當(dāng)中共五十六頁(yè)阻塞(zs)I/O和非阻塞I/O對(duì)比完全(wnqun)功能的讀寫操作包括非阻塞的read和write,使用O_NONBLOCK標(biāo)志打開調(diào)用阻塞read時(shí),如果沒有數(shù)據(jù)可讀,用戶進(jìn)程就會(huì)進(jìn)入睡眠狀態(tài)知道有數(shù)據(jù)可讀當(dāng)調(diào)用非阻塞read時(shí),如果沒有數(shù)據(jù)可讀,read馬上返回-EAGAIN,這樣就提供了用戶進(jìn)程查詢?cè)O(shè)備的機(jī)制阻塞與非阻塞I/O只影響open,read,write著三個(gè)函數(shù)共五十六頁(yè)阻塞I/O的實(shí)例(shl)分析例子(l zi)程序scullpipe實(shí)現(xiàn)了上面介紹的技術(shù)Scullpipe的驅(qū)動(dòng)結(jié)構(gòu)如下typedef struc
17、t Scull_Pipe wait_queue_head_t inq, outq; /* read and write queues */char *buffer, *end; /* begin of buf, end of buf */int buffersize; /* used in pointer arithmetic */char *rp, *wp; /* where to read, where to write */int nreaders, nwriters; /* number of openings for r/w */struct fasync_struct *async
18、_queue; /* asynchronous readers */struct semaphore sem; /* mutual exclusion semaphore */devfs_handle_t handle; /* only used if devfs is there */ Scull_Pipe;共五十六頁(yè)阻塞I/O的實(shí)例(shl)分析(2)ssize_t scull_p_read (struct file *filp, char *buf, size_t count,loff_t *f_pos).if (filp-f_flags & O_NONBLOCK)return -EAG
19、AIN;PDEBUG(%s reading: going to sleepn, current-comm);if (wait_event_interruptible(dev-inq, (dev-rp != dev-wp)return -ERESTARTSYS; dev-rp += count;if (dev-rp = dev-end)dev-rp = dev-buffer; /* wrapped */up (&dev-sem);共五十六頁(yè)字符(z f)設(shè)備定位字符設(shè)備定位通過設(shè)備驅(qū)動(dòng)llseek方法實(shí)現(xiàn)llseek方法修改filp-f_pos來改變?cè)O(shè)備當(dāng)前的定位定位對(duì)有明確(mngqu)數(shù)據(jù)區(qū)
20、的設(shè)備有意義,而對(duì)面向數(shù)據(jù)流的設(shè)備無意義共五十六頁(yè)字符(z f)設(shè)備訪問控制訪問控制可以防止未授權(quán)用戶使用設(shè)備,這種控制通過設(shè)置(shzh)文件系統(tǒng)權(quán)限來實(shí)現(xiàn)最簡(jiǎn)單實(shí)現(xiàn)訪問控制是一次只允許一個(gè)進(jìn)程打開設(shè)備用一個(gè)標(biāo)志變量來指示當(dāng)前設(shè)備是否已經(jīng)被打開若已經(jīng)打開則拒絕新的打開操作共五十六頁(yè)全局標(biāo)志的競(jìng)爭(zhēng)(jngzhng)問題在上例中,如果有兩個(gè)進(jìn)程試圖同時(shí)打開(d ki)設(shè)備,則他們有可能同時(shí)測(cè)試全局標(biāo)志,并同時(shí)成功打開(d ki)。為了避免這種情況發(fā)生,我們可以以原子操作的形式修改標(biāo)志使用自旋鎖比較適合此處使用共五十六頁(yè)限制每次只有一個(gè)用戶(yngh)訪問此種實(shí)現(xiàn)允許一個(gè)用戶多次打開設(shè)備維護(hù)數(shù)據(jù)結(jié)
21、構(gòu)的完整性由用戶來完成用戶第一次打開設(shè)備時(shí)授權(quán),并記錄下設(shè)備的屬主。該用戶可以(ky)對(duì)此打開設(shè)備其他用戶試圖再打開設(shè)備時(shí),UID檢查結(jié)果會(huì)拒絕打開,并返回-EBUSY,指示設(shè)備忙共五十六頁(yè)用阻塞(zs)open代替EBUSY有些情況下,設(shè)備忙時(shí)最好讓用戶稍延遲一會(huì)兒而不是返回失敗可以用阻塞型的open來實(shí)現(xiàn)當(dāng)用戶試圖打開設(shè)備時(shí),如果設(shè)備忙,則把當(dāng)前進(jìn)程置入等待隊(duì)列當(dāng)前一個(gè)用戶使用完設(shè)備,使用計(jì)數(shù)(j sh)減到0時(shí),下一個(gè)用戶睡眠的進(jìn)程將被喚醒共五十六頁(yè)Ioctl簡(jiǎn)介(jin ji)驅(qū)動(dòng)程序支持除了標(biāo)準(zhǔn)的操作,往往還需要支持各種控制命令由此引入和一個(gè)重要(zhngyo)的命令操作機(jī)制ioct
22、lIoctl相對(duì)于使用標(biāo)準(zhǔn)I/O來控制設(shè)備有很多好處比如,不用保留特殊關(guān)鍵字符作控制控制處理代碼編寫明晰,驅(qū)動(dòng)程序和用戶程序同時(shí)受益于此共五十六頁(yè)怎樣(znyng)使用ioctl用戶應(yīng)用程序調(diào)用int ioctl(int fd, int cmd, .);設(shè)備驅(qū)動(dòng)程序里實(shí)現(xiàn)ioctl方法(fngf)int (*ioctl) (struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg);編碼上容易采用switchcase實(shí)現(xiàn)各種不同的命令處理共五十六頁(yè)Ioctl命令(mng lng)實(shí)例CDROMEJECT
23、CDROM_SET_SPEEDHDIO_SET_DMAHDIO_GET_DMA串口的ioctl,TIO族TIOCMIWAIT等等(dn dn)共五十六頁(yè)Ioctl參數(shù)(cnsh)用法如果參數(shù)是整數(shù),在驅(qū)動(dòng)的ioctl方法里面可以直接使用如果參數(shù)是指針,驅(qū)動(dòng)程序首先要檢查指針的合法性我們(w men)可以使用int access_ok(int type, const void *addr, unsigned long size);檢查通過后,我們可以使用put_user(datum, ptr)put_user(datum, ptr)這兩個(gè)宏用來訪問用戶傳遞來的指針共五十六頁(yè)Ioctl權(quán)能(qun
24、nng)和受限操作驅(qū)動(dòng)程序的訪問控制采用(ciyng)linux文件系統(tǒng)的權(quán)限機(jī)制驅(qū)動(dòng)程序采用權(quán)能機(jī)制來控制特殊的操作權(quán)限驅(qū)動(dòng)程序通過int capable(int capability);函數(shù)來確定調(diào)用進(jìn)程是否有權(quán)執(zhí)行操作共五十六頁(yè)驅(qū)動(dòng)程序當(dāng)中(dngzhng)如何實(shí)現(xiàn)ioctlioctl(,int cmd,)cmd變量存儲(chǔ)了IOCTL命令處理代碼直接判斷cmd里面的內(nèi)容,來決定(judng)程序處理分支。共五十六頁(yè)用ioctl控制驅(qū)動(dòng)程序?qū)嵗?shl)分析int scull_ioctl(struct inode *inode, struct file *filp, unsigned int
25、 cmd, unsigned long arg)int err = 0, tmp;int retval = 0; if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;if (_IOC_NR(cmd) SCULL_IOC_MAXNR) return -ENOTTY;if (_IOC_DIR(cmd) & _IOC_READ)err = !access_ok(VERIFY_WRITE, (void _user *)arg, _IOC_SIZE(cmd);else if (_IOC_DIR(cmd) & _IOC_WRITE)err = !access_ok(VERIFY_READ, (void _user *)arg, _IOC_SIZE(cmd);if (err) return -EFAULT;共五十六頁(yè)用ioctl控
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 公司晚會(huì)演出合同范例
- 微交易合同范例
- 水電工程承包合同范例
- 鳳爪貿(mào)易合同范例
- 博物館托管運(yùn)營(yíng)合同范例
- 牌樓施工合同范例
- 民間收養(yǎng)合同范例
- 中班創(chuàng)意美術(shù)課程設(shè)計(jì)
- 廣西網(wǎng)絡(luò)推廣課程設(shè)計(jì)
- 懸臂梁配筋課程設(shè)計(jì)
- 科研項(xiàng)目(課題)證明材料模板
- 2023簡(jiǎn)約黃藍(lán)平安校園知識(shí)競(jìng)賽PPT模板
- JJF 1999-2022轉(zhuǎn)子式流速儀校準(zhǔn)規(guī)范
- GB/T 39204-2022信息安全技術(shù)關(guān)鍵信息基礎(chǔ)設(shè)施安全保護(hù)要求
- JJG 736-1991氣體層流流量傳感器
- GB/T 6479-2013高壓化肥設(shè)備用無縫鋼管
- GB/T 6072.1-2008往復(fù)式內(nèi)燃機(jī)性能第1部分:功率、燃料消耗和機(jī)油消耗的標(biāo)定及試驗(yàn)方法通用發(fā)動(dòng)機(jī)的附加要求
- GB/T 17622-2008帶電作業(yè)用絕緣手套
- 企業(yè)年終總結(jié)大會(huì)PPT模板
- 2023年黑龍江公務(wù)員考試申論真題及答案
- 計(jì)量管理人員培訓(xùn)資料課件
評(píng)論
0/150
提交評(píng)論