विक्रेता मॉड्यूल दिशानिर्देश

अपने विक्रेता मॉड्यूल की मजबूती और विश्वसनीयता बढ़ाने के लिए निम्नलिखित दिशानिर्देशों का उपयोग करें। कई दिशानिर्देशों का, जब पालन किया जाता है, तो सही मॉड्यूल लोड क्रम और ड्राइवरों को उपकरणों की जांच करने के क्रम को निर्धारित करना आसान बनाने में मदद मिल सकती है।

एक मॉड्यूल एक लाइब्रेरी या ड्राइवर हो सकता है।

  • लाइब्रेरी मॉड्यूल वे लाइब्रेरी हैं जो अन्य मॉड्यूल के उपयोग के लिए एपीआई प्रदान करती हैं। ऐसे मॉड्यूल आमतौर पर हार्डवेयर-विशिष्ट नहीं होते हैं। लाइब्रेरी मॉड्यूल के उदाहरणों में एईएस एन्क्रिप्शन मॉड्यूल, remoteproc फ्रेमवर्क जिसे मॉड्यूल के रूप में संकलित किया गया है, और एक लॉगबफ़र मॉड्यूल शामिल हैं। module_init() में मॉड्यूल कोड डेटा संरचनाओं को स्थापित करने के लिए चलता है, लेकिन कोई अन्य कोड तब तक नहीं चलता जब तक कि बाहरी मॉड्यूल द्वारा ट्रिगर न किया जाए।

  • ड्राइवर मॉड्यूल ऐसे ड्राइवर होते हैं जो एक विशिष्ट प्रकार के डिवाइस की जांच करते हैं या उससे जुड़ते हैं। ऐसे मॉड्यूल हार्डवेयर-विशिष्ट होते हैं। ड्राइवर मॉड्यूल के उदाहरणों में यूएआरटी, पीसीआईई और वीडियो एनकोडर हार्डवेयर शामिल हैं। ड्राइवर मॉड्यूल तभी सक्रिय होते हैं जब उनसे संबंधित डिवाइस सिस्टम पर मौजूद होता है।

    • यदि डिवाइस मौजूद नहीं है, तो चलने वाला एकमात्र मॉड्यूल कोड module_init() कोड है जो ड्राइवर को ड्राइवर कोर फ्रेमवर्क के साथ पंजीकृत करता है।

    • यदि डिवाइस मौजूद है और ड्राइवर सफलतापूर्वक उस डिवाइस की जांच करता है या उससे जुड़ जाता है, तो अन्य मॉड्यूल कोड चल सकता है।

मॉड्यूल init/exit का सही ढंग से उपयोग करें

ड्राइवर मॉड्यूल को module_init() में ड्राइवर पंजीकृत करना होगा और module_exit() में ड्राइवर को अपंजीकृत करना होगा। इन प्रतिबंधों को लागू करने का एक आसान तरीका रैपर मैक्रोज़ का उपयोग करना है, जो module_init() , *_initcall() , या module_exit() मैक्रोज़ के सीधे उपयोग से बचाता है।

  • अनलोड किए जा सकने वाले मॉड्यूल के लिए, module_ subsystem _driver() का उपयोग करें। उदाहरण: module_platform_driver() , module_i2c_driver() , और module_pci_driver()

  • उन मॉड्यूल के लिए जिन्हें अनलोड नहीं किया जा सकता है, builtin_ subsystem _driver() उदाहरण का उपयोग करें: builtin_platform_driver() , builtin_i2c_driver() , और builtin_pci_driver()

कुछ ड्राइवर मॉड्यूल module_init() और module_exit() का उपयोग करते हैं क्योंकि वे एक से अधिक ड्राइवर पंजीकृत करते हैं। एक ड्राइवर मॉड्यूल के लिए जो एकाधिक ड्राइवरों को पंजीकृत करने के लिए module_init() और module_exit() का उपयोग करता है, ड्राइवरों को एक ही ड्राइवर में संयोजित करने का प्रयास करें। उदाहरण के लिए, आप अलग-अलग ड्राइवरों को पंजीकृत करने के बजाय डिवाइस के compatible स्ट्रिंग या ऑक्स डेटा का उपयोग करके अंतर कर सकते हैं। वैकल्पिक रूप से, आप ड्राइवर मॉड्यूल को दो मॉड्यूल में विभाजित कर सकते हैं।

प्रारंभ और निकास फ़ंक्शन अपवाद

