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 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 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 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 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 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 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 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 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 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