;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;      /*****************************************************************/
;      /*                                                               */
;      /*                                                               */
;      /*****************************************************************/
;      /******************* START OF SPECIFICATIONS *********************/
;      /*                                                               */
;      /*  SOURCE FILE NAME: PENDD.ASM                                  */
;      /*                                                               */
;      /*  DESCRIPTIVE NAME: Serial digitizer device driver sample      */
;      /*                                                               */
;      /*                                                               */
;      /*  STATUS:  Version 1.0                                         */
;      /*                                                               */
;      /*  NOTES: This is a sample device dependent driver module       */
;      /*                                                               */
;      /*  ENTRY POINTS:                                                */
;      /*      See public statements                                    */
;      /*  EXTERNAL REFERENCES:                                         */
;      /*      See extrn statements                                     */
;      /*                                                               */
;      /******************* END  OF  SPECIFICATIONS *********************/
.xlist
  include pensegs.inc
  include pen.inc
  include penei.inc
  include penidc.inc
  include penioctl.inc
  include serial.inc
  include devsym.inc
  include struc.inc
.list

.286p

;------------------------------------------------------------------------------
;declare data values
;------------------------------------------------------------------------------

  extrn DDHdr1 : byte
  extrn dcb0 : byte

;------------------------------------------------------------------------------
;declare external routines
;------------------------------------------------------------------------------

extrn Ser_Init : near
extrn Ser_FIFO : near
extrn Ser_DoOut : near
extrn Ser_DoIn : near
extrn Ser_DoPut : near
extrn Ser_EnableInts : near
extrn Ser_DisableInts : near
extrn Ser_InterruptHandler : near

extrn Gio_AddDCB : near
extrn Loc_Engine : near
extrn Loc_ForceClear: near
extrn But_Engine : near
extrn But_CalcCaps : near
extrn Dsp_Engine : near
extrn Dsp_SetInactPeriod : near
extrn Tim_Mill2Tick : near
extrn Loc_ProxFilterTC : near
extrn Loc_ProxFilter   : near
extrn Vmc_Change : near
extrn Vmc_LcdType : near

extrn SetDeviceName : near
extrn SetDriverName : near
extrn skip_to_white : near
extrn skip_white : near
extrn str_i_cmp : near
extrn to_upper : near
extrn get_hex_num : near

;------------------------------------------------------------------------------
; local equates
;------------------------------------------------------------------------------

DRIVER_LEV_MAJOR equ 0
DRIVER_LEV_MINOR equ 1

; button configuration

NUM_BUTTONS      equ  1

; display configuration

PERIOD_DEFAULT   equ  300 ; default inactivity period is 5 minutes(300 seconds)
AUTO_DEFAULT     equ  1   ; 1 =auto is enabled 0=auto is disabled

; hardware configuration

SYNCBIT       equ   80h
PEN_BUTTON    equ   02h  ; side button is down
PEN_CONTACT   equ   01h  ; pen in contact
PEN_INVALID   equ  0DCh  ; these should not be on in last byte of packet
PACKET_BYTECOUNT equ 7

;------------------------------------------------------------------------------
; extend the device control block for this device
;------------------------------------------------------------------------------

dd_DCB struc
  db size DCB_LOC dup (0)  ; reserve room for common DCB

  ; allocate device dependent stuff

  proxBox       db  size BOX_FILTER dup (0) ; reserve room for the filtering
  byteCount     dw  0  ; to keep tract of collecting digitizer bytes
  tickCount     dw  0  ; to clean up incase of a      digitizer packet
  @Serial       dw  0  ; Addr to serial struc
  mEvent        db  PACKET_BYTECOUNT dup (0) ; array to collect digitizer bytes

dd_DCB ends

bt_DCB struc
  db size DCB_BUT dup (0)  ; reserve room for common DCB
bt_DCB ends

dt_DCB struc
  db size DCB_DISP dup (0)  ; reserve room for common DCB
dt_DCB ends

DSEG segment
;---- DATA FOR FIRST LOCATOR DEVICE -------------------------------------------
;
; each locator device must have:
;       1) Locator Device Control Block (DCB)
;       2) Mouse device configuration data
;       3) Device capabilities for registration
;       4) Locator extended interface event buffer
;------------------------------------------------------------------------------
public dcb1
dcb1          dd_DCB <>
deviceData1   DevData <size DevData,20,3,4,4,1>
regCaps1      LCAP <>
locEvent1     LEV  <>
; Unit Variables (UVARS) follows UVARS struc format for locator
UVAR_COUNT    equ  1
numUVars DD UVAR_COUNT
UVarss   DD UVAR_COUNT dup (0)
;------- device specific per device data
serial1       Serial <1,03f8h,4,6,3,0Bh,1>  ; type 1
serial2       Serial <2,02f8h,3,0Ch,3,0Bh,1>; type 2

