Advertisement
matthiasbock

Speedport W500V GPIO control - extio.c

Aug 26th, 2012
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.42 KB | None | 0 0
  1. /*
  2.  * extio.c
  3.  *
  4.  * Copyright (C) 2011 [scolopender] (scolopender@arcor.de)
  5.  *
  6.  * Basics adopted from "Linux Device Drivers" by Alessandro Rubini and
  7.  * Jonathan Corbet, published by O'Reilly & Associates.
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License along
  20.  * with this program; if not, write to the Free Software Foundation, Inc.,
  21.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  22.  */
  23.  
  24. #include <linux/config.h>
  25. #include <linux/types.h>
  26. #include <linux/module.h>
  27. #include <linux/moduleparam.h>
  28. #include <linux/init.h>
  29. #include <linux/kernel.h>
  30. #include <linux/fs.h>
  31. #include <linux/errno.h>
  32. #include <linux/fcntl.h>
  33. #include <linux/cdev.h>
  34. #include <asm/semaphore.h>
  35. #include <asm/system.h>
  36. #include <asm/uaccess.h>
  37.  
  38. #include <bcm_map_part.h>
  39. #include <bcmtypes.h>
  40.  
  41.  
  42. #define EXTIO_NAME      "extio"
  43. #define EXTIO_COUNT     3
  44.  
  45. #define EXTIO_MAJOR     200
  46. #define EXTIO_MINOR     0
  47.  
  48. /* port direction */
  49. #define EXTIO_DIR_IN    0UL
  50. #define EXTIO_DIR_OUT   1UL
  51.  
  52. /* sinal level */
  53. #define EXTIO_ACT_HI    0UL
  54. #define EXTIO_ACT_LO    1UL
  55.  
  56. /* relay K1, output */
  57. #define EXTIO_OUT_0             0
  58. #define EXTIO_GPIO_0            7
  59. #define EXTIO_DIR_0             EXTIO_DIR_OUT
  60. #define EXTIO_ACT_0             EXTIO_ACT_LO
  61. #define EXTIO_SHIFT_0           EXTIO_GPIO_0
  62. #define EXTIO_GPIO_DIR_0        GPIO->GPIODir
  63. #define EXTIO_GPIO_PORT_0       GPIO->GPIOio
  64.  
  65. /* relay K2, output */
  66. #define EXTIO_OUT_1             1
  67. #define EXTIO_GPIO_1            35
  68. #define EXTIO_DIR_1             EXTIO_DIR_OUT
  69. #define EXTIO_ACT_1             EXTIO_ACT_LO
  70. #define EXTIO_SHIFT_1           (EXTIO_GPIO_1 - 32)
  71. #define EXTIO_GPIO_DIR_1        GPIO->GPIODir_high
  72. #define EXTIO_GPIO_PORT_1       GPIO->GPIOio_high
  73.  
  74. /* photocoupler PC1, input */
  75. #define EXTIO_IN_2              2
  76. #define EXTIO_GPIO_2            27
  77. #define EXTIO_DIR_2             EXTIO_DIR_IN
  78. #define EXTIO_ACT_2             EXTIO_ACT_LO
  79. #define EXTIO_SHIFT_2           EXTIO_GPIO_2
  80. #define EXTIO_GPIO_DIR_2        GPIO->GPIODir
  81. #define EXTIO_GPIO_PORT_2       GPIO->GPIOio
  82.  
  83. /* convenience */
  84. typedef struct cdev CDEV, *CDEV_P;
  85. typedef struct file FILE_, *FILE_P;
  86. typedef struct inode INODE, *INODE_P;
  87. typedef struct file_operations F_OPS, *F_OPS_P;
  88. typedef struct semaphore SEMA, *SEMA_P;
  89.  
  90. /* GPIO descriptor */
  91. struct extio_gpio_s
  92. {
  93.   volatile uint32 *dir_p;
  94.   volatile uint32 *port_p;
  95.   uint32 mask;
  96.   uint32 level;
  97.   uint32 dir;
  98. };
  99. typedef struct extio_gpio_s EXTIO_GPIO, *EXTIO_GPIO_P;
  100. typedef const EXTIO_GPIO *C_EXTIO_GPIO_P;
  101.  
  102. struct extio_driver_s
  103. {
  104.   C_EXTIO_GPIO_P c_eg_p;
  105.   int eof_flag;
  106.   SEMA sema;
  107.   CDEV_P cdev_p;
  108. };
  109. typedef struct extio_driver_s EXTIO_DRIVER, *EXTIO_DRIVER_P;
  110.  
  111. MODULE_AUTHOR("scolopender");
  112. MODULE_LICENSE("Proprietary");
  113.  
  114. const char kern_alert[] = KERN_ALERT;
  115. const char kern_warning[] = KERN_WARNING;
  116. const char extio_name[] = EXTIO_NAME;
  117.  
  118. /* GPIO descriptor table */
  119. const EXTIO_GPIO extio_gpio[EXTIO_COUNT] =
  120. {
  121.   /* relay K1 */
  122.   {
  123.     (volatile uint32 *)&(EXTIO_GPIO_DIR_0),
  124.     (volatile uint32 *)&(EXTIO_GPIO_PORT_0),
  125.     (1UL << EXTIO_SHIFT_0),
  126.     (EXTIO_ACT_0 << EXTIO_SHIFT_0),
  127.     (EXTIO_DIR_0 << EXTIO_SHIFT_0),
  128.   },
  129.   /* relay K2 */
  130.   {
  131.     (volatile uint32 *)&(EXTIO_GPIO_DIR_1),
  132.     (volatile uint32 *)&(EXTIO_GPIO_PORT_1),
  133.     (1UL << EXTIO_SHIFT_1),
  134.     (EXTIO_ACT_1 << EXTIO_SHIFT_1),
  135.     (EXTIO_DIR_1 << EXTIO_SHIFT_1),
  136.   },
  137.   /* photocoupler PC1 */
  138.   {
  139.     (volatile uint32 *)&(EXTIO_GPIO_DIR_2),
  140.     (volatile uint32 *)&(EXTIO_GPIO_PORT_2),
  141.     (1UL << EXTIO_SHIFT_2),
  142.     (EXTIO_ACT_2 << EXTIO_SHIFT_2),
  143.     (EXTIO_DIR_2 << EXTIO_SHIFT_2),
  144.   }
  145. };
  146.  
  147. /* module parameters, default */
  148. int extio_major = EXTIO_MAJOR;
  149. int extio_minor = EXTIO_MINOR;
  150.  
  151. module_param(extio_major, int, S_IRUGO);
  152. module_param(extio_minor, int, S_IRUGO);
  153.  
  154. dev_t extio_dev = 0;
  155. EXTIO_DRIVER extio_driver[EXTIO_COUNT];
  156.  
  157.  
  158. /* get GPIO pin state */
  159. static char get_gpio(C_EXTIO_GPIO_P c_eg_p)
  160. {
  161.   return( ( ((*(c_eg_p->port_p) & c_eg_p->mask) ^ c_eg_p->level) != 0 ) ? '1' : '0' );
  162. }
  163.  
  164.  
  165. /* change GPIO pin state */
  166. static int put_gpio(C_EXTIO_GPIO_P c_eg_p, char state)
  167. {
  168.   uint32 mask, level, port;
  169.   volatile uint32 *port_p;
  170.  
  171.   mask = c_eg_p->mask;
  172.   level = c_eg_p->level;
  173.   port_p = c_eg_p->port_p;
  174.  
  175.   port = *port_p ^ level;
  176.  
  177.   /* assert / release */
  178.   switch ( state )
  179.   {
  180.     case '0' :
  181.     {
  182.       /* release gpio */
  183.       port &= ~mask;
  184.  
  185.       break;
  186.     } /* '0' */
  187.  
  188.     case '1' :
  189.     {
  190.       /* assert gpio */
  191.       port |= mask;
  192.  
  193.       break;
  194.     } /* '1' */
  195.  
  196.     default :
  197.     {
  198.       return(-EINVAL);
  199.     }
  200.   }
  201.  
  202.   *port_p = port ^ level;
  203.  
  204.   return(0);
  205.  
  206. } /* put_gpio */
  207.  
  208.  
  209. /* "device" read */
  210. static ssize_t extio_read(FILE_P file_p, char __user *buf_p, size_t count, loff_t *loff_p)
  211. {
  212.   EXTIO_DRIVER_P ed_p;
  213.   C_EXTIO_GPIO_P c_eg_p;
  214.   ssize_t retval;
  215.   char data;
  216.  
  217.   ed_p = file_p->private_data;
  218.  
  219.   if ( down_interruptible(&(ed_p->sema)) )
  220.   {
  221.     return(-ERESTARTSYS);
  222.   }
  223.  
  224.   c_eg_p = ed_p->c_eg_p;
  225.  
  226.   /* one byte only */
  227.   if ( count > 1 )
  228.   {
  229.     if ( ed_p->eof_flag != 0 )
  230.     {
  231.       count = 0;
  232.     }
  233.     else
  234.     {
  235.       count = 1;
  236.       ed_p->eof_flag = 1;
  237.     }
  238.   }
  239.  
  240.   if ( count != 0 )
  241.   {
  242.     /* get port state */
  243.     data = get_gpio(c_eg_p);
  244.  
  245.     /* copy to user */
  246.     retval = put_user(data, buf_p);
  247.     if ( retval != 0 )
  248.     {
  249.       goto out;
  250.     }
  251.   }
  252.  
  253.   retval = count;
  254.  
  255. out :
  256.  
  257.   up(&(ed_p->sema));
  258.  
  259.   return(retval);
  260.  
  261. } /* extio_read */
  262.  
  263.  
  264. /* "device" write */
  265. static ssize_t extio_write(FILE_P file_p, const char __user *buf_p, size_t count, loff_t *loff_p)
  266. {
  267.   EXTIO_DRIVER_P ed_p;
  268.   C_EXTIO_GPIO_P c_eg_p;
  269.   ssize_t retval;
  270.   char data;
  271.  
  272.   ed_p = file_p->private_data;
  273.  
  274.   if ( down_interruptible(&(ed_p->sema)) )
  275.   {
  276.     return(-ERESTARTSYS);
  277.   }
  278.  
  279.   c_eg_p = ed_p->c_eg_p;
  280.  
  281.   /* first byte only */
  282.   /* copy from user */
  283.   retval = get_user(data, buf_p);
  284.   if ( retval != 0 )
  285.   {
  286.     goto out;
  287.   }
  288.  
  289.   /* assert / release */
  290.   retval = put_gpio(c_eg_p, data);
  291.   if ( retval != 0 )
  292.   {
  293.     goto out;
  294.   }
  295.  
  296.   retval = count;
  297.  
  298. out :
  299.  
  300.   up(&(ed_p->sema));
  301.  
  302.   return(retval);
  303.  
  304. } /* extio_write */
  305.  
  306.  
  307. /* "device" open */
  308. static int extio_open(INODE_P inode_p, FILE_P file_p)
  309. {
  310.   EXTIO_DRIVER_P ed_p;
  311.  
  312.   ed_p = &(extio_driver[iminor(inode_p) - extio_minor]);
  313.   file_p->private_data = ed_p;
  314.   ed_p->eof_flag = 0;
  315.  
  316.   /* always success */
  317.   return(0);
  318.  
  319. } /* extio_open */
  320.  
  321.  
  322. /* "device" close */
  323. static int extio_release(INODE_P inode_p, FILE_P file_p)
  324. {
  325.   /* always success */
  326.   return(0);
  327.  
  328. } /* extio_release */
  329.  
  330.  
  331. /* "methods" */
  332. struct file_operations extio_fops =
  333. {
  334.   .owner = THIS_MODULE,
  335.   .read = extio_read,
  336.   .write = extio_write,
  337.   .open = extio_open,
  338.   .release = extio_release,
  339. };
  340.  
  341.  
  342. static void extio_cleanup(void)
  343. {
  344.   EXTIO_DRIVER_P ed_p;
  345.   int index;
  346.  
  347.   for ( index = 0, ed_p = extio_driver; index < EXTIO_COUNT; index++, ed_p++ )
  348.   {
  349.     if ( ed_p->cdev_p != NULL )
  350.     {
  351.       cdev_del(ed_p->cdev_p);
  352.       kfree(ed_p->cdev_p);
  353.       ed_p->cdev_p = NULL;
  354.     }
  355.   }
  356.  
  357.   if ( extio_dev != 0 )
  358.   {
  359.     unregister_chrdev_region(extio_dev, EXTIO_COUNT);
  360.     extio_dev = 0;
  361.   }
  362. } /* extio_cleanup */
  363.  
  364.  
  365. /* module dtor */
  366. static void __exit extio_exit(void)
  367. {
  368.   extio_cleanup();
  369.  
  370.   printk("%s%s stopped !\n", kern_alert, extio_name);
  371.  
  372. } /* extio_exit */
  373.  
  374.  
  375. /* module ctor */
  376. static int __init extio_init(void)
  377. {
  378.   EXTIO_DRIVER_P ed_p;
  379.   C_EXTIO_GPIO_P c_eg_p;
  380.   dev_t dev;
  381.   int index, result;
  382.   uint32 mask;
  383.   volatile uint32 *port_p, *dir_p;
  384.  
  385.   /* parameter check */
  386.   if ( (extio_major < 0) || (extio_major > 255) )
  387.   {
  388.     printk("%s%s: parameter 'major' invalid\n", kern_alert, extio_name);
  389.     return(-EINVAL);
  390.   }
  391.  
  392.   /* parameter check */
  393.   if ( (extio_minor < 0) || (extio_minor > (256 - EXTIO_COUNT)) )
  394.   {
  395.     printk("%s%s: parameter 'minor' invalid\n", kern_alert, extio_name);
  396.     return(-EINVAL);
  397.   }
  398.  
  399.   /* storage preset */
  400.   memset(extio_driver, 0, sizeof(extio_driver));
  401.  
  402.   /* device number */
  403.   extio_dev = MKDEV(extio_major, extio_minor);
  404.   result = register_chrdev_region(extio_dev, EXTIO_COUNT, (char *)extio_name);
  405.   if ( result < 0 )
  406.   {
  407.     printk("%s%s: cannot get major %d\n", kern_warning, extio_name, MAJOR(extio_dev));
  408.     extio_dev = 0;
  409.     return(result);
  410.   }
  411.  
  412.   /* char device allocation */
  413.   for ( index = 0, ed_p = extio_driver, c_eg_p = extio_gpio; index < EXTIO_COUNT; index++, ed_p++, c_eg_p++ )
  414.   {
  415.     ed_p->cdev_p = cdev_alloc();
  416.     if ( ed_p->cdev_p == NULL )
  417.     {
  418.       printk("%s%s%d: cannot get memory for cdev struct\n", kern_warning, extio_name, index);
  419.       extio_cleanup();
  420.       return(-ENOMEM);
  421.     }
  422.  
  423.     /* semaphore setup */
  424.     init_MUTEX(&(ed_p->sema));
  425.  
  426.     /* char device init */
  427.     cdev_init(ed_p->cdev_p, &extio_fops);
  428.     ed_p->cdev_p->owner = THIS_MODULE;
  429.     ed_p->cdev_p->ops = &extio_fops;
  430.  
  431.     /* GPIO descriptor */
  432.     ed_p->c_eg_p = c_eg_p;
  433.  
  434.     /* gpio setup */
  435.     mask = c_eg_p->mask;
  436.     port_p = c_eg_p->port_p;
  437.     dir_p = c_eg_p->dir_p;
  438.  
  439.     if ( c_eg_p->dir == 0 )
  440.     {
  441.       /* configure for input */
  442.       *dir_p &= ~mask;
  443.     }
  444.     else
  445.     {
  446.       /* configure for output */
  447.       *dir_p |= mask;
  448.  
  449.       /* initially release gpio */
  450.       if ( c_eg_p->level == 0 )
  451.       {
  452.         *port_p &= ~mask;
  453.       }
  454.       else
  455.       {
  456.         *port_p |= mask;
  457.       }
  458.     }
  459.  
  460.     /* driver start */
  461.     dev = MKDEV(extio_major, extio_minor + index);
  462.     result = cdev_add(ed_p->cdev_p, dev, 1);
  463.     if ( result < 0 )
  464.     {
  465.       printk("%s%s%d: cannot add device %d\n", kern_warning, extio_name, index, extio_minor + index);
  466.       kfree(ed_p->cdev_p);
  467.       ed_p->cdev_p = NULL;
  468.       extio_cleanup();
  469.       return(result);
  470.     }
  471.   }
  472.  
  473.   printk("%s%s started !\n", kern_alert, extio_name);
  474.  
  475.   return(0);
  476.  
  477. } /* extio_init */
  478.  
  479.  
  480. module_init(extio_init);
  481. module_exit(extio_exit);
  482.  
  483. /* EoF */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement