dev_adb.cc Source File
Back to the index.
src
devices
dev_adb.cc
Go to the documentation of this file.
1
/*
2
* Copyright (C) 2005-2009 Anders Gavare. All rights reserved.
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
6
*
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
* 3. The name of the author may not be used to endorse or promote products
13
* derived from this software without specific prior written permission.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*
27
*
28
* COMMENT: Apple Desktop Bus (ADB) controller
29
*
30
* Based on intuition from reverse-engineering NetBSD/macppc source code,
31
* so it probably only works with that OS.
32
*
33
* The comment "OK" means that 100% of the functionality used by NetBSD/macppc
34
* is covered.
35
*
36
* TODO:
37
* o) Clean up, don't hardcode values.
38
* o) Convert into a separate controller, bus, device architecture.
39
*/
40
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <sys/time.h>
45
46
#include "
console.h
"
47
#include "
cpu.h
"
48
#include "
device.h
"
49
#include "
interrupt.h
"
50
#include "
machine.h
"
51
#include "
memory.h
"
52
#include "
misc.h
"
53
54
#include "
thirdparty/adb_viareg.h
"
55
56
57
#define debug fatal
58
/* #define ADB_DEBUG */
59
60
61
#define TICK_SHIFT 17
62
#define DEV_ADB_LENGTH 0x2000
63
64
#define N_VIA_REGS 0x10
65
#define VIA_REG_SHIFT 9
66
67
#define MAX_BUF 100
68
69
70
static
const
char
*via_regname[
N_VIA_REGS
] = {
71
"vBufB"
,
"vBufA"
,
"vDirB"
,
"vDirA"
,
72
"vT1C"
,
"vT1CH"
,
"vT1L"
,
"vT1LH"
,
73
"vT2C"
,
"vT2CH"
,
"vSR"
,
"vACR"
,
74
"vPCR"
,
"vIFR"
,
"vIER"
,
"(unknown)"
};
75
76
struct
adb_data
{
77
struct
interrupt
irq
;
78
int
int_asserted
;
79
80
int
kbd_dev
;
81
82
long
long
transfer_nr
;
83
84
uint8_t
reg
[
N_VIA_REGS
];
85
86
int
cur_output_offset
;
87
uint8_t
output_buf
[
MAX_BUF
];
88
89
int
cur_input_offset
;
90
int
cur_input_length
;
91
uint8_t
input_buf
[
MAX_BUF
];
92
93
int
dir
;
94
int
int_enable
;
95
int
ack
;
/* last ack state */
96
int
tip
;
/* transfer in progress */
97
};
98
99
#define DIR_INPUT 0
100
#define DIR_OUTPUT 1
101
102
#define BUFB_nINTR 0x08
103
#define BUFB_ACK 0x10
104
#define BUFB_nTIP 0x20
105
#define IFR_SR 0x04
106
#define IFR_ANY 0x80
107
#define ACR_SR_OUT 0x10
108
109
110
111
DEVICE_TICK
(adb)
112
{
113
struct
adb_data
*d = (
struct
adb_data
*) extra;
114
int
assert;
115
116
assert = d->
reg
[
vIFR
>>
VIA_REG_SHIFT
] &
IFR_ANY
;
117
if
(assert ==
IFR_ANY
&& d->
int_enable
)
118
assert = 1;
119
120
if
(assert)
121
INTERRUPT_ASSERT
(d->
irq
);
122
else
if
(d->
int_asserted
)
123
INTERRUPT_DEASSERT
(d->
irq
);
124
125
d->
int_asserted
= assert;
126
}
127
128
129
/*
130
* adb_reset():
131
*
132
* Reset registers to default values.
133
*/
134
static
void
adb_reset(
struct
adb_data
*d)
135
{
136
d->
kbd_dev
= 2;
137
138
memset(d->
reg
, 0,
sizeof
(d->
reg
));
139
d->
reg
[
vBufB
>>
VIA_REG_SHIFT
] =
BUFB_nINTR
|
BUFB_nTIP
;
140
141
d->
cur_output_offset
= 0;
142
memset(d->
output_buf
, 0,
sizeof
(d->
output_buf
));
143
144
d->
dir
= 0;
145
d->
int_enable
= 0;
146
d->
ack
= 0;
147
d->
tip
= 0;
148
}
149
150
151
/*
152
* adb_process_cmd():
153
*
154
* This function should be called whenever a complete ADB command has been
155
* received.
156
*/
157
static
void
adb_process_cmd(
struct
cpu
*
cpu
,
struct
adb_data
*d)
158
{
159
int
i,
reg
, dev;
160
161
debug
(
"[ adb: COMMAND:"
);
162
for
(i=0; i<d->
cur_output_offset
; i++)
163
debug
(
" %02x"
, d->
output_buf
[i]);
164
debug
(
" ]\n"
);
165
166
if
(d->
cur_output_offset
< 2) {
167
fatal
(
"[ adb: WEIRD output length: %i ]\n"
,
168
d->
cur_output_offset
);
169
exit(1);
170
}
171
172
switch
(d->
output_buf
[0]) {
173
174
case
0:
/* ADB commands: */
175
if
(d->
output_buf
[1] == 0x00) {
176
/* Reset. */
177
return
;
178
}
179
if
((d->
output_buf
[1] & 0x0c) == 0x0c) {
180
/* ADBTALK: */
181
reg
= d->
output_buf
[1] & 3;
182
dev = d->
output_buf
[1] >> 4;
183
fatal
(
"dev=%i reg=%i\n"
, dev,
reg
);
184
/* Default values: nothing here */
185
d->
input_buf
[0] = 0x00;
186
d->
input_buf
[1] = 0x00;
187
d->
input_buf
[2] = d->
output_buf
[1];
188
d->
cur_input_length
= 3;
189
if
(dev == d->
kbd_dev
) {
190
/* Keyboard. */
191
d->
input_buf
[0] = 0x01;
192
d->
input_buf
[1] = 0x01;
193
d->
input_buf
[2] = d->
output_buf
[1];
194
d->
input_buf
[3] = 0x01;
195
d->
input_buf
[4] = 0x01;
196
d->
cur_input_length
= 5;
197
}
198
}
else
if
((d->
output_buf
[1] & 0x0c) == 0x08) {
199
int
new_dev_pos = d->
output_buf
[2] & 15;
200
/* ADBLISTEN: */
201
if
((d->
output_buf
[1] >> 4) != d->
kbd_dev
) {
202
fatal
(
"[ adb: ADBLISTEN not to kbd ]\n"
);
203
exit(1);
204
}
205
if
(d->
output_buf
[3] != 0xfe ||
206
(d->
output_buf
[2] & 0xf0) != 0x60) {
207
fatal
(
"[ adb: unknown ADBLISTEN ]\n"
);
208
exit(1);
209
}
210
/* Move device. */
211
d->
kbd_dev
= new_dev_pos;
212
}
else
{
213
fatal
(
"[ adb: unknown ADB command? ]\n"
);
214
exit(1);
215
}
216
break
;
217
218
case
1:
/* PRAM/RTC: */
219
if
(d->
cur_output_offset
== 3 &&
220
d->
output_buf
[1] == 0x01 &&
221
d->
output_buf
[2] == 0x01) {
222
/* Autopoll: */
223
d->
input_buf
[0] = 0x00;
224
d->
input_buf
[1] = 0x00;
225
d->
input_buf
[2] = d->
output_buf
[1];
226
d->
cur_input_length
= 3;
227
}
else
if
(d->
cur_output_offset
== 2 &&
228
d->
output_buf
[1] == 0x03) {
229
/* Read RTC date/time: */
230
struct
timeval tv;
231
gettimeofday(&tv, NULL);
232
d->
input_buf
[0] = tv.tv_sec >> 24;
233
d->
input_buf
[1] = tv.tv_sec >> 16;
234
d->
input_buf
[2] = tv.tv_sec >> 8;
235
d->
input_buf
[3] = tv.tv_sec;
236
d->
cur_input_length
= 4;
237
}
else
if
(d->
cur_output_offset
== 2 &&
238
d->
output_buf
[1] == 0x11) {
239
/* Reboot. */
240
fatal
(
"[ adb: reboot. TODO: make this nicer ]\n"
);
241
exit(1);
242
}
else
{
243
fatal
(
"[ adb: UNIMPLEMENTED PRAM/RTC command ]\n"
);
244
exit(1);
245
}
246
break
;
247
248
default
:
fatal
(
"[ adb: UNKNOWN command type 0x%02x ]\n"
,
249
d->
output_buf
[0]);
250
exit(1);
251
}
252
253
d->
reg
[
vBufB
>>
VIA_REG_SHIFT
] &= ~
BUFB_nINTR
;
254
d->
reg
[
vIFR
>>
VIA_REG_SHIFT
] |=
IFR_ANY
|
IFR_SR
;
255
d->
reg
[
vSR
>>
VIA_REG_SHIFT
] = 0x00;
/* Dummy. */
256
}
257
258
259
/*
260
* adb_transfer():
261
*
262
* This function should be called whenever a new transfer is started, a
263
* transfer is finished, or when the next byte in a transfer should be
264
* sent/received.
265
*/
266
static
void
adb_transfer(
struct
cpu
*
cpu
,
struct
adb_data
*d,
int
state_change)
267
{
268
unsigned
char
c = 0x00;
269
270
if
(state_change) {
271
if
(d->
tip
== 0) {
272
debug
(
"[ adb: transfer #%lli done ]\n"
,
273
(
long
long
)d->
transfer_nr
);
274
if
(d->
cur_output_offset
> 0)
275
adb_process_cmd(
cpu
, d);
276
d->
transfer_nr
++;
277
return
;
278
}
279
debug
(
"[ adb: starting transfer #%lli: %s ]\n"
, (
long
long
)
280
d->
transfer_nr
, d->
dir
==
DIR_INPUT
?
"INPUT"
:
"OUTPUT"
);
281
d->
cur_input_offset
= d->
cur_output_offset
= 0;
282
}
283
284
debug
(
"[ adb: transfer #%lli: "
, (
long
long
)d->
transfer_nr
);
285
286
switch
(d->
dir
) {
287
288
case
DIR_INPUT
:
289
if
(d->
cur_input_offset
>= d->
cur_input_length
)
290
fatal
(
"[ adb: INPUT beyond end of data? ]\n"
);
291
else
292
c = d->
input_buf
[d->
cur_input_offset
++];
293
debug
(
"input 0x%02x"
, c);
294
d->
reg
[
vSR
>>
VIA_REG_SHIFT
] = c;
295
d->
reg
[
vIFR
>>
VIA_REG_SHIFT
] |=
IFR_ANY
|
IFR_SR
;
296
if
(d->
cur_input_offset
>= d->
cur_input_length
)
297
d->
reg
[
vBufB
>>
VIA_REG_SHIFT
] |=
BUFB_nINTR
;
298
break
;
299
300
case
DIR_OUTPUT
:
301
c = d->
reg
[
vSR
>>
VIA_REG_SHIFT
];
302
debug
(
"output 0x%02x"
, c);
303
d->
reg
[
vIFR
>>
VIA_REG_SHIFT
] |=
IFR_ANY
|
IFR_SR
;
304
d->
reg
[
vBufB
>>
VIA_REG_SHIFT
] |=
BUFB_nINTR
;
305
d->
output_buf
[d->
cur_output_offset
++] = c;
306
break
;
307
}
308
309
debug
(
" ]\n"
);
310
}
311
312
313
DEVICE_ACCESS
(adb)
314
{
315
uint64_t idata = 0, odata = 0;
316
struct
adb_data
*d = (
struct
adb_data
*) extra;
317
// uint8_t old = 0;
318
319
if
(writeflag ==
MEM_WRITE
)
320
idata =
memory_readmax64
(
cpu
,
data
, len);
321
322
#ifdef ADB_DEBUG
323
if
((relative_addr & ((1 <<
VIA_REG_SHIFT
) - 1)) != 0)
324
fatal
(
"[ adb: %s non-via register? offset 0x%x ]\n"
,
325
writeflag ==
MEM_READ
?
"read from"
:
"write to"
,
326
(
int
)relative_addr);
327
else
if
(writeflag ==
MEM_READ
)
328
fatal
(
"[ adb: read from %s: 0x%02x ]\n"
,
329
via_regname[relative_addr >>
VIA_REG_SHIFT
],
330
(
int
)d->
reg
[relative_addr >>
VIA_REG_SHIFT
]);
331
else
332
fatal
(
"[ adb: write to %s: 0x%02x ]\n"
, via_regname[
333
relative_addr >>
VIA_REG_SHIFT
], (
int
)idata);
334
#endif
335
336
if
(writeflag ==
MEM_READ
)
337
odata = d->
reg
[relative_addr >>
VIA_REG_SHIFT
];
338
else
{
339
// old = d->reg[relative_addr >> VIA_REG_SHIFT];
340
switch
(relative_addr) {
341
case
vIFR
:
342
/*
343
* vIFR is write-ones-to-clear, and the highest bit
344
* (IFR_ANY) is set if any of the lower bits are set.
345
*/
346
d->
reg
[relative_addr >>
VIA_REG_SHIFT
] &= ~(idata|0x80);
347
if
(d->
reg
[relative_addr >>
VIA_REG_SHIFT
] & 0x7f)
348
d->
reg
[relative_addr >>
VIA_REG_SHIFT
] |= 0x80;
349
break
;
350
default
:
351
d->
reg
[relative_addr >>
VIA_REG_SHIFT
] = idata;
352
}
353
}
354
355
switch
(relative_addr) {
356
357
case
vBufB
:
358
/* OK */
359
if
(writeflag ==
MEM_WRITE
) {
360
int
old_tip = d->
tip
;
361
int
old_ack = d->
ack
;
362
if
(idata &
BUFB_nINTR
)
363
idata &= ~
BUFB_nINTR
;
364
d->
ack
= 0;
365
if
(idata &
BUFB_ACK
) {
366
idata &= ~
BUFB_ACK
;
367
d->
ack
= 1;
368
}
369
d->
tip
= 1;
370
if
(idata &
BUFB_nTIP
) {
371
idata &= ~
BUFB_nTIP
;
372
d->
tip
= 0;
373
}
374
if
(idata != 0)
375
fatal
(
"[ adb: WARNING! UNIMPLEMENTED bits in"
376
" vBufB: 0x%02x ]\n"
, (
int
)idata);
377
if
(old_tip != d->
tip
)
378
adb_transfer(
cpu
, d, 1);
379
else
if
(old_ack != d->
ack
)
380
adb_transfer(
cpu
, d, 0);
381
}
382
break
;
383
384
case
vDirB
:
385
break
;
386
387
case
vSR
:
388
/* Clear the SR interrupt flag, if set: */
389
d->
reg
[
vIFR
>>
VIA_REG_SHIFT
] &= ~
IFR_SR
;
390
break
;
391
392
case
vACR
:
393
/* OK */
394
if
(writeflag ==
MEM_WRITE
) {
395
if
(idata &
ACR_SR_OUT
)
396
d->
dir
=
DIR_OUTPUT
;
397
else
398
d->
dir
=
DIR_INPUT
;
399
}
400
break
;
401
402
case
vIFR
:
403
/* OK */
404
break
;
405
406
case
vIER
:
407
/* OK */
408
if
(writeflag ==
MEM_WRITE
) {
409
d->
int_enable
= idata & 0x80? 1 : 0;
410
if
(idata != 0x04 && idata != 0x84)
411
fatal
(
"[ adb: WARNING! vIER value 0x%x is"
412
" UNKNOWN ]\n"
, (
int
)idata);
413
}
414
break
;
415
416
default
:
if
((relative_addr & ((1 <<
VIA_REG_SHIFT
) - 1)) != 0)
417
fatal
(
"[ adb: %s non-via register? offset 0x%x ]\n"
,
418
writeflag ==
MEM_READ
?
"read from"
:
"write to"
,
419
(
int
)relative_addr);
420
else
if
(writeflag ==
MEM_READ
)
421
fatal
(
"[ adb: READ from UNIMPLEMENTED %s ]\n"
,
422
via_regname[relative_addr >>
VIA_REG_SHIFT
]);
423
else
424
fatal
(
"[ adb: WRITE to UNIMPLEMENTED %s: 0x%x ]\n"
,
425
via_regname[relative_addr >>
VIA_REG_SHIFT
],
426
(
int
)idata);
427
exit(1);
428
}
429
430
if
(writeflag ==
MEM_READ
)
431
memory_writemax64
(
cpu
,
data
, len, odata);
432
433
return
1;
434
}
435
436
437
DEVINIT
(adb)
438
{
439
struct
adb_data
*d;
440
441
CHECK_ALLOCATION
(d = (
struct
adb_data
*) malloc(
sizeof
(
struct
adb_data
)));
442
memset(d, 0,
sizeof
(
struct
adb_data
));
443
444
INTERRUPT_CONNECT
(
devinit
->
interrupt_path
, d->
irq
);
445
446
adb_reset(d);
447
448
memory_device_register
(
devinit
->
machine
->
memory
,
devinit
->
name
,
449
devinit
->
addr
,
DEV_ADB_LENGTH
, dev_adb_access, d,
DM_DEFAULT
, NULL);
450
machine_add_tickfunction
(
devinit
->
machine
, dev_adb_tick, d,
451
TICK_SHIFT
);
452
453
return
1;
454
}
455
adb_data::irq
struct interrupt irq
Definition:
dev_adb.cc:77
data
u_short data
Definition:
siireg.h:79
INTERRUPT_CONNECT
#define INTERRUPT_CONNECT(name, istruct)
Definition:
interrupt.h:77
adb_data::cur_output_offset
int cur_output_offset
Definition:
dev_adb.cc:86
adb_data::cur_input_offset
int cur_input_offset
Definition:
dev_adb.cc:89
BUFB_nTIP
#define BUFB_nTIP
Definition:
dev_adb.cc:104
INTERRUPT_ASSERT
#define INTERRUPT_ASSERT(istruct)
Definition:
interrupt.h:74
ACR_SR_OUT
#define ACR_SR_OUT
Definition:
dev_adb.cc:107
debug
#define debug
Definition:
dev_adb.cc:57
vIER
#define vIER
Definition:
adb_viareg.h:172
adb_data::reg
uint8_t reg[N_VIA_REGS]
Definition:
dev_adb.cc:84
adb_data::int_enable
int int_enable
Definition:
dev_adb.cc:94
adb_data
Definition:
dev_adb.cc:76
devinit::addr
uint64_t addr
Definition:
device.h:46
memory_device_register
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition:
memory.cc:339
adb_viareg.h
adb_data::input_buf
uint8_t input_buf[MAX_BUF]
Definition:
dev_adb.cc:91
MEM_READ
#define MEM_READ
Definition:
memory.h:116
DM_DEFAULT
#define DM_DEFAULT
Definition:
memory.h:130
devinit::machine
struct machine * machine
Definition:
device.h:41
console.h
device.h
vIFR
#define vIFR
Definition:
adb_viareg.h:171
vDirB
#define vDirB
Definition:
adb_viareg.h:160
MEM_WRITE
#define MEM_WRITE
Definition:
memory.h:117
IFR_SR
#define IFR_SR
Definition:
dev_adb.cc:105
vACR
#define vACR
Definition:
adb_viareg.h:169
adb_data::cur_input_length
int cur_input_length
Definition:
dev_adb.cc:90
machine_add_tickfunction
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition:
machine.cc:280
MAX_BUF
#define MAX_BUF
Definition:
dev_adb.cc:67
devinit::interrupt_path
char * interrupt_path
Definition:
device.h:50
BUFB_ACK
#define BUFB_ACK
Definition:
dev_adb.cc:103
adb_data::kbd_dev
int kbd_dev
Definition:
dev_adb.cc:80
interrupt.h
fatal
void fatal(const char *fmt,...)
Definition:
main.cc:152
N_VIA_REGS
#define N_VIA_REGS
Definition:
dev_adb.cc:64
TICK_SHIFT
#define TICK_SHIFT
Definition:
dev_adb.cc:61
adb_data::ack
int ack
Definition:
dev_adb.cc:95
misc.h
adb_data::transfer_nr
long long transfer_nr
Definition:
dev_adb.cc:82
memory_readmax64
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition:
memory.cc:55
machine.h
adb_data::dir
int dir
Definition:
dev_adb.cc:93
IFR_ANY
#define IFR_ANY
Definition:
dev_adb.cc:106
devinit::name
char * name
Definition:
device.h:43
devinit
Definition:
device.h:40
cpu.h
DEVICE_ACCESS
DEVICE_ACCESS(adb)
Definition:
dev_adb.cc:313
adb_data::output_buf
uint8_t output_buf[MAX_BUF]
Definition:
dev_adb.cc:87
machine::memory
struct memory * memory
Definition:
machine.h:126
reg
#define reg(x)
Definition:
tmp_alpha_tail.cc:53
vBufB
#define vBufB
Definition:
adb_viareg.h:158
BUFB_nINTR
#define BUFB_nINTR
Definition:
dev_adb.cc:102
DEVICE_TICK
DEVICE_TICK(adb)
Definition:
dev_adb.cc:111
INTERRUPT_DEASSERT
#define INTERRUPT_DEASSERT(istruct)
Definition:
interrupt.h:75
vSR
#define vSR
Definition:
adb_viareg.h:168
adb_data::tip
int tip
Definition:
dev_adb.cc:96
VIA_REG_SHIFT
#define VIA_REG_SHIFT
Definition:
dev_adb.cc:65
DIR_OUTPUT
#define DIR_OUTPUT
Definition:
dev_adb.cc:100
interrupt
Definition:
interrupt.h:36
DIR_INPUT
#define DIR_INPUT
Definition:
dev_adb.cc:99
memory_writemax64
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition:
memory.cc:89
cpu
Definition:
cpu.h:326
adb_data::int_asserted
int int_asserted
Definition:
dev_adb.cc:78
DEVINIT
DEVINIT(adb)
Definition:
dev_adb.cc:437
memory.h
DEV_ADB_LENGTH
#define DEV_ADB_LENGTH
Definition:
dev_adb.cc:62
CHECK_ALLOCATION
#define CHECK_ALLOCATION(ptr)
Definition:
misc.h:239
Generated on Tue Mar 24 2020 14:04:48 for GXemul by
1.8.17