public Dev_ErrorCount
  Dev_ErrorCount dd 0 ; times we got a     packet (just for debug)

;---- DATA FOR BUTTON DEVICE --------------------------------------------------
;
; each button device must have:
;       1) Button Device Control Block (DCB)
;       2) Device capabilities for registration
;       3) Extended interface event buffer
;------------------------------------------------------------------------------
public dcbb
dcbb          bt_DCB <>
regCapsb      BCAP <>
butEvent      BEV  <>
ButDefArray   label byte
              BUT_DEF <SHIFTBUTTON,MOUSEBUTTON2>

; Unit Variables (UVARS) follows UVARS struc format for locator
BUVAR_COUNT    equ  1
bnumUVars DD BUVAR_COUNT
bUVarss   DD BUVAR_COUNT dup (0)

;---- DATA FOR DISPLAY DEVICE -------------------------------------------------
;
; each button device must have:
;       1) Bisplay Device Control Block (DCB)
;       2) Device capabilities for registration
;       3) Extended interface event buffer
;------------------------------------------------------------------------------
public dcbd
dcbd          dt_DCB <>
regCapsd      DCAP <>
disEvent      DEV  <>
; Unit Variables (UVARS) follows UVARS struc format for display
DUVAR_COUNT    equ  1
dnumUVars DD DUVAR_COUNT
dUVarss   DD DUVAR_COUNT dup (0)

;---- OTHER STUFF -------------------------------------------------------------
; other stuff
;------------------------------------------------------------------------------
cnf_type dw 1 ; config.sys type=
cnf_init dw 0 ; =0 initialize serial late, =1 initialize serial early
public Dev_Lev_Major,Dev_Lev_Minor
  Dev_Lev_Major db  DRIVER_LEV_MAJOR
  Dev_Lev_Minor db  DRIVER_LEV_MINOR

DSEG ends

;------------------------------------------------------------------------------
; Initialization data to be free at end of the init command
;------------------------------------------------------------------------------

DSEGI SEGMENT
  driverName    db  'PENDD$  '            ; driver name (8 chars)
  deviceName1   db  'Digitizer Mod 1                ',0   ; driver device name - type 1
  deviceName2   db  'Digitizer Mod 2                ',0   ; driver device name - type 2
  deviceName3   db  'Digitizer Mod 3                ',0   ; driver device name - type 3
  deviceNamel   db  'Pen                            ',0   ; locator device name
  deviceNameb   db  'Barrel Button                  ',0   ; button device name
  deviceNamed   db  'LCD                            ',0   ; display device name

  opt_type      db  'TYPE=',0
  opt_init1     db  'SERIALINIT=EARLY',0
  opt_init2     db  'SERIALINIT=LATE',0

; the following fields have different values depending on the TYPE= parm
; values are defaults for TYPE = 1

cnf_xExtent        dd 1920   ; in device cooridinates
cnf_yExtent        dd 1440
cnf_xStdExtent     dd 7750   ; in standard 1/000 of inch coordinates
cnf_yStdExtent     dd 5750
cnf_xOriginDefault dw 0
cnf_yOriginDefault dw 0
cnf_xRes           dw 250
cnf_yRes           dw 250
cnf_haveDsp        db 1        ; need a display device =1 no display device=0
cnf_@serial        dw serial1

DSEGI ends

CSEG segment
     ASSUME    CS:CGROUP, SS:nothing, ES:nothing, DS:DGROUP

;---- SERVICE ROUTINES CALLED FROM COMMON CODE VIA DCB@ -----------------------
;
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Process READ_ENABLE notification
;------------------------------------------------------------------------------
public Dev_ReadEnable
Dev_ReadEnable   Proc  Near
  CALL_TYPE setnotify,DT_DISPLAY          ; request video mode notification
  xor  ax,ax                              ; if display device is present
  ret

setnotify:
  and  dx,NOT STYLE_NOTIFY_VMCHANGE       ; request video mode notification
  ret
Dev_ReadEnable   EndP

;------------------------------------------------------------------------------
; make sure barrel button is up
;------------------------------------------------------------------------------
public myloc_ForceClear
myloc_ForceClear proc
  mov  dl, 0       ; barrel button is not down
  mov  cx, 0       ; button number
  push bx
  lea  bx,dcbb
  call But_Engine  ; bx = dcb
  pop  bx
  call Loc_ForceClear
  ret
myloc_ForceClear endp

;------------------------------------------------------------------------------
; resume interrupt driven events for the driver
;------------------------------------------------------------------------------
public dev_Enable
dev_Enable  Proc  Near
  lea  bx, dcb1
  mov  si, [bx].@Serial ;pass serial structure
  call Ser_EnableInts
  xor  ax,ax
  ret
