বিক্রেতা মডিউল নির্দেশিকা

আপনার বিক্রেতা মডিউলগুলির দৃঢ়তা এবং নির্ভরযোগ্যতা বাড়াতে নিম্নলিখিত নির্দেশিকাগুলি ব্যবহার করুন৷ অনেক নির্দেশিকা, যখন অনুসরণ করা হয়, সঠিক মডিউল লোড অর্ডার এবং ড্রাইভারকে ডিভাইসগুলির জন্য অনুসন্ধান করতে হবে এমন ক্রম নির্ধারণ করা সহজ করতে সাহায্য করতে পারে।

একটি মডিউল একটি লাইব্রেরি বা ড্রাইভার হতে পারে।

  • লাইব্রেরি মডিউল হল লাইব্রেরি যা অন্যান্য মডিউল ব্যবহারের জন্য API প্রদান করে। এই ধরনের মডিউলগুলি সাধারণত হার্ডওয়্যার-নির্দিষ্ট নয়। লাইব্রেরি মডিউলগুলির উদাহরণগুলির মধ্যে একটি AES এনক্রিপশন মডিউল, একটি মডিউল হিসাবে সংকলিত remoteproc ফ্রেমওয়ার্ক এবং একটি লগবাফার মডিউল অন্তর্ভুক্ত রয়েছে। module_init() এর মডিউল কোডটি ডেটা স্ট্রাকচার সেট আপ করার জন্য চলে, কিন্তু বাইরের মডিউল দ্বারা ট্রিগার না করা পর্যন্ত অন্য কোন কোড চলে না।

  • ড্রাইভার মডিউলগুলি এমন ড্রাইভার যা একটি নির্দিষ্ট ধরণের ডিভাইসের জন্য অনুসন্ধান বা আবদ্ধ করে। এই ধরনের মডিউলগুলি হার্ডওয়্যার-নির্দিষ্ট। ড্রাইভার মডিউলগুলির উদাহরণগুলির মধ্যে রয়েছে UART, PCIe এবং ভিডিও এনকোডার হার্ডওয়্যার। ড্রাইভার মডিউল শুধুমাত্র সক্রিয় হয় যখন তাদের সংশ্লিষ্ট ডিভাইস সিস্টেমে উপস্থিত থাকে।

    • যদি ডিভাইসটি উপস্থিত না থাকে, একমাত্র মডিউল কোড যেটি চলে তা হল 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 ম্যাক্রো অন্তর্ভুক্ত করতে হবে, যা ব্যবহারকারী স্থানকে মডিউল লোড করার আগে ড্রাইভার মডিউল দ্বারা সমর্থিত ডিভাইসগুলি নির্ধারণ করতে দেয়৷ অ্যান্ড্রয়েড মডিউল লোডিং অপ্টিমাইজ করতে এই ডেটা ব্যবহার করতে পারে, যেমন সিস্টেমে উপস্থিত নেই এমন ডিভাইসগুলির জন্য মডিউল লোড করা এড়াতে। ম্যাক্রো ব্যবহার করার উদাহরণের জন্য, আপস্ট্রিম কোড পড়ুন।

ফরওয়ার্ড-ঘোষিত ডেটা প্রকারের কারণে CRC অমিল এড়িয়ে চলুন

ফরোয়ার্ড-ঘোষিত ডেটা প্রকারগুলিতে দৃশ্যমানতা পেতে হেডার ফাইলগুলি অন্তর্ভুক্ত করবেন না। হেডার ফাইলে ( header-Ah ) সংজ্ঞায়িত কিছু স্ট্রাক্‌স, ইউনিয়ন এবং অন্যান্য ডাটা টাইপ ফরওয়ার্ড ডিক্লেয়ার করা যেতে পারে ভিন্ন হেডার ফাইলে ( header-Bh ) যা সাধারণত সেই ডাটা টাইপের পয়েন্টার ব্যবহার করে। এই কোড প্যাটার্নের অর্থ হল কার্নেল ইচ্ছাকৃতভাবে header-Bh ব্যবহারকারীদের কাছে ডেটা স্ট্রাকচার ব্যক্তিগত রাখার চেষ্টা করছে।

এই ফরোয়ার্ড-ঘোষিত ডেটা স্ট্রাকচারের অভ্যন্তরীণ সরাসরি অ্যাক্সেস করতে header-Bh এর ব্যবহারকারীদের header-Ah অন্তর্ভুক্ত করা উচিত নয়। যখন একটি ভিন্ন কার্নেল (যেমন GKI কার্নেল) মডিউলটি লোড করার চেষ্টা করে তখন এটি করার ফলে CONFIG_MODVERSIONS CRC অমিল সমস্যা (যা ABI সম্মতির সমস্যা তৈরি করে) সৃষ্টি করে।

