Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 * /dev/lcd driver for Apple Network Servers.
  3 */
  4
  5#include <linux/types.h>
  6#include <linux/errno.h>
  7#include <linux/kernel.h>
  8#include <linux/miscdevice.h>
  9#include <linux/fcntl.h>
 10#include <linux/init.h>
 11#include <linux/delay.h>
 12#include <linux/fs.h>
 13
 14#include <asm/uaccess.h>
 15#include <asm/sections.h>
 16#include <asm/prom.h>
 17#include <asm/io.h>
 18
 19#include "ans-lcd.h"
 20
 21#define ANSLCD_ADDR		0xf301c000
 22#define ANSLCD_CTRL_IX 0x00
 23#define ANSLCD_DATA_IX 0x10
 24
 25static unsigned long anslcd_short_delay = 80;
 26static unsigned long anslcd_long_delay = 3280;
 27static volatile unsigned char __iomem *anslcd_ptr;
 28static DEFINE_MUTEX(anslcd_mutex);
 29
 30#undef DEBUG
 31
 32static void
 33anslcd_write_byte_ctrl ( unsigned char c )
 34{
 35#ifdef DEBUG
 36	printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c);
 37#endif
 38	out_8(anslcd_ptr + ANSLCD_CTRL_IX, c);
 39	switch(c) {
 40		case 1:
 41		case 2:
 42		case 3:
 43			udelay(anslcd_long_delay); break;
 44		default: udelay(anslcd_short_delay);
 45	}
 46}
 47
 48static void
 49anslcd_write_byte_data ( unsigned char c )
 50{
 51	out_8(anslcd_ptr + ANSLCD_DATA_IX, c);
 52	udelay(anslcd_short_delay);
 53}
 54
 55static ssize_t
 56anslcd_write( struct file * file, const char __user * buf, 
 57				size_t count, loff_t *ppos )
 58{
 59	const char __user *p = buf;
 60	int i;
 61
 62#ifdef DEBUG
 63	printk(KERN_DEBUG "LCD: write\n");
 64#endif
 65
 66	if (!access_ok(VERIFY_READ, buf, count))
 67		return -EFAULT;
 68
 69	mutex_lock(&anslcd_mutex);
 70	for ( i = *ppos; count > 0; ++i, ++p, --count ) 
 71	{
 72		char c;
 73		__get_user(c, p);
 74		anslcd_write_byte_data( c );
 75	}
 76	mutex_unlock(&anslcd_mutex);
 77	*ppos = i;
 78	return p - buf;
 79}
 80
 81static long
 82anslcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 83{
 84	char ch, __user *temp;
 85	long ret = 0;
 86
 87#ifdef DEBUG
 88	printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg);
 89#endif
 90
 91	mutex_lock(&anslcd_mutex);
 92
 93	switch ( cmd )
 94	{
 95	case ANSLCD_CLEAR:
 96		anslcd_write_byte_ctrl ( 0x38 );
 97		anslcd_write_byte_ctrl ( 0x0f );
 98		anslcd_write_byte_ctrl ( 0x06 );
 99		anslcd_write_byte_ctrl ( 0x01 );
100		anslcd_write_byte_ctrl ( 0x02 );
101		break;
102	case ANSLCD_SENDCTRL:
103		temp = (char __user *) arg;
104		__get_user(ch, temp);
105		for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */
106			anslcd_write_byte_ctrl ( ch );
107			__get_user(ch, temp);
108		}
109		break;
110	case ANSLCD_SETSHORTDELAY:
111		if (!capable(CAP_SYS_ADMIN))
112			ret =-EACCES;
113		else
114			anslcd_short_delay=arg;
115		break;
116	case ANSLCD_SETLONGDELAY:
117		if (!capable(CAP_SYS_ADMIN))
118			ret = -EACCES;
119		else
120			anslcd_long_delay=arg;
121		break;
122	default:
123		ret = -EINVAL;
124	}
125
126	mutex_unlock(&anslcd_mutex);
127	return ret;
128}
129
130static int
131anslcd_open( struct inode * inode, struct file * file )
132{
133	return 0;
134}
135
136const struct file_operations anslcd_fops = {
137	.write		= anslcd_write,
138	.unlocked_ioctl	= anslcd_ioctl,
139	.open		= anslcd_open,
140	.llseek		= default_llseek,
141};
142
143static struct miscdevice anslcd_dev = {
144	ANSLCD_MINOR,
145	"anslcd",
146	&anslcd_fops
147};
148
149const char anslcd_logo[] =	"********************"  /* Line #1 */
150				"*      LINUX!      *"  /* Line #3 */
151				"*    Welcome to    *"  /* Line #2 */
152				"********************"; /* Line #4 */
153
154static int __init
155anslcd_init(void)
156{
157	int a;
158	int retval;
159	struct device_node* node;
160
161	node = of_find_node_by_name(NULL, "lcd");
162	if (!node || !node->parent || strcmp(node->parent->name, "gc")) {
163		of_node_put(node);
164		return -ENODEV;
165	}
166	of_node_put(node);
167
168	anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
169	
170	retval = misc_register(&anslcd_dev);
171	if(retval < 0){
172		printk(KERN_INFO "LCD: misc_register failed\n");
173		iounmap(anslcd_ptr);
174		return retval;
175	}
176
177#ifdef DEBUG
178	printk(KERN_DEBUG "LCD: init\n");
179#endif
180
181	mutex_lock(&anslcd_mutex);
182	anslcd_write_byte_ctrl ( 0x38 );
183	anslcd_write_byte_ctrl ( 0x0c );
184	anslcd_write_byte_ctrl ( 0x06 );
185	anslcd_write_byte_ctrl ( 0x01 );
186	anslcd_write_byte_ctrl ( 0x02 );
187	for(a=0;a<80;a++) {
188		anslcd_write_byte_data(anslcd_logo[a]);
189	}
190	mutex_unlock(&anslcd_mutex);
191	return 0;
192}
193
194static void __exit
195anslcd_exit(void)
196{
197	misc_deregister(&anslcd_dev);
198	iounmap(anslcd_ptr);
199}
200
201module_init(anslcd_init);
202module_exit(anslcd_exit);
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * /dev/lcd driver for Apple Network Servers.
  4 */
  5
  6#include <linux/types.h>
  7#include <linux/errno.h>
  8#include <linux/kernel.h>
  9#include <linux/miscdevice.h>
 10#include <linux/fcntl.h>
 11#include <linux/module.h>
 12#include <linux/delay.h>
 13#include <linux/fs.h>
 14
 15#include <linux/uaccess.h>
 16#include <asm/sections.h>
 17#include <asm/prom.h>
 18#include <asm/io.h>
 19
 20#include "ans-lcd.h"
 21
 22#define ANSLCD_ADDR		0xf301c000
 23#define ANSLCD_CTRL_IX 0x00
 24#define ANSLCD_DATA_IX 0x10
 25
 26static unsigned long anslcd_short_delay = 80;
 27static unsigned long anslcd_long_delay = 3280;
 28static volatile unsigned char __iomem *anslcd_ptr;
 29static DEFINE_MUTEX(anslcd_mutex);
 30
 31#undef DEBUG
 32
 33static void
 34anslcd_write_byte_ctrl ( unsigned char c )
 35{
 36#ifdef DEBUG
 37	printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c);
 38#endif
 39	out_8(anslcd_ptr + ANSLCD_CTRL_IX, c);
 40	switch(c) {
 41		case 1:
 42		case 2:
 43		case 3:
 44			udelay(anslcd_long_delay); break;
 45		default: udelay(anslcd_short_delay);
 46	}
 47}
 48
 49static void
 50anslcd_write_byte_data ( unsigned char c )
 51{
 52	out_8(anslcd_ptr + ANSLCD_DATA_IX, c);
 53	udelay(anslcd_short_delay);
 54}
 55
 56static ssize_t
 57anslcd_write( struct file * file, const char __user * buf, 
 58				size_t count, loff_t *ppos )
 59{
 60	const char __user *p = buf;
 61	int i;
 62
 63#ifdef DEBUG
 64	printk(KERN_DEBUG "LCD: write\n");
 65#endif
 66
 67	if (!access_ok(buf, count))
 68		return -EFAULT;
 69
 70	mutex_lock(&anslcd_mutex);
 71	for ( i = *ppos; count > 0; ++i, ++p, --count ) 
 72	{
 73		char c;
 74		__get_user(c, p);
 75		anslcd_write_byte_data( c );
 76	}
 77	mutex_unlock(&anslcd_mutex);
 78	*ppos = i;
 79	return p - buf;
 80}
 81
 82static long
 83anslcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 84{
 85	char ch, __user *temp;
 86	long ret = 0;
 87
 88#ifdef DEBUG
 89	printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg);
 90#endif
 91
 92	mutex_lock(&anslcd_mutex);
 93
 94	switch ( cmd )
 95	{
 96	case ANSLCD_CLEAR:
 97		anslcd_write_byte_ctrl ( 0x38 );
 98		anslcd_write_byte_ctrl ( 0x0f );
 99		anslcd_write_byte_ctrl ( 0x06 );
100		anslcd_write_byte_ctrl ( 0x01 );
101		anslcd_write_byte_ctrl ( 0x02 );
102		break;
103	case ANSLCD_SENDCTRL:
104		temp = (char __user *) arg;
105		__get_user(ch, temp);
106		for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */
107			anslcd_write_byte_ctrl ( ch );
108			__get_user(ch, temp);
109		}
110		break;
111	case ANSLCD_SETSHORTDELAY:
112		if (!capable(CAP_SYS_ADMIN))
113			ret =-EACCES;
114		else
115			anslcd_short_delay=arg;
116		break;
117	case ANSLCD_SETLONGDELAY:
118		if (!capable(CAP_SYS_ADMIN))
119			ret = -EACCES;
120		else
121			anslcd_long_delay=arg;
122		break;
123	default:
124		ret = -EINVAL;
125	}
126
127	mutex_unlock(&anslcd_mutex);
128	return ret;
129}
130
131static int
132anslcd_open( struct inode * inode, struct file * file )
133{
134	return 0;
135}
136
137const struct file_operations anslcd_fops = {
138	.write		= anslcd_write,
139	.unlocked_ioctl	= anslcd_ioctl,
140	.open		= anslcd_open,
141	.llseek		= default_llseek,
142};
143
144static struct miscdevice anslcd_dev = {
145	ANSLCD_MINOR,
146	"anslcd",
147	&anslcd_fops
148};
149
150const char anslcd_logo[] =	"********************"  /* Line #1 */
151				"*      LINUX!      *"  /* Line #3 */
152				"*    Welcome to    *"  /* Line #2 */
153				"********************"; /* Line #4 */
154
155static int __init
156anslcd_init(void)
157{
158	int a;
159	int retval;
160	struct device_node* node;
161
162	node = of_find_node_by_name(NULL, "lcd");
163	if (!node || !of_node_name_eq(node->parent, "gc")) {
164		of_node_put(node);
165		return -ENODEV;
166	}
167	of_node_put(node);
168
169	anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
170	
171	retval = misc_register(&anslcd_dev);
172	if(retval < 0){
173		printk(KERN_INFO "LCD: misc_register failed\n");
174		iounmap(anslcd_ptr);
175		return retval;
176	}
177
178#ifdef DEBUG
179	printk(KERN_DEBUG "LCD: init\n");
180#endif
181
182	mutex_lock(&anslcd_mutex);
183	anslcd_write_byte_ctrl ( 0x38 );
184	anslcd_write_byte_ctrl ( 0x0c );
185	anslcd_write_byte_ctrl ( 0x06 );
186	anslcd_write_byte_ctrl ( 0x01 );
187	anslcd_write_byte_ctrl ( 0x02 );
188	for(a=0;a<80;a++) {
189		anslcd_write_byte_data(anslcd_logo[a]);
190	}
191	mutex_unlock(&anslcd_mutex);
192	return 0;
193}
194
195static void __exit
196anslcd_exit(void)
197{
198	misc_deregister(&anslcd_dev);
199	iounmap(anslcd_ptr);
200}
201
202module_init(anslcd_init);
203module_exit(anslcd_exit);
204MODULE_LICENSE("GPL v2");