class.c 添加中文註釋(1)

来源:http://www.cnblogs.com/hackfun/archive/2016/08/05/5741599.html
-Advertisement-
Play Games

註釋僅代表個人理解,僅供參考。 ...


註釋僅代表個人理解,僅供參考。

 

  1 /*
  2  * class.c - basic device class management
  3  *
  4  * Copyright (c) 2002-3 Patrick Mochel
  5  * Copyright (c) 2002-3 Open Source Development Labs
  6  * Copyright (c) 2003-2004 Greg Kroah-Hartman
  7  * Copyright (c) 2003-2004 IBM Corp.
  8  *
  9  * This file is released under the GPLv2
 10  *
 11  */
 12 
 13 #include <linux/device.h>
 14 #include <linux/module.h>
 15 #include <linux/init.h>
 16 #include <linux/string.h>
 17 #include <linux/kdev_t.h>
 18 #include <linux/err.h>
 19 #include <linux/slab.h>
 20 #include "base.h"
 21 
 22 #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
 23 #define to_class(obj) container_of(obj, struct class, subsys.kobj)
 24 
 25 static ssize_t
 26 class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 27 {
 28     /* [cgw]: 找出包含這個attr的struct class_attribute *指針 */
 29     struct class_attribute * class_attr = to_class_attr(attr);
 30     /* [cgw]: 找出包含這個kobj的struct class *指針,struct class沒有直接
 31       * 包含kobj,通過subsys.kobj間接找到struct class *指針
 32       */
 33     struct class * dc = to_class(kobj);
 34     ssize_t ret = -EIO;
 35     /* [cgw]: class_attr->show指針不為空 */
 36     if (class_attr->show)
 37         /* [cgw]: 調用class_attr->show這個方法 */
 38         ret = class_attr->show(dc, buf);
 39     return ret;
 40 }
 41 
 42 static ssize_t
 43 class_attr_store(struct kobject * kobj, struct attribute * attr,
 44          const char * buf, size_t count)
 45 {
 46     /* [cgw]: 找出包含這個attr的struct class_attribute *指針 */
 47     struct class_attribute * class_attr = to_class_attr(attr);
 48     /* [cgw]: 找出包含這個kobj的struct class *指針,struct class沒有直接
 49       * 包含kobj,通過subsys.kobj間接找到struct class *指針
 50       */
 51     struct class * dc = to_class(kobj);
 52     ssize_t ret = -EIO;
 53 
 54     /* [cgw]: class_attr->store指針不為空 */
 55     if (class_attr->store)
 56         /* [cgw]: 調用class_attr->store這個方法 */
 57         ret = class_attr->store(dc, buf, count);
 58     return ret;
 59 }
 60 
 61 static void class_release(struct kobject * kobj)
 62 {
 63     /* [cgw]: 找出包含這個kobj的struct class *指針,struct class沒有直接
 64       * 包含kobj,通過subsys.kobj間接找到struct class *指針
 65       */
 66     struct class *class = to_class(kobj);
 67 
 68     pr_debug("class '%s': release.\n", class->name);
 69 
 70     /* [cgw]: 釋放這個類的方法class->class_release指針不為空 */
 71     if (class->class_release)
 72         /* [cgw]: 調用這個方法 */
 73         class->class_release(class);
 74     else
 75         pr_debug("class '%s' does not have a release() function, "
 76              "be careful\n", class->name);
 77 }
 78 
 79 static struct sysfs_ops class_sysfs_ops = {
 80     .show    = class_attr_show,
 81     .store    = class_attr_store,
 82 };
 83 
 84 static struct kobj_type ktype_class = {
 85     .sysfs_ops    = &class_sysfs_ops,
 86     .release    = class_release,
 87 };
 88 
 89 /* Hotplug events for classes go to the class_obj subsys */
 90 static decl_subsys(class, &ktype_class, NULL);
 91 
 92 
 93 int class_create_file(struct class * cls, const struct class_attribute * attr)
 94 {
 95     int error;
 96     /* [cgw]: cls指針不為空 */
 97     if (cls) {
 98         /* [cgw]: 為cls->subsys.kobj對象創建一個屬性文件 */
 99         error = sysfs_create_file(&cls->subsys.kobj, &attr->attr);
100     } else
101         error = -EINVAL;
102     return error;
103 }
104 
105 void class_remove_file(struct class * cls, const struct class_attribute * attr)
106 {
107     /* [cgw]: cls指針不為空 */
108     if (cls)
109         /* [cgw]: 刪除cls->subsys.kobj這個對象的屬性文件 */
110         sysfs_remove_file(&cls->subsys.kobj, &attr->attr);
111 }
112 
113 static struct class *class_get(struct class *cls)
114 {
115     /* [cgw]: cls不為空 */
116     if (cls)
117         /* [cgw]: cls->subsys.kobj引用計數+1,並返回cls指針 */
118         return container_of(subsys_get(&cls->subsys), struct class, subsys);
119     return NULL;
120 }
121 
122 static void class_put(struct class * cls)
123 {
124     /* [cgw]: cls指針不為空 */
125     if (cls)
126         /* [cgw]: 實際上是cls->subsys.kobj引用計數-1 */
127         subsys_put(&cls->subsys);
128 }
129 
130 
131 static int add_class_attrs(struct class * cls)
132 {
133     int i;
134     int error = 0;
135 
136     /* [cgw]: cls->class_attrs指針不為空 */
137     if (cls->class_attrs) {
138         /* [cgw]: cls->class_attrs指向了一個struct class_attribute數組
139               * 歷遍這個數組,併為這個數組裡的每一個元素創建一個屬性
140               * 文件
141               */
142         for (i = 0; attr_name(cls->class_attrs[i]); i++) {
143             /* [cgw]: 為cls->subsys.kobj創建一個屬性文件 */
144             error = class_create_file(cls,&cls->class_attrs[i]);
145             /* [cgw]: 創建失敗 */
146             if (error)
147                 goto Err;
148         }
149     }
150  Done:
151     return error;
152  Err:
153     /* [cgw]: 逐個刪除cls->subsys.kobj對應的屬性文件列表 */
154     while (--i >= 0)
155         class_remove_file(cls,&cls->class_attrs[i]);
156     goto Done;
157 }
158 
159 static void remove_class_attrs(struct class * cls)
160 {
161     int i;
162 
163     /* [cgw]: cls->class_attrs指針不為空 */
164     if (cls->class_attrs) {
165         /* [cgw]: cls->class_attrs指向了一個struct class_attribute數組
166               * 歷遍這個數組,並刪除這個數組裡的每一個元素對應的屬
167               * 性文件
168               */
169         for (i = 0; attr_name(cls->class_attrs[i]); i++)
170             /* [cgw]: 刪除cls->subsys.kobj對應的一個屬性文件 */
171             class_remove_file(cls,&cls->class_attrs[i]);
172     }
173 }
174 
175 int class_register(struct class * cls)
176 {
177     int error;
178 
179     pr_debug("device class '%s': registering\n", cls->name);
180 
181     /* [cgw]: 初始化children鏈表 */
182     INIT_LIST_HEAD(&cls->children);
183     /* [cgw]: 初始化devices鏈表 */
184     INIT_LIST_HEAD(&cls->devices);
185     /* [cgw]: 初始化interfaces鏈表 */
186     INIT_LIST_HEAD(&cls->interfaces);
187     /* [cgw]: 初始化kset */
188     kset_init(&cls->class_dirs);
189     /* [cgw]: 初始化一個互斥信號量 */
190     init_MUTEX(&cls->sem);
191     /* [cgw]: 設置kobj的名字和類的一樣 */
192     error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name);
193     /* [cgw]: 設置kobj的名字失敗 */
194     if (error)
195         return error;
196     /* [cgw]: cls->subsys.kobj.kset指向class_subsys (kset)
197           * 實際上是分配了一個kset
198           */
199     subsys_set_kset(cls, class_subsys);
200     /* [cgw]: 註冊子系統,實際上是註冊了kset */
201     error = subsystem_register(&cls->subsys);
202     /* [cgw]: 註冊成功 */
203     if (!error) {
204         /* [cgw]: 添加類屬性 */
205         error = add_class_attrs(class_get(cls));
206         /* [cgw]: cls->subsys.kobj 引用計數-1
207           * why ???? 
208           */
209         class_put(cls);
210     }
211     return error;
212 }
213 
214 void class_unregister(struct class * cls)
215 {
216     pr_debug("device class '%s': unregistering\n", cls->name);
217     /* [cgw]: 刪除這個類的所有屬性文件 */
218     remove_class_attrs(cls);
219     /* [cgw]: 註銷這個子系統,cls->subsys.kobj */
220     subsystem_unregister(&cls->subsys);
221 }
222 
223 static void class_create_release(struct class *cls)
224 {
225     pr_debug("%s called for %s\n", __FUNCTION__, cls->name);
226     /* [cgw]: 釋放這個已分配的struct class *的記憶體空間 */
227     kfree(cls);
228 }
229 
230 static void class_device_create_release(struct class_device *class_dev)
231 {
232     pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
233     /* [cgw]: 釋放這個已分配的struct class_device *記憶體空間 */
234     kfree(class_dev);
235 }
236 
237 /* needed to allow these devices to have parent class devices */
238 static int class_device_create_uevent(struct class_device *class_dev,
239                        char **envp, int num_envp,
240                        char *buffer, int buffer_size)
241 {
242     pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
243     return 0;
244 }
245 
246 /**
247  * class_create - create a struct class structure
248  * @owner: pointer to the module that is to "own" this struct class
249  * @name: pointer to a string for the name of this class.
250  *
251  * This is used to create a struct class pointer that can then be used
252  * in calls to class_device_create().
253  *
254  * Note, the pointer created here is to be destroyed when finished by
255  * making a call to class_destroy().
256  */
257 struct class *class_create(struct module *owner, const char *name)
258 {
259     struct class *cls;
260     int retval;
261 
262     /* [cgw]: 分配sizeof(*cls)個位元組的記憶體空間 */
263     cls = kzalloc(sizeof(*cls), GFP_KERNEL);
264     /* [cgw]: 分配失敗 */
265     if (!cls) {
266         retval = -ENOMEM;
267         goto error;
268     }
269 
270     /* [cgw]: 給這個類分配一個名字 */
271     cls->name = name;
272     /* [cgw]: 這個類屬於哪個內核模塊 */
273     cls->owner = owner;
274     /* [cgw]: 分配用於釋放這個struct class類的回調 
275       * 當一個設備從這個類中移除時調用
276       */
277     cls->class_release = class_create_release;
278     /* [cgw]: 分配用於釋放這個struct class_device類的回調
279       * 當這個類本身被移除時調用
280       */
281     cls->release = class_device_create_release;
282     /* [cgw]: 註冊這個類 */
283     retval = class_register(cls);
284     /* [cgw]: 註冊失敗 */
285     if (retval)
286         goto error;
287 
288     return cls;
289 
290 error:
291     /* [cgw]: 釋放這個類 */
292     kfree(cls);
293     return ERR_PTR(retval);
294 }
295 
296 /**
297  * class_destroy - destroys a struct class structure
298  * @cls: pointer to the struct class that is to be destroyed
299  *
300  * Note, the pointer to be destroyed must have been created with a call
301  * to class_create().
302  */
303 void class_destroy(struct class *cls)
304 {
305     if ((cls == NULL) || (IS_ERR(cls)))
306         return;
307     /* [cgw]: 註銷這個類cls,這個類必須是由class_create()
308           * 創建的
309           */
310     class_unregister(cls);
311 }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • http://stackoverflow.com/questions/12426320/how-do-i-set-the-default-schema-for-a-user-in-mysql http://stackoverflow.com/questions/12426320/how-do-i-s ...
  • 題目:設有一資料庫,包括四個表:學生表(Student)、課程表(Course)、成績表(Score)以及教師信息表(Teacher)。 四個表的結構分別如表1-1的表(一)~表(四)所示,數據如表1-2的表(一)~表(四)所示。用SQL語句創建四個表並完成相關題目。 表1-1資料庫的表結構 表(一 ...
  • MySql學習筆記 ...
  • Oracle學習筆記——點滴彙總 http://www.botangdb.com/ Oracle GI = Grid Infrastructure = ASM + Cluster ...
  • 在 Oracle 中,ST_Geometry 和 ST_Raster 的 SQL 函數使用通過 Oracle 的外部過程代理(即 extproc)訪問的共用庫。要將 SQL 和 ST_Geometry 或 ST_Raster 配合使用或訪問 GDB_ITEMS_VW 和 GDB_ITEMRELATI ...
  • 1、執行環境:可以在SQLPLUS.EXE或者DOS(命令行)中執行(DOS命令可以執行是由於..\product\11.2.0\client_1\bin被設置了環境變數) 2、執行語句: 一、數據導出: 1 將資料庫TEST完全導出,用戶名system 密碼manager 導出到D:\daochu ...
  • // order by 排序 //<![CDATA[ 值 ]]> 過濾符號 //${}方式會引發SQL註入 //#{} 解析的是占位符 <![CDATA[ order by ${參數1} ${參數2} ]]> 例子: SQL:select * from A where A.id=#{id} id=h ...
  • Crontab 是 Linux 平臺下的一款用於迴圈執行例行任務的工具,Linux 系統由 cron (crond) 這個系統服務來控制任務 , Linux系統本來就有很多的計劃任務需要啟動 , 所以這個系統服務是預設開機啟動的 。 Linux 為使用者提供的計劃任務的命令就是 Crontab ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...