উদাহরণস্বরূপ, 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() দ্বারা ফিরে এসেছে।

শুধুমাত্র কার্নেল দ্বারা রপ্তানিকৃত ফাংশনের মাধ্যমে বা বিক্রেতা হুকগুলিতে ইনপুট হিসাবে স্পষ্টভাবে পাস করা পরামিতির মাধ্যমে কোর কার্নেল ডেটা স্ট্রাকচার অ্যাক্সেস করুন। আপনার যদি একটি কোর কার্নেল ডেটা স্ট্রাকচারের অংশগুলি পরিবর্তন করার জন্য একটি API বা বিক্রেতা হুক না থাকে তবে এটি সম্ভবত ইচ্ছাকৃত এবং আপনার মডিউলগুলি থেকে ডেটা কাঠামো পরিবর্তন করা উচিত নয়। উদাহরণস্বরূপ, struct device বা struct device.links এর ভিতরে কোনো ক্ষেত্র পরিবর্তন করবেন না।

  • device.devres_head পরিবর্তন করতে, একটি devm_*() ফাংশন ব্যবহার করুন যেমন devm_clk_get() , devm_regulator_get() , বা devm_kzalloc()

  • struct device.links এর ভিতরে ক্ষেত্রগুলি পরিবর্তন করতে, একটি ডিভাইস লিঙ্ক API ব্যবহার করুন যেমন device_link_add() বা device_link_del()

ডিভাইসট্রি নোডগুলিকে সামঞ্জস্যপূর্ণ সম্পত্তির সাথে পার্স করবেন না

একটি ডিভাইস ট্রি (DT) নোডের একটি compatible বৈশিষ্ট্য থাকলে, একটি struct device স্বয়ংক্রিয়ভাবে এটির জন্য বরাদ্দ করা হয় বা যখন প্যারেন্ট ডিটি নোডে (সাধারণত প্যারেন্ট ডিভাইসের ডিভাইস ড্রাইভার দ্বারা) of_platform_populate() কল করা হয়। ডিফল্ট প্রত্যাশা (শিডিউলারের জন্য শুরুর দিকে শুরু করা কিছু ডিভাইস বাদে) হল যে একটি compatible বৈশিষ্ট্য সহ একটি DT নোডের একটি struct device এবং একটি ম্যাচিং ডিভাইস ড্রাইভার রয়েছে। অন্যান্য সমস্ত ব্যতিক্রম ইতিমধ্যে আপস্ট্রিম কোড দ্বারা পরিচালিত হয়।

উপরন্তু, fw_devlink (আগে বলা হত of_devlink ) compatible সম্পত্তির সাথে DT নোডকে একটি বরাদ্দকৃত struct device সাথে ডিভাইস হিসাবে বিবেচনা করে যা একজন ড্রাইভার দ্বারা অনুসন্ধান করা হয়। যদি একটি DT নোডের একটি compatible বৈশিষ্ট্য থাকে কিন্তু বরাদ্দকৃত struct device অনুসন্ধান করা না হয়, fw_devlink তার ভোক্তা ডিভাইসগুলিকে প্রোব করা থেকে ব্লক করতে পারে বা sync_state() কলগুলিকে তার সরবরাহকারী ডিভাইসগুলির জন্য কল করা থেকে ব্লক করতে পারে।

আপনার ড্রাইভার যদি একটি of_find_*() ফাংশন ব্যবহার করে (যেমন of_find_node_by_name() বা of_find_compatible_node() ) সরাসরি একটি compatible সম্পত্তি আছে এমন একটি DT নোড খুঁজে পেতে এবং তারপর সেই DT নোডটিকে পার্স করে, একটি ডিভাইস ড্রাইভার লিখে মডিউলটি ঠিক করুন যা অনুসন্ধান করতে পারে ডিভাইস বা compatible সম্পত্তি সরান (সম্ভব শুধুমাত্র যদি এটি আপস্ট্রিম করা না হয়)। বিকল্পগুলি নিয়ে আলোচনা করতে, kernel-team@android.com- এ Android কার্নেল টিমের সাথে যোগাযোগ করুন এবং আপনার ব্যবহারের ক্ষেত্রে ন্যায্যতা দেওয়ার জন্য প্রস্তুত থাকুন৷

সরবরাহকারীদের সন্ধান করতে ডিটি ফ্যান্ডেল ব্যবহার করুন

