linux/drivers/tty/serial/8250/8250_acorn.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/serial/acorn.c
   3 *
   4 *  Copyright (C) 1996-2003 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#include <linux/module.h>
  11#include <linux/types.h>
  12#include <linux/tty.h>
  13#include <linux/serial_core.h>
  14#include <linux/errno.h>
  15#include <linux/ioport.h>
  16#include <linux/slab.h>
  17#include <linux/device.h>
  18#include <linux/init.h>
  19
  20#include <asm/io.h>
  21#include <asm/ecard.h>
  22#include <asm/string.h>
  23
  24#include "8250.h"
  25
  26#define MAX_PORTS       3
  27
  28struct serial_card_type {
  29        unsigned int    num_ports;
  30        unsigned int    uartclk;
  31        unsigned int    type;
  32        unsigned int    offset[MAX_PORTS];
  33};
  34
  35struct serial_card_info {
  36        unsigned int    num_ports;
  37        int             ports[MAX_PORTS];
  38        void __iomem *vaddr;
  39};
  40
  41static int
  42serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
  43{
  44        struct serial_card_info *info;
  45        struct serial_card_type *type = id->data;
  46        struct uart_8250_port uart;
  47        unsigned long bus_addr;
  48        unsigned int i;
  49
  50        info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL);
  51        if (!info)
  52                return -ENOMEM;
  53
  54        info->num_ports = type->num_ports;
  55
  56        bus_addr = ecard_resource_start(ec, type->type);
  57        info->vaddr = ecardm_iomap(ec, type->type, 0, 0);
  58        if (!info->vaddr) {
  59                kfree(info);
  60                return -ENOMEM;
  61        }
  62
  63        ecard_set_drvdata(ec, info);
  64
  65        memset(&uart, 0, sizeof(struct uart_8250_port));
  66        uart.port.irq   = ec->irq;
  67        uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
  68        uart.port.uartclk       = type->uartclk;
  69        uart.port.iotype        = UPIO_MEM;
  70        uart.port.regshift      = 2;
  71        uart.port.dev   = &ec->dev;
  72
  73        for (i = 0; i < info->num_ports; i++) {
  74                uart.port.membase = info->vaddr + type->offset[i];
  75                uart.port.mapbase = bus_addr + type->offset[i];
  76
  77                info->ports[i] = serial8250_register_8250_port(&uart);
  78        }
  79
  80        return 0;
  81}
  82
  83static void serial_card_remove(struct expansion_card *ec)
  84{
  85        struct serial_card_info *info = ecard_get_drvdata(ec);
  86        int i;
  87
  88        ecard_set_drvdata(ec, NULL);
  89
  90        for (i = 0; i < info->num_ports; i++)
  91                if (info->ports[i] > 0)
  92                        serial8250_unregister_port(info->ports[i]);
  93
  94        kfree(info);
  95}
  96
  97static struct serial_card_type atomwide_type = {
  98        .num_ports      = 3,
  99        .uartclk        = 7372800,
 100        .type           = ECARD_RES_IOCSLOW,
 101        .offset         = { 0x2800, 0x2400, 0x2000 },
 102};
 103
 104static struct serial_card_type serport_type = {
 105        .num_ports      = 2,
 106        .uartclk        = 3686400,
 107        .type           = ECARD_RES_IOCSLOW,
 108        .offset         = { 0x2000, 0x2020 },
 109};
 110
 111static const struct ecard_id serial_cids[] = {
 112        { MANU_ATOMWIDE,        PROD_ATOMWIDE_3PSERIAL, &atomwide_type  },
 113        { MANU_SERPORT,         PROD_SERPORT_DSPORT,    &serport_type   },
 114        { 0xffff, 0xffff }
 115};
 116
 117static struct ecard_driver serial_card_driver = {
 118        .probe          = serial_card_probe,
 119        .remove         = serial_card_remove,
 120        .id_table       = serial_cids,
 121        .drv = {
 122                .name   = "8250_acorn",
 123        },
 124};
 125
 126static int __init serial_card_init(void)
 127{
 128        return ecard_register_driver(&serial_card_driver);
 129}
 130
 131static void __exit serial_card_exit(void)
 132{
 133        ecard_remove_driver(&serial_card_driver);
 134}
 135
 136MODULE_AUTHOR("Russell King");
 137MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver");
 138MODULE_LICENSE("GPL");
 139
 140module_init(serial_card_init);
 141module_exit(serial_card_exit);
 142