ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/video.cpp
Revision: 1.16
Committed: 2008-06-25T02:52:22Z (15 years, 10 months ago) by asvitkine
Branch: MAIN
Changes since 1.15: +102 -12 lines
Log Message:
[patch from Kelvin Delbarre]
Software cursor mode is now supported, although currently the existing hardware
cursor mode is used whenever possible. (Software mode will be used if you are
running with a recent version of SDL's Quartz video driver, since a bug in SDL
1.2.11 and later prevents the hardware cursor from working properly with that
driver.)

In hardware cursor mode, the hot-spot is now determined heuristically. Formerly
it could not be determined and was always (1,1), an annoyance for many cursors
other than the arrow.

In hardware cursor mode, the cursor will now be hidden when requested by the
emulated OS (such as when you are typing in a text field).

In hardware cursor mode, some cursor image formats that the code does not handle
correctly will now be rejected, causing the emulated OS to revert temporarily to
software cursor mode. Formerly you would just end up with random garbage for a
cursor. This typically happened for grayscale or color cursors; rejecting images
with rowBytes != 2 eliminates the worst cases.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video.cpp - Video/graphics emulation
3     *
4 gbeauche 1.15 * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     /*
22     * TODO
23     * - check for supported modes ???
24     */
25    
26     #include <stdio.h>
27     #include <string.h>
28    
29     #include "sysdeps.h"
30     #include "video.h"
31     #include "video_defs.h"
32     #include "main.h"
33     #include "adb.h"
34     #include "macos_util.h"
35     #include "user_strings.h"
36     #include "version.h"
37 gbeauche 1.4 #include "thunks.h"
38 cebix 1.1
39     #define DEBUG 0
40     #include "debug.h"
41    
42    
43     // Global variables
44     bool video_activated = false; // Flag: video display activated, mouse and keyboard data valid
45     uint32 screen_base = 0; // Frame buffer base address
46     int cur_mode; // Number of current video mode (index in VModes array)
47     int display_type = DIS_INVALID; // Current display type
48     rgb_color mac_pal[256];
49     uint8 remap_mac_be[256];
50     uint8 MacCursor[68] = {16, 1}; // Mac cursor image
51    
52    
53     bool keyfile_valid; // Flag: Keyfile is valid, enable full-screen modes
54    
55    
56     /*
57     * Video mode information (constructed by VideoInit())
58     */
59    
60     struct VideoInfo VModes[64];
61    
62    
63     /*
64     * Driver local variables
65     */
66    
67     VidLocals *private_data = NULL; // Pointer to driver local variables (there is only one display, so this is ok)
68    
69     static long save_conf_id = APPLE_W_640x480;
70     static long save_conf_mode = APPLE_8_BIT;
71    
72    
73     // Function pointers of imported functions
74     typedef int16 (*iocic_ptr)(void *, int16);
75     static uint32 iocic_tvect = 0;
76 gbeauche 1.9 static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2)
77 cebix 1.1 {
78 gbeauche 1.9 return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2);
79 cebix 1.1 }
80     typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *);
81     static uint32 vslnewis_tvect = 0;
82 gbeauche 1.9 static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3)
83 cebix 1.1 {
84 gbeauche 1.9 return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3);
85 cebix 1.1 }
86     typedef int16 (*vsldisposeis_ptr)(uint32);
87     static uint32 vsldisposeis_tvect = 0;
88     static inline int16 VSLDisposeInterruptService(uint32 arg1)
89     {
90     return (int16)CallMacOS1(vsldisposeis_ptr, vsldisposeis_tvect, arg1);
91     }
92     typedef int16 (*vsldois_ptr)(uint32);
93     static uint32 vsldois_tvect = 0;
94     int16 VSLDoInterruptService(uint32 arg1)
95     {
96     return (int16)CallMacOS1(vsldois_ptr, vsldois_tvect, arg1);
97     }
98     typedef void (*nqdmisc_ptr)(uint32, void *);
99     static uint32 nqdmisc_tvect = 0;
100 gbeauche 1.9 void NQDMisc(uint32 arg1, uintptr arg2)
101 cebix 1.1 {
102 gbeauche 1.9 CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2);
103 cebix 1.1 }
104    
105    
106     // Prototypes
107     static int16 set_gamma(VidLocals *csSave, uint32 gamma);
108    
109    
110     /*
111     * Tell whether window/screen is activated or not (for mouse/keyboard polling)
112     */
113    
114     bool VideoActivated(void)
115     {
116     return video_activated;
117     }
118    
119    
120     /*
121     * Create RGB snapshot of current screen
122     */
123    
124     bool VideoSnapshot(int xsize, int ysize, uint8 *p)
125     {
126     if (display_type == DIS_WINDOW) {
127     uint8 *screen = (uint8 *)private_data->saveBaseAddr;
128     uint32 row_bytes = VModes[cur_mode].viRowBytes;
129     uint32 y2size = VModes[cur_mode].viYsize;
130     uint32 x2size = VModes[cur_mode].viXsize;
131     for (int j=0;j<ysize;j++) {
132     for (int i=0;i<xsize;i++) {
133     *p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].red;
134     *p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].green;
135     *p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].blue;
136     }
137     }
138     return true;
139     }
140     return false;
141     }
142    
143    
144     /*
145 asvitkine 1.16 * Determine whether we should use the hardware or software cursor, and return true for the former, false for the latter.
146     * Currently we use the hardware cursor if we can, but perhaps this can be made a preference someday.
147     */
148    
149     static bool UseHardwareCursor(void)
150     {
151     return video_can_change_cursor();
152     }
153    
154    
155     /*
156 cebix 1.1 * Video driver open routine
157     */
158    
159     static int16 VideoOpen(uint32 pb, VidLocals *csSave)
160     {
161     D(bug("Video Open\n"));
162    
163     // Set up VidLocals
164     csSave->saveBaseAddr = screen_base;
165     csSave->saveData = VModes[cur_mode].viAppleID;// First mode ...
166     csSave->saveMode = VModes[cur_mode].viAppleMode;
167     csSave->savePage = 0;
168     csSave->saveVidParms = 0; // Add the right table
169     csSave->luminanceMapping = false;
170 asvitkine 1.16 csSave->cursorHardware = UseHardwareCursor();
171 cebix 1.1 csSave->cursorX = 0;
172     csSave->cursorY = 0;
173     csSave->cursorVisible = 0;
174     csSave->cursorSet = 0;
175 asvitkine 1.16 csSave->cursorHotFlag = false;
176     csSave->cursorHotX = 0;
177     csSave->cursorHotY = 0;
178 cebix 1.1
179 gbeauche 1.11 // Find and set default gamma table
180     csSave->gammaTable = 0;
181     csSave->maxGammaTableSize = 0;
182 cebix 1.1 set_gamma(csSave, 0);
183    
184     // Install and activate interrupt service
185 gbeauche 1.4 SheepVar32 theServiceID = 0;
186 gbeauche 1.12 VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), theServiceID.addr());
187 gbeauche 1.4 csSave->vslServiceID = theServiceID.value();
188 cebix 1.1 D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID));
189     csSave->interruptsEnabled = true;
190    
191     return noErr;
192     }
193    
194    
195     /*
196     * Video driver control routine
197     */
198    
199 gbeauche 1.11 static bool allocate_gamma_table(VidLocals *csSave, uint32 size)
200     {
201     if (size > csSave->maxGammaTableSize) {
202     if (csSave->gammaTable) {
203     Mac_sysfree(csSave->gammaTable);
204     csSave->gammaTable = 0;
205     csSave->maxGammaTableSize = 0;
206     }
207     if ((csSave->gammaTable = Mac_sysalloc(size)) == 0)
208     return false;
209     csSave->maxGammaTableSize = size;
210     }
211     return true;
212     }
213    
214 cebix 1.1 static int16 set_gamma(VidLocals *csSave, uint32 gamma)
215     {
216 gbeauche 1.11 return paramErr;
217    
218     if (gamma == 0) { // Build linear ramp, 256 entries
219    
220     // Allocate new table, if necessary
221     if (!allocate_gamma_table(csSave, SIZEOF_GammaTbl + 256))
222     return memFullErr;
223    
224     // Initialize header
225     WriteMacInt16(csSave->gammaTable + gVersion, 0); // A version 0 style of the GammaTbl structure
226     WriteMacInt16(csSave->gammaTable + gType, 0); // Frame buffer hardware invariant
227     WriteMacInt16(csSave->gammaTable + gFormulaSize, 0); // No formula data, just correction data
228     WriteMacInt16(csSave->gammaTable + gChanCnt, 1); // Apply same correction to Red, Green, & Blue
229     WriteMacInt16(csSave->gammaTable + gDataCnt, 256); // gDataCnt == 2^^gDataWidth
230     WriteMacInt16(csSave->gammaTable + gDataWidth, 8); // 8 bits of significant data per entry
231 cebix 1.1
232     // Build the linear ramp
233 gbeauche 1.11 uint32 p = csSave->gammaTable + gFormulaData;
234     for (int i=0; i<256; i++)
235     WriteMacInt8(p + i, i);
236 cebix 1.1
237 gbeauche 1.11 } else { // User-supplied gamma table
238 cebix 1.1
239 gbeauche 1.11 // Validate header
240     if (ReadMacInt16(gamma + gVersion) != 0)
241 cebix 1.1 return paramErr;
242 gbeauche 1.11 if (ReadMacInt16(gamma + gType) != 0)
243 cebix 1.1 return paramErr;
244 gbeauche 1.11 int chan_cnt = ReadMacInt16(gamma + gChanCnt);
245     if (chan_cnt != 1 && chan_cnt != 3)
246 cebix 1.1 return paramErr;
247 gbeauche 1.11 int data_width = ReadMacInt16(gamma + gDataWidth);
248     if (data_width > 8)
249 cebix 1.1 return paramErr;
250 gbeauche 1.11 int data_cnt = ReadMacInt16(gamma + gDataWidth);
251     if (data_cnt != (1 << data_width))
252 cebix 1.1 return paramErr;
253    
254 gbeauche 1.11 // Allocate new table, if necessary
255     int size = SIZEOF_GammaTbl + ReadMacInt16(gamma + gFormulaSize) + chan_cnt * data_cnt;
256     if (!allocate_gamma_table(csSave, size))
257     return memFullErr;
258 cebix 1.1
259 gbeauche 1.11 // Copy table
260     Mac2Mac_memcpy(csSave->gammaTable, gamma, size);
261 cebix 1.1 }
262     return noErr;
263     }
264    
265     static int16 VideoControl(uint32 pb, VidLocals *csSave)
266     {
267     int16 code = ReadMacInt16(pb + csCode);
268     D(bug("VideoControl %d: ", code));
269     uint32 param = ReadMacInt32(pb + csParam);
270     switch (code) {
271    
272     case cscReset: // VidReset
273     D(bug("VidReset\n"));
274     return controlErr;
275    
276     case cscKillIO: // VidKillIO
277     D(bug("VidKillIO\n"));
278     return controlErr;
279    
280     case cscSetMode: // SetVidMode
281     D(bug("SetVidMode\n"));
282     D(bug("mode:%04x page:%04x \n", ReadMacInt16(param + csMode),
283     ReadMacInt16(param + csPage)));
284     WriteMacInt32(param + csData, csSave->saveData);
285     return video_mode_change(csSave, param);
286    
287     case cscSetEntries: { // SetEntries
288     D(bug("SetEntries\n"));
289     if (VModes[cur_mode].viAppleMode > APPLE_8_BIT) return controlErr;
290 gbeauche 1.6 uint32 s_pal = ReadMacInt32(param + csTable);
291     uint16 start = ReadMacInt16(param + csStart);
292     uint16 count = ReadMacInt16(param + csCount);
293     if (s_pal == 0 || count > 256) return controlErr;
294 cebix 1.1
295     // Preparations for gamma correction
296     bool do_gamma = false;
297     uint8 *red_gamma = NULL;
298     uint8 *green_gamma = NULL;
299     uint8 *blue_gamma = NULL;
300     int gamma_data_width = 0;
301 gbeauche 1.11 if (csSave->gammaTable) {
302     #ifdef __BEOS__
303     // Windows are gamma-corrected by BeOS
304     const bool can_do_gamma = (display_type == DIS_SCREEN);
305     #else
306     const bool can_do_gamma = true;
307     #endif
308     if (can_do_gamma) {
309     uint32 gamma_table = csSave->gammaTable;
310     red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
311     int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
312     if (chan_cnt == 1)
313     green_gamma = blue_gamma = red_gamma;
314     else {
315     int ofs = ReadMacInt16(gamma_table + gDataCnt);
316     green_gamma = red_gamma + ofs;
317     blue_gamma = green_gamma + ofs;
318     }
319     gamma_data_width = ReadMacInt16(gamma_table + gDataWidth);
320     do_gamma = true;
321 cebix 1.1 }
322     }
323    
324     // Set palette
325     rgb_color *d_pal;
326 gbeauche 1.6 if (start == 0xffff) { // Indexed
327 cebix 1.1 for (int i=0; i<=count; i++) {
328 gbeauche 1.6 d_pal = mac_pal + (ReadMacInt16(s_pal + csValue) & 0xff);
329     uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
330     uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
331     uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
332 cebix 1.1 if (csSave->luminanceMapping)
333     red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
334     if (do_gamma) {
335     red = red_gamma[red >> (8 - gamma_data_width)];
336     green = green_gamma[green >> (8 - gamma_data_width)];
337     blue = blue_gamma[blue >> (8 - gamma_data_width)];
338     }
339     (*d_pal).red = red;
340     (*d_pal).green = green;
341     (*d_pal).blue = blue;
342 gbeauche 1.6 s_pal += 8;
343 cebix 1.1 }
344 gbeauche 1.6 } else { // Sequential
345     d_pal = mac_pal + start;
346 cebix 1.1 for (int i=0; i<=count; i++) {
347 gbeauche 1.6 uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
348     uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
349     uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
350 cebix 1.1 if (csSave->luminanceMapping)
351     red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
352     if (do_gamma) {
353     red = red_gamma[red >> (8 - gamma_data_width)];
354     green = green_gamma[green >> (8 - gamma_data_width)];
355     blue = blue_gamma[blue >> (8 - gamma_data_width)];
356     }
357     (*d_pal).red = red;
358     (*d_pal).green = green;
359     (*d_pal).blue = blue;
360 gbeauche 1.6 d_pal++;
361     s_pal += 8;
362 cebix 1.1 }
363     }
364     video_set_palette();
365     return noErr;
366     }
367    
368 gbeauche 1.11 case cscSetGamma: { // SetGamma
369     uint32 user_table = ReadMacInt32(param + csGTable);
370     D(bug("SetGamma %08x\n", user_table));
371     return set_gamma(csSave, ReadMacInt32(user_table));
372     }
373 cebix 1.1
374     case cscGrayPage: { // GrayPage
375 gbeauche 1.6 D(bug("GrayPage %d\n", ReadMacInt16(param + csPage)));
376     if (ReadMacInt16(param + csPage))
377     return paramErr;
378    
379     uint32 pattern[6] = {
380     0xaaaaaaaa, // 1 bpp
381     0xcccccccc, // 2 bpp
382     0xf0f0f0f0, // 4 bpp
383     0xff00ff00, // 8 bpp
384     0xffff0000, // 16 bpp
385     0xffffffff // 32 bpp
386     };
387     uint32 p = csSave->saveBaseAddr;
388     uint32 pat = pattern[VModes[cur_mode].viAppleMode - APPLE_1_BIT];
389     bool invert = (VModes[cur_mode].viAppleMode == APPLE_32_BIT);
390     for (uint32 y=0; y<VModes[cur_mode].viYsize; y++) {
391     for (uint32 x=0; x<VModes[cur_mode].viRowBytes; x+=4) {
392     WriteMacInt32(p + x, pat);
393     if (invert)
394     pat = ~pat;
395     }
396     p += VModes[cur_mode].viRowBytes;
397     pat = ~pat;
398 cebix 1.1 }
399     return noErr;
400     }
401    
402     case cscSetGray: // SetGray
403     D(bug("SetGray %02x\n", ReadMacInt8(param)));
404     csSave->luminanceMapping = ReadMacInt8(param);
405     return noErr;
406    
407     case cscSetInterrupt: // SetInterrupt
408     D(bug("SetInterrupt\n"));
409     csSave->interruptsEnabled = !ReadMacInt8(param);
410     return noErr;
411    
412     case cscDirectSetEntries: // DirectSetEntries
413     D(bug("DirectSetEntries\n"));
414     return controlErr;
415    
416     case cscSetDefaultMode: // SetDefaultMode
417     D(bug("SetDefaultMode\n"));
418     return controlErr;
419    
420     case cscSwitchMode:
421     D(bug("cscSwitchMode (Display Manager support) \nMode:%02x ID:%04x Page:%d\n",
422     ReadMacInt16(param + csMode), ReadMacInt32(param + csData), ReadMacInt16(param + csPage)));
423     return video_mode_change(csSave, param);
424    
425     case cscSavePreferredConfiguration:
426     D(bug("SavePreferredConfiguration\n"));
427     save_conf_id = ReadMacInt32(param + csData);
428     save_conf_mode = ReadMacInt16(param + csMode);
429     return noErr;
430    
431     case cscSetHardwareCursor: {
432     // D(bug("SetHardwareCursor\n"));
433 asvitkine 1.16
434     if (!csSave->cursorHardware)
435     return controlErr;
436    
437 cebix 1.1 csSave->cursorSet = false;
438     bool changed = false;
439    
440     // Image
441     uint32 cursor = ReadMacInt32(param); // Pointer to CursorImage
442     uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap);
443     if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0)
444     return controlErr;
445     uint32 pixmap = ReadMacInt32(pmhandle);
446 asvitkine 1.16
447     // XXX: only certain image formats are handled properly at the moment
448     uint16 rowBytes = ReadMacInt16(pixmap + 4) & 0x7FFF;
449     if (rowBytes != 2)
450     return controlErr;
451 cebix 1.1
452     // Mask
453     uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask);
454     if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0)
455     return controlErr;
456     uint32 bitmap = ReadMacInt32(bmhandle);
457 asvitkine 1.16
458     // Get cursor data even on a screen, to set the right cursor image when switching back to a window.
459     // Hotspot is stale, but will be fixed by the next call to DrawHardwareCursor, which is likely to
460     // occur immediately hereafter.
461    
462     if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) {
463     memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32);
464     changed = true;
465     }
466 cebix 1.1 if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) {
467     memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32);
468     changed = true;
469     }
470    
471     // Set new cursor image
472 gbeauche 1.8 if (!video_can_change_cursor())
473 cebix 1.1 return controlErr;
474     if (changed)
475     video_set_cursor();
476    
477     csSave->cursorSet = true;
478 asvitkine 1.16 csSave->cursorHotFlag = true;
479 cebix 1.1 return noErr;
480     }
481    
482 asvitkine 1.16 case cscDrawHardwareCursor: {
483 cebix 1.1 // D(bug("DrawHardwareCursor\n"));
484 asvitkine 1.16
485     if (!csSave->cursorHardware)
486     return controlErr;
487    
488     int32 oldX = csSave->cursorX;
489     int32 oldY = csSave->cursorY;
490     uint32 oldVisible = csSave->cursorVisible;
491    
492 cebix 1.1 csSave->cursorX = ReadMacInt32(param + csCursorX);
493     csSave->cursorY = ReadMacInt32(param + csCursorY);
494     csSave->cursorVisible = ReadMacInt32(param + csCursorVisible);
495 asvitkine 1.16 bool changed = (csSave->cursorVisible != oldVisible);
496    
497     // If this is the first DrawHardwareCursor call since the cursor was last set (via SetHardwareCursor),
498     // attempt to set an appropriate cursor hotspot. SetHardwareCursor itself does not know what the
499     // hotspot should be; it knows only the cursor image and mask. The hotspot is known only to the caller,
500     // and we have to try to infer it here. The usual sequence of calls when changing the cursor is:
501     //
502     // DrawHardwareCursor with (oldX, oldY, invisible)
503     // SetHardwareCursor with (cursor)
504     // DrawHardwareCursor with (newX, newY, visible)
505     //
506     // The key thing to note is that the sequence is intended not to change the current screen pixel location
507     // indicated by the hotspot. Thus, the difference between (newX, newY) and (oldX, oldY) reflects precisely
508     // the difference between the old cursor hotspot and the new one. For example, if you change from a
509     // cursor whose hotspot is (1, 1) to one whose hotspot is (7, 4), then you must adjust the cursor position
510     // by (-6, -3) in order for the same screen pixel to remain under the new hotspot.
511     //
512     // Alas, on rare occasions this heuristic can fail, and if you did nothing else you could even get stuck
513     // with the wrong hotspot from then on. To address that possibility, we force the hotspot to (1, 1)
514     // whenever the cursor being drawn is the standard arrow. Thus, while it is very unlikely that you will
515     // ever have the wrong hotspot, if you do, it is easy to recover.
516    
517     if (csSave->cursorHotFlag) {
518     csSave->cursorHotFlag = false;
519     D(bug("old hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
520    
521     static uint8 arrow[] = {
522     0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00,
523     0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
524     };
525     if (memcmp(MacCursor + 4, arrow, 32) == 0) {
526     csSave->cursorHotX = 1;
527     csSave->cursorHotY = 1;
528     } else if (csSave->cursorX != oldX || csSave->cursorY != oldY) {
529     int32 hotX = csSave->cursorHotX + (oldX - csSave->cursorX);
530     int32 hotY = csSave->cursorHotY + (oldY - csSave->cursorY);
531    
532     if (0 <= hotX && hotX <= 15 && 0 <= hotY && hotY <= 15) {
533     csSave->cursorHotX = hotX;
534     csSave->cursorHotY = hotY;
535     }
536     }
537     if (MacCursor[2] != csSave->cursorHotX || MacCursor[3] != csSave->cursorHotY) {
538     MacCursor[2] = csSave->cursorHotX;
539     MacCursor[3] = csSave->cursorHotY;
540     changed = true;
541     }
542     D(bug("new hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
543     }
544    
545     if (changed && video_can_change_cursor())
546     video_set_cursor();
547    
548 cebix 1.1 return noErr;
549 asvitkine 1.16 }
550 cebix 1.1
551     case 43: { // Driver Gestalt
552     uint32 sel = ReadMacInt32(pb + csParam);
553     D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel));
554     switch (sel) {
555     case FOURCC('v','e','r','s'):
556     WriteMacInt32(pb + csParam + 4, 0x01008000);
557     break;
558     case FOURCC('i','n','t','f'):
559     WriteMacInt32(pb + csParam + 4, FOURCC('c','a','r','d'));
560     break;
561     case FOURCC('s','y','n','c'):
562     WriteMacInt32(pb + csParam + 4, 0x01000000);
563     break;
564     default:
565     return statusErr;
566     };
567     return noErr;
568     }
569    
570     default:
571     D(bug(" unknown control code %d\n", code));
572     return controlErr;
573     }
574     }
575    
576    
577     /*
578     * Video driver status routine
579     */
580    
581     // Search for given AppleID in mode table
582     static bool has_mode(uint32 id)
583     {
584     VideoInfo *p = VModes;
585     while (p->viType != DIS_INVALID) {
586     if (p->viAppleID == id)
587     return true;
588     p++;
589     }
590     return false;
591     }
592    
593     // Find maximum depth for given AppleID
594     static uint32 max_depth(uint32 id)
595     {
596     uint32 max = APPLE_1_BIT;
597     VideoInfo *p = VModes;
598     while (p->viType != DIS_INVALID) {
599     if (p->viAppleID == id && p->viAppleMode > max)
600     max = p->viAppleMode;
601     p++;
602     }
603     return max;
604     }
605    
606 gbeauche 1.14 // Get X/Y size of specified resolution
607     static void get_size_of_resolution(int id, uint32 &x, uint32 &y)
608     {
609     VideoInfo *p = VModes;
610     while (p->viType != DIS_INVALID) {
611     if (p->viAppleID == id) {
612     x = p->viXsize;
613     y = p->viYsize;
614     return;
615     }
616     p++;
617     }
618     x = y = 0;
619     }
620    
621 cebix 1.1 static int16 VideoStatus(uint32 pb, VidLocals *csSave)
622     {
623     int16 code = ReadMacInt16(pb + csCode);
624     D(bug("VideoStatus %d: ", code));
625     uint32 param = ReadMacInt32(pb + csParam);
626     switch (code) {
627    
628     case cscGetMode: // GetMode
629     D(bug("GetMode\n"));
630     WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
631     WriteMacInt16(param + csMode, csSave->saveMode);
632     WriteMacInt16(param + csPage, csSave->savePage);
633     D(bug("return: mode:%04x page:%04x ", ReadMacInt16(param + csMode),
634     ReadMacInt16(param + csPage)));
635     D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr)));
636     return noErr;
637    
638     case cscGetEntries: { // GetEntries
639     D(bug("GetEntries\n"));
640 gbeauche 1.6 uint32 d_pal = ReadMacInt32(param + csTable);
641     uint16 start = ReadMacInt16(param + csStart);
642     uint16 count = ReadMacInt16(param + csCount);
643 cebix 1.1 rgb_color *s_pal;
644     if ((VModes[cur_mode].viAppleMode == APPLE_32_BIT)||
645     (VModes[cur_mode].viAppleMode == APPLE_16_BIT)) {
646     D(bug("ERROR: GetEntries in direct mode \n"));
647     return statusErr;
648     }
649 gbeauche 1.6
650     if (start == 0xffff) { // Indexed
651 cebix 1.1 for (uint16 i=0;i<count;i++) {
652 gbeauche 1.6 s_pal = mac_pal + (ReadMacInt16(d_pal + csValue) & 0xff);
653     uint8 red = (*s_pal).red;
654     uint8 green = (*s_pal).green;
655     uint8 blue = (*s_pal).blue;
656     WriteMacInt16(d_pal + csRed, red * 0x0101);
657     WriteMacInt16(d_pal + csGreen, green * 0x0101);
658     WriteMacInt16(d_pal + csBlue, blue * 0x0101);
659     d_pal += 8;
660 cebix 1.1 }
661 gbeauche 1.6 } else { // Sequential
662     if (start + count > 255)
663     return paramErr;
664     s_pal = mac_pal + start;
665 cebix 1.1 for (uint16 i=0;i<count;i++) {
666 gbeauche 1.6 uint8 red = (*s_pal).red;
667     uint8 green = (*s_pal).green;
668     uint8 blue = (*s_pal).blue;
669     s_pal++;
670     WriteMacInt16(d_pal + csRed, red * 0x0101);
671     WriteMacInt16(d_pal + csGreen, green * 0x0101);
672     WriteMacInt16(d_pal + csBlue, blue * 0x0101);
673     d_pal += 8;
674 cebix 1.1 }
675     };
676     return noErr;
677     }
678    
679     case cscGetPageCnt: // GetPage
680     D(bug("GetPage\n"));
681     WriteMacInt16(param + csPage, 1);
682     return noErr;
683    
684     case cscGetPageBase: // GetPageBase
685     D(bug("GetPageBase\n"));
686     WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
687     return noErr;
688    
689     case cscGetGray: // GetGray
690     D(bug("GetGray\n"));
691     WriteMacInt8(param, csSave->luminanceMapping ? 1 : 0);
692     return noErr;
693    
694     case cscGetInterrupt: // GetInterrupt
695     D(bug("GetInterrupt\n"));
696     WriteMacInt8(param, csSave->interruptsEnabled ? 0 : 1);
697     return noErr;
698    
699     case cscGetGamma: // GetGamma
700     D(bug("GetGamma\n"));
701     WriteMacInt32(param, (uint32)csSave->gammaTable);
702     return statusErr;
703    
704     case cscGetDefaultMode: // GetDefaultMode
705     D(bug("GetDefaultMode\n"));
706     return statusErr;
707    
708     case cscGetCurMode: // GetCurMode
709     D(bug("GetCurMode\n"));
710     WriteMacInt16(param + csMode, csSave->saveMode);
711     WriteMacInt32(param + csData, csSave->saveData);
712     WriteMacInt16(param + csPage, csSave->savePage);
713     WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
714    
715     D(bug("return: mode:%04x ID:%08lx page:%04x ", ReadMacInt16(param + csMode),
716     ReadMacInt32(param + csData), ReadMacInt16(param + csPage)));
717     D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr)));
718     return noErr;
719    
720     case cscGetConnection: // GetConnection
721     D(bug("GetConnection\n"));
722     WriteMacInt16(param + csDisplayType, kMultiModeCRT3Connect);
723     WriteMacInt8(param + csConnectTaggedType, 6);
724     WriteMacInt8(param + csConnectTaggedData, 0x23);
725     WriteMacInt32(param + csConnectFlags, (1<<kAllModesValid)|(1<<kAllModesSafe));
726     WriteMacInt32(param + csDisplayComponent, 0);
727     return noErr;
728    
729     case cscGetModeBaseAddress:
730     D(bug("GetModeBaseAddress (obsolete !) \n"));
731     return statusErr;
732    
733     case cscGetPreferredConfiguration:
734     D(bug("GetPreferredConfiguration \n"));
735     WriteMacInt16(param + csMode, save_conf_mode);
736     WriteMacInt32(param + csData, save_conf_id);
737     return noErr;
738    
739     case cscGetNextResolution: {
740     D(bug("GetNextResolution \n"));
741     int work_id = ReadMacInt32(param + csPreviousDisplayModeID);
742     switch (work_id) {
743     case kDisplayModeIDCurrent:
744     work_id = csSave->saveData;
745     break;
746     case kDisplayModeIDFindFirstResolution:
747     work_id = APPLE_ID_MIN;
748     while (!has_mode(work_id))
749     work_id ++;
750     break;
751     default:
752     if (!has_mode(work_id))
753     return paramErr;
754     work_id++;
755     while (!has_mode(work_id)) {
756     work_id++;
757     if (work_id > APPLE_ID_MAX) {
758     WriteMacInt32(param + csRIDisplayModeID, kDisplayModeIDNoMoreResolutions);
759     return noErr;
760     }
761     }
762     break;
763     }
764     WriteMacInt32(param + csRIDisplayModeID, work_id);
765     WriteMacInt16(param + csMaxDepthMode, max_depth(work_id));
766     switch (work_id) {
767     case APPLE_640x480:
768     WriteMacInt32(param + csHorizontalPixels, 640);
769     WriteMacInt32(param + csVerticalLines, 480);
770     WriteMacInt32(param + csRefreshRate, 75<<16);
771     break;
772     case APPLE_W_640x480:
773     WriteMacInt32(param + csHorizontalPixels, 640);
774     WriteMacInt32(param + csVerticalLines, 480);
775     WriteMacInt32(param + csRefreshRate, 60<<16);
776     break;
777     case APPLE_800x600:
778     WriteMacInt32(param + csHorizontalPixels, 800);
779     WriteMacInt32(param + csVerticalLines, 600);
780     WriteMacInt32(param + csRefreshRate, 75<<16);
781     break;
782     case APPLE_W_800x600:
783     WriteMacInt32(param + csHorizontalPixels, 800);
784     WriteMacInt32(param + csVerticalLines, 600);
785     WriteMacInt32(param + csRefreshRate, 60<<16);
786     break;
787     case APPLE_1024x768:
788     WriteMacInt32(param + csHorizontalPixels, 1024);
789     WriteMacInt32(param + csVerticalLines, 768);
790     WriteMacInt32(param + csRefreshRate, 75<<16);
791     break;
792 gbeauche 1.7 case APPLE_1152x768:
793     WriteMacInt32(param + csHorizontalPixels, 1152);
794     WriteMacInt32(param + csVerticalLines, 768);
795     WriteMacInt32(param + csRefreshRate, 75<<16);
796     break;
797 cebix 1.1 case APPLE_1152x900:
798     WriteMacInt32(param + csHorizontalPixels, 1152);
799     WriteMacInt32(param + csVerticalLines, 900);
800     WriteMacInt32(param + csRefreshRate, 75<<16);
801     break;
802     case APPLE_1280x1024:
803     WriteMacInt32(param + csHorizontalPixels, 1280);
804     WriteMacInt32(param + csVerticalLines, 1024);
805     WriteMacInt32(param + csRefreshRate, 75<<16);
806     break;
807     case APPLE_1600x1200:
808     WriteMacInt32(param + csHorizontalPixels, 1600);
809     WriteMacInt32(param + csVerticalLines, 1200);
810     WriteMacInt32(param + csRefreshRate, 75<<16);
811     break;
812 gbeauche 1.14 case APPLE_CUSTOM: {
813     uint32 x, y;
814     get_size_of_resolution(work_id, x, y);
815     WriteMacInt32(param + csHorizontalPixels, x);
816     WriteMacInt32(param + csVerticalLines, y);
817     WriteMacInt32(param + csRefreshRate, 75<<16);
818     break;
819     }
820 cebix 1.1 }
821     return noErr;
822     }
823    
824     case cscGetVideoParameters: // GetVideoParameters
825     D(bug("GetVideoParameters ID:%08lx Depth:%04x\n",
826     ReadMacInt32(param + csDisplayModeID),
827     ReadMacInt16(param + csDepthMode)));
828    
829     // find right video mode
830     for (int i=0; VModes[i].viType!=DIS_INVALID; i++) {
831     if ((ReadMacInt16(param + csDepthMode) == VModes[i].viAppleMode) &&
832     (ReadMacInt32(param + csDisplayModeID) == VModes[i].viAppleID)) {
833     uint32 vpb = ReadMacInt32(param + csVPBlockPtr);
834     WriteMacInt32(vpb + vpBaseOffset, 0);
835     WriteMacInt16(vpb + vpRowBytes, VModes[i].viRowBytes);
836     WriteMacInt16(vpb + vpBounds, 0);
837     WriteMacInt16(vpb + vpBounds + 2, 0);
838     WriteMacInt16(vpb + vpBounds + 4, VModes[i].viYsize);
839     WriteMacInt16(vpb + vpBounds + 6, VModes[i].viXsize);
840     WriteMacInt16(vpb + vpVersion, 0); // Pixel Map version number
841     WriteMacInt16(vpb + vpPackType, 0);
842     WriteMacInt32(vpb + vpPackSize, 0);
843     WriteMacInt32(vpb + vpHRes, 0x00480000); // horiz res of the device (ppi)
844     WriteMacInt32(vpb + vpVRes, 0x00480000); // vert res of the device (ppi)
845     switch (VModes[i].viAppleMode) {
846     case APPLE_1_BIT:
847     WriteMacInt16(vpb + vpPixelType, 0);
848     WriteMacInt16(vpb + vpPixelSize, 1);
849     WriteMacInt16(vpb + vpCmpCount, 1);
850     WriteMacInt16(vpb + vpCmpSize, 1);
851     WriteMacInt32(param + csDeviceType, 0); // CLUT
852     break;
853     case APPLE_2_BIT:
854     WriteMacInt16(vpb + vpPixelType, 0);
855     WriteMacInt16(vpb + vpPixelSize, 2);
856     WriteMacInt16(vpb + vpCmpCount, 1);
857     WriteMacInt16(vpb + vpCmpSize, 2);
858     WriteMacInt32(param + csDeviceType, 0); // CLUT
859     break;
860     case APPLE_4_BIT:
861     WriteMacInt16(vpb + vpPixelType, 0);
862     WriteMacInt16(vpb + vpPixelSize, 4);
863     WriteMacInt16(vpb + vpCmpCount, 1);
864     WriteMacInt16(vpb + vpCmpSize, 4);
865     WriteMacInt32(param + csDeviceType, 0); // CLUT
866     break;
867     case APPLE_8_BIT:
868     WriteMacInt16(vpb + vpPixelType, 0);
869     WriteMacInt16(vpb + vpPixelSize, 8);
870     WriteMacInt16(vpb + vpCmpCount, 1);
871     WriteMacInt16(vpb + vpCmpSize, 8);
872     WriteMacInt32(param + csDeviceType, 0); // CLUT
873     break;
874     case APPLE_16_BIT:
875     WriteMacInt16(vpb + vpPixelType, 0x10);
876     WriteMacInt16(vpb + vpPixelSize, 16);
877     WriteMacInt16(vpb + vpCmpCount, 3);
878     WriteMacInt16(vpb + vpCmpSize, 5);
879     WriteMacInt32(param + csDeviceType, 2); // DIRECT
880     break;
881     case APPLE_32_BIT:
882     WriteMacInt16(vpb + vpPixelType, 0x10);
883     WriteMacInt16(vpb + vpPixelSize, 32);
884     WriteMacInt16(vpb + vpCmpCount, 3);
885     WriteMacInt16(vpb + vpCmpSize, 8);
886     WriteMacInt32(param + csDeviceType, 2); // DIRECT
887     break;
888     }
889     WriteMacInt32(param + csPageCount, 1);
890     return noErr;
891     }
892     }
893     return paramErr;
894    
895     case cscGetModeTiming:
896     D(bug("GetModeTiming mode %08lx\n", ReadMacInt32(param + csTimingMode)));
897     WriteMacInt32(param + csTimingFormat, kDeclROMtables);
898     WriteMacInt32(param + csTimingFlags, (1<<kModeValid)|(1<<kModeSafe)|(1<<kShowModeNow)); // Mode valid, safe, default and shown in Monitors panel
899     for (int i=0; VModes[i].viType!=DIS_INVALID; i++) {
900     if (ReadMacInt32(param + csTimingMode) == VModes[i].viAppleID) {
901     uint32 timing = timingUnknown;
902     uint32 flags = (1<<kModeValid) | (1<<kShowModeNow);
903     switch (VModes[i].viAppleID) {
904     case APPLE_640x480:
905     timing = timingVESA_640x480_75hz;
906     flags |= (1<<kModeSafe);
907     break;
908     case APPLE_W_640x480:
909     timing = timingVESA_640x480_60hz;
910     flags |= (1<<kModeSafe);
911     break;
912     case APPLE_800x600:
913     timing = timingVESA_800x600_75hz;
914     flags |= (1<<kModeSafe);
915     break;
916     case APPLE_W_800x600:
917     timing = timingVESA_800x600_60hz;
918     flags |= (1<<kModeSafe);
919     break;
920     case APPLE_1024x768:
921     timing = timingVESA_1024x768_75hz;
922 gbeauche 1.7 break;
923     case APPLE_1152x768:
924     timing = timingApple_1152x870_75hz; // FIXME
925 cebix 1.1 break;
926     case APPLE_1152x900:
927     timing = timingApple_1152x870_75hz;
928     break;
929     case APPLE_1280x1024:
930     timing = timingVESA_1280x960_75hz;
931     break;
932     case APPLE_1600x1200:
933     timing = timingVESA_1600x1200_75hz;
934     break;
935     default:
936     timing = timingUnknown;
937     break;
938     }
939     WriteMacInt32(param + csTimingData, timing);
940     WriteMacInt32(param + csTimingFlags, flags);
941     return noErr;
942     }
943     }
944     return paramErr;
945    
946     case cscSupportsHardwareCursor:
947     D(bug("SupportsHardwareCursor\n"));
948 asvitkine 1.16 WriteMacInt32(param, csSave->cursorHardware);
949 cebix 1.1 return noErr;
950    
951     case cscGetHardwareCursorDrawState:
952     D(bug("GetHardwareCursorDrawState\n"));
953 asvitkine 1.16
954     if (!csSave->cursorHardware)
955     return statusErr;
956    
957 cebix 1.1 WriteMacInt32(param + csCursorX, csSave->cursorX);
958     WriteMacInt32(param + csCursorY, csSave->cursorY);
959     WriteMacInt32(param + csCursorVisible, csSave->cursorVisible);
960     WriteMacInt32(param + csCursorSet, csSave->cursorSet);
961     return noErr;
962    
963     default:
964     D(bug(" unknown status code %d\n", code));
965     return statusErr;
966     }
967     }
968    
969    
970     /*
971     * Video driver close routine
972     */
973    
974     static int16 VideoClose(uint32 pb, VidLocals *csSave)
975     {
976     D(bug("VideoClose\n"));
977    
978     // Delete interrupt service
979     csSave->interruptsEnabled = false;
980     VSLDisposeInterruptService(csSave->vslServiceID);
981    
982     return noErr;
983     }
984    
985    
986     /*
987     * Native (PCI) driver entry
988     */
989    
990 gbeauche 1.9 int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind)
991 cebix 1.1 {
992 gbeauche 1.9 // D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind));
993 cebix 1.1 int16 err = noErr;
994    
995     switch (commandCode) {
996     case kInitializeCommand:
997     case kReplaceCommand:
998 gbeauche 1.11 if (private_data != NULL) { // Might be left over from a reboot
999     if (private_data->gammaTable)
1000     Mac_sysfree(private_data->gammaTable);
1001 gbeauche 1.12 if (private_data->regEntryID)
1002     Mac_sysfree(private_data->regEntryID);
1003 gbeauche 1.11 }
1004 cebix 1.1 delete private_data;
1005    
1006 gbeauche 1.10 iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
1007 cebix 1.1 D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect));
1008     if (iocic_tvect == 0) {
1009     printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n");
1010     err = -1;
1011     break;
1012     }
1013 gbeauche 1.10 vslnewis_tvect = FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService");
1014 cebix 1.1 D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect));
1015     if (vslnewis_tvect == 0) {
1016     printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n");
1017     err = -1;
1018     break;
1019     }
1020 gbeauche 1.10 vsldisposeis_tvect = FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService");
1021 cebix 1.1 D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect));
1022     if (vsldisposeis_tvect == 0) {
1023     printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n");
1024     err = -1;
1025     break;
1026     }
1027 gbeauche 1.10 vsldois_tvect = FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService");
1028 cebix 1.1 D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect));
1029     if (vsldois_tvect == 0) {
1030     printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n");
1031     err = -1;
1032     break;
1033     }
1034 gbeauche 1.10 nqdmisc_tvect = FindLibSymbol("\014InterfaceLib", "\007NQDMisc");
1035 cebix 1.1 D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect));
1036     if (nqdmisc_tvect == 0) {
1037     printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n");
1038     err = -1;
1039     break;
1040     }
1041    
1042     private_data = new VidLocals;
1043 gbeauche 1.11 private_data->gammaTable = 0;
1044 gbeauche 1.12 private_data->regEntryID = Mac_sysalloc(sizeof(RegEntryID));
1045     if (private_data->regEntryID == 0) {
1046     printf("FATAL: VideoDoDriverIO(): Can't allocate service owner\n");
1047     err = -1;
1048     break;
1049     }
1050     Mac2Mac_memcpy(private_data->regEntryID, commandContents + 2, 16); // DriverInitInfo.deviceEntry
1051 cebix 1.1 private_data->interruptsEnabled = false; // Disable interrupts
1052     break;
1053    
1054     case kFinalizeCommand:
1055     case kSupersededCommand:
1056 gbeauche 1.12 if (private_data != NULL) {
1057     if (private_data->gammaTable)
1058     Mac_sysfree(private_data->gammaTable);
1059     if (private_data->regEntryID)
1060     Mac_sysfree(private_data->regEntryID);
1061     }
1062 cebix 1.1 delete private_data;
1063     private_data = NULL;
1064     break;
1065    
1066     case kOpenCommand:
1067 gbeauche 1.9 err = VideoOpen(commandContents, private_data);
1068 cebix 1.1 break;
1069    
1070     case kCloseCommand:
1071 gbeauche 1.9 err = VideoClose(commandContents, private_data);
1072 cebix 1.1 break;
1073    
1074     case kControlCommand:
1075 gbeauche 1.9 err = VideoControl(commandContents, private_data);
1076 cebix 1.1 break;
1077    
1078     case kStatusCommand:
1079 gbeauche 1.9 err = VideoStatus(commandContents, private_data);
1080 cebix 1.1 break;
1081    
1082     case kReadCommand:
1083     case kWriteCommand:
1084     break;
1085    
1086     case kKillIOCommand:
1087     err = abortErr;
1088     break;
1089    
1090     default:
1091     err = paramErr;
1092     break;
1093     }
1094    
1095     if (commandKind == kImmediateIOCommandKind)
1096     return err;
1097     else
1098     return IOCommandIsComplete(commandID, err);
1099     }