OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [mux.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
** mux.c:
3
**      MUX console for the NOVA and K-Class systems.
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
**
14
** This Driver used Christoph Plattner's pdc_console.c as a driver
15
** template.
16
**
17
** This Driver currently only supports the console (port 0) on the MUX.
18
** Additional work will be needed on this driver to enable the full
19
** functionality of the MUX.
20
**
21
*/
22
 
23
static char *mux_drv_version = "0.1";
24
 
25
#include <linux/config.h>
26
#include <linux/version.h>
27
 
28
#undef SERIAL_PARANOIA_CHECK
29
#define CONFIG_SERIAL_NOPAUSE_IO
30
#define SERIAL_DO_RESTART
31
 
32
#include <linux/module.h>
33
#include <linux/serial.h>
34
#include <linux/serialP.h>
35
#include <linux/tty.h>
36
#include <linux/slab.h>
37
#include <linux/init.h>
38
#include <linux/delay.h>
39
#include <asm/uaccess.h>
40
 
41
#ifdef CONFIG_MAGIC_SYSRQ
42
#include <linux/sysrq.h>
43
static unsigned long break_pressed;
44
#endif
45
 
46
#ifdef CONFIG_GSC
47
#include <asm/gsc.h>
48
#endif
49
 
50
static unsigned long hpa;
51
 
52
#define MUX_OFFSET 0x800
53
#define MUX_LINE_OFFSET 0x80
54
 
55
#define MUX_FIFO_SIZE 255
56
#define MUX_MIN_FREE_SIZE 32
57
 
58
#define MUX_FIFO_DRAIN_DELAY 1
59
#define MUX_POLL_DELAY (30 * HZ / 1000)
60
 
61
#define IO_COMMAND_REG_OFFSET 0x30
62
#define IO_STATUS_REG_OFFSET 0x34
63
#define IO_DATA_REG_OFFSET 0x3c
64
#define IO_DCOUNT_REG_OFFSET 0x40
65
#define IO_UCOUNT_REG_OFFSET 0x44
66
#define IO_FIFOS_REG_OFFSET 0x48
67
 
68
#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
69
#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
70
#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
71
 
72
static int mux_drv_refcount; /* = 0 */
73
static struct tty_driver mux_drv_driver;
74
static struct async_struct *mux_drv_info;
75
static struct timer_list mux_drv_timer;
76
 
77
#define NR_PORTS 1
78
static struct tty_struct *mux_drv_table[NR_PORTS];
79
static struct termios *mux_drv_termios[NR_PORTS];
80
static struct termios *mux_drv_termios_locked[NR_PORTS];
81
 
82
/**
83
 * mux_read_fifo - Read chars from the mux fifo.
84
 * @info: Ptr to the async structure.
85
 *
86
 * This reads all available data from the mux's fifo and pushes
87
 * the data to the tty layer.
88
 */
89
static void
90
mux_read_fifo(struct async_struct *info)
91
{
92
        int data;
93
        struct tty_struct *tty = info->tty;
94
 
95
        while(1) {
96
                data = __raw_readl((unsigned long)info->iomem_base
97
                                   + IO_DATA_REG_OFFSET);
98
 
99
                if (MUX_STATUS(data))
100
                        continue;
101
 
102
                if (MUX_EOFIFO(data))
103
                        break;
104
 
105
                if (tty->flip.count >= TTY_FLIPBUF_SIZE)
106
                        continue;
107
 
108
                *tty->flip.char_buf_ptr = data & 0xffu;
109
                *tty->flip.flag_buf_ptr = 0;
110
 
111
#ifdef CONFIG_MAGIC_SYSRQ
112
                if (MUX_BREAK(data) && !break_pressed) {
113
                        break_pressed = jiffies;
114
                        continue;
115
                }
116
 
117
                if(MUX_BREAK(data)) {
118
                        *tty->flip.flag_buf_ptr = TTY_BREAK;
119
                }
120
 
121
                if(break_pressed) {
122
                        if(time_before(jiffies, break_pressed + HZ * 5)) {
123
                                handle_sysrq(data & 0xffu, NULL, NULL, NULL);
124
                                break_pressed = 0;
125
                                continue;
126
                        }
127
                        break_pressed = 0;
128
                }
129
#endif
130
 
131
                tty->flip.flag_buf_ptr++;
132
                tty->flip.char_buf_ptr++;
133
                tty->flip.count++;
134
        }
135
 
136
        tty_flip_buffer_push(tty);
137
}
138
 
139
 
140
/**
141
 * mux_drv_poll - Mux poll function.
142
 * @unused: Unused variable
143
 *
144
 * This function periodically polls the Mux to check for new data.
145
 */
146
static void
147
mux_drv_poll(unsigned long unused)
148
{
149
        struct async_struct *info = mux_drv_info;
150
 
151
        if(info && info->tty && mux_drv_refcount) {
152
                mux_read_fifo(info);
153
                info->last_active = jiffies;
154
        }
155
 
156
        mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
157
}
158
 
159
/**
160
 * mux_chars_in_buffer - Returns the number of chars present in the outbound fifo.
161
 * @tty: Ptr to the tty structure.
162
 *
163
 * This function returns the number of chars sitting in the outbound fifo.
164
 * [Note: This function is required for the normal_poll function in
165
 *  drivers/char/n_tty.c].
166
 */
167
static int
168
mux_chars_in_buffer(struct tty_struct *tty)
169
{
170
        struct async_struct *info = (struct async_struct *)tty->driver_data;
171
        return __raw_readl((unsigned long)info->iomem_base
172
                           + IO_DCOUNT_REG_OFFSET);
173
}
174
 
175
/**
176
 * mux_flush_buffer - Pause until the fifo is empty.
177
 * @tty: Ptr to the tty structure.
178
 *
179
 * Since the mux fifo is self draining, this function just
180
 * waits until the fifo has completely drained.
181
 */
182
static void
183
mux_flush_buffer(struct tty_struct *tty)
184
{
185
        while(mux_chars_in_buffer(tty))
186
                mdelay(MUX_FIFO_DRAIN_DELAY);
187
}
188
 
189
/**
190
 * mux_write_room - How much room is left in the fifo.
191
 * @tty: Ptr to the tty structure.
192
 *
193
 * This function returns how much room is in the fifo for
194
 * writing.
195
 */
196
static int
197
mux_write_room(struct tty_struct *tty)
198
{
199
        int room = mux_chars_in_buffer(tty);
200
        if(room > MUX_FIFO_SIZE)
201
                return 0;
202
 
203
        return MUX_FIFO_SIZE - room;
204
}
205
 
206
/**
207
 * mux_write - Write chars to the mux fifo.
208
 * @tty: Ptr to the tty structure.
209
 * @from_user: Is the buffer from user space?
210
 * @buf: The buffer to write to the mux fifo.
211
 * @count: The number of chars to write to the mux fifo.
212
 *
213
 * This function writes the data from buf to the mux fifo.
214
 * [Note: we need the mux_flush_buffer() at the end of the
215
 * function, otherwise the system will wait for LONG_MAX
216
 * if the fifo is not empty when the TCSETSW ioctl is called.]
217
 */
218
static int
219
mux_write(struct tty_struct *tty, int from_user,
220
          const unsigned char *buf, int count)
221
{
222
        int size, len, ret = count;
223
        char buffer[MUX_FIFO_SIZE], *buf_p;
224
        unsigned long iomem_base =
225
                (unsigned long)((struct async_struct *)tty->driver_data)->iomem_base;
226
 
227
        while (count) {
228
                size = mux_write_room(tty);
229
                len = (size < count) ? size : count;
230
 
231
                if (from_user) {
232
                        copy_from_user(buffer, buf, len);
233
                        buf_p = buffer;
234
                } else {
235
                        buf_p = (char *)buf;
236
                }
237
 
238
                count -= len;
239
                buf += len;
240
 
241
                if(size < MUX_MIN_FREE_SIZE)
242
                        mux_flush_buffer(tty);
243
 
244
                while(len--) {
245
                        __raw_writel(*buf_p++, iomem_base + IO_DATA_REG_OFFSET);
246
                }
247
        }
248
 
249
        mux_flush_buffer(tty);
250
        return ret;
251
}
252
 
253
/**
254
 * mux_break - Turn break handling on or off.
255
 * @tty: Ptr to the tty structure.
256
 * @break_state: break value.
257
 *
258
 * This function must be defined because the send_break() in
259
 * drivers/char/tty_io.c requires it.  Currently the Serial Mux
260
 * does nothing when this function is called.
261
 */
262
static void
263
mux_break(struct tty_struct *tty, int break_state)
264
{
265
}
266
 
267
/**
268
 * get_serial_info - Return the serial structure to userspace.
269
 * @info: Ptr to the async structure.
270
 * @retinfo: Ptr to the users space buffer.
271
 *
272
 * Fill in this serial structure and return it to userspace.
273
 */
274
static int
275
get_serial_info(struct async_struct *info,
276
                struct serial_struct *retinfo)
277
{
278
        struct serial_struct tmp;
279
 
280
        if (!retinfo)
281
                return -EFAULT;
282
 
283
        memset(&tmp, 0, sizeof(tmp));
284
        tmp.line = info->line;
285
        tmp.port = info->line;
286
        tmp.flags = info->flags;
287
        tmp.close_delay = info->close_delay;
288
        return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
289
}
290
 
291
/**
292
 * get_modem_info - Return the modem control and status signals to userspace.
293
 * @info: Ptr to the async structure.
294
 * @value: The return buffer.
295
 *
296
 * The Serial MUX driver always returns these values to userspace:
297
 *      Data Terminal Ready, Carrier Detect, Clear To Send,
298
 *      Request To Send.
299
 *
300
 */
301
static int
302
get_modem_info(struct async_struct *info, unsigned int *value)
303
{
304
        unsigned int result = TIOCM_DTR|TIOCM_CAR|TIOCM_CTS|TIOCM_RTS;
305
        return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
306
}
307
 
308
/**
309
 * get_lsr_info - Return line status register info to userspace.
310
 * @info: Ptr to the async structure.
311
 * @value: The return buffer.
312
 *
313
 * The Serial MUX driver always returns empty transmitter to userspace.
314
 */
315
static int
316
get_lsr_info(struct async_struct *info, unsigned int *value)
317
{
318
        unsigned int result = TIOCSER_TEMT;
319
        return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
320
}
321
 
322
/**
323
 * mux_ioctl - Handle driver specific ioctl commands.
324
 * @tty: Ptr to the tty structure.
325
 * @file: Unused.
326
 * @cmd: The ioctl number.
327
 * @arg: The ioctl argument.
328
 *
329
 * This function handles ioctls specific to the Serial MUX driver,
330
 * or ioctls that need driver specific information.
331
 *
332
 */
333
static int
334
mux_ioctl(struct tty_struct *tty, struct file *file,
335
          unsigned int cmd, unsigned long arg)
336
{
337
        struct async_struct *info = (struct async_struct *) tty->driver_data;
338
 
339
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
340
            (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
341
            (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
342
                if (tty->flags & (1 << TTY_IO_ERROR))
343
                        return -EIO;
344
        }
345
 
346
        switch (cmd) {
347
        case TIOCMGET:
348
                return get_modem_info(info, (unsigned int *) arg);
349
 
350
        case TIOCMBIS:
351
        case TIOCMBIC:
352
        case TIOCMSET:
353
                return 0;
354
 
355
        case TIOCGSERIAL:
356
                return get_serial_info(info, (struct serial_struct *) arg);
357
 
358
        case TIOCSSERIAL:
359
                return 0;
360
 
361
        case TIOCSERCONFIG:
362
                return 0;
363
 
364
        case TIOCSERGETLSR:
365
                return get_lsr_info(info, (unsigned int *) arg);
366
 
367
        case TIOCSERGSTRUCT:
368
                if (copy_to_user((struct async_struct *) arg,
369
                                 info, sizeof (struct async_struct)))
370
                        return -EFAULT;
371
                return 0;
372
 
373
        case TIOCMIWAIT:
374
                return 0;
375
 
376
        case TIOCGICOUNT:
377
                return 0;
378
 
379
        case TIOCSERGWILD:
380
        case TIOCSERSWILD:
381
                /* "setserial -W" is called in Debian boot */
382
                printk("TIOCSER?WILD ioctl obsolete, ignored.\n");
383
                return 0;
384
 
385
        default:
386
                return -ENOIOCTLCMD;
387
        }
388
        return 0;
389
}
390
 
391
/**
392
 * mux_close - Close the serial mux driver.
393
 * @tty: Ptr to the tty structure.
394
 * @filp: Unused.
395
 *
396
 * This routine is called when the serial port gets closed.  First, we
397
 * wait for the last remaining data to be sent.  Then, we unlink its
398
 * async structure from the interrupt chain if necessary, and we free
399
 * that IRQ if nothing is left in the chain.
400
 */
401
static void
402
mux_close(struct tty_struct *tty, struct file *filp)
403
{
404
        struct async_struct *info = (struct async_struct *) tty->driver_data;
405
 
406
        mux_drv_refcount--;
407
        if (mux_drv_refcount > 0)
408
                return;
409
 
410
        info->flags |= ASYNC_CLOSING;
411
 
412
        /*
413
         * Save the termios structure, since this port may have
414
         * separate termios for callout and dialin.
415
         */
416
        if (info->flags & ASYNC_NORMAL_ACTIVE)
417
                info->state->normal_termios = *tty->termios;
418
        if (info->flags & ASYNC_CALLOUT_ACTIVE)
419
                info->state->callout_termios = *tty->termios;
420
 
421
        /*
422
         * At this point we stop accepting input.  To do this, we
423
         * disable the receive line status interrupts, and tell the
424
         * interrupt driver to stop checking the data ready bit in the
425
         * line status register.
426
         */
427
 
428
        /* XXX CP: make mask for receive !!! */
429
 
430
        if (tty->driver.flush_buffer)
431
                tty->driver.flush_buffer(tty);
432
        if (tty->ldisc.flush_buffer)
433
                tty->ldisc.flush_buffer(tty);
434
        tty->closing = 0;
435
        info->event = 0;
436
        info->tty = 0;
437
        mux_drv_info = NULL;
438
        if (info->blocked_open) {
439
                if (info->close_delay) {
440
                        set_current_state(TASK_INTERRUPTIBLE);
441
                        schedule_timeout(info->close_delay);
442
                }
443
                wake_up_interruptible(&info->open_wait);
444
        }
445
        info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
446
                         ASYNC_CLOSING);
447
        wake_up_interruptible(&info->close_wait);
448
        MOD_DEC_USE_COUNT;
449
}
450
 
451
/**
452
 * get_async_struct - Get the async structure.
453
 * @line: Minor number of the tty device.
454
 * @ret_info: Ptr to the newly allocated async structure.
455
 *
456
 * Allocate and return an async structure for the specified
457
 * tty device line.
458
 */
459
static int
460
get_async_struct(int line, struct async_struct **ret_info)
461
{
462
        struct async_struct *info;
463
 
464
        info = kmalloc(sizeof (struct async_struct), GFP_KERNEL);
465
        if (!info) {
466
                return -ENOMEM;
467
        }
468
        memset(info, 0, sizeof (struct async_struct));
469
        init_waitqueue_head(&info->open_wait);
470
        init_waitqueue_head(&info->close_wait);
471
        init_waitqueue_head(&info->delta_msr_wait);
472
        info->magic = SERIAL_MAGIC;
473
        info->port = 0;
474
        info->flags = 0;
475
        info->io_type = 0;
476
        info->iomem_base = (void *)(hpa + MUX_OFFSET);
477
        info->iomem_reg_shift = 0;
478
        info->xmit_fifo_size = MUX_FIFO_SIZE;
479
        info->line = line;
480
        info->tqueue.routine = NULL;
481
        info->tqueue.data = info;
482
        info->state = NULL;
483
        *ret_info = info;
484
        return 0;
485
}
486
 
487
/**
488
 * mux_open - Open the serial mux driver.
489
 * @tty: Ptr to the tty structure.
490
 * @filp: Unused.
491
 *
492
 * This routine is called whenever a serial port is opened.  It
493
 * enables interrupts for a serial port, linking in its async structure
494
 * into the IRQ chain.   It also performs the serial-specific
495
 * initialization for the tty structure.
496
 */
497
static int
498
mux_open(struct tty_struct *tty, struct file *filp)
499
{
500
        struct async_struct *info;
501
        int retval, line;
502
 
503
        MOD_INC_USE_COUNT;
504
        line = MINOR(tty->device) - tty->driver.minor_start;
505
        if ((line < 0) || (line >= NR_PORTS)) {
506
                MOD_DEC_USE_COUNT;
507
                return -ENODEV;
508
        }
509
        retval = get_async_struct(line, &info);
510
        if (retval) {
511
                MOD_DEC_USE_COUNT;
512
                return retval;
513
        }
514
 
515
        tty->driver_data = info;
516
        info->tty = tty;
517
        mux_drv_info = info;
518
        info->tty->low_latency = 0;
519
        info->session = current->session;
520
        info->pgrp = current->pgrp;
521
        mux_drv_refcount++;
522
        return 0;
523
}
524
 
525
/**
526
 * mux_probe - Determine if the Serial Mux should claim this device.
527
 * @dev: The parisc device.
528
 *
529
 * Deterimine if the Sserial Mux should claim this chip (return 0)
530
 * or not (return 1).
531
 */
532
static int __init
533
mux_probe(struct parisc_device *dev)
534
{
535
        if(hpa) {
536
                printk(KERN_INFO "Serial MUX driver already registered, skipping additonal MUXes for now.\n");
537
                return 1;
538
        }
539
 
540
        init_timer(&mux_drv_timer);
541
        mux_drv_timer.function = mux_drv_poll;
542
        mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
543
 
544
        hpa = dev->hpa;
545
        printk(KERN_INFO "Serial MUX driver version %s at 0x%lx\n",
546
               mux_drv_version, hpa);
547
 
548
        /* Initialize the tty_driver structure */
549
 
550
        memset(&mux_drv_driver, 0, sizeof (struct tty_driver));
551
        mux_drv_driver.magic = TTY_DRIVER_MAGIC;
552
        mux_drv_driver.driver_name = "Serial MUX driver";
553
#ifdef CONFIG_DEVFS_FS
554
        mux_drv_driver.name = "ttb/%d";
555
#else
556
        mux_drv_driver.name = "ttyB";
557
#endif
558
        mux_drv_driver.major = MUX_MAJOR;
559
        mux_drv_driver.minor_start = 0;
560
        mux_drv_driver.num = NR_PORTS;
561
        mux_drv_driver.type = TTY_DRIVER_TYPE_SERIAL;
562
        mux_drv_driver.subtype = SERIAL_TYPE_NORMAL;
563
        mux_drv_driver.init_termios = tty_std_termios;
564
        mux_drv_driver.init_termios.c_cflag =
565
            B9600 | CS8 | CREAD | HUPCL | CLOCAL;
566
        mux_drv_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
567
        mux_drv_driver.refcount = &mux_drv_refcount;
568
        mux_drv_driver.table = mux_drv_table;
569
        mux_drv_driver.termios = mux_drv_termios;
570
        mux_drv_driver.termios_locked = mux_drv_termios_locked;
571
 
572
        mux_drv_driver.open = mux_open;
573
        mux_drv_driver.close = mux_close;
574
        mux_drv_driver.write = mux_write;
575
        mux_drv_driver.put_char = NULL;
576
        mux_drv_driver.flush_chars = NULL;
577
        mux_drv_driver.write_room = mux_write_room;
578
        mux_drv_driver.chars_in_buffer = mux_chars_in_buffer;
579
        mux_drv_driver.flush_buffer = mux_flush_buffer;
580
        mux_drv_driver.ioctl = mux_ioctl;
581
        mux_drv_driver.throttle = NULL;
582
        mux_drv_driver.unthrottle = NULL;
583
        mux_drv_driver.set_termios = NULL;
584
        mux_drv_driver.stop = NULL;
585
        mux_drv_driver.start = NULL;
586
        mux_drv_driver.hangup = NULL;
587
        mux_drv_driver.break_ctl = mux_break;
588
        mux_drv_driver.send_xchar = NULL;
589
        mux_drv_driver.wait_until_sent = NULL;
590
        mux_drv_driver.read_proc = NULL;
591
 
592
        if (tty_register_driver(&mux_drv_driver))
593
                panic("Could not register the serial MUX driver\n");
594
 
595
        return 0;
596
}
597
 
598
static struct parisc_device_id mux_tbl[] = {
599
        { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
600
        { 0, }
601
};
602
 
603
MODULE_DEVICE_TABLE(parisc, mux_tbl);
604
 
605
static struct parisc_driver mux_driver = {
606
        name:           "Serial MUX driver",
607
        id_table:       mux_tbl,
608
        probe:          mux_probe,
609
};
610
 
611
/**
612
 * mux_init - Serial MUX initalization procedure.
613
 *
614
 * Register the Serial MUX driver.
615
 */
616
static int __init mux_init(void)
617
{
618
        return register_parisc_driver(&mux_driver);
619
}
620
 
621
/**
622
 * mux_exit - Serial MUX cleanup procedure.
623
 *
624
 * Unregister the Serial MUX driver from the tty layer.
625
 */
626
static void __exit mux_exit(void)
627
{
628
        int status = tty_unregister_driver(&mux_drv_driver);
629
        if(status) {
630
                printk("MUX: failed to unregister the Serial MUX driver (%d)\n", status);
631
        }
632
}
633
 
634
module_init(mux_init);
635
module_exit(mux_exit);
636
MODULE_DESCRIPTION("Serial MUX driver");
637
MODULE_AUTHOR("Ryan Bradetich");
638
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.