dev_Enable EndP

;------------------------------------------------------------------------------
; suspend interrupt driven events for the driver
;------------------------------------------------------------------------------
public dev_Disable
dev_Disable  Proc  Near
  lea  bx, dcb1
  mov  si, [bx].@Serial ;pass serial structure
  call Ser_DisableInts                   ; save state of IF
  xor  ax,ax
  ret
dev_Disable  EndP

;------------------------------------------------------------------------------
; set FIFO during device startup
; bx = dcb for this device
;------------------------------------------------------------------------------
public loc_Start
loc_Start    Proc  Near
  mov  si, [bx].@Serial ;pass serial structure
  push bx
  .if  <cnf_init eq 0>
     call Ser_Init        ; initialize the serial port
  .else
     call Ser_FIFO        ; just reset FIFO
  .endif
  pop  bx
  xor  ax,ax
  ret
loc_Start    EndP

;------------------------------------------------------------------------------
; my timer routine that checks for an unfinished packet
;  bx = dcb for this device
; note: TickCount is reset each time a byte comes in. If the count makes it
;       to the limit, then the byteCount is reset to 0 so that the next packet
;       starts fresh. byteCount should already have been at zero.
;------------------------------------------------------------------------------
public loc_Tick
loc_Tick    Proc  Near
  inc [bx].tickCount
  .if <[bx].tickCount gt 4>    ; fix if we got screwed up
    mov [bx].byteCount,0
    mov [bx].tickCount,0
  .endif
  lea  di,[bx].proxBox
  call Loc_ProxFilterTC        ; process proximity filter tick counter
  ret
loc_Tick       EndP

;------------------------------------------------------------------------------
; set sample rate
;  bx = DCB
;  ax = sample rate
;------------------------------------------------------------------------------
decimalRate equ bp-2
roundedRate equ bp-4

public loc_slsr
loc_slsr proc

  enter 4,0

; convert interrupt interval (divided by 5)
; 100 ints per second --> 10 millisecond interrupt time ---> 2 device number

  mov cx, ax
  mov ax, 1000
  mov dx, 0
  div cx
  .if <nonzero dx>
    inc ax
  .endif
  mov  dx,0
  mov  cx,5
  div  cx
  .if <nonzero dx>
    inc ax
  .endif
  mov  [roundedRate],ax
  mov  cl,10
  div  cl
  mov  [decimalRate],ax

; send command to device
;
; note: doing it twice avoids leaving the error light on (???)

  mov  cx,2
  .repeat
     push cx
     mov  si, [bx].@Serial
     mov  al,   'I'
     call Ser_DoPut
     mov  al,   'T'
     call Ser_DoPut
                                     ; send n1 n2 value
     mov  al,byte ptr [decimalRate]  ; If n1 is 0 ONLY SEND n2!
    .if < al ne 0 >                  ; So, make sure al is not zero
       or   al,030h
       call Ser_DoPut
    .endif

     mov  al,byte ptr [decimalRate+1]
     or   al,030h
     call Ser_DoPut
     mov  al,0dh
     call Ser_DoPut
     pop  cx
  .loop

  ; calculate actual rate

  mov  ax,[roundedRate]
  ; calculate actual rate
  mov  cx,5
  imul cx
  mov  cx, ax
  mov  ax, 1000
  mov  dx, 0
  div  cx
  mov  si,[bx].dcb_@RegCaps
  mov  [si].lcap_sample_rate,ax
  xor  ax,ax
  leave
  ret
loc_slsr endp

;---- BUTTON ROUTINES CALLED FROM COMMON CODE VIA DCB@ ------------------------
;
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; set FIFO during device startup
; bx = dcb for this device
;------------------------------------------------------------------------------
public but_Start
but_Start    Proc  Near
  xor  ax,ax
  ret
but_Start    EndP


;---- DISPLAY ROUTINES CALLED FROM COMMON CODE VIA DCB@ -----------------------
;
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; startup automatic display support
; bx = dcb for this device
;------------------------------------------------------------------------------
public Dsp_Start
Dsp_Start    Proc  Near
  or   [bx].dcb_DspFlags,DSP_AUTO_ENABLED+DSP_SUPPRESS
  call Dsp_SetInactPeriod
  xor  ax,ax
  ret
Dsp_Start    EndP

;------------------------------------------------------------------------------
; stub to do actual backlight control
; ax = command, 1=turn on 0=turn off
; bx = dcb for this device
;------------------------------------------------------------------------------
public Dsp_Back
Dsp_Back     Proc  Near
  mov  word ptr dUVarss,ax ; just for debugging on systems without a real dsp
  call Dsp_Engine
  ret
Dsp_Back     EndP

