1 |
/* |
2 |
* Copyright (C) 2003-2007 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 |
* $Id: dev_bt459.c,v 1.67 2006/12/30 13:30:57 debug Exp $ |
29 |
* |
30 |
* Brooktree 459 vdac, used by TURBOchannel graphics cards. |
31 |
*/ |
32 |
|
33 |
#include <stdio.h> |
34 |
#include <stdlib.h> |
35 |
#include <string.h> |
36 |
|
37 |
#include "cpu.h" |
38 |
#include "devices.h" |
39 |
#include "machine.h" |
40 |
#include "memory.h" |
41 |
#include "misc.h" |
42 |
#include "x11.h" |
43 |
|
44 |
#include "bt459.h" |
45 |
|
46 |
|
47 |
#ifdef WITH_X11 |
48 |
#include <X11/Xlib.h> |
49 |
#include <X11/Xutil.h> |
50 |
#endif |
51 |
|
52 |
extern int quiet_mode; |
53 |
|
54 |
|
55 |
/* #define BT459_DEBUG */ |
56 |
/* #define WITH_CURSOR_DEBUG */ |
57 |
#define BT459_TICK_SHIFT 14 |
58 |
|
59 |
struct bt459_data { |
60 |
uint32_t bt459_reg[DEV_BT459_NREGS]; |
61 |
|
62 |
unsigned char cur_addr_hi; |
63 |
unsigned char cur_addr_lo; |
64 |
|
65 |
int planes; |
66 |
int type; |
67 |
|
68 |
struct interrupt irq; |
69 |
int interrupts_enable; |
70 |
int interrupt_time; |
71 |
int interrupt_time_reset_value; |
72 |
|
73 |
int cursor_x_add; |
74 |
int cursor_y_add; |
75 |
|
76 |
int need_to_redraw_whole_screen; |
77 |
|
78 |
int need_to_update_cursor_shape; |
79 |
int cursor_on; |
80 |
int cursor_x; |
81 |
int cursor_y; |
82 |
int cursor_xsize; |
83 |
int cursor_ysize; |
84 |
|
85 |
int palette_sub_offset; /* 0, 1, or 2 */ |
86 |
|
87 |
struct vfb_data *vfb_data; |
88 |
|
89 |
/* |
90 |
* There is one pointer to the framebuffer's RGB palette, |
91 |
* and then a local copy of the palette. 256 * 3 bytes (r,g,b). |
92 |
* The reason for this is that when we need to blank the screen |
93 |
* (ie video_on = 0), we can set the framebuffer's palette to all |
94 |
* zeroes, but keep our own copy intact, to be reused later again |
95 |
* when the screen is unblanked. |
96 |
*/ |
97 |
int video_on; |
98 |
unsigned char *rgb_palette; /* 256 * 3 (r,g,b) */ |
99 |
unsigned char local_rgb_palette[256 * 3]; |
100 |
}; |
101 |
|
102 |
|
103 |
/* |
104 |
* bt459_update_X_cursor(): |
105 |
* |
106 |
* This routine takes the color values in the cursor RAM area, and put them |
107 |
* in the framebuffer window's cursor_pixels. |
108 |
* |
109 |
* d->cursor_xsize and ysize are also updated. |
110 |
*/ |
111 |
static void bt459_update_X_cursor(struct cpu *cpu, struct bt459_data *d) |
112 |
{ |
113 |
int i, x,y, xmax=0, ymax=0; |
114 |
int bw_only = 1; |
115 |
|
116 |
/* First, let's calculate the size of the cursor: */ |
117 |
for (y=0; y<64; y++) |
118 |
for (x=0; x<64; x+=4) { |
119 |
int reg = BT459_REG_CRAM_BASE + y*16 + x/4; |
120 |
unsigned char data = d->bt459_reg[reg]; |
121 |
|
122 |
if (data) |
123 |
ymax = y; |
124 |
|
125 |
for (i=0; i<4; i++) { |
126 |
int color = (data >> (6-2*i)) & 3; |
127 |
if (color != 0) |
128 |
xmax = x + i; |
129 |
if (color != 0 && color != 3) |
130 |
bw_only = 0; |
131 |
} |
132 |
} |
133 |
|
134 |
d->cursor_xsize = xmax + 1; |
135 |
d->cursor_ysize = ymax + 1; |
136 |
|
137 |
/* |
138 |
* The 'bw_only' hack is because it is nicer to have the b/w |
139 |
* text cursor invert whatever it is standing on, not just overwrite |
140 |
* it with a big white box. |
141 |
* |
142 |
* The following seems to work with NetBSD/OpenBSD/Ultrix/Sprite: |
143 |
* 0 = transparent, 1 and 2 = use the color specified by |
144 |
* BT459_REG_CCOLOR_2, 3 = reverse of color 1/2. |
145 |
*/ |
146 |
|
147 |
#ifdef WITH_X11 |
148 |
if (cpu->machine->use_x11 && d->vfb_data->fb_window != NULL) { |
149 |
for (y=0; y<=ymax; y++) { |
150 |
for (x=0; x<=xmax; x+=4) { |
151 |
struct fb_window *win = d->vfb_data->fb_window; |
152 |
int reg = BT459_REG_CRAM_BASE + y*16 + x/4; |
153 |
unsigned char data = d->bt459_reg[reg]; |
154 |
|
155 |
for (i=0; i<4; i++) { |
156 |
int color = (data >> (6-2*i)) & 3; |
157 |
int pixelvalue; |
158 |
|
159 |
if (bw_only) { |
160 |
if (color) |
161 |
pixelvalue = |
162 |
CURSOR_COLOR_INVERT; |
163 |
else |
164 |
pixelvalue = 0; |
165 |
} else { |
166 |
pixelvalue = |
167 |
CURSOR_COLOR_TRANSPARENT; |
168 |
switch (color) { |
169 |
case 1: |
170 |
case 2: pixelvalue = (d-> |
171 |
bt459_reg[ |
172 |
BT459_REG_CCOLOR_2] |
173 |
>> 4) & 0xf; |
174 |
break; |
175 |
case 3: pixelvalue = 15 - |
176 |
((d->bt459_reg[ |
177 |
BT459_REG_CCOLOR_2] |
178 |
>> 4) & 0xf); |
179 |
break; |
180 |
} |
181 |
} |
182 |
|
183 |
win->cursor_pixels[y][x+i] = |
184 |
pixelvalue; |
185 |
#ifdef WITH_CURSOR_DEBUG |
186 |
printf("%i", color); |
187 |
#endif |
188 |
} |
189 |
} |
190 |
#ifdef WITH_CURSOR_DEBUG |
191 |
printf("\n"); |
192 |
#endif |
193 |
} |
194 |
#ifdef WITH_CURSOR_DEBUG |
195 |
printf("color 1,2,3 = 0x%02x, 0x%02x, 0x%02x\n", |
196 |
d->bt459_reg[BT459_REG_CCOLOR_1], |
197 |
d->bt459_reg[BT459_REG_CCOLOR_2], |
198 |
d->bt459_reg[BT459_REG_CCOLOR_3]); |
199 |
printf("\n"); |
200 |
#endif |
201 |
/* |
202 |
* Make sure the cursor is redrawn, if it is on: |
203 |
* |
204 |
* How does this work? Well, 0 is off, and non-zero is on, |
205 |
* but if the old and new differ, the cursor is redrawn. |
206 |
* (Hopefully this will "never" overflow.) |
207 |
*/ |
208 |
if (d->cursor_on) |
209 |
d->cursor_on ++; |
210 |
} |
211 |
#endif |
212 |
} |
213 |
|
214 |
|
215 |
/* |
216 |
* bt459_update_cursor_position(): |
217 |
*/ |
218 |
static void bt459_update_cursor_position(struct bt459_data *d, |
219 |
int old_cursor_on) |
220 |
{ |
221 |
int new_cursor_x = (d->bt459_reg[BT459_REG_CXLO] & 255) + |
222 |
((d->bt459_reg[BT459_REG_CXHI] & 255) << 8) - d->cursor_x_add; |
223 |
int new_cursor_y = (d->bt459_reg[BT459_REG_CYLO] & 255) + |
224 |
((d->bt459_reg[BT459_REG_CYHI] & 255) << 8) - d->cursor_y_add; |
225 |
|
226 |
if (new_cursor_x != d->cursor_x || new_cursor_y != d->cursor_y || |
227 |
d->cursor_on != old_cursor_on) { |
228 |
int on; |
229 |
|
230 |
d->cursor_x = new_cursor_x; |
231 |
d->cursor_y = new_cursor_y; |
232 |
|
233 |
if (!quiet_mode) |
234 |
debug("[ bt459: cursor = %03i,%03i ]\n", |
235 |
d->cursor_x, d->cursor_y); |
236 |
|
237 |
on = d->cursor_on; |
238 |
if (d->cursor_xsize == 0 || d->cursor_ysize == 0) |
239 |
on = 0; |
240 |
|
241 |
dev_fb_setcursor(d->vfb_data, d->cursor_x, d->cursor_y, |
242 |
on, d->cursor_xsize, d->cursor_ysize); |
243 |
} |
244 |
} |
245 |
|
246 |
|
247 |
DEVICE_TICK(bt459) |
248 |
{ |
249 |
struct bt459_data *d = extra; |
250 |
int old_cursor_on = d->cursor_on; |
251 |
|
252 |
if (d->need_to_update_cursor_shape) { |
253 |
d->need_to_update_cursor_shape = 0; |
254 |
bt459_update_X_cursor(cpu, d); |
255 |
bt459_update_cursor_position(d, old_cursor_on); |
256 |
} |
257 |
|
258 |
if (d->need_to_redraw_whole_screen) { |
259 |
d->vfb_data->update_x1 = 0; |
260 |
d->vfb_data->update_x2 = d->vfb_data->xsize - 1; |
261 |
d->vfb_data->update_y1 = 0; |
262 |
d->vfb_data->update_y2 = d->vfb_data->ysize - 1; |
263 |
d->need_to_redraw_whole_screen = 0; |
264 |
} |
265 |
|
266 |
/* |
267 |
* Vertical retrace interrupts. (This hack is kind of ugly.) |
268 |
* Once every 'interrupt_time_reset_value', the interrupt is |
269 |
* asserted. It is acked either manually (by someone reading |
270 |
* a normal BT459 register or the Interrupt ack register), |
271 |
* or after another tick has passed. (This is to prevent |
272 |
* lockups from unhandled interrupts.) |
273 |
*/ |
274 |
if (d->type != BT459_PX && d->interrupts_enable) { |
275 |
d->interrupt_time --; |
276 |
if (d->interrupt_time < 0) { |
277 |
d->interrupt_time = d->interrupt_time_reset_value; |
278 |
INTERRUPT_ASSERT(d->irq); |
279 |
} else |
280 |
INTERRUPT_DEASSERT(d->irq); |
281 |
} |
282 |
} |
283 |
|
284 |
|
285 |
DEVICE_ACCESS(bt459_irq) |
286 |
{ |
287 |
struct bt459_data *d = (struct bt459_data *) extra; |
288 |
uint64_t idata = 0, odata = 0; |
289 |
|
290 |
if (writeflag == MEM_WRITE) |
291 |
idata = memory_readmax64(cpu, data, len); |
292 |
|
293 |
#ifdef BT459_DEBUG |
294 |
fatal("[ bt459: IRQ ack ]\n"); |
295 |
#endif |
296 |
|
297 |
d->interrupts_enable = 1; |
298 |
|
299 |
INTERRUPT_DEASSERT(d->irq); |
300 |
|
301 |
if (writeflag == MEM_READ) |
302 |
memory_writemax64(cpu, data, len, odata); |
303 |
|
304 |
return 1; |
305 |
} |
306 |
|
307 |
|
308 |
/* |
309 |
* dev_bt459_access(): |
310 |
*/ |
311 |
DEVICE_ACCESS(bt459) |
312 |
{ |
313 |
struct bt459_data *d = (struct bt459_data *) extra; |
314 |
uint64_t idata = 0, odata = 0; |
315 |
int btaddr, old_cursor_on = d->cursor_on, modified; |
316 |
|
317 |
idata = memory_readmax64(cpu, data, len); |
318 |
|
319 |
#ifdef BT459_DEBUG |
320 |
if (writeflag == MEM_WRITE) |
321 |
fatal("[ bt459: write to addr 0x%02x: %08x ]\n", |
322 |
(int)relative_addr, (int)idata); |
323 |
#endif |
324 |
|
325 |
/* |
326 |
* Vertical retrace interrupts are acked either by |
327 |
* accessing a normal BT459 register, or the irq register, |
328 |
* or by simply "missing" it. |
329 |
*/ |
330 |
INTERRUPT_DEASSERT(d->irq); |
331 |
|
332 |
/* ID register is read-only, should always be 0x4a or 0x4a4a4a: */ |
333 |
if (d->planes == 24) |
334 |
d->bt459_reg[BT459_REG_ID] = 0x4a4a4a; |
335 |
else { |
336 |
/* |
337 |
* TODO: Is it really 0x4a, or 0x4a0000? |
338 |
* Ultrix panics with a "bad VDAC ID" message if 0x4a |
339 |
* is returned. |
340 |
*/ |
341 |
d->bt459_reg[BT459_REG_ID] = 0x4a0000; |
342 |
} |
343 |
|
344 |
btaddr = ((d->cur_addr_hi << 8) + d->cur_addr_lo) % DEV_BT459_NREGS; |
345 |
|
346 |
/* Read from/write to the bt459: */ |
347 |
switch (relative_addr) { |
348 |
case 0x00: /* Low byte of address: */ |
349 |
if (writeflag == MEM_WRITE) { |
350 |
if (!quiet_mode) |
351 |
debug("[ bt459: write to Low Address Byte, " |
352 |
"0x%02x ]\n", (int)idata); |
353 |
d->cur_addr_lo = idata; |
354 |
d->palette_sub_offset = 0; |
355 |
} else { |
356 |
odata = d->cur_addr_lo; |
357 |
if (!quiet_mode) |
358 |
debug("[ bt459: read from Low Address Byte: " |
359 |
"0x%0x ]\n", (int)odata); |
360 |
} |
361 |
break; |
362 |
case 0x04: /* High byte of address: */ |
363 |
if (writeflag == MEM_WRITE) { |
364 |
if (!quiet_mode) |
365 |
debug("[ bt459: write to High Address Byte, " |
366 |
"0x%02x ]\n", (int)idata); |
367 |
d->cur_addr_hi = idata; |
368 |
d->palette_sub_offset = 0; |
369 |
} else { |
370 |
odata = d->cur_addr_hi; |
371 |
if (!quiet_mode) |
372 |
debug("[ bt459: read from High Address Byte: " |
373 |
"0x%0x ]\n", (int)odata); |
374 |
} |
375 |
break; |
376 |
case 0x08: /* Register access: */ |
377 |
if (writeflag == MEM_WRITE) { |
378 |
if (!quiet_mode) |
379 |
debug("[ bt459: write to BT459 register " |
380 |
"0x%04x, value 0x%02x ]\n", btaddr, |
381 |
(int)idata); |
382 |
modified = (d->bt459_reg[btaddr] != idata); |
383 |
d->bt459_reg[btaddr] = idata; |
384 |
|
385 |
switch (btaddr) { |
386 |
case BT459_REG_CCOLOR_1: |
387 |
case BT459_REG_CCOLOR_2: |
388 |
case BT459_REG_CCOLOR_3: |
389 |
if (modified) |
390 |
d->need_to_update_cursor_shape = 1; |
391 |
break; |
392 |
case BT459_REG_PRM: |
393 |
/* |
394 |
* NetBSD writes 0x00 to this register to |
395 |
* blank the screen (video off), and 0xff |
396 |
* to turn the screen on. |
397 |
*/ |
398 |
switch (idata & 0xff) { |
399 |
case 0: d->video_on = 0; |
400 |
memset(d->rgb_palette, 0, 256*3); |
401 |
d->need_to_redraw_whole_screen = 1; |
402 |
debug("[ bt459: video OFF ]\n"); |
403 |
break; |
404 |
default:d->video_on = 1; |
405 |
memcpy(d->rgb_palette, |
406 |
d->local_rgb_palette, 256*3); |
407 |
d->need_to_redraw_whole_screen = 1; |
408 |
debug("[ bt459: video ON ]\n"); |
409 |
} |
410 |
break; |
411 |
case BT459_REG_CCR: |
412 |
/* Cursor control register: */ |
413 |
switch (idata & 0xff) { |
414 |
case 0x00: d->cursor_on = 0; break; |
415 |
case 0xc0: |
416 |
case 0xc1: d->cursor_on = 1; break; |
417 |
default: |
418 |
fatal("[ bt459: unimplemented CCR " |
419 |
"value 0x%08x ]\n", (int)idata); |
420 |
} |
421 |
if (modified) |
422 |
d->need_to_update_cursor_shape = 1; |
423 |
break; |
424 |
default: |
425 |
if (btaddr < 0x100) |
426 |
fatal("[ bt459: write to BT459 " |
427 |
"register 0x%04x, value 0x%02x ]\n", |
428 |
btaddr, (int)idata); |
429 |
} |
430 |
|
431 |
/* Write to cursor bitmap: */ |
432 |
if (btaddr >= BT459_REG_CRAM_BASE && modified) |
433 |
d->need_to_update_cursor_shape = 1; |
434 |
} else { |
435 |
odata = d->bt459_reg[btaddr]; |
436 |
|
437 |
/* Perhaps this hack is not necessary: */ |
438 |
if (btaddr == BT459_REG_ID && len==1) |
439 |
odata = (odata >> 16) & 255; |
440 |
|
441 |
if (!quiet_mode) |
442 |
debug("[ bt459: read from BT459 register " |
443 |
"0x%04x, value 0x%02x ]\n", btaddr, |
444 |
(int)odata); |
445 |
} |
446 |
|
447 |
/* Go to next register: */ |
448 |
d->cur_addr_lo ++; |
449 |
if (d->cur_addr_lo == 0) |
450 |
d->cur_addr_hi ++; |
451 |
break; |
452 |
case 0xc: /* Color map: */ |
453 |
if (writeflag == MEM_WRITE) { |
454 |
idata &= 255; |
455 |
if (!quiet_mode) |
456 |
debug("[ bt459: write to BT459 colormap " |
457 |
"0x%04x subaddr %i, value 0x%02x ]\n", |
458 |
btaddr, d->palette_sub_offset, (int)idata); |
459 |
|
460 |
if (btaddr < 0x100) { |
461 |
if (d->video_on && |
462 |
d->local_rgb_palette[(btaddr & 0xff) * 3 |
463 |
+ d->palette_sub_offset] != idata) |
464 |
d->need_to_redraw_whole_screen = 1; |
465 |
|
466 |
/* |
467 |
* Actually, the palette should only be |
468 |
* updated after the third write, |
469 |
* but this should probably work fine too: |
470 |
*/ |
471 |
d->local_rgb_palette[(btaddr & 0xff) * 3 |
472 |
+ d->palette_sub_offset] = idata; |
473 |
|
474 |
if (d->video_on) |
475 |
d->rgb_palette[(btaddr & 0xff) * 3 |
476 |
+ d->palette_sub_offset] = idata; |
477 |
} |
478 |
} else { |
479 |
if (btaddr < 0x100) |
480 |
odata = d->local_rgb_palette[(btaddr & 0xff) |
481 |
* 3 + d->palette_sub_offset]; |
482 |
if (!quiet_mode) |
483 |
debug("[ bt459: read from BT459 colormap " |
484 |
"0x%04x subaddr %i, value 0x%02x ]\n", |
485 |
btaddr, d->palette_sub_offset, (int)odata); |
486 |
} |
487 |
|
488 |
d->palette_sub_offset ++; |
489 |
if (d->palette_sub_offset >= 3) { |
490 |
d->palette_sub_offset = 0; |
491 |
|
492 |
d->cur_addr_lo ++; |
493 |
if (d->cur_addr_lo == 0) |
494 |
d->cur_addr_hi ++; |
495 |
} |
496 |
|
497 |
break; |
498 |
default: |
499 |
if (writeflag == MEM_WRITE) { |
500 |
debug("[ bt459: unimplemented write to address 0x%x, " |
501 |
"data=0x%02x ]\n", (int)relative_addr, (int)idata); |
502 |
} else { |
503 |
debug("[ bt459: unimplemented read from address " |
504 |
"0x%x ]\n", (int)relative_addr); |
505 |
} |
506 |
} |
507 |
|
508 |
|
509 |
bt459_update_cursor_position(d, old_cursor_on); |
510 |
|
511 |
if (writeflag == MEM_READ) |
512 |
memory_writemax64(cpu, data, len, odata); |
513 |
|
514 |
#ifdef BT459_DEBUG |
515 |
if (writeflag == MEM_READ) |
516 |
fatal("[ bt459: read from addr 0x%02x: %08x ]\n", |
517 |
(int)relative_addr, (int)idata); |
518 |
#endif |
519 |
|
520 |
return 1; |
521 |
} |
522 |
|
523 |
|
524 |
/* |
525 |
* dev_bt459_init(): |
526 |
*/ |
527 |
void dev_bt459_init(struct machine *machine, struct memory *mem, |
528 |
uint64_t baseaddr, uint64_t baseaddr_irq, struct vfb_data *vfb_data, |
529 |
int planes, char *irq_path, int type) |
530 |
{ |
531 |
struct bt459_data *d = malloc(sizeof(struct bt459_data)); |
532 |
if (d == NULL) { |
533 |
fprintf(stderr, "out of memory\n"); |
534 |
exit(1); |
535 |
} |
536 |
|
537 |
memset(d, 0, sizeof(struct bt459_data)); |
538 |
|
539 |
INTERRUPT_CONNECT(irq_path, d->irq); |
540 |
|
541 |
d->vfb_data = vfb_data; |
542 |
d->rgb_palette = vfb_data->rgb_palette; |
543 |
d->planes = planes; |
544 |
d->type = type; |
545 |
d->cursor_x = -1; |
546 |
d->cursor_y = -1; |
547 |
d->cursor_xsize = d->cursor_ysize = 0; /* anything */ |
548 |
d->video_on = 1; |
549 |
|
550 |
/* |
551 |
* These offsets are based on those mentioned in NetBSD, |
552 |
* and then adjusted to look good with both NetBSD and |
553 |
* Ultrix: |
554 |
*/ |
555 |
switch (d->type) { |
556 |
case BT459_PX: |
557 |
d->cursor_x_add = 370; |
558 |
d->cursor_y_add = 37; |
559 |
break; |
560 |
case BT459_BA: |
561 |
d->cursor_x_add = 220; |
562 |
d->cursor_y_add = 35; |
563 |
break; |
564 |
case BT459_BBA: |
565 |
if (vfb_data->xsize == 1280) { |
566 |
/* 1280x1024: */ |
567 |
d->cursor_x_add = 368; |
568 |
d->cursor_y_add = 38; |
569 |
} else { |
570 |
/* 1024x864: */ |
571 |
d->cursor_x_add = 220; |
572 |
d->cursor_y_add = 35; |
573 |
} |
574 |
break; |
575 |
} |
576 |
|
577 |
d->interrupt_time_reset_value = 500; |
578 |
|
579 |
memory_device_register(mem, "bt459", baseaddr, DEV_BT459_LENGTH, |
580 |
dev_bt459_access, (void *)d, DM_DEFAULT, NULL); |
581 |
|
582 |
if (baseaddr_irq != 0) |
583 |
memory_device_register(mem, "bt459_irq", baseaddr_irq, 0x10000, |
584 |
dev_bt459_irq_access, (void *)d, DM_DEFAULT, NULL); |
585 |
|
586 |
machine_add_tickfunction(machine, dev_bt459_tick, d, |
587 |
BT459_TICK_SHIFT, 0.0); |
588 |
} |
589 |
|