xref: /haiku/src/add-ons/kernel/drivers/audio/ac97/auich/io.c (revision 6ae6d56c27db185eb03bff6c9f2e0e7105cddd42)
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 
38 extern pci_module_info  *pci;
39 
40 uint8
auich_reg_read_8(device_config * config,uint8 regno)41 auich_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 
51 uint16
auich_reg_read_16(device_config * config,uint8 regno)52 auich_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 
62 uint32
auich_reg_read_32(device_config * config,uint8 regno)63 auich_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 
73 void
auich_reg_write_8(device_config * config,uint8 regno,uint8 value)74 auich_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 
84 void
auich_reg_write_16(device_config * config,uint8 regno,uint16 value)85 auich_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 
95 void
auich_reg_write_32(device_config * config,uint8 regno,uint32 value)96 auich_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 */
107 static uint8 sCodecLastReadRegister = 0;
108 static uint8 sCodecLastWrittenRegister = 0;
109 
110 static int
auich_codec_wait(device_config * config)111 auich_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 
130 uint16
auich_codec_read(device_config * config,uint8 regno)131 auich_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 
147 void
auich_codec_write(device_config * config,uint8 regno,uint16 value)148 auich_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