aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2013-02-06 09:45:01 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-02-06 14:10:17 -0500
commit8200e38a0cbf95dd2acaa565badb9b6a71c0e9c3 (patch)
tree6becf07cd2f608d3feeb56132484438fe3607c52 /drivers/tty
parent26f7936c332a3ddc7ce88d5eceffbac3062ab836 (diff)
tty: metag_da: Add metag DA TTY driver
Add a TTY driver for communicating over a Meta DA (Debug Adapter) channel using the bios channel SWITCH operation. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Jiri Slaby <jslaby@suse.cz> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/Kconfig13
-rw-r--r--drivers/tty/Makefile1
-rw-r--r--drivers/tty/metag_da.c680
3 files changed, 694 insertions, 0 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 29dfc24f2dbb..978db344bda0 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -406,4 +406,17 @@ config GOLDFISH_TTY
406 help 406 help
407 Console and system TTY driver for the Goldfish virtual platform. 407 Console and system TTY driver for the Goldfish virtual platform.
408 408
409config DA_TTY
410 bool "DA TTY"
411 depends on METAG_DA
412 select SERIAL_NONSTANDARD
413 help
414 This enables a TTY on a Dash channel.
415
416config DA_CONSOLE
417 bool "DA Console"
418 depends on DA_TTY
419 help
420 This enables a console on a Dash channel.
421
409endif # TTY 422endif # TTY
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 35649d35abf0..6b78399bc7c9 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -28,5 +28,6 @@ obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
28obj-$(CONFIG_SYNCLINK) += synclink.o 28obj-$(CONFIG_SYNCLINK) += synclink.o
29obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o 29obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
30obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o 30obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
31obj-$(CONFIG_DA_TTY) += metag_da.o
31 32
32obj-y += ipwireless/ 33obj-y += ipwireless/
diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c
new file mode 100644
index 000000000000..fc2a36bddd3f
--- /dev/null
+++ b/drivers/tty/metag_da.c
@@ -0,0 +1,680 @@
1/*
2 * dashtty.c - tty driver for Dash channels interface.
3 *
4 * Copyright (C) 2007,2008,2012 Imagination Technologies
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 *
10 */
11
12#include <linux/atomic.h>
13#include <linux/completion.h>
14#include <linux/console.h>
15#include <linux/delay.h>
16#include <linux/export.h>
17#include <linux/init.h>
18#include <linux/kernel.h>
19#include <linux/kthread.h>
20#include <linux/mutex.h>
21#include <linux/sched.h>
22#include <linux/serial.h>
23#include <linux/slab.h>
24#include <linux/spinlock.h>
25#include <linux/string.h>
26#include <linux/timer.h>
27#include <linux/tty.h>
28#include <linux/tty_driver.h>
29#include <linux/tty_flip.h>
30#include <linux/uaccess.h>
31
32#include <asm/da.h>
33
34/* Channel error codes */
35#define CONAOK 0
36#define CONERR 1
37#define CONBAD 2
38#define CONPRM 3
39#define CONADR 4
40#define CONCNT 5
41#define CONCBF 6
42#define CONCBE 7
43#define CONBSY 8
44
45/* Default channel for the console */
46#define CONSOLE_CHANNEL 1
47
48#define NUM_TTY_CHANNELS 6
49
50/* Auto allocate */
51#define DA_TTY_MAJOR 0
52
53/* A speedy poll rate helps the userland debug process connection response.
54 * But, if you set it too high then no other userland processes get much
55 * of a look in.
56 */
57#define DA_TTY_POLL (HZ / 50)
58
59/*
60 * A short put delay improves latency but has a high throughput overhead
61 */
62#define DA_TTY_PUT_DELAY (HZ / 100)
63
64static atomic_t num_channels_need_poll = ATOMIC_INIT(0);
65
66static struct timer_list poll_timer;
67
68static struct tty_driver *channel_driver;
69
70static struct timer_list put_timer;
71static struct task_struct *dashtty_thread;
72
73#define RX_BUF_SIZE 1024
74
75enum {
76 INCHR = 1,
77 OUTCHR,
78 RDBUF,
79 WRBUF,
80 RDSTAT
81};
82
83/**
84 * struct dashtty_port - Wrapper struct for dashtty tty_port.
85 * @port: TTY port data
86 * @rx_lock: Lock for rx_buf.
87 * This protects between the poll timer and user context.
88 * It's also held during read SWITCH operations.
89 * @rx_buf: Read buffer
90 * @xmit_lock: Lock for xmit_*, and port.xmit_buf.
91 * This protects between user context and kernel thread.
92 * It's also held during write SWITCH operations.
93 * @xmit_cnt: Size of xmit buffer contents
94 * @xmit_head: Head of xmit buffer where data is written
95 * @xmit_tail: Tail of xmit buffer where data is read
96 * @xmit_empty: Completion for xmit buffer being empty
97 */
98struct dashtty_port {
99 struct tty_port port;
100 spinlock_t rx_lock;
101 void *rx_buf;
102 struct mutex xmit_lock;
103 unsigned int xmit_cnt;
104 unsigned int xmit_head;
105 unsigned int xmit_tail;
106 struct completion xmit_empty;
107};
108
109static struct dashtty_port dashtty_ports[NUM_TTY_CHANNELS];
110
111static atomic_t dashtty_xmit_cnt = ATOMIC_INIT(0);
112static wait_queue_head_t dashtty_waitqueue;
113
114/*
115 * Low-level DA channel access routines
116 */
117static int chancall(int in_bios_function, int in_channel,
118 int in_arg2, void *in_arg3,
119 void *in_arg4)
120{
121 register int bios_function asm("D1Ar1") = in_bios_function;
122 register int channel asm("D0Ar2") = in_channel;
123 register int arg2 asm("D1Ar3") = in_arg2;
124 register void *arg3 asm("D0Ar4") = in_arg3;
125 register void *arg4 asm("D1Ar5") = in_arg4;
126 register int bios_call asm("D0Ar6") = 3;
127 register int result asm("D0Re0");
128
129 asm volatile (
130 "MSETL [A0StP++], %6,%4,%2\n\t"
131 "ADD A0StP, A0StP, #8\n\t"
132 "SWITCH #0x0C30208\n\t"
133 "GETD %0, [A0StP+#-8]\n\t"
134 "SUB A0StP, A0StP, #(4*6)+8\n\t"
135 : "=d" (result) /* outs */
136 : "d" (bios_function),
137 "d" (channel),
138 "d" (arg2),
139 "d" (arg3),
140 "d" (arg4),
141 "d" (bios_call) /* ins */
142 : "memory");
143
144 return result;
145}
146
147/*
148 * Attempts to fetch count bytes from channel and returns actual count.
149 */
150static int fetch_data(struct tty_struct *tty)
151{
152 unsigned int channel = tty->index;
153 struct dashtty_port *dport = &dashtty_ports[channel];
154 int received = 0;
155
156 spin_lock_bh(&dport->rx_lock);
157 /* check the port isn't being shut down */
158 if (!dport->rx_buf)
159 goto unlock;
160 if (chancall(RDBUF, channel, RX_BUF_SIZE,
161 (void *)dport->rx_buf, &received) == CONAOK) {
162 if (received) {
163 int space;
164 unsigned char *cbuf;
165
166 space = tty_prepare_flip_string(&dport->port, &cbuf,
167 received);
168
169 if (space <= 0)
170 goto unlock;
171
172 memcpy(cbuf, dport->rx_buf, space);
173 tty_flip_buffer_push(&dport->port);
174 }
175 }
176unlock:
177 spin_unlock_bh(&dport->rx_lock);
178
179 return received;
180}
181
182/**
183 * find_channel_to_poll() - Returns kref to the next channel tty to poll.
184 * Returns: The TTY of the next channel to poll, or NULL if no TTY needs
185 * polling. Release with tty_kref_put().
186 */
187static struct tty_struct *find_channel_to_poll(void)
188{
189 static int last_polled_channel;
190 int last = last_polled_channel;
191 int chan;
192 struct tty_struct *tty = NULL;
193
194 for (chan = last + 1; ; ++chan) {
195 if (chan >= NUM_TTY_CHANNELS)
196 chan = 0;
197
198 tty = tty_port_tty_get(&dashtty_ports[chan].port);
199 if (tty) {
200 last_polled_channel = chan;
201 return tty;
202 }
203
204 if (chan == last)
205 break;
206 }
207 return tty;
208}
209
210/**
211 * put_channel_data() - Write out a block of channel data.
212 * @chan: DA channel number.
213 *
214 * Write a single block of data out to the debug adapter. If the circular buffer
215 * is wrapped then only the first block is written.
216 *
217 * Returns: 1 if the remote buffer was too full to accept data.
218 * 0 otherwise.
219 */
220static int put_channel_data(unsigned int chan)
221{
222 struct dashtty_port *dport;
223 struct tty_struct *tty;
224 int number_written;
225 unsigned int count = 0;
226
227 dport = &dashtty_ports[chan];
228 mutex_lock(&dport->xmit_lock);
229 if (dport->xmit_cnt) {
230 count = min((unsigned int)(SERIAL_XMIT_SIZE - dport->xmit_tail),
231 dport->xmit_cnt);
232 chancall(WRBUF, chan, count,
233 dport->port.xmit_buf + dport->xmit_tail,
234 &number_written);
235 dport->xmit_cnt -= number_written;
236 if (!dport->xmit_cnt) {
237 /* reset pointers to avoid wraps */
238 dport->xmit_head = 0;
239 dport->xmit_tail = 0;
240 complete(&dport->xmit_empty);
241 } else {
242 dport->xmit_tail += number_written;
243 if (dport->xmit_tail >= SERIAL_XMIT_SIZE)
244 dport->xmit_tail -= SERIAL_XMIT_SIZE;
245 }
246 atomic_sub(number_written, &dashtty_xmit_cnt);
247 }
248 mutex_unlock(&dport->xmit_lock);
249
250 /* if we've made more data available, wake up tty */
251 if (count && number_written) {
252 tty = tty_port_tty_get(&dport->port);
253 if (tty) {
254 tty_wakeup(tty);
255 tty_kref_put(tty);
256 }
257 }
258
259 /* did the write fail? */
260 return count && !number_written;
261}
262
263/**
264 * put_data() - Kernel thread to write out blocks of channel data to DA.
265 * @arg: Unused.
266 *
267 * This kernel thread runs while @dashtty_xmit_cnt != 0, and loops over the
268 * channels to write out any buffered data. If any of the channels stall due to
269 * the remote buffer being full, a hold off happens to allow the debugger to
270 * drain the buffer.
271 */
272static int put_data(void *arg)
273{
274 unsigned int chan, stall;
275
276 __set_current_state(TASK_RUNNING);
277 while (!kthread_should_stop()) {
278 /*
279 * For each channel see if there's anything to transmit in the
280 * port's xmit_buf.
281 */
282 stall = 0;
283 for (chan = 0; chan < NUM_TTY_CHANNELS; ++chan)
284 stall += put_channel_data(chan);
285
286 /*
287 * If some of the buffers are full, hold off for a short while
288 * to allow them to empty.
289 */
290 if (stall)
291 msleep(25);
292
293 wait_event_interruptible(dashtty_waitqueue,
294 atomic_read(&dashtty_xmit_cnt));
295 }
296
297 return 0;
298}
299
300/*
301 * This gets called every DA_TTY_POLL and polls the channels for data
302 */
303static void dashtty_timer(unsigned long ignored)
304{
305 struct tty_struct *tty;
306
307 /* If there are no ports open do nothing and don't poll again. */
308 if (!atomic_read(&num_channels_need_poll))
309 return;
310
311 tty = find_channel_to_poll();
312
313 /* Did we find a channel to poll? */
314 if (tty) {
315 fetch_data(tty);
316 tty_kref_put(tty);
317 }
318
319 mod_timer_pinned(&poll_timer, jiffies + DA_TTY_POLL);
320}
321
322static void add_poll_timer(struct timer_list *poll_timer)
323{
324 setup_timer(poll_timer, dashtty_timer, 0);
325 poll_timer->expires = jiffies + DA_TTY_POLL;
326
327 /*
328 * Always attach the timer to the boot CPU. The DA channels are per-CPU
329 * so all polling should be from a single CPU.
330 */
331 add_timer_on(poll_timer, 0);
332}
333
334static int dashtty_port_activate(struct tty_port *port, struct tty_struct *tty)
335{
336 struct dashtty_port *dport = container_of(port, struct dashtty_port,
337 port);
338 void *rx_buf;
339
340 /* Allocate the buffer we use for writing data */
341 if (tty_port_alloc_xmit_buf(port) < 0)
342 goto err;
343
344 /* Allocate the buffer we use for reading data */
345 rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL);
346 if (!rx_buf)
347 goto err_free_xmit;
348
349 spin_lock_bh(&dport->rx_lock);
350 dport->rx_buf = rx_buf;
351 spin_unlock_bh(&dport->rx_lock);
352
353 /*
354 * Don't add the poll timer if we're opening a console. This
355 * avoids the overhead of polling the Dash but means it is not
356 * possible to have a login on /dev/console.
357 *
358 */
359 if (dport != &dashtty_ports[CONSOLE_CHANNEL])
360 if (atomic_inc_return(&num_channels_need_poll) == 1)
361 add_poll_timer(&poll_timer);
362
363 return 0;
364err_free_xmit:
365 tty_port_free_xmit_buf(port);
366err:
367 return -ENOMEM;
368}
369
370static void dashtty_port_shutdown(struct tty_port *port)
371{
372 struct dashtty_port *dport = container_of(port, struct dashtty_port,
373 port);
374 void *rx_buf;
375 unsigned int count;
376
377 /* stop reading */
378 if (dport != &dashtty_ports[CONSOLE_CHANNEL])
379 if (atomic_dec_and_test(&num_channels_need_poll))
380 del_timer_sync(&poll_timer);
381
382 mutex_lock(&dport->xmit_lock);
383 count = dport->xmit_cnt;
384 mutex_unlock(&dport->xmit_lock);
385 if (count) {
386 /*
387 * There's still data to write out, so wake and wait for the
388 * writer thread to drain the buffer.
389 */
390 del_timer(&put_timer);
391 wake_up_interruptible(&dashtty_waitqueue);
392 wait_for_completion(&dport->xmit_empty);
393 }
394
395 /* Null the read buffer (timer could still be running!) */
396 spin_lock_bh(&dport->rx_lock);
397 rx_buf = dport->rx_buf;
398 dport->rx_buf = NULL;
399 spin_unlock_bh(&dport->rx_lock);
400 /* Free the read buffer */
401 kfree(rx_buf);
402
403 /* Free the write buffer */
404 tty_port_free_xmit_buf(port);
405}
406
407static const struct tty_port_operations dashtty_port_ops = {
408 .activate = dashtty_port_activate,
409 .shutdown = dashtty_port_shutdown,
410};
411
412static int dashtty_install(struct tty_driver *driver, struct tty_struct *tty)
413{
414 return tty_port_install(&dashtty_ports[tty->index].port, driver, tty);
415}
416
417static int dashtty_open(struct tty_struct *tty, struct file *filp)
418{
419 return tty_port_open(tty->port, tty, filp);
420}
421
422static void dashtty_close(struct tty_struct *tty, struct file *filp)
423{
424 return tty_port_close(tty->port, tty, filp);
425}
426
427static void dashtty_hangup(struct tty_struct *tty)
428{
429 int channel;
430 struct dashtty_port *dport;
431
432 channel = tty->index;
433 dport = &dashtty_ports[channel];
434
435 /* drop any data in the xmit buffer */
436 mutex_lock(&dport->xmit_lock);
437 if (dport->xmit_cnt) {
438 atomic_sub(dport->xmit_cnt, &dashtty_xmit_cnt);
439 dport->xmit_cnt = 0;
440 dport->xmit_head = 0;
441 dport->xmit_tail = 0;
442 complete(&dport->xmit_empty);
443 }
444 mutex_unlock(&dport->xmit_lock);
445
446 tty_port_hangup(tty->port);
447}
448
449/**
450 * dashtty_put_timer() - Delayed wake up of kernel thread.
451 * @ignored: unused
452 *
453 * This timer function wakes up the kernel thread if any data exists in the
454 * buffers. It is used to delay the expensive writeout until the writer has
455 * stopped writing.
456 */
457static void dashtty_put_timer(unsigned long ignored)
458{
459 if (atomic_read(&dashtty_xmit_cnt))
460 wake_up_interruptible(&dashtty_waitqueue);
461}
462
463static int dashtty_write(struct tty_struct *tty, const unsigned char *buf,
464 int total)
465{
466 int channel, count, block;
467 struct dashtty_port *dport;
468
469 /* Determine the channel */
470 channel = tty->index;
471 dport = &dashtty_ports[channel];
472
473 /*
474 * Write to output buffer.
475 *
476 * The reason that we asynchronously write the buffer is because if we
477 * were to write the buffer synchronously then because DA channels are
478 * per-CPU the buffer would be written to the channel of whatever CPU
479 * we're running on.
480 *
481 * What we actually want to happen is have all input and output done on
482 * one CPU.
483 */
484 mutex_lock(&dport->xmit_lock);
485 /* work out how many bytes we can write to the xmit buffer */
486 total = min(total, (int)(SERIAL_XMIT_SIZE - dport->xmit_cnt));
487 atomic_add(total, &dashtty_xmit_cnt);
488 dport->xmit_cnt += total;
489 /* write the actual bytes (may need splitting if it wraps) */
490 for (count = total; count; count -= block) {
491 block = min(count, (int)(SERIAL_XMIT_SIZE - dport->xmit_head));
492 memcpy(dport->port.xmit_buf + dport->xmit_head, buf, block);
493 dport->xmit_head += block;
494 if (dport->xmit_head >= SERIAL_XMIT_SIZE)
495 dport->xmit_head -= SERIAL_XMIT_SIZE;
496 buf += block;
497 }
498 count = dport->xmit_cnt;
499 /* xmit buffer no longer empty? */
500 if (count)
501 INIT_COMPLETION(dport->xmit_empty);
502 mutex_unlock(&dport->xmit_lock);
503
504 if (total) {
505 /*
506 * If the buffer is full, wake up the kthread, otherwise allow
507 * some more time for the buffer to fill up a bit before waking
508 * it.
509 */
510 if (count == SERIAL_XMIT_SIZE) {
511 del_timer(&put_timer);
512 wake_up_interruptible(&dashtty_waitqueue);
513 } else {
514 mod_timer(&put_timer, jiffies + DA_TTY_PUT_DELAY);
515 }
516 }
517 return total;
518}
519
520static int dashtty_write_room(struct tty_struct *tty)
521{
522 struct dashtty_port *dport;
523 int channel;
524 int room;
525
526 channel = tty->index;
527 dport = &dashtty_ports[channel];
528
529 /* report the space in the xmit buffer */
530 mutex_lock(&dport->xmit_lock);
531 room = SERIAL_XMIT_SIZE - dport->xmit_cnt;
532 mutex_unlock(&dport->xmit_lock);
533
534 return room;
535}
536
537static int dashtty_chars_in_buffer(struct tty_struct *tty)
538{
539 struct dashtty_port *dport;
540 int channel;
541 int chars;
542
543 channel = tty->index;
544 dport = &dashtty_ports[channel];
545
546 /* report the number of bytes in the xmit buffer */
547 mutex_lock(&dport->xmit_lock);
548 chars = dport->xmit_cnt;
549 mutex_unlock(&dport->xmit_lock);
550
551 return chars;
552}
553
554static const struct tty_operations dashtty_ops = {
555 .install = dashtty_install,
556 .open = dashtty_open,
557 .close = dashtty_close,
558 .hangup = dashtty_hangup,
559 .write = dashtty_write,
560 .write_room = dashtty_write_room,
561 .chars_in_buffer = dashtty_chars_in_buffer,
562};
563
564static int __init dashtty_init(void)
565{
566 int ret;
567 int nport;
568 struct dashtty_port *dport;
569
570 if (!metag_da_enabled())
571 return -ENODEV;
572
573 channel_driver = tty_alloc_driver(NUM_TTY_CHANNELS,
574 TTY_DRIVER_REAL_RAW);
575 if (IS_ERR(channel_driver))
576 return PTR_ERR(channel_driver);
577
578 channel_driver->driver_name = "metag_da";
579 channel_driver->name = "ttyDA";
580 channel_driver->major = DA_TTY_MAJOR;
581 channel_driver->minor_start = 0;
582 channel_driver->type = TTY_DRIVER_TYPE_SERIAL;
583 channel_driver->subtype = SERIAL_TYPE_NORMAL;
584 channel_driver->init_termios = tty_std_termios;
585 channel_driver->init_termios.c_cflag |= CLOCAL;
586
587 tty_set_operations(channel_driver, &dashtty_ops);
588 for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
589 dport = &dashtty_ports[nport];
590 tty_port_init(&dport->port);
591 dport->port.ops = &dashtty_port_ops;
592 spin_lock_init(&dport->rx_lock);
593 mutex_init(&dport->xmit_lock);
594 /* the xmit buffer starts empty, i.e. completely written */
595 init_completion(&dport->xmit_empty);
596 complete(&dport->xmit_empty);
597 }
598
599 setup_timer(&put_timer, dashtty_put_timer, 0);
600
601 init_waitqueue_head(&dashtty_waitqueue);
602 dashtty_thread = kthread_create(put_data, NULL, "ttyDA");
603 if (IS_ERR(dashtty_thread)) {
604 pr_err("Couldn't create dashtty thread\n");
605 ret = PTR_ERR(dashtty_thread);
606 goto err_destroy_ports;
607 }
608 /*
609 * Bind the writer thread to the boot CPU so it can't migrate.
610 * DA channels are per-CPU and we want all channel I/O to be on a single
611 * predictable CPU.
612 */
613 kthread_bind(dashtty_thread, 0);
614 wake_up_process(dashtty_thread);
615
616 ret = tty_register_driver(channel_driver);
617
618 if (ret < 0) {
619 pr_err("Couldn't install dashtty driver: err %d\n",
620 ret);
621 goto err_stop_kthread;
622 }
623
624 return 0;
625
626err_stop_kthread:
627 kthread_stop(dashtty_thread);
628err_destroy_ports:
629 for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
630 dport = &dashtty_ports[nport];
631 tty_port_destroy(&dport->port);
632 }
633 put_tty_driver(channel_driver);
634 return ret;
635}
636
637static void dashtty_exit(void)
638{
639 int nport;
640 struct dashtty_port *dport;
641
642 del_timer_sync(&put_timer);
643 kthread_stop(dashtty_thread);
644 del_timer_sync(&poll_timer);
645 tty_unregister_driver(channel_driver);
646 for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
647 dport = &dashtty_ports[nport];
648 tty_port_destroy(&dport->port);
649 }
650 put_tty_driver(channel_driver);
651}
652
653module_init(dashtty_init);
654module_exit(dashtty_exit);
655
656#ifdef CONFIG_DA_CONSOLE
657
658static void dash_console_write(struct console *co, const char *s,
659 unsigned int count)
660{
661 int actually_written;
662
663 chancall(WRBUF, CONSOLE_CHANNEL, count, (void *)s, &actually_written);
664}
665
666static struct tty_driver *dash_console_device(struct console *c, int *index)
667{
668 *index = c->index;
669 return channel_driver;
670}
671
672struct console dash_console = {
673 .name = "ttyDA",
674 .write = dash_console_write,
675 .device = dash_console_device,
676 .flags = CON_PRINTBUFFER,
677 .index = 1,
678};
679
680#endif