--- miscemu/instr.c.orig Mon Sep 28 22:07:49 1998 +++ miscemu/instr.c Wed Oct 21 23:26:01 1998 @@ -489,21 +489,41 @@ { case 0x6c: *((BYTE *)data) = IO_inport( DX_sig(context), 1); + TRACE(io, "0x%x < %02x @ %04x:%04x\n", DX_sig(context), + *((BYTE *)data), CS_sig(context), IP_sig(context)); break; case 0x6d: if (long_op) + { *((DWORD *)data) = IO_inport( DX_sig(context), 4); + TRACE(io, "0x%x < %08lx @ %04x:%04x\n", DX_sig(context), + *((DWORD *)data), CS_sig(context), IP_sig(context)); + } else + { *((WORD *)data) = IO_inport( DX_sig(context), 2); + TRACE(io, "0x%x < %04x @ %04x:%04x\n", DX_sig(context), + *((WORD *)data), CS_sig(context), IP_sig(context)); + } break; case 0x6e: IO_outport( DX_sig(context), 1, *((BYTE *)data)); + TRACE(io, "0x%x > %02x @ %04x:%04x\n", DX_sig(context), + *((BYTE *)data), CS_sig(context), IP_sig(context)); break; case 0x6f: if (long_op) + { IO_outport( DX_sig(context), 4, *((DWORD *)data)); + TRACE(io, "0x%x > %08lx @ %04x:%04x\n", DX_sig(context), + *((DWORD *)data), CS_sig(context), IP_sig(context)); + } else + { IO_outport( DX_sig(context), 2, *((WORD *)data)); + TRACE(io, "0x%x > %04x @ %04x:%04x\n", DX_sig(context), + *((WORD *)data), CS_sig(context), IP_sig(context)); + } break; } } @@ -609,45 +629,93 @@ case 0xe4: /* inb al,XX */ AL_sig(context) = IO_inport( instr[1], 1 ); + TRACE(io, "0x%x < %02x @ %04x:%04x\n", instr[1], + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 2; return TRUE; case 0xe5: /* in (e)ax,XX */ - if (long_op) EAX_sig(context) = IO_inport( instr[1], 4 ); - else AX_sig(context) = IO_inport( instr[1], 2 ); + if (long_op) + { + EAX_sig(context) = IO_inport( instr[1], 4 ); + TRACE(io, "0x%x < %08lx @ %04x:%04x\n", instr[1], + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + AX_sig(context) = IO_inport( instr[1], 2 ); + TRACE(io, "0x%x < %04x @ %04x:%04x\n", instr[1], + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 2; return TRUE; case 0xe6: /* outb XX,al */ IO_outport( instr[1], 1, AL_sig(context) ); + TRACE(io, "0x%x > %02x @ %04x:%04x\n", instr[1], + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 2; return TRUE; case 0xe7: /* out XX,(e)ax */ - if (long_op) IO_outport( instr[1], 4, EAX_sig(context) ); - else IO_outport( instr[1], 2, AX_sig(context) ); + if (long_op) + { + IO_outport( instr[1], 4, EAX_sig(context) ); + TRACE(io, "0x%x > %08lx @ %04x:%04x\n", instr[1], + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + IO_outport( instr[1], 2, AX_sig(context) ); + TRACE(io, "0x%x > %04x @ %04x:%04x\n", instr[1], + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 2; return TRUE; case 0xec: /* inb al,dx */ AL_sig(context) = IO_inport( DX_sig(context), 1 ); + TRACE(io, "0x%x < %02x @ %04x:%04x\n", DX_sig(context), + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 1; return TRUE; case 0xed: /* in (e)ax,dx */ - if (long_op) EAX_sig(context) = IO_inport( DX_sig(context), 4 ); - else AX_sig(context) = IO_inport( DX_sig(context), 2 ); + if (long_op) + { + EAX_sig(context) = IO_inport( DX_sig(context), 4 ); + TRACE(io, "0x%x < %08lx @ %04x:%04x\n", DX_sig(context), + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + AX_sig(context) = IO_inport( DX_sig(context), 2 ); + TRACE(io, "0x%x < %04x @ %04x:%04x\n", DX_sig(context), + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 1; return TRUE; case 0xee: /* outb dx,al */ IO_outport( DX_sig(context), 1, AL_sig(context) ); + TRACE(io, "0x%x > %02x @ %04x:%04x\n", DX_sig(context), + AL_sig(context), CS_sig(context), IP_sig(context)); EIP_sig(context) += prefixlen + 1; return TRUE; case 0xef: /* out dx,(e)ax */ - if (long_op) IO_outport( DX_sig(context), 4, EAX_sig(context) ); - else IO_outport( DX_sig(context), 2, AX_sig(context) ); + if (long_op) + { + IO_outport( DX_sig(context), 4, EAX_sig(context) ); + TRACE(io, "0x%x > %08lx @ %04x:%04x\n", DX_sig(context), + EAX_sig(context), CS_sig(context), IP_sig(context)); + } + else + { + IO_outport( DX_sig(context), 2, AX_sig(context) ); + TRACE(io, "0x%x > %04x @ %04x:%04x\n", DX_sig(context), + AX_sig(context), CS_sig(context), IP_sig(context)); + } EIP_sig(context) += prefixlen + 1; return TRUE; --- documentation/wine.man.orig Thu Sep 24 04:43:35 1998 +++ documentation/wine.man Sat Oct 24 12:04:41 1998 @@ -100,8 +100,8 @@ commdlg, console, crtdll, cursor, dc, dde, ddeml, ddraw, debug, dialog, dinput, dll, dosfs, driver, dsound, edit, event, exec, file, fixup, font, gdi, global, graphics, header, heap, hook, icon, imagelist, int, int21, -int31, key, keyboard, ldt, listbox, local, mci, mcianim, mciwave, mdi, menu, -message, metafile, midi, mmaux, mmio, mmsys, mmtime, module, mpr, msg, +int31, io, key, keyboard, ldt, listbox, local, mci, mcianim, mciwave, mdi, +menu, message, metafile, midi, mmaux, mmio, mmsys, mmtime, module, mpr, msg, nonclient, ntdll, ole, palette, print, process, profile, prop, reg, region, relay, resource, scroll, security, segment, selector, sem, sendmsg, shell, shm, snoop, sound, stress, string, syscolor, task, text, thread, thunk, timer, +++ documentation/ioport-trace-hints Sat Oct 24 12:58:39 1998 @@ -0,0 +1,223 @@ +cat > /dev/null < >(sed 's/^[^:]*:io:[^ ]* //' > YYYY) + +You will need large amounts of hard disk space (read hundreds of megabytes if +you do a full page scan), and for reasonable performance a really fast +processor and lots of RAM. + +You might well find the log compression program that David Campbell + wrote helpfull in reducing the size of the log files. +This can be obtained by the following command: + + sh ioport-trace-hints + +This should extract shrink.c (which is located at the end of this file. Compile +the log compression program by: + + cc shrink.c -o shrink + +Use the shrink program to reduce the physical size of the raw log as follows: + + cat log | shrink > log2 + +The trace has the basic form of + + XXXX > YY @ ZZZZ:ZZZZ + +where XXXX is the port in hexidecimal being accessed, YY is the data written +(or read) from the port, and ZZZZ:ZZZZ is the address in memory of the +instruction that accessed the port. The direction of the arrow indicates +whether the data was written or read from the port. + + > data was written to the port + < data was read from the port + + +My basic tip for interperating these logs is to pay close attention to the +addresses of the IO instructions. There grouping and sometimes proximity should +reveal the presence of subroutines in the driver. By studying the different +versions you should be able to work them out. For example consider the +following section of trace from my UMAX Astra 600P + + 0x378 > 55 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > aa @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + 0x378 > 00 @ 0297:01ec + 0x37a > 05 @ 0297:01f5 + 0x379 < 8f @ 0297:01fa + 0x37a > 04 @ 0297:0211 + +As you can see their is a repeating structure starting at address 0297:01ec +that consists of four io access on the parallel port. Looking at it the first +io access writes a changing byte to the data port the second always writes the +byte 0x05 to the control port, then a value which always seems to 0x8f is read +from the status port at which point a byte 0x04 is written to the control port. +By studying this and other sections of the trace we can write a C routine that +emulates this, shown below with some macros to make reading/writing on the +parallel port easier to read. + + +#define r_dtr(x) inb(x) +#define r_str(x) inb(x+1) +#define r_ctr(x) inb(x+2) +#define w_dtr(x,y) outb(y, x) +#define w_str(x,y) outb(y, x+1) +#define w_ctr(x,y) outb(y, x+2) + +/* + * Seems to be sending a command byte to the scanner + * + */ +int udpp_put(int udpp_base, unsigned char command) +{ + int loop,value; + + w_dtr(udpp_base, command); + w_ctr(udpp_base, 0x05); + + for (loop=0;loop<10;loop++) + if (((value=r_str(udpp_base)) & 0x80)!=0x00) { + w_ctr(udpp_base, 0x04); + return value & 0xf8; + } + + return (value & 0xf8) | 0x01; +} + + +For the UMAX Astra 600P only seven such routines exist (well 14 really, seven +for SPP and seven for EPP). Whether you choose to disassemble the driver at +this point to verify the routines is your own choice. If you do, the address +from the trace should help in locating them in the disassembly. + +You will probably then find it useful to write a script/perl/C program to +analyse the logfile and decode them futher as this can reveal higher level +grouping of the low level routines. For example from the logs from my UMAX +Astra 600P when decoded futher reveal (this is a small snippet) + + +start: +put: 55 8f +put: aa 8f +put: 00 8f +put: 00 8f +put: 00 8f +put: c2 8f +wait: ff +get: af,87 +wait: ff +get: af,87 +end: cc +start: +put: 55 8f +put: aa 8f +put: 00 8f +put: 03 8f +put: 05 8f +put: 84 8f +wait: ff + +From this it is easy to see that put routine is oftern gouped together in five +sucessive calls sending information to the scanner. Once these are understood +it should be possible to process the logs further to show the higher level +routines in an easy to see format. Once the higest level format that you +can derive from this process is understood, you then need to produce a +series of scans varying only one parameter between them, so you can +discover how to set the various parameters for the scanner. + + +Jonathan Buzzard + + + +-------------------------------------------------------------------- +The following is the shrink.c program. +EOF +cat > shrink.c < +#include + +void +main (void) +{ + char buff[256], lastline[256]; + int count; + + count = 0; + lastline[0] = 0; + + while (!feof (stdin)) + { + fgets (buff, sizeof (buff), stdin); + if (strcmp (buff, lastline) == 0) + { + count++; + } + else + { + if (count > 1) + fprintf (stdout, "# Last line repeated %i times #\n", count); + fprintf (stdout, "%s", buff); + strcpy (lastline, buff); + count = 1; + } + } +} +EOF