;---- ROUTINES TO PROCESS EVENTS ----------------------------------------------
;
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; process a byte, called from serial interrupt handler
; al = input byte
; bx = dcb for this device
;------------------------------------------------------------------------------
public ProcessByte
ProcessByte proc

  mov [bx].tickCount,0    ; restart watch dog for resetting count if its
                          ; screwed up
; al = input byte

  mov  di, [bx].byteCount
  .if <bit al nz SYNCBIT>         ; if 1st byte of packet
    .if <nonzero di>              ; expect to be at bytecount == 0
       .386p
       inc  Dev_ErrorCount
       .286p
       ret                        ; ignore it
    .endif

    TraceByte1
    mov  [bx].mEvent[0], al       ; save first byte
    mov  [bx].byteCount,1
    ret
  .endif

; not the first byte in the packet

  .if <zero di>              ; If sync bit is off, then the byteCount better
                             ; not be at zero!
     .386p
     inc  Dev_ErrorCount
     .286p
     ret                     ; ignore it
  .endif

  TraceByte
  mov  [bx].mEvent[di], al   ; save this byte
  .if <di ge PACKET_BYTECOUNT-1>
     mov  [bx].byteCount, 0  ; next byte starts new packet
     call packDone
     ret
  .endif
  inc  [bx].byteCount
  ret
ProcessByte endp

;------------------------------------------------------------------------------
; process a complete device packet
; bx = dcb for this device
;
; note: Modification of the Mouse Absolute Packet and the EIQ locator packet
;       and calling the engine is serialized against a race condition with
;       the timer in case of the proximity or contact state time out. This
;       is done with the GetCritSec macro.
;------------------------------------------------------------------------------
public packDone
packDone Proc  Near
.386p
  GetCritSec [bx].dcb_Sem1 ; sets NZ if crit section is busy
  .if  z

;    figure out the cooridinates from the collected digitizer packet

     mov  ah, byte ptr [bx].MEvent[1] ; high order   x
     xor  al,al
     shr  ax, 1
     or   al, byte ptr [bx].MEvent[2] ; low order
     cwde
     mov  [bx].dcb_LocNewX, eax

     mov  ah, byte ptr [bx].MEvent[4] ; high order   y
     xor  al,al
     shr  ax, 1
     or   al, byte ptr [bx].MEvent[5] ; low order
     cwde
     mov  [bx].dcb_LocNewY, eax

;    figure out whether the pen is in contact or proximity and position of
;    the barrel button
;
; note: when using the  proximity filter, it must be called before the
;       dcb_LocNewState is updated. When prox pts are being ignored, we want
;       the state to become CLEAR and stay that way until the pen moves.

     mov  al, byte ptr [bx].mEvent[6]
     .if <bit al nz PEN_INVALID> ; last sanity check for valid data
        inc Dev_ErrorCount
        jmp short dd_ignorePts
     .endif
     .if <bit al z PEN_CONTACT> ; in proximity
        lea  di,[bx].proxBox
        call Loc_ProxFilter
        .if  <zero cx>
           jmp short dd_ignorePts
        .endif
        mov  dx,STATE_PROX
     .else                      ; in contact
        mov  dx,STATE_CONTACT
     .endif
     mov  [bx].dcb_LocNewState,dx

     push bx
     lea  bx,dcbb
     .if <bit al z PEN_BUTTON>
        mov  dl, 0                ; barrel button is not down
     .else
        mov  dl,-1                ; barrel button is down
     .endif
     mov  cx, 0       ; button number
     call But_Engine  ; bx = dcb
     pop  bx

; do direct event buffer stuff
;    lev_dev_sequence
;    lev_cntrl
;    lev_dev_timestamp   - not used
;    lev_OEM_data        - not used

     mov  di,[bx].dcb_@EiEvent
     inc  [di].lev_dev_sequence
     mov  [di].lev_cntrl,LOC_ABS

; process event

     call Loc_Engine  ; bx = dcb
                      ; di = event packet

dd_ignorePts:
     ClearCritSec [bx].dcb_Sem1
  .endif
  ret                                  ; return to IDC router
packDone EndP

;------------------------------------------------------------------------------
; io error routine
; bx = dcb for this device
; note: don't need to increment error count
;------------------------------------------------------------------------------
public dev_ioerror
dev_ioerror Proc
    mov  [bx].byteCount,0  ; start looking for new packet
    ret
dev_ioerror endp

;------------------------------------------------------------------------------
; Interrupt handler stub
;------------------------------------------------------------------------------
public intHandler1
intHandler1 proc
  lea bx, dcb1         ; pass dcb
  mov si, [bx].@Serial ;pass serial structure
  jmp Ser_InterruptHandler
intHandler1 endp

