brintos

brintos / linux-shallow public Read only

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