File: acpi_serial.c

package info (click to toggle)
kernel-image-2.4.17-hppa 32.4
  • links: PTS
  • area: main
  • in suites: woody
  • size: 156,356 kB
  • ctags: 442,585
  • sloc: ansic: 2,542,442; asm: 144,771; makefile: 8,468; sh: 3,097; perl: 2,578; yacc: 1,177; tcl: 577; lex: 352; awk: 251; lisp: 218; sed: 72
file content (203 lines) | stat: -rw-r--r-- 5,870 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
 *  linux/drivers/char/acpi_serial.c
 *
 *  Copyright (C) 2000  Hewlett-Packard Co.
 *  Copyright (C) 2000  Khalid Aziz <khalid_aziz@hp.com>
 *
 *  Detect and initialize the headless console serial port defined in 
 *  SPCR table and debug serial port defined in DBGP table
 *
 */
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <asm/serial.h>
#include <asm/io.h>
#include <linux/acpi_serial.h>
/*#include <asm/acpi-ext.h>*/

#undef SERIAL_DEBUG_ACPI

/*
 * Query ACPI tables for a debug and a headless console serial
 * port. If found, add them to rs_table[]. A pointer to either SPCR
 * or DBGP table is passed as parameter. This function should be called 
 * before serial_console_init() is called to make sure the SPCR serial 
 * console will be available for use. IA-64 kernel calls this function
 * from within acpi.c when it encounters SPCR or DBGP tables as it parses 
 * the ACPI 2.0 tables during bootup.
 *
 */
void __init setup_serial_acpi(void *tablep) 
{
	acpi_ser_t *acpi_ser_p;
	struct serial_struct serial_req;
	unsigned long iobase;
	int global_sys_irq;

#ifdef SERIAL_DEBUG_ACPI
	printk("Entering setup_serial_acpi()\n");
#endif

	/* Now get the table */
	if (tablep == NULL) {
		return;
	}

	acpi_ser_p = (acpi_ser_t *)tablep;

	/*
	 * Perform a sanity check on the table. Table should have a 
	 * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes
	 * long.
	 */
	if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, 
					ACPI_SIG_LEN) != 0) && 
		(strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, 
					ACPI_SIG_LEN) != 0)) {
		return;
	}
	if (acpi_ser_p->length < 52) {
		return;
	}

	iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl;
	global_sys_irq = (acpi_ser_p->global_int[3] << 24) | 
			(acpi_ser_p->global_int[2] << 16) |
			(acpi_ser_p->global_int[1] << 8) |
			acpi_ser_p->global_int[0];

#ifdef SERIAL_DEBUG_ACPI
	printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p);
	printk("                     sig = '%c%c%c%c'\n",
			acpi_ser_p->signature[0],
			acpi_ser_p->signature[1],
			acpi_ser_p->signature[2],
			acpi_ser_p->signature[3]);
	printk("                     length = %d\n", acpi_ser_p->length);
	printk("                     Rev = %d\n", acpi_ser_p->rev);
	printk("                     Interface type = %d\n", acpi_ser_p->intfc_type);
	printk("                     Base address = 0x%lX\n", iobase);
	printk("                     IRQ = %d\n", acpi_ser_p->irq);
	printk("                     Global System Int = %d\n", global_sys_irq);
	printk("                     Baud rate = ");
	switch (acpi_ser_p->baud) {
		case ACPI_SERIAL_BAUD_9600:
			printk("9600\n");
			break;

		case ACPI_SERIAL_BAUD_19200:
			printk("19200\n");
			break;

		case ACPI_SERIAL_BAUD_57600:
			printk("57600\n");
			break;

		case ACPI_SERIAL_BAUD_115200:
			printk("115200\n");
			break;

		default:
			printk("Huh (%d)\n", acpi_ser_p->baud);
			break;

	}
	if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) {
		printk("                     PCI serial port:\n");
		printk("                         Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n",
		acpi_ser_p->pci_bus, acpi_ser_p->pci_dev,
		acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id);
	}
#endif

	/* 
	 * Now build a serial_req structure to update the entry in
	 * rs_table for the headless console port.
	 */
	switch (acpi_ser_p->intfc_type) {
 		case ACPI_SERIAL_INTFC_16550:
			serial_req.type = PORT_16550;
			serial_req.baud_base = BASE_BAUD;
			break;

 		case ACPI_SERIAL_INTFC_16450:
			serial_req.type = PORT_16450;
			serial_req.baud_base = BASE_BAUD;
			break;

		default:
			serial_req.type = PORT_UNKNOWN;
			break;
	}
	if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE,
					ACPI_SIG_LEN) == 0) {
		serial_req.line = ACPI_SERIAL_CONSOLE_PORT;
	}
	else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, 
					ACPI_SIG_LEN) == 0) {
		serial_req.line = ACPI_SERIAL_DEBUG_PORT;
	}
	/*
	 * Check if this is an I/O mapped address or a memory mapped address
	 */
	if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) {
		serial_req.port = 0;
		serial_req.port_high = 0;
		serial_req.iomem_base = (void *)ioremap(iobase, 64);
		serial_req.io_type = SERIAL_IO_MEM;
	}
	else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) {
		serial_req.port = (unsigned long) iobase & 0xffffffff;
		serial_req.port_high = (unsigned long)(((u64)iobase) >> 32);
		serial_req.iomem_base = NULL;
		serial_req.io_type = SERIAL_IO_PORT;
	}
	else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) {
		printk("WARNING: No support for PCI serial console\n");
		return;
	}

	/*
	 * If the table does not have IRQ information, use 0 for IRQ. 
	 * This will force rs_init() to probe for IRQ. 
	 */
	if (acpi_ser_p->length < 53) {
		serial_req.irq = 0;
	}
	else {
		serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF | 
					ASYNC_AUTO_IRQ;
		if (acpi_ser_p->int_type & 
			(ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) {
			serial_req.irq = global_sys_irq;
		}
		else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) {
			serial_req.irq = acpi_ser_p->irq;
		}
		else {
			/*
			 * IRQ type not being set would mean UART will
			 * run in polling mode. Do not probe for IRQ in
			 * that case.
			 */
			serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF;
		}
	}

	serial_req.xmit_fifo_size = serial_req.custom_divisor = 0;
	serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0;
	serial_req.iomem_reg_shift = 0;
	if (early_serial_setup(&serial_req) < 0) {
		printk("early_serial_setup() for ACPI serial console port failed\n");
		return;
	}

#ifdef SERIAL_DEBUG_ACPI
	printk("Leaving setup_serial_acpi()\n");
#endif
}