[FE training-materials-updates] kernel: complete i2c lab with input interface

Michael Opdenacker michael.opdenacker at free-electrons.com
Wed Oct 2 12:47:58 CEST 2013


Repository : git://git.free-electrons.com/training-materials.git

On branch  : kernel-ng
Link       : http://git.free-electrons.com/training-materials/commit/?id=ad0693986bbdc1b65aa20b2a0e2ee765b8a7ce29

>---------------------------------------------------------------

commit ad0693986bbdc1b65aa20b2a0e2ee765b8a7ce29
Author: Michael Opdenacker <michael.opdenacker at free-electrons.com>
Date:   Wed Oct 2 12:47:17 2013 +0200

    kernel: complete i2c lab with input interface
    
    Signed-off-by: Michael Opdenacker <michael.opdenacker at free-electrons.com>


>---------------------------------------------------------------

ad0693986bbdc1b65aa20b2a0e2ee765b8a7ce29
 .../kernel-i2c-input-interface.tex                 |  172 ++++++++++++++++++++
 1 file changed, 172 insertions(+)

diff --git a/labs/kernel-i2c-input-interface/kernel-i2c-input-interface.tex b/labs/kernel-i2c-input-interface/kernel-i2c-input-interface.tex
index bbba5e7..590ef3c 100644
--- a/labs/kernel-i2c-input-interface/kernel-i2c-input-interface.tex
+++ b/labs/kernel-i2c-input-interface/kernel-i2c-input-interface.tex
@@ -73,4 +73,176 @@ See {\em Chapter 7: Centralized exiting of functions} in
 \code{Documentation/CodingStyle} for useful guidelines and an example.
 Implement this in your driver. 
 
+\section{Implement the remove() function}
+
+We now need to release the resources allocated and registered in the
+\code{probe()} routine.
+
+However, this is not trivial in the way we implemented the
+\code{probe()} routine. As we have to support multiple devices, we chose
+not to use global variables, and as a consequence, we can't use such
+global variables to release the corresponding resources. 
+
+This raises a very important aspect of the device model: the need to
+keep pointers between {\em physical} devices (devices as handled by the
+physical bus, I2C in our case) and {\em logical} devices (devices handled by subsystems,
+like the input subsystem in our case).
 
+This way, when the \code{remove()} routine is called (typically if the
+bus detects the removal of a device), we can find out which logical
+device to unregister. Conversely, when we have an event on the logical
+side (such as opening or closing an input device for the first time),
+we can find out which i2c slave this corresponds to, to do the specific
+things with the hardware.  
+
+This need is typically implemented by creating a {\em private} data
+structure to manage our device and implement such pointers between
+the physical and logical worlds.
+
+Add the below definition to your code:
+
+\begin{verbatim}
+struct nunchuk_dev {
+        struct input_polled_dev *polled_input;
+        struct i2c_client *i2c_client;
+};
+\end{verbatim}
+
+Now, in your \code{probe()} routine, declare an instance of
+this structure:
+
+\begin{verbatim}
+        struct nunchuk_dev *nunchuk;
+\end{verbatim}
+
+Then allocate one such instead for each new device:
+
+\begin{verbatim}
+        nunchuk = kzalloc(sizeof(struct nunchuk_dev), GFP_KERNEL);
+        if (!nunchuk) {
+                dev_err(&client->dev, "Failed to allocate memory\n");
+                return -ENOMEM;
+        }
+\end{verbatim}
+
+Note that we haven't seen kernel memory allocator routines and flags
+yet. We haven't explained the \code{dev_*} logging routines yet either
+(they are basically used to tell which device a given log message is
+associated to).  For the moment, just use the above code. You will get
+the details later.
+
+You will actually have to modify your code and the above lines to call 
+\code{kfree(nunchuk)} if one of the subsequent registration and
+allocation routines fail.
+
+Now implement the pointers: 
+
+\begin{verbatim}
+	nunchuk->i2c_client = client;
+	nunchuk->polled_input = polled_input;
+	polled_input->private = nunchuk;
+	i2c_set_clientdata(client, nunchuk);
+	input = polled_input->input;
+	input->dev.parent = &client->dev;
+\end{verbatim}
+
+Make sure you add this code before registering the input device. You
+don't want to enable a device with incomplete information or when it is
+not completely yet (there could be race conditions). 
+
+With all this in place, you now have everything you need to implement
+the \code{remove()} routine. Look at the I2C and input slides for
+examples, or directly find your examples in the Linux kernel code!
+
+Recompile your module, and load it and remove it multiple times, to
+make sure that everything is properly registered and unregistered.
+
+\section{Add proper input device registration information}
+
+We actually need to add more information to the input structure before
+registering it. That's why we are getting the below warnings:
+
+\begin{verbatim}
+input: Unspecified device as /devices/virtual/input/input0
+\end{verbatim}
+
+Add the below lines of code (still before device registration, of
+course):
+
+\begin{verbatim}
+        input->name = "Wii Nunchuk";
+        input->id.bustype = BUS_I2C;
+
+        set_bit(EV_KEY, input->evbit);
+        set_bit(BTN_C, input->keybit);
+        set_bit(BTN_Z, input->keybit);
+\end{verbatim}
+
+Recompile and reload your driver. You should now see in the kernel log
+that the \code{Unspecified device} type is replaced by 
+code{Wii Nunchuck} and that the physical path of the device is reported
+too. 
+
+\section{Implement the polling routine}
+
+It's time to implement the routine which will poll the nunchuk registers
+at a regular interval. 
+
+Create a \code{nunchuck_poll()} function with the right prototype (find
+it by looking at the definition of the \code{input_polled_dev} structure.
+
+First, add lines retrieving the I2C physical device from the
+\code{input_polled_dev} structure. That's where you will need your
+private \code{nunchuk} structure.
+
+Now that you have a handle on the I2C physical device, you can move the
+code reading the nunchuk registers to this function. You can
+remove the double reading of the device state, as the polling function
+will make periodic reads anyway \footnote{During the move, you will have
+to handle communication errors in a slightly different way, as the
+\code{nunchuk_poll()} routine has a \code{void} type. When the function 
+reading registers fails, you can use a \code{return;} statement instead
+of \code{return value;}}.
+
+At the end of the polling routine, the last thing to do is post the events 
+and notify the \code{input} core:
+
+\begin{verbatim}
+        input_event(nunchuk->polled_input->input,
+                    EV_KEY, BTN_Z, zpressed);
+        input_event(nunchuk->polled_input->input,
+                    EV_KEY, BTN_C, cpressed);
+
+        input_sync(nunchuk->polled_input->input);
+\end{verbatim}
+
+Now, back to the \code{probe()} function, the last thing to do
+is to declare the new polling function (see the slides if you forgot
+about the details) and specify a polling interval of 50 ms.
+
+You can now make sure that your code compiles and loads successfully.
+
+\section{Testing your input interface}
+
+Testing an input device is easy with the \code{evtest} application
+that is included in the root filesystem. Just run:
+
+\begin{verbatim}
+evtest
+\end{verbatim}
+
+The application will show you all the available input devices, and will let
+you choose the one you are interested in (make sure you type a choice,
+\code{0} by default, and do not just type \code{[Enter]}). You can also
+type \code{evtest /dev/input/event0} right away.
+
+Press the various buttons and see that the corresponding events are
+reported by \code{evtest}.
+
+\section{Going further}
+
+If you complete your lab before the others, you can add support for the
+nunchuk joystick coordinates.
+
+Another thing you can do then is add support for the coord nunchuk accelerometer
+coordinates.



More information about the training-materials-updates mailing list