1/*
2 * Auich BeOS Driver for Intel Southbridge audio
3 *
4 * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
5 *
6 * Original code : BeOS Driver for Intel ICH AC'97 Link interface
7 * Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de>
8 *
9 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 *   this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 *   this list of conditions and the following disclaimer in the documentation
17 *   and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31#include <KernelExport.h>
32#include <OS.h>
33#include "io.h"
34#include "auichreg.h"
35#include "debug.h"
36#include <PCI.h>
37
38extern pci_module_info  *pci;
39
40uint8
41auich_reg_read_8(device_config *config, uint8 regno)
42{
43	ASSERT(regno >= 0);
44	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63);
45	if (config->type & TYPE_ICH4)
46		return *(uint8 *)(((char *)config->log_mbbar) + regno);
47	else
48		return pci->read_io_8(config->nabmbar + regno);
49}
50
51uint16
52auich_reg_read_16(device_config *config, uint8 regno)
53{
54	ASSERT(regno >= 0);
55	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63);
56	if (config->type & TYPE_ICH4)
57		return *(uint16 *)(((char *)config->log_mbbar) + regno);
58	else
59		return pci->read_io_16(config->nabmbar + regno);
60}
61
62uint32
63auich_reg_read_32(device_config *config, uint8 regno)
64{
65	ASSERT(regno >= 0);
66	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63);
67	if (config->type & TYPE_ICH4)
68		return *(uint32 *)(((char *)config->log_mbbar) + regno);
69	else
70		return pci->read_io_32(config->nabmbar + regno);
71}
72
73void
74auich_reg_write_8(device_config *config, uint8 regno, uint8 value)
75{
76	ASSERT(regno >= 0);
77	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63);
78	if (config->type & TYPE_ICH4)
79		*(uint8 *)(((char *)config->log_mbbar) + regno) = value;
80	else
81		pci->write_io_8(config->nabmbar + regno, value);
82}
83
84void
85auich_reg_write_16(device_config *config, uint8 regno, uint16 value)
86{
87	ASSERT(regno >= 0);
88	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63);
89	if (config->type & TYPE_ICH4)
90		*(uint16 *)(((char *)config->log_mbbar) + regno) = value;
91	else
92		pci->write_io_16(config->nabmbar + regno, value);
93}
94
95void
96auich_reg_write_32(device_config *config, uint8 regno, uint32 value)
97{
98	ASSERT(regno >= 0);
99	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63);
100	if (config->type & TYPE_ICH4)
101		*(uint32 *)(((char *)config->log_mbbar) + regno) = value;
102	else
103		pci->write_io_32(config->nabmbar + regno, value);
104}
105
106/* codec */
107static uint8 sCodecLastReadRegister = 0;
108static uint8 sCodecLastWrittenRegister = 0;
109
110static int
111auich_codec_wait(device_config *config)
112{
113	int i;
114	/* Anyone holding a semaphore for 1 msec should be 'shot'... */
115	for (i = 0; i < 200; i++) {
116		if ((auich_reg_read_8(config, AUICH_REG_ACC_SEMA) & 0x01) == 0)
117			return B_OK;
118		if (i > 100)
119			snooze(10);
120	}
121	/* access to some forbidden (non existant) ac97 registers will not
122	 * reset the semaphore. So even if you don't get the semaphore, still
123	 * continue the access. We don't really need the semaphore anyway. */
124	PRINT(("codec semaphore timed out!\n"));
125	PRINT(("last read/write registers: %x/%x\n", sCodecLastReadRegister, sCodecLastWrittenRegister));
126
127	return B_OK;
128}
129
130uint16
131auich_codec_read(device_config *config, uint8 regno)
132{
133	sCodecLastReadRegister = regno;
134	ASSERT(regno >= 0);
135	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 511) || regno <= 255);
136	if (auich_codec_wait(config)!=B_OK) {
137		PRINT(("codec busy (2)\n"));
138		return -1;
139	}
140
141	if (config->type & TYPE_ICH4)
142		return *(uint16 *)(((char *)config->log_mmbar) + regno);
143	else
144		return pci->read_io_16(config->nambar + regno);
145}
146
147void
148auich_codec_write(device_config *config, uint8 regno, uint16 value)
149{
150	sCodecLastWrittenRegister = regno;
151	ASSERT(regno >= 0);
152	ASSERT(((config->type & TYPE_ICH4) != 0 && regno <= 511) || regno <= 255);
153	if (auich_codec_wait(config)!=B_OK) {
154		PRINT(("codec busy (4)\n"));
155		return;
156	}
157	if (config->type & TYPE_ICH4)
158		*(uint16 *)(((char *)config->log_mmbar) + regno) = value;
159	else
160		pci->write_io_16(config->nambar + regno, value);
161}
162