gpio.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: gpio.c,v 1.12 2001/11/12 19:42:15 pkj Exp $
  2.  *
  3.  * Etrax general port I/O device
  4.  *
  5.  * Copyright (c) 1999, 2000, 2001 Axis Communications AB
  6.  *
  7.  * Authors:    Bjorn Wesen      (initial version)
  8.  *             Ola Knutsson     (LED handling)
  9.  *             Johan Adolfsson  (read/set directions, write)
  10.  *
  11.  * $Log: gpio.c,v $
  12.  * Revision 1.12  2001/11/12 19:42:15  pkj
  13.  * * Corrected return values from gpio_leds_ioctl().
  14.  * * Fixed compiler warnings.
  15.  *
  16.  * Revision 1.11  2001/10/30 14:39:12  johana
  17.  * Added D() around gpio_write printk.
  18.  *
  19.  * Revision 1.10  2001/10/25 10:24:42  johana
  20.  * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast
  21.  * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB
  22.  * from ~60 seconds to 4 seconds).
  23.  * Added save_flags/cli/restore_flags in ioctl.
  24.  *
  25.  * Revision 1.9  2001/05/04 14:16:07  matsfg
  26.  * Corrected spelling error
  27.  *
  28.  * Revision 1.8  2001/04/27 13:55:26  matsfg
  29.  * Moved initioremap.
  30.  * Turns off all LEDS on init.
  31.  * Added support for shutdown and powerbutton.
  32.  *
  33.  * Revision 1.7  2001/04/04 13:30:08  matsfg
  34.  * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping
  35.  *
  36.  * Revision 1.6  2001/03/26 16:03:06  bjornw
  37.  * Needs linux/config.h
  38.  *
  39.  * Revision 1.5  2001/03/26 14:22:03  bjornw
  40.  * Namechange of some config options
  41.  *
  42.  * Revision 1.4  2001/02/27 13:52:48  bjornw
  43.  * malloc.h -> slab.h
  44.  *
  45.  * Revision 1.3  2001/01/24 15:06:48  bjornw
  46.  * gpio_wq correct type
  47.  *
  48.  * Revision 1.2  2001/01/18 16:07:30  bjornw
  49.  * 2.4 port
  50.  *
  51.  * Revision 1.1  2001/01/18 15:55:16  bjornw
  52.  * Verbatim copy of etraxgpio.c from elinux 2.0 added
  53.  *
  54.  *
  55.  */
  56. #include <linux/config.h>
  57. #include <linux/module.h>
  58. #include <linux/sched.h>
  59. #include <linux/slab.h>
  60. #include <linux/ioport.h>
  61. #include <linux/errno.h>
  62. #include <linux/kernel.h>
  63. #include <linux/fs.h>
  64. #include <linux/string.h>
  65. #include <linux/poll.h>
  66. #include <linux/init.h>
  67. #include <asm/etraxgpio.h>
  68. #include <asm/svinto.h>
  69. #include <asm/io.h>
  70. #include <asm/system.h>
  71. #define GPIO_MAJOR 120  /* experimental MAJOR number */
  72. #define D(x)
  73. static char gpio_name[] = "etrax gpio";
  74. #if 0
  75. static wait_queue_head_t *gpio_wq;
  76. #endif
  77. static int gpio_ioctl(struct inode *inode, struct file *file,
  78.       unsigned int cmd, unsigned long arg);
  79. static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
  80.                           loff_t *off);
  81. static int gpio_open(struct inode *inode, struct file *filp);
  82. static int gpio_release(struct inode *inode, struct file *filp);
  83. static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
  84. /* private data per open() of this driver */
  85. struct gpio_private {
  86. struct gpio_private *next;
  87. volatile unsigned char *port, *shadow;
  88. volatile unsigned char *dir, *dir_shadow;
  89. unsigned char changeable_dir;
  90. unsigned char changeable_bits;
  91. unsigned char highalarm, lowalarm;
  92. unsigned char clk_mask;
  93. unsigned char data_mask;
  94. unsigned char write_msb;
  95. wait_queue_head_t alarm_wq;
  96. int minor;
  97. };
  98. /* linked list of alarms to check for */
  99. static struct gpio_private *alarmlist = 0;
  100. #define NUM_PORTS 2
  101. static volatile unsigned char *ports[2] = { R_PORT_PA_DATA, R_PORT_PB_DATA };
  102. static volatile unsigned char *shads[2] = {
  103. &port_pa_data_shadow, &port_pb_data_shadow };
  104. /* What direction bits that are user changeable 1=changeable*/
  105. #ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR
  106. #define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00
  107. #endif
  108. #ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR
  109. #define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00
  110. #endif
  111. #ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS
  112. #define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF
  113. #endif
  114. #ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS
  115. #define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF
  116. #endif
  117. static unsigned char changeable_dir[2] = { CONFIG_ETRAX_PA_CHANGEABLE_DIR,
  118.                                            CONFIG_ETRAX_PB_CHANGEABLE_DIR };
  119. static unsigned char changeable_bits[2] = { CONFIG_ETRAX_PA_CHANGEABLE_BITS,
  120.                                             CONFIG_ETRAX_PB_CHANGEABLE_BITS };
  121. static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR };
  122. static volatile unsigned char *dir_shadow[2] = {
  123. &port_pa_dir_shadow, &port_pb_dir_shadow };
  124. #define LEDS 2
  125. static unsigned int 
  126. gpio_poll(struct file *filp,
  127.   struct poll_table_struct *wait)
  128. {
  129. /* TODO poll on alarms! */
  130. #if 0
  131.         if (!ANYTHING_WANTED) {
  132. D(printk("gpio_select sleeping taskn"));
  133.         select_wait(&gpio_wq, table);
  134.         return 0;
  135. }
  136. D(printk("gpio_select readyn"));
  137. #endif
  138. return 1;
  139. }
  140. static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
  141.                           loff_t *off)
  142. {
  143. struct gpio_private *priv = (struct gpio_private *)file->private_data;
  144. unsigned char data, clk_mask, data_mask, write_msb;
  145. unsigned long flags;
  146. ssize_t retval = count;
  147. if (verify_area(VERIFY_READ, buf, count)) {
  148. return -EFAULT;
  149. }
  150. clk_mask = priv->clk_mask;
  151. data_mask = priv->data_mask;
  152. /* It must have been configured using the IO_CFG_WRITE_MODE */
  153. /* Perhaps a better error code? */
  154. if (clk_mask == 0 || data_mask == 0) {
  155. return -EPERM;
  156. }
  157. write_msb = priv->write_msb;
  158. D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %in",count, data_mask, clk_mask, write_msb));
  159. while (count--) {
  160. int i;
  161. data = *buf++;
  162. if (priv->write_msb) {
  163. for (i = 7; i >= 0;i--) {
  164. save_flags(flags); cli();
  165. *priv->port = *priv->shadow &= ~clk_mask;
  166. if (data & 1<<i)
  167. *priv->port = *priv->shadow |= data_mask;
  168. else
  169. *priv->port = *priv->shadow &= ~data_mask;
  170. /* For FPGA: min 5.0ns (DCC) before CCLK high */
  171. *priv->port = *priv->shadow |= clk_mask;
  172. restore_flags(flags);
  173. }
  174. } else {
  175. for (i = 0; i <= 7;i++) {
  176. save_flags(flags); cli();
  177. *priv->port = *priv->shadow &= ~clk_mask;
  178. if (data & 1<<i)
  179. *priv->port = *priv->shadow |= data_mask;
  180. else
  181. *priv->port = *priv->shadow &= ~data_mask;
  182. /* For FPGA: min 5.0ns (DCC) before CCLK high */
  183. *priv->port = *priv->shadow |= clk_mask;
  184. restore_flags(flags);
  185. }
  186. }
  187. }
  188. return retval;
  189. }
  190. static int
  191. gpio_open(struct inode *inode, struct file *filp)
  192. {
  193. struct gpio_private *priv;
  194. int p = MINOR(inode->i_rdev);
  195. if (p >= NUM_PORTS && p != LEDS)
  196. return -EINVAL;
  197. priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), 
  198.       GFP_KERNEL);
  199. if (!priv)
  200. return -ENOMEM;
  201. priv->minor = p;
  202. /* initialize the io/alarm struct and link it into our alarmlist */
  203. priv->next = alarmlist;
  204. alarmlist = priv;
  205. priv->port = ports[p];
  206. priv->shadow = shads[p];
  207. priv->changeable_dir = changeable_dir[p];
  208. priv->changeable_bits = changeable_bits[p];
  209. priv->dir = dir[p];
  210. priv->dir_shadow = dir_shadow[p];
  211. priv->highalarm = 0;
  212. priv->lowalarm = 0;
  213. priv->clk_mask = 0;
  214. priv->data_mask = 0;
  215. init_waitqueue_head(&priv->alarm_wq);
  216. filp->private_data = (void *)priv;
  217. return 0;
  218. }
  219. static int
  220. gpio_release(struct inode *inode, struct file *filp)
  221. {
  222. struct gpio_private *p = alarmlist;
  223. struct gpio_private *todel = (struct gpio_private *)filp->private_data;
  224. /* unlink from alarmlist and free the private structure */
  225. if (p == todel) {
  226. alarmlist = todel->next;
  227. } else {
  228. while (p->next != todel)
  229. p = p->next;
  230. p->next = todel->next;
  231. }
  232. kfree(todel);
  233. return 0;
  234. }
  235. /* Main device API. ioctl's to read/set/clear bits, as well as to 
  236.  * set alarms to wait for using a subsequent select().
  237.  */
  238. static int
  239. gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
  240. static int
  241. gpio_ioctl(struct inode *inode, struct file *file,
  242.    unsigned int cmd, unsigned long arg)
  243. {
  244. unsigned long flags;
  245. struct gpio_private *priv = (struct gpio_private *)file->private_data;
  246. if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
  247. return -EINVAL;
  248. }
  249. switch (_IOC_NR(cmd)) {
  250. case IO_READBITS:
  251. // read the port
  252. return *priv->port;
  253. case IO_SETBITS:
  254. save_flags(flags); cli();
  255. // set changeable bits with a 1 in arg
  256. *priv->port = *priv->shadow |= 
  257.   ((unsigned char)arg & priv->changeable_bits);
  258. restore_flags(flags);
  259. break;
  260. case IO_CLRBITS:
  261. save_flags(flags); cli();
  262. // clear changeable bits with a 1 in arg
  263. *priv->port = *priv->shadow &= 
  264.   ~((unsigned char)arg & priv->changeable_bits);
  265. restore_flags(flags);
  266. break;
  267. case IO_HIGHALARM:
  268. // set alarm when bits with 1 in arg go high
  269. priv->highalarm |= (unsigned char)arg;
  270. break;
  271. case IO_LOWALARM:
  272. // set alarm when bits with 1 in arg go low
  273. priv->lowalarm |= (unsigned char)arg;
  274. break;
  275. case IO_CLRALARM:
  276. // clear alarm for bits with 1 in arg
  277. priv->highalarm &= ~(unsigned char)arg;
  278. priv->lowalarm  &= ~(unsigned char)arg;
  279. break;
  280. case IO_READDIR:
  281. /* Read direction 0=input 1=output */
  282. return *priv->dir_shadow;
  283. case IO_SETINPUT:
  284. save_flags(flags); cli();
  285. /* Set direction 0=unchanged 1=input */
  286. *priv->dir = *priv->dir_shadow &= 
  287. ~((unsigned char)arg & priv->changeable_dir);
  288. restore_flags(flags);
  289. return *priv->dir_shadow;
  290. case IO_SETOUTPUT:
  291. save_flags(flags); cli();
  292. /* Set direction 0=unchanged 1=output */
  293. *priv->dir = *priv->dir_shadow |= 
  294.   ((unsigned char)arg & priv->changeable_dir);
  295. restore_flags(flags);
  296. return *priv->dir_shadow;
  297.                 case IO_SHUTDOWN:
  298.                        SOFT_SHUTDOWN();
  299.                        break;
  300.                 case IO_GET_PWR_BT:
  301. #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
  302.                        return (*R_PORT_G_DATA & 
  303.                                ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
  304. #else
  305.                        return 0;
  306. #endif
  307. break;
  308. case IO_CFG_WRITE_MODE:
  309. priv->clk_mask = arg & 0xFF;
  310. priv->data_mask = (arg >> 8) & 0xFF;
  311. priv->write_msb = (arg >> 16) & 0x01;
  312. /* Check if we're allowed to change the bits and
  313.  * the direction is correct
  314.  */
  315. if (!((priv->clk_mask & priv->changeable_bits) &&
  316.       (priv->data_mask & priv->changeable_bits) &&
  317.       (priv->clk_mask & *priv->dir_shadow) &&
  318.       (priv->data_mask & *priv->dir_shadow)))
  319. {
  320. priv->clk_mask = 0;
  321. priv->data_mask = 0;
  322. return -EPERM;
  323. }
  324. break;
  325. default:
  326. if (priv->minor == LEDS)
  327. return gpio_leds_ioctl(cmd, arg);
  328.                         else
  329. return -EINVAL;
  330. }
  331. return 0;
  332. }
  333. static int
  334. gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
  335. {
  336. unsigned char green;
  337. unsigned char red;
  338. switch (_IOC_NR(cmd)) {
  339. case IO_LEDACTIVE_SET:
  340. green = ((unsigned char) arg) & 1;
  341. red   = (((unsigned char) arg) >> 1) & 1;
  342. LED_ACTIVE_SET_G(green);
  343. LED_ACTIVE_SET_R(red);
  344. break;
  345. case IO_LED_SETBIT:                 
  346. LED_BIT_SET(arg);
  347. break;
  348. case IO_LED_CLRBIT:
  349. LED_BIT_CLR(arg);
  350. break;
  351. default:
  352. return -EINVAL;
  353. }
  354. return 0;
  355. }
  356. struct file_operations gpio_fops = {
  357. owner:       THIS_MODULE,
  358. poll:        gpio_poll,
  359. ioctl:       gpio_ioctl,
  360. write:       gpio_write,
  361. open:        gpio_open,
  362. release:     gpio_release,
  363. };
  364. /* main driver initialization routine, called from mem.c */
  365. static __init int
  366. gpio_init(void)
  367. {
  368. extern void init_ioremap(void);
  369. int res;
  370. #if defined (CONFIG_ETRAX_CSP0_LEDS)
  371. int i;
  372. #endif
  373. /* do the formalities */
  374. res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
  375. if (res < 0) {
  376. printk(KERN_ERR "gpio: couldn't get a major number.n");
  377. return res;
  378. }
  379.         /* Clear all leds */
  380. #if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) 
  381. init_ioremap();
  382. LED_NETWORK_SET(0);
  383. LED_ACTIVE_SET(0);
  384. LED_DISK_READ(0);
  385. LED_DISK_WRITE(0);        
  386. #if defined (CONFIG_ETRAX_CSP0_LEDS)
  387. for (i = 0; i < 32; i++) {
  388. LED_BIT_SET(i);
  389. }
  390. #endif
  391. #endif
  392. printk("ETRAX 100LX GPIO driver v2.2, (c) 2001 Axis Communications ABn");
  393. return res;
  394. }
  395. /* this makes sure that gpio_init is called during kernel boot */
  396. module_init(gpio_init);