Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * @file mike.c
- * @author Ulrich Prinz
- * @date 28 June 2017
- * @brief A kernel module for reading the matrix keyboard of the DV4home microphone.
- * sysfs /sys/class/gpio/gpio115 and gpio49. Therefore, this test LKM circuit assumes that an LED
- * is attached to GPIO 49 which is on P9_23 and the button is attached to GPIO 115 on P9_27. There
- * is no requirement for a custom overlay, as the pins are in their default mux mode states.
- * @see http://www.derekmolloy.ie/
- */
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/gpio.h> // Required for the GPIO functions
- #include <linux/interrupt.h> // Required for the IRQ code
- #include <linux/kthread.h>
- #include <linux/delay.h>
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Ulrich Prinz");
- MODULE_DESCRIPTION("Mike keyboard control driver");
- MODULE_VERSION("0.1");
- static unsigned int gpioData = 124; /* GPIO is hard coded to GPIO4_
- // static unsigned int irqNumber; ///< Used to share the IRQ number within this file
- /* Initial blink delay */
- // static int blink_delay = 100;
- /* Task handle to identify thread */
- static struct task_struct *ts = NULL;
- /// Function prototype for the custom IRQ handler function -- see below for the implementation
- static irq_handler_t mike_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
- static int mike_thread( void *data)
- {
- printk(KERN_INFO "%s\n", __func__);
- gpio_direction_output(gpioData, 0);
- while (!kthread_should_stop()) {
- /* Set as output low */
- printk(KERN_INFO "X\n");
- //gpio_direction_output(gpioData, 0);
- mdelay(100);
- // gpio_direction_input(gpioData);
- // gpio_direction_output(gpioData, 1);
- mdelay(100);
- }
- return 0;
- }
- /** @brief The LKM initialization function
- * The static keyword restricts the visibility of the function to within this C file. The __init
- * macro means that for a built-in driver (not a LKM) the function is only used at initialization
- * time and that it can be discarded and its memory freed up after that point. In this example this
- * function sets up the GPIOs and the IRQ
- * @return returns 0 if successful
- */
- static int __init mike_init(void)
- {
- int result = 0;
- printk(KERN_INFO "MIKE_TEST: Initializing the GPIO\n");
- // Is the GPIO a valid GPIO number (e.g., the BBB has 4x32 but not all available)
- if (!gpio_is_valid(gpioData)) {
- printk(KERN_INFO "GPIO_TEST: invalid LED GPIO\n");
- return -ENODEV;
- }
- gpio_request(gpioData, "sysfs");// gpioLED is hardcoded to 49, request it
- gpio_direction_output(gpioData, 0);// Set the gpio to be in output mode and on
- // gpio_set_value(gpioData, ledOn); // Not required as set by line above (here for reference)
- gpio_export(gpioData, false);// Causes gpio49 to appear in /sys/class/gpio
- // the bool argument prevents the direction from being changed
- // gpio_direction_input(gpioData); // Set the button GPIO to be an input
- // gpio_set_debounce(gpioData, 20); // Debounce the button with a delay of 200ms
- // Perform a quick test to see that the button is working as expected on LKM load
- printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioData));
- #if 0
- // GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
- irqNumber = gpio_to_irq(gpioButton);
- printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irqNumber);
- // This next call requests an interrupt line
- result = request_irq(irqNumber,// The interrupt number requested
- (irq_handler_t) ebbgpio_irq_handler,// The pointer to the handler function below
- IRQF_TRIGGER_RISING,// Interrupt on rising edge (button press, not release)
- "ebb_gpio_handler",// Used in /proc/interrupts to identify the owner
- NULL);// The *dev_id for shared interrupt lines, NULL is okay
- printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);
- #endif
- ts = kthread_create(mike_thread, NULL, "mike_thread");
- if(ts) {
- wake_up_process(ts);
- }
- else {
- printk(KERN_ERR "Unable to create thread\n");
- }
- return result;
- }
- /** @brief The LKM cleanup function
- * Similar to the initialization function, it is static. The __exit macro notifies that if this
- * code is used for a built-in driver (not a LKM) that this function is not required. Used to release the
- * GPIOs and display cleanup messages.
- */
- static void __exit mike_exit(void)
- {
- printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioData));
- gpio_unexport(gpioData); // Unexport the LED GPIO
- // free_irq(irqNumber, NULL); // Free the IRQ number, no *dev_id required in this case
- gpio_unexport(gpioData);// Unexport the Button GPIO
- gpio_free(gpioData);// Free the LED GPIO
- printk(KERN_INFO "Mike says: Goodbye!\n");
- }
- /** @brief The GPIO IRQ Handler function
- * This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt
- * handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete.
- * This function is static as it should not be invoked directly from outside of this file.
- * @param irq the IRQ number that is associated with the GPIO -- useful for logging.
- * @param dev_id the *dev_id that is provided -- can be used to identify which device caused the interrupt
- * Not used in this example as NULL is passed.
- * @param regs h/w specific register values -- only really ever used for debugging.
- * return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise.
- */
- static irq_handler_t mike_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
- {
- #if 0
- ledOn = !ledOn; // Invert the LED state on each button press
- gpio_set_value(gpioLED, ledOn);// Set the physical LED accordingly
- printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)\n", gpio_get_value(gpioButton));
- numberPresses++;// Global counter, will be outputted when the module is unloaded
- #endif
- return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly
- }
- /// This next calls are mandatory -- they identify the initialization function
- /// and the cleanup function (as above).
- module_init(mike_init);
- module_exit(mike_exit);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement