| cat > /dev/null <<EOF | |
| The above line is necessary, leave it alone!! | |
| -------------------------------------------------------------------- | |
| DOING A HARDWARE TRACE IN WINE | |
| ------------------------------ | |
| The primary reason to do this is to reverse engineer a hardware device | |
| for which you don't have documentation, but can get to work under Wine. | |
| This lot is aimed at parallel port devices, and in particular parallel port | |
| scanners which are now so cheap they are virtually being given away. The | |
| problem is that few manufactures will release any programming information which | |
| prevents drivers being written for Sane, and the traditional technique of using | |
| DOSemu to produce the traces does not work as the scanners invariably only have | |
| drivers for Windows. | |
| Please note that I have not been able to get my scanner working properly (a | |
| UMAX Astra 600P), but a couple of people have reported success with at least | |
| the Artec AS6e scanner. I am not in the process of developing any driver nor do | |
| I intend to, so don't bug me about it. My time is now spent writting programs | |
| to set things like battery save options under Linux on Toshiba laptops, ans as | |
| such I don't have any spare time for writting a driver for a parallel port | |
| scanner etc. | |
| Presuming that you have compiled and installed wine the first thing to do is is | |
| to enable direct hardware access to your parallel port. To do this edit | |
| wine.conf (usually in /usr/local/etc) and in the ports section add the | |
| following two lines | |
| read=0x378,0x379,0x37a,0x37c,0x77a | |
| write=0x378,x379,0x37a,0x37c,0x77a | |
| This adds the necessary access required for SPP/PS2/EPP/ECP parallel port on | |
| LPT1. You will need to adjust these number accordingly if your parallel port is | |
| on LPT2 or LPT0. | |
| When starting wine use the following command line, where XXXX is the program | |
| you need to run in order to access your scanner, and YYYY is the file your | |
| trace will be stored in: | |
| wine -debugmsg +io XXXX 2> >(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 | |
| <campbell@torque.net> 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 often grouped together in five | |
| successive 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 highest 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 | |
| <jab@hex.prestel.co.uk> | |
| -------------------------------------------------------------------- | |
| The following is the shrink.c program. | |
| EOF | |
| cat > shrink.c <<EOF | |
| #include <stdio.h> | |
| #include <string.h> | |
| 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 |