;---- IOCTL ROUTINE -----------------------------------------------------------
;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Handle device specific IOCTLs
;   es:bx = request packet
; returns
;   ax = request packet completion code
;------------------------------------------------------------------------------
public Dev_IOCTL_rtn
Dev_IOCTL_rtn proc
  mov  ax,STERR+STECODE
  ret
Dev_IOCTL_rtn endp

;---- SERIAL INITIALIZATION ROUTINES ------------------------------------------
; NOTE: Must be in resident code segment in case of IO error
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Initialize the digitizer
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public resetDigitizer
resetDigitizer  proc  near
; call doResetD
  call doSR
  call doAS1
  call doIT
  ret
resetDigitizer  endp

;------------------------------------------------------------------------------
; Reset the digitizer
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public  doResetD
doResetD proc
  mov  al,   'R'
  call Ser_DoPut
  mov  al,   'E'
  call Ser_DoPut
  mov  al,   0dh
  call Ser_DoPut
  mov  al,   0ah
  call Ser_DoPut
  ret
doResetD  endp

;------------------------------------------------------------------------------
; Put digitizer into stream mode
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public  doSR
doSR     proc
  mov  al,   'S'
  call Ser_DoPut
  mov  al,   'R'
  call Ser_DoPut
  mov  al,   0dh
  call Ser_DoPut
  ret
doSR      endp

;------------------------------------------------------------------------------
; Have digitizer return binary format
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public  doAS1
doAS1    proc
  mov  al,   'A'
  call Ser_DoPut
  mov  al,   'S'
  call Ser_DoPut
  mov  al,   '1'
  call Ser_DoPut
  mov  al,   0dh
  call Ser_DoPut
  ret
doAS1     endp

;------------------------------------------------------------------------------
; Set the interrupt rate
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public  doIT
doIT     proc
  mov  di,[bx].dcb_@RegCaps
  mov  ax,[di].lcap_sample_rate
  push si
  call loc_slsr
  pop  si
  ret
doIT      endp
CSEG ends

;---- INITIALIZATION ROUTINES -------------------------------------------------
;
; note: this code is truncated from the driver after the INIT command returns
;       to OS/2
;------------------------------------------------------------------------------

CSEGI segment
;------------------------------------------------------------------------------
; Initialize the device. First do device specific stuff, then complete code
; shared for all devices of this type
;  bx = dcb for this device
;  es:di = config.sys parm line
;------------------------------------------------------------------------------
public Dev_Init
Dev_Init  proc
  call getParms
  call setType
  call initDcb0
  call initLoc1Dev
  call initButDev
  .if <cnf_haveDsp eq 1>
     call initDispDev
  .endif
  xor ax,ax
  ret
Dev_Init  endp

;------------------------------------------------------------------------------
; Init routine addresses in dcb0
;------------------------------------------------------------------------------
Public InitDcb0
InitDcb0 proc
  mov  dcb0.dcb_@Dev_Enable,    offset dev_Enable
  mov  dcb0.dcb_@Dev_Disable,   offset dev_Disable
  mov  dcb0.dcb_@Dev_ReadEnable,offset dev_ReadEnable
  mov  dcb0.dcb_@Dev_VMChange,  offset Vmc_Change       ; use standard routine

; set up driver device name

  mov  si, offset driverName
  call SetDriverName

  mov  si, offset deviceName1          ; default driver device name
  .if <cnf_type eq 2>
     mov  si, offset deviceName2       ; device name for type 2
  .elseif <cnf_type eq 3>
     mov  si, offset deviceName3       ; device name for type 3
  .endif
  call SetDeviceName

  ret
InitDcb0 endp

;------------------------------------------------------------------------------
; Initialize the first locator device
;------------------------------------------------------------------------------
public initLoc1Dev
initLoc1Dev proc
; add DCB to list
  lea  bx, dcb1    ; add the locator
  call Gio_AddDCB

; configure common dcb fields for device 1
  mov  [bx].dcb_DevType, DT_LOCATOR
  mov  [bx].dcb_@DeviceData, offset deviceData1
  mov  [bx].dcb_@RegCaps,    offset regCaps1
  mov  [bx].dcb_@EiEvent,    offset locEvent1
  mov  [bx].dcb_@UVars,      offset numUVars
.386p
; configure device specific fields for device 1

; X coordinate stuff

  mov  [bx].dcb_Xtrans.trn_flags,  STANDARD_USD

  mov  eax,cnf_xExtent                          ; extents
  mov  [bx].dcb_Xtrans.trn_ext_max,            eax
  mov  [bx].dcb_Xtrans.trn_ext_max_PM,         eax
  mov  [bx].dcb_Xtrans.trn_ext_adj,            eax
  mov  [bx].dcb_Xtrans.trn_ext_adj_default,    eax
  mov  [bx].dcb_Xtrans.trn_ext_adj_calibrated, eax

  mov  ax, cnf_xOriginDefault                   ; origin
  cwde
  mov  [bx].dcb_Xtrans.trn_org_adj,        eax
  mov  [bx].dcb_Xtrans.trn_org_default,    eax
  mov  [bx].dcb_Xtrans.trn_org_calibrated, eax