যখনই সম্ভব DT-তে ফ্যান্ডেল (ডিটি নোডের একটি রেফারেন্স/পয়েন্টার) ব্যবহার করে একজন সরবরাহকারীর সাথে যোগাযোগ করুন। সরবরাহকারীদের উল্লেখ করার জন্য স্ট্যান্ডার্ড ডিটি বাইন্ডিং এবং ফ্যান্ডেল ব্যবহার করা fw_devlink (আগে of_devlink ) কে রানটাইমে ডিটি পার্স করে স্বয়ংক্রিয়ভাবে আন্তঃ-ডিভাইস নির্ভরতা নির্ধারণ করতে সক্ষম করে। মডিউল লোড অর্ডারিং বা MODULE_SOFTDEP() এর প্রয়োজনীয়তা দূর করে কার্নেল স্বয়ংক্রিয়ভাবে সঠিক ক্রমে ডিভাইসগুলি অনুসন্ধান করতে পারে।

লিগ্যাসি দৃশ্যকল্প (এআরএম কার্নেলে কোনও ডিটি সমর্থন নেই)

পূর্বে, এআরএম কার্নেলে ডিটি সমর্থন যোগ করার আগে, টাচ ডিভাইসের মতো ভোক্তারা বিশ্বব্যাপী অনন্য স্ট্রিং ব্যবহার করে নিয়ন্ত্রকদের মতো সরবরাহকারীদের সন্ধান করত। উদাহরণস্বরূপ, ACME PMIC ড্রাইভার একাধিক নিয়ন্ত্রককে নিবন্ধন বা বিজ্ঞাপন দিতে পারে (যেমন acme-pmic-ldo1 থেকে acme-pmic-ldo10 ) এবং একজন টাচ ড্রাইভার regulator_get(dev, "acme-pmic-ldo10") ব্যবহার করে একটি নিয়ন্ত্রক খুঁজতে পারে। . যাইহোক, একটি ভিন্ন বোর্ডে, LDO8 টাচ ডিভাইস সরবরাহ করতে পারে, একটি কষ্টকর সিস্টেম তৈরি করে যেখানে একই টাচ ড্রাইভারকে প্রতিটি বোর্ডের জন্য যে টাচ ডিভাইসটি ব্যবহার করা হয় তার নিয়ন্ত্রকের জন্য সঠিক লুক-আপ স্ট্রিং নির্ধারণ করতে হবে।

বর্তমান পরিস্থিতি (এআরএম কার্নেলে ডিটি সমর্থন)

ARM কার্নেলে DT সমর্থন যোগ করার পর, গ্রাহকরা একটি ফ্যান্ডেল ব্যবহার করে সরবরাহকারীর ডিভাইস ট্রি নোড উল্লেখ করে DT-তে সরবরাহকারীদের সনাক্ত করতে পারে। কে সরবরাহ করে তার পরিবর্তে এটি কিসের জন্য ব্যবহৃত হয় তার উপর ভিত্তি করে ভোক্তারা সম্পদের নামও দিতে পারেন। উদাহরণস্বরূপ, পূর্ববর্তী উদাহরণের টাচ ড্রাইভারটি টাচ ডিভাইসের কোর এবং সেন্সরকে শক্তি প্রদানকারী সরবরাহকারীদের পেতে regulator_get(dev, "core") এবং regulator_get(dev, "sensor") ব্যবহার করতে পারে। এই জাতীয় ডিভাইসের জন্য সংশ্লিষ্ট DT নিম্নলিখিত কোড নমুনার অনুরূপ:

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 {
        ...
    };
};

উভয় জগতের সবচেয়ে খারাপ দৃশ্য

পুরানো কার্নেল থেকে পোর্ট করা কিছু ড্রাইভার DT-তে লিগ্যাসি আচরণ অন্তর্ভুক্ত করে যা লিগ্যাসি স্কিমের সবচেয়ে খারাপ অংশ নেয় এবং এটিকে নতুন স্কিমে বাধ্য করে যা জিনিসগুলিকে সহজ করার জন্য। এই ধরনের ড্রাইভারগুলিতে, ভোক্তা ড্রাইভার একটি ডিভাইস-নির্দিষ্ট ডিটি বৈশিষ্ট্য ব্যবহার করে সন্ধানের জন্য ব্যবহার করার জন্য স্ট্রিংটি পড়েন, সরবরাহকারী সংস্থান নিবন্ধন করার জন্য ব্যবহার করা নামটি সংজ্ঞায়িত করতে সরবরাহকারী অন্য সরবরাহকারী-নির্দিষ্ট সম্পত্তি ব্যবহার করে, তারপর ভোক্তা এবং সরবরাহকারী ব্যবহার চালিয়ে যান সরবরাহকারীর সন্ধান করতে স্ট্রিং ব্যবহার করার একই পুরানো স্কিম। এই উভয় বিশ্বের সবচেয়ে খারাপ পরিস্থিতিতে:

  • টাচ ড্রাইভার নিম্নলিখিত কোডের অনুরূপ কোড ব্যবহার করে:

    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);
    
  • DT নিম্নলিখিত অনুরূপ কোড ব্যবহার করে:

    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"
      };
    };
    

