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

Subversion Repositories or1k

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 kdev_t rs285_console_device(struct console *c)
393
{
394
        return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
395
}
396
 
397
static int __init rs285_console_setup(struct console *co, char *options)
398
{
399
        int baud = 9600;
400
        int bits = 8;
401
        int parity = 'n';
402
        int cflag = CREAD | HUPCL | CLOCAL;
403
 
404
        if (machine_is_personal_server())
405
                baud = 57600;
406
 
407
        if (options) {
408
                char *s = options;
409
                baud = simple_strtoul(options, NULL, 10);
410
                while (*s >= '0' && *s <= '9')
411
                        s++;
412
                if (*s)
413
                        parity = *s++;
414
                if (*s)
415
                        bits = *s - '0';
416
        }
417
 
418
        /*
419
         *    Now construct a cflag setting.
420
         */
421
        switch (baud) {
422
        case 1200:
423
                cflag |= B1200;
424
                break;
425
        case 2400:
426
                cflag |= B2400;
427
                break;
428
        case 4800:
429
                cflag |= B4800;
430
                break;
431
        case 9600:
432
                cflag |= B9600;
433
                break;
434
        case 19200:
435
                cflag |= B19200;
436
                break;
437
        case 38400:
438
                cflag |= B38400;
439
                break;
440
        case 57600:
441
                cflag |= B57600;
442
                break;
443
        case 115200:
444
                cflag |= B115200;
445
                break;
446
        default:
447
                cflag |= B9600;
448
                break;
449
        }
450
        switch (bits) {
451
        case 7:
452
                cflag |= CS7;
453
                break;
454
        default:
455
                cflag |= CS8;
456
                break;
457
        }
458
        switch (parity) {
459
        case 'o':
460
        case 'O':
461
                cflag |= PARODD;
462
                break;
463
        case 'e':
464
        case 'E':
465
                cflag |= PARENB;
466
                break;
467
        }
468
        co->cflag = cflag;
469
        rs285_set_cflag(cflag);
470
        rs285_console_write(NULL, "\e[2J\e[Hboot ", 12);
471
        if (options)
472
                rs285_console_write(NULL, options, strlen(options));
473
        else
474
                rs285_console_write(NULL, "no options", 10);
475
        rs285_console_write(NULL, "\n", 1);
476
 
477
        return 0;
478
}
479
 
480
static struct console rs285_cons =
481
{
482
        name:           SERIAL_21285_NAME,
483
        write:          rs285_console_write,
484
        device:         rs285_console_device,
485
        setup:          rs285_console_setup,
486
        flags:          CON_PRINTBUFFER,
487
        index:          -1,
488
};
489
 
490
void __init rs285_console_init(void)
491
{
492
        register_console(&rs285_cons);
493
}
494
 
495
#endif  /* CONFIG_SERIAL_21285_CONSOLE */
496
 
497
MODULE_LICENSE("GPL");
498
EXPORT_NO_SYMBOLS;

powered by: WebSVN 2.1.0

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