2 * include/asm-v850/rte_cb_leds.c -- Midas lab RTE-CB board LED device support
4 * Copyright (C) 2002,03 NEC Electronics Corporation
5 * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
7 * This file is subject to the terms and conditions of the GNU General
8 * Public License. See the file COPYING in the main directory of this
9 * archive for more details.
11 * Written by Miles Bader <miles@gnu.org>
14 #include <linux/config.h>
15 #include <linux/init.h>
16 #include <linux/spinlock.h>
18 #include <linux/miscdevice.h>
20 #include <asm/uaccess.h>
22 #define LEDS_MINOR 169 /* Minor device number, using misc major. */
24 /* The actual LED hardware is write-only, so we hold the contents here too. */
25 static unsigned char leds_image
[LED_NUM_DIGITS
] = { 0 };
27 /* Spinlock protecting the above leds. */
28 static DEFINE_SPINLOCK(leds_lock
);
30 /* Common body of LED read/write functions, checks POS and LEN for
31 correctness, declares a variable using IMG_DECL, initialized pointing at
32 the POS position in the LED image buffer, and and iterates COPY_EXPR
33 until BUF is equal to the last buffer position; finally, sets LEN to be
34 the amount actually copied. IMG should be a variable declaration
35 (without an initializer or a terminating semicolon); POS, BUF, and LEN
36 should all be simple variables. */
37 #define DO_LED_COPY(img_decl, pos, buf, len, copy_expr) \
39 if (pos > LED_NUM_DIGITS) \
42 if (pos + len > LED_NUM_DIGITS) \
43 len = LED_NUM_DIGITS - pos; \
47 const char *_end = buf + len; \
48 img_decl = &leds_image[pos]; \
50 spin_lock_irqsave (leds_lock, _flags); \
53 while (buf != _end); \
54 spin_unlock_irqrestore (leds_lock, _flags); \
59 /* Read LEN bytes from LEDs at position POS, into BUF.
60 Returns actual amount read. */
61 unsigned read_leds (unsigned pos
, char *buf
, unsigned len
)
63 DO_LED_COPY (const char *img
, pos
, buf
, len
, *buf
++ = *img
++);
67 /* Write LEN bytes to LEDs at position POS, from BUF.
68 Returns actual amount written. */
69 unsigned write_leds (unsigned pos
, const char *buf
, unsigned len
)
71 /* We write the actual LED values backwards, because
72 increasing memory addresses reflect LEDs right-to-left. */
73 volatile char *led
= &LED (LED_NUM_DIGITS
- pos
- 1);
74 /* We invert the value written to the hardware, because 1 = off,
76 DO_LED_COPY (char *img
, pos
, buf
, len
,
77 *led
-- = 0xFF ^ (*img
++ = *buf
++));
82 /* Device functions. */
84 static ssize_t
leds_dev_read (struct file
*file
, char *buf
, size_t len
,
87 char temp_buf
[LED_NUM_DIGITS
];
88 len
= read_leds (*pos
, temp_buf
, len
);
89 if (copy_to_user (buf
, temp_buf
, len
))
95 static ssize_t
leds_dev_write (struct file
*file
, const char *buf
, size_t len
,
98 char temp_buf
[LED_NUM_DIGITS
];
99 if (copy_from_user (temp_buf
, buf
, min_t(size_t, len
, LED_NUM_DIGITS
)))
101 len
= write_leds (*pos
, temp_buf
, len
);
106 static loff_t
leds_dev_lseek (struct file
*file
, loff_t offs
, int whence
)
109 offs
+= file
->f_pos
; /* relative */
110 else if (whence
== 2)
111 offs
+= LED_NUM_DIGITS
; /* end-relative */
113 if (offs
< 0 || offs
> LED_NUM_DIGITS
)
121 static struct file_operations leds_fops
= {
122 .read
= leds_dev_read
,
123 .write
= leds_dev_write
,
124 .llseek
= leds_dev_lseek
127 static struct miscdevice leds_miscdev
= {
133 int __init
leds_dev_init (void)
135 return misc_register (&leds_miscdev
);
138 __initcall (leds_dev_init
);