लाइब्रेरी मॉड्यूल ड्राइवरों को पंजीकृत नहीं करते हैं और उन्हें module_init() और module_exit() पर प्रतिबंध से छूट दी गई है क्योंकि उन्हें डेटा संरचनाओं, कार्य कतारों या कर्नेल थ्रेड्स को सेट करने के लिए इन कार्यों की आवश्यकता हो सकती है।

MODULE_DEVICE_TABLE मैक्रो का उपयोग करें

ड्राइवर मॉड्यूल में MODULE_DEVICE_TABLE मैक्रो शामिल होना चाहिए, जो मॉड्यूल लोड करने से पहले उपयोगकर्ता स्थान को ड्राइवर मॉड्यूल द्वारा समर्थित उपकरणों को निर्धारित करने की अनुमति देता है। एंड्रॉइड इस डेटा का उपयोग मॉड्यूल लोडिंग को अनुकूलित करने के लिए कर सकता है, जैसे कि उन डिवाइसों के लिए मॉड्यूल लोड करने से बचना जो सिस्टम में मौजूद नहीं हैं। मैक्रो का उपयोग करने के उदाहरणों के लिए, अपस्ट्रीम कोड देखें।

अग्रेषित-घोषित डेटा प्रकारों के कारण सीआरसी बेमेल से बचें

अग्रेषित-घोषित डेटा प्रकारों में दृश्यता प्राप्त करने के लिए हेडर फ़ाइलें शामिल न करें। हेडर फ़ाइल ( header-Ah ) में परिभाषित कुछ संरचनाएं, यूनियन और अन्य डेटा प्रकारों को एक अलग हेडर फ़ाइल ( header-Bh ) में घोषित किया जा सकता है जो आम तौर पर उन डेटा प्रकारों के लिए पॉइंटर्स का उपयोग करता है। इस कोड पैटर्न का मतलब है कि कर्नेल जानबूझकर header-Bh के उपयोगकर्ताओं के लिए डेटा संरचना को निजी रखने की कोशिश कर रहा है।

header-Bh के उपयोगकर्ताओं को इन अग्रेषित-घोषित डेटा संरचनाओं के आंतरिक तक सीधे पहुंचने के लिए header-Ah शामिल नहीं करना चाहिए। ऐसा करने से CONFIG_MODVERSIONS CRC बेमेल समस्याएँ उत्पन्न होती हैं (जो ABI अनुपालन समस्याएँ उत्पन्न करती हैं) जब कोई भिन्न कर्नेल (जैसे GKI कर्नेल) मॉड्यूल को लोड करने का प्रयास करता है।

उदाहरण के लिए, struct fwnode_handle को include/linux/fwnode.h में परिभाषित किया गया है, लेकिन इसे आगे struct fwnode_handle; include/linux/device.h में क्योंकि कर्नेल include/linux/device.h के उपयोगकर्ताओं से struct fwnode_handle के विवरण को निजी रखने का प्रयास कर रहा है। इस परिदृश्य में, struct fwnode_handle के सदस्यों तक पहुंच प्राप्त करने के लिए मॉड्यूल में #include <linux/fwnode.h> न जोड़ें। कोई भी डिज़ाइन जिसमें आपको ऐसी हेडर फ़ाइलें शामिल करनी होती हैं, एक ख़राब डिज़ाइन पैटर्न को इंगित करता है।

सीधे कोर कर्नेल संरचनाओं तक न पहुँचें

कोर कर्नेल डेटा संरचनाओं को सीधे एक्सेस करने या संशोधित करने से अवांछित व्यवहार हो सकता है, जिसमें मेमोरी लीक, क्रैश और भविष्य के कर्नेल रिलीज़ के साथ टूटी संगतता शामिल है। एक डेटा संरचना एक कोर कर्नेल डेटा संरचना होती है जब यह निम्नलिखित में से किसी भी शर्त को पूरा करती है:

  • डेटा संरचना को KERNEL-DIR /include/ के अंतर्गत परिभाषित किया गया है। उदाहरण के लिए, struct device और struct dev_links_infoinclude/linux/soc में परिभाषित डेटा संरचनाओं को छूट दी गई है।

  • डेटा संरचना को मॉड्यूल द्वारा आवंटित या आरंभ किया जाता है, लेकिन कर्नेल द्वारा निर्यात किए गए फ़ंक्शन में इनपुट के रूप में, अप्रत्यक्ष रूप से (संरचना में एक सूचक के माध्यम से) या सीधे पारित करके कर्नेल को दृश्यमान बनाया जाता है। उदाहरण के लिए, एक cpufreq ड्राइवर मॉड्यूल struct cpufreq_driver प्रारंभ करता है और फिर इसे cpufreq_register_driver() में इनपुट के रूप में पास करता है। इस बिंदु के बाद, cpufreq ड्राइवर मॉड्यूल को struct cpufreq_driver सीधे संशोधित नहीं करना चाहिए क्योंकि cpufreq_register_driver() कॉल करने से struct cpufreq_driver कर्नेल के लिए दृश्यमान हो जाता है।

  • डेटा संरचना आपके मॉड्यूल द्वारा प्रारंभ नहीं की गई है। उदाहरण के लिए, struct regulator_dev regulator_register() द्वारा लौटाया गया।

