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