Blame view

drivers/char/briq_panel.c 5.22 KB
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
1
2
3
4
5
6
7
8
9
10
  /*
   * Drivers for the Total Impact PPC based computer "BRIQ"
   * by Dr. Karsten Jeppesen
   *
   */
  
  #include <linux/module.h>
  
  #include <linux/types.h>
  #include <linux/errno.h>
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
11
12
  #include <linux/tty.h>
  #include <linux/timer.h>
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
13
14
15
  #include <linux/kernel.h>
  #include <linux/wait.h>
  #include <linux/string.h>
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  #include <linux/ioport.h>
  #include <linux/delay.h>
  #include <linux/miscdevice.h>
  #include <linux/fs.h>
  #include <linux/mm.h>
  #include <linux/init.h>
  
  #include <asm/uaccess.h>
  #include <asm/io.h>
  #include <asm/prom.h>
  
  #define		BRIQ_PANEL_MINOR	156
  #define		BRIQ_PANEL_VFD_IOPORT	0x0390
  #define		BRIQ_PANEL_LED_IOPORT	0x0398
  #define		BRIQ_PANEL_VER		"1.1 (04/20/2002)"
  #define		BRIQ_PANEL_MSG0		"Loading Linux"
  
  static int		vfd_is_open;
  static unsigned char	vfd[40];
  static int		vfd_cursor;
  static unsigned char	ledpb, led;
  
  static void update_vfd(void)
  {
  	int	i;
  
  	/* cursor home */
  	outb(0x02, BRIQ_PANEL_VFD_IOPORT);
  	for (i=0; i<20; i++)
  		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
  
  	/* cursor to next line */
  	outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
  	for (i=20; i<40; i++)
  		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
  
  }
  
  static void set_led(char state)
  {
  	if (state == 'R')
  		led = 0x01;
  	else if (state == 'G')
  		led = 0x02;
  	else if (state == 'Y')
  		led = 0x03;
  	else if (state == 'X')
  		led = 0x00;
  	outb(led, BRIQ_PANEL_LED_IOPORT);
  }
  
  static int briq_panel_open(struct inode *ino, struct file *filep)
  {
ec79d6056   Arnd Bergmann   tty: replace BKL ...
69
  	tty_lock();
556889a4a   Arnd Bergmann   briq_panel: BKL p...
70
71
  	/* enforce single access, vfd_is_open is protected by BKL */
  	if (vfd_is_open) {
ec79d6056   Arnd Bergmann   tty: replace BKL ...
72
  		tty_unlock();
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
73
  		return -EBUSY;
556889a4a   Arnd Bergmann   briq_panel: BKL p...
74
  	}
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
75
  	vfd_is_open = 1;
ec79d6056   Arnd Bergmann   tty: replace BKL ...
76
  	tty_unlock();
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
77
78
79
80
81
82
83
84
85
86
87
88
  	return 0;
  }
  
  static int briq_panel_release(struct inode *ino, struct file *filep)
  {
  	if (!vfd_is_open)
  		return -ENODEV;
  
  	vfd_is_open = 0;
  
  	return 0;
  }
4ac493b1d   Al Viro   [PATCH] briq_pane...
89
  static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
90
91
92
93
  			 loff_t *ppos)
  {
  	unsigned short c;
  	unsigned char cp;
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  	if (!vfd_is_open)
  		return -ENODEV;
  
  	c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
  	set_led(' ');
  	/* upper button released */
  	if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
  		cp = ' ';
  		ledpb = c;
  		if (copy_to_user(buf, &cp, 1))
  			return -EFAULT;
  		return 1;
  	}
  	/* lower button released */
  	else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
  		cp = '\r';
  		ledpb = c;
  		if (copy_to_user(buf, &cp, 1))
  			return -EFAULT;
  		return 1;
  	} else {
  		ledpb = c;
  		return 0;
  	}
  }
  
  static void scroll_vfd( void )
  {
  	int	i;
  
  	for (i=0; i<20; i++) {
  		vfd[i] = vfd[i+20];
  		vfd[i+20] = ' ';
  	}
  	vfd_cursor = 20;
  }
4ac493b1d   Al Viro   [PATCH] briq_pane...
130
  static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
