 I am Linus Valle. I am the maintainer of the GPIO and pin control subsystems in the Linux kernel. Plus, I do MISC ARM32 maintenance and generally, like, all over the place when I have to be there. I upstream a few boards and so on. I'm going to talk today about GPIO for engineers and makers. I put this title because the engineers want to use GPIO for their board support or for their, like, very clearly defined task, let's say, and the makers, they just want to bang the GPIOs to do MISC stuff, interesting things. You're familiar with the maker concept, the maker community is a maker spaces and so on. It's been bust around a lot. And I didn't put the IoT in here. I'm sorry. I'm not buzzword compliant, but I did put in the makers. They do have interesting use cases, as we will see. So the GPIO subsystem came about in 2006. Until then, GPIO was seen as obscurity, just something very local to a certain SOC or PCI ISA card, something like that. The parallel part on the first PCs was seen as some kind of home-brewed GPIO. It had a 24 volts pin, so it was a bit nasty to use. But it was seen as somewhat of an obscurity, not nothing that really needed a subsystem or so. The target hardware when this was invented, and here you see the calls that were implemented by David Bronell. That was an SOC that has a few lines of GPIO on the SOC. It was invented for the ARM SOCs, primarily strong ARM, I think. And it was implicit that there is just one GPIO controller on the system. There is no GPIO expanders or several instances, banks and such things, nothing like that. The API here was merged eventually in 2007. I was defined first, and then in 2007 the GPIO Lib driver's GPIO was created. Again, by David Bronell. And he started to maintain it, not officially, but half-officially. And it goes on for a while. Then David who invented this got very ill. And Grant Lively took over the subsystem in February 2011. And started to maintain it. And in April David died, so no more work from him on GPIO. We are very grateful for his contributions, but it's one of the things that he never really could drive to the finishing line. I picked it up later the same year in December, because Grant simply didn't have time to take care of it. I think he wrote in the commit when he took it over that I'm going to regret this, and he did quite quickly. And also in December the same year I got Alexandre Corbeau from NVIDIA as co-maintainer. And we have been bringing it forward since that time, 2011-12-14. I got it mostly because I created PingControl, which is related as a subsystem. So Grant said you can have this too. First I said no, but then he listed me as co-maintainer and then removed himself. Very clever. Biggest lies. You can insert whatever burlesque quote you want here. It's somewhat of a meme, but GPIO is simple. It's not. It turns out it's not. You think it's so simple. It's just one line. It goes up and down. And a GPIO driver should be nothing. It's just something that sets register. And it can be like that. But it turns out that the infrastructure around the whole thing is actually pretty complex. So let's start with the engineer part. And now we're going to be inside the kernel. And later on in this seminar I'm going to switch over to talking about user space. And I want to share with you a few things that have happened since 2011 until now, the last five years. Because I've never lectured about them until now. I've done a lecture at the embedded Linux conference about ping control. Very interesting. And I've done some kind of a smallish GPIO lecture on assembly Norikonnect. But this time I'm going to go over the changes we actually made. Because it makes a lot of sense. And a lot of people, it turns out, haven't really noticed these things and still ask me questions about it. So let me share this with you. I have separate slides for these things. We can just first name the few things that I fixed recently. If you want to use GPIO lib, the library, the driver subsystem as it is now, just select GPIO lib. We used to have two kernel symbols that's called ArcRequires GPIO lib. Or Arc wants optional GPIO lib. And I never wrapped my head around that until I read the changelog. The latter, like Arc wants optional GPIO lib that sounded like a wish list to Santa Claus or something. I never... And then I asked the guy who submitted a patch and he didn't remember either why he called it like that. So just get rid of it. We select the subsystem just like we select all others. And making it abstract code that gets compiled everywhere amounted to some work. So, for example, user-mode Linux crashed immediately because it doesn't have IOMapped memory. And we had to work around it. So now you can compile GPIO lib actually for user-mode. Not that I know what you would use it for because there's no way out of it, but anyway, you can do it. Yeah, then we have this to add to the small things. GPIO ship add data, that's only that the GPIO lib stores a pointer to your driver data internally. So, because it will itself appropriate the data pointer in the driver. So, to help you out, we add another pointer. Some people think that the container of construction here is better. That's what we used before, usually. So the state container for the driver would have a GPIO ship embedded inside of it and you would do container of to get the pointer to the state container. And it can be argued that that is more typesafe to do it that way. And I argue that this is easier from a user perspective. It's a matter of show. If you can make a good argument for using container of and type safety, okay, I buy it. If you don't know what that is and you think that container of is obscure, use this. So it's a matter of taste, I would say. And much of the change that started from 2011 and forward and even earlier was driven by the incentive to refactor the ARM architecture to use device tree or just generally clean up stuff. Get drivers out of the ARM architecture tree and now also other trees actually do it, MIPS, PowerPC and so on, move it down into drivers proper. And another thing was getting rid of the global number space and get device associated descriptors instead. Make it a real driver subsystem, make it a device, things like that. I will go into those details because I have separate slides about that. GPIO descriptors, this is the big refactoring that's been done inside the kernel and the big change. Alexandre Corbeau has driven it mostly. The motivation is that GPIO numbers are inherently unstable. You're used to pausing a number or something here instead of device pointer and names and so on. So it would say GPIO get. Now GPIO request, actually. We didn't even have a get function. So I'm already forgetting the old API. But it doesn't work because it doesn't scale and it's unpredictable. Imagine, for example, as I said in the beginning with GPIO, you would have SOC and it would have one GPIO controller. It's right to have numbers, just 0, 1, 2, up to N, no problem. Now we have SOCs which have multiple GPIO controllers on them and then we have GPIO expanders and sometimes there's a secondary processor with GPIOs that you control from the first one. And ProBorder comes into play here because if you don't hard code your GPIO number space, it will be controlled by ProBorder, dynamically assigned a number. And then you hard code that number into a lot of platform data or, in worst case, start using it from the surface in user space. It's just mess, just complete disaster. Some people just like to do this hash define games and really carefully architecture and design like this number goes here, this number goes here and so on. That's train spotting. We don't do that. We need to manage this by machine. That's like getting a human to do machines work and that's never a good idea, just never. So we need to dynamically assign descriptors to the GPIOs and not use fixed numbers. So we have associated descriptors with the device. By using this pointer, you can retrieve the GPIO descriptor from device tree, ACPI, or board files. Actually board files was the first thing I supported. There's no excuse whatsoever not to use descriptors on a new architecture or system. There is no excuse to not convert old architectures to use descriptors apart from time and effort or testing. So we have had a bunch of conversions going on here. Then there are corner cases. Regulators is one. But generally for any simple GPIO, use descriptors internally in your drivers everywhere. It's so much neater. We get this opaque cookie here. And let's say this device needs to de-assert a reset to be up and running. It's active high. So when the reset line is high, the device is in reset state. So you just issue this. Associate with DevM here. We'll garbage collect this when we remove it. Call it reset and say that when you fire it up, when you retrieve this descriptor, set it low. This is all. It's done. Finished. Finito. It will be retrieved, set low, and then garbage collected when you remove the module. It's a bit of a chosen example. But you get the picture. Select here out high, of course, and you can also select as is if you don't want to touch the pin when you retrieve it. It will take some time to convert the whole world to using this. I'm aware of that. It's just so much better when you're dealing with abstract stuff instead of these fixed numbers. More stuff. As I said, you define these descriptors like this in a device tree, for example. There is a similar thing for the ACPI, but I don't understand ACPI, so I can't give you an example. But for example, here you specify that it's active high. And you can specify active low, and that means if you ask the descriptor to go high, it will actually go low, so it will just invert it. Sometimes you want that, sometimes not. There is also GPIOD API to do it raw, so you actually control the actual value if you want to. What is good with this is here you can also specify in your device tree, and for the consumer, you are defining it for the consumer, not like a hack in the GPIO controller. That was very common before that people had their driver and they just hack in some extra numbers here that I set a little bit of extra flags here and there. It's going to work out fine, but what they didn't think about was reusability, of course, because they hard-coded it to their system, and then when the next system was using the same driver, they got open drain or something that was used for something totally different. Here, you define for the consumer that you want it active high and you can oar on flags for open drain, for example here. Open drain and open source you can set. We will get to what that is. So no silly hard coding in the driver or special platform data quirks or anything like this. No, no, define it here in the device tree. This consumer needs it to be active high or open drain or active low or whatever. You just put it there. Same thing for ACPI, but I don't know how it looks. Use any function prefixed GPIOD or DevM in front of it is even better. So GPIOD set value, GPIOD set direction, so on. GPIOD direction input, GPIOD direction output, and so on. And I said the GPIO ship is now a real device. So internally in the GPIO lib, it is a device. The struct GPIO ship that you used to know, that's what you register in your driver. That's ideally just static information. It's not really true, but ideally it's just static information that's passed and then the subsystem instantiated a state container for it. And it's called like this GPIO device. Very straightforward. But this is private. This is for my subsystem. That's not for you to play around with unless you're GPIO subsystem developers. So this is hidden from the rest of the kernel. But it does contain a struct device like this. And that device is registered on the bus. This bus GPIO is where it appears. This is not where it appears. This is the old CISFS interface that I hate. And as you can see, there's also a character device here. We'll talk about that later. But GPIO ships, they are now real devices after you instantiate them. And we have added open drain, open source. Also known from the past as open collector and open emitter. I really love this. If you don't understand electronics, this is going to be very esoteric. We support a callback in the driver called set single ended. That's the generic term for this kind of open collector, open emitter, open drain, open source business. If you don't know it, these are transistors. This is CMOS and TTL logic. And this is a typical construction of a push-pull gate. If the hardware support, open drain and open source configuration, it will now be possible to use that with the set and get single ended setting from the driver framework. And it boils down to controlling these switches here. That's also transistor in practice. But these are software controlled and not all systems have them. And some have a static configuration. They have just synthesized their ship to have a thing like that instead of push-pull construction. And that's called an open drain construction. Open drain is used for level shifting, mostly. So as you can see, if this is the output pin and you have something pulling it up to VDD here, that VDD doesn't have to be the same voltage level that's used inside of this ship. It can be 24 volts, no problem. You will get a 24-volt signal out so you can drive your long-distance serial cable or something with it. That's awesome. Provided that you understand the concept here that either you short this within and then you pull this line down to ground so it becomes zero and when you close the gate it will drift up to whatever is connected here. That's also used for wire or constructions so that any transistor on the line can pull it low and it becomes a negative oar for the entire rail that is connected to it. That's not so popular as popular as using it for level shifting. So you can say that I want to set this into open drain mode, then I flick the switch open. This just goes numb and the output is just this transistor down here. I can set it to open source, then this one is disabled and I just have this and I can only drive it low actively. And that's exactly how it looks on the silicone more or less. So it's kind of neat. But until now we only emulated it in the GPIO library by setting it as input. If I turn this into an input I don't have a good illustration but if you have done operation amplifiers you know what is the input resistance of an ideal operational amplifier? Eternal. So it's infinite input resistance. And that's of course exactly what you get here when you turn off the gate. You get infinite resistance here, ideally. Not in practice, but ideally. So it will drift to whatever the line is pulled up by a resistor or so. That's nice. So we have this. What we do not have is other stuff, other electrical stuff that you want to do over here in your gate. We can set open drain, open source, we can set push-pull. Free state of the single-endedness, the output modes. And that's because the GPIO lib has supported that for some time. We can also set debounds with a special function. Hackish. Driver can implement it. We cannot set biasing, like pull-up, pull-down. We cannot set drive strength. And that's when you stack a few of these output stages so you get more drive strength out, more milliamps out of the line. And those things, because they are generally considered ping control. And I have a separate lecture about ping control that I could give you, but that would take the rest of the day. So it's not going to happen. But you can read up on it. The thing is there are things you can do in ping control that you cannot, at least yet, do in GPIO. Only open drain, open source, and debounds for now. Maybe we need to add some more stuff here. I will get to that in a minute. And we have ping control backends. Okay, let's continue with some ping control here. These sort of presupposes that you understand what ping control is. I usually say that GPIO is about driving lines high and low. I've been so far. Now I also just gave you an example of open drain. So it's not really true. But it is something about driving lines high and low. And ping control has been specifically of pins coming out of a package. Pins, balls, what else do they call pads? These kind of things that are on the edges of an SOC or circuit. Those things and their electrical characteristics, their flexing, and their biasing, and drive strength, and such things. That's generally considered ping control and ping config. Maxing is a separate subsub system in the subsystem. And config, electrical configuration of pins is another subsub system in the subsystem. Did anybody understand anything? So since the pins are the physical place where the GPIOs come out and the GPIOs here in the back somewhere as a separate IP block in many modern SOCs, you need sometimes to use it as a back end of the GPIO. There's a pin control subsystem in the back end managing the electrical and multiplexing, and so on of the pin. And here in the front end, we have the GPIO, which is a little bit simpler. So we mapped the two subsystems together with something like GPIO chip add-pin range tell of this GPIO chip with this pin controller, which we give by name, from that offset of the GPIO local number space, not the global one, to that offset of the pin controller local number space, we map this number of pins. It's okay to pass one here if it's very sparse. Just add as many ranges as you want. Just make sure they map. You can also map by name here. This is a bit esoteric. I think maybe one driver uses it. Then to get the pin controller to use this, you put these calls into your GPIO driver. So in the request function, you call back to the pin control layer, in the free function, in the input and output direction callbacks, you put these things, and it will call back into the pin controller and do these things for you. There's nothing to set any configuration and debounce and biasing or driving and so on. Maybe there should be. I just didn't do it because, well, I didn't have a use case for it. If you have, you're welcome to come in and help out. I am thinking that maybe we should have a callback that can set any config, one more callback, not 12. One more callback to set config using the generic pin config configuration options to let the GPIO subsystem put the pin into open drain or add free drive stages or a Schmidt trigger or anything, fun like that. But it has not yet been conceptualized or realized. In the back end of the pin controller, now we are jumping over to another subsystem. It looks like this. You have to implement this. If you are using that from the first slide, if you are calling back to the pin controller like this, your pin controller must, must implement this. Otherwise, it's not going to work and you're just going to sit there and look puzzled. So they fit together like this. Request enable, that is going to max that very pin to GPIO function. Same in this, it's going to free it up and then for setting the direction. And that's it. And also here, we would need to add another callback if you want to set some other configs. Preferably just one more. Then this one is something that people evidently don't know very much about. What this thing means, if you set it to true in your pin controller, it means that the pin cannot be used at the same time for GPIO and something else. Because it turns out the surprising number of systems actually allow you to use something as GPIO at the same time as it's used for something else. It's detailed in the documentation slash pincontrol.txt file. If you're interested in how you construct hardware to either do this or not, you can just go and read that document. It's called GPIO mode pitfall. It has something to do with the fact that the way you duct tape together these silicon blocks and the fact that hardware engineers tend to think about their IO cells as GPIO because they are general purpose for them. When you synthesize something on hardware, of course you take a general purpose input-output cell and you synthesize it. So to a hardware engineer, that cell is very much general purpose input-output. You're following me now. But to me as a software engineer, when they have purposed that input-output line for a specific purpose, it is no longer general purpose. It is special purpose. So it's not GPIO at all. Maybe it's special purpose UART, for example. Then it's not the GPIO thing. But the hardware engineers do this and then they go and write the manual and then they write, this is GPIO. And that's where the confusion just starts to go all over the map. You have to think as a hardware engineer to get this right. You have to figure out what they were actually meaning when they wrote the datasheet. Sometimes they say, like, this is a GPIO line and it's very much not general purpose at all. Now it gets tricky. Here's another thing I added to the GPIO lib. It's very useful. It's very nice refactoring. First, I realized that I started fiddling around with this GPIO lock as IRQ. This is a good function because if something is used as an IRQ, a GPIO line is used to generate an interrupt. You don't really want to switch that line to output mode, right? Because the logic will probably allow it and get you, like, events fired all over. Of course I can think of hacks. I can think of hacks where you absolutely want to do this. Then that's the exception. The rule is if something is in output mode you probably don't want interrupts from it. And it's probably an error. So out of that, well, then we started to actually, you know, this whole interrupt business from GPIOs. GPIOs are model-less cascaded interrupt controllers or IRQ ships. Actually, that looks the same pretty much everywhere, especially if the hardware is simple. It's a register where you get a zero or one depending on whether that GPIO pin fired an interrupt or not. And surely we can handle that centrally in the GPIO library. And we do. So you just select GPIO lib IRQ ship. You include the header and then you use this GPIO lib IRQ ship ad with the GPIO ship and IRQ ship like that. Of course you need to know what you're doing. You need to know exactly how to define that struct. So set type, for example. You absolutely have to understand what you're doing in set type. You have to understand, like, what functions you have to implement for your IRQ ship. But once you understand that part, associating it with a GPIO ship and telling it where to enumerate IRQs, this should be zero on all model systems. So we just pick something dynamically, an interrupt range. And you can give it a default handler here and a type default type. Edge setting, for example. Normally none. It will help you out by constructing IRQ domain, mapping all the offsets to IRQ numbers, setting up the nested thread if this is a sleeping IRQ ship. And generally just helping out and putting things into the library and managing it with central code. Because it's quite a bit of code and everybody gets it wrong. So set one thing or another. Just use this, unless you have a very good excuse. So you do it in two steps. First you associate them and then the IRQ domain and so on are created. And then you set a chained IRQ ship and say, like, this IRQ ship with this interrupt ship is going to spawn cascade off of this parent interrupt with this handler. And this you really have to implement a register and look which bits are set to one and so on and fire those interrupts and wait for them to go low. This handler is for the default handler for the individual interrupt on the individual offset line on the GPIO ship. Did you understand the difference between this one and this one? With the parent, which goes and cascades into a lot of children here. So they have different handlers depending on if they are children. This will typically be something simple like handle edge, what's the exact name? Handle edge IRQ or handle level IRQ. And if your GPIO controller supports both edge and level IRQs you can also have handle simple IRQ. If it supports both and need, let me think, clear the edge register, the first thing it does in its hard path in order to be able to receive another edge while it is processing the previous edge. Then you definitely need to have this to handle edge IRQ because it will call back into a special function in your IRQ ship that does exactly that, clears that bit and then continues processing. And some IRQ, some GPIO IRQ ships will need to associate different handlers here depending on if it's an edge or a level IRQ. Because they need to clear that bit if it was an edge IRQ and do absolutely nothing if it was a level IRQ. Instead just pull the register at the end of the function to see if the flag is still there. And for that case you actually have to assign this handler in the set type callback in your IRQ ship. And then what you should pass here is actually handle bad IRQ because everything is bad until it has got the proper handler associated. There are examples just grep in driver's GPIO. PLO61 for example, the prime cell from ARM. Very good example on this. It is also possible now to have holes in this IRQ domain. So let's say not all of the interrupts that can be generated or all the lines on this GPIO ship can actually be used to generate IRQs. So Mika Westerberg from Intel added functionality so that you can say pass in a bitmap and say like this and this and this IRQ. No mapping, no using. That's helpful. And as I mentioned you can have sleeping communication here and then the interrupt handler will become nested and if it's not sleeping it will be just chained. I know the difference between a nested and a chained IRQ cascade handler. Yeah, everybody knows it, I understand. Okay. A cascaded one will just call down to all the cascaded IRQ ships in the hard IRQ context from the IRQ signal to the processor to the primary interrupt controller down to the GPIO block or even out onto the peripheral. Whereas a nested one will it runs in an IRQ thread context so you will have something with the request threaded IRQ and then it will handle in the top half just a quick callback to the main interrupt controller of the system and then shoot off the thread and the thread will go out to a typical I2C device, pull its interrupt register, 400 kilohertz maybe, I2C traffic and then handle all the callbacks in a thread context. Absolutely necessary to do in the thread, it will not work otherwise because the CPU will not wait for that long. GPIO expanders typically on I2C do this. Both of them can be handled with this central code because they are both essentially very simple. But all the IRQ domain stuff like map, unmap, translate all that is inside the GPIO lib here and you cut quite a bit of code out of your driver and it's quite a bit of code that everybody got wrong so please use it if you can. And it will tear down and remove the IRQ domain and everything when the driver is removed when you, there is even DevM GPIO chip add so when that is unreferenced everything will be torn down and disposed of including mappings and IRQ domain and what not. There are excuses for using some custom local handling and those are typically used in the IRQ hierarchy. Then we have hogs. That's when you want to set up something at boot. Those are also new and you can define in your device tree that you want this set up low at the boot time and don't do it when it's easy to abuse for example when you have too much well a reset line for example is not okay but the bias line, the reset line pertains to certain hardware it should be handled by the driver but if you set up bias here it's not really it's a board thing it's not associated with any device so then you can use hogs but don't abuse it please now let's go to user space. SysFS is dead use shardev you have this in sysfs you have this in slashdev from kernel 4.8 everything is there it was released the other day so start using it no excuse to use the old stuff I have marked this as for deprecation the sysfs abi has been marked for deprecation in 2020 we will see about that I know I can't just remove things but the good thing is that this is a kconfig option you have to actually turn it on actively turn it on this one I have made compiled in all ways so there's no way getting away from this and that's how I push it so then the lazy people will be like yeah but I have you have some library for this but this is already available I want to use this that's nice so that's how I enforce it the rules of linux user space GPIO you do not access GPIOs from user space you do not access GPIOs from user space and all of yet all of you do it my god you read this document and then you use the character device if you anyway have to do it so I have been convinced that there are indeed use cases where you have to access GPIOs from user space but for push buttons for sensors any bit bank GPIO I to C SPI traffic one wire whatever you're doing write freaking kernel drivers don't bit bank stuff from user space I know it's fun it's very Arduino to do it but it's not engineering it's it's it's fooling around it's not the proper thing to do recompile your kernel have a good time write the driver we need more people like that because it's the right thing to do and with I understand that all mechanism for using easily using device trees for things like you boards and whatever they call them it's not always really there we had this session the other day discussing device tree overlays which is the mechanism by why you by why you can plug in a board on top of your board someone but it's getting there and for example sensors IO use IO use use real drivers even if they have GPIOs in the back and use the kernel internal GPIO API to get to them and write the real IO driver no fooling around all right but there are use cases where you have to do user space GPIO I have been convinced industrial automation factory lines doing with the Linux systems I don't want random hard kernel drivers for hydraulic press or bottle filler or whatever I mean that doesn't make sense of course you just want to drive that from user space control systems or industrial control robots and stuff fire alarms door openers and this very highly specific domain specific systems I don't want the door opener driver in my kernel I understand that you want to use this you want to use the character device I'm not going to give any examples for this it the problem with the system as I said is it uses the global GPIO number space well that's enough as an argument to remove it really because it's a mess and it can't be maintained but it's also stateless because it emulates states by doing export and unexport in system and creating mock devices for every one of these exports so new device is created every time you do export number so into a sysfs and then it plops up as another sysfs file and if your script or whatever you're using program who did that crashes guess what it's going to stay around forever until you reboot the system or go in there manually and remove the GPIO from export really really stable right there are so many horrible things with the sysfs that you can't imagine it was unfortunately merged in the period between David Brownell getting too ill to maintain and grant likely taking over but it's a big historical mistake don't use it and it involves of course compulsory string parsing when doing context switch from kernel space to user space maybe that's not very much overhead but it's still silly from an engineering point of view I parse a zero or one or whatever what is good about the character device we have a discovery mechanism based on strings we can look up GPIOs in user space by their name if they have a reasonable name you can also hard code an offset on a specific GPIO chip it cleans up resources when you close or crash so close the character device everything is cleaned up the GPIOs are available for the next client to use use support open drain open source I will not add support for this to the sysfs ABI forget it it's obsolete but you can do it with the character device go ahead you can get and set multiple lines at once and if the driver supported you can write several lines with one single register right there are good examples on how to use it so there is really no excuse not to use it other than not being on kernel v4.8 plus but that's not a problem right you're not following mainline anyways this is a little tool like LS GPIO it will look through all your chips and this chip has this name that's just a helpful string it has 54 GPIO lines and it goes on like this those are not really GPIO I just it's like maybe you didn't want to see those even I'm thinking about this where we should mask off something else but there's something GPIO here active loaders generic 1 and 2 and so on this is from the Raspberry Pi by the way the maintainer was happy with it so we're going to merge something like this so you can just go in and look through the GPIO chips I have in dev, look up GPIO name GPIO gen3 and that's where I connected my thing on this header thing let's bit bang it from user space and do our Arduino niche thing that's much better than using sysfs by the way you can name these things in the device tree with GPIO line names this is merge functionality you can use it today for all of your boards lab boards whatever go in and it should be on the top level DTS file usually because that's a specific hardware and the routing and railing is going to be specific to that one you set up here the names of the GPIO lines the names are up to you if there's a specification for your board that says it should be named like this use that name that's the case for example for 96 boards for aspery pi we are discussing it if you don't have a better idea use the rail name that's usually what people are going to see in the schematic this is how it works you open this device which will appear after it will appear by default with Udev I have patched busybox to also create it because busybox had a bug that it didn't create device nodes for devices that were bus only and didn't have a class it's going to be fixed in the next release of busybox which will be 1.26x just call an IO control on this thing that you open get the chip info into this struct and then you can print fields from it like that just check the header file this one this is not the kernel internal header file mind you this is the include UABI GPIO.h file this is user space and then you can check for a certain line whether it's high or low or whatever and what name it has this just gets the information so it's telling you the name for example of the line there's an information gathering ABI for ships and lines then you can read lines, the values say you want to read offset 4 on this specific GPIO chip and then you can print out the data that you already opened this fd that's the one from the previous slide that's opening the device itself just open on the GPIO chip this say line handle 4 request only that line as input call it push button this will be what the kernel will name it get the line handle that's the one from the previous slide there if you think that this arraying business here and telling how many is awkward I could have added another eye of control to just handle one line I mean I understand that but the neat thing with this is you can get and set many lines at the time that is indeed very neat you can handle up to this is 64 lines wide once so you can make a 64 line signal analyzer for example and read all 64 lines with one eye of control atomic and it depends on the driver I mean if it's an expander then it's going to be doing I2C traffic or something like so so it depends depends very much on the driver it's probably not atomic at all but it's fast if the driver supports setting multiple lines with a single register right it's going to be writing atomically to those that share a single register we don't have a get multiple call somebody write the patch you over there patch all drivers that can read several lines with a single register right that's also going to be atomic in that case but at least it has one context switch to kernel mode and then it will loop over there and read with several callbacks into the driver so it's going to be faster because you avoid overhead of a context switch from user space to kernel space we can optimize but the infrastructure to optimize upon there is in place and that's most my idea you can request let me see here as input you can also add on that you want open drain for example here or active low also very neat thing that you can't do with the CFFS same thing to write things again this one line request as output call it blinker get the line handle set the data to one and then set line values set it to zero set the line value so you toggle it from one to zero like that let's slide line events this only handles one GPIO because you're going to have to register an interrupt to handle events just to make it a little bit more tricky example I set it to open drain both rising and falling edges get the line event for that thing read the event this is based on IIO same principle as IIO and then you get the time stamp and you can look here what kind of event it was rising edge falling edge and print it out why do you want the time stamp you want it to do sensor fusion because that's something very important for sensor people or anything that's related to whatever industrial control really the time stamp is something you want to correlate with your accelerometer gyroscope or whatever you probably want that that's why I put it in there I hope I was not wrong in putting it there your GPIO ship must support interrupts for this to work otherwise the call will fail that sort of given so it will call eventually to IRQ and set up an IRQ handler and that IRQ handler will use a K-5-4 to push events up to user space in a 5-4 it's 16 events deep right now we can expand it if you get overflow and they will appear as interrupts go into the kernel and interrupt is handled in the kernel the event is pushed up to user space in this binary way which is exactly the way that it's done in IIO more or less you just pull the file descriptor for these structs there are some future works on this for example you might want to select this uses the nanoseconds from 1970 I think this time stamp that's a bit coarse people want to use the RTC or something like that that is available in the IIO subsystem so we might want to put that also into GPIO for the character device so we can select there are some rough edges but the ABI is there anyways alright I'm out of time I don't know if somebody else wants to use this facility or if you want to put some questions or if you want to ask them in person does anybody have a very important question to ask did anybody understand anything of what I said alright then it's good because when I did the pin control lecture at the ELC and the USA nobody understood what I was saying really because it was so complicated and GPIO is a little bit simpler so okay thank you then