File: /usr/src/linux/drivers/char/serial_21285.c

1     /*
2      * linux/drivers/char/serial_21285.c
3      *
4      * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
5      *
6      * Based on drivers/char/serial.c
7      */
8     
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/slab.h>
23     #include <linux/init.h>
24     #include <linux/console.h>
25     
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>
31     
32     #define BAUD_BASE		(mem_fclk_21285/64)
33     
34     #define SERIAL_21285_NAME	"ttyFB"
35     #define SERIAL_21285_MAJOR	204
36     #define SERIAL_21285_MINOR	4
37     
38     #define SERIAL_21285_AUXNAME	"cuafb"
39     #define SERIAL_21285_AUXMAJOR	205
40     #define SERIAL_21285_AUXMINOR	4
41     
42     static struct tty_driver rs285_driver, callout_driver;
43     static int rs285_refcount;
44     static struct tty_struct *rs285_table[1];
45     
46     static struct termios *rs285_termios[1];
47     static struct termios *rs285_termios_locked[1];
48     
49     static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char;
50     static struct tty_struct *rs285_tty;
51     static int rs285_use_count;
52     
53     static int rs285_write_room(struct tty_struct *tty)
54     {
55     	return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1);
56     }
57     
58     static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs)
59     {
60     	if (!rs285_tty) {
61     		disable_irq(IRQ_CONRX);
62     		return;
63     	}
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);
75     	}
76     	tty_flip_buffer_push(rs285_tty);
77     }
78     
79     static void rs285_send_xchar(struct tty_struct *tty, char ch)
80     {
81     	x_char = ch;
82     	enable_irq(IRQ_CONTX);
83     }
84     
85     static void rs285_throttle(struct tty_struct *tty)
86     {
87     	if (I_IXOFF(tty))
88     		rs285_send_xchar(tty, STOP_CHAR(tty));
89     }
90     
91     static void rs285_unthrottle(struct tty_struct *tty)
92     {
93     	if (I_IXOFF(tty)) {
94     		if (x_char)
95     			x_char = 0;
96     		else
97     			rs285_send_xchar(tty, START_CHAR(tty));
98     	}
99     }
100     
101     static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs)
102     {
103     	while (!(*CSR_UARTFLG & 0x20)) {
104     		if (x_char) {
105     			*CSR_UARTDR = x_char;
106     			x_char = 0;
107     			continue;
108     		}
109     		if (putp == getp) {
110     			disable_irq(IRQ_CONTX);
111     			break;
112     		}
113     		*CSR_UARTDR = *getp;
114     		if (++getp >= wbuf + sizeof(wbuf))
115     			getp = wbuf;
116     	}
117     	if (rs285_tty)
118     		wake_up_interruptible(&rs285_tty->write_wait);
119     }
120     
121     static inline int rs285_xmit(int ch)
122     {
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;
130     }
131     
132     static int rs285_write(struct tty_struct *tty, int from_user,
133     		       const u_char * buf, int count)
134     {
135     	int i;
136     
137     	if (from_user && verify_area(VERIFY_READ, buf, count))
138     		return -EINVAL;
139     
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;
148     	}
149     	return i;
150     }
151     
152     static void rs285_put_char(struct tty_struct *tty, u_char ch)
153     {
154     	rs285_xmit(ch);
155     }
156     
157     static int rs285_chars_in_buffer(struct tty_struct *tty)
158     {
159     	return sizeof(wbuf) - rs285_write_room(tty);
160     }
161     
162     static void rs285_flush_buffer(struct tty_struct *tty)
163     {
164     	disable_irq(IRQ_CONTX);
165     	putp = getp = wbuf;
166     	if (x_char)
167     		enable_irq(IRQ_CONTX);
168     }
169     
170     static inline void rs285_set_cflag(int cflag)
171     {
172     	int h_lcr, baud, quot;
173     
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;
187     
188     	}
189     	if (cflag & CSTOPB)
190     		h_lcr |= 0x08;
191     	if (cflag & PARENB)
192     		h_lcr |= 0x02;
193     	if (!(cflag & PARODD))
194     		h_lcr |= 0x04;
195     
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;
209     	}
210     
211     	/*
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)
220     	 */
221     	quot = (BAUD_BASE - (baud >> 1)) / baud;
222     
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;
228     }
229     
230     static void rs285_set_termios(struct tty_struct *tty, struct termios *old)
231     {
232     	if (old && tty->termios->c_cflag == old->c_cflag)
233     		return;
234     	rs285_set_cflag(tty->termios->c_cflag);
235     }
236     
237     
238     static void rs285_stop(struct tty_struct *tty)
239     {
240     	disable_irq(IRQ_CONTX);
241     }
242     
243     static void rs285_start(struct tty_struct *tty)
244     {
245     	enable_irq(IRQ_CONTX);
246     }
247     
248     static void rs285_wait_until_sent(struct tty_struct *tty, int timeout)
249     {
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;
258     	}
259     	current->state = TASK_RUNNING;
260     }
261     
262     static int rs285_open(struct tty_struct *tty, struct file *filp)
263     {
264     	int line;
265     
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;
271     	}
272     
273     	tty->driver_data = NULL;
274     	if (!rs285_tty)
275     		rs285_tty = tty;
276     
277     	enable_irq(IRQ_CONRX);
278     	rs285_use_count++;
279     	return 0;
280     }
281     
282     static void rs285_close(struct tty_struct *tty, struct file *filp)
283     {
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;
289     	}
290     	MOD_DEC_USE_COUNT;
291     }
292     
293     static int __init rs285_init(void)
294     {
295     	int baud = B9600;
296     
297     	if (machine_is_personal_server())
298     		baud = B57600;
299     
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;
315     
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;
330     
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;
335     
336     	if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL))
337     		panic("Couldn't get rx irq for rs285");
338     
339     	if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL))
340     		panic("Couldn't get tx irq for rs285");
341     
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");
346     
347     	return 0;
348     }
349     
350     static void __exit rs285_fini(void)
351     {
352     	unsigned long flags;
353     	int ret;
354     
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);
368     }
369     
370     module_init(rs285_init);
371     module_exit(rs285_fini);
372     
373     #ifdef CONFIG_SERIAL_21285_CONSOLE
374     /************** console driver *****************/
375     
376     static void rs285_console_write(struct console *co, const char *s, u_int count)
377     {
378     	int i;
379     
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';
387     		}
388     	}
389     	enable_irq(IRQ_CONTX);
390     }
391     
392     static int rs285_console_wait_key(struct console *co)
393     {
394     	int c;
395     
396     	disable_irq(IRQ_CONRX);
397     	while (*CSR_UARTFLG & 0x10);
398     	c = *CSR_UARTDR;
399     	enable_irq(IRQ_CONRX);
400     	return c;
401     }
402     
403     static kdev_t rs285_console_device(struct console *c)
404     {
405     	return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
406     }
407     
408     static int __init rs285_console_setup(struct console *co, char *options)
409     {
410     	int baud = 9600;
411     	int bits = 8;
412     	int parity = 'n';
413     	int cflag = CREAD | HUPCL | CLOCAL;
414     
415     	if (machine_is_personal_server())
416     		baud = 57600;
417     
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';
427     	}
428     
429     	/*
430     	 *    Now construct a cflag setting.
431     	 */
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;
460     	}
461     	switch (bits) {
462     	case 7:
463     		cflag |= CS7;
464     		break;
465     	default:
466     		cflag |= CS8;
467     		break;
468     	}
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;
478     	}
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);
487     
488     	return 0;
489     }
490     
491     static struct console rs285_cons =
492     {
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,
500     };
501     
502     void __init rs285_console_init(void)
503     {
504     	register_console(&rs285_cons);
505     }
506     
507     #endif	/* CONFIG_SERIAL_21285_CONSOLE */
508     
509     MODULE_LICENSE("GPL");
510     EXPORT_NO_SYMBOLS;
511