Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/mwave/smapi.c
49231 views
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
406