1 /* 2 * 3 * smapi.c -- SMAPI interface routines 4 * 5 * 6 * Written By: Mike Sullivan IBM Corporation 7 * 8 * Copyright (C) 1999 IBM Corporation 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * NO WARRANTY 21 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 22 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 23 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 24 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 25 * solely responsible for determining the appropriateness of using and 26 * distributing the Program and assumes all risks associated with its 27 * exercise of rights under this Agreement, including but not limited to 28 * the risks and costs of program errors, damage to or loss of data, 29 * programs or equipment, and unavailability or interruption of operations. 30 * 31 * DISCLAIMER OF LIABILITY 32 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 33 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 36 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 37 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 38 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 39 * 40 * You should have received a copy of the GNU General Public License 41 * along with this program; if not, write to the Free Software 42 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 43 * 44 * 45 * 10/23/2000 - Alpha Release 46 * First release to the public 47 */ 48 49 #include <linux/kernel.h> 50 #include <linux/mc146818rtc.h> /* CMOS defines */ 51 #include "smapi.h" 52 #include "mwavedd.h" 53 54 static unsigned short g_usSmapiPort = 0; 55 56 57 static int smapi_request(unsigned short inBX, unsigned short inCX, 58 unsigned short inDI, unsigned short inSI, 59 unsigned short *outAX, unsigned short *outBX, 60 unsigned short *outCX, unsigned short *outDX, 61 unsigned short *outDI, unsigned short *outSI) 62 { 63 unsigned short myoutAX = 2, *pmyoutAX = &myoutAX; 64 unsigned short myoutBX = 3, *pmyoutBX = &myoutBX; 65 unsigned short myoutCX = 4, *pmyoutCX = &myoutCX; 66 unsigned short myoutDX = 5, *pmyoutDX = &myoutDX; 67 unsigned short myoutDI = 6, *pmyoutDI = &myoutDI; 68 unsigned short myoutSI = 7, *pmyoutSI = &myoutSI; 69 unsigned short usSmapiOK = -EIO, *pusSmapiOK = &usSmapiOK; 70 unsigned int inBXCX = (inBX << 16) | inCX; 71 unsigned int inDISI = (inDI << 16) | inSI; 72 73 __asm__ __volatile__("movw $0x5380,%%ax\n\t" 74 "movl %7,%%ebx\n\t" 75 "shrl $16, %%ebx\n\t" 76 "movw %7,%%cx\n\t" 77 "movl %8,%%edi\n\t" 78 "shrl $16,%%edi\n\t" 79 "movw %8,%%si\n\t" 80 "movw %9,%%dx\n\t" 81 "out %%al,%%dx\n\t" 82 "out %%al,$0x4F\n\t" 83 "cmpb $0x53,%%ah\n\t" 84 "je 2f\n\t" 85 "1:\n\t" 86 "orb %%ah,%%ah\n\t" 87 "jnz 2f\n\t" 88 "movw %%ax,%0\n\t" 89 "movw %%bx,%1\n\t" 90 "movw %%cx,%2\n\t" 91 "movw %%dx,%3\n\t" 92 "movw %%di,%4\n\t" 93 "movw %%si,%5\n\t" 94 "movw $1,%6\n\t" 95 "2:\n\t":"=m"(*(unsigned short *) pmyoutAX), 96 "=m"(*(unsigned short *) pmyoutBX), 97 "=m"(*(unsigned short *) pmyoutCX), 98 "=m"(*(unsigned short *) pmyoutDX), 99 "=m"(*(unsigned short *) pmyoutDI), 100 "=m"(*(unsigned short *) pmyoutSI), 101 "=m"(*(unsigned short *) pusSmapiOK) 102 :"m"(inBXCX), "m"(inDISI), "m"(g_usSmapiPort) 103 :"%eax", "%ebx", "%ecx", "%edx", "%edi", 104 "%esi"); 105 106 *outAX = myoutAX; 107 *outBX = myoutBX; 108 *outCX = myoutCX; 109 *outDX = myoutDX; 110 *outDI = myoutDI; 111 *outSI = myoutSI; 112 113 return usSmapiOK == 1 ? 0 : -EIO; 114 } 115 116 117 int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings) 118 { 119 int bRC; 120 unsigned short usAX, usBX, usCX, usDX, usDI, usSI; 121 static const unsigned short ausDspBases[] = { 122 0x0030, 0x4E30, 0x8E30, 0xCE30, 123 0x0130, 0x0350, 0x0070, 0x0DB0 }; 124 static const unsigned short ausUartBases[] = { 125 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; 126 127 bRC = smapi_request(0x1802, 0x0000, 0, 0, 128 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 129 if (bRC) { 130 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Error: Could not get DSP Settings. Aborting.\n"); 131 return bRC; 132 } 133 134 pSettings->bDSPPresent = ((usBX & 0x0100) != 0); 135 pSettings->bDSPEnabled = ((usCX & 0x0001) != 0); 136 pSettings->usDspIRQ = usSI & 0x00FF; 137 pSettings->usDspDMA = (usSI & 0xFF00) >> 8; 138 if ((usDI & 0x00FF) < ARRAY_SIZE(ausDspBases)) { 139 pSettings->usDspBaseIO = ausDspBases[usDI & 0x00FF]; 140 } else { 141 pSettings->usDspBaseIO = 0; 142 } 143 144 /* check for illegal values */ 145 if ( pSettings->usDspBaseIO == 0 ) 146 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP base I/O address is 0\n"); 147 if ( pSettings->usDspIRQ == 0 ) 148 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP IRQ line is 0\n"); 149 150 bRC = smapi_request(0x1804, 0x0000, 0, 0, 151 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 152 if (bRC) { 153 PRINTK_ERROR("smapi::smapi_query_DSP_cfg: Error: Could not get DSP modem settings. Aborting.\n"); 154 return bRC; 155 } 156 157 pSettings->bModemEnabled = ((usCX & 0x0001) != 0); 158 pSettings->usUartIRQ = usSI & 0x000F; 159 if (((usSI & 0xFF00) >> 8) < ARRAY_SIZE(ausUartBases)) { 160 pSettings->usUartBaseIO = ausUartBases[(usSI & 0xFF00) >> 8]; 161 } else { 162 pSettings->usUartBaseIO = 0; 163 } 164 165 /* check for illegal values */ 166 if ( pSettings->usUartBaseIO == 0 ) 167 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART base I/O address is 0\n"); 168 if ( pSettings->usUartIRQ == 0 ) 169 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART IRQ line is 0\n"); 170 171 return bRC; 172 } 173 174 175 int smapi_set_DSP_cfg(void) 176 { 177 int bRC = -EIO; 178 int i; 179 unsigned short usAX, usBX, usCX, usDX, usDI, usSI; 180 static const unsigned short ausDspBases[] = { 181 0x0030, 0x4E30, 0x8E30, 0xCE30, 182 0x0130, 0x0350, 0x0070, 0x0DB0 }; 183 static const unsigned short ausUartBases[] = { 184 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; 185 static const unsigned short ausDspIrqs[] = { 186 5, 7, 10, 11, 15 }; 187 static const unsigned short ausUartIrqs[] = { 188 3, 4 }; 189 190 unsigned short dspio_index = 0, uartio_index = 0; 191 192 if (mwave_3780i_io) { 193 for (i = 0; i < ARRAY_SIZE(ausDspBases); i++) { 194 if (mwave_3780i_io == ausDspBases[i]) 195 break; 196 } 197 if (i == ARRAY_SIZE(ausDspBases)) { 198 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_io address %x. Aborting.\n", mwave_3780i_io); 199 return bRC; 200 } 201 dspio_index = i; 202 } 203 204 if (mwave_3780i_irq) { 205 for (i = 0; i < ARRAY_SIZE(ausDspIrqs); i++) { 206 if (mwave_3780i_irq == ausDspIrqs[i]) 207 break; 208 } 209 if (i == ARRAY_SIZE(ausDspIrqs)) { 210 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_irq %x. Aborting.\n", mwave_3780i_irq); 211 return bRC; 212 } 213 } 214 215 if (mwave_uart_io) { 216 for (i = 0; i < ARRAY_SIZE(ausUartBases); i++) { 217 if (mwave_uart_io == ausUartBases[i]) 218 break; 219 } 220 if (i == ARRAY_SIZE(ausUartBases)) { 221 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_io address %x. Aborting.\n", mwave_uart_io); 222 return bRC; 223 } 224 uartio_index = i; 225 } 226 227 228 if (mwave_uart_irq) { 229 for (i = 0; i < ARRAY_SIZE(ausUartIrqs); i++) { 230 if (mwave_uart_irq == ausUartIrqs[i]) 231 break; 232 } 233 if (i == ARRAY_SIZE(ausUartIrqs)) { 234 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_irq %x. Aborting.\n", mwave_uart_irq); 235 return bRC; 236 } 237 } 238 239 if (mwave_uart_irq || mwave_uart_io) { 240 241 /* Check serial port A */ 242 bRC = smapi_request(0x1402, 0x0000, 0, 0, 243 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 244 if (bRC) goto exit_smapi_request_error; 245 /* bRC == 0 */ 246 if (usBX & 0x0100) { /* serial port A is present */ 247 if (usCX & 1) { /* serial port is enabled */ 248 if ((usSI & 0xFF) == mwave_uart_irq) { 249 PRINTK_ERROR(KERN_ERR_MWAVE 250 "smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq); 251 goto exit_conflict; 252 } else { 253 if ((usSI >> 8) == uartio_index) { 254 PRINTK_ERROR(KERN_ERR_MWAVE 255 "smapi::smapi_set_DSP_cfg: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]); 256 goto exit_conflict; 257 } 258 } 259 } 260 } 261 262 /* Check serial port B */ 263 bRC = smapi_request(0x1404, 0x0000, 0, 0, 264 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 265 if (bRC) goto exit_smapi_request_error; 266 /* bRC == 0 */ 267 if (usBX & 0x0100) { /* serial port B is present */ 268 if (usCX & 1) { /* serial port is enabled */ 269 if ((usSI & 0xFF) == mwave_uart_irq) { 270 PRINTK_ERROR(KERN_ERR_MWAVE 271 "smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq); 272 goto exit_conflict; 273 } else { 274 if ((usSI >> 8) == uartio_index) { 275 PRINTK_ERROR(KERN_ERR_MWAVE 276 "smapi::smapi_set_DSP_cfg: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]); 277 goto exit_conflict; 278 } 279 } 280 } 281 } 282 283 /* Check IR port */ 284 bRC = smapi_request(0x1700, 0x0000, 0, 0, 285 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 286 if (bRC) goto exit_smapi_request_error; 287 bRC = smapi_request(0x1704, 0x0000, 0, 0, 288 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 289 if (bRC) goto exit_smapi_request_error; 290 /* bRC == 0 */ 291 if ((usCX & 0xff) != 0xff) { /* IR port not disabled */ 292 if ((usCX & 0xff) == mwave_uart_irq) { 293 PRINTK_ERROR(KERN_ERR_MWAVE 294 "smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq); 295 goto exit_conflict; 296 } else { 297 if ((usSI & 0xff) == uartio_index) { 298 PRINTK_ERROR(KERN_ERR_MWAVE 299 "smapi::smapi_set_DSP_cfg: IR port base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI & 0xff], ausUartBases[uartio_index]); 300 goto exit_conflict; 301 } 302 } 303 } 304 } 305 306 bRC = smapi_request(0x1802, 0x0000, 0, 0, 307 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 308 if (bRC) goto exit_smapi_request_error; 309 310 if (mwave_3780i_io) { 311 usDI = dspio_index; 312 } 313 if (mwave_3780i_irq) { 314 usSI = (usSI & 0xff00) | mwave_3780i_irq; 315 } 316 317 bRC = smapi_request(0x1803, 0x0101, usDI, usSI, 318 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 319 if (bRC) goto exit_smapi_request_error; 320 321 bRC = smapi_request(0x1804, 0x0000, 0, 0, 322 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 323 if (bRC) goto exit_smapi_request_error; 324 325 if (mwave_uart_io) { 326 usSI = (usSI & 0x00ff) | (uartio_index << 8); 327 } 328 if (mwave_uart_irq) { 329 usSI = (usSI & 0xff00) | mwave_uart_irq; 330 } 331 bRC = smapi_request(0x1805, 0x0101, 0, usSI, 332 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 333 if (bRC) goto exit_smapi_request_error; 334 335 bRC = smapi_request(0x1802, 0x0000, 0, 0, 336 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 337 if (bRC) goto exit_smapi_request_error; 338 339 bRC = smapi_request(0x1804, 0x0000, 0, 0, 340 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 341 if (bRC) goto exit_smapi_request_error; 342 343 /* normal exit: */ 344 return 0; 345 346 exit_conflict: 347 /* Message has already been printed */ 348 return -EIO; 349 350 exit_smapi_request_error: 351 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg exit on smapi_request error bRC %x\n", bRC); 352 return bRC; 353 } 354 355 356 int smapi_set_DSP_power_state(bool bOn) 357 { 358 unsigned short usAX, usBX, usCX, usDX, usDI, usSI; 359 unsigned short usPowerFunction; 360 361 usPowerFunction = (bOn) ? 1 : 0; 362 363 return smapi_request(0x4901, 0x0000, 0, usPowerFunction, &usAX, &usBX, &usCX, &usDX, &usDI, 364 &usSI); 365 } 366 367 int smapi_init(void) 368 { 369 int retval = -EIO; 370 unsigned short usSmapiID = 0; 371 unsigned long flags; 372 373 spin_lock_irqsave(&rtc_lock, flags); 374 usSmapiID = CMOS_READ(0x7C); 375 usSmapiID |= (CMOS_READ(0x7D) << 8); 376 spin_unlock_irqrestore(&rtc_lock, flags); 377 378 if (usSmapiID == 0x5349) { 379 spin_lock_irqsave(&rtc_lock, flags); 380 g_usSmapiPort = CMOS_READ(0x7E); 381 g_usSmapiPort |= (CMOS_READ(0x7F) << 8); 382 spin_unlock_irqrestore(&rtc_lock, flags); 383 if (g_usSmapiPort == 0) { 384 PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n"); 385 } else { 386 retval = 0; 387 //SmapiQuerySystemID(); 388 } 389 } else { 390 PRINTK_ERROR("smapi::smapi_init, ERROR invalid usSmapiID\n"); 391 retval = -ENXIO; 392 } 393 394 return retval; 395 } 396