; Y coordinate stuff

  mov  [bx].dcb_Ytrans.trn_flags,  STANDARD_USD

  mov  eax,cnf_yExtent                          ; extents
  mov  [bx].dcb_Ytrans.trn_ext_max,            eax
  mov  [bx].dcb_Ytrans.trn_ext_max_PM,         eax
  mov  [bx].dcb_Ytrans.trn_ext_adj,            eax
  mov  [bx].dcb_Ytrans.trn_ext_adj_default,    eax
  mov  [bx].dcb_Ytrans.trn_ext_adj_calibrated, eax

  mov  ax, cnf_yOriginDefault                   ; origin
  cwde
  mov  [bx].dcb_Ytrans.trn_org_adj,        eax
  mov  [bx].dcb_Ytrans.trn_org_default,    eax
  mov  [bx].dcb_Ytrans.trn_org_calibrated, eax

; timer values

  mov  eax,DEFAULT_REPORT_TIMEOUT
  call Tim_Mill2Tick
  mov  [bx].dcb_TimeoutLimProx, ax
  mov  [bx].dcb_TimeoutLimCont, ax

; serial

  mov  ax,cnf_@serial
  mov  [bx].@Serial,ax

; configure the common registration capabilities for device 1

  push bx
  mov  al, [bx].dcb_Unit
  mov  bx, [bx].dcb_@regCaps
  mov  [bx].ccap_unit, al
  mov  [bx].ccap_length, size LCAP
  mov  [bx].ccap_device_type, DT_LOCATOR
  mov  [bx].ccap_event_caps,EV_STD_MOUSE+EV_BUTTON_CHG+EV_EXIT_PROX

; integrated displays must use CCAP_OS2INI
; default should be CCAP_OS2INI
  .if < cnf_haveDsp eq 1 >
     mov  [bx].ccap_flags, CCAP_OS2INI
  .else
; for opaque non-calibrating tablets
;      mov  [bx].ccap_flags, CCAP_DEFAULTDATA
; for opaque calibrating tablets
      mov  [bx].ccap_flags, CCAP_OS2INI
  .endif

  mov  si, offset DDHdr1 + 10       ; driver name
  lea  di, [bx].ccap_driver_name
  cld
  push ds
  pop  es
  mov  cx,8
  rep  movsb
  mov  si, offset deviceNamel       ; device name
  lea  di, [bx].ccap_device_name
  mov  cx,SIZEOF_DEVICE_NAME
  rep  movsb
  pop  bx                           ; restore dcb

; configure locator registration capabilities for device 1

  mov  si, [bx].dcb_@RegCaps
  mov  [si].lcap_type,LOCTYPE_PEN+LOCTYPE_ABSOLUTE
  mov  [si].lcap_caps, PENCAP_PROXIMITY
  .if  <cnf_haveDsp eq 1>
     or   [si].lcap_caps, PENCAP_DISPLAY
  .endif
  mov  [si].lcap_sample_rate, 100
  mov  [si].lcap_max_sample_rate, 200
  mov  [si].lcap_num_mouse_but, 3
  mov  [si].lcap_barrel_num, 1
  mov  [si].lcap_barrel_mask, 1

  mov  eax, [bx].dcb_Xtrans.trn_ext_max_PM
  mov  [si].lcap_dev_x_extent, eax
  mov  eax, cnf_xStdExtent
  mov  [si].lcap_std_x_extent, eax

  mov  eax, [bx].dcb_Ytrans.trn_ext_max_PM
  mov  [si].lcap_dev_y_extent, eax
  mov  eax, cnf_yStdExtent
  mov  [si].lcap_std_y_extent, eax
.286p
  mov  ax,  cnf_xRes
  mov  [si].lcap_dev_x_res,ax
  mov  ax,  cnf_yRes
  mov  [si].lcap_dev_y_res,ax
  mov  [si].lcap_std_res,STD_RESOLUTION
  mov  word ptr [si].lcap_dev_timestampRes, 0   ; no device timer

; configure extended interface locator event buffer

  mov  si, [bx].dcb_@EiEvent
  mov  [si].cev_length, size LEV
  mov  [si].cev_device_type, DT_LOCATOR

; configure proximity filter

  .386p
  mov  [bx].proxBox.box_Size, DEFAULT_BOX_SIZE
  mov  eax, DEFAULT_PROX_FILTER
  call Tim_Mill2Tick
  mov  [bx].proxBox.box_TickLimit,ax
  .286p

; configure device instance independent

  call initDev                 ; do the common init parts

