Linuxデバイスモデル(バス、デバイス、ドライバ、クラス)の3つ:device_driver&&マルチメーカー駆動自動認識
7971 ワード
デバイスモデルは、すべてのシステムで既知のドライバを追跡します.主な目的は、ドライバコアがドライバと新しいデバイスの関係を調整できるようにすることです.システム内で既知のオブジェクトであるドライバを駆動すると、多くの作業が完了する可能性があります.ドライバの構造体device_driver定義は以下の通りです:struct device_driver{const char*name;/*ドライバの名前(sysfsに表示)*/struct bus_type*bus;/*ドライバが動作するバスタイプ*/
struct module *owner; const char *mod_name;/* used for built-in modules */
int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev);
struct attribute_group **groups;
struct pm_ops *pm; struct driver_private *p; }; (1)ドライバの登録とログアウト/*登録device_driver構造の関数は*/int driver_register(struct device_driver *drv); void driver_unregister(struct device_driver *drv); (2)ドライバの属性/*driverの属性構造:*/struct driver_attribute { struct attribute attr; ssize_t (*show)(struct device_driver *drv, char *buf); ssize_t (*store)(struct device_driver *drv, const char *buf, size_t count); }; マクロ定義DRIVER_ATTR(_name,_mode,_show,_store)の原型は:
#define DRIVER_ATTR(_name, _mode, _show, _store)\struct driver_attribute driver_attr_##_name = \__ATTR(_name, _mode, _show, _store)
そして#define_ATTR(_name,_mode,_show,_store) {\.attr = {.name = __stringify(_name), .mode = _mode },\.show = _show, \.store = _store, \}
*プロパティファイルの作成方法:*/int driver_create_file(struct device_driver * drv, struct driver_attribute * attr); void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr); (3)ドライバ構造の組み込みは、ほとんどのドライバコア構造、device_driver構造は、通常、より高いレベルのバス関連構造に組み込まれる.もちろん、高層構造体に埋め込まずに直接登録駆動するものもあります.例えばdriver_register(&wm97xx_driver). lddbusサブシステムを例にとるとldd_が定義されますdriver構造:
struct ldd_driver { char *version; struct module *module; struct device_driver driver; struct driver_attribute version_attr; }; #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver); lddbusバスに関連するドライバ登録およびログアウト関数は、static ssize_t show_version(struct device_driver *driver, char *buf) { struct ldd_driver *ldriver = to_ldd_driver(driver); sprintf(buf, "%s/n", ldriver->version); return strlen(buf); } int register_ldd_driver(struct ldd_driver *driver) //device_driverはより上位構造体{int ret;driver->driver.bus=&ldd_bus_type;ret=driver_register(&driver->driver);/*下位層のdevice_driver構造をコア*/if(ret)return ret;driver->version_attr.attr.name="version"に埋め込まれる;/* driver_attribute構造は、*/driver->version_を手動で埋め込む必要があります.attr.attr.owner = driver->module; driver->version_attr.attr.mode = S_IRUGO; driver->version_attr.show = show_version; driver->version_attr.store = NULL; return driver_create_file(&driver->driver, &driver->version_attr);/*実行時に作成されるため、DRIVER_は使用できません.ATTRマクロ*/}void unregister_ldd_driver(struct ldd_driver *driver) { driver_unregister(&driver->driver); } EXPORT_SYMBOL(register_ldd_driver); EXPORT_SYMBOL(unregister_ldd_driver);
sculldで作成されたldd_driver構造は以下の通り:/*Device model stuff*/static struct ldd_driver sculld_driver = { .version = "$Revision: 1.21 $", .module = THIS_MODULE, .driver = { .name = "sculld", }, };
=====================================================================================================================
異なるチップスキームの自動認識、例えばTPチップ、GSENSORなどの自動認識は、実際の生産と応用において必要であり、ソフトウェアのメンテナンスとリリースプロセスを大幅に簡素化する.以下の説明は、MTKのスマートマシンプラットフォームに基づいて、他のプラットフォームには適用されません.MTK自身にはデバイス駆動管理プロセスがあり、同じ種類の駆動に管理層を追加することに相当します.
(1)MTKのTPを登録するplatform_driverの場合、名前は#define TPD_DEVICE「mtk-tpd」なので、他のTP候補チップのi 2 c_driverのdriver->nameもTPDでなければなりませんDEVICE、設備の接続を便利にする.なぜ最初に変更せずにプロファイルで2つのTPモデルを同時にコンパイルすると、コンパイルエラー(実行エラーかもしれません)が発生するのですか?TPの駆動ごとにi 2 c_があるのでadd_driver、同じTPDにいるはずがない.DEVICEの名前には2つのI 2 Cデバイスが接続されています.
(2)新たな方法は、1つ目のコンパイルロードされたTPドライバにおいてリードID番号の判定を行い、正しいIDが認識されていなければ、当該チップが一致しないと認定した場合、i 2 c_を実行することであるdel_driverは、後でコンパイル実行される他のTPがTPD_に接続され続けることを保証する.DEVICEのplatform_driver.
(3)プロセス:melfasとmstarの2つのTPチップを例に、前者が後者の前にコンパイルロードされた場合、後者は変更せず、前者は一定の修正を駆動する.
単一ファイル内のグローバル変数の定義:static int i 2 c_tetect =0;
melfasのi 2 c_driverの定義は次のとおりです.
[cpp] view plain copy print ?
static struct i2c_driver tpd_i2c_driver = {
.driver = { .name = TPD_DEVICE,
.owner = THIS_MODULE, },
.probe = tpd_probe, .remove = __devexit_p(tpd_remove),
.id_table = tpd_id, .detect = tpd_detect,
.address_data = &addr_data, };
そのtpd_probeで判断し始めましたが、正しいIDは読めませんでした、i 2 c_tetect=-1;同時に、関数は-1を返します.注意:tpd_load_status = 1;は、各TP probeドライバの最後に存在する文であり、そのドライバのロードが成功したことを示す.
(4)melfasの駆動におけるローカルtpd_local_initでは、
[cpp] view plain copy print ?
if(i2c_add_driver(&tpd_i2c_driver) != 0) {
printk("melfas unable to add i2c driver."); return -1;
}//tpd_でもProbeは-1を返し、この駆動がチップを正しく認識していないことを示し、i 2 c_add_driverは必ずしも-1を返す必要はありません.
if(i 2 c_tetect!=0)/0に等しくない、tpd_probeに値を付与し、標識判断に成功しなかった {
i2c_del_driver(&tpd_i2c_driver);//i 2 c_の実行del_driver、空席を残して printk("melfas not detect .");
return -1; }
(5)MTKのTPDマネージャでは、
[cpp] view plain copy print ?
for(i = 1; i < TP_DRV_MAX_COUNT; i++) {
/* add tpd driver into list */ if(tpd_driver_list[i].tpd_device_name != NULL)
{ tpd_driver_list[i].tpd_local_init();
if(tpd_load_status ==1) { TPD_DMESG("[mtk-tpd]tpd_probe, tpd_driver_name=%s", tpd_driver_list[i].tpd_device_name);
g_tpd_drv = &tpd_driver_list[i]; break;
} }
}
各TP駆動のtpd_が順次実行されますlocal_init、tpd_のみload_statusが1のものはすでに完全なPROBEの駆動であり、すぐにサイクルを終了する.そうでなければ、次のTPのマッチング検索を続行します.もちろん、ここでもtpd_local_Init関数の戻り値を判断基準とし,PROBEは成功して0を返し,成功しない場合は-1を繰り上げる.
実際の生産において、TPの自動認識はMELFASのデバイスID番号を読み取ることによって判断され、読み取りが成功しなければMSTARのTPであるという問題があった.しかし、起動MELFASのTPが最初の起動アップグレード中に電源が切れた場合、TPが動作せずID番号も読めないため、強制アップグレードしなければTPの後続作業を保証できないという問題がある.このようにIDの読み取りが成功しない場合、2つの可能性がある.1つはMELFASのTPであり、強制的にアップグレードしなければならない.二つ目はMSTARのTPなので、プログラムの中で判断処理をしなければなりません.処理の原則は保証しなければならない.
1,MSTAR TP使用可(検証OK)2,MELFAS正常起動可(検証OK)3,MELFAS第一回起動アップグレード断電可再アップグレード可(検証OK)4,MELFAS第一回起動アップグレードは一回のみ(検証OK)
参考原文:http://blog.csdn.net/funy_liu/archive/2010/02/25/5322040.aspx
struct module *owner; const char *mod_name;/* used for built-in modules */
int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev);
struct attribute_group **groups;
struct pm_ops *pm; struct driver_private *p; }; (1)ドライバの登録とログアウト/*登録device_driver構造の関数は*/int driver_register(struct device_driver *drv); void driver_unregister(struct device_driver *drv); (2)ドライバの属性/*driverの属性構造:*/struct driver_attribute { struct attribute attr; ssize_t (*show)(struct device_driver *drv, char *buf); ssize_t (*store)(struct device_driver *drv, const char *buf, size_t count); }; マクロ定義DRIVER_ATTR(_name,_mode,_show,_store)の原型は:
#define DRIVER_ATTR(_name, _mode, _show, _store)\struct driver_attribute driver_attr_##_name = \__ATTR(_name, _mode, _show, _store)
そして#define_ATTR(_name,_mode,_show,_store) {\.attr = {.name = __stringify(_name), .mode = _mode },\.show = _show, \.store = _store, \}
*プロパティファイルの作成方法:*/int driver_create_file(struct device_driver * drv, struct driver_attribute * attr); void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr); (3)ドライバ構造の組み込みは、ほとんどのドライバコア構造、device_driver構造は、通常、より高いレベルのバス関連構造に組み込まれる.もちろん、高層構造体に埋め込まずに直接登録駆動するものもあります.例えばdriver_register(&wm97xx_driver). lddbusサブシステムを例にとるとldd_が定義されますdriver構造:
struct ldd_driver { char *version; struct module *module; struct device_driver driver; struct driver_attribute version_attr; }; #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver); lddbusバスに関連するドライバ登録およびログアウト関数は、static ssize_t show_version(struct device_driver *driver, char *buf) { struct ldd_driver *ldriver = to_ldd_driver(driver); sprintf(buf, "%s/n", ldriver->version); return strlen(buf); } int register_ldd_driver(struct ldd_driver *driver) //device_driverはより上位構造体{int ret;driver->driver.bus=&ldd_bus_type;ret=driver_register(&driver->driver);/*下位層のdevice_driver構造をコア*/if(ret)return ret;driver->version_attr.attr.name="version"に埋め込まれる;/* driver_attribute構造は、*/driver->version_を手動で埋め込む必要があります.attr.attr.owner = driver->module; driver->version_attr.attr.mode = S_IRUGO; driver->version_attr.show = show_version; driver->version_attr.store = NULL; return driver_create_file(&driver->driver, &driver->version_attr);/*実行時に作成されるため、DRIVER_は使用できません.ATTRマクロ*/}void unregister_ldd_driver(struct ldd_driver *driver) { driver_unregister(&driver->driver); } EXPORT_SYMBOL(register_ldd_driver); EXPORT_SYMBOL(unregister_ldd_driver);
sculldで作成されたldd_driver構造は以下の通り:/*Device model stuff*/static struct ldd_driver sculld_driver = { .version = "$Revision: 1.21 $", .module = THIS_MODULE, .driver = { .name = "sculld", }, };
=====================================================================================================================
異なるチップスキームの自動認識、例えばTPチップ、GSENSORなどの自動認識は、実際の生産と応用において必要であり、ソフトウェアのメンテナンスとリリースプロセスを大幅に簡素化する.以下の説明は、MTKのスマートマシンプラットフォームに基づいて、他のプラットフォームには適用されません.MTK自身にはデバイス駆動管理プロセスがあり、同じ種類の駆動に管理層を追加することに相当します.
(1)MTKのTPを登録するplatform_driverの場合、名前は#define TPD_DEVICE「mtk-tpd」なので、他のTP候補チップのi 2 c_driverのdriver->nameもTPDでなければなりませんDEVICE、設備の接続を便利にする.なぜ最初に変更せずにプロファイルで2つのTPモデルを同時にコンパイルすると、コンパイルエラー(実行エラーかもしれません)が発生するのですか?TPの駆動ごとにi 2 c_があるのでadd_driver、同じTPDにいるはずがない.DEVICEの名前には2つのI 2 Cデバイスが接続されています.
(2)新たな方法は、1つ目のコンパイルロードされたTPドライバにおいてリードID番号の判定を行い、正しいIDが認識されていなければ、当該チップが一致しないと認定した場合、i 2 c_を実行することであるdel_driverは、後でコンパイル実行される他のTPがTPD_に接続され続けることを保証する.DEVICEのplatform_driver.
(3)プロセス:melfasとmstarの2つのTPチップを例に、前者が後者の前にコンパイルロードされた場合、後者は変更せず、前者は一定の修正を駆動する.
単一ファイル内のグローバル変数の定義:static int i 2 c_tetect =0;
melfasのi 2 c_driverの定義は次のとおりです.
[cpp] view plain copy print ?
static struct i2c_driver tpd_i2c_driver =
.driver = {
.owner = THIS_MODULE,
.probe = tpd_probe,
.id_table = tpd_id,
.address_data = &addr_data,
static struct i2c_driver tpd_i2c_driver =
{
.driver = {
.name = TPD_DEVICE,
.owner = THIS_MODULE,
},
.probe = tpd_probe,
.remove = __devexit_p(tpd_remove),
.id_table = tpd_id,
.detect = tpd_detect,
.address_data = &addr_data,
};
そのtpd_probeで判断し始めましたが、正しいIDは読めませんでした、i 2 c_tetect=-1;同時に、関数は-1を返します.注意:tpd_load_status = 1;は、各TP probeドライバの最後に存在する文であり、そのドライバのロードが成功したことを示す.
(4)melfasの駆動におけるローカルtpd_local_initでは、
[cpp] view plain copy print ?
if(i2c_add_driver(&tpd_i2c_driver) != 0)
printk("melfas unable to add i2c driver.");
}//tpd_でもProbeは-1を返し、この駆動がチップを正しく認識していないことを示し、i 2 c_add_driverは必ずしも-1を返す必要はありません.
if(i 2 c_tetect!=0)/0に等しくない、tpd_probeに値を付与し、標識判断に成功しなかった
i2c_del_driver(&tpd_i2c_driver);//i 2 c_の実行del_driver、空席を残して
return -1;
if(i2c_add_driver(&tpd_i2c_driver) != 0)
{
printk("melfas unable to add i2c driver.
");
return -1;
} // tpd_probe -1, ,i2c_add_driver -1。
if(i2c_tetect!=0) // 0, tpd_probe ,
{
i2c_del_driver(&tpd_i2c_driver); // i2c_del_driver,
printk("melfas not detect .
");
return -1;
}
(5)MTKのTPDマネージャでは、
[cpp] view plain copy print ?
for(i = 1; i < TP_DRV_MAX_COUNT; i++)
/* add tpd driver into list */
{
if(tpd_load_status ==1) {
g_tpd_drv = &tpd_driver_list[i];
}
}
for(i = 1; i < TP_DRV_MAX_COUNT; i++)
{
/* add tpd driver into list */
if(tpd_driver_list[i].tpd_device_name != NULL)
{
tpd_driver_list[i].tpd_local_init();
if(tpd_load_status ==1) {
TPD_DMESG("[mtk-tpd]tpd_probe, tpd_driver_name=%s
", tpd_driver_list[i].tpd_device_name);
g_tpd_drv = &tpd_driver_list[i];
break;
}
}
}
各TP駆動のtpd_が順次実行されますlocal_init、tpd_のみload_statusが1のものはすでに完全なPROBEの駆動であり、すぐにサイクルを終了する.そうでなければ、次のTPのマッチング検索を続行します.もちろん、ここでもtpd_local_Init関数の戻り値を判断基準とし,PROBEは成功して0を返し,成功しない場合は-1を繰り上げる.
実際の生産において、TPの自動認識はMELFASのデバイスID番号を読み取ることによって判断され、読み取りが成功しなければMSTARのTPであるという問題があった.しかし、起動MELFASのTPが最初の起動アップグレード中に電源が切れた場合、TPが動作せずID番号も読めないため、強制アップグレードしなければTPの後続作業を保証できないという問題がある.このようにIDの読み取りが成功しない場合、2つの可能性がある.1つはMELFASのTPであり、強制的にアップグレードしなければならない.二つ目はMSTARのTPなので、プログラムの中で判断処理をしなければなりません.処理の原則は保証しなければならない.
1,MSTAR TP使用可(検証OK)2,MELFAS正常起動可(検証OK)3,MELFAS第一回起動アップグレード断電可再アップグレード可(検証OK)4,MELFAS第一回起動アップグレードは一回のみ(検証OK)
参考原文:http://blog.csdn.net/funy_liu/archive/2010/02/25/5322040.aspx