added mtd driver
[linux-2.4.git] / drivers / s390 / char / hwc_tty.c
1 /*
2  *  drivers/s390/char/hwc_tty.c
3  *    HWC line mode terminal driver.
4  *
5  *  S390 version
6  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7  *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
8  *
9  *  Thanks to Martin Schwidefsky.
10  */
11
12 #include <linux/config.h>
13 #include <linux/major.h>
14 #include <linux/termios.h>
15 #include <linux/tty.h>
16 #include <linux/tty_driver.h>
17 #include <linux/sched.h>
18 #include <linux/mm.h>
19 #include <linux/devfs_fs_kernel.h>
20 #include <linux/init.h>
21
22 #include <asm/uaccess.h>
23
24 #include "hwc_rw.h"
25 #include "ctrlchar.h"
26
27 #define HWC_TTY_PRINT_HEADER "hwc tty driver: "
28
29 #define HWC_TTY_BUF_SIZE 512
30
31 typedef struct {
32
33         struct tty_struct *tty;
34
35         unsigned char buf[HWC_TTY_BUF_SIZE];
36
37         unsigned short int buf_count;
38
39         spinlock_t lock;
40
41         hwc_high_level_calls_t calls;
42 } hwc_tty_data_struct;
43
44 static hwc_tty_data_struct hwc_tty_data =
45 { /* NULL/0 */ };
46 static struct tty_driver hwc_tty_driver;
47 static struct tty_struct *hwc_tty_table[1];
48 static struct termios *hwc_tty_termios[1];
49 static struct termios *hwc_tty_termios_locked[1];
50 static int hwc_tty_refcount = 0;
51
52 extern struct termios tty_std_termios;
53
54 void hwc_tty_wake_up (void);
55 void hwc_tty_input (unsigned char *, unsigned int);
56
57 static int 
58 hwc_tty_open (struct tty_struct *tty,
59               struct file *filp)
60 {
61
62         if (MINOR (tty->device) - tty->driver.minor_start)
63                 return -ENODEV;
64
65         tty->driver_data = &hwc_tty_data;
66         hwc_tty_data.buf_count = 0;
67         hwc_tty_data.tty = tty;
68         tty->low_latency = 0;
69
70         hwc_tty_data.calls.wake_up = hwc_tty_wake_up;
71         hwc_tty_data.calls.move_input = hwc_tty_input;
72         hwc_register_calls (&(hwc_tty_data.calls));
73
74         return 0;
75 }
76
77 static void 
78 hwc_tty_close (struct tty_struct *tty,
79                struct file *filp)
80 {
81         if (MINOR (tty->device) != tty->driver.minor_start) {
82                 printk (KERN_WARNING HWC_TTY_PRINT_HEADER
83                         "do not close hwc tty because of wrong device number");
84                 return;
85         }
86         if (tty->count > 1)
87                 return;
88
89         hwc_tty_data.tty = NULL;
90
91         hwc_unregister_calls (&(hwc_tty_data.calls));
92 }
93
94 static int 
95 hwc_tty_write_room (struct tty_struct *tty)
96 {
97         int retval;
98
99         retval = hwc_write_room (IN_BUFS_TOTAL);
100         return retval;
101 }
102
103 static int 
104 hwc_tty_write (struct tty_struct *tty,
105                int from_user,
106                const unsigned char *buf,
107                int count)
108 {
109         int retval;
110
111         if (hwc_tty_data.buf_count > 0) {
112                 hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
113                 hwc_tty_data.buf_count = 0;
114         }
115         retval = hwc_write (from_user, buf, count);
116         return retval;
117 }
118
119 static void 
120 hwc_tty_put_char (struct tty_struct *tty,
121                   unsigned char ch)
122 {
123         unsigned long flags;
124
125         spin_lock_irqsave (&hwc_tty_data.lock, flags);
126         if (hwc_tty_data.buf_count >= HWC_TTY_BUF_SIZE) {
127                 hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
128                 hwc_tty_data.buf_count = 0;
129         }
130         hwc_tty_data.buf[hwc_tty_data.buf_count] = ch;
131         hwc_tty_data.buf_count++;
132         spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
133 }
134
135 static void 
136 hwc_tty_flush_chars (struct tty_struct *tty)
137 {
138         unsigned long flags;
139
140         spin_lock_irqsave (&hwc_tty_data.lock, flags);
141         hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
142         hwc_tty_data.buf_count = 0;
143         spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
144 }
145
146 static int 
147 hwc_tty_chars_in_buffer (struct tty_struct *tty)
148 {
149         int retval;
150
151         retval = hwc_chars_in_buffer (IN_BUFS_TOTAL);
152         return retval;
153 }
154
155 static void 
156 hwc_tty_flush_buffer (struct tty_struct *tty)
157 {
158         hwc_tty_wake_up ();
159 }
160
161 static int 
162 hwc_tty_ioctl (
163                       struct tty_struct *tty,
164                       struct file *file,
165                       unsigned int cmd,
166                       unsigned long arg)
167 {
168         if (tty->flags & (1 << TTY_IO_ERROR))
169                 return -EIO;
170
171         return hwc_ioctl (cmd, arg);
172 }
173
174 void 
175 hwc_tty_wake_up (void)
176 {
177         if (hwc_tty_data.tty == NULL)
178                 return;
179         if ((hwc_tty_data.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
180             hwc_tty_data.tty->ldisc.write_wakeup)
181                 (hwc_tty_data.tty->ldisc.write_wakeup) (hwc_tty_data.tty);
182         wake_up_interruptible (&hwc_tty_data.tty->write_wait);
183 }
184
185 void 
186 hwc_tty_input (unsigned char *buf, unsigned int count)
187 {
188         struct tty_struct *tty = hwc_tty_data.tty;
189
190         if (tty != NULL) {
191                 char *cchar;
192                 if ((cchar = ctrlchar_handle (buf, count, tty))) {
193                         if (cchar == (char *) -1)
194                                 return;
195                         tty->flip.count++;
196                         *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
197                         *tty->flip.char_buf_ptr++ = *cchar;
198                 } else {
199
200                         memcpy (tty->flip.char_buf_ptr, buf, count);
201                         if (count < 2 || (
202                                          strncmp (buf + count - 2, "^n", 2) ||
203                                     strncmp (buf + count - 2, "\0252n", 2))) {
204                                 tty->flip.char_buf_ptr[count] = '\n';
205                                 count++;
206                         } else
207                                 count -= 2;
208                         memset (tty->flip.flag_buf_ptr, TTY_NORMAL, count);
209                         tty->flip.char_buf_ptr += count;
210                         tty->flip.flag_buf_ptr += count;
211                         tty->flip.count += count;
212                 }
213                 tty_flip_buffer_push (tty);
214                 hwc_tty_wake_up ();
215         }
216 }
217
218 void 
219 hwc_tty_init (void)
220 {
221         if (!CONSOLE_IS_HWC)
222                 return;
223
224         ctrlchar_init ();
225
226         memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
227         memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
228         hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
229         hwc_tty_driver.driver_name = "tty_hwc";
230         hwc_tty_driver.name = "ttyS";
231         hwc_tty_driver.name_base = 0;
232         hwc_tty_driver.major = TTY_MAJOR;
233         hwc_tty_driver.minor_start = 64;
234         hwc_tty_driver.num = 1;
235         hwc_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM;
236         hwc_tty_driver.subtype = SYSTEM_TYPE_TTY;
237         hwc_tty_driver.init_termios = tty_std_termios;
238         hwc_tty_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
239         hwc_tty_driver.init_termios.c_oflag = ONLCR;
240         hwc_tty_driver.init_termios.c_lflag = ISIG | ECHO;
241         hwc_tty_driver.flags = TTY_DRIVER_REAL_RAW;
242         hwc_tty_driver.refcount = &hwc_tty_refcount;
243
244         hwc_tty_driver.table = hwc_tty_table;
245         hwc_tty_driver.termios = hwc_tty_termios;
246         hwc_tty_driver.termios_locked = hwc_tty_termios_locked;
247
248         hwc_tty_driver.open = hwc_tty_open;
249         hwc_tty_driver.close = hwc_tty_close;
250         hwc_tty_driver.write = hwc_tty_write;
251         hwc_tty_driver.put_char = hwc_tty_put_char;
252         hwc_tty_driver.flush_chars = hwc_tty_flush_chars;
253         hwc_tty_driver.write_room = hwc_tty_write_room;
254         hwc_tty_driver.chars_in_buffer = hwc_tty_chars_in_buffer;
255         hwc_tty_driver.flush_buffer = hwc_tty_flush_buffer;
256         hwc_tty_driver.ioctl = hwc_tty_ioctl;
257
258         hwc_tty_driver.throttle = NULL;
259         hwc_tty_driver.unthrottle = NULL;
260         hwc_tty_driver.send_xchar = NULL;
261         hwc_tty_driver.set_termios = NULL;
262         hwc_tty_driver.set_ldisc = NULL;
263         hwc_tty_driver.stop = NULL;
264         hwc_tty_driver.start = NULL;
265         hwc_tty_driver.hangup = NULL;
266         hwc_tty_driver.break_ctl = NULL;
267         hwc_tty_driver.wait_until_sent = NULL;
268         hwc_tty_driver.read_proc = NULL;
269         hwc_tty_driver.write_proc = NULL;
270
271         if (tty_register_driver (&hwc_tty_driver))
272                 panic ("Couldn't register hwc_tty driver\n");
273 }