Root/target/linux/amazon/files/drivers/tty/serial/amazon_asc.c

1/*
2 * Driver for AMAZONASC serial ports
3 *
4 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
5 * Based on drivers/serial/serial_s3c2400.c
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * Copyright (C) 2004 Infineon IFAP DC COM CPE
22 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
23 * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
24 */
25
26#include <linux/module.h>
27#include <linux/errno.h>
28#include <linux/signal.h>
29#include <linux/sched.h>
30#include <linux/interrupt.h>
31#include <linux/tty.h>
32#include <linux/tty_flip.h>
33#include <linux/major.h>
34#include <linux/string.h>
35#include <linux/fcntl.h>
36#include <linux/ptrace.h>
37#include <linux/ioport.h>
38#include <linux/mm.h>
39#include <linux/slab.h>
40#include <linux/init.h>
41#include <linux/circ_buf.h>
42#include <linux/serial.h>
43#include <linux/serial_core.h>
44#include <linux/console.h>
45#include <linux/sysrq.h>
46#include <linux/irq.h>
47#include <linux/platform_device.h>
48
49#include <asm/system.h>
50#include <asm/io.h>
51#include <asm/uaccess.h>
52#include <asm/bitops.h>
53#include <asm/amazon/amazon.h>
54#include <asm/amazon/irq.h>
55#include <asm/amazon/serial.h>
56
57#define PORT_AMAZONASC 111
58
59#include <linux/serial_core.h>
60
61#define UART_NR 1
62
63#define UART_DUMMY_UER_RX 1
64
65#define SERIAL_AMAZONASC_MAJOR TTY_MAJOR
66#define CALLOUT_AMAZONASC_MAJOR TTYAUX_MAJOR
67#define SERIAL_AMAZONASC_MINOR 64
68#define SERIAL_AMAZONASC_NR UART_NR
69
70static void amazonasc_tx_chars(struct uart_port *port);
71static struct uart_port amazonasc_ports[UART_NR];
72static struct uart_driver amazonasc_reg;
73static unsigned int uartclk = 0;
74
75static void amazonasc_stop_tx(struct uart_port *port)
76{
77    /* fifo underrun shuts up after firing once */
78    return;
79}
80
81static void amazonasc_start_tx(struct uart_port *port)
82{
83    unsigned long flags;
84
85    local_irq_save(flags);
86    amazonasc_tx_chars(port);
87    local_irq_restore(flags);
88
89    return;
90}
91
92static void amazonasc_stop_rx(struct uart_port *port)
93{
94    /* clear the RX enable bit */
95    amazon_writel(ASCWHBCON_CLRREN, AMAZON_ASC_WHBCON);
96}
97
98static void amazonasc_enable_ms(struct uart_port *port)
99{
100    /* no modem signals */
101    return;
102}
103
104#include <linux/version.h>
105
106static void
107amazonasc_rx_chars(struct uart_port *port)
108{
109#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
110    struct tty_struct *tty = port->state->port.tty;
111#else
112    struct tty_struct *tty = port->info->port.tty;
113#endif
114    unsigned int ch = 0, rsr = 0, fifocnt;
115
116    fifocnt = amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
117    while (fifocnt--)
118    {
119        u8 flag = TTY_NORMAL;
120        ch = amazon_readl(AMAZON_ASC_RBUF);
121        rsr = (amazon_readl(AMAZON_ASC_CON) & ASCCON_ANY) | UART_DUMMY_UER_RX;
122        tty_flip_buffer_push(tty);
123        port->icount.rx++;
124
125        /*
126         * Note that the error handling code is
127         * out of the main execution path
128         */
129        if (rsr & ASCCON_ANY) {
130            if (rsr & ASCCON_PE) {
131                port->icount.parity++;
132                amazon_writel_masked(AMAZON_ASC_WHBCON, ASCWHBCON_CLRPE, ASCWHBCON_CLRPE);
133            } else if (rsr & ASCCON_FE) {
134                port->icount.frame++;
135                amazon_writel_masked(AMAZON_ASC_WHBCON, ASCWHBCON_CLRFE, ASCWHBCON_CLRFE);
136            }
137            if (rsr & ASCCON_OE) {
138                port->icount.overrun++;
139                amazon_writel_masked(AMAZON_ASC_WHBCON, ASCWHBCON_CLROE, ASCWHBCON_CLROE);
140            }
141
142            rsr &= port->read_status_mask;
143
144            if (rsr & ASCCON_PE)
145                flag = TTY_PARITY;
146            else if (rsr & ASCCON_FE)
147                flag = TTY_FRAME;
148        }
149
150        if ((rsr & port->ignore_status_mask) == 0)
151            tty_insert_flip_char(tty, ch, flag);
152
153        if (rsr & ASCCON_OE)
154            /*
155             * Overrun is special, since it's reported
156             * immediately, and doesn't affect the current
157             * character
158             */
159            tty_insert_flip_char(tty, 0, TTY_OVERRUN);
160    }
161    if (ch != 0)
162        tty_flip_buffer_push(tty);
163
164    return;
165}
166
167
168static void amazonasc_tx_chars(struct uart_port *port)
169{
170#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
171    struct circ_buf *xmit = &port->state->xmit;
172#else
173    struct circ_buf *xmit = &port->info->xmit;
174#endif
175
176    if (uart_tx_stopped(port)) {
177        amazonasc_stop_tx(port);
178        return;
179    }
180    
181    while (((amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_TXFFLMASK)
182            >> ASCFSTAT_TXFFLOFF) != AMAZONASC_TXFIFO_FULL)
183    {
184        if (port->x_char) {
185            amazon_writel(port->x_char, AMAZON_ASC_TBUF);
186            port->icount.tx++;
187            port->x_char = 0;
188            continue;
189        }
190
191        if (uart_circ_empty(xmit))
192            break;
193
194        amazon_writel(xmit->buf[xmit->tail], AMAZON_ASC_TBUF);
195        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
196        port->icount.tx++;
197    }
198
199    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
200        uart_write_wakeup(port);
201}
202
203static irqreturn_t amazonasc_tx_int(int irq, void *port)
204{
205    amazon_writel(ASC_IRNCR_TIR, AMAZON_ASC_IRNCR1);
206    amazonasc_start_tx(port);
207
208    /* clear any pending interrupts */
209    amazon_writel_masked(AMAZON_ASC_WHBCON,
210            (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE),
211            (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE));
212
213    return IRQ_HANDLED;
214}
215
216static irqreturn_t amazonasc_er_int(int irq, void *port)
217{
218    /* clear any pending interrupts */
219    amazon_writel_masked(AMAZON_ASC_WHBCON,
220            (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE),
221            (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE));
222    
223    return IRQ_HANDLED;
224}
225
226static irqreturn_t amazonasc_rx_int(int irq, void *port)
227{
228    amazon_writel(ASC_IRNCR_RIR, AMAZON_ASC_IRNCR1);
229    amazonasc_rx_chars((struct uart_port *) port);
230    return IRQ_HANDLED;
231}
232
233static u_int amazonasc_tx_empty(struct uart_port *port)
234{
235    int status;
236
237    /*
238     * FSTAT tells exactly how many bytes are in the FIFO.
239     * The question is whether we really need to wait for all
240     * 16 bytes to be transmitted before reporting that the
241     * transmitter is empty.
242     */
243    status = amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
244    return status ? 0 : TIOCSER_TEMT;
245}
246
247static u_int amazonasc_get_mctrl(struct uart_port *port)
248{
249    /* no modem control signals - the readme says to pretend all are set */
250    return TIOCM_CTS|TIOCM_CAR|TIOCM_DSR;
251}
252
253static void amazonasc_set_mctrl(struct uart_port *port, u_int mctrl)
254{
255    /* no modem control - just return */
256    return;
257}
258
259static void amazonasc_break_ctl(struct uart_port *port, int break_state)
260{
261    /* no way to send a break */
262    return;
263}
264
265static int amazonasc_startup(struct uart_port *port)
266{
267    unsigned int con = 0;
268    unsigned long flags;
269    int retval;
270
271    /* this assumes: CON.BRS = CON.FDE = 0 */
272    if (uartclk == 0)
273        uartclk = amazon_get_fpi_hz();
274
275    amazonasc_ports[0].uartclk = uartclk;
276
277    local_irq_save(flags);
278
279    /* this setup was probably already done in u-boot */
280    /* ASC and GPIO Port 1 bits 3 and 4 share the same pins
281     * P1.3 (RX) in, Alternate 10
282     * P1.4 (TX) in, Alternate 10
283     */
284     amazon_writel_masked(AMAZON_GPIO_P1_DIR, 0x18, 0x10); //P1.4 output, P1.3 input
285     amazon_writel_masked(AMAZON_GPIO_P1_ALTSEL0, 0x18, 0x18); //ALTSETL0 11
286     amazon_writel_masked(AMAZON_GPIO_P1_ALTSEL1, 0x18, 0); //ALTSETL1 00
287     amazon_writel_masked(AMAZON_GPIO_P1_OD, 0x18, 0x10);
288    
289    /* set up the CLC */
290    amazon_writel_masked(AMAZON_ASC_CLC, AMAZON_ASC_CLC_DISS, 0);
291    amazon_writel_masked(AMAZON_ASC_CLC, ASCCLC_RMCMASK, 1 << ASCCLC_RMCOFFSET);
292    
293    /* asynchronous mode */
294    con = ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_OEN | ASCCON_PEN;
295    
296    /* choose the line - there's only one */
297    amazon_writel(0, AMAZON_ASC_PISEL);
298    amazon_writel(((AMAZONASC_TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
299        AMAZON_ASC_TXFCON);
300    amazon_writel(((AMAZONASC_RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
301        AMAZON_ASC_RXFCON);
302    wmb();
303    
304    amazon_writel_masked(AMAZON_ASC_CON, con, con);
305
306    retval = request_irq(AMAZONASC_RIR, amazonasc_rx_int, 0, "asc_rx", port);
307    if (retval){
308        printk("failed to request amazonasc_rx_int\n");
309        return retval;
310    }
311    retval = request_irq(AMAZONASC_TIR, amazonasc_tx_int, 0, "asc_tx", port);
312    if (retval){
313        printk("failed to request amazonasc_tx_int\n");
314        goto err1;
315    }
316
317    retval = request_irq(AMAZONASC_EIR, amazonasc_er_int, 0, "asc_er", port);
318    if (retval){
319        printk("failed to request amazonasc_er_int\n");
320        goto err2;
321    }
322    
323    local_irq_restore(flags);
324    return 0;
325
326err2:
327    free_irq(AMAZONASC_TIR, port);
328    
329err1:
330    free_irq(AMAZONASC_RIR, port);
331    local_irq_restore(flags);
332    return retval;
333}
334
335static void amazonasc_shutdown(struct uart_port *port)
336{
337    free_irq(AMAZONASC_RIR, port);
338    free_irq(AMAZONASC_TIR, port);
339    free_irq(AMAZONASC_EIR, port);
340    /*
341     * disable the baudrate generator to disable the ASC
342     */
343    amazon_writel(0, AMAZON_ASC_CON);
344
345    /* flush and then disable the fifos */
346    amazon_writel_masked(AMAZON_ASC_RXFCON, ASCRXFCON_RXFFLU, ASCRXFCON_RXFFLU);
347    amazon_writel_masked(AMAZON_ASC_RXFCON, ASCRXFCON_RXFEN, 0);
348    amazon_writel_masked(AMAZON_ASC_TXFCON, ASCTXFCON_TXFFLU, ASCTXFCON_TXFFLU);
349    amazon_writel_masked(AMAZON_ASC_TXFCON, ASCTXFCON_TXFEN, 0);
350}
351
352static void amazonasc_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old)
353{
354    unsigned int cflag;
355    unsigned int iflag;
356    unsigned int baud, quot;
357    unsigned int con = 0;
358    unsigned long flags;
359
360    cflag = new->c_cflag;
361    iflag = new->c_iflag;
362
363    /* byte size and parity */
364    switch (cflag & CSIZE) {
365    /* 7 bits are always with parity */
366    case CS7: con = ASCCON_M_7ASYNCPAR; break;
367    /* the ASC only suports 7 and 8 bits */
368    case CS5:
369    case CS6:
370    default:
371        if (cflag & PARENB)
372            con = ASCCON_M_8ASYNCPAR;
373        else
374            con = ASCCON_M_8ASYNC;
375        break;
376    }
377    if (cflag & CSTOPB)
378        con |= ASCCON_STP;
379    if (cflag & PARENB) {
380        if (!(cflag & PARODD))
381            con &= ~ASCCON_ODD;
382        else
383            con |= ASCCON_ODD;
384    }
385
386    port->read_status_mask = ASCCON_OE;
387    if (iflag & INPCK)
388        port->read_status_mask |= ASCCON_FE | ASCCON_PE;
389    
390    port->ignore_status_mask = 0;
391    if (iflag & IGNPAR)
392        port->ignore_status_mask |= ASCCON_FE | ASCCON_PE;
393    
394    if (iflag & IGNBRK) {
395        /*
396         * If we're ignoring parity and break indicators,
397         * ignore overruns too (for real raw support).
398         */
399        if (iflag & IGNPAR)
400            port->ignore_status_mask |= ASCCON_OE;
401    }
402
403    /*
404     * Ignore all characters if CREAD is not set.
405     */
406    if ((cflag & CREAD) == 0)
407        port->ignore_status_mask |= UART_DUMMY_UER_RX;
408
409    /* set error signals - framing, parity and overrun */
410    con |= ASCCON_FEN;
411    con |= ASCCON_OEN;
412    con |= ASCCON_PEN;
413    /* enable the receiver */
414    con |= ASCCON_REN;
415
416    /* block the IRQs */
417    local_irq_save(flags);
418
419    /* set up CON */
420    amazon_writel(con, AMAZON_ASC_CON);
421
422    /* Set baud rate - take a divider of 2 into account */
423    baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
424    quot = uart_get_divisor(port, baud);
425    quot = quot/2 - 1;
426
427    /* the next 3 probably already happened when we set CON above */
428    /* disable the baudrate generator */
429    amazon_writel_masked(AMAZON_ASC_CON, ASCCON_R, 0);
430    /* make sure the fractional divider is off */
431    amazon_writel_masked(AMAZON_ASC_CON, ASCCON_FDE, 0);
432    /* set up to use divisor of 2 */
433    amazon_writel_masked(AMAZON_ASC_CON, ASCCON_BRS, 0);
434    /* now we can write the new baudrate into the register */
435    amazon_writel(quot, AMAZON_ASC_BTR);
436    /* turn the baudrate generator back on */
437    amazon_writel_masked(AMAZON_ASC_CON, ASCCON_R, ASCCON_R);
438
439    local_irq_restore(flags);
440}
441
442static const char *amazonasc_type(struct uart_port *port)
443{
444    return port->type == PORT_AMAZONASC ? "AMAZONASC" : NULL;
445}
446
447/*
448 * Release the memory region(s) being used by 'port'
449 */
450static void amazonasc_release_port(struct uart_port *port)
451{
452    return;
453}
454
455/*
456 * Request the memory region(s) being used by 'port'
457 */
458static int amazonasc_request_port(struct uart_port *port)
459{
460    return 0;
461}
462
463/*
464 * Configure/autoconfigure the port.
465 */
466static void amazonasc_config_port(struct uart_port *port, int flags)
467{
468    if (flags & UART_CONFIG_TYPE) {
469        port->type = PORT_AMAZONASC;
470        amazonasc_request_port(port);
471    }
472}
473
474/*
475 * verify the new serial_struct (for TIOCSSERIAL).
476 */
477static int amazonasc_verify_port(struct uart_port *port, struct serial_struct *ser)
478{
479    int ret = 0;
480    if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMAZONASC)
481        ret = -EINVAL;
482    if (ser->irq < 0 || ser->irq >= NR_IRQS)
483        ret = -EINVAL;
484    if (ser->baud_base < 9600)
485        ret = -EINVAL;
486    return ret;
487}
488
489static struct uart_ops amazonasc_pops = {
490    .tx_empty = amazonasc_tx_empty,
491    .set_mctrl = amazonasc_set_mctrl,
492    .get_mctrl = amazonasc_get_mctrl,
493    .stop_tx = amazonasc_stop_tx,
494    .start_tx = amazonasc_start_tx,
495    .stop_rx = amazonasc_stop_rx,
496    .enable_ms = amazonasc_enable_ms,
497    .break_ctl = amazonasc_break_ctl,
498    .startup = amazonasc_startup,
499    .shutdown = amazonasc_shutdown,
500    .set_termios = amazonasc_set_termios,
501    .type = amazonasc_type,
502    .release_port = amazonasc_release_port,
503    .request_port = amazonasc_request_port,
504    .config_port = amazonasc_config_port,
505    .verify_port = amazonasc_verify_port,
506};
507
508static struct uart_port amazonasc_ports[UART_NR] = {
509    {
510        membase: (void *)AMAZON_ASC,
511        mapbase: AMAZON_ASC,
512        iotype: SERIAL_IO_MEM,
513        irq: AMAZONASC_RIR, /* RIR */
514        uartclk: 0, /* filled in dynamically */
515        fifosize: 16,
516        unused: { AMAZONASC_TIR, AMAZONASC_EIR}, /* xmit/error/xmit-buffer-empty IRQ */
517        type: PORT_AMAZONASC,
518        ops: &amazonasc_pops,
519        flags: ASYNC_BOOT_AUTOCONF,
520    },
521};
522
523static void amazonasc_console_write(struct console *co, const char *s, u_int count)
524{
525    int i, fifocnt;
526    unsigned long flags;
527    local_irq_save(flags);
528    for (i = 0; i < count;)
529    {
530        /* wait until the FIFO is not full */
531        do
532        {
533            fifocnt = (amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_TXFFLMASK)
534                    >> ASCFSTAT_TXFFLOFF;
535        } while (fifocnt == AMAZONASC_TXFIFO_FULL);
536        if (s[i] == '\0')
537        {
538            break;
539        }
540        if (s[i] == '\n')
541        {
542            amazon_writel('\r', AMAZON_ASC_TBUF);
543            do
544            {
545                fifocnt = (amazon_readl(AMAZON_ASC_FSTAT) &
546                ASCFSTAT_TXFFLMASK) >> ASCFSTAT_TXFFLOFF;
547            } while (fifocnt == AMAZONASC_TXFIFO_FULL);
548        }
549        amazon_writel(s[i], AMAZON_ASC_TBUF);
550        i++;
551    }
552
553    local_irq_restore(flags);
554}
555
556static void __init
557amazonasc_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
558{
559    u_int lcr_h;
560
561    lcr_h = amazon_readl(AMAZON_ASC_CON);
562    /* do this only if the ASC is turned on */
563    if (lcr_h & ASCCON_R) {
564        u_int quot, div, fdiv, frac;
565
566        *parity = 'n';
567        if ((lcr_h & ASCCON_MODEMASK) == ASCCON_M_7ASYNCPAR ||
568                    (lcr_h & ASCCON_MODEMASK) == ASCCON_M_8ASYNCPAR) {
569            if (lcr_h & ASCCON_ODD)
570                *parity = 'o';
571            else
572                *parity = 'e';
573        }
574
575        if ((lcr_h & ASCCON_MODEMASK) == ASCCON_M_7ASYNCPAR)
576            *bits = 7;
577        else
578            *bits = 8;
579
580        quot = amazon_readl(AMAZON_ASC_BTR) + 1;
581        
582        /* this gets hairy if the fractional divider is used */
583        if (lcr_h & ASCCON_FDE)
584        {
585            div = 1;
586            fdiv = amazon_readl(AMAZON_ASC_FDV);
587            if (fdiv == 0)
588                fdiv = 512;
589            frac = 512;
590        }
591        else
592        {
593            div = lcr_h & ASCCON_BRS ? 3 : 2;
594            fdiv = frac = 1;
595        }
596        /*
597         * This doesn't work exactly because we use integer
598         * math to calculate baud which results in rounding
599         * errors when we try to go from quot -> baud !!
600         * Try to make this work for both the fractional divider
601         * and the simple divider. Also try to avoid rounding
602         * errors using integer math.
603         */
604        
605        *baud = frac * (port->uartclk / (div * 512 * 16 * quot));
606        if (*baud > 1100 && *baud < 2400)
607            *baud = 1200;
608        if (*baud > 2300 && *baud < 4800)
609            *baud = 2400;
610        if (*baud > 4700 && *baud < 9600)
611            *baud = 4800;
612        if (*baud > 9500 && *baud < 19200)
613            *baud = 9600;
614        if (*baud > 19000 && *baud < 38400)
615            *baud = 19200;
616        if (*baud > 38400 && *baud < 57600)
617            *baud = 38400;
618        if (*baud > 57600 && *baud < 115200)
619            *baud = 57600;
620        if (*baud > 115200 && *baud < 230400)
621            *baud = 115200;
622    }
623}
624
625static int __init amazonasc_console_setup(struct console *co, char *options)
626{
627    struct uart_port *port;
628    int baud = 115200;
629    int bits = 8;
630    int parity = 'n';
631    int flow = 'n';
632
633    /* this assumes: CON.BRS = CON.FDE = 0 */
634    if (uartclk == 0)
635        uartclk = amazon_get_fpi_hz();
636    co->index = 0;
637    port = &amazonasc_ports[0];
638    amazonasc_ports[0].uartclk = uartclk;
639    amazonasc_ports[0].type = PORT_AMAZONASC;
640
641    if (options){
642        uart_parse_options(options, &baud, &parity, &bits, &flow);
643    }
644
645    return uart_set_options(port, co, baud, parity, bits, flow);
646}
647
648static struct uart_driver amazonasc_reg;
649static struct console amazonasc_console = {
650    name: "ttyS",
651    write: amazonasc_console_write,
652    device: uart_console_device,
653    setup: amazonasc_console_setup,
654    flags: CON_PRINTBUFFER,
655    index: -1,
656    data: &amazonasc_reg,
657};
658
659static struct uart_driver amazonasc_reg = {
660    .owner = THIS_MODULE,
661    .driver_name = "serial",
662    .dev_name = "ttyS",
663    .major = TTY_MAJOR,
664    .minor = 64,
665    .nr = UART_NR,
666    .cons = &amazonasc_console,
667};
668
669static int amazon_asc_probe(struct platform_device *dev)
670{
671    unsigned char res;
672    uart_register_driver(&amazonasc_reg);
673    res = uart_add_one_port(&amazonasc_reg, &amazonasc_ports[0]);
674    return res;
675}
676
677static int amazon_asc_remove(struct platform_device *dev)
678{
679    uart_unregister_driver(&amazonasc_reg);
680    return 0;
681}
682
683static struct platform_driver amazon_asc_driver = {
684    .probe = amazon_asc_probe,
685    .remove = amazon_asc_remove,
686    .driver = {
687        .name = "amazon_asc",
688        .owner = THIS_MODULE,
689    },
690};
691
692static int __init amazon_asc_init(void)
693{
694    int ret = platform_driver_register(&amazon_asc_driver);
695    if (ret)
696        printk(KERN_WARNING "amazon_asc: error registering platfom driver!\n");
697    return ret;
698}
699
700static void __exit amazon_asc_cleanup(void)
701{
702    platform_driver_unregister(&amazon_asc_driver);
703}
704
705module_init(amazon_asc_init);
706module_exit(amazon_asc_cleanup);
707
708MODULE_AUTHOR("Gary Jennejohn, Felix Fietkau, John Crispin");
709MODULE_DESCRIPTION("MIPS AMAZONASC serial port driver");
710MODULE_LICENSE("GPL");
711
712

Archive Download this file



interactive