131
132
133
134
  			  loff_t *ppos)
  {
  	size_t indx = len;
  	int i, esc = 0;
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
135
136
137
138
  	if (!vfd_is_open)
  		return -EBUSY;
  
  	for (;;) {
4ac493b1d   Al Viro   [PATCH] briq_pane...
139
  		char c;
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
140
141
  		if (!indx)
  			break;
4ac493b1d   Al Viro   [PATCH] briq_pane...
142
143
  		if (get_user(c, buf))
  			return -EFAULT;
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
144
  		if (esc) {
4ac493b1d   Al Viro   [PATCH] briq_pane...
145
  			set_led(c);
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
146
  			esc = 0;
4ac493b1d   Al Viro   [PATCH] briq_pane...
147
  		} else if (c == 27) {
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
148
  			esc = 1;
4ac493b1d   Al Viro   [PATCH] briq_pane...
149
  		} else if (c == 12) {
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
150
151
152
153
  			/* do a form feed */
  			for (i=0; i<40; i++)
  				vfd[i] = ' ';
  			vfd_cursor = 0;
4ac493b1d   Al Viro   [PATCH] briq_pane...
154
  		} else if (c == 10) {
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
155
156
157
158
159
160
161
162
163
164
165
166
  			if (vfd_cursor < 20)
  				vfd_cursor = 20;
  			else if (vfd_cursor < 40)
  				vfd_cursor = 40;
  			else if (vfd_cursor < 60)
  				vfd_cursor = 60;
  			if (vfd_cursor > 59)
  				scroll_vfd();
  		} else {
  			/* just a character */
  			if (vfd_cursor > 39)
  				scroll_vfd();
4ac493b1d   Al Viro   [PATCH] briq_pane...
167
  			vfd[vfd_cursor++] = c;
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
168
169
170
171
172
173
174
175
  		}
  		indx--;
  		buf++;
  	}
  	update_vfd();
  
  	return len;
  }
2b8693c06   Arjan van de Ven   [PATCH] mark stru...
176
  static const struct file_operations briq_panel_fops = {
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
177
178
179
180
181
  	.owner		= THIS_MODULE,
  	.read		= briq_panel_read,
  	.write		= briq_panel_write,
  	.open		= briq_panel_open,
  	.release	= briq_panel_release,
6038f373a   Arnd Bergmann   llseek: automatic...
182
  	.llseek		= noop_llseek,
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
183
184
185
186
187
188
189
190
191
192
  };
  
  static struct miscdevice briq_panel_miscdev = {
  	BRIQ_PANEL_MINOR,
  	"briq_panel",
  	&briq_panel_fops
  };
  
  static int __init briq_panel_init(void)
  {
8c8dc3224   Stephen Rothwell   [POWERPC] Remove ...
193
  	struct device_node *root = of_find_node_by_path("/");
13b5aeccc   Al Viro   [PATCH] more fall...
194
  	const char *machine;
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
195
  	int i;
40cd3a456   Stephen Rothwell   [POWERPC] Rename ...
196
  	machine = of_get_property(root, "model", NULL);
8c8dc3224   Stephen Rothwell   [POWERPC] Remove ...
197
198
  	if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
  		of_node_put(root);
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
199
  		return -ENODEV;
8c8dc3224   Stephen Rothwell   [POWERPC] Remove ...
200
201
  	}
  	of_node_put(root);
a45b83957   Benjamin Herrenschmidt   [POWERPC] Add sup...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  
  	printk(KERN_INFO
  		"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)
  ",
  		BRIQ_PANEL_VER);
  
  	if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
  		return -EBUSY;
  
  	if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
  		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
  		return -EBUSY;
  	}
  	ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
  
  	if (misc_register(&briq_panel_miscdev) < 0) {
  		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
  		release_region(BRIQ_PANEL_LED_IOPORT, 2);
  		return -EBUSY;
  	}
  
  	outb(0x38, BRIQ_PANEL_VFD_IOPORT);	/* Function set */
  	outb(0x01, BRIQ_PANEL_VFD_IOPORT);	/* Clear display */
  	outb(0x0c, BRIQ_PANEL_VFD_IOPORT);	/* Display on */
  	outb(0x06, BRIQ_PANEL_VFD_IOPORT);	/* Entry normal */
  	for (i=0; i<40; i++)
  		vfd[i]=' ';
  #ifndef MODULE
  	vfd[0] = 'L';
  	vfd[1] = 'o';
  	vfd[2] = 'a';
  	vfd[3] = 'd';
  	vfd[4] = 'i';
  	vfd[5] = 'n';
  	vfd[6] = 'g';
  	vfd[7] = ' ';
  	vfd[8] = '.';
  	vfd[9] = '.';
  	vfd[10] = '.';
  #endif /* !MODULE */
  
  	update_vfd();
  
  	return 0;
  }
  
  static void __exit briq_panel_exit(void)
  {
  	misc_deregister(&briq_panel_miscdev);
  	release_region(BRIQ_PANEL_VFD_IOPORT, 4);
  	release_region(BRIQ_PANEL_LED_IOPORT, 2);
  }
  
  module_init(briq_panel_init);
  module_exit(briq_panel_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
  MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");