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 int retval = 0; 73 74 PRINTK_5(TRACE_SMAPI, "inBX %x inCX %x inDI %x inSI %x\n", 75 inBX, inCX, inDI, inSI); 76 77 __asm__ __volatile__("movw $0x5380,%%ax\n\t" 78 "movl %7,%%ebx\n\t" 79 "shrl $16, %%ebx\n\t" 80 "movw %7,%%cx\n\t" 81 "movl %8,%%edi\n\t" 82 "shrl $16,%%edi\n\t" 83 "movw %8,%%si\n\t" 84 "movw %9,%%dx\n\t" 85 "out %%al,%%dx\n\t" 86 "out %%al,$0x4F\n\t" 87 "cmpb $0x53,%%ah\n\t" 88 "je 2f\n\t" 89 "1:\n\t" 90 "orb %%ah,%%ah\n\t" 91 "jnz 2f\n\t" 92 "movw %%ax,%0\n\t" 93 "movw %%bx,%1\n\t" 94 "movw %%cx,%2\n\t" 95 "movw %%dx,%3\n\t" 96 "movw %%di,%4\n\t" 97 "movw %%si,%5\n\t" 98 "movw $1,%6\n\t" 99 "2:\n\t":"=m"(*(unsigned short *) pmyoutAX), 100 "=m"(*(unsigned short *) pmyoutBX), 101 "=m"(*(unsigned short *) pmyoutCX), 102 "=m"(*(unsigned short *) pmyoutDX), 103 "=m"(*(unsigned short *) pmyoutDI), 104 "=m"(*(unsigned short *) pmyoutSI), 105 "=m"(*(unsigned short *) pusSmapiOK) 106 :"m"(inBXCX), "m"(inDISI), "m"(g_usSmapiPort) 107 :"%eax", "%ebx", "%ecx", "%edx", "%edi", 108 "%esi"); 109 110 PRINTK_8(TRACE_SMAPI, 111 "myoutAX %x myoutBX %x myoutCX %x myoutDX %x myoutDI %x myoutSI %x usSmapiOK %x\n", 112 myoutAX, myoutBX, myoutCX, myoutDX, myoutDI, myoutSI, 113 usSmapiOK); 114 *outAX = myoutAX; 115 *outBX = myoutBX; 116 *outCX = myoutCX; 117 *outDX = myoutDX; 118 *outDI = myoutDI; 119 *outSI = myoutSI; 120 121 retval = (usSmapiOK == 1) ? 0 : -EIO; 122 PRINTK_2(TRACE_SMAPI, "smapi::smapi_request exit retval %x\n", retval); 123 return retval; 124 } 125 126 127 int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings) 128 { 129 int bRC; 130 unsigned short usAX, usBX, usCX, usDX, usDI, usSI; 131 static const unsigned short ausDspBases[] = { 132 0x0030, 0x4E30, 0x8E30, 0xCE30, 133 0x0130, 0x0350, 0x0070, 0x0DB0 }; 134 static const unsigned short ausUartBases[] = { 135 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; 136 137 PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg entry\n"); 138 139 bRC = smapi_request(0x1802, 0x0000, 0, 0, 140 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 141 if (bRC) { 142 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Error: Could not get DSP Settings. Aborting.\n"); 143 return bRC; 144 } 145 146 PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg, smapi_request OK\n"); 147 148 pSettings->bDSPPresent = ((usBX & 0x0100) != 0); 149 pSettings->bDSPEnabled = ((usCX & 0x0001) != 0); 150 pSettings->usDspIRQ = usSI & 0x00FF; 151 pSettings->usDspDMA = (usSI & 0xFF00) >> 8; 152 if ((usDI & 0x00FF) < ARRAY_SIZE(ausDspBases)) { 153 pSettings->usDspBaseIO = ausDspBases[usDI & 0x00FF]; 154 } else { 155 pSettings->usDspBaseIO = 0; 156 } 157 PRINTK_6(TRACE_SMAPI, 158 "smapi::smapi_query_DSP_cfg get DSP Settings bDSPPresent %x bDSPEnabled %x usDspIRQ %x usDspDMA %x usDspBaseIO %x\n", 159 pSettings->bDSPPresent, pSettings->bDSPEnabled, 160 pSettings->usDspIRQ, pSettings->usDspDMA, 161 pSettings->usDspBaseIO); 162 163 /* check for illegal values */ 164 if ( pSettings->usDspBaseIO == 0 ) 165 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP base I/O address is 0\n"); 166 if ( pSettings->usDspIRQ == 0 ) 167 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP IRQ line is 0\n"); 168 169 bRC = smapi_request(0x1804, 0x0000, 0, 0, 170 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 171 if (bRC) { 172 PRINTK_ERROR("smapi::smapi_query_DSP_cfg: Error: Could not get DSP modem settings. Aborting.\n"); 173 return bRC; 174 } 175 176 PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg, smapi_request OK\n"); 177 178 pSettings->bModemEnabled = ((usCX & 0x0001) != 0); 179 pSettings->usUartIRQ = usSI & 0x000F; 180 if (((usSI & 0xFF00) >> 8) < ARRAY_SIZE(ausUartBases)) { 181 pSettings->usUartBaseIO = ausUartBases[(usSI & 0xFF00) >> 8]; 182 } else { 183 pSettings->usUartBaseIO = 0; 184 } 185 186 PRINTK_4(TRACE_SMAPI, 187 "smapi::smapi_query_DSP_cfg get DSP modem settings bModemEnabled %x usUartIRQ %x usUartBaseIO %x\n", 188 pSettings->bModemEnabled, 189 pSettings->usUartIRQ, 190 pSettings->usUartBaseIO); 191 192 /* check for illegal values */ 193 if ( pSettings->usUartBaseIO == 0 ) 194 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART base I/O address is 0\n"); 195 if ( pSettings->usUartIRQ == 0 ) 196 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART IRQ line is 0\n"); 197 198 PRINTK_2(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg exit bRC %x\n", bRC); 199 200 return bRC; 201 } 202 203 204 int smapi_set_DSP_cfg(void) 205 { 206 int bRC = -EIO; 207 int i; 208 unsigned short usAX, usBX, usCX, usDX, usDI, usSI; 209 static const unsigned short ausDspBases[] = { 210 0x0030, 0x4E30, 0x8E30, 0xCE30, 211 0x0130, 0x0350, 0x0070, 0x0DB0 }; 212 static const unsigned short ausUartBases[] = { 213 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; 214 static const unsigned short ausDspIrqs[] = { 215 5, 7, 10, 11, 15 }; 216 static const unsigned short ausUartIrqs[] = { 217 3, 4 }; 218 219 unsigned short dspio_index = 0, uartio_index = 0; 220 221 PRINTK_5(TRACE_SMAPI, 222 "smapi::smapi_set_DSP_cfg entry mwave_3780i_irq %x mwave_3780i_io %x mwave_uart_irq %x mwave_uart_io %x\n", 223 mwave_3780i_irq, mwave_3780i_io, mwave_uart_irq, mwave_uart_io); 224 225 if (mwave_3780i_io) { 226 for (i = 0; i < ARRAY_SIZE(ausDspBases); i++) { 227 if (mwave_3780i_io == ausDspBases[i]) 228 break; 229 } 230 if (i == ARRAY_SIZE(ausDspBases)) { 231 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_io address %x. Aborting.\n", mwave_3780i_io); 232 return bRC; 233 } 234 dspio_index = i; 235 } 236 237 if (mwave_3780i_irq) { 238 for (i = 0; i < ARRAY_SIZE(ausDspIrqs); i++) { 239 if (mwave_3780i_irq == ausDspIrqs[i]) 240 break; 241 } 242 if (i == ARRAY_SIZE(ausDspIrqs)) { 243 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_irq %x. Aborting.\n", mwave_3780i_irq); 244 return bRC; 245 } 246 } 247 248 if (mwave_uart_io) { 249 for (i = 0; i < ARRAY_SIZE(ausUartBases); i++) { 250 if (mwave_uart_io == ausUartBases[i]) 251 break; 252 } 253 if (i == ARRAY_SIZE(ausUartBases)) { 254 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_io address %x. Aborting.\n", mwave_uart_io); 255 return bRC; 256 } 257 uartio_index = i; 258 } 259 260 261 if (mwave_uart_irq) { 262 for (i = 0; i < ARRAY_SIZE(ausUartIrqs); i++) { 263 if (mwave_uart_irq == ausUartIrqs[i]) 264 break; 265 } 266 if (i == ARRAY_SIZE(ausUartIrqs)) { 267 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_irq %x. Aborting.\n", mwave_uart_irq); 268 return bRC; 269 } 270 } 271 272 if (mwave_uart_irq || mwave_uart_io) { 273 274 /* Check serial port A */ 275 bRC = smapi_request(0x1402, 0x0000, 0, 0, 276 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 277 if (bRC) goto exit_smapi_request_error; 278 /* bRC == 0 */ 279 if (usBX & 0x0100) { /* serial port A is present */ 280 if (usCX & 1) { /* serial port is enabled */ 281 if ((usSI & 0xFF) == mwave_uart_irq) { 282 PRINTK_ERROR(KERN_ERR_MWAVE 283 "smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq); 284 goto exit_conflict; 285 } else { 286 if ((usSI >> 8) == uartio_index) { 287 PRINTK_ERROR(KERN_ERR_MWAVE 288 "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]); 289 goto exit_conflict; 290 } 291 } 292 } 293 } 294 295 /* Check serial port B */ 296 bRC = smapi_request(0x1404, 0x0000, 0, 0, 297 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 298 if (bRC) goto exit_smapi_request_error; 299 /* bRC == 0 */ 300 if (usBX & 0x0100) { /* serial port B is present */ 301 if (usCX & 1) { /* serial port is enabled */ 302 if ((usSI & 0xFF) == mwave_uart_irq) { 303 PRINTK_ERROR(KERN_ERR_MWAVE 304 "smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq); 305 goto exit_conflict; 306 } else { 307 if ((usSI >> 8) == uartio_index) { 308 PRINTK_ERROR(KERN_ERR_MWAVE 309 "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]); 310 goto exit_conflict; 311 } 312 } 313 } 314 } 315 316 /* Check IR port */ 317 bRC = smapi_request(0x1700, 0x0000, 0, 0, 318 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 319 if (bRC) goto exit_smapi_request_error; 320 bRC = smapi_request(0x1704, 0x0000, 0, 0, 321 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 322 if (bRC) goto exit_smapi_request_error; 323 /* bRC == 0 */ 324 if ((usCX & 0xff) != 0xff) { /* IR port not disabled */ 325 if ((usCX & 0xff) == mwave_uart_irq) { 326 PRINTK_ERROR(KERN_ERR_MWAVE 327 "smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq); 328 goto exit_conflict; 329 } else { 330 if ((usSI & 0xff) == uartio_index) { 331 PRINTK_ERROR(KERN_ERR_MWAVE 332 "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]); 333 goto exit_conflict; 334 } 335 } 336 } 337 } 338 339 bRC = smapi_request(0x1802, 0x0000, 0, 0, 340 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 341 if (bRC) goto exit_smapi_request_error; 342 343 if (mwave_3780i_io) { 344 usDI = dspio_index; 345 } 346 if (mwave_3780i_irq) { 347 usSI = (usSI & 0xff00) | mwave_3780i_irq; 348 } 349 350 bRC = smapi_request(0x1803, 0x0101, usDI, usSI, 351 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 352 if (bRC) goto exit_smapi_request_error; 353 354 bRC = smapi_request(0x1804, 0x0000, 0, 0, 355 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 356 if (bRC) goto exit_smapi_request_error; 357 358 if (mwave_uart_io) { 359 usSI = (usSI & 0x00ff) | (uartio_index << 8); 360 } 361 if (mwave_uart_irq) { 362 usSI = (usSI & 0xff00) | mwave_uart_irq; 363 } 364 bRC = smapi_request(0x1805, 0x0101, 0, usSI, 365 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 366 if (bRC) goto exit_smapi_request_error; 367 368 bRC = smapi_request(0x1802, 0x0000, 0, 0, 369 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 370 if (bRC) goto exit_smapi_request_error; 371 372 bRC = smapi_request(0x1804, 0x0000, 0, 0, 373 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 374 if (bRC) goto exit_smapi_request_error; 375 376 /* normal exit: */ 377 PRINTK_1(TRACE_SMAPI, "smapi::smapi_set_DSP_cfg exit\n"); 378 return 0; 379 380 exit_conflict: 381 /* Message has already been printed */ 382 return -EIO; 383 384 exit_smapi_request_error: 385 PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg exit on smapi_request error bRC %x\n", bRC); 386 return bRC; 387 } 388 389 390 int smapi_set_DSP_power_state(bool bOn) 391 { 392 int bRC; 393 unsigned short usAX, usBX, usCX, usDX, usDI, usSI; 394 unsigned short usPowerFunction; 395 396 PRINTK_2(TRACE_SMAPI, "smapi::smapi_set_DSP_power_state entry bOn %x\n", bOn); 397 398 usPowerFunction = (bOn) ? 1 : 0; 399 400 bRC = smapi_request(0x4901, 0x0000, 0, usPowerFunction, 401 &usAX, &usBX, &usCX, &usDX, &usDI, &usSI); 402 403 PRINTK_2(TRACE_SMAPI, "smapi::smapi_set_DSP_power_state exit bRC %x\n", bRC); 404 405 return bRC; 406 } 407 408 int smapi_init(void) 409 { 410 int retval = -EIO; 411 unsigned short usSmapiID = 0; 412 unsigned long flags; 413 414 PRINTK_1(TRACE_SMAPI, "smapi::smapi_init entry\n"); 415 416 spin_lock_irqsave(&rtc_lock, flags); 417 usSmapiID = CMOS_READ(0x7C); 418 usSmapiID |= (CMOS_READ(0x7D) << 8); 419 spin_unlock_irqrestore(&rtc_lock, flags); 420 PRINTK_2(TRACE_SMAPI, "smapi::smapi_init usSmapiID %x\n", usSmapiID); 421 422 if (usSmapiID == 0x5349) { 423 spin_lock_irqsave(&rtc_lock, flags); 424 g_usSmapiPort = CMOS_READ(0x7E); 425 g_usSmapiPort |= (CMOS_READ(0x7F) << 8); 426 spin_unlock_irqrestore(&rtc_lock, flags); 427 if (g_usSmapiPort == 0) { 428 PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n"); 429 } else { 430 PRINTK_2(TRACE_SMAPI, 431 "smapi::smapi_init, exit true g_usSmapiPort %x\n", 432 g_usSmapiPort); 433 retval = 0; 434 //SmapiQuerySystemID(); 435 } 436 } else { 437 PRINTK_ERROR("smapi::smapi_init, ERROR invalid usSmapiID\n"); 438 retval = -ENXIO; 439 } 440 441 return retval; 442 } 443