4 一樣的精靈,不一樣的API(2)

2021-06-18 09:28:36 字數 3576 閱讀 2307

4.一樣的精靈,不一樣的api(2)

關於核心空間,我只想說,所有的驅動程式都是執行在核心空間的,核心空間雖然很大,但總是有限的。而在這有限的空間中,其最後乙個page是專門保留的,也就是說,一般人不可能用到核心空間最後乙個page的指標。

換句話說,你在寫裝置驅動程式的過程中,涉及的任何乙個指標,必然有三種情況:一種是有效指標,一種是null(空指標),還有一種是錯誤指標,或者說無效指標。而所謂的錯誤指標就是指其已經到達了最後乙個page。比如對於32bit的系統來說,核心空間最高位址0xffffffff,那麼最後乙個page就是指的0xfffff000~0xffffffff(假設4kb乙個page)。這段位址是被保留的,一般人不得越雷池半步,如果你發現你的乙個指標指向這個範圍中的某個位址,那麼恭喜你,你的**肯定出錯了。

那麼你是不是很好奇,好端端的核心空間幹嘛要留出最後乙個page?這不是明明自己有1000塊錢,非得對自己說只能用900塊。實在不好意思,你說錯了,這裡不僅不是浪費乙個page,反而是充分利用資源,把乙個東西當兩個東西來用。

看見16行那個"max_errno"了嗎?乙個巨集,定義為4095,max_errno就是最大錯誤號,linux核心中,出錯有多種可能,因為有許許多多種錯誤。關於linux核心中的錯誤,我們看include/asm-generic/errno-base.h檔案:

#define eperm            1      /* operation not permitted */  

#define enoent           2      /* no such file or directory */  

#define esrch            3      /* no such process */  

#define eintr            4      /* interrupted system call */  

#define eio              5      /* i/o error */  

#define enxio            6      /* no such device or address */  

#define e2big            7      /* argument list too long */  

#define enoexec          8      /* exec format error */  

#define ebadf            9      /* bad file number */  

#define echild          10      /* no child processes */  

#define eagain          11      /* try again */  

#define enomem          12      /* out of memory */  

#define eacces          13      /* permission denied */  

#define efault          14      /* bad address */  

#define enotblk         15      /* block device required */  

#define ebusy           16      /* device or resource busy */  

#define eexist          17      /* file exists */  

#define exdev           18      /* cross-device link */  

#define enodev          19      /* no such device */  

#define enotdir         20      /* not a directory */  

#define eisdir          21      /* is a directory */  

#define einval          22      /* invalid argument */  

#define enfile          23      /* file table overflow */  

#define emfile          24      /* too many open files */  

#define enotty          25      /* not a typewriter */  

#define etxtbsy         26      /* text file busy */  

#define efbig           27      /* file too large */  

#define enospc          28      /* no space left on device */  

#define espipe          29      /* illegal seek */  

#define erofs           30      /* read-only file system */  

#define emlink          31      /* too many links */  

#define epipe           32      /* broken pipe */  

#define edom            33      /* math argument out of domain of func */  

#define erange          34      /* math result not representable */  

最常見的幾個是-ebusy、-einval、-enodev、-epipe、-eagain、-enomem,我相信只要你使用過linux就有可能見過這幾個錯誤,因為它們確實經常出現。

這些是每個體系結構中都有的,另外各個體系結構也都定義了自己的一些錯誤**。這些東西當然也都是巨集,實際上對應的是一些數字,這些數字就叫做錯誤號。而對於linux核心來說,不管任何體系結構,錯誤號最多不會超過4095,而4095又正好是比4kb小1,即4096-1。而我們知道乙個page可能是4kb,也可能是更多,比如8kb,但至少它也是4kb,所以留出乙個page出來就可以讓我們把核心空間的指標來記錄錯誤了。

什麼意思呢?比如我們這裡的is_err(),它就是判斷kthread_run()返回的指標是否有錯,如果指標並不是指向最後乙個page,那麼沒有問題,申請成功了,如果指標指向了最後乙個page,那麼說明實際上這不是乙個有效的指標,這個指標裡儲存的實際上是一種錯誤**。而通常很常用的方法就是先用is_err()來判斷是否是錯誤,然後如果是,那麼就呼叫ptr_err()來返回這個錯誤**。只不過這裡沒有呼叫ptr_err()而已,因為起決定作用的還是is_err(),而ptr_err()只是返回錯誤**,也就是提供乙個資訊給呼叫者,如果你只需要知道是否出錯,而不在乎因為什麼而出錯,那你當然不用呼叫ptr_err()了。當然,這裡如果出錯了的話,最終usb_deregister()會被呼叫,並且usb_hub_init()會返回-1。

4 一樣的精靈,不一樣的API(1)

4 一樣的精靈,不一樣的api 1 usb register 這個函式是用來向usb核心層,即usb core,註冊乙個usb裝置驅動的,而這裡我們註冊的是hub的驅動程式所對應的struct usb driver結構體變數。定義於drivers usb core hub.c中 2841 stati...

不一樣又不一樣的 木板接水

空地上豎立著n個從左到右排列的木板,它們可以把水擋住,但溢位最邊上木板的水將會流到空地上。已知木板間距都是單位1,現給定每個木板的高度,請求出總共能接住的水量?說明一點,這裡只考慮間距 寬度 和高度,不考慮第三個維度,因此水量是平方單位。木板高度分別是2,1,3,那麼我們可以接住2 2 4平方單位的...

一樣的月亮,不一樣的心情

轉眼間,又是一年的中秋佳節,這都是乙個懷鄉思親的節日,自從讀書和工作後,就很難有機會和父母 兄弟姐妹一起過了,在這個只掛燈籠但毫無節日氛圍的城市裡,你可以看到許許多多偽裝的慶祝和喜悅,一樣的月亮一樣的月光一樣的月餅,但心情卻是千差萬別,各顯千秋,最可憐的就是小朋友們了,他們失去了各種自然的 純樸的 ...