Making a Scanner Driver ======================= A scanner driver is made as an Amiga Device. The Device I/O request ---------------------- The scanner device uses a special I/O request: struct ScannerIO { struct IOStdReq IOScan; struct ScannerOptions option; } where struct IOStdReq is a standard IO request as defined in exec/io.h and struct ScannerOptions is defined in the include file scanner.h Before opening the device BetaScan places a pointer to a string containing the name of the IO unit where the scanner is connected (for instance scsi.device) in the IOScan.io_Data field. Then the open device is called: OpenDevice(scannerName,unit,(struct IORequest *)ScannerIO,0) where unit is the unit number of the IO unit. The open routine must do the necessary initializations and then set the fields in the structure option: struct ScannerOptions { char so_scannerVendor[40]; char so_scannerModel[40]; UBYTE so_driverVersion; UBYTE so_driverRevision; double so_docWidth; /* Paper size in mm */ double so_docHeight; UWORD so_flags; /* Not used */ UWORD so_optionNum; /* Number of option descriptors */ struct OptionDescriptor* so_descriptor; }; The structure OptionDescriptor has the form: struct OptionDescriptor { OptionId od_optionID; ValueType od_valueType; ValueUnit od_valueUnit; Constraint od_constraintType; union { char** stringList; /* Null terminated array of string values */ int* numberList; /* Legal values - numberList[0] = number */ Range* numberRange; } od_constraint; void* od_specialInfo; /* See below */ }; More information in headerfile scanner.h. The following options must be present: ID_SCANMODE /* BW, Gray, RGB etc. */ ID_TL_X /* upper left corner of scan area */ ID_TL_Y /* upper left corner of scan area */ ID_BR_X /* bottom right corner of scan area */ ID_BR_Y, /* bottom right corner of scan area */ ID_RESOLUTION /* scan resolution (combined x and y) */ The scan area options (ID_TL_.. and ID_BR_..) must have units in mm. IO Commands ----------- The device must respond to the following commands (more info in scanner.h): CMD_START - Start scanning The scanning parameters must have been set before (SCANCMD_CONTROL). The IOScan.io_Data field contains a pointer to a structure struct ScanInformation { double sv_xResolution; /* actual horizontal resolution */ double sv_yResolution; /* actual vertical resolution */ LineFormat sv_lineFormat; /* format of scan lines */ UWORD sv_imageWidth; /* image width in pixels */ UWORD sv_imageHeight; /* image height in pixels */ UWORD sv_imageDepth; /* image depth in bits */ UWORD sv_bytesPerLine; /* bytes per line read */ ULONG sv_Flags; /* data information flags */ } Most scanners must do some roundings so that your scanner parameters are not exactly the actual ones. Fill in the actual parameter values in this structure. CMD_STOP - Stop scanning This command is always send (even if the driver has send all scan lines or has reported an error). CMD_READ - Read one or more scan lines The IOScan.io_Data field contains a pointer to a scan line structure struct ScanLine { UBYTE* sl_data; LineFormat sl_color; /* If sv_lineFormat is FORMAT_RGB_RANDOM */ } /* this is either FORMAT_RED, FORMAT_GREEN */ /* or FORMAT_BLUE. Otherwise it must be the */ /* same as sv_lineFormat. */ IOScan.io_Length the buffer length. Return the actual number of bytes returned (an integral multiple of sv_bytesPerLine). SCANCMD_CONTROL - Set/Get option values The field IOScan.io_Data contains a pointer to the structure (found in scanner.h): struct OptionValue { OptionId sp_optionID; int sp_value; ULONG sp_flags; }; sp_optionID field is the indentification number of the option value you want to control. sp_value is the option value send to or returned from the driver. The value type is the same as given in the option descriptor. For TYPE_STRING the value is the index value. sp_flags tells how to control the option. The values are CONTROL_SET (1<<0) /* Set new value */ CONTROL_GET (1<<1) /* Return current value */ Both bits can be set. The following bits may be set at return: CONTROL_ROUNDED (1<<16) /* Value set is not exact */ CONTROL_RANGE (1<<17) /* Out of range - not set */ CONTROL_DISABLED (1<<18) /* Option disabled - not set */ CONTROL_INVALID (1<<19) /* Option not supported */ The command may be send without CONTROL_SET or CONTROL_GET bits set to get information about the option. Actual development ------------------ To avoid making all the nasty device stuff and to facilitate the testing you can use the files in the ScannerDev directory (SAS/C 6.57). By using these files you only have to make a single file with the following routines: void openScanner(char* name,int unit,struct ScannerOptions* option,BYTE* status) This is called when the scanner device is opened. input: name: name of the IO unit unit: number of the IO unit option: pointer to the option structure status: the return value (io_Error) void closeScanner(void) Close the scanner void controlOption(struct OptionValue* optVal,BYTE* status) Set scanning parameters input: optVal: pointer to an OptionValue structure status: the return status void startScanning(struct ScanInformation* inform,BYTE* status) Start the scanning input: inform: a pointer to a ScanInformation structure to be filled by you. status: the return value void stopScanning(void) Stop the scanning void readScanLine(struct ScanLine* line,BYTE* status) Read one ore more scan line(s) input: line: pointer to a scan line structure status: the return status An example file is in ScanDev directory (in fact divided into two: ScanmakerE3.c and Scsi.c). To make a test version execute the command: smake -f smakeTest The resulting executable is called scanner. To make a device execute smake -f smakeDevice The linker will make 4 warnings about absolute addressing. Don't care.