कोर कर्नेल डेटा संरचनाओं तक केवल कर्नेल द्वारा निर्यात किए गए फ़ंक्शंस के माध्यम से या विक्रेता हुक के इनपुट के रूप में स्पष्ट रूप से पारित पैरामीटर के माध्यम से पहुंचें। यदि आपके पास कोर कर्नेल डेटा संरचना के कुछ हिस्सों को संशोधित करने के लिए एपीआई या विक्रेता हुक नहीं है, तो यह संभवतः जानबूझकर है और आपको मॉड्यूल से डेटा संरचना को संशोधित नहीं करना चाहिए। उदाहरण के लिए, struct device या struct device.links के अंदर किसी भी फ़ील्ड को संशोधित न करें।

  • device.devres_head संशोधित करने के लिए, devm_*() फ़ंक्शन जैसे devm_clk_get() , devm_regulator_get() , या devm_kzalloc() का उपयोग करें।

  • struct device.links के अंदर फ़ील्ड को संशोधित करने के लिए, डिवाइस लिंक एपीआई जैसे device_link_add() या device_link_del() उपयोग करें।

संगत संपत्ति के साथ डिवाइसट्री नोड्स को पार्स न करें

यदि डिवाइस ट्री (डीटी) नोड में एक compatible संपत्ति है, तो इसके लिए एक struct device स्वचालित रूप से आवंटित किया जाता है या जब पैरेंट डीटी नोड पर of_platform_populate() को कॉल किया जाता है (आमतौर पर पैरेंट डिवाइस के डिवाइस ड्राइवर द्वारा)। डिफ़ॉल्ट अपेक्षा (अनुसूचक के लिए आरंभिक कुछ उपकरणों को छोड़कर) यह है कि compatible संपत्ति वाले डीटी नोड में एक struct device और एक मिलान डिवाइस ड्राइवर होता है। अन्य सभी अपवाद पहले से ही अपस्ट्रीम कोड द्वारा नियंत्रित किए जाते हैं।

इसके अलावा, fw_devlink (जिसे पहले of_devlink कहा जाता था) compatible संपत्ति वाले DT नोड्स को एक आवंटित struct device के साथ डिवाइस मानता है जिसे ड्राइवर द्वारा जांचा जाता है। यदि डीटी नोड में एक compatible संपत्ति है लेकिन आवंटित struct device जांच नहीं की गई है, fw_devlink अपने उपभोक्ता उपकरणों को जांच करने से रोक सकता है या अपने आपूर्तिकर्ता उपकरणों के लिए sync_state() कॉल को कॉल करने से रोक सकता है।

