- Kai Germaschewski: ymfpci cleanups and resource leak fixes
[davej-history.git] / drivers / char / serial_21285.c
blob16ad022bd7a4c95dd0e7bd001a97e491f7380dc6
1 /*
2 * linux/drivers/char/serial_21285.c
4 * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
6 * Based on drivers/char/serial.c
7 */
9 #include <linux/config.h>
10 #include <linux/module.h>
11 #include <linux/errno.h>
12 #include <linux/signal.h>
13 #include <linux/sched.h>
14 #include <linux/interrupt.h>
15 #include <linux/tty.h>
16 #include <linux/tty_flip.h>
17 #include <linux/serial.h>
18 #include <linux/major.h>
19 #include <linux/ptrace.h>
20 #include <linux/ioport.h>
21 #include <linux/mm.h>
22 #include <linux/malloc.h>
23 #include <linux/init.h>
24 #include <linux/console.h>
26 #include <asm/io.h>
27 #include <asm/irq.h>
28 #include <asm/uaccess.h>
29 #include <asm/dec21285.h>
30 #include <asm/hardware.h>
32 #define BAUD_BASE (mem_fclk_21285/64)
34 #define SERIAL_21285_NAME "ttyFB"
35 #define SERIAL_21285_MAJOR 204
36 #define SERIAL_21285_MINOR 4
38 #define SERIAL_21285_AUXNAME "cuafb"
39 #define SERIAL_21285_AUXMAJOR 205
40 #define SERIAL_21285_AUXMINOR 4
42 static struct tty_driver rs285_driver, callout_driver;
43 static int rs285_refcount;
44 static struct tty_struct *rs285_table[1];
46 static struct termios *rs285_termios[1];
47 static struct termios *rs285_termios_locked[1];
49 static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char;
50 static struct tty_struct *rs285_tty;
51 static int rs285_use_count;
53 static int rs285_write_room(struct tty_struct *tty)
55 return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1);
58 static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs)
60 if (!rs285_tty) {
61 disable_irq(IRQ_CONRX);
62 return;
64 while (!(*CSR_UARTFLG & 0x10)) {
65 int ch, flag;
66 ch = *CSR_UARTDR;
67 flag = *CSR_RXSTAT;
68 if (flag & 4)
69 tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN);
70 if (flag & 2)
71 flag = TTY_PARITY;
72 else if (flag & 1)
73 flag = TTY_FRAME;
74 tty_insert_flip_char(rs285_tty, ch, flag);
76 tty_flip_buffer_push(rs285_tty);
79 static void rs285_send_xchar(struct tty_struct *tty, char ch)
81 x_char = ch;
82 enable_irq(IRQ_CONTX);
85 static void rs285_throttle(struct tty_struct *tty)
87 if (I_IXOFF(tty))
88 rs285_send_xchar(tty, STOP_CHAR(tty));
91 static void rs285_unthrottle(struct tty_struct *tty)
93 if (I_IXOFF(tty)) {
94 if (x_char)
95 x_char = 0;
96 else
97 rs285_send_xchar(tty, START_CHAR(tty));
101 static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs)
103 while (!(*CSR_UARTFLG & 0x20)) {
104 if (x_char) {
105 *CSR_UARTDR = x_char;
106 x_char = 0;
107 continue;
109 if (putp == getp) {
110 disable_irq(IRQ_CONTX);
111 break;
113 *CSR_UARTDR = *getp;
114 if (++getp >= wbuf + sizeof(wbuf))
115 getp = wbuf;
117 if (rs285_tty)
118 wake_up_interruptible(&rs285_tty->write_wait);
121 static inline int rs285_xmit(int ch)
123 if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf))
124 return 0;
125 *putp = ch;
126 if (++putp >= wbuf + sizeof(wbuf))
127 putp = wbuf;
128 enable_irq(IRQ_CONTX);
129 return 1;
132 static int rs285_write(struct tty_struct *tty, int from_user,
133 const u_char * buf, int count)
135 int i;
137 if (from_user && verify_area(VERIFY_READ, buf, count))
138 return -EINVAL;
140 for (i = 0; i < count; i++) {
141 char ch;
142 if (from_user)
143 __get_user(ch, buf + i);
144 else
145 ch = buf[i];
146 if (!rs285_xmit(ch))
147 break;
149 return i;
152 static void rs285_put_char(struct tty_struct *tty, u_char ch)
154 rs285_xmit(ch);
157 static int rs285_chars_in_buffer(struct tty_struct *tty)
159 return sizeof(wbuf) - rs285_write_room(tty);
162 static void rs285_flush_buffer(struct tty_struct *tty)
164 disable_irq(IRQ_CONTX);
165 putp = getp = wbuf;
166 if (x_char)
167 enable_irq(IRQ_CONTX);
170 static inline void rs285_set_cflag(int cflag)
172 int h_lcr, baud, quot;
174 switch (cflag & CSIZE) {
175 case CS5:
176 h_lcr = 0x10;
177 break;
178 case CS6:
179 h_lcr = 0x30;
180 break;
181 case CS7:
182 h_lcr = 0x50;
183 break;
184 default: /* CS8 */
185 h_lcr = 0x70;
186 break;
189 if (cflag & CSTOPB)
190 h_lcr |= 0x08;
191 if (cflag & PARENB)
192 h_lcr |= 0x02;
193 if (!(cflag & PARODD))
194 h_lcr |= 0x04;
196 switch (cflag & CBAUD) {
197 case B200: baud = 200; break;
198 case B300: baud = 300; break;
199 case B1200: baud = 1200; break;
200 case B1800: baud = 1800; break;
201 case B2400: baud = 2400; break;
202 case B4800: baud = 4800; break;
203 default:
204 case B9600: baud = 9600; break;
205 case B19200: baud = 19200; break;
206 case B38400: baud = 38400; break;
207 case B57600: baud = 57600; break;
208 case B115200: baud = 115200; break;
212 * The documented expression for selecting the divisor is:
213 * BAUD_BASE / baud - 1
214 * However, typically BAUD_BASE is not divisible by baud, so
215 * we want to select the divisor that gives us the minimum
216 * error. Therefore, we want:
217 * int(BAUD_BASE / baud - 0.5) ->
218 * int(BAUD_BASE / baud - (baud >> 1) / baud) ->
219 * int((BAUD_BASE - (baud >> 1)) / baud)
221 quot = (BAUD_BASE - (baud >> 1)) / baud;
223 *CSR_UARTCON = 0;
224 *CSR_L_UBRLCR = quot & 0xff;
225 *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
226 *CSR_H_UBRLCR = h_lcr;
227 *CSR_UARTCON = 1;
230 static void rs285_set_termios(struct tty_struct *tty, struct termios *old)
232 if (old && tty->termios->c_cflag == old->c_cflag)
233 return;
234 rs285_set_cflag(tty->termios->c_cflag);
238 static void rs285_stop(struct tty_struct *tty)
240 disable_irq(IRQ_CONTX);
243 static void rs285_start(struct tty_struct *tty)
245 enable_irq(IRQ_CONTX);
248 static void rs285_wait_until_sent(struct tty_struct *tty, int timeout)
250 int orig_jiffies = jiffies;
251 while (*CSR_UARTFLG & 8) {
252 current->state = TASK_INTERRUPTIBLE;
253 schedule_timeout(1);
254 if (signal_pending(current))
255 break;
256 if (timeout && time_after(jiffies, orig_jiffies + timeout))
257 break;
259 current->state = TASK_RUNNING;
262 static int rs285_open(struct tty_struct *tty, struct file *filp)
264 int line;
266 MOD_INC_USE_COUNT;
267 line = MINOR(tty->device) - tty->driver.minor_start;
268 if (line) {
269 MOD_DEC_USE_COUNT;
270 return -ENODEV;
273 tty->driver_data = NULL;
274 if (!rs285_tty)
275 rs285_tty = tty;
277 enable_irq(IRQ_CONRX);
278 rs285_use_count++;
279 return 0;
282 static void rs285_close(struct tty_struct *tty, struct file *filp)
284 if (!--rs285_use_count) {
285 rs285_wait_until_sent(tty, 0);
286 disable_irq(IRQ_CONRX);
287 disable_irq(IRQ_CONTX);
288 rs285_tty = NULL;
290 MOD_DEC_USE_COUNT;
293 static int __init rs285_init(void)
295 int baud = B9600;
297 if (machine_is_personal_server())
298 baud = B57600;
300 rs285_driver.magic = TTY_DRIVER_MAGIC;
301 rs285_driver.driver_name = "serial_21285";
302 rs285_driver.name = SERIAL_21285_NAME;
303 rs285_driver.major = SERIAL_21285_MAJOR;
304 rs285_driver.minor_start = SERIAL_21285_MINOR;
305 rs285_driver.num = 1;
306 rs285_driver.type = TTY_DRIVER_TYPE_SERIAL;
307 rs285_driver.subtype = SERIAL_TYPE_NORMAL;
308 rs285_driver.init_termios = tty_std_termios;
309 rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL;
310 rs285_driver.flags = TTY_DRIVER_REAL_RAW;
311 rs285_driver.refcount = &rs285_refcount;
312 rs285_driver.table = rs285_table;
313 rs285_driver.termios = rs285_termios;
314 rs285_driver.termios_locked = rs285_termios_locked;
316 rs285_driver.open = rs285_open;
317 rs285_driver.close = rs285_close;
318 rs285_driver.write = rs285_write;
319 rs285_driver.put_char = rs285_put_char;
320 rs285_driver.write_room = rs285_write_room;
321 rs285_driver.chars_in_buffer = rs285_chars_in_buffer;
322 rs285_driver.flush_buffer = rs285_flush_buffer;
323 rs285_driver.throttle = rs285_throttle;
324 rs285_driver.unthrottle = rs285_unthrottle;
325 rs285_driver.send_xchar = rs285_send_xchar;
326 rs285_driver.set_termios = rs285_set_termios;
327 rs285_driver.stop = rs285_stop;
328 rs285_driver.start = rs285_start;
329 rs285_driver.wait_until_sent = rs285_wait_until_sent;
331 callout_driver = rs285_driver;
332 callout_driver.name = SERIAL_21285_AUXNAME;
333 callout_driver.major = SERIAL_21285_AUXMAJOR;
334 callout_driver.subtype = SERIAL_TYPE_CALLOUT;
336 if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL))
337 panic("Couldn't get rx irq for rs285");
339 if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL))
340 panic("Couldn't get tx irq for rs285");
342 if (tty_register_driver(&rs285_driver))
343 printk(KERN_ERR "Couldn't register 21285 serial driver\n");
344 if (tty_register_driver(&callout_driver))
345 printk(KERN_ERR "Couldn't register 21285 callout driver\n");
347 return 0;
350 static void __exit rs285_fini(void)
352 unsigned long flags;
353 int ret;
355 save_flags(flags);
356 cli();
357 ret = tty_unregister_driver(&callout_driver);
358 if (ret)
359 printk(KERN_ERR "Unable to unregister 21285 callout driver "
360 "(%d)\n", ret);
361 ret = tty_unregister_driver(&rs285_driver);
362 if (ret)
363 printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n",
364 ret);
365 free_irq(IRQ_CONTX, NULL);
366 free_irq(IRQ_CONRX, NULL);
367 restore_flags(flags);
370 module_init(rs285_init);
371 module_exit(rs285_fini);
373 #ifdef CONFIG_SERIAL_21285_CONSOLE
374 /************** console driver *****************/
376 static void rs285_console_write(struct console *co, const char *s, u_int count)
378 int i;
380 disable_irq(IRQ_CONTX);
381 for (i = 0; i < count; i++) {
382 while (*CSR_UARTFLG & 0x20);
383 *CSR_UARTDR = s[i];
384 if (s[i] == '\n') {
385 while (*CSR_UARTFLG & 0x20);
386 *CSR_UARTDR = '\r';
389 enable_irq(IRQ_CONTX);
392 static int rs285_console_wait_key(struct console *co)
394 int c;
396 disable_irq(IRQ_CONRX);
397 while (*CSR_UARTFLG & 0x10);
398 c = *CSR_UARTDR;
399 enable_irq(IRQ_CONRX);
400 return c;
403 static kdev_t rs285_console_device(struct console *c)
405 return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
408 static int __init rs285_console_setup(struct console *co, char *options)
410 int baud = 9600;
411 int bits = 8;
412 int parity = 'n';
413 int cflag = CREAD | HUPCL | CLOCAL;
415 if (machine_is_personal_server())
416 baud = 57600;
418 if (options) {
419 char *s = options;
420 baud = simple_strtoul(options, NULL, 10);
421 while (*s >= '0' && *s <= '9')
422 s++;
423 if (*s)
424 parity = *s++;
425 if (*s)
426 bits = *s - '0';
430 * Now construct a cflag setting.
432 switch (baud) {
433 case 1200:
434 cflag |= B1200;
435 break;
436 case 2400:
437 cflag |= B2400;
438 break;
439 case 4800:
440 cflag |= B4800;
441 break;
442 case 9600:
443 cflag |= B9600;
444 break;
445 case 19200:
446 cflag |= B19200;
447 break;
448 case 38400:
449 cflag |= B38400;
450 break;
451 case 57600:
452 cflag |= B57600;
453 break;
454 case 115200:
455 cflag |= B115200;
456 break;
457 default:
458 cflag |= B9600;
459 break;
461 switch (bits) {
462 case 7:
463 cflag |= CS7;
464 break;
465 default:
466 cflag |= CS8;
467 break;
469 switch (parity) {
470 case 'o':
471 case 'O':
472 cflag |= PARODD;
473 break;
474 case 'e':
475 case 'E':
476 cflag |= PARENB;
477 break;
479 co->cflag = cflag;
480 rs285_set_cflag(cflag);
481 rs285_console_write(NULL, "\e[2J\e[Hboot ", 12);
482 if (options)
483 rs285_console_write(NULL, options, strlen(options));
484 else
485 rs285_console_write(NULL, "no options", 10);
486 rs285_console_write(NULL, "\n", 1);
488 return 0;
491 static struct console rs285_cons =
493 name: SERIAL_21285_NAME,
494 write: rs285_console_write,
495 device: rs285_console_device,
496 wait_key: rs285_console_wait_key,
497 setup: rs285_console_setup,
498 flags: CON_PRINTBUFFER,
499 index: -1,
502 void __init rs285_console_init(void)
504 register_console(&rs285_cons);
507 #endif /* CONFIG_SERIAL_21285_CONSOLE */