2 * Copyright (c) 2002-2003 Matthew Wilcox for Hewlett-Packard
3 * Copyright (C) 2004 Hewlett-Packard Co
4 * Bjorn Helgaas <bjorn.helgaas@hp.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 #include <linux/acpi.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/serial_core.h>
17 #include <acpi/acpi_bus.h>
23 struct serial_private
{
27 static acpi_status
acpi_serial_mmio(struct uart_port
*port
,
28 struct acpi_resource_address64
*addr
)
30 port
->mapbase
= addr
->minimum
;
31 port
->iotype
= UPIO_MEM
;
32 port
->flags
|= UPF_IOREMAP
;
36 static acpi_status
acpi_serial_port(struct uart_port
*port
,
37 struct acpi_resource_io
*io
)
39 if (io
->address_length
) {
40 port
->iobase
= io
->minimum
;
41 port
->iotype
= UPIO_PORT
;
43 printk(KERN_ERR
"%s: zero-length IO port range?\n", __FUNCTION__
);
47 static acpi_status
acpi_serial_ext_irq(struct uart_port
*port
,
48 struct acpi_resource_extended_irq
*ext_irq
)
52 if (ext_irq
->interrupt_count
> 0) {
53 rc
= acpi_register_gsi(ext_irq
->interrupts
[0],
54 ext_irq
->triggering
, ext_irq
->polarity
);
62 static acpi_status
acpi_serial_irq(struct uart_port
*port
,
63 struct acpi_resource_irq
*irq
)
67 if (irq
->interrupt_count
> 0) {
68 rc
= acpi_register_gsi(irq
->interrupts
[0],
69 irq
->triggering
, irq
->polarity
);
77 static acpi_status
acpi_serial_resource(struct acpi_resource
*res
, void *data
)
79 struct uart_port
*port
= (struct uart_port
*) data
;
80 struct acpi_resource_address64 addr
;
83 status
= acpi_resource_to_address64(res
, &addr
);
84 if (ACPI_SUCCESS(status
))
85 return acpi_serial_mmio(port
, &addr
);
86 else if (res
->type
== ACPI_RESOURCE_TYPE_IO
)
87 return acpi_serial_port(port
, &res
->data
.io
);
88 else if (res
->type
== ACPI_RESOURCE_TYPE_EXTENDED_IRQ
)
89 return acpi_serial_ext_irq(port
, &res
->data
.extended_irq
);
90 else if (res
->type
== ACPI_RESOURCE_TYPE_IRQ
)
91 return acpi_serial_irq(port
, &res
->data
.irq
);
95 static int acpi_serial_add(struct acpi_device
*device
)
97 struct serial_private
*priv
;
99 struct uart_port port
;
102 memset(&port
, 0, sizeof(struct uart_port
));
104 port
.uartclk
= 1843200;
105 port
.flags
= UPF_SKIP_TEST
| UPF_BOOT_AUTOCONF
;
107 priv
= kmalloc(sizeof(struct serial_private
), GFP_KERNEL
);
112 memset(priv
, 0, sizeof(*priv
));
114 status
= acpi_walk_resources(device
->handle
, METHOD_NAME__CRS
,
115 acpi_serial_resource
, &port
);
116 if (ACPI_FAILURE(status
)) {
121 if (!port
.mapbase
&& !port
.iobase
) {
122 printk(KERN_ERR
"%s: no iomem or port address in %s _CRS\n",
123 __FUNCTION__
, device
->pnp
.bus_id
);
128 priv
->line
= serial8250_register_port(&port
);
129 if (priv
->line
< 0) {
130 printk(KERN_WARNING
"Couldn't register serial port %s: %d\n",
131 device
->pnp
.bus_id
, priv
->line
);
136 acpi_driver_data(device
) = priv
;
145 static int acpi_serial_remove(struct acpi_device
*device
, int type
)
147 struct serial_private
*priv
;
149 if (!device
|| !acpi_driver_data(device
))
152 priv
= acpi_driver_data(device
);
153 serial8250_unregister_port(priv
->line
);
159 static struct acpi_driver acpi_serial_driver
= {
164 .add
= acpi_serial_add
,
165 .remove
= acpi_serial_remove
,
169 static int __init
acpi_serial_init(void)
171 return acpi_bus_register_driver(&acpi_serial_driver
);
174 static void __exit
acpi_serial_exit(void)
176 acpi_bus_unregister_driver(&acpi_serial_driver
);
179 module_init(acpi_serial_init
);
180 module_exit(acpi_serial_exit
);
182 MODULE_LICENSE("GPL");
183 MODULE_DESCRIPTION("Generic 8250/16x50 ACPI serial driver");