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