florianscholz

Untitled

May 16th, 2017
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.95 KB | None | 0 0
  1. /**
  2.  * @file   movementsensor.c
  3.  * @author Florian Scholz
  4.  * @date   11. May 2017
  5.  * @brief  A kernel module for handling our movement sensor
  6.  * @see http://www.derekmolloy.ie/
  7. */
  8.  
  9. #include <linux/init.h>
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/gpio.h>                 // Required for the GPIO functions
  13. #include <linux/interrupt.h>            // Required for the IRQ code
  14. #include <linux/ktime.h>
  15. #include <asm/uaccess.h>
  16. MODULE_LICENSE("GPL");
  17. MODULE_AUTHOR("Florian Scholz");
  18. MODULE_DESCRIPTION("A driver for the movement sensor");
  19. MODULE_VERSION("0.1");
  20.  
  21. #define DEVICE_NAME "movementsensorfs"
  22. #define CLASS_NAME "mvsfs"
  23.  
  24.  
  25. static unsigned int gpioSensor = 16;       ///< hard coding the LED gpio for this example to P9_23 (GPIO49)
  26. static unsigned int irqNumber;          ///< Used to share the IRQ number within this file
  27. static int majorNumber;
  28. static ktime_t diff_firing;
  29. static ktime_t last_firing;
  30. // Function prototype for the custom IRQ handler function -- see below for the implementation
  31. static irq_handler_t  ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
  32. static struct class*  ebbcharClass  = NULL; ///< The device-driver class struct pointer
  33. static struct device* ebbcharDevice = NULL; ///< The device-driver device struct pointer
  34.  
  35.  
  36. /** @brief The LKM initialization function
  37.  *  The static keyword restricts the visibility of the function to within this C file. The __init
  38.  *  macro means that for a built-in driver (not a LKM) the function is only used at initialization
  39.  *  time and that it can be discarded and its memory freed up after that point. In this example this
  40.  *  function sets up the GPIOs and the IRQ
  41.  *  @return returns 0 if successful
  42.  */
  43.  
  44.  
  45. static int dev_open(struct inode *inodep, struct file *filep){
  46. return 0;
  47. }
  48.  
  49.  
  50. static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
  51.         char pbuf[64];
  52.         short value;
  53.     struct timespec ts_last = ktime_to_timespec(ktime_sub(ktime_get(), last_firing));
  54.     struct timespec ts_diff = ktime_to_timespec(diff_firing);
  55.  
  56.     int cnt = snprintf(pbuf, len-1, "%d %d\n", ts_last.tv_sec, ts_diff.tv_sec);
  57.     pbuf[cnt] = '\0';
  58.         len -= copy_to_user(buffer,pbuf,cnt);
  59.         *offset += len;
  60.         return len;
  61. }
  62.  
  63. static struct file_operations fops =
  64. {
  65.    .owner = THIS_MODULE,
  66.    .open = dev_open,
  67.    .read = dev_read
  68. };
  69. static int __init ebbgpio_init(void){
  70.     last_firing = diff_firing = ktime_set(0,0);
  71.  
  72.    int result = 0;
  73.    printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n");
  74.    // Is the GPIO a valid GPIO number (e.g., the BBB has 4x32 but not all available)
  75.    if (!gpio_is_valid(gpioSensor)){
  76.       printk(KERN_INFO "GPIO_TEST: invalid LED GPIO\n");
  77.       return -ENODEV;
  78.    }
  79.  
  80.    majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
  81.  
  82.    if (majorNumber<0){
  83.       printk(KERN_ALERT "EBBChar failed to register a major number\n");
  84.       return majorNumber;
  85.    }
  86.  
  87.    // Register the device class
  88.    ebbcharClass = class_create(THIS_MODULE, CLASS_NAME);
  89.    if (IS_ERR(ebbcharClass)){                // Check for error and clean up if there is
  90.       unregister_chrdev(majorNumber, DEVICE_NAME);
  91.       printk(KERN_ALERT "Failed to register device class\n");
  92.       return PTR_ERR(ebbcharClass);          // Correct way to return an error on a pointer
  93.    }
  94.    printk(KERN_INFO "EBBChar: device class registered correctly\n");
  95.    ebbcharDevice = device_create(ebbcharClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
  96.    if (IS_ERR(ebbcharDevice)){               // Clean up if there is an error
  97.       class_destroy(ebbcharClass);           // Repeated code but the alternative is goto statements
  98.       unregister_chrdev(majorNumber, DEVICE_NAME);
  99.       printk(KERN_ALERT "Failed to create the device\n");
  100.       return PTR_ERR(ebbcharDevice);
  101.    }
  102.  
  103.  
  104.  
  105.   // Going to set up the LED. It is a GPIO in output mode and will be on by default
  106.    gpio_request(gpioSensor, "sysfs");       // Set up the gpioButton
  107.    gpio_direction_input(gpioSensor);        // Set the button GPIO to be an input
  108.    gpio_set_debounce(gpioSensor, 20);      // Debounce the button with a delay of 200ms
  109.    gpio_export(gpioSensor, false);          // Causes gpio115 to appear in /sys/class/gpio
  110.                                 // the bool argument prevents the direction from being changed
  111.    // Perform a quick test to see that the button is working as expected on LKM load
  112.    printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioSensor));
  113.  
  114.    last_firing = ktime_get();
  115.  
  116.  
  117.  
  118.  
  119.    // GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
  120.    irqNumber = gpio_to_irq(gpioSensor);
  121.    printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irqNumber);
  122.  
  123.    // This next call requests an interrupt line
  124.    result = request_irq(irqNumber,             // The interrupt number requested
  125.                         (irq_handler_t) ebbgpio_irq_handler, // The pointer to the handler function below
  126.                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,   // Interrupt on rising edge (button press, not release)
  127.                         "ebb_gpio_handler",    // Used in /proc/interrupts to identify the owner
  128.                         NULL);                 // The *dev_id for shared interrupt lines, NULL is okay
  129.  
  130.    printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);
  131.    return result;
  132. }
  133.  
  134. /** @brief The LKM cleanup function
  135.  *  Similar to the initialization function, it is static. The __exit macro notifies that if this
  136.  *  code is used for a built-in driver (not a LKM) that this function is not required. Used to release the
  137.  *  GPIOs and display cleanup messages.
  138.  */
  139. static void __exit ebbgpio_exit(void) {
  140.  
  141.  
  142. free_irq(irqNumber, 0);
  143. gpio_unexport(gpioSensor);               // Unexport the Button GPIO
  144. gpio_free(gpioSensor);                   // Free the Button GPIO
  145.  
  146.    device_destroy(ebbcharClass, MKDEV(majorNumber, 0));     // remove the device
  147.    class_unregister(ebbcharClass);                          // unregister the device class
  148.    class_destroy(ebbcharClass);                             // remove the device class
  149.    unregister_chrdev(majorNumber, DEVICE_NAME);             // unregister the major number
  150. printk(KERN_INFO "GPIO_TEST: Goodbye from the LKM!\n");
  151. }
  152.  
  153. /** @brief The GPIO IRQ Handler function
  154.  *  This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt
  155.  *  handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete.
  156.  *  This function is static as it should not be invoked directly from outside of this file.
  157.  *  @param irq    the IRQ number that is associated with the GPIO -- useful for logging.
  158.  *  @param dev_id the *dev_id that is provided -- can be used to identify which device caused the interrupt
  159.  *  Not used in this example as NULL is passed.
  160.  *  @param regs   h/w specific register values -- only really ever used for debugging.
  161.  *  return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise.
  162.  */
  163. static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs){
  164. //      printk("interrupt fired\n");
  165.     int gpio_number = gpioSensor;
  166.     if (gpio_number == gpioSensor)
  167.     {
  168.         int value = gpio_get_value(gpioSensor);
  169.         if(value == 1) {
  170. //          printk ("movement started\n");
  171.             last_firing = ktime_get();
  172.             diff_firing = ktime_set(0,0);
  173.         }  
  174.         else
  175.         {
  176.             ktime_t current_firing = ktime_get();
  177.             diff_firing = ktime_sub(current_firing, last_firing);
  178. //          struct timespec ts = ktime_to_timespec(diff_firing);
  179. //          printk("movement stopped - duration: %ld\n", ts.tv_sec);
  180.         }  
  181.     }
  182.     return (irq_handler_t) IRQ_HANDLED;      // Announce that the IRQ has been handled correctly
  183. }
  184.  
  185. /// This next calls are  mandatory -- they identify the initialization function
  186. /// and the cleanup function (as above).
  187. module_init(ebbgpio_init);
  188. module_exit(ebbgpio_exit);
Advertisement
Add Comment
Please, Sign In to add comment