summaryrefslogtreecommitdiffstats
path: root/drivers/acorn/char/serial-card.c
blob: b34c9fcad5c9a4953cb0b76de7b53f56818b57fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 *  linux/drivers/acorn/char/serial-card.c
 *
 *  Copyright (C) 1996-1999 Russell King.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * A generic handler of serial expansion cards that use 16550s or
 * the like.
 *
 * Definitions:
 *  MY_PRODS		Product numbers to identify this card by
 *  MY_MANUS		Manufacturer numbers to identify this card by
 *  MY_NUMPORTS		Number of ports per card
 *  MY_BAUD_BASE	Baud base for the card
 *  MY_INIT		Initialisation routine name
 *  MY_BASE_ADDRESS(ec)	Return base address for ports
 *  MY_PORT_ADDRESS
 *	(port,cardaddr)	Return address for port using base address
 *			from above.
 *
 * Changelog:
 *  30-07-1996	RMK	Created
 *  22-04-1998	RMK	Removed old register_pre_init_serial
 */
#include <linux/module.h>
#include <linux/types.h>
#include <linux/serial.h>
#include <linux/errno.h>
#include <linux/init.h>

#include <asm/ecard.h>
#include <asm/string.h>

#ifndef NUM_SERIALS
#define NUM_SERIALS	MY_NUMPORTS * MAX_ECARDS
#endif

#ifdef MODULE
static int __serial_ports[NUM_SERIALS];
static int __serial_pcount;
static int __serial_addr[NUM_SERIALS];
static struct expansion_card *expcard[MAX_ECARDS];
#define ADD_ECARD(ec,card) expcard[(card)] = (ec)
#define ADD_PORT(port,addr)					\
	do {							\
		__serial_ports[__serial_pcount] = (port);	\
		__serial_addr[__serial_pcount] = (addr);	\
		__serial_pcount += 1;				\
	} while (0)
#else
#define ADD_ECARD(ec,card)
#define ADD_PORT(port,addr)
#endif

static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } };

static inline int serial_register_onedev (unsigned long port, int irq)
{
    struct serial_struct req;

    memset(&req, 0, sizeof(req));
    req.baud_base = MY_BAUD_BASE;
    req.irq = irq;
    req.port = port;
    req.flags = 0;

    return register_serial(&req);
}

static int __init INIT (void)
{
    int card = 0;

    ecard_startfind ();

    do {
	struct expansion_card *ec;
	unsigned long cardaddr;
	int port;

	ec = ecard_find (0, serial_cids);
	if (!ec)
	    break;

	cardaddr = MY_BASE_ADDRESS(ec);

	for (port = 0; port < MY_NUMPORTS; port ++) {
	    unsigned long address;
	    int line;

	    address = MY_PORT_ADDRESS(port, cardaddr);

	    line = serial_register_onedev (address, ec->irq);
	    if (line < 0)
		break;
	    ADD_PORT(line, address);
	}

	if (port) {
	    ecard_claim (ec);
	    ADD_ECARD(ec, card);
	} else
	    break;
    } while (++card < MAX_ECARDS);
    return card ? 0 : -ENODEV;
}

static void __exit EXIT (void)
{
#ifdef MODULE
    int i;

    for (i = 0; i < __serial_pcount; i++) {
	unregister_serial(__serial_ports[i]);
	release_region(__serial_addr[i], 8);
    }

    for (i = 0; i < MAX_ECARDS; i++)
	if (expcard[i])
	    ecard_release (expcard[i]);
#endif
}

EXPORT_NO_SYMBOLS;

module_init(INIT);
module_exit(EXIT);