; configure serial

  mov  si, cnf_@Serial         ; configure serial device
  mov  [si].@DCB, bx
  mov  [si].@processByte, offset processByte
  mov  [si].@intHandler,  offset intHandler1
  mov  [si].@initRtn   ,  offset resetDigitizer
  mov  [si].@errorRtn  ,  offset dev_ioerror
  .if  <cnf_init eq 1>    ; do early serial init
     push bx
     call Ser_Init
     pop  bx
  .endif
  ret
initLoc1Dev endp

;------------------------------------------------------------------------------
; Init fields common for all devices of this type
; bx = dcb for this device
;------------------------------------------------------------------------------
public initDev
initDev proc
; configure common dcb fields for device 1
  mov  [bx].dcb_@Dev_DDTick,    offset loc_Tick
  mov  [bx].dcb_@Dev_Start,     offset loc_Start
  mov  [bx].dcb_@slsr,          offset loc_slsr
  mov  [bx].dcb_@Dev_ForceClear,offset myloc_ForceClear
  ret
initDev  endp

;------------------------------------------------------------------------------
; configure the button device
;------------------------------------------------------------------------------
public initButDev
initButDev proc
  lea  bx, dcbb    ; add the button
  call Gio_AddDCB

; configure common dcb fields for device 1
  mov  [bx].dcb_DevType, DT_BUTTON
  mov  [bx].dcb_@RegCaps,    offset regCapsb
  mov  [bx].dcb_@EiEvent,    offset butEvent
  mov  [bx].dcb_@UVars,      offset bnumUVars

; configure the common registration capabilities for device 1

  push bx
  mov  al, [bx].dcb_Unit
  mov  bx, [bx].dcb_@regCaps
  mov  [bx].ccap_unit, al
  mov  [bx].ccap_length, size BCAP
  mov  [bx].ccap_device_type, DT_BUTTON
  mov  [bx].ccap_event_caps,BEV_BUTTON_CHANGE

; integrated displays must use CCAP_OS2INI
; default should be CCAP_OS2INI
  .if < cnf_haveDsp eq 1 >
     mov  [bx].ccap_flags, CCAP_OS2INI
  .else
; for opaque non-calibrating tablets
;      mov  [bx].ccap_flags, CCAP_DEFAULTDATA
; for opaque calibrating tablets
      mov  [bx].ccap_flags, CCAP_OS2INI
  .endif

  mov  si, offset DDHdr1 + 10       ; driver name
  lea  di, [bx].ccap_driver_name
  cld
  push ds
  pop  es
  mov  cx,8
  rep  movsb
  mov  si, offset deviceNameb       ; device name
  lea  di, [bx].ccap_device_name
  mov  cx,SIZEOF_DEVICE_NAME
  rep  movsb
  pop  bx                           ; restore dcb

; configure default button definitions

  mov  [bx].dcb_NumButDefs,NUM_BUTTONS
  lea  ax, ButDefArray
  mov  [bx].dcb_@ButDefArray,ax

; configure locator registration capabilities for button device

  mov  si, [bx].dcb_@RegCaps
  mov  [si].bcap_num, NUM_BUTTONS
  mov  [si].bcap_typeMask, 0001h
  mov  [si].bcap_barrel, CAP_DEFAULT_BARREL
  mov  [si].bcap_nonbarrel, 0
  call But_CalcCaps

; configure extended interface locator event buffer

  mov  si, [bx].dcb_@EiEvent
  mov  [si].cev_length, size BEV
  mov  [si].cev_device_type, DT_BUTTON
  mov  [si].cev_devicebits,  BEV_BUTTON_CHANGE

; configure device instance independent

  mov  [bx].dcb_@Dev_Start,   offset but_Start
  ret
initButDev endp

;------------------------------------------------------------------------------
; configure the display device
;------------------------------------------------------------------------------
public initDispDev
initDispDev proc
  lea  bx, dcbd    ; add the display
  call Gio_AddDCB

; configure common dcb fields for device
  mov  [bx].dcb_DevType, DT_DISPLAY
  mov  [bx].dcb_@RegCaps,    offset regCapsd
  mov  [bx].dcb_@EiEvent,    offset disEvent
  mov  [bx].dcb_@UVars,      offset dnumUVars

; configure the common registration capabilities for device

  push bx
  mov  al, [bx].dcb_Unit
  mov  bx, [bx].dcb_@regCaps
  mov  [bx].ccap_unit, al
  mov  [bx].ccap_length, size DCAP
  mov  [bx].ccap_device_type, DT_DISPLAY
  mov  [bx].ccap_event_caps,DEV_BACKLIGHT_CHANGE

; integrated displays must use CCAP_OS2INI
; default should be CCAP_OS2INI
  .if < cnf_haveDsp eq 1 >
     mov  [bx].ccap_flags, CCAP_OS2INI
  .else
