[sane-devel] check-usb-chip request for help

Henning Meier-Geinitz henning@meier-geinitz.de
Fri, 25 Jun 2004 18:58:40 +0200


Hi,

On Fri, Jun 25, 2004 at 12:16:27PM +0100, Ioan-Cosmin Pop wrote:
>   Henning, you keep telling me about the "protocol of
> the scanner", "commands" and "registers". Can you
> please tell me what they mean? OK, I know this sounds
> stupid. I know what a protocol, command or register
> is. Back in the good ol' DOS days (well, not so good,
> but old for sure) I used to read/write to a specific
> port and mess with the device registers (an aquisition
> device in my case). I can only make some suppositions.
> Please tell me if I'm correct and if I'm on the right
> way.
> - for the "protocol", I think this is something like:
> buffered or direct;

No. What I mean by "protocol" is how the driver/backend communicates
with the scanner. As an example, I'll describe the protocol of the
GrandTech GT6801 chipset. Your scanner's protocol will be completely
different most probably.

Commands and data are sent to the scanner as USB control messages with
a data size of 64 bytes. The request, request_type, value etc. depend
on the type of command. E.g. you can send commands, receive results
from commands, write data to scanner's RAM (firmware) and read from
the RAM.

This is an example for a command sent to the scanner (from a sniffusb
log of a Mustek BearPaw 2400 TA Plus:

| >>>  URB 525 going down >>>
| -- URB_FUNCTION_VENDOR_DEVICE:
|         TransferFlags                   = 00000000
| 	(USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER

The data is sent from the host to the scanner.

| 	TransferBufferLength    = 00000040

64 bytes of data.

|         TransferBuffer          = c1b6b000
|         TransferBufferMDL       = 00000000
|                 0000: 20 01 0f 01 29 05 a4 00 58 02 82 20 64 00 01 00

The data itself. For the gt6801, the first byte is the command code.
0x20 means "setup scan". The second byte is alway 01. Bytes 2+3 and
3+4 are the Y coordinates of the scan widow (Y0 + height). The first
byte is the low byte. In this case the height is 0x0529 = 1321. As
these coordinates are based on 1200 dpi, the height is 1.1 inches in
this case. Byte 0x0a ("82") means gray mode. Byte 0x0c ("64") and 0x0d
("00") are the resolution: 0x0064 = 100 dpi.

|                 0010: 64 00 73 00 0b 00 64 00 3c 00 00 00 00 00 00 00
|                 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|                 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

More settings like lamp, backtracking, bytes per line etc.

|         UrbLink                         = 00000000
|         RequestTypeReservedBits = 00
|         Request                         = 01
|         Value                           = 2010

That means "send a command". For writing firmware "200b" would be used.

|         Index                           = 3f40

Not used here but for firmware writes that would be the memory address
to write to.

Now the data is sent. As confirmation you get the URB back from the
(Windows) operating system (see the same URB number):

|   <<<  URB 525 coming back  <<< 
| -- URB_FUNCTION_CONTROL_TRANSFER:
|         PipeHandle               = C1AD431C
|         TransferFlags           = 00000002
| 	(USBD_TRANSFER_DIRECTION_OUT, USBD_SHORT_TRANSFER_OK)
|         TransferBufferLength    = 00000040
|         TransferBuffer          = c1b6b000
|         TransferBufferMDL       = c1800880
|         UrbLink                 = 00000000
|         SetupPacket             : 40 01 10 20 40 3f 40 00

The setup packet is the same as above but this time it's not split in
request, value etc. See the USB spec for details.

Now we ask for the result of the command we just sent:
|  >>>  URB 526 going down  >>>
| -- URB_FUNCTION_VENDOR_DEVICE:
|         TransferFlags                   = 00000001
| 	(USBD_TRANSFER_DIRECTION_IN, ~USBD_SHORT_TRANSFER_

We want to receive data from the scanner (DIRECTION_IN).

| 	TransferBufferLength    = 00000040

We want to get 64 bytes.

|         TransferBuffer          = e3c09d1c
|         TransferBufferMDL       = 00000000
|         UrbLink                         = 00000000
|         RequestTypeReservedBits = 00
|         Request                         = 01
|         Value                           = 2011

That means: "Read result of command".

|         Index                           = 3f00
	
See above. Ok, now the result:

|  <<<  URB 526 coming back  <<< 
| -- URB_FUNCTION_CONTROL_TRANSFER:
|         PipeHandle               = C1AD431C
|         TransferFlags           = 00000003
| 	(USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
|         TransferBufferLength    = 00000040
|         TransferBuffer          = e3c09d1c
|         TransferBufferMDL       = c1800880
|                 0000: 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00

The first 00 means that the command succeeded. The second byte "20"
repeats the command we sent ("setup scan"). Other commands may return
more data (e.g. the status of scan buttons or a flag if the scan head
is at its home position).

The actual scan data is read by bulk reads.

That's what I mean by a "protocol". Other chipsets don't use commands
(or functions) like in this case but you can set registers. E.g. you
could use a three byte block of data sent by bulk messages:

01 02 03

01 --> type = write register
02 --> register number
03 --> value to write to the register

That's just a protocolo I made up :-)

> - for commands, I have some "IOCTL functions"
> - as for "registers", I really have no idea.

The scanner's chipset may have a buch of registers to which you can
write data. E.g. One register may contain the resolution. When setting
a bit in another register you could start scanning. Think of registers
as processor registers.

>   What I have so far, are some macros (taken from the
> windows sources), like IOCTL_GET_VERSION,
> IOCTL_WRITE_REGISTERS, IOCTL_READ_REGISTERS and so on.

Probably that's how the Windows low level scanner driver is accessed.
This low level driver is able to do basic stuff like writing the
scaynners registers. The higher level software talks to it via ioctls.
(Just a guess but that's similar to how it works with Linux).

>   I think I really need some help, somebody to talk
> to. Ronald Humphries, do you read this? If you do have
> some spare time, can you please send me a message? I
> can't send you the windows sources because I am bound
> by an NDA (non-disclosure agreement) with Mustek, but
> I'm sure we can cut a deal with them to offer you the
> same info they gave me...:)

Try to go down to the lowest level of the Windows source code. Look
for functions that actually write to the scanner.

Bye,
  Henning