TTL "Port-Handler AmigaDos Device Driver" * Port-handler AmigaDos Device Driver * Copyright (c) 1986 John A. Toebes, VIII All Rights Reserved * * Permission is granted for personal usage only. * This program may not be incorporated in any commercial product or sold * for any purpose without the permission of the author. * SECTION CODE StartModule DC.L (EndModule-StartModule)/4 EntryPt EQU * * NOLIST INCLUDE "exec/types.i" INCLUDE "exec/libraries.i" INCLUDE "exec/io.i" INCLUDE "libraries/dosextens.i" LIST INCLUDE "bcpl.i" *** *** Global constants used *** FALSE EQU 0 TRUE EQU -1 IOB_size EQU 30 RAW_NAME EQU ('R'<<24)!('A'<<16)!('W'<<8) MARKER1_DATA EQU ('T'<<24)!('O'<<16)!('P'<<8)!('!') MARKER2_DATA EQU ('J'<<24)!('O'<<16)!('H'<<8)!('N') *** *** This is the global structure that we get a pointer to in A1 *** when our code is executing *** STRUCTURE PORT_HANDLER_GLOBALS,0 LONG IO_parm_pkt *Pointer to our initial packet * LONG MARKER1 * LONG EXECLIB * LONG OURCODE * LONG DOSCALL * LONG DOSRET LONG read_pkt *Pointer to user read request LONG write_pkt *Pointer to user write request BYTE openin *device is open for input BYTE openout *device is open for output WORD FILLER * to pad to a 4 byte boundary BPTR node *pointer to our DeviceList node BPTR inpkt *pointer to read transmission pkt STRUCT inpkt_buf,16 * Buffer for above BPTR outpkt *pointer to write transmission pkt STRUCT outpkt_buf,16 * Buffer for above BPTR IOB *IO request for reading from device STRUCT IOB_buf,(IOB_size*4)+8 * Buffer for above BPTR IOBO *IO request for writing to device STRUCT IOBO_buf,(IOB_size*4)+8 * Buffer for above APTR dataloc *QUE pointer-data to be written/read BPTR tpkt *QUE pointer-IO completion msg packet BPTR use_IOB *QUE pointer-IOB for IO * LONG MARKER2 BPTR FILLER1 LABEL FRAME_SIZE * * This routine is a sample device handler for * SER: The serial port * PAR: The parallel port * PRT: The installed printer * PRT:RAW The installed printer without translating LF to CR * * BCPL driver Entry conditions: * D1 - DosPacket - immediately converted to a real pointer * A0 - 0 * A1 - Pointer to our global data area * A2 - Pointer to BCPL subroutine library * A3 - * A4 - Pointer to Base of out code * A5 - Pointer to Subroutine transfer vector * A6 - Pointer to Code termination vector * * Upon initialization, D1 contains a BPTR to a DosPacket with the info: * arg1 = BPTR to BCPL string of device name * This is should be one of PRT: PRT:RAW SER: PAR: * arg2 = Extra info from the DevList entry. * 0 = SER: 1 = PAR: 2 = PRT: * arg3 = BPTR to the DevList entry * LSL.L #2,D1 *make pointer to DosPacket real * Initialize our global structure * MOVE.L A1,$CA * MOVE.L #MARKER1_DATA,MARKER1(A1) *let us see it in memory * MOVE.L #MARKER2_DATA,MARKER2(A1) * MOVE.L A2,EXECLIB(A1) * MOVE.L A4,OURCODE(A1) * MOVE.L A5,DOSCALL(A1) * MOVE.L A6,DOSRET(A1) CLR.L read_pkt(A1) *No Read request pending CLR.L write_pkt(A1) *No write request pending CLR.B openin(A1) *device not opened for input CLR.B openout(A1) *device not opened for output MOVE.L dp_Arg3(A0,D1.L),D3 LSL.L #2,D3 *make it a real pointer MOVE.L D3,node(A1) *to our DevList entry MOVEQ.L #inpkt_buf,D3 *locate our default input packet ADD.L A1,D3 MOVE.L #act_queueread,dp_Type(A0,D3.L) *and set it as a read packet LSR.L #2,D3 MOVE.L D3,inpkt(A1) MOVEQ.L #outpkt_buf,D4 *locate our default output packet ADD.L A1,D4 MOVE.L #act_queuewrite,dp_Type(A0,D4.L) *and set as write packet LSR.L #2,D4 MOVE.L D4,outpkt(A1) MOVEQ.L #IOB_buf,D5 *locate our input IO request packet ADD.L A1,D5 LSR.L #2,D5 MOVE.L D5,IOB(A1) MOVE.L #IOBO_buf,D6 *locate our output IO request packet ADD.L A1,D6 LSR.L #2,D6 MOVE.L D6,IOBO(A1) MOVEQ.L #IOB_size-1,D5 *Empty our input IOB LEA IOB_buf(A1),A3 CLRIOB CLR.L (A3)+ DBF D5,CLRIOB *** Open the device *** We have to figure out what device we will be opening MOVEQ.L #0,D4 * Flags on the open MOVE.L D4,D3 * Unit number TST.L dp_Arg2(A0,D1.L) * is it a open on SER: BEQ IS_SER MOVEQ.L #1,D2 CMP.L dp_Arg2(A0,D1.L),D2 * is it an open on PAR: BEQ IS_PAR IS_PRT LEA prt_name(A4),A3 PRT: uses printer.device BRA PUTNAME IS_SER LEA ser_name(A4),A3 SER: uses serial.device BRA PUTNAME IS_PAR LEA par_name(A4),A3 PAR: uses parallel.device PUTNAME EQU * MOVE.L A3,D2 LSR.L #2,D2 *make the name a BPTR MOVE.L IOB(A1),D1 BCALL OpenDevice TST.L D1 *did the open succeed BNE GOTOPEN *no... MOVE.L #ERROR_OBJECT_IN_USE,D3 *say it is in use MOVEQ.L #FALSE,D2 MOVE.L (A1),D1 BCALL returnpkt BEXIT GOTOPEN EQU * MOVEQ.L #IOB_size-1,D5 *get a second IOB for output LEA IOB_buf(A1),A3 LEA IOBO_buf(A1),A0 *Use only for copying - restore to 0 later COPYIOB MOVE.L (A3)+,(A0)+ DBF D5,COPYIOB MOVEQ.L #0,D5 MOVE.L D5,A0 *** Now see if they asked to put the printer into the RAW mode MOVE.L (A1),D1 LSL.L #2,D1 MOVEQ.L #2,D5 CMP.L dp_Arg2(A0,D1.L),D5 * is it a open on PRT: BNE NOTRAW MOVE.L dp_Arg1(A0,D1.L),D3 LSL.L #2,D3 CMP.L #RAW_NAME,4(A0,D3.L) *is the secondpart 'RAW\0'? BNE NOTRAW *** Build the IOB for outputing the initialization string LEA prt_init_str(A4),A3 *point to the output string MOVE.L A3,D3 MOVE.L IOBO(A1),D1 ASL.L #2,D1 MOVE.L D1,A3 MOVE.W #CMD_WRITE,D2 MOVE.L D2,IO_COMMAND(A3) ;$1C MOVE.L D3,IO_DATA(A3) ;$28 MOVEQ.L #-1,D4 MOVE.L D4,IO_LENGTH(A3) ;$24 MOVE.L IOBO(A1),D1 *DOIO(IOBO) to output the init string BCALL DoIO NOTRAW EQU * *** set taskid field to our task so everyone comes to us for the device BCALL taskid MOVE.L node(A1),D2 MOVE.L D1,dl_Task(A0,D2.L) *** We are now setup, return our initilization packet so we can *** Let the system start sending us IO requests MOVEQ.L #TRUE,D2 MOVE.L (A1),D1 IO_parm_pkt BCALL returnpkt *** Now that all the initialization is done, here is where we do all *** the work of processing the requests. Of importance to note is that *** although we have opened the device, the real request to open the *** device comes (usually) as the first message to our task. *** *** Events come to us in the form of a DosMessage with the type of *** event in the type field of the packet *** We only need to handle a few of these events and can just send *** the rest back as invalid requests *** *** The ones we handle are: *** 'R' - A request to read from the device *** 'W' - A request to write to a device *** 1001 - A read WE posted to the device completed *** 1002 - A write WE posted to the device completed *** 1005 - The user wishes to open the device we handle for input *** 1006 - The user wishes to open the device we handle for output *** 1007 - The uses wishes to terminate an open on our device *** *** Register usage: *** D1 - BCPL pointer to event message packet *** D2 - real pointer to event message packet - until changed *** *** Wait for the next message LOOP EQU * BCALL taskwait MOVE.L D1,D2 LSL.L #2,D2 *** Now see what type of message it was MOVE.L dp_Type(A0,D2.L),D3 MOVEQ.L #'R',D4 CMP.L D4,D3 *read BEQ do_R MOVEQ.L #'W',D4 CMP.L D4,D3 *write BEQ do_W CMP.L #act_queueread,D3 *act.read BEQ do_read CMP.L #act_queuewrite,D3 *act.write BEQ do_writ CMP.L #act_findinput,D3 *find input BEQ do_old CMP.L #act_findoutput,D3 *find output BEQ do_new CMP.L #act_end,D3 *end BEQ do_end BRA do_dflt *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Open up our device for input *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_old TST.B openin(A1) *make sure it isn't already open for input BNE IN_USE ST openin(A1) *Say we have the device for input MOVE.L #MODE_OLDFILE,D3 BRA SET_SCB *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Open up our device for output *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_new TST.B openout(A1) BNE IN_USE ST openout(A1) *Say we have the device for output MOVE.L #MODE_NEWFILE,D3 SET_SCB MOVE.L dp_Arg1(A0,D2.L),D4 LSL.L #2,D4 MOVE.L D3,fh_Arg1(A0,D4.L) *and set the access mode MOVEQ.L #TRUE,D5 MOVE.L D5,fh_Interactive(A0,D4.L) * Mark file as interactive BRA OK_RET *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Close the device for input/output *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_end CMP.L #MODE_OLDFILE,dp_Arg1(A0,D2.L) BNE closout CLR.B openin(A1) *device no longer needed for input BRA doclose closout CLR.B openout(A1) *device no longer needed for output doclose EQU * *** If this closed both files then it is time to shut down TST.B openin(A1) BNE OK_RET TST.B openout(A1) BNE OK_RET MOVE.L node(A1),D3 *find our devicelist entry CLR.L dl_Task(A0,D3.L) *remove our process id from the entry BRA OK_RET *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Here we have a read request we posted returning to us *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_read MOVE.L D1,inpkt(A1) *restore our packet for posting reads MOVE.L read_pkt(A1),D1 *the message to return to the user LEA IOB_buf(A1),A3 *the IO request that returned BRA CHK_RET *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Here we have a write request we posted returning to us *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_writ MOVE.L D1,outpkt(A1) *restore out packet for posting writes MOVE.L write_pkt(A1),D1 *the message to return to the user LEA IOBO_buf(A1),A3 *the IO request that returned CHK_RET MOVEQ.L #0,D3 MOVE.B IO_ERROR(A3),D3 *get the error code if any BNE BAD_RET *any error? MOVE.L IO_ACTUAL(A3),D2 *return number of bytes read BRA RET_PKT *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Here we have a request from the user to do a read *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_R MOVE.L D1,read_pkt(A1) MOVE.L inpkt(A1),tpkt(A1) CLR.L inpkt(A1) *Indicate input in progress MOVEQ.L #CMD_READ,D4 MOVE.L IOB(A1),D1 BRA QUE_PKT *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Here we have a request from the user to do a write *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_W MOVE.L D1,write_pkt(A1) MOVE.L outpkt(A1),D3 CLR.L outpkt(A1) *Indicate an output is in progress MOVEQ.L #CMD_WRITE,D4 MOVE.L IOBO(A1),D1 *** To queue an IO request we need to have set up: *** D1 - BCPL pointer to the desired IOB *** D2 - The real pointer to the input request message *** D3 - message packet associated with the request *** D4 - I/O request type to be queued QUE_PKT MOVE.L D1,D5 ASL.L #2,D5 MOVE.L D5,A3 MOVE.W D4,IO_COMMAND(A3) ;$1C MOVE.L dp_Arg2(A0,D2.L),IO_DATA(A3) ;$28 MOVE.L dp_Arg3(A0,D2.L),IO_LENGTH(A3) ;$24 CLR.L IO_OFFSET(A3) ;$28 MOVE.L D3,D2 BCALL SendIO BRA LOOP *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *** *** Here we handle all other requests we do not recognize *** *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - do_dflt TST.B openin(A1) BNE BAD_ACT TST.B openout(A1) BNE BAD_ACT MOVE.L node(A1),D1 *keep them from bothering us anymore CLR.L dl_Task(A0,D1.L) BAD_ACT EQU * MOVE.L #ERROR_ACTION_NOT_KNOWN,D3 BRA BAD_RET *** *** Here we return the message to the user *** IN_USE MOVE.L #ERROR_OBJECT_IN_USE,D3 *the device is in use BAD_RET MOVEQ.L #FALSE,D2 *Operation had failed BRA RET_PKT OK_RET MOVEQ.L #TRUE,D2 *Operation has succeeded RET_PKT BCALL returnpkt *D1 already has the packet address in it LOOPIT TST.B openin(A1) *is there anyone open on us? BNE LOOP TST.B openout(A1) BNE LOOP TST.L outpkt(A1) *or an output pending? BEQ LOOP TST.L inpkt(A1) *or an input pending? BEQ LOOP *** *** Our purpose in life is fullfilled, close the device *** and quietly fade off into the sunset *** MOVE.L IOB(A1),D1 BCALL CloseDevice BEXIT CNOP 0,4 ser_name EQU *-EntryPt DC.B 14,'serial.device',0 CNOP 0,4 par_name EQU *-EntryPt DC.B 16,'parallel.device',0 CNOP 0,4 prt_name EQU *-EntryPt DC.B 15,'printer.device',0 CNOP 0,4 prt_init_str EQU *-EntryPt DC.B $1B,'[20l',0 *** *** Trailer stuff to make this look like a BCPL module *** CNOP 0,4 DC.L 0 DC.L 1 DC.L EntryPt-StartModule DC.L (FRAME_SIZE/4)+2+$44 EndModule EQU * END