1/* 2 * linux/drivers/acorn/char/serial-card.c 3 * 4 * Copyright (C) 1996-1999 Russell King. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * A generic handler of serial expansion cards that use 16550s or 11 * the like. 12 * 13 * Definitions: 14 * MY_PRODS Product numbers to identify this card by 15 * MY_MANUS Manufacturer numbers to identify this card by 16 * MY_NUMPORTS Number of ports per card 17 * MY_BAUD_BASE Baud base for the card 18 * MY_INIT Initialisation routine name 19 * MY_BASE_ADDRESS(ec) Return base address for ports 20 * MY_PORT_ADDRESS 21 * (port,cardaddr) Return address for port using base address 22 * from above. 23 * 24 * Changelog: 25 * 30-07-1996 RMK Created 26 * 22-04-1998 RMK Removed old register_pre_init_serial 27 */ 28#include <linux/module.h> 29#include <linux/types.h> 30#include <linux/serial.h> 31#include <linux/errno.h> 32#include <linux/init.h> 33 34#include <asm/ecard.h> 35#include <asm/string.h> 36 37#ifndef NUM_SERIALS 38#define NUM_SERIALS MY_NUMPORTS * MAX_ECARDS 39#endif 40 41#ifdef MODULE 42static int __serial_ports[NUM_SERIALS]; 43static int __serial_pcount; 44static int __serial_addr[NUM_SERIALS]; 45static struct expansion_card *expcard[MAX_ECARDS]; 46#define ADD_ECARD(ec,card) expcard[(card)] = (ec) 47#define ADD_PORT(port,addr) \ 48 do { \ 49 __serial_ports[__serial_pcount] = (port); \ 50 __serial_addr[__serial_pcount] = (addr); \ 51 __serial_pcount += 1; \ 52 } while (0) 53#else 54#define ADD_ECARD(ec,card) 55#define ADD_PORT(port,addr) 56#endif 57 58static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } }; 59 60static inline int serial_register_onedev (unsigned long port, int irq) 61{ 62 struct serial_struct req; 63 64 memset(&req, 0, sizeof(req)); 65 req.baud_base = MY_BAUD_BASE; 66 req.irq = irq; 67 req.port = port; 68 req.flags = 0; 69 70 return register_serial(&req); 71} 72 73static int __init INIT (void) 74{ 75 int card = 0; 76 77 ecard_startfind (); 78 79 do { 80 struct expansion_card *ec; 81 unsigned long cardaddr; 82 int port; 83 84 ec = ecard_find (0, serial_cids); 85 if (!ec) 86 break; 87 88 cardaddr = MY_BASE_ADDRESS(ec); 89 90 for (port = 0; port < MY_NUMPORTS; port ++) { 91 unsigned long address; 92 int line; 93 94 address = MY_PORT_ADDRESS(port, cardaddr); 95 96 line = serial_register_onedev (address, ec->irq); 97 if (line < 0) 98 break; 99 ADD_PORT(line, address); 100 } 101 102 if (port) { 103 ecard_claim (ec); 104 ADD_ECARD(ec, card); 105 } else 106 break; 107 } while (++card < MAX_ECARDS); 108 return card ? 0 : -ENODEV; 109} 110 111static void __exit EXIT (void) 112{ 113#ifdef MODULE 114 int i; 115 116 for (i = 0; i < __serial_pcount; i++) { 117 unregister_serial(__serial_ports[i]); 118 release_region(__serial_addr[i], 8); 119 } 120 121 for (i = 0; i < MAX_ECARDS; i++) 122 if (expcard[i]) 123 ecard_release (expcard[i]); 124#endif 125} 126 127EXPORT_NO_SYMBOLS; 128 129MODULE_LICENSE("GPL"); 130 131module_init(INIT); 132module_exit(EXIT); 133