; for opaque non-calibrating tablets
;      mov  [bx].ccap_flags, CCAP_DEFAULTDATA
; for opaque calibrating tablets
      mov  [bx].ccap_flags, CCAP_OS2INI
  .endif

  mov  si, offset DDHdr1 + 10       ; driver name
  lea  di, [bx].ccap_driver_name
  cld
  push ds
  pop  es
  mov  cx,8
  rep  movsb
  mov  si, offset deviceNamed       ; device name
  lea  di, [bx].ccap_device_name
  mov  cx,SIZEOF_DEVICE_NAME
  rep  movsb
  pop  bx                           ; restore dcb

; configure default definitions

  mov  word ptr [bx].dcb_InactPeriod, PERIOD_DEFAULT
  mov  [bx].dcb_DspFlags,DSP_STATE_ON

; configure locator registration capabilities for button device

  mov  si, [bx].dcb_@regCaps
  mov  [si].dcap_type, DISPTYPE_LCD+DISPTYPE_ATTACHED+DISPTYPE_BATTERY
  mov  [si].dcap_auto_flag, 1
  mov  word ptr [si].dcap_height, 768
  mov  word ptr [si].dcap_width,  576

; configure extended interface locator event buffer

  mov  si, [bx].dcb_@EiEvent
  mov  [si].cev_length, size DEV
  mov  [si].cev_device_type, DT_DISPLAY
  mov  [si].cev_devicebits,  DEV_BACKLIGHT_CHANGE

; configure device instance independent

  mov  [bx].dcb_@Dev_Start,   offset Dsp_Start
  mov  [bx].dcb_@Backlight,   offset Dsp_Back
  ret
initDispDev endp

;------------------------------------------------------------------------------
; process comand line parms
; es:di = config.sys command line
;------------------------------------------------------------------------------
CR equ 0Dh
LF equ 0Ah
temp equ word ptr [bp-2]

public getParms
getParms proc
  enter 2,0
  call  skip_to_white             ; Skip driver name
  mov   [temp],di
  call  parm1
  mov   di,[temp]
  call  parm2
  mov   di,[temp]
  call  parm3
  leave
  ret
getParms endp

;------------------------------------------------------------------------------
; Change configuration fields based on TYPE= parm
;------------------------------------------------------------------------------
parm1 proc
  .repeat
     call    skip_white
     mov     al, es:[di]
     .leave  <al eq CR>
     .leave  <al eq LF>
     .leave  <al eq 0>
     mov  si, offset opt_type
     call str_i_cmp
     .if  <zero ax> ; found TYPE=, get type number
        call get_hex_num
        mov  cnf_type, ax
        ret
     .endif
     call  skip_to_white           ; Skip to next parameter
  .until
  ret
parm1 endp

;------------------------------------------------------------------------------
; Check for early serial initialization parm
;------------------------------------------------------------------------------
parm2 proc
  .repeat
     call    skip_white
     mov     al, es:[di]
     .leave  <al eq CR>
     .leave  <al eq LF>
     .leave  <al eq 0>
     mov  si, offset opt_init1
     call str_i_cmp
     .if     <zero ax> ; found parm
        mov  cnf_init, 1
        ret
     .endif
     call  skip_to_white           ; Skip to next parameter
  .until
  ret
parm2 endp

;------------------------------------------------------------------------------
; Check for late serial initialization parm
;------------------------------------------------------------------------------
parm3 proc
  .repeat
     call    skip_white
     mov     al, es:[di]
     .leave  <al eq CR>
     .leave  <al eq LF>
     .leave  <al eq 0>
     mov  si, offset opt_init2
     call str_i_cmp
     .if     <zero ax> ; found parm
        mov  cnf_init, 0
        ret
     .endif
     call  skip_to_white           ; Skip to next parameter
  .until
  ret
parm3 endp

;----------------------------------------------------------------------------
; Change configuration fields based on TYPE= parm
;----------------------------------------------------------------------------
public setType
setType proc
  .if <cnf_type eq 1>
     mov  ax,VMC_TYPE_CENTER
     call Vmc_LcdType
  .elseif <cnf_type eq 2>
     mov  ax,VMC_TYPE_TOP
     call Vmc_LcdType
  .elseif <cnf_type eq 3>
     mov  ax,VMC_TYPE_NONE
     call Vmc_LcdType
.386p
     mov cnf_xExtent,04566
     mov cnf_yExtent,02954
     mov cnf_xStdExtent,09130
     mov cnf_yStdExtent,05910
.286p
     mov cnf_xRes, 500
     mov cnf_yRes, 500
     mov cnf_haveDsp,0
  .endif
  ret
setType endp

CSEGI ends
end
