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
->min_address_range
;
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
->range_length
) {
40 port
->iobase
= io
->min_base_address
;
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_ext_irq
*ext_irq
)
50 if (ext_irq
->number_of_interrupts
> 0)
51 port
->irq
= acpi_register_gsi(ext_irq
->interrupts
[0],
52 ext_irq
->edge_level
, ext_irq
->active_high_low
);
56 static acpi_status
acpi_serial_irq(struct uart_port
*port
,
57 struct acpi_resource_irq
*irq
)
59 if (irq
->number_of_interrupts
> 0)
60 port
->irq
= acpi_register_gsi(irq
->interrupts
[0],
61 irq
->edge_level
, irq
->active_high_low
);
65 static acpi_status
acpi_serial_resource(struct acpi_resource
*res
, void *data
)
67 struct uart_port
*port
= (struct uart_port
*) data
;
68 struct acpi_resource_address64 addr
;
71 status
= acpi_resource_to_address64(res
, &addr
);
72 if (ACPI_SUCCESS(status
))
73 return acpi_serial_mmio(port
, &addr
);
74 else if (res
->id
== ACPI_RSTYPE_IO
)
75 return acpi_serial_port(port
, &res
->data
.io
);
76 else if (res
->id
== ACPI_RSTYPE_EXT_IRQ
)
77 return acpi_serial_ext_irq(port
, &res
->data
.extended_irq
);
78 else if (res
->id
== ACPI_RSTYPE_IRQ
)
79 return acpi_serial_irq(port
, &res
->data
.irq
);
83 static int acpi_serial_add(struct acpi_device
*device
)
85 struct serial_private
*priv
;
87 struct uart_port port
;
90 memset(&port
, 0, sizeof(struct uart_port
));
92 port
.uartclk
= 1843200;
93 port
.flags
= UPF_SKIP_TEST
| UPF_BOOT_AUTOCONF
;
95 priv
= kmalloc(sizeof(struct serial_private
), GFP_KERNEL
);
100 memset(priv
, 0, sizeof(*priv
));
102 status
= acpi_walk_resources(device
->handle
, METHOD_NAME__CRS
,
103 acpi_serial_resource
, &port
);
104 if (ACPI_FAILURE(status
)) {
109 if (!port
.mapbase
&& !port
.iobase
) {
110 printk(KERN_ERR
"%s: no iomem or port address in %s _CRS\n",
111 __FUNCTION__
, device
->pnp
.bus_id
);
116 priv
->line
= serial8250_register_port(&port
);
117 if (priv
->line
< 0) {
118 printk(KERN_WARNING
"Couldn't register serial port %s: %d\n",
119 device
->pnp
.bus_id
, priv
->line
);
124 acpi_driver_data(device
) = priv
;
133 static int acpi_serial_remove(struct acpi_device
*device
, int type
)
135 struct serial_private
*priv
;
137 if (!device
|| !acpi_driver_data(device
))
140 priv
= acpi_driver_data(device
);
141 serial8250_unregister_port(priv
->line
);
147 static struct acpi_driver acpi_serial_driver
= {
152 .add
= acpi_serial_add
,
153 .remove
= acpi_serial_remove
,
157 static int __init
acpi_serial_init(void)
159 return acpi_bus_register_driver(&acpi_serial_driver
);
162 static void __exit
acpi_serial_exit(void)
164 acpi_bus_unregister_driver(&acpi_serial_driver
);
167 module_init(acpi_serial_init
);
168 module_exit(acpi_serial_exit
);
170 MODULE_LICENSE("GPL");
171 MODULE_DESCRIPTION("Generic 8250/16x50 ACPI serial driver");