ফ্রেমওয়ার্ক API ত্রুটিগুলি সংশোধন করবেন না৷

ফ্রেমওয়ার্ক এপিআই, যেমন regulator , clocks , irq , gpio , phys , এবং extcon , রিটার্ন -EPROBE_DEFER একটি ত্রুটি রিটার্ন মান হিসাবে নির্দেশ করে যে একটি ডিভাইস অনুসন্ধানের চেষ্টা করছে কিন্তু এই সময়ে করতে পারছে না, এবং কার্নেলকে পুনরায় প্রোবের চেষ্টা করা উচিত পরে এই ধরনের ক্ষেত্রে আপনার ডিভাইসের .probe() ফাংশন প্রত্যাশিতভাবে ব্যর্থ হয়েছে তা নিশ্চিত করতে, ত্রুটির মান প্রতিস্থাপন বা রিম্যাপ করবেন না। ত্রুটির মানটি প্রতিস্থাপন বা রিম্যাপ করার ফলে -EPROBE_DEFER বাদ দেওয়া হতে পারে এবং এর ফলে আপনার ডিভাইস কখনই অনুসন্ধান করা হবে না।

devm_*() API ভেরিয়েন্ট ব্যবহার করুন

ডিভাইসটি যখন devm_*() API ব্যবহার করে একটি রিসোর্স অর্জন করে, ডিভাইসটি অনুসন্ধানে ব্যর্থ হলে, অথবা সফলভাবে অনুসন্ধান করতে ব্যর্থ হলে এবং পরে আনবাউন্ড হলে রিসোর্সটি কার্নেল দ্বারা স্বয়ংক্রিয়ভাবে প্রকাশিত হয়। এই কার্যকারিতা probe() ক্লিনারে ত্রুটি হ্যান্ডলিং কোড তৈরি করে কারণ এতে devm_*() দ্বারা অর্জিত সংস্থানগুলি প্রকাশ করতে goto jumps প্রয়োজন হয় না এবং ড্রাইভার আনবাইন্ডিং ক্রিয়াকলাপগুলিকে সহজ করে তোলে।

ডিভাইস ড্রাইভার আনবাইন্ডিং হ্যান্ডেল

ডিভাইস ড্রাইভার আনবাইন্ডিং সম্পর্কে ইচ্ছাকৃত হোন এবং আনবাইন্ডিংকে অনির্ধারিত ছেড়ে দেবেন না কারণ অনির্ধারিত মানে অননুমোদিত নয়। আপনাকে অবশ্যই ডিভাইস-ড্রাইভার আনবাইন্ডিং সম্পূর্ণরূপে বাস্তবায়ন করতে হবে অথবা ডিভাইস-ড্রাইভার আনবাইন্ডিংকে স্পষ্টভাবে অক্ষম করতে হবে।

ডিভাইস-ড্রাইভার আনবাইন্ডিং বাস্তবায়ন করা

ডিভাইস-ড্রাইভার আনবাইন্ডিং সম্পূর্ণরূপে প্রয়োগ করার সময়, মেমরি বা রিসোর্স লিক এবং নিরাপত্তা সমস্যা এড়াতে ডিভাইস ড্রাইভারকে পরিষ্কারভাবে আনবাইন্ড করুন। ড্রাইভারের probe() ফাংশন কল করে আপনি একটি ডিভাইসকে ড্রাইভারের সাথে আবদ্ধ করতে পারেন এবং ড্রাইভারের remove() ফাংশন কল করে একটি ডিভাইস আনবাইন্ড করতে পারেন। যদি কোনো remove() ফাংশন না থাকে, কার্নেল এখনও ডিভাইসটিকে আনবাইন্ড করতে পারে; ড্রাইভার কোর অনুমান করে যে ডিভাইস থেকে আনবাইন্ড করার সময় ড্রাইভারের দ্বারা কোনও পরিষ্কার কাজের প্রয়োজন নেই। একটি ডিভাইস থেকে আনবাউন্ড থাকা ড্রাইভারকে যখন নিচের দুটিই সত্য হয় তখন তাকে কোনো স্পষ্ট পরিষ্কারের কাজ করতে হবে না:

  • ড্রাইভারের probe() ফাংশন দ্বারা অর্জিত সমস্ত সংস্থান devm_*() API-এর মাধ্যমে হয়।

  • হার্ডওয়্যার ডিভাইসের একটি শাটডাউন বা শান্ত ক্রম প্রয়োজন হয় না।

