بيان المشكلة
يحتوي Linux على واجهة قياسية للعمل مع GPIO من خلال sysfs. يمكن العثور على وثائق ذلك
هنا .
باختصار ، هناك ملفات "تصدير" و "unexport" في مجلد "/ sys / class / gpio". من خلال كتابة الرقم X في ملف التصدير ، يمكنك فتح الواجهة في مساحة المستخدم للتحكم في GPIOX
بعد فتح الواجهة ، سيظهر المجلد / sys / class / gpio / gpioX / الذي سيكون فيه ملفات مثل "القيمة" أو "الاتجاه" ، وكتابة "في" أو "الخروج" إلى ملف "الاتجاه" وكتابة 1 أو 0 إلى الملف يمكن لـ "القيمة" التحكم في إخراج GPIO مباشرة من سطر الأوامر.
من أجل أمر "echo X> / sys / class / gpio / export" لإنشاء مجلد "gpioX" ، يجب تسجيل برنامج تشغيل وحدة تحكم GPIO في kernel ، الذي يفتح الواجهة لخطوط GPIO.
حدث ذلك أنني أعمل على نقل coreboot للوحة مخصصة تعتمد على معالج Intel Haswell i7 [بالنسبة لأولئك الذين لا يعرفون ، يعد coreboot مفتوح المصدر لمشروع BIOS مفتوح المصدر (
https://www.coreboot.org/ ) ]. تم بناء الجسر الجنوبي LynxpointLP الذي يوجد فيه 94 خط GPIO في المعالج الخاص بي. وأردت فتحها في sysfs ...
حل المشكلات (اتصال برنامج التشغيل والجهاز في Linux)
بعد بحث قصير على كود النواة ، وجدت أن برنامج التشغيل هذا قد تمت كتابته بالفعل ، موجود في ملف "drivers \ gpio \ gpio-lynxpoint.c" وتم تمكينه باستخدام Kconfig
config GPIO_LYNXPOINT tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 select GPIOLIB_IRQCHIP help driver for GPIO functionality on Intel Lynxpoint PCH chipset Requires ACPI device enumeration code to set up a platform device.
تم تمكين خيار GPIO_LYNXPOINT في النواة التي كنت أعمل معها ، ومع ذلك ، لم يكن هناك مجلد "gpiochipN" لوحدة تحكم GPIO في المجلد "/ sys / class / gpio /" (الذي يجب أن يكون كذلك) ، وحتى هذا النص لم يصدر أي خطوط.
$ for i in {0..255}; do echo $i > /sys/class/gpio/export; done
بالنظر إلى رمز coreboot أو النظر في الوثائق الخاصة بهذا الجسر الجنوبي ، يمكنك أن ترى أن وحدة تحكم GPIO ليست جهاز PCI منفصلًا. وهو جزء من جهاز PCI آخر: جسر واجهة LPC. باستخدام مسجلات مساحة التكوين PCI لهذا الجهاز ، يجب تمكين وحدة تحكم GPIO وتعيينها BASE_ADDRESS في مساحة الإدخال / الإخراج. سيؤدي هذا إلى فتح نافذة في مساحة 1KV I / O. من خلال كتابة / قراءة وحدات البايت في هذه النافذة ، يمكنك التحكم في خطوط GPIO.
ما يمكن أن نراه في رمز الأساسية:
الجسر الجنوبي \ Intel \ lynxpoint \ pch.h:
#define DEFAULT_GPIOBASE 0x1400 #define DEFAULT_GPIOSIZE 0x400 ... #define GPIO_BASE 0x48 #define GPIO_CNTL 0x4C ... #define PCH_LPC_DEV PCI_DEV(0, 0x1f, 0)
الجسر الجنوبي \ Intel \ lynxpoint \ early_pch.c:
pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE|1); pci_write_config8(PCH_LPC_DEV, GPIO_CNTL, 0x10);
إذا نظرنا إلى تسجيلات جهاز LPC في Linux من خلال "lspci -xxx" ، فسوف نرى أن البيانات التي سجلناها موجودة في هذه السجلات. لذلك يبدو أن كل شيء تم تكوينه كما ينبغي.
بمتابعة النظر إلى رمز برنامج التشغيل ، لاحظت أن برنامج تشغيل Linux يتصل بالجهاز من خلال حقل acci_match_table. نظرًا لأنه لا يمكن تعداد جهازنا (لا يوجد في PCI أو ناقل USB) ، فإنه يحتاج إلى برنامج تشغيل النظام الأساسي ، ويتم توصيل برنامج التشغيل هذا بالجهاز عبر جداول ACPI. الحالة المعتادة لـ x86 ، في حالة ARM ، سوف نسجل الجهاز في DeviceTree ، أو نستخدم الرموز الصلبة القديمة في النواة.
برامج التشغيل \ gpio \ gpio-lynxpoint.c:
static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { { "INT33C7", 0 }, { "INT3437", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); static struct platform_driver lp_gpio_driver = { .probe = lp_gpio_probe, .remove = lp_gpio_remove, .driver = { .name = "lp_gpio", .pm = &lp_gpio_pm_ops, .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), }, };
يعمل مثل هذا: إذا كانت النواة ، عند تحليل جدول ACPI ، ترى جهازًا به معرف _HID "INT33C7" ، فستحاول العثور على برنامج تشغيل النظام الأساسي له بمعرفات مطابقة في حقول البنية ".driver-> acpi_match_table".
عند العثور على تطابق ، سينفذ Linux وظيفة برنامج التشغيل .probe.
كما اتضح ، تم تقديم رمز ACPI لهذا الجهاز في coreboot ، لقد علقت عليه للتو. تم التعليق بسبب حقيقة أن Windows لهذا الجهاز لم يتمكن من العثور على برنامج التشغيل وعرض "جهاز غير معروف" في إدارة الجهاز. المزيد عن هذا أدناه.
لذلك نحن مهتمون بالمعلومات من الملف
src \ southbridge \ intel \ lynxpoint \ acpi \ serialio.asl (الرمز مبسط قليلاً):
Scope (\_SB) { Device (PCI0) { ... Device (GPIO) {
لفهم هذا الرمز بالتفصيل ، يجب أن تتعرف على بناء جملة ASL في
مواصفات ACPI .
ولكن باختصار ، ينشئ هذا الرمز جهازًا مع المعرف "INT33C7" الذي يحتوي على 2 موارد:
I/O memory: 1400-17ff; IRQ: 14;
داخل وظيفة .probe Linux ، يتلقى برنامج التشغيل موارد الجهاز المذكورة أعلاه على النحو التالي:
io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
استنادًا إلى هذه البيانات ، سيقوم رمز برنامج التشغيل بملء بنية gpio_chip وتسجيل وحدة تحكم gpio في النظام ، مما يجعلها قابلة للوصول من خلال واجهة sysfs.
بعد إرجاع رمز ASL للجهاز وإعادة تجميع صورة BIOS ، تمكن النظام من الوصول إلى GPIO من خلال sysfs.
للبدء ، ظهر المجلد "gpiochip162" في / sys / class / gpio. يحتوي هذا المجلد على ملف "base" و "ngpio". الملف الأساسي مسؤول عن رقم GPIO الأول لوحدة التحكم هذه ، ngpio عن عددها.
$ cat /sys/class/gpio/gpiochip162/base 162 $ cat /sys/class/gpio/gpiochip162/ngpio 94
وبالتالي ، تم تصدير كل شيء كما ينبغي. نقوم بتنفيذ البرنامج النصي:
$ for i in {162..255}; do echo $i > /sys/class/gpio/export; done
بعد ذلك ، ستظهر مجلدات gpioN الفرعية في المجلد / sys / class / gpio / ، حيث توجد ملفات للتحكم في حالة الخط.
زوجان من التعليقات:
- المجلد / sys / class / gpio162 / مسؤول عن إدارة GPIO0 ، المجلد / sys / class / gpio163 / مسؤول عن GPIO1 حدث هذا التحول بسبب حقيقة أن السائق أثناء تهيئة هيكل التحكم "هيكل gpio_chip" تعيين "gc-> base = -1؛". أي ، تركت النواة لأختار الأرقام بنفسي. هذا ليس حرجًا بشكل عام ، ولكن من الجدير أن نتذكره.
- يتم منح الوصول فقط لخطوط GPIO التي تم تكوينها على أنها GPIO ، وليس كميزات Southbridge الأصلية. لمثل هذه الخطوط ، يعرض برنامج التشغيل المعلومات في dmesg: "gpio٪ d محجوز لـ ACPI". في حالة Coreboot ، يتم تكوين GPIO في ملف "gpio.h" في المجلد مع اللوحة الأم.
- يمكن أيضًا تعيين الجهاز وبرنامج التشغيل باستخدام طريقة _CID (المعرّف المتوافق) ، ويتم تقديم وثائق موضوعنا في النواة في المستند "تعداد الجهاز المستند إلى ACPI"
تجدر الإشارة إلى أن جهاز INT33C7 لا يحتوي على 2 من اللوحات الأم الخاصة على نفس مجموعة الشرائح في جداول ACPI (من IBASE و DFI). صحيح ، هناك على الأرجح خطوط GPIO لا يتم إخراجها (لم أنظر إلى الوثائق في تلك اللحظة بالتفصيل).
المعرف "INT33C7"
بعد رفع وظيفة sysfs ، كان لدي سؤال ، من أين جاء رقم تعريف "INT33C7"؟
بعد النظر في وثائق طريقة _HID ، أصبح من الواضح أنه يجدر النظر في
http://www.uefi.org/PNP_ACPI_Registry_HID (معرف الجهاز)_HID (معرف الجهاز)يستخدم هذا الكائن لتزويد OSPM بمعرف PNP للجهاز أو معرف ACPI *
عند وصف النظام الأساسي ، يكون استخدام أي كائنات _HID اختياريًا. ومع ذلك ، يجب أن يكون كائن _HID
يستخدم لوصف أي جهاز سيتم تعداده بواسطة OSPM. يقوم OSPM فقط بتعداد جهاز
عندما يتعذر على عداد الحافلات اكتشاف معرف الجهاز. على سبيل المثال ، الأجهزة الموجودة على ناقل ISA هي
تم تعدادها بواسطة OSPM. استخدم كائن _ADR لوصف الأجهزة التي تم تعدادها بواسطة عد الناقل
بخلاف OSPM.
الحجج:لا يوجد
قيمة الإرجاع:عدد صحيح أو سلسلة تحتوي على HID
يتم تقييم كائن _HID إما إلى معرف نوع EISA مضغوط رقمي 32 بت أو سلسلة. إذا
السلسلة ، يجب أن يكون التنسيق عبارة عن معرف PNP أبجدي رقمي أو ACPI بدون علامة نجمية أو بادئة أخرى
الشخصيات.
يجب أن يكون معرف PNP صالحًا بالصيغة "AAA ####" حيث يكون الحرف من أحرف كبيرة و # عبارة عن سداسي
رقم. يجب أن يكون معرف ACPI صالحًا بالصيغة "NNNN ####" حيث N هو حرف كبير أو
الرقم ("0" - "9") و # عبارة عن رقم سداسي. تحتفظ هذه المواصفات بالسلسلة "ACPI" للاستخدام فقط
مع قائمة الأجهزة المحددة. تحتفظ أيضًا بجميع السلاسل التي تمثل 4 أرقام HEX لـ
الاستخدام الحصري مع معرفات البائعين المخصصة لـ PCI.
* -PNP ID و ACPI ID Registry موجودان على
http://www.uefi.org/PNP_ACPI_Registry هناك 3 نقاط على هذا الرابط:
- يشار إلى جميع أنواع معرفات الأحرف الثلاثة (PNP ID) هنا
- يشار إلى معرفات PNP التي تبدأ بـ "PNP" المحجوزة من قبل Microsoft هنا.
- يشار إلى جميع أنواع معرفات 4 أحرف (ACPI ID) هنا
ليس من الواضح لماذا ، ولكن من قائمة معرفات PNP ، يمكنك العثور على معرفات "INT" محجوزة على INTERPHASE CORPORATION:
INTERPHASE CORPORATION INT 11/29/1996
على ما يبدو ، لم يتم نشر قائمة واحدة من معرفات الجهاز الكاملة (جزء الرسالة + رقمي). ولكن بمساعدة Google ، كان من الممكن العثور على قوائم الأجهزة و _HID الخاصة بها على سبيل المثال
هنا أو
هنا .
تشير إلى:
INT33C7=Intel Serial I/O GPIO Host Controller
وإذا حكمنا من خلال بقية الأسطر من هذه القائمة ، فإن جميع أجهزة INTxxxx هي أجهزة Intel (الآن يبدو واضحًا جدًا ، ولكن الاتصال مع INTERPHASE CORPORATION لا يزال غير واضح ؛ كما أنه ليس من الواضح جدًا سبب بدء الترقيم بهذه الأرقام الكبيرة ، ولكنه مرئي على تقدير Intel).
برنامج تشغيل الاتصال والجهاز في Windows
بعد أن أرضيت فضولي ، قررت تنزيل Windows على لوحتي. كما هو متوقع ، تعذر على النظام العثور على برنامج تشغيل للجهاز. لم يكن هناك أي مساعدة من السائقين للوحات IBASE و DFI ، وهو أمر مفهوم ، لأنه في BIOS لهذه اللوحات لم تتم الإشارة إلى هذا الجهاز.
تمكنت من العثور على برنامج تشغيل
على موقع Microsoft على الويبومع ذلك ، يتم تقديم برنامج التشغيل هذا لنظام التشغيل Windows 8.1 والإصدارات الأحدث فقط. ما زلت أعمل مع Windows 7.
ومع ذلك ، حاولت تنزيل أحد برامج التشغيل وتحديد مجلده عند البحث عن برنامج تشغيل لجهازي غير المعروف.
ومع ذلك ، تعذر على المرسل تعيين برنامج التشغيل للجهاز. على الرغم من أن ملف inf يحتوي بوضوح على معلومات حول جهاز INT33C7.
[Manufacturer] %INTEL%=Intel,NTamd64.6.3 [Intel.NTamd64.6.3] %iaLPSS_GPIO.DeviceDesc_LPT%=iaLPSS_GPIO_Device, ACPI\INT33C7 %iaLPSS_GPIO.DeviceDesc_WPT%=iaLPSS_GPIO_Device, ACPI\INT3437
في عملية تحليل ملف INF ، اتضح أن قسم [الشركة المصنعة] أشار بوضوح إلى أنه غير مخصص لنظامي:
ما يعنيه Intel.NTamd64.6.3 يمكن فهمه
من الوصف :
nt[Architecture][.[OSMajorVersion][.[OSMinorVersion] OSMajorVersion=6 => Windows 7/Windows 8.1/Windows Server 2012 R2/... OSMinorVersion=3 => Windows 8.1/Windows Server 2012 R2
محاولة دفع برنامج تشغيل Windows 7 عن طريق استبدال Intel.NTamd64.6.3 بـ Intel.NTamd64.6.1 ، لوضعه بشكل معتدل ، فشل ، حيث أعطاني شاشة زرقاء للموت ونظام تشغيل غير قابل للتمهيد ، وبالتالي كان عليّ إجراء استرداد.
تم العثور على برنامج تشغيل Win7 فقط على موقع ويب غير مفهوم على الإنترنت ، وبعد ذلك يتم عرض الجهاز في إدارة الجهاز بعلامة تعجب.
أدركت ضعفه ، وقررت اختبار الوظيفة على Windows 10. كانت هناك مفاجأة سارة.
قام برنامج Intel Chipset Device Software (INF Update Utility) بتثبيت برنامج التشغيل لوحدة التحكم الخاصة بي دون أي مشاكل.

كما ترى ، هذا الجهاز لديه الموارد المخصصة

من الناحية النظرية ، بعد تثبيت برنامج التشغيل باستخدام وحدة تحكم GPIO ، من المحتمل أن يكون من الممكن العمل من خلال وظائف IOCTL (
كما هو الحال في هذا المستند) .
ومع ذلك ، لم تكن هناك مهمة برمجة GPIO من Windows ، لذلك تم تأجيل البحث عن مستند مشابه لشرائحي.
الخلاصة:
فحصت هذه المقالة الاتصال بين برنامج التشغيل والجهاز باستخدام طريقة _HID ACPI. قد يكون هذا الاتصال مطلوبًا على نظام x86 للأجهزة التي لا يمكن تعدادها.
- في حالة Linux ، يتم التواصل مع برنامج التشغيل عبر .acpi_match_table
- في حالة Windows ، يتم الاتصال ببرنامج التشغيل عبر ملف INF