Buffer Manager ============== The buffer manager provides a global buffer managing system, it provides a set of calls for setting up a buffer, inserting and removing data from a buffer and finally removing a buffer. It is also possible to setup an area of memory to be used as a buffer. The buffer manager extends the INSV, REMV and CNPV to provide access to these buffers and also allow block transfers. The buffer manager is used by DeviceFS to provide buffers for the various devices that can be accessed. A device may be linked to a buffer supply routines to be called when data enters the buffer and also a routine to be called when a buffer is removed (or a new device is attached). When registering or creating a buffer it is possible to force a specific buffer handle, if this feature is not used then the manager will asign a unique handle to it. It should be noted that buffer handles are no longer stored as eight bit quanities. Block transfers are signalled by setting bit 31 of the buffer handle, anything which can be performed on a byte by byte basis can also be performed on a block, eg. examine the buffer contents. SWI interface ============= Buffer_Create ------------- in: r0 = flags for the buffer bit 0 =0 => buffer is dormant and should be woken up when data enters it bit 1 =1 => buffer generates "output buffer empty" events bit 2 =1 => buffer generates "input buffer full" events bit 3 =1 => buffer generates upcalls when free space threshold crossed (from above or below) bits 4-31 reserved for future expansion, should be set to zero on creation r1 = size of buffer to be created r2 = buffer handle to assign to buffer, -1 for does not matter out: V =0 => r0 = buffer handle V =1 => r0 -> error block This routine claims an area of memory from the RMA and links it into the buffer list, if r2 =-1 then the buffer manager will attempt to find a unique handle, if r2 <>-1 then the buffer manager will check that the handle specified is unique and then if it is assign it to that buffer. The flags word is used to indicate what should happen when data is being inserted and removed from the buffer. Bit 0 is used to indicate if the device attached to the buffer has been woken up, when =0 then the device is dormant and needs to be woken. When a device is attached and data is put into the buffer this bit is checked, if it is =0 then the wake up code for the device will be called allowing any device to wake up any hardware it may be driving and to start processing data within the buffer. Bit 1 is used to indicate if "output buffer empty" events should be issued for this buffer. Bit 2 is used to indicate if "input buffer full" events should be issued for this buffer. Bit 3 is used to indicate if buffer threshold UpCalls should be issued for this buffer. On exit r0 contains the buffer handle being used or a pointer to an error block. Buffer_Remove ------------- in: r0 = handle of buffer to be removed out: V =1 => r0 -> error block, else preserved This call should only be made on buffers created using Buffer_Create. It attempts to de-register the buffer from the active list and assuming that worked ok it will attempt to free the memory relating to that buffer. Buffer_Register --------------- in: r0 = flags for buffer (see above) r1 -> start of memory for buffer r2 -> end of buffer (+1) r3 = handle to be assigned to buffer (-1 if to be generated) out: V =0 => r0 = handle for buffer V =1 => r0 -> error block This call registers an area of memory as a buffer, the routine accepts similar parameters to the Buffer_Create SWI, but instead of the call claiming tha area of memory for you, you must actually specify the buffer's start and end addresses. It is not advisable to put buffers in application workspace, this area of memory can be switched out when someone else tries to access it. It is however possible for your task if it is going to be the only one using this buffer, and it will only be accessed whilst the task is currently paged in to register a buffer within its workspace. For further details about the flags word and the specified buffer handle see the Buffer_Create call. Buffer_Deregister ----------------- in: r0 = handle of buffer to be deregistered. out: V =0 => all preserved. V =1 => r0 -> error block. This call will simply unlink a buffer from the active list, the data within the buffer will be purged and any access to this buffer via INSV, REMV and CNPV will be ignored. Do not use this call if you have created the buffer using Buffer_Create, instead use Buffer_Remove which releases any memory that may have been claimed. Buffer_ModifyFlags ------------------ in: r0 = handle of buffer to be modified r1 = EOR mask r2 = AND mask out: r1 = old value r2 = new value This call allows you to modify the flags word stored with each buffer, the SWI allows two registers to be ANDed and then EORed with the current flags word, on exit the old and new values of this word are returned to the caller. r1, r2 are applied as follows: new = (old AND r2) EOR r1 The caller should not modify reserved flag bits when issuing this call, ie bits 4 to 31 should be set in r2 and clear in r1. Buffer_LinkDevice ----------------- in: r0 = buffer handle, r1 -> code to wake up device when needed (0 => none) r2 -> code to call when device to be detached (0 => cannot be detached) r3 = private word to be passed in r4 -> workspace for above routines out: V =1 => r0 -> error block, else all preserved. This call links a set of routines to the specified device, the caller supplies two routines, one to be called when data enters the buffer and another to be called when someone else attempts to link to the buffer. r1 this contains a pointer to the routine to be called when data enters the buffer and it is currently marked dormant, the routine can be entered in any mode and with FIQs or IRQs enabled / disabled, the mode should be preserved as should the interrupt state. The registers to the wake up code are setup as follows: in: r0 = buffer handle r8 = private word (specified in r3 in SWI Buffer_LinkDevice) r12 -> workspace for routine (specified in r4 in SWI Buffer_LinkDevice) out: all should be preserved, including PSR. The buffer manager automatically marks the buffer as active (non-dormant) before calling the wake up code. If the caller to Buffer_LinkDevice specifies a routine pointer equal to zero then no wake up call is made. The second routine supplied is a routine to be called whenever the owner of the buffer is about to change; if this value is zero then the device is indicating that the owner can never be changed and changing it will result in an error. The routine if supplied gets called as follows: in: r0 = buffer handle r8 = private word r12 -> workspace for the calls out: V =1 => r0 -> error block V =0 => all preserved On return from this routine the routine can return an error, any errors returned halt the detach process. The detach routines are called when someone attempts to kill the buffer manager module, this results in an error and the buffer manager refuses to die. When attaching to a buffer it is possible that the SWI will fail, this is likely to be because the current owner is refusing to detach itself. Buffer_UnlinkDevice ------------------- in: r0 = buffer handle out: V =0 => all preserved and device detached. V =1 => r0 -> error block. This routine will unlink a device from a buffer, no warning if given of the detach and the data that is currently stored within the buffer is purged. This call should only be used by the actual device that called Buffer_LinkDevice, anyone else calling this SWI could confuse the system. Buffer_GetInfo -------------- in: r0 = buffer handle out: V =1 => r0 -> error block V =0 => r0 = flags relating to buffer r1 -> start of buffer in memory r2 -> end of buffer in memory (+1) r3 = insert index for buffer r4 = remove index for buffer r5 = remaining free space in buffer r6 = number of characters in buffer This call returns data about the buffer, its position in memory, flags, insert and remove offsets and the amount of free space. Buffer_Threshold ---------------- in: r0 = buffer handle r1 = threshold / 0 none / -1 to read out: r1 = previous value This call is used to set/read the warning threshold of the buffer. This is used to trigger UpCalls if bit 3 of the buffer flags is set. The UpCalls are issued when the amount of free space in the buffer crosses the threshold value (see the UpCalls section below) Vector calls ============ The SWIs for the buffer manager module allow you to modify and tinker with the actual buffer itself, they do not however supply a way of inserting and removing data from these buffers. Extensions have been made to the three vectors; InsV, RemV and CnpV to handle the inserting and removing of data from the buffers, these calls have also been extended to allow block inserts. For compatibility marking a block operation is done by setting bit 31 of the buffer handle. This changes the specification for calling these vectors as follows: InsV ---- in: r0 = byte to be inserted r1 = buffer handle (bit 31 is clear) out: r0, r1 preserved r2 corrupt or:- in: r1 = buffer handle (bit 31 is set) r2 -> first byte of data to be inserted r3 = number of bytes to insert out: r0, r1 preserved r2 -> remaining data to be inserted r3 = number of bytes still to be inserted On both calls C is used to indicate if the insertion failed, if C=1 then it was not possible to insert all the specified data, or the specified byte. RemV ---- in: r1 = buffer handle (bit 31 clear) out: r0 = next byte to be removed (for examine only) r1 = preserved r2 = byte removed (for remove only) or:- in: r1 = buffer handle (bit 31 set) r2 -> buffer to be filled r3 = number of bytes to place into buffer out: r0, r1 preserved r2 -> updated buffer position r3 = number of bytes still to be removed On both of the above calls V =1 on entry indicates that the data should be copied out (examine) and V =0 indicates that the data should actually be removed. On exit C is used to indicate if the calls actually worked and if a byte or the requested block of data could be obtained. CnpV ---- Unchanged, except it copes with buffer manager buffers. Events ====== With the changes required to InsV, RemV and CnpV calls to cope with the new buffers and block transfers some of the events have been extended to cope with indicating that a block transfer occurred. For further details of the events and when they are generated consult the PRM, as this remains unchanged. Event_OutputEmpty ----------------- in: r0 = Event_OutputEmpty (0) r1 = buffer handle out: all preserved. This is issued when the last character is removed from a buffer which has output empty events enabled (see description of buffer flags). Event_InputFull --------------- in: r0 = Event_InputFull (1) r1 = buffer handle (bit 31 clear) r2 = character not inserted or:- r0 = Event_InputFull (1) r1 = buffer handle (bit 31 set) r2 -> data not inserted r3 = number of bytes not inserted out: all preserved. This event is generated when a character or block is inserted into a buffer which has input full events enabled (see description of buffer flags), and the insertion failed. Service calls ============= Service_BufferStarting (&6F) ---------------------------- in: r1 = Service_BufferStarting (&6F) out: all preserved. This call is passed around after the module has been initialised or reset. It allows module which wish to register buffers with the buffer manager to do so. When the service is received all SWIs are valid. UpCalls ======= UpCall_BufferFilling (8) ------------------------ in: r0 = 8 r1 = Buffer handle r2 = 0 out: - This is issued when data is inserted into the buffer and the free space becomes less than the specified threshold. UpCall_BufferEmptying (9) ------------------------- in: r0 = 9 r1 = Buffer handle r2 = -1 out: - This is issued when data is removed from the buffer and the free space becomes greater than or equal to the current threshold.