এই পরিস্থিতিতে, ড্রাইভার কোর devm_*() API-এর মাধ্যমে অর্জিত সমস্ত সংস্থান প্রকাশ করে। যদি পূর্ববর্তী বিবৃতিগুলির মধ্যে কোনটিই অসত্য হয়, ড্রাইভারকে ক্লিনআপ করতে হবে (রিলিজ রিসোর্স এবং হার্ডওয়্যারটি বন্ধ বা শান্ত করা) যখন এটি একটি ডিভাইস থেকে আনবাইন্ড হয়। একটি ডিভাইস একটি ড্রাইভার মডিউল পরিষ্কারভাবে আনবাইন্ড করতে পারে তা নিশ্চিত করতে, নিম্নলিখিত বিকল্পগুলির মধ্যে একটি ব্যবহার করুন:

  • যদি হার্ডওয়্যারের শাটডাউন বা স্তব্ধ ক্রম প্রয়োজন না হয়, তাহলে devm_*() API ব্যবহার করে সংস্থানগুলি অর্জন করতে ডিভাইস মডিউল পরিবর্তন করুন।

  • probe() ফাংশনের মতো একই struct-এ remove() ড্রাইভার অপারেশন প্রয়োগ করুন, তারপর remove() ফাংশন ব্যবহার করে ক্লিন আপ পদক্ষেপগুলি করুন।

স্পষ্টভাবে ডিভাইস-ড্রাইভার আনবাইন্ডিং অক্ষম করা (প্রস্তাবিত নয়)

ডিভাইস-ড্রাইভার আনবাইন্ডিংকে স্পষ্টভাবে অক্ষম করার সময়, আপনাকে আনবাইন্ডিংকে অস্বীকৃতি এবং মডিউল আনলোড করার অনুমতি দিতে হবে।

  • আনবাইন্ডিং অনুমোদন না করার জন্য, ড্রাইভারের struct device_driversuppress_bind_attrs পতাকাটিকে true হিসাবে সেট করুন; এই সেটিংটি ড্রাইভারের sysfs ডিরেক্টরিতে ফাইলগুলিকে bind এবং unbind বাধা দেয়। 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 প্রধান ড্রাইভার মডিউল অ্যাসিঙ্ক্রোনাস প্রোবিং সঞ্চালন করে এবং একটি টাচ ড্রাইভার মডিউল I2C বাসে থাকা PMIC-এর উপর নির্ভর করে, এমনকি যদি টাচ ড্রাইভার এবং PMIC ড্রাইভার সঠিক ক্রমে লোড করে, টাচ ড্রাইভারের প্রোব আগে চেষ্টা করা যেতে পারে। PMIC ড্রাইভার তদন্ত।

আপনার যদি MODULE_SOFTDEP() ফাংশন ব্যবহার করে ড্রাইভার মডিউল থাকে, তাহলে সেগুলি ঠিক করুন যাতে তারা সেই ফাংশনটি ব্যবহার না করে। আপনাকে সাহায্য করার জন্য, অ্যান্ড্রয়েড টিম আপস্ট্রিম পরিবর্তন করেছে যা কার্নেলকে MODULE_SOFTDEP() ব্যবহার না করেই অর্ডারিং সমস্যাগুলি পরিচালনা করতে সক্ষম করে। বিশেষভাবে, আপনি fw_devlink ব্যবহার করে প্রোবের অর্ডার নিশ্চিত করতে পারেন এবং (একটি ডিভাইসের সমস্ত গ্রাহকরা অনুসন্ধান করার পরে) যেকোনো প্রয়োজনীয় কাজ সম্পাদন করতে sync_state() কলব্যাক ব্যবহার করতে পারেন।

কনফিগারেশনের জন্য #ifdef এর পরিবর্তে #if IS_ENABLED() ব্যবহার করুন

ভবিষ্যতে যদি কনফিগারেশনটি ট্রাস্টেট কনফিগারেশনে পরিবর্তিত হয় তাহলে #if ব্লকের ভিতরের কোডটি কম্পাইল করা অব্যাহত থাকে তা নিশ্চিত করতে #ifdef CONFIG_XXX এর পরিবর্তে #if IS_ENABLED(CONFIG_XXX) ব্যবহার করুন। পার্থক্যগুলি নিম্নরূপ:

  • #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 ব্যবহার করতে হবে।