新しいLinuxカーネルインターフェースに関する注意-gpio uapi

カーネルバージョン4.6-r1から、gpioカーネルサブシステムと対話するための新しいインターフェイスが利用可能になりました。 現在、gpioを操作し、それらから割り込みを取得する公式の方法が3つあります。 このサブシステムのニーズを掘り下げる意味はありません。小さな部分は過酷な日常生活であり、別の部分は楽しい趣味であり、すべての点で相互作用の新しい機会がカーネルで提供されました。







このノートは本質的に人気があります。なぜなら、イノベーションに伴う主な利点、つまりカーネルのコンテキストでgpioを使用する作業の簡素化については触れないからです。







新しいuapi gpioインターフェイス



https://github.com/torvalds/linux/blob/master/include/uapi/linux/gpio.h







まず、 gpiochipは実際にはデバイスであり、 devfsではgpiochipNとして見ることができます。ここで、Nは初期化順序で割り当てられたチップ番号です。 次に、すべての構成はioctlを介して行われます 。 そして第三に、驚くべきことに、読み取りと書き込みは、特別なstruct gpiohandle_data構造の助けを借りて、読み取り/書き込み呼び出しによって行われます。







gpio-mockup



カーネルバージョンv4.9-rc1(実際にはv4.12-rc1よりも古いバージョンでのみ使用可能)以降、 debugfsによる状態管理をサポートする仮想gpioデバイスが利用可能になりました。







たとえば、ユーザー空間でのsysfsuapiの違いを考えてみましょう







gpio-mockupの初期化



パラメータ:









# modprobe gpio-mockup gpio_mockup_ranges=0,8,8,16
      
      





このチームでは、範囲が[0-8]、[8,16)の8行のgpiochipを2つ作成しました。 gpio_mockup_named_linesについては後ほど説明します。







sysfsとuapiの比較



新しいドライバーを使用して、ユーザーの観点から2つのシステムの違いを検討します。







Gpiochipの情報



sysfs



  # cat /sys/class/gpio/gpiochip*/base 0 8 # cat /sys/class/gpio/gpiochip*/ngpio 8 8 # cat /sys/class/gpio/gpiochip*/label gpio-mockup-A gpio-mockup-B
      
      





ウアピ



  struct gpiochip_info chip_info; ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info);
      
      





  # ./lsgpio | grep GPIO\ chip GPIO chip: gpiochip1, "gpio-mockup-B", 8 GPIO lines GPIO chip: gpiochip0, "gpio-mockup-A", 8 GPIO lines
      
      





行を入力として設定し、値を読み取る



sysfs



  # echo in > /sys/class/gpio/gpio0/direction # cat /sys/class/gpio/gpio0/value
      
      





ウアピ



  struct gpiohandle_request req; req.lineoffsets[0] = 0; req.flags = GPIOHANDLE_REQUEST_INPUT; req.lines = 1; struct gpiohandle_data data; ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
      
      





行を出力として設定する



sysfs



  # echo high > /sys/class/gpio/gpio0/direction
      
      





ウアピ



  struct gpiohandle_request req; req.lineoffsets[0] = 0; req.flags = GPIOHANDLE_REQUEST_OUTPUT; req.default_values[0] = 1; req.lines = 1; ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
      
      





エッジ処理



sysfs



  # echo both > /sys/class/gpio/gpio0/edge
      
      





ウアピ



  struct gpioevent_request ereq; ereq.lineoffset = 0; ereq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &ereq);
      
      





イベントのポーリング



sysfsのカーネルドキュメントでは、 EPOLLPRIおよびEPOLLERR (またはselectのexceptfds )を使用することが示されています。これは、原則として、 gpioサブシステムではなくsysfs_notifyの呼び出しで一般的です。







uapiには、EPOLLINで十分です。







  struct epoll_event event; event.data.fd = ereq.fd; event.events = EPOLLIN; epoll_ctl(epollfd, EPOLL_CTL_ADD, ereq.fd, &event);
      
      





タイムスタンプ付きのイベントを読み取り、タイプGPIOEVENT_EVENT_RISING_EDGEまたはGPIOEVENT_EVENT_FALLING_EDGEを入力します。







  struct gpioevent_data event; read(pin->fd, &event, sizeof(event));
      
      





EPOLLET for uapiは 、epollのドキュメントに従って機能します。







ラベル



sysfsについてのちょっとしたコメント



誰もが慣れている連絡先名gpioNは一般に正規ではありませんが、連絡先に名前が付けられていない場合、たとえばデバイスツリーで使用されます。







  // drivers/gpio/gpiolib-sysfs.c // int gpiod_export(struct gpio_desc *desc, bool direction_may_change) offset = gpio_chip_hwgpio(desc); if (chip->names && chip->names[offset]) ioname = chip->names[offset]; dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, ioname ? ioname : "gpio%u", desc_to_gpio(desc));
      
      





gpio_mockup_named_linesオプションを使用してgpio - mockupを試してみましょう。







  # modprobe gpio-mockup gpio_mockup_ranges=0,8,8,16 gpio_mockup_named_lines=1 # echo 0 > /sys/class/gpio/export # ls /sys/class/gpio/gpio-mockup-A-0 active_low device direction edge power subsystem uevent value
      
      





ご覧のとおり、連絡先名はgpio_chip_label - gpio_offsetになりましたが、これはgpio - mockup ドライバーにのみ当てはまります。







  // drivers/gpio/gpio-mockup.c // static int gpio_mockup_name_lines(struct device *dev, struct gpio_mockup_chip *chip) for (i = 0; i < gc->ngpio; i++) names[i] = devm_kasprintf(dev, GFP_KERNEL, "%s-%d", gc->label, i);
      
      