यदि आपका ड्राइवर एक compatible संपत्ति वाले डीटी नोड को सीधे खोजने के लिए of_find_*() फ़ंक्शन (जैसे कि of_find_node_by_name() या of_find_compatible_node() का उपयोग करता है और फिर उस DT नोड को पार्स करता है, तो एक डिवाइस ड्राइवर लिखकर मॉड्यूल को ठीक करें जो जांच कर सकता है डिवाइस या compatible संपत्ति को हटा दें (केवल तभी संभव है जब इसे अपस्ट्रीम नहीं किया गया हो)। विकल्पों पर चर्चा करने के लिए, kernel-team@android.com पर Android कर्नेल टीम से संपर्क करें और अपने उपयोग के मामलों को उचित ठहराने के लिए तैयार रहें।

आपूर्तिकर्ताओं को खोजने के लिए डीटी हैंडल का उपयोग करें

जब भी संभव हो डीटी में एक फैंडल (डीटी नोड के लिए एक संदर्भ/सूचक) का उपयोग करके आपूर्तिकर्ता को देखें। आपूर्तिकर्ताओं को संदर्भित करने के लिए मानक डीटी बाइंडिंग और फैंडल का उपयोग रनटाइम पर डीटी को पार्स करके स्वचालित रूप से अंतर-डिवाइस निर्भरता निर्धारित करने के लिए fw_devlink (पहले of_devlink ) को सक्षम बनाता है। मॉड्यूल लोड ऑर्डरिंग या MODULE_SOFTDEP() की आवश्यकता को हटाते हुए, कर्नेल स्वचालित रूप से सही क्रम में उपकरणों की जांच कर सकता है।

विरासत परिदृश्य (एआरएम कर्नेल में कोई डीटी समर्थन नहीं)

पहले, एआरएम कर्नेल में डीटी समर्थन जोड़े जाने से पहले, टच डिवाइस जैसे उपभोक्ता विश्व स्तर पर अद्वितीय स्ट्रिंग्स का उपयोग करने वाले नियामकों जैसे आपूर्तिकर्ताओं को देखते थे। उदाहरण के लिए, ACME PMIC ड्राइवर कई नियामकों को पंजीकृत या विज्ञापित कर सकता है (जैसे acme-pmic-ldo1 से acme-pmic-ldo10 ) और एक टच ड्राइवर regulator_get(dev, "acme-pmic-ldo10") उपयोग करके एक नियामक को देख सकता है। . हालाँकि, एक अलग बोर्ड पर, LDO8 टच डिवाइस की आपूर्ति कर सकता है, जिससे एक बोझिल प्रणाली बन सकती है जहाँ एक ही टच ड्राइवर को प्रत्येक बोर्ड के लिए नियामक के लिए सही लुक-अप स्ट्रिंग निर्धारित करने की आवश्यकता होती है जिसमें टच डिवाइस का उपयोग किया जाता है।

वर्तमान परिदृश्य (एआरएम कर्नेल में डीटी समर्थन)

एआरएम कर्नेल में डीटी समर्थन जोड़े जाने के बाद, उपभोक्ता फैंडल का उपयोग करके आपूर्तिकर्ता के डिवाइस ट्री नोड का संदर्भ लेकर डीटी में आपूर्तिकर्ताओं की पहचान कर सकते हैं। उपभोक्ता संसाधन का नाम इसके उपयोग के आधार पर भी रख सकते हैं, न कि इसकी आपूर्ति कौन करता है। उदाहरण के लिए, पिछले उदाहरण का टच ड्राइवर टच डिवाइस के कोर और सेंसर को पावर देने वाले आपूर्तिकर्ताओं को प्राप्त करने के लिए regulator_get(dev, "core") और regulator_get(dev, "sensor") उपयोग कर सकता है। ऐसे उपकरण के लिए संबद्ध डीटी निम्नलिखित कोड नमूने के समान है:

touch-device {
    compatible = "fizz,touch";
    ...
    core-supply = <&acme_pmic_ldo4>;
    sensor-supply = <&acme_pmic_ldo10>;
};

acme-pmic {
    compatible = "acme,super-pmic";
    ...
    acme_pmic_ldo4: ldo4 {
        ...
    };
    ...
    acme_pmic_ldo10: ldo10 {
        ...
    };
};

दोनों दुनियाओं का सबसे खराब परिदृश्य

पुराने कर्नेल से पोर्ट किए गए कुछ ड्राइवरों में डीटी में विरासत व्यवहार शामिल होता है जो विरासत योजना का सबसे खराब हिस्सा लेता है और इसे नई योजना पर मजबूर करता है जो चीजों को आसान बनाने के लिए होती है। ऐसे ड्राइवरों में, उपभोक्ता ड्राइवर डिवाइस-विशिष्ट डीटी संपत्ति का उपयोग करके लुकअप के लिए उपयोग करने के लिए स्ट्रिंग को पढ़ता है, आपूर्तिकर्ता आपूर्तिकर्ता संसाधन को पंजीकृत करने के लिए उपयोग किए जाने वाले नाम को परिभाषित करने के लिए किसी अन्य आपूर्तिकर्ता-विशिष्ट संपत्ति का उपयोग करता है, फिर उपभोक्ता और आपूर्तिकर्ता उपयोग करना जारी रखते हैं आपूर्तिकर्ता को खोजने के लिए स्ट्रिंग्स का उपयोग करने की वही पुरानी योजना। दोनों दुनियाओं के इस सबसे खराब परिदृश्य में:

  • टच ड्राइवर निम्नलिखित कोड के समान कोड का उपयोग करता है:

    str = of_property_read(np, "fizz,core-regulator");
    core_reg = regulator_get(dev, str);
    str = of_property_read(np, "fizz,sensor-regulator");
    sensor_reg = regulator_get(dev, str);
    
  • डीटी निम्नलिखित के समान कोड का उपयोग करता है:

    touch-device {
      compatible = "fizz,touch";
      ...
      fizz,core-regulator = "acme-pmic-ldo4";
      fizz,sensor-regulator = "acme-pmic-ldo4";
    };
    acme-pmic {
      compatible = "acme,super-pmic";
      ...
      ldo4 {
        regulator-name = "acme-pmic-ldo4"
        ...
      };
      ...
      acme_pmic_ldo10: ldo10 {
        ...
        regulator-name = "acme-pmic-ldo10"
      };
    };
    

फ़्रेमवर्क एपीआई त्रुटियों को संशोधित न करें

फ्रेमवर्क एपीआई, जैसे कि regulator , clocks , irq , gpio , phys और extcon , एक त्रुटि रिटर्न मान के रूप में -EPROBE_DEFER लौटाते हैं, यह इंगित करने के लिए कि एक डिवाइस जांच करने का प्रयास कर रहा है, लेकिन इस समय नहीं कर सकता है, और कर्नेल को जांच का पुन: प्रयास करना चाहिए बाद में। यह सुनिश्चित करने के लिए कि आपके डिवाइस का .probe() फ़ंक्शन ऐसे मामलों में अपेक्षा के अनुरूप विफल हो जाए, त्रुटि मान को प्रतिस्थापित या रीमैप न करें। त्रुटि मान को बदलने या पुनः मैप करने से -EPROBE_DEFER हटा दिया जा सकता है और परिणामस्वरूप आपके डिवाइस की कभी जांच नहीं हो सकेगी।

Devm_*() API वेरिएंट का उपयोग करें

जब डिवाइस devm_*() एपीआई का उपयोग करके एक संसाधन प्राप्त करता है, तो यदि डिवाइस जांच करने में विफल रहता है, या सफलतापूर्वक जांच करता है और बाद में अनबाउंड होता है, तो संसाधन स्वचालित रूप से कर्नेल द्वारा जारी किया जाता है। यह कार्यक्षमता probe() फ़ंक्शन में त्रुटि प्रबंधन कोड को क्लीनर बनाती है क्योंकि इसमें devm_*() द्वारा प्राप्त संसाधनों को जारी करने के लिए goto जंप की आवश्यकता नहीं होती है और ड्राइवर अनबाइंडिंग ऑपरेशंस को सरल बनाता है।

हैंडल डिवाइस-ड्राइवर अनबाइंडिंग

अनबाइंडिंग डिवाइस ड्राइवरों के बारे में जानबूझकर रहें और अनबाइंडिंग को अपरिभाषित न छोड़ें क्योंकि अपरिभाषित का मतलब अस्वीकृत नहीं है। आपको या तो डिवाइस-ड्राइवर अनबाइंडिंग को पूरी तरह से लागू करना होगा या डिवाइस-ड्राइवर अनबाइंडिंग को स्पष्ट रूप से अक्षम करना होगा।

डिवाइस-ड्राइवर अनबाइंडिंग लागू करना

डिवाइस-ड्राइवर अनबाइंडिंग को पूरी तरह से लागू करने का चयन करते समय, मेमोरी या संसाधन लीक और सुरक्षा समस्याओं से बचने के लिए डिवाइस ड्राइवरों को सफाई से अनबाइंड करें। आप ड्राइवर के probe() फ़ंक्शन को कॉल करके किसी डिवाइस को ड्राइवर से बाइंड कर सकते हैं और ड्राइवर के remove() फ़ंक्शन को कॉल करके किसी डिवाइस को अनबाइंड कर सकते हैं। यदि कोई remove() फ़ंक्शन मौजूद नहीं है, तो कर्नेल अभी भी डिवाइस को अनबाइंड कर सकता है; ड्राइवर कोर मानता है कि डिवाइस से अनबाइंड होने पर ड्राइवर को किसी सफाई कार्य की आवश्यकता नहीं है। एक ड्राइवर जो किसी डिवाइस से अनबाउंड है, उसे निम्नलिखित दोनों सत्य होने पर कोई स्पष्ट सफाई कार्य करने की आवश्यकता नहीं है:

  • ड्राइवर के probe() फ़ंक्शन द्वारा प्राप्त सभी संसाधन devm_*() API के माध्यम से होते हैं।

  • हार्डवेयर डिवाइस को शटडाउन या क्विसिंग अनुक्रम की आवश्यकता नहीं है।

इस स्थिति में, ड्राइवर कोर devm_*() एपीआई के माध्यम से प्राप्त सभी संसाधनों को जारी करने का प्रबंधन करता है। यदि पूर्ववर्ती कथनों में से कोई भी असत्य है, तो ड्राइवर को डिवाइस से अनबाइंड होने पर क्लीनअप (संसाधन जारी करना और हार्डवेयर बंद करना या बंद करना) करने की आवश्यकता होती है। यह सुनिश्चित करने के लिए कि कोई डिवाइस ड्राइवर मॉड्यूल को साफ़-साफ़ अनबाइंड कर सकता है, निम्न विकल्पों में से किसी एक का उपयोग करें:

  • यदि हार्डवेयर को शटडाउन या क्विज़िंग अनुक्रम की आवश्यकता नहीं है, तो devm_*() API का उपयोग करके संसाधन प्राप्त करने के लिए डिवाइस मॉड्यूल को बदलें।

  • probe() फ़ंक्शन के समान संरचना में remove() ड्राइवर ऑपरेशन को कार्यान्वित करें, फिर remove() फ़ंक्शन का उपयोग करके सफाई चरण करें।

डिवाइस-ड्राइवर अनबाइंडिंग को स्पष्ट रूप से अक्षम करना (अनुशंसित नहीं)

डिवाइस-ड्राइवर अनबाइंडिंग को स्पष्ट रूप से अक्षम करने का चयन करते समय, आपको अनबाइंडिंग को अस्वीकार करना होगा और मॉड्यूल अनलोडिंग को अस्वीकार करना होगा।

  • अनबाइंडिंग को अस्वीकार करने के लिए, ड्राइवर के struct device_driver में suppress_bind_attrs ध्वज को true पर सेट करें; यह सेटिंग bind और unbind फ़ाइलों को ड्राइवर की sysfs निर्देशिका में दिखने से रोकती है। unbind फ़ाइल वह है जो उपयोगकर्ता स्थान को उसके डिवाइस से ड्राइवर की अनबाइंडिंग को ट्रिगर करने की अनुमति देती है।

  • मॉड्यूल अनलोडिंग की अनुमति न देने के लिए, सुनिश्चित करें कि मॉड्यूल में lsmod में [permanent] है। module_exit() या module_XXX_driver() का उपयोग न करने से, मॉड्यूल को [permanent] के रूप में चिह्नित किया जाता है।

जांच फ़ंक्शन के भीतर से फर्मवेयर लोड न करें

ड्राइवर को फर्मवेयर को .probe() फ़ंक्शन के भीतर से लोड नहीं करना चाहिए क्योंकि यदि ड्राइवर फ्लैश या स्थायी स्टोरेज आधारित फ़ाइल सिस्टम माउंट होने से पहले जांच करता है तो उनके पास फर्मवेयर तक पहुंच नहीं हो सकती है। ऐसे मामलों में, request_firmware*() API लंबे समय तक अवरुद्ध हो सकता है और फिर विफल हो सकता है, जो अनावश्यक रूप से बूट प्रक्रिया को धीमा कर सकता है। इसके बजाय, फ़र्मवेयर की लोडिंग को उस समय के लिए स्थगित कर दें जब कोई क्लाइंट डिवाइस का उपयोग शुरू करता है। उदाहरण के लिए, डिस्प्ले डिवाइस खुलने पर डिस्प्ले ड्राइवर फर्मवेयर लोड कर सकता है।

फर्मवेयर लोड करने के लिए .probe() उपयोग करना कुछ मामलों में ठीक हो सकता है, जैसे कि एक क्लॉक ड्राइवर में जिसे कार्य करने के लिए फर्मवेयर की आवश्यकता होती है लेकिन डिवाइस उपयोगकर्ता स्थान के संपर्क में नहीं आता है। अन्य उपयुक्त उपयोग के मामले संभव हैं।

अतुल्यकालिक जांच कार्यान्वित करें

भविष्य के संवर्द्धन का लाभ उठाने के लिए अतुल्यकालिक जांच का समर्थन और उपयोग करें, जैसे समानांतर मॉड्यूल लोडिंग या बूट समय को तेज करने के लिए डिवाइस जांच, जिसे भविष्य के रिलीज में एंड्रॉइड में जोड़ा जा सकता है। ड्राइवर मॉड्यूल जो अतुल्यकालिक जांच का उपयोग नहीं करते हैं, ऐसे अनुकूलन की प्रभावशीलता को कम कर सकते हैं।

किसी ड्राइवर को एसिंक्रोनस जांच का समर्थन करने और प्राथमिकता देने के लिए चिह्नित करने के लिए, ड्राइवर के struct device_driver सदस्य में probe_type फ़ील्ड सेट करें। निम्नलिखित उदाहरण प्लेटफ़ॉर्म ड्राइवर के लिए सक्षम ऐसे समर्थन को दिखाता है:

static struct platform_driver acme_driver = {
        .probe          = acme_probe,
        ...
        .driver         = {
                .name   = "acme",
                ...
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
};

ड्राइवर को एसिंक्रोनस प्रोबिंग के साथ काम करने के लिए विशेष कोड की आवश्यकता नहीं होती है। हालाँकि, अतुल्यकालिक जांच समर्थन जोड़ते समय निम्नलिखित को ध्यान में रखें।

  • पहले जांच की गई निर्भरताओं के बारे में धारणाएं न बनाएं। प्रत्यक्ष या अप्रत्यक्ष रूप से जाँच करें (अधिकांश फ़्रेमवर्क कॉल) और यदि एक या अधिक आपूर्तिकर्ता अभी तक तैयार नहीं हैं तो -EPROBE_DEFER लौटाएँ।

  • यदि आप किसी मूल डिवाइस के जांच फ़ंक्शन में चाइल्ड डिवाइस जोड़ते हैं, तो यह न मानें कि चाइल्ड डिवाइस की जांच तुरंत हो गई है।

  • यदि कोई जांच विफल हो जाती है, तो उचित त्रुटि प्रबंधन करें और साफ़ करें ( devm_*() API वेरिएंट का उपयोग करें देखें)।

डिवाइस जांच का ऑर्डर देने के लिए MODULE_SOFTDEP का उपयोग न करें

MODULE_SOFTDEP() फ़ंक्शन डिवाइस जांच के क्रम की गारंटी के लिए एक विश्वसनीय समाधान नहीं है और निम्नलिखित कारणों से इसका उपयोग नहीं किया जाना चाहिए।

  • जांच टाल दी. जब कोई मॉड्यूल लोड होता है, तो डिवाइस जांच स्थगित हो सकती है क्योंकि इसका कोई आपूर्तिकर्ता तैयार नहीं है। इससे मॉड्यूल लोड ऑर्डर और डिवाइस जांच ऑर्डर के बीच बेमेल हो सकता है।

  • एक ड्राइवर, कई डिवाइस। एक ड्राइवर मॉड्यूल एक विशिष्ट डिवाइस प्रकार को प्रबंधित कर सकता है। यदि सिस्टम में डिवाइस प्रकार के एक से अधिक उदाहरण शामिल हैं और उन डिवाइसों में प्रत्येक के लिए एक अलग जांच आदेश की आवश्यकता होती है, तो आप मॉड्यूल लोड ऑर्डरिंग का उपयोग करके उन आवश्यकताओं का सम्मान नहीं कर सकते हैं।

  • अतुल्यकालिक जांच. ड्राइवर मॉड्यूल जो एसिंक्रोनस जांच करते हैं, मॉड्यूल लोड होने पर तुरंत डिवाइस की जांच नहीं करते हैं। इसके बजाय, एक समानांतर थ्रेड डिवाइस जांच को संभालता है, जिससे मॉड्यूल लोड ऑर्डर और डिवाइस जांच ऑर्डर के बीच बेमेल हो सकता है। उदाहरण के लिए, जब एक I2C मुख्य ड्राइवर मॉड्यूल अतुल्यकालिक जांच करता है और एक टच ड्राइवर मॉड्यूल PMIC पर निर्भर करता है जो I2C बस पर है, भले ही टच ड्राइवर और PMIC ड्राइवर सही क्रम में लोड हो, टच ड्राइवर की जांच का प्रयास पहले किया जा सकता है पीएमआईसी ड्राइवर जांच।

यदि आपके पास MODULE_SOFTDEP() फ़ंक्शन का उपयोग करने वाले ड्राइवर मॉड्यूल हैं, तो उन्हें ठीक करें ताकि वे उस फ़ंक्शन का उपयोग न करें। आपकी सहायता के लिए, एंड्रॉइड टीम ने अपस्ट्रीम परिवर्तन किए हैं जो कर्नेल को MODULE_SOFTDEP() उपयोग किए बिना ऑर्डरिंग समस्याओं को संभालने में सक्षम बनाते हैं। विशेष रूप से, आप जांच आदेश सुनिश्चित करने के लिए fw_devlink उपयोग कर सकते हैं और (डिवाइस के सभी उपभोक्ताओं द्वारा जांच करने के बाद) किसी भी आवश्यक कार्य को करने के लिए sync_state() कॉलबैक का उपयोग कर सकते हैं।

कॉन्फ़िगरेशन के लिए #ifdef के बजाय #if IS_ENABLED() का उपयोग करें

यह सुनिश्चित करने के लिए #ifdef CONFIG_XXX के बजाय #if IS_ENABLED(CONFIG_XXX) का उपयोग करें कि यदि कॉन्फ़िगरेशन भविष्य में ट्रिस्टेट कॉन्फ़िगरेशन में बदल जाता है तो #if ब्लॉक के अंदर का कोड संकलित होता रहे। अंतर इस प्रकार हैं:

  • #if IS_ENABLED(CONFIG_XXX) तब true का मूल्यांकन करता है जब CONFIG_XXX मॉड्यूल ( =m ) या बिल्ट-इन ( =y ) पर सेट किया जाता है।

  • #ifdef CONFIG_XXX तब true का मूल्यांकन करता है जब CONFIG_XXX बिल्ट-इन ( =y ) पर सेट किया जाता है, लेकिन जब CONFIG_XXX को मॉड्यूल ( =m ) पर सेट किया जाता है तो ऐसा नहीं होता है। इसका उपयोग केवल तभी करें जब आप निश्चित हों कि आप वही काम करना चाहते हैं जब कॉन्फ़िगरेशन मॉड्यूल पर सेट हो या अक्षम हो।

सशर्त संकलन के लिए सही मैक्रो का उपयोग करें

यदि CONFIG_XXX मॉड्यूल ( =m ) पर सेट किया गया है, तो बिल्ड सिस्टम स्वचालित रूप से CONFIG_XXX_MODULE परिभाषित करता है। यदि आपका ड्राइवर CONFIG_XXX द्वारा नियंत्रित है और आप जांचना चाहते हैं कि क्या आपका ड्राइवर एक मॉड्यूल के रूप में संकलित किया जा रहा है, तो निम्नलिखित दिशानिर्देशों का उपयोग करें:

  • आपके ड्राइवर के लिए C फ़ाइल (या कोई भी स्रोत फ़ाइल जो हेडर फ़ाइल नहीं है) में, #ifdef CONFIG_XXX_MODULE उपयोग न करें क्योंकि यह अनावश्यक रूप से प्रतिबंधात्मक है और यदि कॉन्फ़िगरेशन का नाम बदलकर CONFIG_XYZ कर दिया जाता है तो यह टूट जाता है। मॉड्यूल में संकलित किसी भी गैर-हेडर स्रोत फ़ाइल के लिए, बिल्ड सिस्टम स्वचालित रूप से उस फ़ाइल के दायरे के लिए MODULE परिभाषित करता है। इसलिए, यह जांचने के लिए कि क्या C फ़ाइल (या कोई गैर-हेडर स्रोत फ़ाइल) को मॉड्यूल के हिस्से के रूप में संकलित किया जा रहा है, #ifdef MODULE ( CONFIG_ उपसर्ग के बिना) का उपयोग करें।

  • हेडर फ़ाइलों में, वही जाँच पेचीदा है क्योंकि हेडर फ़ाइलों को सीधे बाइनरी में संकलित नहीं किया जाता है, बल्कि C फ़ाइल (या अन्य स्रोत फ़ाइलों) के भाग के रूप में संकलित किया जाता है। हेडर फ़ाइलों के लिए निम्नलिखित नियमों का उपयोग करें:

    • #ifdef MODULE का उपयोग करने वाली हेडर फ़ाइल के लिए, परिणाम इस आधार पर बदलता है कि कौन सी स्रोत फ़ाइल इसका उपयोग कर रही है। इसका मतलब यह है कि एक ही बिल्ड में एक ही हेडर फ़ाइल में अलग-अलग स्रोत फ़ाइलों (मॉड्यूल बनाम अंतर्निहित या अक्षम) के लिए संकलित कोड के विभिन्न भाग हो सकते हैं। यह तब उपयोगी हो सकता है जब आप एक मैक्रो को परिभाषित करना चाहते हैं जिसे अंतर्निहित कोड के लिए एक तरह से विस्तारित करने और मॉड्यूल के लिए एक अलग तरीके से विस्तार करने की आवश्यकता होती है।

    • एक हेडर फ़ाइल के लिए जिसे एक विशिष्ट CONFIG_XXX मॉड्यूल पर सेट होने पर कोड के एक टुकड़े में संकलित करने की आवश्यकता होती है (भले ही इसमें शामिल स्रोत फ़ाइल एक मॉड्यूल हो), हेडर फ़ाइल को #ifdef CONFIG_XXX_MODULE उपयोग करना होगा।