summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md235
1 files changed, 235 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5efdcef
--- /dev/null
+++ b/README.md
@@ -0,0 +1,235 @@
+# gpio-cdev
+
+[![Build Status](https://github.com/rust-embedded/gpio-cdev/workflows/Build/badge.svg)](https://github.com/rust-embedded/gpio-cdev/actions)
+[![Version](https://img.shields.io/crates/v/gpio-cdev.svg)](https://crates.io/crates/gpio-cdev)
+[![License](https://img.shields.io/crates/l/gpio-cdev.svg)](https://github.com/rust-embedded/gpio-cdev/blob/master/README.md#license)
+
+- [API Documentation](https://docs.rs/gpio-cdev)
+
+rust-gpio-cdev is a Rust library/crate providing access to [GPIO character device
+ABI](https://www.kernel.org/doc/Documentation/ABI/testing/gpio-cdev). This API,
+stabilized with Linux v4.4, deprecates the legacy sysfs interface to GPIOs that is
+planned to be removed from the upstream kernel after
+year 2020 (which is coming up quickly).
+
+Use of this API is encouraged over the sysfs API used by this crate's
+predecessor [sysfs_gpio](https://crates.io/crates/sysfs_gpio) if you don't need
+to target older kernels. For more information on differences see [Sysfs GPIO vs
+GPIO Character Device](#sysfs-gpio-vs-gpio-character-device).
+
+## Installation
+
+Add the following to your `Cargo.toml`
+
+```
+[dependencies]
+gpio-cdev = "0.4"
+```
+
+Note that the following features are available:
+
+* `async-tokio`: Adds a Stream interface for consuming GPIO events in async code
+ within a tokio runtime.
+
+## Examples
+
+There are several additional examples available in the [examples
+directory](https://github.com/rust-embedded/rust-gpio-cdev/tree/master/examples).
+
+### Read State
+
+```rust
+use gpio_cdev::{Chip, LineRequestFlags};
+
+// Read the state of GPIO4 on a raspberry pi. /dev/gpiochip0
+// maps to the driver for the SoC (builtin) GPIO controller.
+let mut chip = Chip::new("/dev/gpiochip0")?;
+let handle = chip
+ .get_line(4)?
+ .request(LineRequestFlags::INPUT, 0, "read-input")?;
+for _ in 1..4 {
+ println!("Value: {:?}", handle.get_value()?);
+}
+```
+
+### Mirror State (Read/Write)
+
+```rust
+use gpio_cdev::{Chip, LineRequestFlags, EventRequestFlags, EventType};
+
+// Lines are offset within gpiochip0; see docs for more info on chips/lines
+//
+// This function will synchronously follow the state of one line
+// on gpiochip0 and mirror its state on another line. With this you
+// could, for instance, control the state of an LED with a button
+// if hooked up to the right pins on a raspberry pi.
+fn mirror_gpio(inputline: u32, outputline: u32) -> Result<(), gpio_cdev::Error> {
+ let mut chip = Chip::new("/dev/gpiochip0")?;
+ let input = chip.get_line(inputline)?;
+ let output = chip.get_line(outputline)?;
+ let output_handle = output.request(LineRequestFlags::OUTPUT, 0, "mirror-gpio")?;
+ for event in input.events(
+ LineRequestFlags::INPUT,
+ EventRequestFlags::BOTH_EDGES,
+ "mirror-gpio",
+ )? {
+ let evt = event?;
+ println!("{:?}", evt);
+ match evt.event_type() {
+ EventType::RisingEdge => {
+ output_handle.set_value(1)?;
+ }
+ EventType::FallingEdge => {
+ output_handle.set_value(0)?;
+ }
+ }
+ }
+
+ Ok(())
+}
+```
+
+### Async Usage
+
+Note that this requires the addition of the `async-tokio` feature.
+
+```rust
+use futures::stream::StreamExt;
+use gpio_cdev::{Chip, AsyncLineEventHandle};
+
+async fn gpiomon(chip: String, line: u32) -> gpio_cdev::Result<()> {
+ let mut chip = Chip::new(args.chip)?;
+ let line = chip.get_line(args.line)?;
+ let mut events = AsyncLineEventHandle::new(line.events(
+ LineRequestFlags::INPUT,
+ EventRequestFlags::BOTH_EDGES,
+ "gpioevents",
+ )?)?;
+
+ while let Some(event) = events.next().await {
+ let event = event?;
+ println!("GPIO Event: {:?}", event);
+ }
+
+ Ok(())
+}
+```
+
+## Sysfs GPIO vs GPIO Character Device
+
+Compared to the sysfs gpio interface (as made available by the sysfs_gpio crate)
+the character device has several advantages and critical design differences
+(some of which are driving the deprecation in the kernel).
+
+Since many people are familiar with the sysfs interface (which is easily
+accessible via basic commands in the shell) and few people are familiar with the
+GPIO character device, an exploration of the two and key differences here may
+prove useful.
+
+### Getting Access to a GPIO
+
+In the Linux kernel, individual GPIOs are exposed via drivers that on probe register
+themselves as GPIO chips with the gpio subsystem. Each of these chips provides
+access to a set of GPIOs. At present, when this chip is registered a global
+base number is assigned to this driver. The comments from the linux kernel
+[`gpio_chip_add_data`](https://elixir.bootlin.com/linux/v4.9.85/source/drivers/gpio/gpiolib.c#L1087)
+sum up the situation nicely when assigning the a base number to a GPIO chip
+on registration.
+
+ /*
+ * TODO: this allocates a Linux GPIO number base in the global
+ * GPIO numberspace for this chip. In the long run we want to
+ * get *rid* of this numberspace and use only descriptors, but
+ * it may be a pipe dream. It will not happen before we get rid
+ * of the sysfs interface anyways.
+ */
+
+The entire sysfs interface to GPIO is based around offsets from the base number
+assigned to a GPIO chip. The base number is completely dependent on the order
+in which the chip was registered with the subsystem and the number of GPIOs that
+each of the previous chips registered. The only reason this is usable at all is
+that most GPIOs are accessed via SoC hardware that is registered consistently
+during boot. It's not great; in fact, it's not even good.
+
+The GPIO character device ABI provides access to GPIOs owned by a GPIO chip via
+a bus device, `/sys/bus/gpiochipN` (or `/dev/gpiochipN`). Within a chip, the
+programmer will still need to know some details about how to access the GPIO but
+things are generally sane. Figuring out which bus device is the desired GPIO
+chip can be done by iterating over all that are present and/or setting up
+appropriate udev rules. One good example of this is the [`lsgpio` utility in
+the kernel source](https://github.com/torvalds/linux/blob/master/tools/gpio/lsgpio.c).
+
+In sysfs each GPIO within a chip would be exported and used individually. The
+GPIO character device allows for one or more GPIOs (referenced via offsets) to
+be read, written, configured, and monitored via a "linehandle" fd that is
+created dynamically on request.
+
+### "Exporting" a GPIO
+
+Using the sysfs API, one would write the global GPIO number to the "export" file
+to perform further operations using new files on the filesystem. Using the
+gpiochip character device, a handle for performing operations on one or more
+GPIO offsets within a chip are available via a "linehandle" fd created using the
+`GPIO_GET_LINEHANDLE_IOCTL`. A consequence of this is that a line will remember
+its state only for as long as the fd is open; the line's state will be reset
+once the fd is closed.
+
+When a linehandle is requested, additional information is also included about
+how the individual GPIOs will be used (input, output, as-is, active-low, open
+drain, open source, etc). Multiple lines can be grouped together in a single
+request but they must all be configured the same way if being used in that way.
+See `struct gpioevent_request`.
+
+### Reading/Writing GPIOs
+
+Via sysfs, GPIOs could be read/written using the value file. For GPIO character
+devices, the `GPIOHANDLE_GET_LINE_VALUES_IOCTL` and
+`GPIOHANDLE_SET_LINE_VALUES_IOCTL` may be used to get/set the state of one or
+more offsets within the chip.
+
+### Input Events
+
+Via sysfs, one could setup things up using the trigger file to notify userspace
+(by polling on the value file) of a single event based on how things were setup.
+With GPIO character devices, one can setup a `gpio_eventrequest` that will create
+a new anonymous file (fd provided) for event notifications on a lines within a
+gpiochip. Contrary to sysfs gpio events, the event file will queue multiple events
+and include with the event (best effort) nanosecond-precision timing and an
+identifier with event type.
+
+With this information one could more reasonably consider interpreting a basic
+digital signal from userspace (with rising and falling edges) from userspace
+using the queueing with timing information captured in the kernel. Previously, one
+would need to quickly handle the event notification, make another system call
+to the value file to see the state, etc. which had far too many variables involved
+to be considered reliable.
+
+## Minimum Supported Rust Version (MSRV)
+
+This crate is guaranteed to compile on stable Rust 1.65.0 and up. It *might*
+compile with older versions but that may change in any new patch release.
+
+## License
+
+Licensed under either of
+
+- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
+ http://www.apache.org/licenses/LICENSE-2.0)
+- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
+
+## Code of Conduct
+
+Contribution to this crate is organized under the terms of the [Rust Code of
+Conduct][CoC], the maintainer of this crate, the [Embedded Linux Team][team], promises
+to intervene to uphold that code of conduct.
+
+[CoC]: CODE_OF_CONDUCT.md
+[team]: https://github.com/rust-embedded/wg#the-embedded-linux-team