diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/serial/mux.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/serial/mux.c')
-rw-r--r-- | drivers/serial/mux.c | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c new file mode 100644 index 000000000000..dadd7e19714e --- /dev/null +++ b/drivers/serial/mux.c | |||
@@ -0,0 +1,539 @@ | |||
1 | /* | ||
2 | ** mux.c: | ||
3 | ** serial driver for the Mux console found in some PA-RISC servers. | ||
4 | ** | ||
5 | ** (c) Copyright 2002 Ryan Bradetich | ||
6 | ** (c) Copyright 2002 Hewlett-Packard Company | ||
7 | ** | ||
8 | ** This program is free software; you can redistribute it and/or modify | ||
9 | ** it under the terms of the GNU General Public License as published by | ||
10 | ** the Free Software Foundation; either version 2 of the License, or | ||
11 | ** (at your option) any later version. | ||
12 | ** | ||
13 | ** This Driver currently only supports the console (port 0) on the MUX. | ||
14 | ** Additional work will be needed on this driver to enable the full | ||
15 | ** functionality of the MUX. | ||
16 | ** | ||
17 | */ | ||
18 | |||
19 | #include <linux/config.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/tty.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/serial.h> | ||
25 | #include <linux/console.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/delay.h> /* for udelay */ | ||
28 | #include <linux/device.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/parisc-device.h> | ||
31 | |||
32 | #ifdef CONFIG_MAGIC_SYSRQ | ||
33 | #include <linux/sysrq.h> | ||
34 | #define SUPPORT_SYSRQ | ||
35 | #endif | ||
36 | |||
37 | #include <linux/serial_core.h> | ||
38 | |||
39 | #define MUX_OFFSET 0x800 | ||
40 | #define MUX_LINE_OFFSET 0x80 | ||
41 | |||
42 | #define MUX_FIFO_SIZE 255 | ||
43 | #define MUX_POLL_DELAY (30 * HZ / 1000) | ||
44 | |||
45 | #define IO_DATA_REG_OFFSET 0x3c | ||
46 | #define IO_DCOUNT_REG_OFFSET 0x40 | ||
47 | |||
48 | #define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000) | ||
49 | #define MUX_STATUS(status) ((status & 0xF000) == 0x8000) | ||
50 | #define MUX_BREAK(status) ((status & 0xF000) == 0x2000) | ||
51 | |||
52 | #define MUX_NR 256 | ||
53 | static unsigned int port_cnt = 0; | ||
54 | static struct uart_port mux_ports[MUX_NR]; | ||
55 | |||
56 | static struct uart_driver mux_driver = { | ||
57 | .owner = THIS_MODULE, | ||
58 | .driver_name = "ttyB", | ||
59 | .dev_name = "ttyB", | ||
60 | .major = MUX_MAJOR, | ||
61 | .minor = 0, | ||
62 | .nr = MUX_NR, | ||
63 | }; | ||
64 | |||
65 | static struct timer_list mux_timer; | ||
66 | |||
67 | #define UART_PUT_CHAR(p, c) __raw_writel((c), (unsigned long)(p)->membase + IO_DATA_REG_OFFSET) | ||
68 | #define UART_GET_FIFO_CNT(p) __raw_readl((unsigned long)(p)->membase + IO_DCOUNT_REG_OFFSET) | ||
69 | #define GET_MUX_PORTS(iodc_data) ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8 | ||
70 | |||
71 | /** | ||
72 | * mux_tx_empty - Check if the transmitter fifo is empty. | ||
73 | * @port: Ptr to the uart_port. | ||
74 | * | ||
75 | * This function test if the transmitter fifo for the port | ||
76 | * described by 'port' is empty. If it is empty, this function | ||
77 | * should return TIOCSER_TEMT, otherwise return 0. | ||
78 | */ | ||
79 | static unsigned int mux_tx_empty(struct uart_port *port) | ||
80 | { | ||
81 | unsigned int cnt = __raw_readl((unsigned long)port->membase | ||
82 | + IO_DCOUNT_REG_OFFSET); | ||
83 | |||
84 | return cnt ? 0 : TIOCSER_TEMT; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * mux_set_mctrl - Set the current state of the modem control inputs. | ||
89 | * @ports: Ptr to the uart_port. | ||
90 | * @mctrl: Modem control bits. | ||
91 | * | ||
92 | * The Serial MUX does not support CTS, DCD or DSR so this function | ||
93 | * is ignored. | ||
94 | */ | ||
95 | static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
96 | { | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * mux_get_mctrl - Returns the current state of modem control inputs. | ||
101 | * @port: Ptr to the uart_port. | ||
102 | * | ||
103 | * The Serial MUX does not support CTS, DCD or DSR so these lines are | ||
104 | * treated as permanently active. | ||
105 | */ | ||
106 | static unsigned int mux_get_mctrl(struct uart_port *port) | ||
107 | { | ||
108 | return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * mux_stop_tx - Stop transmitting characters. | ||
113 | * @port: Ptr to the uart_port. | ||
114 | * @tty_stop: tty layer issue this command? | ||
115 | * | ||
116 | * The Serial MUX does not support this function. | ||
117 | */ | ||
118 | static void mux_stop_tx(struct uart_port *port, unsigned int tty_stop) | ||
119 | { | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * mux_start_tx - Start transmitting characters. | ||
124 | * @port: Ptr to the uart_port. | ||
125 | * @tty_start: tty layer issue this command? | ||
126 | * | ||
127 | * The Serial Mux does not support this function. | ||
128 | */ | ||
129 | static void mux_start_tx(struct uart_port *port, unsigned int tty_start) | ||
130 | { | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * mux_stop_rx - Stop receiving characters. | ||
135 | * @port: Ptr to the uart_port. | ||
136 | * | ||
137 | * The Serial Mux does not support this function. | ||
138 | */ | ||
139 | static void mux_stop_rx(struct uart_port *port) | ||
140 | { | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * mux_enable_ms - Enable modum status interrupts. | ||
145 | * @port: Ptr to the uart_port. | ||
146 | * | ||
147 | * The Serial Mux does not support this function. | ||
148 | */ | ||
149 | static void mux_enable_ms(struct uart_port *port) | ||
150 | { | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * mux_break_ctl - Control the transmitssion of a break signal. | ||
155 | * @port: Ptr to the uart_port. | ||
156 | * @break_state: Raise/Lower the break signal. | ||
157 | * | ||
158 | * The Serial Mux does not support this function. | ||
159 | */ | ||
160 | static void mux_break_ctl(struct uart_port *port, int break_state) | ||
161 | { | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * mux_write - Write chars to the mux fifo. | ||
166 | * @port: Ptr to the uart_port. | ||
167 | * | ||
168 | * This function writes all the data from the uart buffer to | ||
169 | * the mux fifo. | ||
170 | */ | ||
171 | static void mux_write(struct uart_port *port) | ||
172 | { | ||
173 | int count; | ||
174 | struct circ_buf *xmit = &port->info->xmit; | ||
175 | |||
176 | if(port->x_char) { | ||
177 | UART_PUT_CHAR(port, port->x_char); | ||
178 | port->icount.tx++; | ||
179 | port->x_char = 0; | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | if(uart_circ_empty(xmit) || uart_tx_stopped(port)) { | ||
184 | mux_stop_tx(port, 0); | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | count = (port->fifosize) - UART_GET_FIFO_CNT(port); | ||
189 | do { | ||
190 | UART_PUT_CHAR(port, xmit->buf[xmit->tail]); | ||
191 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
192 | port->icount.tx++; | ||
193 | if(uart_circ_empty(xmit)) | ||
194 | break; | ||
195 | |||
196 | } while(--count > 0); | ||
197 | |||
198 | while(UART_GET_FIFO_CNT(port)) | ||
199 | udelay(1); | ||
200 | |||
201 | if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
202 | uart_write_wakeup(port); | ||
203 | |||
204 | if (uart_circ_empty(xmit)) | ||
205 | mux_stop_tx(port, 0); | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * mux_read - Read chars from the mux fifo. | ||
210 | * @port: Ptr to the uart_port. | ||
211 | * | ||
212 | * This reads all available data from the mux's fifo and pushes | ||
213 | * the data to the tty layer. | ||
214 | */ | ||
215 | static void mux_read(struct uart_port *port) | ||
216 | { | ||
217 | int data; | ||
218 | struct tty_struct *tty = port->info->tty; | ||
219 | __u32 start_count = port->icount.rx; | ||
220 | |||
221 | while(1) { | ||
222 | data = __raw_readl((unsigned long)port->membase | ||
223 | + IO_DATA_REG_OFFSET); | ||
224 | |||
225 | if (MUX_STATUS(data)) | ||
226 | continue; | ||
227 | |||
228 | if (MUX_EOFIFO(data)) | ||
229 | break; | ||
230 | |||
231 | if (tty->flip.count >= TTY_FLIPBUF_SIZE) | ||
232 | continue; | ||
233 | |||
234 | *tty->flip.char_buf_ptr = data & 0xffu; | ||
235 | *tty->flip.flag_buf_ptr = TTY_NORMAL; | ||
236 | port->icount.rx++; | ||
237 | |||
238 | if (MUX_BREAK(data)) { | ||
239 | port->icount.brk++; | ||
240 | if(uart_handle_break(port)) | ||
241 | continue; | ||
242 | } | ||
243 | |||
244 | if (uart_handle_sysrq_char(port, data & 0xffu, NULL)) | ||
245 | continue; | ||
246 | |||
247 | tty->flip.flag_buf_ptr++; | ||
248 | tty->flip.char_buf_ptr++; | ||
249 | tty->flip.count++; | ||
250 | } | ||
251 | |||
252 | if (start_count != port->icount.rx) { | ||
253 | tty_flip_buffer_push(tty); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * mux_startup - Initialize the port. | ||
259 | * @port: Ptr to the uart_port. | ||
260 | * | ||
261 | * Grab any resources needed for this port and start the | ||
262 | * mux timer. | ||
263 | */ | ||
264 | static int mux_startup(struct uart_port *port) | ||
265 | { | ||
266 | mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * mux_shutdown - Disable the port. | ||
272 | * @port: Ptr to the uart_port. | ||
273 | * | ||
274 | * Release any resources needed for the port. | ||
275 | */ | ||
276 | static void mux_shutdown(struct uart_port *port) | ||
277 | { | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * mux_set_termios - Chane port parameters. | ||
282 | * @port: Ptr to the uart_port. | ||
283 | * @termios: new termios settings. | ||
284 | * @old: old termios settings. | ||
285 | * | ||
286 | * The Serial Mux does not support this function. | ||
287 | */ | ||
288 | static void | ||
289 | mux_set_termios(struct uart_port *port, struct termios *termios, | ||
290 | struct termios *old) | ||
291 | { | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * mux_type - Describe the port. | ||
296 | * @port: Ptr to the uart_port. | ||
297 | * | ||
298 | * Return a pointer to a string constant describing the | ||
299 | * specified port. | ||
300 | */ | ||
301 | static const char *mux_type(struct uart_port *port) | ||
302 | { | ||
303 | return "Mux"; | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * mux_release_port - Release memory and IO regions. | ||
308 | * @port: Ptr to the uart_port. | ||
309 | * | ||
310 | * Release any memory and IO region resources currently in use by | ||
311 | * the port. | ||
312 | */ | ||
313 | static void mux_release_port(struct uart_port *port) | ||
314 | { | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * mux_request_port - Request memory and IO regions. | ||
319 | * @port: Ptr to the uart_port. | ||
320 | * | ||
321 | * Request any memory and IO region resources required by the port. | ||
322 | * If any fail, no resources should be registered when this function | ||
323 | * returns, and it should return -EBUSY on failure. | ||
324 | */ | ||
325 | static int mux_request_port(struct uart_port *port) | ||
326 | { | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * mux_config_port - Perform port autoconfiguration. | ||
332 | * @port: Ptr to the uart_port. | ||
333 | * @type: Bitmask of required configurations. | ||
334 | * | ||
335 | * Perform any autoconfiguration steps for the port. This functino is | ||
336 | * called if the UPF_BOOT_AUTOCONF flag is specified for the port. | ||
337 | * [Note: This is required for now because of a bug in the Serial core. | ||
338 | * rmk has already submitted a patch to linus, should be available for | ||
339 | * 2.5.47.] | ||
340 | */ | ||
341 | static void mux_config_port(struct uart_port *port, int type) | ||
342 | { | ||
343 | port->type = PORT_MUX; | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * mux_verify_port - Verify the port information. | ||
348 | * @port: Ptr to the uart_port. | ||
349 | * @ser: Ptr to the serial information. | ||
350 | * | ||
351 | * Verify the new serial port information contained within serinfo is | ||
352 | * suitable for this port type. | ||
353 | */ | ||
354 | static int mux_verify_port(struct uart_port *port, struct serial_struct *ser) | ||
355 | { | ||
356 | if(port->membase == NULL) | ||
357 | return -EINVAL; | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | /** | ||
363 | * mux_drv_poll - Mux poll function. | ||
364 | * @unused: Unused variable | ||
365 | * | ||
366 | * This function periodically polls the Serial MUX to check for new data. | ||
367 | */ | ||
368 | static void mux_poll(unsigned long unused) | ||
369 | { | ||
370 | int i; | ||
371 | |||
372 | for(i = 0; i < port_cnt; ++i) { | ||
373 | if(!mux_ports[i].info) | ||
374 | continue; | ||
375 | |||
376 | mux_read(&mux_ports[i]); | ||
377 | mux_write(&mux_ports[i]); | ||
378 | } | ||
379 | |||
380 | mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); | ||
381 | } | ||
382 | |||
383 | |||
384 | #ifdef CONFIG_SERIAL_MUX_CONSOLE | ||
385 | static void mux_console_write(struct console *co, const char *s, unsigned count) | ||
386 | { | ||
387 | while(count--) | ||
388 | pdc_iodc_putc(*s++); | ||
389 | } | ||
390 | |||
391 | static int mux_console_setup(struct console *co, char *options) | ||
392 | { | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | struct tty_driver *mux_console_device(struct console *co, int *index) | ||
397 | { | ||
398 | *index = co->index; | ||
399 | return mux_driver.tty_driver; | ||
400 | } | ||
401 | |||
402 | static struct console mux_console = { | ||
403 | .name = "ttyB", | ||
404 | .write = mux_console_write, | ||
405 | .device = mux_console_device, | ||
406 | .setup = mux_console_setup, | ||
407 | .flags = CON_ENABLED | CON_PRINTBUFFER, | ||
408 | .index = 0, | ||
409 | }; | ||
410 | |||
411 | #define MUX_CONSOLE &mux_console | ||
412 | #else | ||
413 | #define MUX_CONSOLE NULL | ||
414 | #endif | ||
415 | |||
416 | static struct uart_ops mux_pops = { | ||
417 | .tx_empty = mux_tx_empty, | ||
418 | .set_mctrl = mux_set_mctrl, | ||
419 | .get_mctrl = mux_get_mctrl, | ||
420 | .stop_tx = mux_stop_tx, | ||
421 | .start_tx = mux_start_tx, | ||
422 | .stop_rx = mux_stop_rx, | ||
423 | .enable_ms = mux_enable_ms, | ||
424 | .break_ctl = mux_break_ctl, | ||
425 | .startup = mux_startup, | ||
426 | .shutdown = mux_shutdown, | ||
427 | .set_termios = mux_set_termios, | ||
428 | .type = mux_type, | ||
429 | .release_port = mux_release_port, | ||
430 | .request_port = mux_request_port, | ||
431 | .config_port = mux_config_port, | ||
432 | .verify_port = mux_verify_port, | ||
433 | }; | ||
434 | |||
435 | /** | ||
436 | * mux_probe - Determine if the Serial Mux should claim this device. | ||
437 | * @dev: The parisc device. | ||
438 | * | ||
439 | * Deterimine if the Serial Mux should claim this chip (return 0) | ||
440 | * or not (return 1). | ||
441 | */ | ||
442 | static int __init mux_probe(struct parisc_device *dev) | ||
443 | { | ||
444 | int i, status, ports; | ||
445 | u8 iodc_data[32]; | ||
446 | unsigned long bytecnt; | ||
447 | struct uart_port *port; | ||
448 | |||
449 | status = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 32); | ||
450 | if(status != PDC_OK) { | ||
451 | printk(KERN_ERR "Serial mux: Unable to read IODC.\n"); | ||
452 | return 1; | ||
453 | } | ||
454 | |||
455 | ports = GET_MUX_PORTS(iodc_data); | ||
456 | printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports); | ||
457 | |||
458 | if(!port_cnt) { | ||
459 | mux_driver.cons = MUX_CONSOLE; | ||
460 | |||
461 | status = uart_register_driver(&mux_driver); | ||
462 | if(status) { | ||
463 | printk(KERN_ERR "Serial mux: Unable to register driver.\n"); | ||
464 | return 1; | ||
465 | } | ||
466 | |||
467 | init_timer(&mux_timer); | ||
468 | mux_timer.function = mux_poll; | ||
469 | } | ||
470 | |||
471 | for(i = 0; i < ports; ++i, ++port_cnt) { | ||
472 | port = &mux_ports[port_cnt]; | ||
473 | port->iobase = 0; | ||
474 | port->mapbase = dev->hpa + MUX_OFFSET + (i * MUX_LINE_OFFSET); | ||
475 | port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET); | ||
476 | port->iotype = SERIAL_IO_MEM; | ||
477 | port->type = PORT_MUX; | ||
478 | port->irq = SERIAL_IRQ_NONE; | ||
479 | port->uartclk = 0; | ||
480 | port->fifosize = MUX_FIFO_SIZE; | ||
481 | port->ops = &mux_pops; | ||
482 | port->flags = UPF_BOOT_AUTOCONF; | ||
483 | port->line = port_cnt; | ||
484 | status = uart_add_one_port(&mux_driver, port); | ||
485 | BUG_ON(status); | ||
486 | } | ||
487 | |||
488 | #ifdef CONFIG_SERIAL_MUX_CONSOLE | ||
489 | register_console(&mux_console); | ||
490 | #endif | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static struct parisc_device_id mux_tbl[] = { | ||
495 | { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D }, | ||
496 | { 0, } | ||
497 | }; | ||
498 | |||
499 | MODULE_DEVICE_TABLE(parisc, mux_tbl); | ||
500 | |||
501 | static struct parisc_driver serial_mux_driver = { | ||
502 | .name = "Serial MUX", | ||
503 | .id_table = mux_tbl, | ||
504 | .probe = mux_probe, | ||
505 | }; | ||
506 | |||
507 | /** | ||
508 | * mux_init - Serial MUX initalization procedure. | ||
509 | * | ||
510 | * Register the Serial MUX driver. | ||
511 | */ | ||
512 | static int __init mux_init(void) | ||
513 | { | ||
514 | return register_parisc_driver(&serial_mux_driver); | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * mux_exit - Serial MUX cleanup procedure. | ||
519 | * | ||
520 | * Unregister the Serial MUX driver from the tty layer. | ||
521 | */ | ||
522 | static void __exit mux_exit(void) | ||
523 | { | ||
524 | int i; | ||
525 | |||
526 | for (i = 0; i < port_cnt; i++) { | ||
527 | uart_remove_one_port(&mux_driver, &mux_ports[i]); | ||
528 | } | ||
529 | |||
530 | uart_unregister_driver(&mux_driver); | ||
531 | } | ||
532 | |||
533 | module_init(mux_init); | ||
534 | module_exit(mux_exit); | ||
535 | |||
536 | MODULE_AUTHOR("Ryan Bradetich"); | ||
537 | MODULE_DESCRIPTION("Serial MUX driver"); | ||
538 | MODULE_LICENSE("GPL"); | ||
539 | MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR); | ||