uapiを使用せずに連絡先の名前が存在するかどうかを事前に「推測」することはできません。 また 、名前が事前にわからない場合は、エクスポートされた「名前付き」行を見つけることは困難です(これがわかっている場合は、明確な識別のために、既知の名前とオフセットが必要です) gpiochip )。







ウアピ



uapiインターフェイスを使用すると、初期化せずに行名を表示できます。







  #./lsgpio | grep gpio-mockup-A GPIO chip: gpiochip0, "gpio-mockup-A", 8 GPIO lines line 0: "gpio-mockup-A-0" unused [output] ... line 7: "gpio-mockup-A-7" unused [output]
      
      





対応するデバイスツリーファイル(例はカーネルのドキュメントから取得):







  gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R", "LED G", "LED B", "Col A", "Col B", "Col C", "Col D", "Row A", "Row B", "Row C", "Row D", "NMI button", "poweroff", "reset";
      
      





連絡先ごとにgpioline_info構造体に名前が表示されますが、残念ながら、SBCが広く普及している場合でも、連絡先に名前を付ける人はほとんどいません。







sysfsでは利用できないUapi機能



次に、古いインターフェイスでは利用できない利点をリストします。







私が考える主な利点は、割り込みハンドラーの上半分でイベントに割り当てられるタイムスタンプです。 これは、イベント間の時間を正確に測定する必要があるアプリケーションに不可欠です。







  le->timestamp = ktime_get_real_ns();
      
      





デバイスドライバーが許可する場合、ラインはさらにオープンコレクター( GPIOLINE_FLAG_OPEN_DRAIN )またはオープンエミッター( GPIOLINE_FLAG_OPEN_SOURCE )として構成できます。このイノベーションはsysfsに簡単に転送できますが、Linus Werleyが反対しているため、これは起こりません。







また、新しいapiを使用すると、初期化中にgpiohandle_requestフィールドconsumer_labelで各連絡先にカスタムラベルを割り当てることができます。







結論として、連絡先の州のグループをすぐに「読み取り」および「書き込み」することができます。







結論の比較



主観的に、 uapisysfsよりも扱いにくいように見えますが、標準のGNUユーティリティcatおよびechoおよびCコードを介して制御を比較したことを忘れないでください。各インターフェイスのCコードを比較すると、複雑さとボリュームがほぼ同じであることがわかります。







重要な点は、 sysfsを使用する場合、ユーザーが反対を要求するか、リブートするまで、行は初期化されたままになるということです。 uapiは、ファイル記述子を閉じた直後に行を解放します。







Uapiの利点





批評UAPI



公式または非公式の批判はありません、または私はそれを見つけませんでした。 したがって、私たち自身の考えをいくつか理解しましょう。









sysfs gpioの批判



sysfsインターフェースに対する公式の批判で終わりましょう。 Linus Vaerli(カーネル内のgpioおよびpinctrlサブシステムに付属)のパッチに関するコメントで、次の論文が提案されました。









一般的に、そして正直に言うと、sysfsはユーザー空間でgpioに割り当てられたタスクにとって非常に正常だと思います。 電気工学の基礎に詳しくない人でもechoを使用してライトを点灯できると、ロマンチックなものが生まれます。 新しいインターフェイスでは、対話に追加のユーティリティが必要になるため、このような直接接続は感じられません。







しかし、GPIOはしばしばグループとして一緒に使用されます。 簡単な例(そして唯一)として、I2Cバスとして使用されるGPIOのペアを考えます。 1行はデータを処理し、もう1行はクロックを処理します。

最初の論文については何も言えません。そのようなニーズに出会ったことはありません。最終的に、連絡先をすぐにデバイスツリーの入力または出力として初期化できます 。 この機能は、 ユーザー空間ビットバンギングが必要な人にとって有用であることを知っていますが、ここには1つありますが、 純粋な Linuxでは、 ビットバンギングは非常に低周波のものにのみ可能であり、少なくともPREEMPT_RTパッチが必要です







2番目の論文も奇妙で、sysfsを無効にする必要があるほどのスペース節約は想像できません。







3番目はさらに奇妙です。アプリケーションを「クラッシュ」させる必要はないのでしょうか。







4番目については、基本的に何も本質的に変わっていないと言える。 プラットフォームドライバーまたはgpiochipのデバイスツリーラベルで指定されているものがtrueの場合、「検索」は単純であり、「hell-like」と呼ばれる場合、インターフェイスはここでは役に立ちません。







一般的に、わかりやすい答えは見つかりませんでした。 私は新しいインターフェースに反対しているわけではありませんが、それでも私はそうですが、古いインターフェースをこのように注意深く掘り下げることは個人的に理解できず、不快です。







公益事業



uapiの場合、sysfsほど多くはありません。







Linuxカーネルgpioツール



https://github.com/torvalds/linux/tree/master/tools/gpio









libgpiod



https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/







ドライバーgpio - mockupおよびirq-simの同志Bartosz'aGołaszewskiの作者から。







作成者によってライブラリとして位置付けられ、新しいuapiインターフェイスを介してgpioでの作業を容易にするために、有用なユーティリティのセットも含まれています。









素材



  1. GPIOインターフェイス(レガシー)
  2. デバイスのGPIO情報を指定する
  3. カーネルのデバイスモデルの新しい外観
  4. カーネルのデバイスモデルであるLinus Wのコメント
  5. シミュレートされた割り込み
  6. カーネルv4.6のGPIO一括変更


動画



  1. エンジニアおよびメーカー向けGPIO、Linus Walleij
  2. ユーザー空間用の新しいGPIOインターフェイス、Bartosz Golaszewski



All Articles