File:  [Apple Darwin 0.x] / driverkit / doc / OLD_NRW / NRWDeviceDriver.frame.backup
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:51 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

<MakerFile 2.0J>
	

Aa��@"�ff�����HH	$	d 		d[Footnote*���. � �]�Zm�[
���x��*1HeadL2Headx(IOReturn)devEjectDisk(IOReturn)getPhysParamsj(IOReturn)isDiskPresent�
(IOReturn)rtn�(IOReturn)setFormatted(IOReturn)someMethod(boolean_t)isDiskOpen�(dev_port_t)dev_port(dev_port_t)getDevPort(int)channelNum�(int)ioReturnToErrno(int)netInit
(int)netInputR(int)registerDevice�(int)someArgument�(ioResult_t)someMethod(ioReturn_t)devEjectDisk(ioReturn_t)getBlockSize(ioReturn_t)getDevSize(ioReturn_t)rtn\(ioReturn_t)setFormatted(netif_t)getNetif�(netif_t)realNetif(port_name_t)notifyPortj(port_t)IOPort(readyState_t)checkReady(u_int)formattedFlag(u_int)getQueryFlags(u_int)getUnit(unsigned)deviceIntrMask(unsigned)diskIsOpen(unsigned)dma_id(unsigned)getDevIntrMask(unsigned)getIntrSumm	(unsigned)intrSummary(unsigned)isPhysDevice(void)abortDma(void)abortRequest(void)disableDma(void)diskPresent(void)dmaAbort(void)dmaDisable(void)dmaForceBufAdv(void)dmaReset(void)dmaStart(void)doIoComplete(void)flushIntrMsgs�(void)freeDmaFrame(void)incrCollisions(void)incrInErrors(void)incrInPacketsr(void)incrOutErrorsR(void)incrOutPackets(void)registerDisk(void)resetDma(void)setChanIntrCause(void)setChanIntrMaskd(void)setChannelIntrMask(void)setDevIntrCauset(void)setDevIntrMask(void)setDevName(void)setDevPort(void)setDeviceIntrCause(void)setDeviceNamed(void)setDevicePaget(void)setDevicePortB(void)setDeviceSize)(void)setNetif(void)setQueryFlagsr
(void)setUnitd(void)startDma(void)unRegisterDeviceAutoconfiguringtConfigDiskObject:IODeviceaDiskReadyStateIOAttachChannelaIOAttachInterrupttIOChannelCommandIOChannelDequeueOptionIOChannelEnqueueOptionIOChannelReturneIOChannelStatuseIOConfigDeviceIOConfigReturnIOCreateDevicePortIODelayrIODeleteDeviceIODeleteDriverIODequeueDmaIODequeueDma()'dIODescriptorCommandiIODestroyDevicePort)IODetachChannelmIODetachInterruptFIODevToIdMapIODeviceNumberIODeviceNumbersiIODevicePageIODevicePortIODeviceReturnIODeviceTypeIODiskDeviceIODiskDevice:IODeviceoIODmaDirectionIODmaStatusiIOEnqueueDmaIOExitThreadIOForkThreadIOForkThread(IOThreadFcnIOFreeIOGetDeviceTypeC
IOIntToStringCIOIntToString(int)IOLog(constrIOMalloc
IOMapBoardIOMapDevicePageD	IOMapSlotIONetDevicea
IOPanic(constvIORegisterDriverIORescanDriverIOResumeThreadIOResumeThread(IOThreadIOReturnIOReturnToStringIOSendChannelCommandIOServerIOSleep(intyIOSlotIdIOSuspendThreadiIOSuspendThread(IOThreadIOTaskIOThread	IOTimeoutoIOTimeout(IOThreadFcnc
IOUnitName
IOUnitTypeIOUnmapBoardIOUnmapDevicePageIOUnmapSlotaIOUntimeoutDIOUntimeout(IOThreadFcnqIOlibIOInitOLaserPrinterLogicalDiskLockeLogicalDisksMyDeviceNetDriver:IODevice
NetDriverKernaOR�dSCSIControllerSCSIDisk	XPRVieweruaThreadeabcdabcdABCDactualLengthaddrargtbcountblockDevblockId[NPART]	blockSizee
block_sizebootstrap_infobootstrap_look_upubootstrap_lookup()sbuffer_size	bytesReadubytesWrittencause:(unsigned)causekchan_commandchan_command_tchan_dequeue_opt_tchan_desc_cmd_ttchan_dma_dequeuechan_dma_dequeue()'dchan_dma_enqueuechan_enqueue_opts_tTchan_num
chan_return_tnchan_statuss
chan_status_tOchan_t
channelNumbergchannelRegschannelSpecificO	classNamevcmdecmdBuf
cmdBufLockcmdBuf_tcmdLockh
configPortconfig_return_tdevPagendevPagePdevPortdevSizendevToIdMap_t
dev_board_map(dev_board_unmapOdev_chan_attachOdev_chan_detachhdev_config_porth	dev_entryedev_get_type	dev_indexcdev_intr_attachOdev_intr_detachB	dev_nmbera	dev_num_t
dev_numberdev_numbersu
dev_page_tdev_portdev_port_<dev_number>adev_port_createadev_port_destroy
dev_port_tdev_port_to_typedev_reg_mapi
dev_reg_unmapdev_return_tdev_sizedev_slot_mapdev_slot_unmapdev_tDdev_type
dev_type_tdeviceIndex
deviceNamedeviceNumber
deviceNumbersc
devicePage
devicePortdevicePortsk
deviceSize
deviceType
device_delete
device_masterydevnamen	devname_tsdevrdevsdirndirectDriverdirection_thdiskIddmaAbortdmaFreeFramedma_id
dma_statusdma_status_tdoIoComplete	driveNameedriveName[MAXDNMLEN]
drive_info
driverPort
driverSigPorts
driver_configO
driver_deleteedriver_portndriver_registerS
driver_rescanNdriver_sig_portf	driverkitk	ejectDiskendifheorfexec'dexecutable_fidexecutable_file_name
extDeviceRegszfcnefloppyThreadgetChanRegsgetChanSpecific
getDevName
getDevPagegetDriveNamegetExternalDev
get_devr_port_human_readable_name
idMapArray	if_attachnif_getbuf_func_tif_ipackets_if_output_func_t
if_privatein_useindirectDevices_insertNotify	int)countoint)maxCountintDeviceSpecificRegstinternalDevMapinternalDevMap_t	intr_portnioQueue_ioQueueLock_ioReturnText
ioReturn_tkernel'slastReadyStatelibDevlibIOelibname
livePartIdlockUntil:COMPLETEmask:(unsigned)maskemaxCountnbnetControl(netif_tnetGetBuf(netif_tenetInit(netif_tinetInput(netif_t	netOutput_netOutput(netif_tnnetbuf_tnetifinetif_thnmserverosdevt	ownerPortaparameterArrayphysFlagprobe:deviceMasterprobe:directDriverrawDevrawDevId	readAsyncoreadAtreadOpsvreadyState_t	realnetifOregArrayregArray:(regValues_trregTextsregText:regArrayregVal
regValueArrayr	regValuesjregValues_ti
reg_valuesregisterLogicalDisk
removableP
returnedCountvrvNamervValuelrw
setDevPagesizepslotIdslot_id	slot_id_tesprintfastartOpistream_modettarget_task_task_createu	task_portetimeReadingAtimeWritingctsvalgunlockWith:COMPLETEk
unregisterusruvolCheckwaitForWorke
writeAsyncwriteOpsxprAdd
xpr_string���nt��-}<-�Map.ntr/�n0ue_1�ueu2�_3urn4�
io5�n_t6nel7�ast8Sta9�ibD:ibI;ibn>�
li?tId@�kUnA�OMPBmaC�nsiDmasUaxChnbiConjnetkneluf(�%��@Ini7second-level heading; headings:second-level[headings:2]_tn�1buf7second-level heading; headings:second-level[headings:2]eteUy7second-level heading; headings:second-level[headings:2]rahd	7second-level heading; headings:second-level[headings:2]egAire7second-level heading; headings:second-level[headings:2]
rejeAr7second-level heading; headings:second-level[headings:2]alDk
re7second-level heading; headings:second-level[headings:2]el7second-level heading; headings:second-level[headings:2]m���
rg�-
�k_�/
�_c�2
�	�4
�or�5
�me�7
�gA�9
�Wr�A
��C
��>
�Wi
�
�
�
�<$lastpagenum>ck
�<$monthname> <$daynum>, <$year>p
�"<$monthnum>/<$daynum>/<$shortyear>
�;<$monthname> <$daynum>, <$year> <$hour>:<$minute00> <$ampm>_
�"<$monthnum>/<$daynum>/<$shortyear>
�<$monthname> <$daynum>, <$year>
�"<$monthnum>/<$daynum>/<$shortyear>ma
�	<$fullfilename>C
�
<$filename>
�<$paranum[ChapterNum]>@
�<$paratext[ChapterTitle]>ngs
�
<$curpagenum>s:2
�
<$paratext[1Head]> h
�
<$marker1>ec
�
�Page #page <$pagenum>ond
�Heading & Page<$paratext> on page <$pagenum>
�StatusPRELIMINARYadi
�
Figure Number-
<$paranum>
�Heading<$paratext>v
�Pagepage <$pagenum>-
�Section & Page%section <$paranum> on page <$pagenum>su�u	v..krey::hAiz22cA-{;;2|5�dAv}77dAs~88einPPgA-�RR2QO	>or
3�me
�9
�
�>

+�
tpa
�
thnSYNOPSIS
$ye
-"hn
-$da
hor
�
thn 
*ynu!
r> "�$mi#�$am$
"%
m>/&�/<$'�>(�$mo)
<$dSUMMARY*
�+
thnSYNOPSIS,
hor-
�	.
lfi/
 �
0�ena1
2
[Ch3
>@4
$paSUMMARY5
Ble]6�
7
numSYNOPSIS8
ate9
> h:
$ma;
 �<
Pa=
e <>
3ond?
din@
<$SUMMARYA
  <$B
�SUMMARYC
NARSYNOPSISD
NumE
araF
HeG
 $paH
�I
ageJ
m>-SUMMARYK
ageSYNOPSISL
um>M
<$pN
 O
u	P
v.Q
R
:hSUMMARYS
2cSYNOPSIST
;2U
V
 AvW
}7X�Note:  eY
Z
PgSUMMARY[
R2SYNOPSIS\
�me]
�9^��_
 �>`
a
�b
tpac��d�thne
SISf
g
-h�$dai
3horj
�SUMMARYk� 
*l
3!
m
3"�n�#�o
$
p
%
2.&�q
r
1.s
<$d3.RYt��u�thnv
SISw
x
SYNOPSISy
�
z
ena{
 |
[Ch}
>@~�$paNote:  �le]�

�
numSUMMARY�
ateSYNOPSIS�
:
�
;
 �
 <
�
=
SUMMARY�
SYNOPSIS�
<$�
RY�
�
�
 C
�
YNO�
Num�
araSUMMARY�
G
 SYNOPSIS�
�
�
 �
K
�
YNO�
um>SUMMARY�
N
 SYNOPSIS�
�
�
 �
�
S
SUMMARY�
T
SUMMARY�
SYNOPSIS�
}7�
�
  e�
SUMMARY�
RY�
SUMMARY�
SYNOPSIS�
��
�>�
 �
��
tpa�
�SUMMARY�
e
SYNOPSIS�
�
�
 �
�
�
k�SUMMARY�
SYNOPSIS�
#��
$
�
 %
�
&��
�
�
s
�
3.�
��
thn�
SIS�
�
SUMMARY�
�
�
enaSYNOPSIS�
|
�
}
�
~��
 ote�
le]�

�
numSUMMARY�
ate�
SISSYNOPSIS�
;
 �
<
�
 =
�
RY�
SUMMARY�
�
SYNOPSIS�
�
C
�
 YNO�
Num�
araSUMMARY�
G
 �
SISSYNOPSIS�
�
�
 K
�
YNO�
um>SUMMARY�
N
 �
SISSYNOPSIS�
�
�
 �
S
�
RYSUMMARY�
RY�
SYNOPSIS�
�
�
 ��Note:  ��Note:  ��RY�
�
�
�
B�
���
 �
B�
�
B�
�
B�
�
BUMM�
e
�
SIS�
B�
B�
B�
B�
B�
B�
B�
�
BYNO
B#�
B$

B%

&�

B
Bs

B3.
B�	
Bthn

BSIS�
	�MM

	�
�
	ena�NO
	�
�
}

~�
ote
le]
	
�

	�Y
	ate�


�
��
��
 ��

�

UMM

 
SIS!
"
#
$
%
B&
B�
'
B�
(
BYNO)
B*
B+
BK
,
BYNO-
Bum>.
BRY/
B0
B1
�
2
�
3
�
 4��
5
B�
6
UMM7
BRY8
B9
BSIS:
B;
B<
B=
>
��?�ote@
RYA
B
�
C
�
D��
 E
�
F��
G
B�
H
BUMMI
Be
J
BSISK
L
M
N
O
BP
BQ
B�
R
YNOS
#�T
$
U
B%
V
B&�W�X
Y
s
Z
3.[
	��
B\
	�IS]
	��^
	�MM_
	�
�`
Benaa
B
	b
Bc
Bd
Be
Bf
Bg
Bh
Bi
B
	j
B
k
Bl
Bm
Bn
Bo
Bp
Bq
Br
Bs
Bt
Bu
Bv
Bw
Bx
By
Bz
B{
B|
}
B~
B
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
�
�
�
�
�
B�
B�
B�
B�
B�
B�
B�
B�
�
�
�
�
B�
B���
�
B�
�
B�
B�
B�
B�
�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B]
	�
B�
B�
B�
��`
B�
Ba
B�
Bb
B�
Bc
B�
Bd
B�
Be
B�
Bf
B�
Bg
B�
h
B�
Bi
B�
Bj
B�
Bk
B�
l
B�
m
B�
n
B�
Bo
B�
Bp
B�
Bq
B�
Br
B�
Bs
B�
Bt
B�
Bu
B�
Bv
B�
Bw
B�
Bx
B�
By
B�
Bz
B�
B{
B�
B|
�
B}
B�
B~
B�
B
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
B�
�
B�
�
B�
�
B�
�
B�
�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
B�
�
B�
�
B�
�
�
B�
�
B�
B���
B�
�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
�
B�
�
B�
�
B�
B�
B�
�
B�
�
B�
B�
B
�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B	
B�
B

B��
�
B
�
B

�
B
	�
B�
	e
B�
B
	�
B
	�
�
i
B�j
B
Bk
B
Bl
B
Bm
B
Bn
B
Bo
B
Bp
B
q
B
Br
B
Bs
B
Bt
B
Bu
B
Bv
B 
Bw
B!
Bx
B"
By
B#
Bz
B$
B{
B%
B|
&
B}
B'
~
B(

B)
�
B*
B�
B+
B�
B,
B�
B-
B�
B.
B�
B/
B�
B0
B�
B1
B�
2
B�
3
B�
4
B�
5
B�
6
B�
7
B�
B8
B�
B9
B�
B:
B�
B;
B�
B<
B�
B=
B�
B>
B�
B?
B�
@
B�
A
B�
B
B�
C
B�
BD
B�
BE
��F��
G
B�
BH
B�
BI
B�
BJ
B�
BK
B�
BL
B�
M
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B�
BV
B�
BW
B�
BX
�
BY��
BNote:  BZ

B[�
B\
	
B]


B^

_

`


a

	b
c
d
e

	f
g
h
i
j
k
l
m
n�o
Bp
q
SUMMARYr
u
BSYNOPSISs
 
Bt
!
Bu
"
Bv
#
Bw
$
Bx
 %
By
&
Bz
'
{
(
|
)
}
*
B~
+
B
,
BSUMMARY�
SYNOPSIS�
�
B�
�
B�
�
�
�
�
 �
�
�
�
�
�
�
SUMMARY�
8
BSYNOPSIS�
�
�
�
�
�
�
 �
�
�
�
�
�
�
�
�
SUMMARY�
�
BSYNOPSIS�
K
B�
L
B�
M
B�
N
B�
 O
B�
P
B�
Q
B�
R
BSUMMARY�
SYNOPSIS�
�
B�
�
B�
�
B�
�
B�
�
B�
  B�
 �
�
�
�
�
�
�
SUMMARY�
SYNOPSIS�
e
�
f
�
g
�
h
�
i
�
 j
�
k
�
l
�
m
SUMMARY�
SYNOPSIS�
�
�
RY�
�
s
�
t
�
u
�
v
�
w
�
x
 �
y
�
z
�
{
�
|
�
}
�
~
�

�
UMMSUMMARY�
YNOSYNOPSIS�
�
�
�
�
�
�
�
 �
�
�
�
�
 �
�
UMM�
8
B�
SISSUMMARY�
SYNOPSIS�
�
�
�
�
�
�
�
 �
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
UMM�
�
B�
SIS�
�
�
SUMMARY�
O
BSYNOPSIS�
�
�
�
�
UMM�
�
SIS�
�
 �
���
�
SUMMARY�
SYNOPSIS�
�
�
�
�
�
�
�
�
�
�
 UMM�

SIS


!
!
!
!
!
	


�
SUMMARY
�
SYNOPSIS


















�

YNO
�
 
�
!
�
"
�
 #
�
$
�
%
�
&
UMM'
!8
B(
!SIS)
!RY*
!+
!�
,
�
-
�
.
�
/
�
SUMMARY0
SYNOPSIS1
�
2
�
3
�
4
�
5
�
6
UMM7
�
B8
SIS9
:
;
 <
RY=
>
�
?
�
@
�
A
!�
B
!�
C
!�
D
!�
 E
�
F
��G
�
H
�
I
UMMJ
K�SISL�M
BN
BO
BP
BQ
BR
BS
BT
BU
BV
BW
BX
BY
BZ
B[
B\
B]
B^
B
_
BYNO`
Ba
Bb
c
d
Be
Bf
Bg
Bh
Bi
Bj
Bk
Bl
Bm
n
	�
o
Bp
Bq
r
s
t
u
v
Bw
Bx
By
Bz
B{
B|
B}
B~
B
B�
B�
B�
B�
B�
B0
�
BYNO�
B�
�
B�
�
B�
�
B�
�
B�
�
BUMM�
B�
B�
BSIS�
B�
B�
B�
BRY�
B�
B�
�
B�
�
B�
�
B�
�
B�
�
B�
�
B�
 �
B�
�
B���
B�
�
B�
�
BUMM�
B�
BSIS�
�
�
�
�
�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B
�
BYNO�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
Bo
B�
Bp
B�
Bq
�
Br
�
Bs
�
Bt
�
Bu
�
Bv
B�
Bw
B�
Bx
B�
By
B�
Bz
B�
B{
B�
|
B�
}
B�
~
B�

B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
B�
�
B�
�
B�
�
B�
�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B
�
B
B�
B
B�
B
B�
B
B�
B
B�
B��
B
B�
B
B�
B	
B�
B

B�
B
B�
B
B�
B

B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B 
B�
B!
B�
B"
B�
B#
B�
B$
B�
B%
B�
B&
B�
'
B�
(
B�
)
B�
*
B�
B+
B�
B,
B�
B-
B�
B.
B�
B/
B�
B0
B�
B1
B�
B2
B�
B3
B�
B4
B�
B5
B�
B6
B�
B7
B�
B8
B�
B9
�
B:
�
B;
�
B<
�
B=
B�
B>
B�
B?
B�
B@
B�
BA
B�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
BG
B�
BH
�
BI
B�
BJ
�
BK
B�
BL
B�
BM
�
BN
B�
BO
B�
BP
�
BQ
�
BR
�
BS
�
BSUMMARYT
SYNOPSISU
�
BV��
BW
�
BX
�
BY��
BZ
�
B[
�
B\
�
B]
�
B^
�
B_
 �
B`��
Ba
�
Bb
�
Bc
�
Bd
�
Be
�
BSUMMARYf

Bg

BSUMMARYh
SYNOPSISi
B�
Bj
�
Bk
�
Bl
�
Bm
�
Bn
�
Bo
�
Bp
 �
Bq
�
BSYNOPSISr
!
Bs
"
Bt
#
BSUMMARYu
v
	�
w
'
BSYNOPSISx
	�
y
*
BSYNOPSISz
	�
B{
-
B|
.
B}
/
B~
0
BSUMMARY�Note:  �
�
BSYNOPSIS�
5
B�
6
B�
7
B�
 8
B�
 9
�
 :
�
;
�
	<
��
�
B�
�
B�
�
B�
�
B���
B�
�
B�
�
B�
�
B�
�
B�
�
B�
	�
B�
�
	�
B�
	J
��
	�
B�
B�
	�
B�
N
B�
	O
B��
	�
B�
�
	�
B�
	S
���RY�
�
BU
�
V��
W
�
BX
�
BY��
BZ
�
B[
�
B\
�
B]
�
B^
�
B_
 �
B`��
Ba
�
Bb
�
c
�
d
�
e
�
UMM�

B�

B�
BRY�
�
Bi
B�
Bj
��k
�
Bl
�
m
�
Bn
�
	o
��
	�
B�
�
	�IS�
	!
B�
�
�
�
u
�
v
	�
B
�
�
Bx
	�
B
�
B�
Bz
	�

B�
B�
�
B�
B����
Bote�
�
B�
BSIS�
�
B�
�
�
B�
�
B�
 �
B�
B�
B�
�
B�
�
B�
B�
B�
�
B�
B�
B�
B�
B�
B�
B�
 �
B�
�
B�
�
B�
B�
	�

B���
�
B�
�
	�

B�
�
B�
�
B�
B�
	�
!
B�
B�
BRY�
�
U
�
V��
BW
�
X
�
BY��
Z
�
B[
�
B\
�
B]
�
B^
�
B_
 �
B`��
Ba

Bb

Bc

Bd

Be

BUMM
B
B
B
B
BRY
B	
Bi
B

Bj

Bk

Bl


Bm

Bn

Bo

B�
	
B

B
B!
B
B�

B�

B�

B�

B�
B
B�

B�
B
B�
B
B�
B
�
B��

�
B 
�
!
B�
B"
�
BSYNOPSIS#
$
%
&
'
 (
)
B*
B+
B,
B-
B.
B/
B0
B1
B2
B3
B4
B5
B6
B7
B8
B9
B:
B;
B<
B=
B>
B?
B@
BA
BB
BC
BD
BE
BF
BG
BH
BI
BJ
BK
BL
BM
BN
BO
BP
BQ
BR
BS
BT
BU
BV
BW
BX
BY
BZ
B[
B\
B]
B^
B_
B`
Ba
Bb
Bc
Bd
Be
Bf
Bg
Bh
Bi
Bj
Bk
Bl
Bm
Bn
Bo
Bp
Bq
Br
Bs
Bt
Bu
Bv
Bw
Bx
B#
y
B$
z
B%
{
B&
|
B'
 }
B(
~
B)
B
B*
B�
B+
B�
B,
B�
B-
B�
B.
B�
B/
B�
B0
B�
B1
B�
B2
B�
B3
B�
B4
B�
B5
B�
B6
B�
B7
B�
B8
B�
B9
B�
B:
B�
B;
B�
B<
B�
B=
B�
B>
B�
B?
B�
B@
B�
BA
B�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
BG
B�
BH
B�
BI
B�
BJ
B�
BK
B�
BL
B�
BM
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B�
BV
B�
BW
B�
BX
B�
BY
B�
BZ
B�
B[
B�
B\
B�
B]
B�
B^
B�
B_
B�
B`
B�
Ba
B�
Bb
B�
Bc
B�
Bd
B�
Be
B�
Bf
B�
Bg
B�
Bh
B�
Bi
B�
Bj
B�
k
B�
l
B�
m
B�
Bn
B�
Bo
B�
Bp
B�
Bq
B�
Br
B�
Bs
B�
Bt
B�
Bu
B�
Bv
B�
Bw
B�
Bx
B�
By
B�
Bz
B�
B{
B�
B|
B�
B}
B�
B~
B�
B
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
B�
�
B�
�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B	
B�
B

B�
B
B�
B
B�
B

B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�

B�

B�

B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B 
B�
B!
B�
B"
B�
B#
B�
B$
B�
B%
�
B&
�
B'
(
�
B)
B�
B*
B�
B+
B�
B,
B�
B-
B�
B.
B�
B/
B�
B0
B�
B1
B�
B2
B�
B3
B�
B4
B�
B5
B�
B6
B�
B7
B�
B8
B�
B9
B�
B:
B�
B;
B�
B<
B�
B=
B�
B>
B�
B?
B�
B@
B�
BA
B�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
BG
B�
BH
B�
I
B�
J
B�
K
B�
BL
B�
BM
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B
BV
B
BW
B
BX
B
BY
B
BZ
B
B[
B
B\
B
B]
B
B^
B	
B_
B

B`
B
Ba
B
Bb
B

Bc
B
Bd
B
Be
B
Bf
B
Bg
B
Bh
B
Bi
B
Bj
B
Bk
B
Bl
B
Bm
B
Bn
B
Bo
B
Bp
B
Bq
B
Br
B
Bs
B
Bt
B
Bu
B 
Bv
B!
Bw
B"
Bx
B#
By
B$
Bz
B%
{
B&
|
B'
}
B(
~
B)
B
B*
B�
B+
B�
B,
B�
B-
B�
B.
B�
B/
B�
B0
B�
B1
B�
B2
B�
B3
B�
B4
B�
B5
B�
B6
B�
B7
B�
B8
B�
B9
B�
B:
B�
B;
B�
B<
B�
B=
B�
B>
B�
B?
B�
B@
B�
BA
B�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
BG
B�
BH
B�
I
B�
J
B�
BK
B�
L
B�
BM
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B�
BV
B�
BW
B�
BX
B�
BY
B�
BZ
B�
B[
B�
B\
B�
B]
B�
B^
B�
B_
B�
B`
B�
Ba
B�
Bb
B�
Bc
B�
Bd
B�
Be
B�
Bf
B�
Bg
B�
Bh
B�
Bi
B�
Bj
B�
Bk
B�
Bl
B�
Bm
B�
Bn
B�
Bo
B�
Bp
B�
Bq
B�
Br
B�
Bs
B�
Bt
B�
Bu
B�
Bv
B�
Bw
B�
Bx
B�
By
B�
Bz
B�
B{
B�
B|
B�
B}
B�
B~
B�
B
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
B�
	�
��
	J
B�
B�
	�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B	
B�
B

B�
B
B�
B
B�
B

B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B 
B�
B!
B�
B"
B�
B#
B�
B$
B�
B%
B�
B&
B'
B�
B(
B�
B)
B�
B*
B�
B+
B�
B,
B�
B-
B�
B.
B�
B/
B�
B0
B�
B1
B�
B2
B�
B3
B�
B4
B�
B5
B�
B6
B�
B7
B�
B8
B�
B9
B�
B:
B�
B;
B�
B<
B�
B=
B�
B>
B�
B?
B�
B@
B�
BA
B�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
G
B�
	H
BI
BJ
BK
B�
BL
B�
BM
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B
BV
B
BW
B
BX
B
BY
B
BZ
B
B[
B
B\
B
B]
B
B^
B	
B_
B

B`
B
Ba
B
Bb
B

Bc
B
Bd
B
Be
B
Bf
B
Bg
B
Bh
B
Bi
B
Bj
B
Bk
B
Bl
B
Bm
B
Bn
B
Bo
B
Bp
B
Bq
B
Br
B
Bs
B
Bt
B
Bu
B 
Bv
B!
Bw
B"
Bx
B#
By
B$
Bz
B%
B{
B&
B|
B'
B}
B(
B~
B)
B
B*
B�
B+
B�
B,
B�
B-
B�
B.
B�
B/
B�
B0
B�
B1
B�
B2
B�
B3
B�
B4
B�
B5
B�
B6
B�
B7
B�
B8
B�
B9
B�
B:
B�
B;
B�
B<
B�
B=
B�
>
B�
?
B�
@
B�
BA
B�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
BG
B�
BH
B�
BI
B�
BJ
B�
BK
B�
BL
B�
BM
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B�
BV
B�
BW
B�
BX
B�
BY
B�
BZ
B�
B[
B�
B\
B�
B]
B�
B^
B�
B_
B�
B`
B�
Ba
B�
Bb
B�
Bc
B�
Bd
B�
Be
B�
Bf
B�
Bg
B�
Bh
B�
Bi
B�
Bj
B�
Bk
B�
Bl
B�
Bm
B�
Bn
B�
Bo
B�
Bp
B�
Bq
B�
Br
B�
Bs
B�
Bt
B�
Bu
B�
Bv
B�
Bw
B�
Bx
B�
By
B�
Bz
B�
B{
B�
B|
B�
B}
B�
B~
B�
B
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
�
B�
�
B�
�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
	�
B�
	\
B�
B
	�
B
	�
B�	
B`
B

Ba
B
Bb
B
Bc
B

Bd
B
Be
B
Bf
B
g
B
h
B
Bi
B
Bj
B
Bk
B
Bl
B
Bm
B
Bn
B
Bo
B
p
B�q
B
r
B
s
B
	t
B�
B
	�
B
	�
B� 
x
B!
By
B"
Bz
B#
{
B$
B|
B%
B}
B&
B~
B'
B
B(
B�
B)
B�
B*
B�
B+
*�
B,��
B-
)�
B.
B�
B/
B�
B0
B�
B1
�
B2��
B3
B�
B4
B�
B5
B�
B6
B�
B7
�
B8
�
B9
�
B:
�
BSUMMARY;��
BLIBRARY<
SYNOPSIS=
�
B>
�
B?
 �
B@
B�
BA
�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
BG
B�
BH
B�
BI
B�
BJ
B�
BK
B�
BL
B�
BM
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B�
BV
B�
BW
B
	X
B
BY
BZ
B�
B[
B	
B\
B

B]
B
B^
B
B_
B

B`
B
Ba
B
Bb
B
c
B
d
B
Be
B
Bf
B
Bg
B
Bh
B
Bi
B
Bj
B
Bk
B
l
B�m
B
n
B
o
B
	p
B
Bq
Br
B�
Bs
B 
t
B!
Bu
B"
Bv
B#
w
Bx
B%
By
B&
Bz
B'
B{
B(
B|
B)
B}
B*
B~
B+
*
B,��
B-
)�
B.
B�
B/
B�
B0
B�
B1
�
B2��
!3
B�
!4
B�
5
B�
B6
B�
B7
�
B8
�
9
�
	:
��
RY�
	�Y�
	�NO�
	=
��
	�
B�
 �
B�
	�
B�
BB
B�
BC
B�
BD
B�
BE
B�
BF
B�
BG
B�
BH
B�
BI
B�
BJ
B�
BK
B�
BL
B�
BM
B�
BN
B�
BO
B�
BP
B�
BQ
B�
BR
B�
BS
B�
BT
B�
BU
B�
BV
B�
BW
B�
BX
B�
BY
B�
BZ
B�
B[
B�
B\
B�
B]
B�
B^
B�
B_
B�
B`
B�
Ba
B�
Bb
B�
Bc
B�
Bd
B�
Be
B�
Bf
B�
Bg
B�
Bh
B�
Bi
B�
Bj
B�
Bk
B�
Bl
B�
Bm
B�
Bn
B�
Bo
B�
Bp
B�
Bq
B�
Br
B�
Bs
B�
Bt
B�
Bu
B�
Bv
B�
w
B�
Bx
B�
By
B�
z
B�
B{
B�
|
B�
B}
B�
B~
B�
B
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
!�
B�
!�
B�
�
B�
B�
B�
B�
B�
B�
B�
�
B�
	�
B�
B�
B�
B�
B�
	�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B	
B�
B

B�
B
B�
B
B�
B

B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
B�
B
)�
B
)�
B
)�
B
)�
B
)�
B
)�
 
)�
B!
)�
B"
B�
#
B�
B$
B�
%
B�
B&
B�
B'
B�
B(
�
B)
�
B*
�
B+
	�
B�,
�
BSUMMARY-
�
B.
�
BSYNOPSIS/
0
1
2
3
4
5
 6
7
8
9
SUMMARY:
;
SYNOPSIS<
�
B=
�
B>
�
B?
�
BSUMMARY@
A
B
 C
D
E
SYNOPSISF
�
BG
�
BH
�
BI
�
BJ
B�
BK
B�
BL
 �
BM
�
BN
B�
B���d�
B.2�
Bd�
B�
B$6��
B$6�)!| 
B#
��
��UUh'
Z
B'UlibDev - Standard IODevice Classes

BB����UT`(
[	IODevice
]UMUR�� C
U
B]This is the superclass of all device driver classes. It contains minimal state information - BjUHUR��C
U
BTdevice name, unit number, and device page pointer, device port. (Note - the current 
BwUCUR��C
UXIODevice.h actually contains a number of other variables which will probably be deleted 
�U>UR��C
UWbefore final release; most of these deal with a prototype Remote Object implementation �U9UR��@C
UISTwhich is being discarded soon.) The primary areas of functionality of IODevice are:
�U4UR��`
U
;Manipulation of standard NRW device and channel registers.
�U/UR��`
U
B Common DMA operations. 
�U*UR�� 
U
BXStandard device probe and driver startup (the interface of which is defined in IODevice ��U%UR��@
U9but which is implemented by device-specific subclasses).
U UR�� 
USOnce the Remote Object (RO) mechanism is finalized, there will probably be some RO sesUUR��@
U(support in IODevice as well.
CG������`D
\suIODevice Interface
e d`������`Q
Ico#import <objc/Object.h>
mal������`
I��##import <driverkit/deviceCommon.h>
nd x������`M
Ir,!#import <architecture/m88k/io.h>
B�������`
I
O�������`
Ico@interface IODevice: Object
bl�������`
Iab{
�������`"
IUR	@private
�������`#
Iea
 �������`G
I wint_unit;
o�������`H
ItaIOUnitName_deviceName;
�������`6
IrdIOUnitType_deviceType;
�������`I
IDe*volatile IODevicePage*_devicePage;
�������`J
I d IODevicePort_devicePort;
U/�������`
I C
������`
I
/*
UR������`
Ida7  * ...Other private or soon-to-be-obsolete instance 
h i ������`	
Iic/ *    variables deleted from this document...
d b,������`

Isu */
s8������`
I}
ST�UR��`K
QObP_unit
U is a device-relative unit number, analogous to a Unix �minor� number.
mT�UR��`L
QODD_deviceName
U is an ASCII string like �sd0� or �en0� or �sound2�.
��d �!!�#i$6�!� d $6�#| e/0o.{T�UR��`7
U
URUR�� 8
QV_deviceType
U is an ASCII string like �SCSIDisk� (Maybe more general, like �Disk� - UMUR��@8
U#TBD...)
��.UHUR��`M
Qi;_devicePage
U is a pointer to a driver�s register space.
eNaHUCUR�� N
Q6__devicePort
U is a port by which a driver authenticates its ownership of a particular device e;
UU>UR��N
U dQwhen communicating with the kernel (See the section entitled Kernel Level Driver /bU9UR��@N
U
Support).
z������`O
I s/*
o-b�������`P
Ie G * A Kernel level driver should implement one of these probe methods. 
d b�������`Q
Isu *
/
s�������`R
I4 * All probe methods return id of the instantiated 
ve�������`S
Iog9 * driver on successful initialization; else return nil.
c�������`T
ICI *
ing�������`U
I0�1 * Direct device driver (connected to hardware).
�������`V
I */
�������`W
IE+ probe:(IODeviceNumber)devNumber deviceMaster:(port_t)deviceMaster;
R�������`X
IUR
R�������`Y
Iic/*

U�������`Z
Ing; * Indirect device driver (connected to another IODevice).
��
������`[
I�� */
UR������`\
Iic+ probe:directDriver;
"������`]
Ite
p.������`^
I��/*
Q6:������`_
Iis) * Pseudo device (connected to nothing).
 F������``
Iti */
deR������`a
I��	+ probe;
h^������`b
Uit
hj������`
Ise/*
 env������`R
Il ; * Initialize common instance variables. Typically invoked
/*�������`S
IP1 * via [super init:] in subclass's init: method.
 �������`T
Iho */
 b�������`O
Isu- init;
���������`U
I *
l�������`�
Iur/*
of �������`�
Ive@ * Free up resources used by this device; invoke Object's free.
 r�������`�
I��; * Instance will be �gone� upon return. Typically invoked 
ive�������`�
I? * by subclass; each subclass should implement this method to 
:(I�������`�
Ium2 * free up resources particular to that subclass.
�������`�
I�� */
Y�������`V
I��
��}����`P
Iec- free;
ri�z����`�
Ian
e�w����`�
I��/*
��*�t����`�
I��E * Register/unregister instance with nmserver (or IOServer or ...). 
�6�q����`�
I6) * devname must be valid for both calls.
nB�n����`�
I
  */
��N�k����`�
Ide- (int)registerDevice;
robZ�h����`�
Ib- (void)unregisterDevice;
d"�ni##�e $6�#�"��$6�!+| su6's������`�
I��
�������`�
I b/*
��������`�
Iit  * Get/Set instance variables. 
��)������`�
If  */
��5������`�
Ire4- (void)setDeviceName: (const char *)name;
eeA������`�
I�- (const char *)deviceName;
�M������`�
Ica&- (void)setUnit: (u_int)Unit;
Y������`�
I s- (u_int)unit;
plee������`�
Io 9- (void)setDevicePort: (IODevicePort)devicePort;
oq������`�
I��- (IODevicePort)devicePort;
��}������`�
I�}
��������`�
Iee/*
�z�������`�
I
e6 * Convert an IOReturn to text. Subclasses which add 
�������`�
Ins: * additional IOReturn's should override this method and 
�������`�
IusE * call [super IOReturnToString:] if the desired value is not found.
��������`�
Ite */
e;�������`�
I�.- (const char *)ioReturnText: (IOReturn)rtn;
�������`�
Ini
�������`�
Ie /*
6�������`�
I( * Convert an IOReturn to a Unix errno.
�������`�
I�� */
��������`�
I��/- (int)ioReturnToErrno        : (IOReturn)rtn;
Set
������`
Is.
�������`�
If /*

��%������`�
Ire: * General purpose get/set parameter methods. IODevice�s 
1������`�
I- " * versions return IO_DR_INVALID.
=������`�
Ioi */
niI������`j
IC- (IODeviceReturn)getParameterInt : (IOParameterName)parameterName
voiU������`k
I)   maxCount : (unsigned int)maxCount
�a������`l
Iic   parameterArray : 
�m������`m
I��(   (unsigned int *)parameterArray

ey������`n
IRe   returnedCount : 
hi�������`o
I��(   (unsigned int *)returnedCount;
ov�������`p
I a

�������`q
IusD- (IODeviceReturn)getParameterChar : (IOParameterName)parameterName

��������`r
Ite)   maxCount : (unsigned int)maxCount
 �������`s
IIO   parameterArray : 
��������`t
I��)   (unsigned char *)parameterArray
n�������`u
Io    returnedCount : 
���������`v
I��(   (unsigned int *)returnedCount;
  �������`w
In;
���������`x
I
�C- (IODeviceReturn)setParameterInt : (IOParameterName)parameterName
get�������`y
Iho$    count : (unsigned int)count
 *	�}����`z
IO_    parameterArray : 
�z����`{
I��)   (unsigned int *)parameterArray;
r!�w����`|
INa
p-�t����`}
I��D- (IODeviceReturn)setParameterChar : (IOParameterName)parameterName
��9�q����`~
Iar%     count : (unsigned int)count
E�n����`
Int     parameterArray : 
��Q�k����`�
Iet,     (unsigned char *)parameterArray;
(]�h����`�
Iur 
unti�e����`i
Ip
au�b����`
Iq@end
 ��_����`�
ItP
md$�te%%�r$6�%�$in$6�5'| ar	Ar
UT
UT��`1
`��
t0UR
UT��`
`si
dSUP
UT��`
`rr
nvUN
UT��`
`o 
�UL
UT��`
` :
��UJ
UT��`
`��
�UH
UT��`
`nt
rUF
UT��` 
`��
�%UD
UT��`!
`��&(table of contents goes on this page)
d&�)p''���$6�'�&ig$6�%)|   $me
��
��UUh"
[��@
ZIntroduction
(B����UT`c
[amScope
]UMUR�� 
U|WThis document provides a description of the software development environment available etejUHUR��
U��Qfor use when developing Device Drivers for the Next RISC Workstation (NRW). This mwUCUR��
U�k\develeopment environment is collectively referred to as the �driverkit�. It is assumed that �e�U>UR��
U
aRthe reader is somewhat familiar with the architecture of the NRW and with the NRW �U9UR��
UZSystem Specification, particularly the sections of the specification dealing with the I/O �U4UR��
U1WSubsystem. This document contains no descriptions of any hardware features of the NRW. ���U/UR��
UUTSIt is also assumed that the reader is familiar with the Mach Operating System API, &(t�U*UR��@
UoeGspecifically, the Mach Message mechanism and the Mach Port primitive. 
���U%UR�� q
U�ZIn the future, portions of this document will also apply to the development of User-level �U UR��q
U\device drivers for the m68k product line; Kernel support for such drivers will probably not so�UUR��q
U eZbe available for such drivers until the 4.0 Software release (at least). This document is �UUR��@q
UtiQcurrently intended to be used by developers working on the 3.1 Software release.
r.�g��UT`#
[ve	Overview
sIU
UR�� -
UU>\There are three significant features in the NRW system which are of interest for developers e VUUR��@-
Uof device drivers:
atipUUR�� r
UheONRW device drivers can run in User space as normal, non-privileged Unix tasks. em.}T�UR��r
UtaMDevice drivers in previous NeXT machines had to run in the Kernel, either as T�T�UR��r
UedTstandard parts of the release version of the Kernel, or as loadable Kernel servers. oe�T�UR��r
Ue UThe primary feature which makes this possible is that each device�s registers reside t�T�UR��r
UhiSon separate pages in the physical memory map - i.e., all of the SCSI registers are ice�T�UR��r
U68Von one page, all of the Ethernet registers are on another page, etc. Kernel functions �T�UR��r
U sRare provided to allow drivers to map in the single page containing their device�s �T�UR��@r
Uy ,registers into the driver�s address space. 
he�T�UR�� p
UasPNRW device drivers are written in Objective C. A set of standard device classes an�T�UR��p
UNRR(IODevice, DiskObject, LogicalDisk, NetDriver) has been written to facilitate the �T�UR��p
U��Rdevelopment of drivers with reasonably uniform APIs and internal structures. This T�UR��p
U��Valso allows code which is common to all drivers - or a set of drivers - to be written T�UR��@p
Ued"once and inherited by subclasses.
3T�UR�� s
U oOThe old Unix way of designing device drivers, with the standard �top half� and ake@T�UR��s
U tS�bottom half� portions of the driver, has been replaced by a thread-based model in ysiMT�UR��s
U.eRwhich no code whatsoever in the drivers themselves runs with interrupts disabled. ZT�UR��s
UreRThe concept of an interrupt handler has been replaced by a mechanism in which the gT�UR��s
UthUKernel detects a hardware interrupt and notifies a driver of this event by sending a �tT�UR��@s
UheMach message to the driver. 
ed(�C.))�ic$6�)�((I$6�'| r)
eeURUR�� v
Uit\In the initial design of the NRW, it was intended that all device drivers would run in User  sUMUR��v
UT�dspace. For a variety of reasons, this goal was deferred until at least the 4.0 release; the initial n !UHUR��v
UedUNRW release (3.1) will contain a mixture of User level and Kernel level drivers. One  .UCUR��v
Uth\implication of this is that some number of device drivers will run in the Kernel in 3.1 and s ;U>UR��v
U tWin User space in 4.0. One goal of the design of the support software described in this mseHU9UR��v
UerXdocument was to make the transition between 3.1 and 4.0 (which involves porting drivers d UU4UR��v
Uwh[from the Kernel to User space) as easy as possible; the vast majority of the functions and is bU/UR��v
U �XObjective C classes described in this document have identical APIs in the Kernel and in oU*UR��v
Uic[User space. One library, libIO, was written specifically for the purpose of minimizing the UR|U%UR��@v
Uhe@differences between Kernel and User versions of device drivers.
s d*�v++�ie$6�+�*re$6�#-| ia2UH������`F
\NRIODevice NRW Category
"UOUR�� �
UUsXThese methods are all related to NRW-specific hardware registers. Some familiarity with so/UJUR���
Ue Wthe kernel DMA interface, as well as a thorough understanding of the NRW register map, ne <UEUR��@�
U o$is required in using these methods.
isVU@UR�� 
Uv[Note that the method setDevPage: must be called to initialize to devPage instance variable  d cU;UR��
UwhZbefore any other of these methods can be used. See the section entitled �Kernel Level DMA pU6UR��@
Uv>Support� for details on how to obtain a IODevicePage pointer.
�������`�
Irn#import <driverkit/IODevice.h>
[Us�������`
Iar
l�������`
Isp@interface IODevice(NRW)
o�������`
IUR
%�������`
Idi/*
nce�������`�
Ind * Get/set hardware pointers.
�������`�
I */
�������`�
I;- (void)setDevicePage : (volatile IODevicePage *)devPageP;
�������`�
I-'- (volatile IODevicePage *)devicePage;
IO�������`�
Iy

O������`�
ITh/*
eth������`�
Id - * Get pointer to external device registers.
a������`�
IUR */
�$������`�
IMA- (void *)extDeviceRegs;
o0������`�
Ig 
t<������`�
Ip,/*
<UEH������`�
Iis6 * Get pointer to internal device-specific registers.
T������`�
Ith */
De`������`�
Ile!- (void *)intDeviceSpecificRegs;
 l������`�
IUR
�x������`�
Iny/* 
 o�������`�
In 7 * Get pointer to internal channel-specific registers.
UR�������`�
Ior */
 d�������`�
Ibt-- (void *)channelSpecific : (int)channelNum;
n�������`�
Iit
D�������`�
I��/*
`�������`�
I��: * Get pointer to chan_t registers for specified channel.
�������`�
Idi */
ce�������`�
Ind4- (volatile chan_t *)channelRegs : (int)channelNum;
 *�������`�
I�
�������`�
IeP/*
 (v�������`�
Ige7 * Get/set interrupt cause and mask registers, device 
ePa�}����`�
IIOA * and channel versions. All registers read and written as ints.
��z����`�
Ier */
te �w����`�
Ier7- (unsigned)channelIntrMask: (int)channelNum;
voi,�t����`�
I
o9-     (void)setChannelIntrMask: (int)channelNum
�8�q����`�
Iet"    mask:(unsigned)mask;
D�n����`�
I��8- (unsigned)channelIntrCause: (int)channelNum;
icP�k����`�
I��:-     (void)setChannelIntrCause: (int)channelNum
\�h����`�
Ioi#   cause:(unsigned)cause;
isth�e����`�
I��- (unsigned)deviceIntrMask;
�t�b����`�
Ian8-     (void)setDeviceIntrMask: (unsigned)mask;
����_����`�
I/*- (unsigned)deviceIntrCause;
td,�pe--���$6�-�,�$6�+0| in0ne������`�
I��:-     (void)setDeviceIntrCause: (unsigned)cause;
������`N
Iru
c������`	
Ist/*
dev)������`

I��- * Obtain device interrupt summary register.
s5������`
Ias */

�A������`�
Ier- (unsigned)intrSummary;
rM������`�
Ine
tY������`�
Int/*
nele������`�
I��F * Enable a DMA channel. Does a channel reset, configures appropriate
q������`�
I@ * direction, loads first descriptor, and enables the channel. 
ch}������`�
I@ * Kernel's IOEnqueueDma() must have been called prior to this.
el�������`�
I:  */
ha�������`�
I��+- (void)startDma: (int)channelNum
ist�������`�
I��'   dir : (IODmaDirection)dir;
���������`�
Ioi 
�������`�
I/*
sig�������`�
I��  * simple DMA channel commands.
tr�������`�
I *
,��������`
I * Set Disable Channel bit.
�������`

I*/
$�������`�
I.- (void)disableDma: (int)channelNum;
������`
Iev
I
������`
I (/*
ned������`
I��! * Set Force Buffer Advance bit.
*%������`
I
 */
 *1������`�
Ier9- (void)forceDmaBufferAdvance: (int)channelNum;
�=������`
Ins
eI������`
I��/*
��U������`
I��  * Disable channel, then reset.
�a������`
IDM */
nem������`�
Ire,- (void)resetDma: (int)channelNum;
y������`�
I�
i�������`�
Id /*
es �������`�
I��7 * Abort any pending DMA. Dequeue all enqueued frames.
en �������`�
Iis9 * dmaFreeFrame: will be called for each dequeued frame.
i�������`�
I: */
ch�������`�
I��,- (void)abortDma: (int)channelNum;
n)�������`�
I��
��������`�
I��/*
`��������`�
I��< * To be optionally implemented by subclass; this is called
��������`
I�� * as a result of dmaAbort:.
a�������`�
I�� */

�������`�
I��1- (void)freeDmaFrame: (unsigned)dma_id;
n	�}����`�
I��
�z����`�
I��/*
I (!�w����`�
I��, * Flush messages queued at specified port.
��-�t����`�
I * */
��9�q����`�
I- )- (void)flushIntrMsgs: (port_t)IOPort;
cH��X�
.�2
eH��X�
v *������h
_thyNRW Device Driver Guide    /830 of 5846                          79/24/918       COMPANY CONFIDENTIAL
� ������`
_���d/� *00�. $6�0�/��$6�-3| c%fo������`�
\amStandard data types
:"UOUR��`�
U��6The IODevice class introduces one standard data type:
:������`d
I��typedef int IOReturn;
UUGUR�� c
U��ZThis is a standard return value for methods which perform I/O. It�s analogous to the Unix bUBUR��c
Uf Rerrno. Common values for IOReturn are defined in <driverkit/deviceCommon.h>. Each oU=UR��@c
U)dUsubclass is free to define its device-specific IOReturn values in addition to these.
u�U8UR��`�
\ a#General Get/Set Parameters methods
I *�U3UR�� �
U��YThese four IODevice methods (getParameter{int,char}, setParameter{int,char}) are used in �U.UR���
URconjunction with four similarly named RPCs implemented by the kernel to provide a �U)UR���
U  [general, extensible means of accessing, from user programs, device-specific parameters for �U$UR���
UWdrivers which reside in the kernel. The main reason for this mechanism is to provide a �UUR���
UWstandard way of gathering run-time statistics of drivers which reside in the kernel by e c�UUR���
Ue ZApplications running in User space. The basic requirement of this type of operation is to �UUR���
Un \allow the definition of name/value pairs in a device-specific manner and to allow access to om�UUR���
Uet[the data so defined in a uniform manner from user level. When the driverkit functionalitry  deUUR���
Uec`resides in a shlib (instead of in a separate archive, as it currently does), this functionality dsUUR��@�
U�/will also be provided for user-level drivers. 
nt,2UUR��`�
Ur{4The general scheme of this mechanism is as follows:
ioLT�UR�� �
UrlWParameters are either arrays of integers or arrays of chars. The minimum of size of an iblYT�UR���
UngLa parameter array is one element. The maximum size of a parameters array is drfT�UR��@�
U i;IO_MAX_PARAMETER_ARRAY, a system constant (currently 512).
e a�T�UR��`�
U�>Parameters are addressed (named) via human-readable strings. 
�T�UR�� �
U kVAny subclass of IODevice can define any get/set parameters it wishes. Any class which �T�UR���
Uf Odoes so must implement the appropriate method by which the parameter(s) can be  a �T�UR���
UnnWaccessed (getParameterInt, setParameterChar, etc.). If such a method is invoked with a  fr�T�UR���
Un UparemeterName argument which the class does not recognize, the method call is passed  �T�UR���
U, Mup to super. If no classes recognize the parameterName, IODevice will return p�T�UR��@�
UevIO_DR_INVALID.
2U�T�UR�� �
UThQThe IODevice class in the kernel maintains a list which maps global unit numbers sT�UR���
U oV(IOUnitNumber) to id�s. An entry is added to this list when IODevice�s registerDevice T�UR���
U�Vmthods is called. An entry is deleted from this list when unregisterDevice is called. T�UR��@�
U c&Each entry has a unique IOUnitNumber.
6T�UR�� �
UrsOAny user program with root privileges can obtain the IOUnitName and IOUnitType claCT�UR���
U dZstrings of any instance of any driver in the kernel via the IOInquire() RPC. The instance PT�UR���
UprX- i.e., the global unit number - is specified by a IOUnitNumber in the IOInquire() RPC. er]T�UR���
UhaY(See the section entitled �Kernel-Level Driver Support� for detailed information on this tjT�UR��@�
Uoeand other related RPCs).
 d1�, 33�la$6�2�.IO$6�z IOVAURUR��`
U���$6�3�1rn$6�0=| n3 sURUR�� +
U oRAlternately, the IOUnitNumber and IOUnitType can be obtained if the IOUnitName is UMUR��@+
U�)known. This is performed via IOLookup().
 .UHUR�� �
Un ROnce a user program has determined the IOUnitNumber of a desired instance, it can ;UCUR���
U�Vuse the RPCs listed below to get or set device-specific parameters. Once again, these HU>UR���
U dSRCPs are provided by the kernel. The kernel�s DMA server works in conjunction with staUU9UR���
U�RIODevice to map an IOUnitNumber tothe id of the appropriate object. The pertinent bU4UR��@�
UUR@RPCs are listed below along with the methods to which they map:
rtz������`�
Ior
This RPC:
�������`�
I�
e�������`�
Id "IODeviceReturn IOGetParameterInt(
�������`�
I3port_t device_master,
��������`�
IIOIOUnitNumber unit,
�������`�
IIO IOParameterName parameterName,
�������`�
Iunsigned int maxCount,
�������`�
I;unsigned int *parameterArray,     // data returned here
Num�������`�
I c;unsigned int *returnedCount);     // size returned here
wn.�������`�
I v
I�������`�
IUR
....Maps to:
n�������`�
Iha
e
������`�
ItN;    getParameterInt:maxCount:parameterArray:returnedCount:
 th������`�
Iw 
g"������`�
Ipe
This RPC:
.������`�
Ith
 :������`�
I d#IODeviceReturn IOGetParameterChar(
e kF������`�
I wport_t device_master,
staR������`�
I�IOUnitNumber unit,
OU^������`�
I o IOParameterName parameterName,
inj������`�
I�unsigned int maxCount,
w v������`�
Iho=unsigned char *parameterArray,        // data returned here
��������`�
I��=unsigned int *returnedCount);         // size returned here
��������`�
Ide
e�������`�
I��
....Maps to:
I�������`�
I
��������`�
II<    getParemeterChar:maxCount:parameterArray:returnedCount:
d �������`�
I��
��������`�
Iig
This RPC:
�������`�
I/
a�������`�
Ium"IODeviceReturn IOSetParameterInt(
��~����`�
I  port_t device_master,
wn.��{����`�
I vIOUnitNumber unit,
UR�x����`�
I�� IOParameterName parameterName,
��u����`�
Ietunsigned int count,      
�r����`�
I�� unsigned int *parameterArray);
�*�o����`�
I��
�6�l����`�
I��...Maps to:
 dB�i����`�
IOG
aN�f����`�
I��+    setParameterInt:count:parameterArray::
R��Z�c����`�
II
if�`����`�
I��
This RPC:
r�]����`�
INa
p~�Z����`�
I��#IODeviceReturn IOSetParameterChar(
untd4�d 55�  $6�5�4��$6�%|);  
UT
UT��`b
`he
�eUR
UT��`o
`de
e�UP
UT��`
`��"NRW Device Driver Developer Guide
UL	UR��`+
K�Author: Doug Mitchell 
r:m.UG	UR��h 
Krr>9/10/91?
d OUD
UT��`-
`��
�d6���78���$6�7�86OS$6�} t_ceURUR��`
U���H��X�
8�76�xH��X�
~ er�������hg
_et�                                NRW Device Driver Specification    -#. of 2783                          49/10/91;       CONFIDENTIAL
� ������`i
_�f
�+������`
_serd9���:;�
i$6�:�;9�]$6�y IOReURUR��`
UrC(H��X�
;�:9H��X�
{ ������h!
_xNRW Device Driver Guide    9#: of A78B                          C9/10/91D       COMPANY CONFIDENTIAL
ce ������`l
_Gu

+������`
_�ud<���==�?$6�=�<$6�3?|��������`�
I�port_t device_master,
������`�
IIOUnitNumber unit,
UR������`�
I� IOParameterName parameterName,
�x)������`�
Iunsigned int count,      
5������`�
Iet unsigned int *parameterArray);
 NA������`�
Ipe
iM������`�
I ...Maps to:
  Y������`�
I  
 e������`�
I  ,    setParameterChar:count:parameterArray::
��q������`�
I
}������ �
UPSee the section entitled �Code Examples� for an illustration on the use of this �������@�
Umechanism. 
I 
Rd>�??�$6�?�>$6�=A| ce2r ����UT`%
[ o
IODiskDevice
 #UNUR�� B
U  aThis section to be written later. All of the drivers for 3.1 which will use the DiskObject class 0UIUR��@B
U;and it subclass LogicalDisk have already been implemented.
<JUDUR��`m
U0For reference, here�s the DiskObject interface:
��b������`o
Ide#ifdef KERNEL
n������`p
I
Iz������`q
I�/*
���������`r
Iar5 * The Unix-level code associated with a particular 
g�������`s
I  3 * subclass of DiskObject keeps an array of these 
ay)�������`H
I�1 * to allow mapping from a dev_t to a DiskObject
��������`t
I��6 * id. One per Unix unit (a unit is a physical disk).
�������`u
I�� */
�������`v
I�typedef struct {
o�������`w
Ixa2id rawDevId;      // LogicalDisk for raw device
�������`x
ImeFid livePartId;    // DiskObject/SCSIDisk (etc.) for live partition
�������`y
I)id blockId[NPART];// for block devices
�������`z
Ice/dev_t rawDev;     // used by volCheck logic
UR�������`{
I sdev_t blockDev;   // ditto

������`|
I 3} IODevToIdMap;
th������`}
I 
I"������`~
Ian#endif KERNEL
.������`
Iea
b:������`�
I/*
URF������`�
Ire& * Basic �usefulness� state of drive.
R������`�
Io */
#i^������`�
I��typedef enum {
z��j������`�
I�5IO_RS_READY,          // Ready for r/w operations
av������`�
Ila<IO_RS_NOTREADY,       // not ready (spinning up or busy)
rr�������`�
I��,IO_RS_NODISK,         // no disk present
ev�������`�
I
�.IO_RS_EJECTING        // eject in progress
�������`�
Ial} DiskReadyState;
�������`�
I��
��������`�
Ide!@interface IODiskDevice:IODevice
i�������`�
I//{
�������`$
Iev	@private
��������`%
Ili
a�������`�
IOb8id       _logicalDisk;     // first LogicalDisk object
�������`�
IT]-         // attached to this raw disk.
d�������`�
I /         // May be nil. 
��������`�
I_t)u_int    _blockSize;       // in bytes 
3�����`�
Ith/u_int    _deviceSize;      // in blockSize's 
dif�|����`�
I��7unsigned _removable:1,     // removable media device 
Ire*�y����`�
Ine1         _formatted:1,     // disk is formatted
�6�v����`�
Ity         _diskIsOpen:1,
�B�s����`�
IEA:         _isPhysDevice:1;  // this is NOT a logical disk
N�p����`I
IAD
Z�m����`�
Iy #ifdef KERNEL
f�j����`�
I��4IODevToIdMap *idMapArray; // provides dev_t to id 
evr�g����`�
I
�.        // mapping. The array itself is
~�d����`�
Ial-        // statically allocated by the
�d@�kDAA���$6�A�@ev$6�?C| ��6�������`�
Iog-        // Unix portion of the driver.
�������`�
I#endif KERNEL
������`�
Iaw.id_LogicalDiskLock;  // NXLock. Serializes
)������`�
I��*        // operations which change 
5������`�
I�+        // LogicalDisks attached to 
 //A������`�
Iif        // this device.
M������`�
I//7char_driveName[MAXDNMLEN];// for Unix 'drive_info'
   Y������`�
I//        // requests 
��e������`�
I  
en:q������`�
I�/*
 }������`�
Iic3 * The lastReadyState variable is initialized by 
IAD�������`�
I�3 * device-specific subclass, but is subsequently 
ap �������`J
Iov) * only changed by the volCheck module.
�������`�
Ipi */
 �������`�
I�d!DiskReadyState _lastReadyState;
s�������`\
Id 
t�������`^
I/*
�������`_
I' * Statistics. Accessed en masse via 
@�������``
I' * getParameterInt(DISK_STATS_ARRAY).
���������`a
I */
 �������`b
In unsigned       _readOps;
������`c
IERunsigned       _bytesRead;
_
������`d
I//,unsigned       _timeReading;      // in ms
������`e
Ionunsigned       _writeOps;
`�%������`f
I  unsigned       _bytesWritten;
A��1������`g
Iunsigned       _timeWriting;
=������`h
Ic1struct tsval   _startOp;          // private...
'I������`]
I�
/U������`�
I r}
a������`�
I��
�m������`�
I��/*
��y������`�
I��# * Register insertion notify port.
ate�������`�
Ial */
y �������`�
I�6- (IOReturn) insertNotify  : (port_name_t)notifyPort
�������`�
IJ-     ownerPort : (port_name_t)ownerPort;
�������`�
Ipi
 �������`�
I�/*
!D�������`�
ItR3 * Public methods to get and set disk parameters. 
I�������`�
I��3 * These are implemented in the DiskObject class. 
����������`�
I  */
ar�������`�
ITS- (unsigned)deviceSize;
a�������`�
I��- (unsigned)blockSize;
   �������`�
I��4- (IOReturn)setFormatted    : (u_int)formattedFlag;
��	�}����`�
Id - (unsigned)formatted;
// �z����`�
I��- (unsigned)removable;
 _w!�w����`�
I��- (const char *)driveName;
 _b-�t����`�
I��- (unsigned)isPhysDevice;
9�q����`�
I;
- (unsigned)diskIsOpen;
ucE�n����`�
I; 
 Q�k����`�
I
'/*
��]�h����`�
I��' * Public 'Eject current disk' method.

�i�e����`�
I�� */
��u�b����`�
I��- (IOReturn) ejectDisk;
ti��_����`�
I��
dB��CC�ot$6�C�B��$6�AF| rt6t)������`�
I��
�������`�
I��/*
`�������`�
I��7 * These methods must be implemented by each subclass.
ete)������`�
I�� */
��5������`K
Ile
tA������`�
Ict/*
s. M������`�
I�8 * Determine basic state of device. This method should 
aY������`�
I��2 * NOT implement any retries. It also should not 
e������`L
Itt2 * return IO_RS_EJECTING (That's only used in the
q������`�
Iat& * lastReadyState instance variable).
}������`�
I�w */
���������`�
I c- (DiskReadyState)checkReady;
�������`�
Ine
s�������`�
I��/*
`��������`�
Idi" * Device-specific eject command.
�������`�
I
' */
���������`�
I��- (IOReturn)devEjectDisk;
�������`�
I�e
��������`�
I�/*
���������`�
IOR9 * Get physical parameters (dev_size, block_size, etc.) 
�������`M
I� * from new disk. Called 
������`�
I" * upon disk insertion detection.

������`�
Irt */
t)������`�
I��- (IOReturn)getPhysParams;
`�%������`�
I��
*1������`�
It /*
ple=������`�
Icl9 * Called by volCheck thread when WS has told us that a 
tI������`�
Ict6 * requested disk is not present. Pending I/Os which 
U������`�
Iho1 * require a disk to be present must be aborted.
aa������`�
Io  */
 nm������`�
IL- (void)abortRequest;
y������`�
Iy 
d�������`�
I��/*
Iat�������`�
Ie 7 * Called by the volCheck thread when a transition to 
���������`�
Iea; * �ready� is detected. Pending I/Os which require a disk 
I���������`N
I�� * may proceed.
e-�������`�
Ima */
���������`�
I *- (void)diskPresent;
��������`�
Ije
i�������`�
I�/*

��������`�
I�8 * Inquire if disk is present; if not, and 'prompt' is 
de�������`�
I, , * YES, ask for it. Returns IO_R_NODISK if:
. �������`�
I��6 *    prompt YES, disk not present, and user cancels 
	�}����`O
I�� * request for disk.
ur�z����`�
I�# *    prompt NO, disk not present.
`�!�w����`�
I�� * Else returns IO_R_SUCCESS.
-�t����`�
I h */
d 9�q����`�
I��*- (IOReturn)isDiskPresent: (BOOL)prompt;
E�n����`�
Ihi

Q�k����`�
Iho/*
req]�h����`�
Ipr$ * Standard DiskObject I/O methods.
�i�e����`�
I�� */
�u�b����`�
ItR&- (IOReturn) readAt: (u_int)offset 
��_����`�
Iat  length : (u_int)length 
dD�siFF���dE�PePR�re$6�F�D *$6�CH| ��6��������`�
Ioi  buffer : (void *)buffer
������`�
I��;  actualLength : (u_int *)actualLength; /* returned */
res������`�
Ipr 
)������`�
I�(- (IOReturn) readAsync: (u_int)offset 
IS5������`�
I��  length : (u_int)length 
A������`�
Ius  buffer : (void *)buffer
M������`�
Ir !  pending : (void *)pending;
 Y������`�
It  
e������`�
I�%- (IOReturn) write: (u_int)offset 
tq������`�
I *  length : (u_int)length 
}������`�
It  buffer : (void *)buffer
�������`�
I��;  actualLength : (u_int *)actualLength; /* returned */
I/O�������`
I�� 
I���������`
I��)- (IOReturn) writeAsync: (u_int)offset 
s�������`
I�  length : (u_int)length 
�������`
I  buffer : (void *)buffer
�������`
I!  pending : (void *)pending;
�������`
I 
�������`
I
*�������`	
I/*
�������`

I * Private methods.
oi������`
Ivo */
uf
������`
I�
�������`

Ith/*
_in%������`
I/*+ * Register a connection with LogicalDisk.
)��1������`
I-  */
ur=������`
Iin'- (void) registerLogicalDisk: diskId;
engI������`
I 

�U������`
I/*
uffa������`
Ir
< * Implemented by DiskObject class, invoked by instance of 
��m������`
I 
7 * subclass upon completion of device initialization. 
 
ty������`
I *8 * Handles communication with LogicalDisk, polling for 
  �������`�
Iuf * disk insertion, etc.
�������`
I ( */
*)�������`
Iet- (void)registerDisk;
�������`
I��
��������`
I- /*
tur�������`
I_i * Private Get/set methods.
��������`
Iu_ */
ng�������`
I.- (void)setDeviceSize       : (unsigned)size;
�������`
Ind.- (void)setBlockSize        : (unsigned)size;
�������`
I4- (void)setIsPhysDevice     : (unsigned)isPhysFlag;
�������`
Ids- getLogicalDisk;
	�}����` 
I��7- (void)setRemovable        : (unsigned)removableFlag;
`�z����`!
Ia 2- (void)setDriveName        : (const char *)name;
!�w����`"
I��%- (DiskReadyState)getLastReadyState;
:-�t����`#
I��:- (void)setLastReadyState   : (DiskReadyState)readyState;
9�q����`$
Ied4- (void)setDiskIsOpen       : (unsigned)isOpenFlag;
��E�n����`%
Iub
sQ�k����`f
Iof/*
ce ]�h����`g
I
t * Statistics support.
Hani�e����`h
I w *
ogiu�b����`i
Ior: * These four methods are invoked by subclass during I/O.
��_����`j
I*) */
��dG�;
HH�
�$6�H�G��$6�FJ| �1��������`k
Ing- (void)startRead;
.- ������`l
Ie 5- (void)endRead             : (int)bytesTransferred;
e������`@
I: - (void)startWrite;
��)������`B
Ioi5- (void)endWrite            : (int)bytesTransferred;
�5������`C
ItL
cA������`D
I��/*
I��M������`E
Iab( * For gathering cumulative statistics.
�zY������`F
I-  */
see������`G
I: C- (IODeviceReturn)getParameterInt : (IOParameterName)parameterName
adyq������`H
I��)   maxCount : (unsigned int)maxCount
s}������`I
Ita   parameterArray : 
 �������`J
In (   (unsigned int *)parameterArray
���������`K
I��   returnedCount : 
���������`L
Ita(   (unsigned int *)returnedCount;
 *�������`M
Ii
�������`N
Is 0#define DISK_STATS_ARRAY   "IO_Disk_Statistics"
j�������`O
I
�������`P
I/*
�������`Q
I
�G * Indices into array obtained via getParameterInt : DISK_STATS_ARRAY.
�������`R
I�� */
k�������`S
ItR'#define DISK_STATS_READ_OPS        (0)
Rea������`T
Int'#define DISK_STATS_BYTES_READ      (1)
- 
������`U
I��'#define DISK_STATS_TIME_READING    (2)
   ������`V
ITr'#define DISK_STATS_WRITE_OPS       (3)
��%������`W
I��'#define DISK_STATS_BYTES_WRITTEN   (4)
mul1������`X
I�z'#define DISK_STATS_TIME_WRITING    (5)
`G=������`Y
Iet'#define DISK_STATS_ARRAY_SIZE      (6)
ramI������`Z
I��
�U������`[
Iax/*
 : a������`e
Iou
sm������`&
Ita/*
  y������`'
I
 < * internal setFormatted - avoids logical disk interaction.
���������`(
I�� */
  �������`)
I��,- (void)setFormattedInt:(int)formattedFlag;
)r�������`*
I��
��������`+
I
/*
���������`,
Iin9 * Lock/Unlock device for LogicalDisk-specific methods. 
O�������`-
I��< * Invoked only by LogicalDisks which are attached to this 
ta�������`�
Ite * device.
TAT�������`.
I�� */
R�������`/
I��- (void)lockLogical;
I�������`0
I  - (void)unlockLogical;
`T�������`1
I_S
S	�}����`2
I1)#ifdef KERNEL
�z����`3
IDI
S!�w����`4
I  - (IODevToIdMap *)getIdMap;
#d-�t����`5
IRI*- (void)setIdMap : (IODevToIdMap *)idMap;
9�q����`6
IYT
WE�n����`7
I�#endif KERNEL
dI�  JJ�Y$6�J�IE $6�HL| ��[������`8
I��
ou������`9
I&/*
/*������`:
I'8 * Convert an IOReturn to text. Overrides superclass's 
ac)������`;
I��; * method of same name to allow for additional IOReturn's 
:(i5������`
I)r * defined in DiskObject.h.
��A������`<
I�� */
��M������`=
Ioc2- (const char *)IOReturnToString : (IOReturn)rtn;
Y������`>
I��
*e������`?
Iog@end
kq������`@
Ied
 }������`A
I��/*
Ite�������`B
I��& * IOReturn's specific to DiskObject.
�������`C
ILo */

I�������`D
I  B#define IO_R_NOLABEL         (-1100)       /* no label present */
�������`E
IL
D#define IO_R_UNFORMATTED     (-1101)       /* disk not formatted */
ap�������`F
I5B#define IO_R_NODISK          (-1102)       /* disk not present */
�������`G
I7
�dK��LL�$6�L�K�$6�JN| '����UT`*
[��IONetDevice
��#UNUR�� 
U��WThe IONetDevice class is basically just an Objective C layer which sits underneath the cla0UIUR��
U��^existing kernel netif interface. Implementing netif-type protocols in User space is not going =UDUR��@
Uje$to be possible until at least 4.0. 
��WU?UR�� 

U- UThe NetDriver module consists of the IONetDevice class and the NetDriverKern module. ?dU:UR��

U��ONetwork drivers (e.g., the Ethernet driver) are subclasses of IONetDevice. The pecqU5UR��

U.
SNetDriverKern module converts netif �C� calls (e.g., a netif�s if_output_func_t or )  ~U0UR��

UreSif_getbuf_func_t) into IONetDevice method calls. The relationship between what the for�U+UR��@

U��^kernel sees as a netif module and an actual instance of a IONetDevice subclass is as follows:
�U&UR��`
UQthe if_private data of the netif is the id of the IONetDevice subclass instance.
��U!UR��`
UHThe IONetDevice class contains a netif pointer as an instance variable.
UR�UUR�� 
UIOSAt initialization time, the driver (i.e., the IONetDevice subclass instance) calls 0UI�UUR��
Uex\if_attach() in the normal fashion; all of the function pointers registered in this call are UD�UUR��@
Utofunctions in NetDriverKern.
0.
U
UR�� 
U
XWhen one of the functions in NetDriverKern is called; the netif pointer is converted to  ?UUR��
U��Pan id via if_private() and the appropriate method is invoked in the IONetDevice ec'UUR��@
U.
subclass instance.
e cAT�UR�� 
Uca^The actual functionality provided by the IONetDevice class itself is minimal; it exists along NT�UR��
U TVwith the NetDriverKern module to provide a common way for an IODevice-based driver to [T�UR��@
Uan(work with the standard netif interface.
:
������� 
\	h�������@
\ofIONetDevice Interface
�T�UR��`
\bc
s�������`
IUR#import <driverkit/IODevice.h>
ss �������`B
Ioi#import <net/netif.h>
�������`C
I��
�������`A
Iat @interface IONetDevice:IODevice
Ne������`
Ins{
������`&
IUR	@private
x�~����`'
Ihe
r$�{����`
If netif_t _netif;
r0�x����`
Iis}
<�u����`
I��
H�r����` 
I N/*
verT�o����`!
I��: * Get/set netif pointer for use with normal netif calls.
`�l����`"
Ite */
onl�i����`#
IUR#- (void)setNetif: (netif_t)Netif;
andx�f����`$
Iet- (netif_t)getNetif;
O��c����`%
IUR
�dM�T�NN�ac$6�N�M I$6�LQ| st0g ������`&
I T/*
h t������`'
IodD * Increment packet, error, and collision counts (accessed here via
��������`(
Ih H * if_ipackets(), etc.). These are typically used only internally by a 
of)������`)
Irf * IONetDevice subclass.
s5������`*
IUR */
orA������`+
Iic- (void)incrInPackets;
IoiM������`,
Iif- (void)incrOutPackets;

Y������`-
Iat- (void)incrInErrors;
e������`.
I��- (void)incrOutErrors;
��q������`/
I
x- (void)incrCollisions;
�{}������`0
In
f�������`1
I��/*
`�������`2
I��= * Methods to be implemented by subclass. These methods are 
*�������`3
Int; * invoked by the NetDriverKern module; they're basically 

on�������`D
IUR * just an Objective C layer 
�������`4
I��, * underneath the kernel's netif interface.
%�������`5
I */
��������`6
I- (int)netInit;
ac�������`7
I�(- (int)netInput   : (netif_t)realNetif 
�������`8
I(                    buf : (netbuf_t)buf
���������`9
Ime+                    extra : (void *)extra;
sed������`:
I��"- (int)netOutput : (netbuf_t)buf

������`;
I�+                    addrs : (void *)addrs;
`)������`<
Ice- (netbuf_t)netGetBuf;
`*%������`=
I��+- (int)netControl  : (const char *)command
��1������`>
Ioi*                     data : (void *)data;
=������`?
I;
 
I������`@
I- @end
n~������`F
\��NetDriverKern Interface
in�T�UR�� X
U��XThe functions in this module are registered by all subclasses of IONetDevice during the le�T�UR��X
U. `if_attach() call. The functions here just map a netif pointer to an id and forward the calls to y �T�UR��@X
UDthe appropriate driver method.
r 
�������`T
I��
*�������`W
Irn #import <driverkit/NetDriver.h>
���������`U
I��#import <net/netif.h>
�������`V
I��
��������`G
Iet#extern int netInit(netif_t netif);
��������`H
I  $extern int netInput(netif_t netif, 
��������`I
I  netif_t realnetif,
a ������`J
Iednetbuf_t nb, 
I��+������`K
I void *extra);

��7�}����`L
I�%extern int netOutput(netif_t netif, 
;C�z����`M
I<netbuf_t nb, 
)neO�w����`N
I��void *address);
t[�t����`O
Ins*extern netbuf_t netGetBuf(netif_t netif);
g�q����`P
I d&extern int netControl(netif_t netif, 
s�n����`Q
I@const char *command, 
`F�k����`R
In void *data);
dO� tQQ�re$6�P�RE d$6� h(. URUR��`9
U j $6�Q�Oor$6�NT| thop
��
��UUhd
[d.2h
ZlibIO - Kernel/User Compatibility Library
B����UT`
[etPurpose
��]UMUR�� `
U��ZThis library provides a consistent API for device drivers which may have to run in Kernel jUHUR��`
U��[space at one time (or in one configuration) and in User space at another time. Using libIO tifwUCUR��`
UJZminimizes the work or porting between the two environments. libDev itself, as well as all �U>UR��`
Uif]of the NRW Kernel level drivers, were written using libIO in order to have one set of source t�U9UR��@`
UexBfiles with minimal #ifdef�s for Kernel and User mode differences.
�U4UR�� �
UtiZFor developers who are writing User-level drivers which are known to never have to run in �U/UR���
U]the Kernel, many of these functions can be disregarded in favor of their libsys counterparts �U*UR���
UZ(e.g., malloc() instead of IOMalloc()). It is advisable to look long and hard at possible �U%UR���
U[system requirements for the next several years before making such a decision to use libsys ���U UR��@�
Uoscalls in favor of libIO calls.
bra�q��UT`t
[isImplementation
ce I������`n
\haKernel Mode
erdUUR�� w
U`WAll device drivers in the Kernel run in the kernel�s memory address space; any threads g lqUUR��w
U��\which these drivers create (using IOForkThread(), see below) are threads in a �kernel task� s ~U
UR��w
U`f- this is a task which shares the kernel�s address space but 
Vnot
U the kernel�s IPC space. Mach �UUR��w
Ufi[RPCs are available to device drivers via the mach_user_internal mechanism; this allows for elo�UUR��w
Ung]all of the Mach functions normally used in user space (e.g., port_allocate(), vm_allocate()) a�T�UR��w
Uon]to be accessed in the kernel with the standard User-level API. All of the threads created by (�T�UR��w
Ulo]all of the device drivers in the kernel run as part of one kernel task, IOTask. This task is t�T�UR��w
Uer`created early during system initialization, before any device drivers are probed or initialized bI�T�UR��@w
U��0(see the section entitled �Autoconfiguration�).
ha�T�UR��`�
\UUser Mode
U
T�UR�� �
UrsZThe current User-level implementation of libIO provides an archive (.a) file which driver 
T�UR���
Uer]developers can link into their drivers. Each driver is a separate task, with its own copy of `T�UR��@�
U wZlibIO. After some time of development and debug, libIO will be added to the libsys shlib.
H��X�
R�PEo H��X�
� mem;������`$
_lo`NRW Device Driver Guide    # of 18                          7/30/91       COMPANY CONFIDENTIAL
,  ������`m
_T�
R+������`>
_e edS�rdTT�f $6�T�S��$6�QV|  kru����UT`,
[erThread Functions
h#UNUR�� 
UUR\These functions basically provide the functionality of the cthread package in a uniform way  o0UIUR��@
UT� in both User and Kernel space. 
 ee����UT`
[guIOForkThread()
UR�U@UR��`B
U M Start a new thread. 
�U;UR��`
UUs
l�U6UR��`3
Vn #import <driverkit/libIO.h>
.a�U1UR��`
Ur CIOThread 
VIOForkThread(
UIOThreadFcn fcn, void *arg
V)
U;
ive�U,UR��`A
U�DESCRIPTION
 c�U'UR�� D
U��XThis function causes a new thread to be started up in the current task�s address space. ysU"UR��@D
UbThe thread begins execution at function 
Qfcn
U, which is passed as its argument 
Qarg
U.
8�s��UT`
[idIOSuspendThread()
VUUR��`)
U 7?Suspend the execution of a thread started with IOForkThread().
��mUUR��`+
U
~UUR��`<
V#import <driverkit/libIO.h>
f �U
UR��`.
U�8void 
VIOSuspendThread(
UIOThread aThread
V)
U;
 k�UUR��`/
UUTDESCRIPTION
ad�UUR�� 
UURSThis function causes the execution of a running thread to pause. The thread can be age�T�UR��@
U oresumed with IOResumeThread().
r a�L��UT`2
[ eIOResumeThread()
u)T�UR��`4
UURCResume the execution of a thread suspended with IOSuspendThread().
�U6@T�UR��`7
U#i
rQT�UR��`8
V.h#import <driverkit/libIO.h>
rekT�UR��`:
Ud(7void 
VIOResumeThread(
UIOThread aThread
V)
U;
`AdU�DVV�us$6�V�Un $6�TX| URDURUR��`;
UegDESCRIPTION
atUMUR��`=
U
UGThis function causes the execution of a suspended thread to continue. 
uspM����UT`?
[URIOExitThread()
penkUDUR��`@
U a/Terminate the execution of the current thread.
���U?UR��`C
UUR
��U:UR��`E
V<d#import <driverkit/libIO.h>
���U5UR��`F
UI&volatile void 
VIOExitThread()
U;
�U0UR��`G
U��DESCRIPTION
RI�U+UR�� H
U��[This function causes the execution of the current (calling) thread to terminate. Note that age�U&UR��H
U oXthere is no way for one thread to �kill� another thread other than by sending some kind 4�U!UR��@H
UxeNof message to the soon-to-be-terminated thread instructing it to kill itself.
-�r��UT`0
[.hTimer Functions
itc�n��UT`I
[UR
IOSleep()
�UUR��`J
UeT,Sleep for indicated number of milliseconds.
�UUR��`K
U
�U
UR��`L
V#import <driverkit/libIO.h>
�UUR��`M
U0void 
VIOSleep(
Uint milliseconds
V)
U;
UR�UUR��`N
URIDESCRIPTION
UR�T�UR��`O
U fSThis function causes the caller to block for the indicated number of milliseconds.
[URT�UR�� ~
UenTThe current User level implementation of IOSleep only has a resolution of 1 second; CT�UR��~
U��Zthe indicated number of milliseconds is rounded up to the next highest integral number of (T�UR��@~
U��Tseconds. When we have a thread-safe implementation of usleep(), this will be fixed.
e BT�UR��`P
Uth
ddW�URXX� n$6�X�Wth$6�VZ| 4UR����UT`Q
[es
IODelay()
&UNUR��`R
UteD�Wait� (without blocking) for the indicated number of microseconds.
nc=UIUR��`S
UUT
INUDUR��`T
VU#import <driverkit/libIO.h>
dihU?UR��`U
U��0void 
VIODelay(
Uint microseconds
V)
U;
L�U:UR��`V
UveDESCRIPTION
�U5UR��`W
U5This is a quick, non-blocking version of IOSleep(). 
�U0UR�� X
UDE\This function only guaranteed a 
Qminimum
U �spin� delay in the User level version; due um�U+UR��X
Us.\to thread scheduling, the call to IODelay() could take much longer than the indicated time. on�U&UR��X
UT�]This should not be a problem with properly designed User level drivers as this is actually a a�U!UR��@X
UUR4common real-time constraint on all User-level code.
em�r��UT`Y
[()IOTimeout()
 f-UUR�� Z
U��IArrange for the specified function to be called at a certain time in the :UUR��@Z
Ufuture.
thQUUR��`[
U
bU	UR��`\
V4#import <driverkit/libIO.h>
IO|UUR��`]
U��Ivoid 
VIOTimeout(
UIOThreadFcn fcn, void *arg, int seconds
V)
U;
s�T�UR��`_
USDESCRIPTION
UR�T�UR�� e
Uor}This function causes function 
Qfcn
U to be called in 
Qseconds
U seconds
Q, 
Uwith 
Qarg
U as 
Qfcn
U�s O�T�UR��e
UWTargument. The timeout request can be cancelled via IOUntimeout().The callout occurs  f�T�UR��@e
UntOin the context of the caller�s task, but in a thread which is unique to libIO.
X��A��UT`f
[heIOUntimeout()
T�UR��`j
Ud <Cancel an outstanding timeout request made via IOTimeout().
T�1T�UR��`x
Ube
pBT�UR��`y
Vly#import <driverkit/libIO.h>
s \T�UR��`z
U a>void 
VIOUntimeout(
UIOThreadFcn fcn, void *arg
V)
U;
dY�IOZZ���$6�Z�Yd $6�X\|  tUURUR��`{
UfuDESCRIPTION
URUMUR�� |
UU	VThis function removes a request made via IOTimeout() from the current list of pending %UHUR��|
UcnZtimeout requests. An error will be logged to the console if the specified fcn/arg pair is 2UCUR��@|
Uus(not currently registered for a callout.
Qg����UT`�
[sIOTimeStamp()
�U:UR��`�
Ucn2Obtains a microsecond-accurate current timestamp.
�U5UR��`�
Uce
d�U0UR��`�
V.T#import <driverkit/libIO.h>
���U+UR��`�
Von#import <sys/time_stamp.h>
t i�U&UR��`�
Us 4void 
VIOTimeStamp(
Ustruct tsval *ts
V)
U;
)
U!UR��`�
Ud DESCRIPTION
tsUUR��`1
UquLThis function obtains a quick, microsecond-accurate, system-wide timestamp.
orG�m��UT`6
[.hMemory Allocation Functions
 }�i��UT`�
[IIOMalloc()
n, �UUR��`�
U;
Standard memory allocator.
�U
UR��`�
U
�UUR��`�
V#import <driverkit/libIO.h>
�UUR��`�
U\*void *
VIOMalloc(
Uint size
V)
U;
�T�UR��`�
UURDESCRIPTION
ThT�UR�� �
Us ^This function causes 
Qsize
U bytes of memory to be allocated; a pointer to the memory is T�UR���
UilTreturned. No guarantees exist as to the alignment or the physical contiguity of the cu(T�UR���
UANallocated memory. The memory allocated via IOMalloc() is eventually freed via 5T�UR��@�
Ucu
IOFree().
d[�
d\\�#i$6�\�[UR$6�Z^|  iUR����UT`�
[ 	IOFree()
a&UNUR��`�
Ul %Free memory allocated by IOMalloc().
E=UIUR��`�
UUR
�NUDUR��`�
Vct#import <driverkit/libIO.h>
ndhU?UR��`�
Uwi0void 
VIOFree(
Uvoid *p, int size
V)
U;
at�U:UR��`�
U�iDESCRIPTION
I�U5UR�� }
UUUThis function frees memory allocated by IOMalloc(). Unlike the standard User version ��U0UR��}
Uve^of free(), the 
Qsize
U argument is required here to have a consistent API between Kernel �U+UR��@}
UThand User versions.
^Th�|��UT`^
[ Miscellaneous Functions
y �x��UT`�
[ pIOLog()
th<UUR��`�
UURLog a string to the console.
aSUUR��`�
Uth
ldUUR��`�
Vsi#import <driverkit/libIO.h>
UR~UUR��`�
Uca5void 
VIOLog(
Uconst char *format, ...
V)
U;
t�U
UR��`�
UT�DESCRIPTION
cu�UUR�� �
UXThis is the standard way of logging a string to the console. The arguments are stdargs, �UUR��@�
Ujust like printf.
�Q��UT`�
[UTIOVmTaskSelf()
)
aT�UR��`�
Ul *Obtain the vm_task_t of the current task.
&T�UR��`�
U
�
D7T�UR��`�
V#i#import <driverkit/libIO.h>
U?QT�UR��`�
Uvo"vm_task_t 
VIOVmTaskSelf()
U;
d]�DE^^���$6�^�]ry$6�\`| ar vURUR��`�
U��DESCRIPTION
reUMUR�� �
U
UWThis is used to obtain the current task�s vm_task_t. This function is required because an%UHUR���
UThYthe typedef of vm_task_t is a vm_map_t inside the Kernel and basically a port_t (i.e., a �2UCUR��@�
Uritask_t) in User space. 
URg����UT`�
[U
IOPanic()
�U:UR��`�
Uve>Panic or dump core, logging a �reason� string to the console.
�U5UR��`�
UV
U�U0UR��`�
V�#import <driverkit/libIO.h>
���U+UR��`�
Uth@volatile void 
VIOPanic(
Uconst char *format, ...
V)
U;
re�U&UR��`�
UURDESCRIPTION
ju�U!UR�� �
U�Q_The 
Qformat
U argument is logged to the console; then either a panic (if in Kernel space) k.
UUR��@�
U
�*or a core dump (if in user space) occurs.
:�m��UT`�
[URIOlibIOInit()
XUUR��`�
Usk2One-time only initialization of the libIO module.
oUUR��`�
U��
�U	UR��`�
V#import <driverkit/libIO.h>
�UUR��`�
Uvoid 
VIOlibIOInit()
U;
���T�UR��`�
UUMDESCRIPTION

U�T�UR�� �
UobUIn the current implementation of libIO (which is not a shlib), this function must be ��T�UR��@�
Uof1called once before using any functions in libIO.
c
�F��UT`�
[.,IOIntToString()
�+T�UR��`:
Use<Convert an integer to a string value via a regValues array.
veBT�UR��`;
U��
oYT�UR��`<
Utr
 jT�UR��`=
VU5#import <driverkit/libIO.h>
���T�UR��`>
U<dGconst char *
VIOIntToString
U(int value, regValues *regValueArray)
onsd_�U&``�RI$6�`�_
$6�^b| so(enURUR��`?
Uf DESCRIPTION
e)UMUR��`A
U�=This function is the primary use of the following data type:
�0������`�
I)
typedef struct {
k<������`�
Iitint rvValue;
H������`�
IUconst char *rvName;
	T������`�
I#i
} regValues;
t`������`�
IUR
�rU9UR�� 9
UIYThis is the same thing as the Unix reg_values struct, and it�s used for the same thing - tU4UR��9
U lVto map integer values to strings. IOIntToString provides a method for mapping a given �U/UR��9
UctUint value to a string given an int an a pointer to an array of regValues�s. One very n�U*UR��9
UngRcommon use for this mechanism is to map IOReturn�s into error strings. IODevice�s �U%UR��9
U#iK-IOReturnToString: method performs this function. A subclass which defines ng�U UR��9
UVaGadditional IOReturn values should override this method and call [super ��UUR��9
UVIOReturnToString:] if it the specified value does not match one of the class-specific �UUR��@9
UIOIOReturn�s.
���UUR��`�
Uct
 �b��UT`u
[ oXPR Functions
7UUR�� �
U��RXPR is a module which allows performance measurement and execution tracing with a DUUR���
U*rSminimum of run-time intrusion. Using XPRs is kind of like using printfs to debug a UIQT�UR���
U t\user-level program, except that making the XPR call which is equivalent to a printf is much to^T�UR���
Us Mfaster (tens of microseconds on the 68040, we�ll see about the NRW) and each 9kT�UR���
U aRprintf-equivalent is timestamped with microsecond accuracy. Typically a driver is xT�UR���
UseVinstrumented with XPR functionality using a set of macros which are converted to NULL �T�UR��@�
Utr-statements in release versions of the code. 
w�T�UR�� �
UU YThe basic mechanism of a printf-type operation in XPR is that a driver calls a function, �T�UR���
UbxprAdd(), to add one entry to a circular buffer. Each entry consists of a list of stdargs, passed �T�UR���
U�s[to xprAdd, as well as a timestamp and the current CPU number. Note that the first argument a m�T�UR���
U pein a stdargs list is a string pointer; this pointer is stored in the circular buffer, not the string .�T�UR���
Ud [itself. Later on, when the developer wishes to examine the XPR buffer contents, each entry ing�T�UR���
Uh \is converted into a human readable string by sprintf�ing the arguments originally passed to 68�T�UR��@�
Uut xprAdd(). (More on this below.)
�T�UR�� �
UalZEach module has associated with it an array of mask bits which control the amount of data T�UR���
UR Ycollected at run time. For example, in a network driver, there might be one mask bit for m!T�UR���
Urs[�packet receive� code, one mask bit for �packet send� code, one packet for �configuration� PR .T�UR���
Ual]code, etc. Events associated with a given mask bit will only be collected if the mask bit is r;T�UR��@�
UstE1. These mask bits can be manipulated by the developer at run time. 
tUT�UR�� �
Ut TThe developer can examine the printf-type strings by using an App called XPRViewer.  abT�UR���
UhiRAdditionally, in the kernel, one can examine the XPR strings from the NMI prompt. oT�UR���
UenQXPRViewer also allows manipulation of the mask bits and clearing the XPR buffer. �|T�UR���
Urt[XPRViewer is a separate task from the driver being tested (it can be on a separate host as ��da�bebb��$6�b�ait$6�`d| het URUR���
U��]well); it communicates with a server thread (in the driver or in the kernel, as the case may fUMUR���
U�Vbe) via Mach IPC; XPRViewer asks the server thread for entries, and the server thread !UHUR���
UURYsprintf�s the arguments in one entry in the circular XPR buffer and passes the resulting t.UCUR��@�
UT�Tstring back to XPRViewer, which displays the strings thus obtained in a ScrollView.

tHU>UR�� �
Ut TOne notable difference between the XPR module described here and the 2.0 kernel XPR  aUU9UR���
UhiWmodule is that there are multiple words of bit masks, allowing for more detailed event URbU4UR���
Uie[filtering. Also, in the XPRViewer App, bit masks are referred to by a human-readable name, UrtoU/UR���
UepZlike �Transmit� (for example). Other than at the time when various macros tailored to one |U*UR���
UbeWmodule are written, the developer never manipulates XPR mask bits as hex numbers, only `d�U%UR��@�
Ut as labels.
���v��UT`�
[mm
xprInit()
�UUR��`�
U(i0One-time only initialization of the XPR module.
UM�UUR��`�
Ube
iUUR��`�
Vwe#import <driverkit/uxpr.h>
entU
UR��`�
Uervoid 
VxprInit
U();
UR>UUR��`�
UguDESCRIPTION
ntOUUR��`�
U XOThis must be called once before calling any other functions in the XPR module.
r, ��T��UT`�
[ s	xprAdd()
 �T�UR��`�
Ull!Add one entry to the XPR buffer.
o�T�UR��`�
Uet
n�T�UR��`�
Vsc#import <driverkit/uxpr.h>
 XP�T�UR��`�
U�Rvoid 
VxprAdd
U(char *str, int arg1, int arg2, int arg3, int arg4, int arg5);
T�UR��`�
UURDESCRIPTION
fiT�UR�� �
UthVThis is the exported function which is used to add events to the circular XPR buffer. "T�UR���
UitUHowever, drivers typically do not use this directly; instead, they should use macros �/T�UR���
UreRwhich call xprAdd() conditionally based on the current state of xprFlags. See the <T�UR��@�
Uas!section below under �XPR Macros�
pVT�UR�� �
U��RThe last 5 arguments to this function are typed here as ints, but they are really cT�UR���
Uwe[untyped and could be any 32-bit quantity. They are stored in the XPR array as ints but are `�pT�UR���
Unt]eventually evaluated as arguments to sprint, so they could be ints, chars, shorts, or string d}T�UR��@�
UUT[pointers. See xpr_string(), below, for information on passing string pointers to xprAdd().
Uetdc�<ddd�T�$6�d�c
U$6�bf|  i4,����UT`�
[URxprClear()
DE&UNUR��`�
UURClear the circular XPR Buffer.
d f=UIUR��`�
Use
oNUDUR��`�
V c#import <driverkit/uxpr.h>
��hU?UR��`�
U dvoid 
VxprClear
U();
 �U:UR��`�
UteDESCRIPTION
d �U5UR��`�
UUR?This one�s easy; it brings the XPR buffer to an �empty� state.
ent���UT`�
[. xprSetBitmask()
���U,UR��`�
Ube/Set specified bitmask word to specified value.
 laU'UR��`�
Uth
fU"UR��`�
Vhe#import <driverkit/uxpr.h>
ly .UUR��`�
Uwe9void 
VxprSetBitmask
U(int index, unsigned bitmask);
 NUUR��`�
Us DESCRIPTION
�_UUR�� �
Unt]This is typically used by individual User-level drivers at init time, if then. Subsequently, dlUUR��@�
UUTWit is usually only used by the XPR server thread to change the current bitmask value. 
().�U	UR�� �
U_The 
Qindex
U argument is an index into the array xprMask[], which is an array of unsigned �UUR��@�
U+ints, each of which contains 32 mask bits.
DEȪU��UT`�
[URxprGetBitmask()
ar�T�UR��`�
UUI$Returns the specified bitmask word.
 c�T�UR��`�
Uit
pT�UR��`�
V��#import <driverkit/uxpr.h>
U((T�UR��`�
U�+unsigned 
VxprGetBitmask
U(int index);
s oHT�UR��`�
UgsDESCRIPTION
r YT�UR�� �
Ue.UThis is typically not used by drivers; it provides a procedural means of obtaining a  fT�UR���
UvaVspecified bitmask value. For performance reasons, the macros which are used to filter sT�UR���
UvoTand call xprAdd() typically read the index words directly (the xprMask[] array is a IO�T�UR��@�
U�	global).
ide�r-ff�ti$6�f�eUR$6�dh| he$er����UT`�
[ge
xpr_string()
t&UNUR��`�
UU	,Return a malloc�d copy of specified string.
s =UIUR��`�
Uar
 NUDUR��`�
Vs #import <driverkit/uxpr.h>
URhU?UR��`�
U, 6const char *
Vxpr_string
U(const char *instring);
�U:UR��`�
Uk(DESCRIPTION
���U5UR�� �
UthXThis function is required when you want to use a pointer to a string whose existence is it�U0UR���
UUR[transitory as an argument. The reason for this is that the string itself won�t be accessed 
r �U+UR���
Ue.Uuntil the XPR buffer is examined, which could be a long time (minutes or more) after  �U&UR���
UvaYthe call to xprAdd(). By then, the string pointer passed to xprAdd() no longer points to ��U!UR��@�
Uana useful string.
i�UUR�� �
UexTOne big caution here! The string returned by this function will never be freed. Use �UUR��@�
Uwith discretion.
(������`�
\Using XPR Macros
CUUR�� �
U_Typically, drivers do not call xprAdd() directly. Instead, each driver (or kernel module) will urnPU
UR���
Uf Yhave a set of macros which encapsulate the checking of the xprMask[] bits appropriate to >]UUR��@�
U�0that module and conditionally calling xprAdd().
nswUUR��`�
U��FFor example, suppose driver �Stub� uses two mask bits in mask word 0:
�������`�
Ise#import <driverkit/uxpr.h>
exi�������`�
IUR
��������`�
Iry:#defineSTUB_XPR_INDEX0// index into xprMask[]
�������`5
IedA#defineSTUB_XPR_SEND0x00000001// mask bit for �send�
o�������`�
I (D#defineSTUB_XPR_RECV0x00000002// mask bit for �receive�
 t�������`�
Iin
 �T�UR��`�
U nOUseful macros to use in place of direct calls to xprAdd() would be as follows:
TOn�������`�
I! <#define xpr_stub_send(x, a, b, c, d, e) {\

������`�
I@if(xprMask[STUB_XPR_INDEX] & STUB_XPR_SEND) {\
UR������`�
Ica7xprAdd(x, (int)a, (int)b, (int)c, (int)d, (int)e);\
 dr"������`�
Idu}\
��.������`�
Iet}
:������`�
Isu<#define xpr_stub_recv(x, a, b, c, d, e) {\
URF�~����`�
I m@if(xprMask[STUB_XPR_INDEX] & STUB_XPR_RECV) {\
FoR�{����`
I d7xprAdd(x, (int)a, (int)b, (int)c, (int)d, (int)e);\
��^�x����`
I<d}\
��j�u����`
I
�}
v�r����`�
I#d
ndg�exhh���$6�h�gEN$6�fj| 
o��URUR�� 
UinQThese macros would typically be conditional on an #ifdef UXPR (currently UXPR is nUMUR��
U�Sdefined to be 1 for DEBUG configurations); for release versions, the macros should TOn!UHUR��@
U! compile to �nothing�:
9������`
I{)#define xpr_stub_send(x, a, b, c, d, e) 
iE������`
I_I(#define xpr_stub_recv(x, a, b, c, d, e)
URQ������`
Ica
lU:UR��`
U(i(In the driver, the usage would just be 
���������`
Iextern int foo;
���������`

I}

��������`	
I#d=xpr_stub_send(�Log this entry; foo = 0x%x\n�, foo, 2,3,4,5);
~�U,UR�� �
Ui\The last 4 arguments are necessary to avoid compiler errors, since xpr_stub_send() requires (x�U'UR���
U(iW6 arguments. Some programmers will surely find ways around this hassle; the above form I
��U"UR��@�
U�Xmerely keeps one on one�s toes to ensure that one knows what arguments are going where.
������`�
\!Standard XPR #defines and Macros
o UUR�� �
U��WThe file <driverkit/DeviceUxpr.h> contains common bit mask and macro definitions which s n-UUR���
U�Zare used by the libDev device classes. Other drivers should not use these same bit masks. :UUR��@�
UcoFCommon bit masks for kernel drivers are in <driverkit/KernDevUxpr.h> 
di�#djj� a$6�j�ica$6�hl| he" w
��
��UUh�
[��-i
ZThe Thread Based Model of Device I/O
�B����UT`
[��	Overview
d]UMUR�� 
UogZThe traditional Unix device driver design involved a conceptual �top half�, which is code jUHUR��
Uco`called from higher layers in the kernel to initiate an I/O, and a �bottom half�, which consists s wUCUR��
Uay\of various interrupt handlers and I/O complete logic. The simple model of an I/O using this o �U>UR��@
Uowdesign is:
nts�U9UR�� 
U_Higher level Kernel code calls the driver�s strategy() or write() (or ...) routine to start an /De�U4UR��@
UnsI/O.
 �U/UR�� 

U dXThe strategy() routine enqueues the I/O on an I/O queue which is private to the driver, ve�U*UR��@

UthSperhaps after massaging the incoming data structure into a driver-specific format.
<dr�U%UR��`
Ur.\If the bottom half of the driver is idle, call a start() routine to get the hardware going.
U UR�� 
URThe bottom takes over from here. When an interrupt occurs, the driver�s interrupt UUR��
U
�Shandler runs and either decides that the hardware needs some more attention before ver UUR��
U cTcompleting the I/O (in which case a state machine is advanced and the driver awaits  t-UUR��
UatXanother interrupt), or that the I/O is complete (in which case higher level code in the  h:UUR��@
Ump"kernel is notified of this fact).
TUUR�� 
UU>\Things actually get much more complicated than this. For one thing, there tends to be a lot r�aUUR��
UitZof code that sometimes runs at interrupt level and sometimes runs at ipl0. One example of nT�UR��
Unq`this kind of code is the routine that starts up an I/O. In the above example, this code runs at r {T�UR��
Umi]ipl0, but if at I/O complete time there is more work to be done, the interrupt handler calls  �T�UR��@
U, the startup routine as well. 
�T�UR�� 
U]Portions of device driver code which run at interrupt level can get out of control resulting n�T�UR��
U��Yin cases where some interrupts are disabled for hundreds of microseconds (or even more), e�T�UR��
UYseriously hampering system throughput and crippling the ability of the system to respond t�T�UR��@
Uat6to real time events like the arrival of serial data. 
�T�UR�� 
UveWAnother problem with running some subset of a driver�s code at interrupt level is that UU>�T�UR��
Uge]performing locking of shared data structures (even if they are only shared between the files t�T�UR��
Uet\comprising one device driver) is difficult on a multiprocessor system. To access a critical th
T�UR��
U t\data structure on a multiprocessor system, when the data can be accessed at interrupt level miT�UR��
UI/\by all CPUs, non-interrupt code must first disable interrupts on both CPUs and then acquire , $T�UR��@
Uin	a lock. 

>T�UR�� 
UYNRW device drivers have avoided all of these problems by disposing of the Unix model and iKT�UR��@
UIchoosing instead a thread-based paradigm. Basically, the model is this: 
neT�UR��`
U e@Drivers are notified of hardware interrupts via Mach messages. 
ipdk� rll�$6�l�k a$6�jn| ve!heURUR�� 
UniWThere is one thread which is responsible for any given hardware device. This thread is forUMUR��@
Uarcalled an I/O thread.
.UHUR�� 
UshUAt any given time, a driver�s I/O thread is either executing (i.e., dealing with the t;UCUR��@
UorNhardware) or waiting for one of two things - new work to do, or an interrupt.
UU>UR�� 
UheYThis model is intended to be used for drivers both in the Kernel and in User space. This rbU9UR��@
UstQmodel has been found to simplify driver development and to minimize debug time. 

|U4UR��`
U?The above three bullet items each merit a detailed discussion.
ing�����UT`
[ aInterrupt Notification
Ich�U+UR�� 
Uhr[As far as the low-level kernel code is concerned, handling device interrupts is easy. When d o�U&UR��
Upt\an interrupt occurs, the kernel masks off further occurrences of that particular interrupt, �U!UR��
U\sends a message to a port, and returns from the interrupt. The port to which the �interrupt ea�UUR��
UibZmessage� is sent belongs to a device driver, which at some time previously has registered UUR��
Uathis port to be associated with this particular interrupt. Each interrupt bit is associated with R
UUR��
Uwa_either 0 or 1 interrupt ports. (See the section of this document entitled �Kernel Level Driver s mU
UR��
Uo ZSupport� for details on the interrupt port registration mechanism.) The interrupt message 'UUR��
UsiYcontains no information other than a msg_id in its message header, which identifies this e4UUR��
Uh ]message as an interrupt message. It is up to the driver to receive this message, examine the AT�UR��
Ue [hardware to determine the cause of the interrupt, perform whatever action is necessary for NT�UR��
U oZcontinuing the I/O in progress, and finally to notify the kernel that it should re-enable [T�UR��
Ume[interrupt notification for the device in question. Only when the kernel is so notified can ��hT�UR��@
U i1another interrupt message be sent to the driver.
m��@��UT`
[egOne Device, One Thread
U�T�UR�� 
Uas[A device driver is responsible for maintaining and dealing with three kinds of resources - �T�UR��
U1 \hardware, private data, and client I/O requests. In a multiprocessor system, or in a system ���T�UR��
U f]in which device driver code contains actual interrupt handlers, a great deal of care must be �T�UR��
Uinbtaken to protect access to all three of these resources; locks and spl()�s are required in almost �T�UR��
Uup[every routine. Looking at the current m68k drivers, it is apparent that even with the most [ha�T�UR��
Ue Ywell-thought out design, the need for spl()�s and locks has caused a lot of problems and oT�UR��
U/OXextra crufty code. This problem is most apparent in code which manipulates the hardware meT�UR��@
Uca
directly.
-T�UR��`
Un.,There is a simple solution to this problem:
T�GT�UR��  
UanVGiven any hardware resource, one and only one thread can deal with that resource at a TT�UR��@ 
U��>time. The resource is never accessed in an interrupt handler.
dm� -nn�1 $6�n�mnt$6�lp|  o' sURUR�� !
U��YFor example, take the SCSI controller chip. If there is exactly one thread in the system aUMUR��!
UUR^which can access that resource, there is no need for locking or for spl()�s around code which !UHUR��@!
UT�accesses this hardware. 
t;UCUR�� "
Ue ^Another way of looking at this is that for a given piece of hardware, there is only one thing HU>UR��"
U n^which can be happening at a time. At point A, a driver might be setting up a chip to start an UU9UR��"
Uis]I/O. At point B, the driver might be waiting for an interrupt from the chip. At point C, the RbU4UR��"
Ue ^driver might be responding to an interrupt and interrogating registers to see what caused the oU/UR��"
U ccinterrupt. A driver is never setting up a chip to start an I/O at the same time it�s interrogating rru|U*UR��"
U]registers to see what caused an interrupt. All these operations are single threaded. In Unix �U%UR��"
UYdrivers, this single threading is performed by a combination of locking, spl()�s, and an f�U UR��"
Uon]interrupt-driven state machine. In the NRW, this single threading is done by, well, a single f�UUR��@"
Usp0thread. Let�s call this thread an �I/O thread�.
ss�UUR�� #
U
t[Another reason for this model is the desire to have drivers run in user space. There is no her�UUR��#
Ug Xpractical way for User-level drivers to actually run interrupt handlers with interrupts in�UUR��#
UrtVdisabled. The fundamental quanta of program control in User space is the thread. Some �UUR��#
UpoUdrivers in exceptional cases may choose to have multiple threads access one piece of o�UUR��#
Uo [hardware; the �one device, one thread� model is not an absolute. It�s merely a design goal tar�T�UR��@#
UmeFwhich has proved to be a viable basis for writing NRW device drivers.
3�N��UT`
[t.Simple Thread Model
arNT�UR�� $
U I\Let�s look at a simple piece of hardware, the Floppy controller chip. Floppy I/O is totally lo[T�UR��$
Ud `single threaded - you start up an I/O, wait for an interrupt, diddle some registers, and you�re e hT�UR��$
U f\done. A single thread which �owns� this controller chip is doing one of three things - it�s AnuT�UR��$
Uhibidle and waiting for work to do, it�s executing (i.e., twiddling bits in the controller chip), or �T�UR��$
Uev]it�s waiting for an interrupt. That�s all it ever does. At the highest level, the Floppy I/O  �T�UR��@$
Uanthread looks like this:
se�������`%
IeafloppyThread()
��������`&
Iin{
��|����`'
I c#initialize local data structures;
 on��y����`)
IURinitialize hardware;
��v����`*
Inewhile(1) {
 i��s����`+
I I)wait for an I/O request from a client;
#��p����`-
Iov/set up the controller chip to start the I/O;
ive��m����`.
Iwait for interrupt;
�j����`/
I$6diddle with controller registers to finish the I/O;
�g����`0
I. !notify client of I/O complete;
��d����`,
Ihr}
 - +�a����`(
IO,}
FT�UR�� 1
U, bNot all devices are this simple, but this illustrates how a single thread is sufficient to do all ST�UR��@1
Uoi1the manipulation of a single hardware resource. 
ido� ipp�wi$6�p�o),$6�nr|  a(rr������`W
\ e:Communication between Exported Methods and the I/O Thread
"UOUR�� 2
UooYThe one tricky part of this model is the communication between a driver class�s exported �/UJUR��2
UizVmethods and the I/O thread. In some cases, an exported method needs to do synchronous <UEUR��2
U i[communication with the I/O thread - that is, the exported method wants to send some quanta p tIU@UR��2
U t`of work to the I/O thread and wait (sleep) until that work is done. In other cases, an exported h VU;UR��2
Urs\method does asynchronous I/O - it just wants to send a quanta of work to the I/O thread and hrcU6UR��@2
U��be done with it.
R}U1UR�� X
UalQBoth types of I/O - synchronous and asynchronous - can be performed via Mach IPC o�U,UR��X
U��Ybetween the exported methods and the I/O thread. This technique is 
Vnot
U generally �U'UR��X
UTrecommended, but it�s sometimes useful. A Mach IPC interface is generally done with  a�U"UR��X
U��VMIG, though some programmer prefers hand-coded messages and explicit msg_rpc() calls. �UUR��@X
Uar3This technique is adequately documented elsewhere.
 cl�UUR�� Y
UUJVOne reason that this technique is generally not recommended for communication with an �UUR��Y
UUEVI/O thread is performance. A msg_rpc() between threads in one task (which is the case �UUR��Y
UtaXwhen a class�s exported method wishes to communicate with that class�s I/O thread) is a ne�U	UR��Y
Uan[pretty heavyweight operation. A more efficient way to do this is with condition locks. The ta �UUR��Y
U tVclass NXConditionLock is documented elsewhere; this is the typical mechanism by which T�UR��Y
UanXexported methods send I/O requests to an I/O thread and by which exported methods sleep  mT�UR��Y
U tYuntil an I/O request is complete. (Note: I know that User level implementations of sleep  &T�UR��Y
UA Plocks and condition locks currently use Mach RPC as their underlying mechanism.  p3T�UR��Y
Uha[Hopefully, this will not always be the case. Kernel level implementations of both of these ate@T�UR��@Y
Uwh(use lower-level scheduling primitives.)
haZT�UR�� E
Us WAnother reason this technique is to be avoided is that using Mach messages to transfer erfgT�UR��E
U()\information between threads in a single task is kind of messy; most of the information in a metT�UR��E
UmuYMach message exists to allow marshalling of various data types and to facilitate sending i�T�UR��E
Unt]complex data over a network interface. Neither of these operations of required for intratask d�T�UR��@E
Ue;communication.
cal�T�UR�� Z
Uh ZThe general technique for passing I/O information from a driver�s exported methods to its �T�UR��@Z
U mI/O thread is as follows:
�T�UR�� [
UcoPDefine a struct which will serve as a �command buffer�, the fundamental unit of A �T�UR��[
UioNcommunication between exported methods and the I/O thread. The command buffer �T�UR��[
Uhi\(let�s call it a cmdBuf_t) is different for each driver; it contains all of the information Y�T�UR��[
UveUneeded by the I/O thread to perform a single I/O. For example, a cmdBuf_t for a disk eT�UR��[
UsiXdriver might contain a disk address, a VM address, a byte count, and a read/write flag. glT�UR��[
UmeRThe cmdBuf_t also contains fields by which the I/O thread can indicate completion T�UR��@[
UvaVstatus - for example, a device-specific status field and a �bytes transferred� field.
7T�UR�� ^
UeiNThe cmdBuf_t also contains an NXConditionLock. This lock will be the means by DT�UR��^
UURVwhich an exported method sleeps until an I/O is complete. We�ll call this cmdBufLock. QT�UR��^
UT�DcmdBufLock�s condition variable will have two states - COMPLETE and ne^T�UR��@^
UllNOT_COMPLETE.
dq� orr�io$6�r�qet$6�pt| r 0URURUR�� \
U�sTDeclare a queue as an instance variable on which cmdBuf_t�s are enqueue by exported YUMUR��\
UveUmethods and dequeued by the I/O thread. This queue will be referred to as ioQueue in e!UHUR��\
UsiVthis discussion. (The implementation of the queue - singly linked list, Mach queue_t, .UCUR��@\
U[.etc., isn�t important; it�s device-specific.)
HU>UR�� ]
Un TDeclare an NXConditionLock as an instance variable; this protects the I/O queue and usUU9UR��]
Us ]also provides a way for the I/O thread to sleep until it has work to do. We�ll refer to this obU4UR��]
UnsHas ioQueueLock. ioQueueLock�s condition variable will have two states - cooU/UR��@]
U t!QUEUE_EMPTY and QUEUE_NOT_EMPTY.
��U*UR��`_
UdiJAn exported method wishing to perform synchronous I/O does the following:
�������``
I+- (IOReturn)someMethod : (int)someArgument
�������`a
I{
�������`f
IcmdBuf_t cmdBuf;
�������`g
Ir 
�������`d
I\0fill in cmdBuf fields appropriate to this I/O;
hi�������`h
Ien4Initialize cmdBufLock to condition �NOT_COMPLETE�;
de�������`i
Ith
d�������`j
Ibe/*
re������`k
I eC * Enqueue this cmdBuf on ioQueue and let I/O thread know that it
ue 
������`m
Ist * has work to do.
UR������`l
I,  */
m%������`b
Ice[ioQueueLock lock];
�1������`e
Ianenqueue cmdBuf on ioQueue;
e =������`n
Ite4[ioQueueLock unlockWithCondition:QUEUE_NOT_EMPTY];
viI������`o
II/
hU������`p
Il /*
 wa������`q
Ief?  * Now wait for I/O thread to process the cmdBuf and signal 
ondm������`r
Il  * completion.
coy������`s
I t */
_�������`t
IT_)[cmdBuf.cmdBufLock lockUntil:COMPLETE];
e�������`u
Irf[cmdBuf.cmdBufLock unlock];
l�������`�
I��
`�������`v
Iso/*
od�������`w
Int  * I/O is complete. 
{
�������`x
I */
u�������`y
I��"Free necessary data from cmdBuf;
�������`z
IfiReturn I/O result;
is�������`c
I��}
��}����`{
Icm
fT�UR��`|
U�NXThe I/O thread calls the following while awaiting work to do from the exported methods:
 $�u����`}
IBu
n0�r����`~
I/O- (cmdBuf_t *)waitForWork
<�o����`
I {
H�l����`�
I��cmdBuf_t *cmdBuf;
/
mT�i����`�
Ice
[`�f����`�
I
�*[ioQueueLock lockUntil:QUEUE_NOT_EMPTY];
l�c����`�
I��*dequeue head of ioQueue, save in cmdBuf;
x�`����`.
Iviif(ioQueue empty)

h��]����`�
Il ([ioQueueLock unlockWith:QUEUE_EMPTY];
t ds�uftt���$6�t�s��$6�rv| T_(dB������`/
IUnelse
P������`0
I��+[ioQueueLock unlockWith:QUEUE_NOT_EMPTY];
��������`�
I��return cmdBuf;
/)������`�
Iw}
5������`5
Ile
 PUCUR�� 6
UxYAfter performing the I/O, the I/O thread does the following to notify the client (who is R]U>UR��@6
UisBsleeping in the exported method which generated the I/O request):
u������`7
Ial
t�������`8
I a*- (void)doIoComplete : (cmdBuf_t *)cmdBuf
�������`9
I}{
�������`:
I~[cmdBuf->cmdBufLock lock];
k
�������`<
I +[cmdBuf->cmdBufLock unlockWith:COMPLETE];
/
m�������`;
Ice}
�������`4
\
�1Other types of communication with the I/O Thread
�U$UR�� 3
UueRAsynchronous I/O is a subset of the above code example. For asynchronous I/O, the UUR��3
ULexported method does not have to do a lockUntil: on cmdBuf.cmdBufLock after UUR��3
U��Tenqueueing the cmdBuf on ioQueue; the method returns immediately. Likewise, the I/O dB(UUR��@3
UUn/thread need not call the doIoComplete: method.
kWiBUUR�� =
U];YSome drivers require their I/O threads to be able to service incoming I/O requests while  OUUR��=
UxYwaiting for interrupt messages. The SCSIController class is an example of this. The SCSI R\UUR��=
UisWbus is capable of performing overlapped I/Os, in which one I/O can be started up while 
tiUUR��=
U a^another I/O is in progress and is disconnected from the bus. In this case, the SCSIController vT�UR��=
Uk]]I/O thread receives both its I/O requests as well as its interrupt messages on the same port 
�T�UR��=
U
�Yset. The port set consists of an interrupt port and a command port. Messages sent to the i�T�UR��=
UabVcommand port are �Mach message wrappers� around a cmdBuf_t-type structure. (Actually, �T�UR��=
UckWthe messages merely contains a pointer to a cmdBuf_t; this of course couldn�t work for e; �T�UR��=
U iSmessages which are passed between tasks, but the SCSIController�s exported methods mpl�T�UR��=
UUValways execute in the same memory address space as its I/O thread.) Sometimes the I/O �T�UR��=
U  Vthread needs to only wait for an interrupt, without wanting to deal with incoming I/O �T�UR��=
USC_requests; in this situation, the I/O thread removes the command port from its port set so that tar�T�UR��=
UU[it only will respond to interrupts. When it is able to deal with I/O requests, it adds the the�T�UR��@=
UT�%command port back into its port set.
oT�UR�� >
Us XSometimes, for performance (or other) reasons, a driver might have its exported methods t T�UR��>
UerZperform some I/O directly without going through the I/O thread. The Ethernet driver is an T�UR��>
UerWexample of this. The netOutput: method, which is called when a client wishes to send a  co,T�UR��>
Uo Zpacket out to the net, usually performs no I/O - it just adds a DMA frame to the device�s 9T�UR��>
U bXDMA queue. The exported method does this directly without waking up the I/O thread. The meFT�UR��>
UacXEthernet I/O thread basically just services interrupts and dispatches incoming packets. r ST�UR��>
Uou]There is a lock implemented in the driver to allow this type of behavior. This lock protects t`T�UR��@>
Uco]access to the hardware in the case where the netOutput has to start up an idle DMA channel. 
sdu� rvv�he$6�v�u b$6�tx| s 	ti������`?
\;Summary
) "UOUR�� @
UmiXThe above model is just provided as a guide. As evidenced by the previous section, some in/UJUR��@
UthYdriver have their own peculiar I/O thread communication requirements and many variations d<UEUR��@
Uwh]on this standard model will exist. However, it�s clear that each driver which has to respond oIU@UR��@
Us Zto interrupts has to have at least one thread (which does msg_receive()�s on an interrupt VU;UR��@
Ukidport); the premise being made here is that these drivers should have 
Vexactly
U one I/O thread tscU6UR��@@
UcoWwhich services interrupts and does as much of the low-level bit twiddling as possible.
thi}U1UR�� A
U. XSee the section of this document entitled �Code Examples� for more illustrations of the Ou�U,UR��@A
Uupconcepts presented above.
dw�xx�$6�x�w$6�vz| !��
��
��UUh&
Z��$j1Kernel-Level Driver Support
e 'UQUR�� Y
Uid=This section describes an interface which was designed to be J4ULUR��Y
Udr[architecture-independent as much as possible. Due to the nature of the functions described URAUGUR��Y
Uhi_here, there are a number of limitations and qualifications referring to architecture type. The ��NUBUR��@Y
UruSarchitectures are referred to as �m68k� (current 680x0 products) and �m88k� (NRW).
UR�����UT`L
[);
Device Ports
i�U9UR�� Z
UatYRights to access a device's registers, to program its DMA channel, and receive interrupt v�U4UR��Z
Ud ^notification are conveyed by a task holding send rights to a per-device port referred to here �U/UR��Z
U efas the 
QdevicePort
U. The kernel responds to requests sent on the devicePort in order to provide �U*UR��Z
U�_these services to the requesting task. devicePort's are created early in system initialization �U%UR��Z
U^and passed out to the appropriate device drivers by a process that is described later, in the �U UR��Z
Un Zsection entitled �Autoconfiguration�. Operations are performed upon device ports by a via �UUR��@Z
U tRPCs to a kernel server.
d!�l��UT`[
[URRegister Mapping
 <UUR�� \
U o[This interface provides various mechanisms for device drivers to map the physical register SarIU
UR��\
Ufe[space associated with their devices into their local address space. Which mechanism(s) can PorVUUR��\
UZZbe used by a particular device driver are determined by the machine architecture, whether cUUR��@\
UZ_the device is a native device or a NextBus device, and the Slot ID in which the device lives. 
re }T�UR�� ]
U e_For the purposes of the following discussion, an 
VNRW DMA Device
U is defined as a device rov�T�UR��]
UZ[in an m88k machine which resides in a slot with whose NextBus slot Id bits 9 through 7 are iza�T�UR��@]
U��`'111'. A 
Vnative m68k device
U is a device which is an integral part of an m68k-based CPU.
n �T�UR�� ^
UZ[There are three kinds of device register space which can be mapped in to a device driver's ia �T�UR��@^
U tlocal address space:
e�T�UR�� _
V[\Register Space
U consists of one page (the size of which is machine dependent but can for ev�T�UR��_
U tYnow be assumed to be 8k bytes) consisting of device-specific registers. For NRW devices, r�T�UR��_
Uce]the format of a device page is defined in the NRW system specification, section 5.2.8.2. For e�T�UR��_
UinZm68k devices, a device page is the physical memory region comprising all of the registers T�UR��@_
UID\in one native device; the start of the register space may not be page-aligned in this case.
si&T�UR��``
] Dm88k devices:
@T�UR�� a
UovTA driver can map in a register page if and only if it is associated with an NRW DMA otMT�UR��@a
U 7	Device. 
�gT�UR��`b
]'1m68k devices:
�T�UR��`c
U�_A driver can map in a register page if and only if it is associated with a native device.
N 
 kidy� czz�ev$6�z�y t$6�x|| [stURUR��`d
NstP
VSlot Space 
Uconsists of up to 16 MB of memory, starting at 0xfs000000. 
_!UMUR��`e
]edm88k devices:
;UHUR�� f
UicKAn NRW DMA device driver can map in the first 0xf00000 (15 M) bytes of its  deHUCUR��f
UedTassociated slot space, or a portion thereof. A non-NRW DMA device driver can map in icUU>UR��@f
Uis7all 16 MB of its slot space, or a portion thereof
N.
rs oU9UR��`g
]IDm68k devices:
�U4UR�� h
UofUOnly drivers associated with non-native devices can map in slot space; native device d�U/UR��@h
U��1drivers have no slot space associated with them.
d�U*UR��`i
VocBBoard space 
Uconsists of up to 256 MB, starting at 0xs000000. 
�U%UR��`j
]icm88k devices:
�U UR�� k
U cXDrivers associated with devices in slots 13 and 14 are allowed to map in all or part of �UUR��@k
UAtheir board space. Other drivers can not map in any board space.
UUR��`l
]m68k devices:
%UUR��`m
UstHOnly drivers associated with non-native devices can map in board space.
y,Z�b��UT`
[00Initialization RPCs
e��^��UT`p
[:
IOAttachInterrupt()
An�UUR��`q
Uiv Request interrupt notification.
15�T�UR��`r
Ude
C�T�UR��`s
Vas"#import <driverkit/user_driver.h>
�T�UR��`t
UMA&IODeviceReturn 
VIOAttachInterrupt(
�T�UR��`u
UB $IODevicePort 
QdevicePort
U,
f
T�UR��`v
U��port_t 
Qintr_port
U);
T�UR��`w
U d
e7T�UR��`x
U n
DESCRIPTION
eHT�UR�� y
VspUIOAttachInterrupt
U() requests that interrupt notification messages for the device eUT�UR��@y
UiIrepresented by 
QdevicePort
U be sent to the port 
Qintr_port
U.
%oT�UR�� z
Um8YOnly a single port may be attached for device interrupts at any point in time. (A policy l|T�UR��@z
U o-decision, more than functional requirement.)
pd{�an||�UR$6�|�{UR$6�z~|  nivURUR��`{
UinPIn NRW, this request also binds a device interrupt with a global interrupt bit.
IO!UMUR��`|
QAnFdevicePort
U is the port representing the device access capability.
;UHUR��`}
Q��Qintr_port
U is the port to which interrupt notification messages will be sent.
Vp����UT`~
[(
IODetachInterrupt()
�U?UR��`
Ude Disable interrupt notification.
���U:UR��`�
Utr
r�U5UR��`�
V��"#import <driverkit/user_driver.h>
�U0UR��`�
UUR*IODeviceReturn 
VIODetachInterrupt
U(
�U+UR��`�
Uno#IODevicePort 
QdevicePort
U,
UT��U&UR��`�
Ureport_t i
Qntr_port
U);
 
U!UR��`�
Ut 
DESCRIPTION
U$UUR�� �
VzSIODetachInterrupt
U disassociates interrupt notification messages for the device (A 1UUR��@�
U��Hrepresented by 
QdevicePort
U from being sent to 
Qintr_port
U.
�f�h��UT`�
[IOAttachChannel()
�UUR��`�
U�,Attach a DMA channel to a specified device.
~�U	UR��`�
Uiv
R�UUR��`�
VIn"#import <driverkit/user_driver.h>
�T�UR��`�
Ua (IODeviceReturn 
VIOAttachChannel
U(
An�T�UR��`�
Us #IODevicePort 
QdevicePort
U,
ss �T�UR��`�
UURint 
QchannelNumber
U,
t�T�UR��`�
UntBOOL 
Qstream_mode
U,
il�T�UR��`�
U��int 
Qbuffer_size
U);
t(T�UR��`�
U
DESCRIPTION
n+T�UR�� �
VonIIOAttachChannel
U associates a system-wide global DMA channel with the r8T�UR��@�
U��edevice-specific local channel 
QchannelNumber
U of the device represented by 
QdevicePort
U.
RT�UR�� �
U��UA 
VIOAttachChannel
U must be performed for each physical DMA channel to be used �_T�UR��@�
UInwith the device. 
yT�UR��`�
QtiFdevicePort
U is the port representing the device access capability.
d}�t ~~��$6�~�}ne$6�|�| nna URUR�� �
Q~WchannelNumber
U is the device-specific local DMA channel number that should be bound ��UMUR��@�
URewith a global DMA channel.

An.UHUR�� �
Qs Tstream_mode
U specifies whether or not the device-specific hardware is capable of 
U;UCUR���
U�Rgenerating an End Of Record signal on input. See the description for IOEnqueueDma HU>UR��@�
U�1for more information on streaming mode channels.
hbU9UR�� �
QesZbuffer_size
U is the device-specific DMA buffer size. The kernel needs this information oU4UR���
UbeQwhen performing DMA dequeue operations; it is also used in verifying correct DMA |U/UR��@�
U alignment.
rme�����UT`�
[l IODetachChannel()
�U&UR��`�
U�(Dissociate a DMA channel from a device.
ti�U!UR��`�
Us 
 �UUR��`�
Vth"#import <driverkit/user_driver.h>
UUR��`�
U(IODeviceReturn 
VIODetachChannel
U(
UUR��`�
U#IODevicePort 
QdevicePort
U,
|+U
UR��`�
UURint 
QchannelNumber
U);
KUUR��`�
Usp
DESCRIPTION
A\UUR�� �
VatWIODetachChannel
U disassociates the local DMA channel 
QchannelNumber
U from the Qs iT�UR��@�
Usp*device represented by 
QdevicePort
U.
��O��UT`�
[ oIOMapDevicePage()
�T�UR��`�
Un 1Map a device page into a driver�s address space.
f�T�UR��`�
UU>
R�T�UR��`�
Vmo"#import <driverkit/user_driver.h>
�T�UR��`�
U��(IODeviceReturn 
VIOMapDevicePage
U(
ecT�UR��`�
Uze#IODevicePort 
QdevicePort
U,
oU4T�UR��`�
Uwh!vm_task_t 
Qtarget_task
U,
s%T�UR��`�
Uin1vm_offset_t *
Qaddr
U,/* in/out */
m2T�UR��`�
UUTBOOL 
Qanywhere
U);
RT�UR��`�
U�DESCRIPTION
 DcT�UR�� �
UdeLIOMapDevicePage maps the device register page of the device associated with drpT�UR���
U��XdevicePort into the target task at addr. This RPC is invalid for m88k devices which are 
Q}T�UR��@�
U5not NRW DMA devices and for non-native m68k devices.
d�U���ta$6���ca$6�~�| heT�URUR��`�
Qde=devicePort
U is the kernel provided handle for the device.
O!UMUR��`�
QT�Ztarget_task
U represents the address space into which the device page should be mapped.
;UHUR��`�
QmoWaddr
U is the address in 
Qtarget_task
U where the device page should be mapped.
ageUUCUR�� �
Q��Wanywhere
U is a boolean; if YES, indicates the kernel may pick any unused address to getbU>UR��@�
UURmap the device page.
e�����UT`�
[IOUnmapDevicePage()
T��U5UR��`�
U4Remove a device page from a driver�s address space.
IO�U0UR��`�
U�
e�U+UR��`�
Vma"#import <driverkit/user_driver.h>
�U&UR��`�
Uit*IODeviceReturn 
VIOUnmapDevicePage
U(
U!UR��`�
Udd#IODevicePort 
QdevicePort
U,
es UUR��`�
UUR!vm_task_t 
Qtarget_task
U,
nUUR��`�
U68vm_offset_t 
Qaddr
U);
�>UUR��`�
UDESCRIPTION
OU
UR�� �
VTIOUnmapDevicePage
U unmaps the device register page of the device associated with �\UUR���
QUhdevicePort
U. 
Qtarget_task
U and 
Qaddr
U must match similar parameters passed to a previous ssiUUR��@�
Uthcall to IOMapDevicePage().
d.
��T��UT`�
[moIOMapSlot()
th�T�UR��`�
Uar.Map slot space into a driver�s address space.
�T�UR��`�
U��
��T�UR��`�
V i"#import <driverkit/user_driver.h>
�T�UR��`�
U u"IODeviceReturn 
VIOMapSlot
U(
T�UR��`�
Uce#IODevicePort 
QdevicePort
U,
DevT�UR��`�
UUR!vm_task_t 
Qtarget_task
U,
f%T�UR��`�
Urevm_offset_t 
Qoffset
U,
2T�UR��`�
U�vm_size_t 
Qlen
U,
e?T�UR��`�
UUR1vm_offset_t *
Qaddr
U,/* in/out */

LT�UR��`�
U�BOOL 
Qanywhere
U);
fT�UR��`�
UU
Rd��et�����$6����U$6���| U
��URUR�� �
Vev`IOMapSlot
U maps the slot space of the NeXTbus device associated with 
QdevicePort
U into deUMUR��@�
UtaNthe target task at 
Qaddr
U. This RPC is illegal for native m68k devices.
.UHUR��`�
Q�=devicePort
U is the kernel provided handle for the device.
SHUCUR��`�
Q��Ztarget_task
U represents the address space into which the device page should be mapped.
bU>UR��`�
Q<dVoffset
U is an offset within the device's slot space at which mapping should begin.
|U9UR��`�
QDeNaddr
U is the address in target_task where the slot space should be mapped.
�U4UR�� �
Q��clen
U is the length in bytes of the region to be mapped. The maximum value for (
Qoffset
U + `��U/UR���
Qt Nlen
U) is 0xf00000 (15M) for NRW DMA devices and 0x1000000 (16 M) for other �U*UR��@�
U�	devices.
�U%UR�� �
QWanywhere
U is a boolean, if YES, indicates the kernel may pick any unused address to �U UR��@�
Umap the slot space.
���q��UT`�
[tIOUnmapSlot()
*UUR��`�
UTb0Remove slot space from a driver�s address space
deAUUR��`�
Uta
hRU
UR��`�
V
Q"#import <driverkit/user_driver.h>
lUUR��`�
U.
$IODeviceReturn 
VIOUnmapSlot
U(
s yUUR��`�
Ud #IODevicePort 
QdevicePort
U,
`��T�UR��`�
U
U!vm_task_t 
Qtarget_task
U,
 �T�UR��`�
Uagvm_offset_t 
Qaddr
U,
���T�UR��`�
UUvm_size_t 
Qlen
U);
�T�UR��`�
Ut DESCRIPTION
sh�T�UR�� �
VURLIOUnmapSlot
U unmaps the slot space of the NeXTbus device associated with ld�T�UR��@�
QURrdevicePort
U. 
Qaddr 
Uand 
Qlen
U must match similar fields from a previous call to 
VIOMapSlot
U.
d��0x���MA$6����ot$6���| UR�����UT`�
[ i
IOMapBoard()
 &UNUR��`�
U k/Map board space into a driver�s address space.
��=UIUR��`�
Usl
sNUDUR��`�
VUT"#import <driverkit/user_driver.h>
hU?UR��`�
Ulo#IODeviceReturn 
VIOMapBoard
U(

deuU:UR��`�
Uta#IODevicePort 
QdevicePort
U,
ive�U5UR��`�
U>
!vm_task_t 
Qtarget_task
U,
n�U0UR��`�
UUvm_offset_t 
Qoffset
U,
�U+UR��`�
UePvm_size_t 
Qlen
U,
��U&UR��`�
U
0vm_offset_t *
Qaddr
U,/* in/out */
se�U!UR��`�
U��BOOL 
Qanywhere
U);
�UUR��`�
U;

��UUR�� �
VDE]IOMapBoard
U maps the board space of the NeXTbus device associated with 
QdevicePort
U s�UUR��@�
UT�&into the target task at 
Qaddr
U.
U
UR��`�
Q�=devicePort
U is the kernel provided handle for the device.
l+UUR��`�
QZtarget_task
U represents the address space into which the board space should be mapped.
EUUR��`�
QWoffset
U is an offset within the device's board space at which mapping should begin.
rd _T�UR��`�
Qr�Waddr
U is the address in 
Qtarget_task
U where the board space should be mapped.
_dryT�UR�� �
Q��clen
U is the length in bytes of the region to be mapped. The maximum value for (
Qoffset
U + U,�T�UR��@�
Q�len
U) is 0x10000000 (256M).

U�T�UR�� �
Q�Wanywhere
U is a boolean, if YES, indicates the kernel may pick any unused address to UR�T�UR��@�
U_omap the board space.
�;��UT`�
[seIOUnmapBoard()
U��T�UR��`�
Uer2Remove board space from a driver�s address space.
T�UR��`�
Uap
h(T�UR��`�
Vhe"#import <driverkit/user_driver.h>
BT�UR��`�
UU%IODeviceReturn 
VIOUnmapBoard
U(
aOT�UR��`�
UU
#IODevicePort 
QdevicePort
U,
he \T�UR��`�
Und!vm_task_t 
Qtarget_task
U,
�iT�UR��`�
U
Uvm_offset_t 
Qaddr
U,
 ivT�UR��`�
Ud vm_size_t 
Qlen
U);
d�� o���e'$6����ul$6���|  iadURUR��`�
Ut_DESCRIPTION
 tUMUR�� �
VulNIOUnmapBoard
U unmaps the board space of the NeXTbus device associated with %UHUR���
Qhe_devicePort
U. 
Qaddr 
Uand 
Qlen
U must match similar fields from a previous call to �T�2UCUR��@�
UanIOMapBoard.
a g����UT`�
[ndOperational RPC's
�����UT`�
[adIOSendChannelCommand()
@��U6UR��`�
Ud  Issue channel-specific command.
ma�U1UR��`�
UUR
��U,UR��`�
Voa"#import <driverkit/user_driver.h>
�U'UR��`�
U�.IOChannelReturn 
VIOSendChannelCommand
U(

U"UR��`�
UT�#IODevicePort 
QdevicePort
U,
IOUUUR��`�
UT�int 
QchannelNumber
U,
t$UUR��`�
U,%IOChannelCommand 
Qcommand
U);

DUUR��`�
U
�DESCRIPTION
�UUUR�� �
Vt QIOSendChannelCommand
U is used to issue commands on the DMA channel identified �bU	UR���
UPby 
QdevicePort
U and 
QchannelNumber
U. CHAN_NONE can be specified for oUUR���
QKchannelNumber
U if no channels are attached; in this case the only legal  u|T�UR���
Uac>IOChannelCommand bits are IO_CC_INTR_ENABLE and INTR_DISABLE. �T�UR��@�
UadCOtherwise it is an error if the device or channel is not attached.
 to�T�UR��`
Q�=devicePort
U is the kernel provided handle for the device.
��T�UR��`
QIO-channelNumber
U is a local channel number.
s�T�UR��`
Qic7command
U is the command for the channel to execute:
"#i�T�UR��`
Use0IO_CC_START_READ -- enable read DMA (68K only)

T�UR��`
Uma2IO_CC_START_WRITE -- enable write DMA (68K only)
%T�UR��`
UU@IO_CC_ABORT -- abort current DMA (disables channel) (68K only)
,?T�UR��`
Und7IO_CC_INTR_ENABLE -- enable interrupts on the channel
UUYT�UR��`
UIO9IO_CC_INTR_DISABLE -- disable interrupts on the channel
 sT�UR�� �
U �GIO_CC_LOOP_FRAME - link current end of DMA frame queue to start of DMA AN_�T�UR���
UieKframe queue. This allows a continuous DMA operation for devices like video in d��UR���lC$6����an$6���| rw) iURUR���
UdeRwithout the need for any software intervention at the completion of a list of DMA UMUR���
U fOframes. Note that once a DMA frame is put into �loop� configuration, no frames .
s!UHUR���
UicCmay be enqueued or dequeued until the frame loop is broken via the ��.UCUR��@�
UTAIO_CC_UNLOOP_FRAME command.
K HU>UR�� �
U��@IO_CC_UNLOOP_FRAME - unlink end of DMA frame queue from head of URUU9UR���
UCCPqueue. This is illegal when the channel is enabled; IO_CR_BUSY will be returned IbU4UR��@�
U- in that case. 
 on|U/UR�� 
UT�3All commands may be OR�d with IO_CC_INTR_ENABLE or rru�U*UR��
U
 AIO_CC_INTR_DISABLE to form compound commands (e.g. IO_CC_ABORT | a�U%UR��
Uof=IO_CC_INTR_DISABLE or IO_CC_START_READ | IO_CC_INTR_ENABLE). u�U UR��
Ufo;Note than on NRW, IO_CC_START_READ, IO_CC_START_WRITE, and �UUR��
UlCMIO_CC_ABORT are done by the driver by directly accessing the channel command w�UUR��@
U��
register.
�g��UT`	
[ aIOEnqueueDma()
venU
UR��`

Uti*Add a DMA Frame to the current DMA queue.
'UUR��`
Uce
D8UUR��`
Vto"#import <driverkit/user_driver.h>
RT�UR��`

Uic&IOChannelReturn 
VIOEnqueueDma
U(
_T�UR��`
Uen#IODevicePort 
QdevicePort
U,
CC_lT�UR��`
Undint channelNumber,
�yT�UR��`
UMEtask_t 
Qtask_port
U,
ue�T�UR��`
UU9vm_offset_t 
Qaddr
U,
is�T�UR��`
U�vm_size_t 
Qlen
U,
Y�T�UR��`
UIIODmaDirection 
Qrw
U,
a�T�UR��`
U��#IODescriptorCommand 
Qcmd
U,
th �T�UR��`
Uorunsigned char 
Qindex
U,
NTR�T�UR��`
Uom'IOChannelEnqueueOption 
Qopts
U,
UR�T�UR��`
UC_unsigned 
Qdma_id
U,
EAD�T�UR��`
ULEBOOL *
Qrunning
U);
�T�UR��`
U_C
T�T�UR�� 
VARUIOEnqueueDma 
Ubuilds and enqueues a list of DMA descriptors describing a block of cT�UR��
U cYmemory. This block of memory is referred to as a 
Vframe
U. The frame may cross page �T�UR��
UA Vboundaries in most cases. The exception is for channels which have been configured as &T�UR��
UerX�streaming mode� channels per 
VIOAttachChannel
U(). Frames for DMA read operations De3T�UR��
UePS(device to memory) for streaming mode channels must not cross page boundaries. The t @T�UR��
Uue\reason for this restriction is that when the device-specific logic signals �End of record�, 
UMT�UR��
UWthe DMA hardware will advance to the next buffer descriptor, not the next frame. There U,ZT�UR��
UOis no way for the hardware to advance to the next frame; frames are a software ptigT�UR��
UURUconstruct. Therefore for such channels, we force one frame to consist of exactly one utT�UR��
UURNDMA descriptor. This does not preclude the use of multiple frames for a given �T�UR��@
Ursstreaming-mode type packet.
URd��f ���as$6����os$6���| n asURUR�� 
UisRThere are system dependent limits to the amount of memory that may be queued with UMUR��
VAtUIOEnqueueDma
U; exceeding this limit will return an error and the data will not be m!UHUR��@
U m
enqueued.
;UCUR�� (
VgeQIOEnqueueDma
U will return IO_CR_BUSY if the specified channel is currently in tHU>UR��@(
U��;�DMA Frame Loop� mode (See IOSendChannelCommand(), above).
 habU9UR�� 
Qe aaddr
U must be aligned to the size of the device buffer. On m68K machines, 
Qlen
U must be  oU4UR��
Ue Va multiple of the device buffer length for all descriptors with IO_CEO_EOR not set in |U/UR��
Uweathe 
Qopts
U argument. On m88k machines, 
Qlen
U must be a multiple of the device buffer c�U*UR��@
Ult length for DMA read operations.
���U%UR��`
Ug-CChains of DMA frames will be limited to some length by the kernel.
��U UR��`
Q=devicePort
U is the kernel provided handle for the device.
�UUR��`
QUR-channelNumber
U is a local channel number.
 �UUR��` 
Qem:task_port
U is the task where DMA will be done to/from.
UUR��`!
QthHaddr
U is the address in the current task where the DMA should begin.
 m%UUR��`"
QURDlen
U is the length of the DMA in the target tasks address space.
 c?UUR�� #
Qy Orw
U is the direction of the DMA, either IO_DMA_DIR_READ (from the device to e).LUUR��@#
U9memory) or IO_DMA_DIR_WRITE (from memory to the device).
ffT�UR��`$
Qne8cmd
U is a NRW channel descriptor command (m88k only)
f �T�UR��`%
Qle[index c
Uontains the region and register index to which cmd will be written (m88k only).
gum�T�UR��`&
Qne[opts
U are channel options that should apply to the frame being enqueued. These include:
rea�T�UR�� '
UU%JIO_CEO_EOR -- the last descriptor in the frame should be indicated as the �T�UR��@'
UURend-of-record.
ice�T�UR��`(
Urn<IO_CEO_DESC_INTR -- interrupt when this frame is completed.
ne�T�UR��`)
Uoc6IO_CEO_ENABLE_INTR -- enable interrupt notification.
T�UR��`*
UDMDIO_CEO_ENABLE_CHAN -- enable DMA channel after enqueue (m68k only).
in)T�UR��`+
UwhBIO_CEO_DESC_CMD -- enable channel descriptor command (m88k only)
CT�UR�� ,
Qth^dma_id
U is an integer, uninterpreted by the kernel, whose sole purpose is to identify this PT�UR��@,
UfrVframe when 
VIODequeueDma
U()'d. 
Qdma_id
U must not be equal to DMA_ID_NULL.
jT�UR�� -
QUR[running
U is returned; on the m68k this indicates whether the channel was enabled at the [inwT�UR��-
UheStime of the enqueue (if not, a channel enable will be required). On the m88k, this `&�T�UR��-
U cYindicates whether or not the transfer engine had a non-empty descriptor list at the time �d��es���ho$6������$6���| ( IOURUR��-
UinZof the enqueue. If on the m88k 
Qrunning
U is NO, a Load Descriptor operation will be UMUR��@-
Uti necessary to start the channel.
NAI����UT`.
[ DIODequeueDma()
enqgUDUR��`/
Uin/Dequeue DMA frames from the current DMA queue.
cha~U?UR��`0
Umm
 �U:UR��`1
VUR"#import <driverkit/user_driver.h>
�U5UR��`2
Uby&IOChannelReturn 
VIODequeueDma
U(
�U0UR��`3
UUR#IODevicePort 
QdevicePort
U,
eDm�U+UR��`4
U_iint 
QchannelNumber
U,
I�U&UR��`5
U��'IOChannelDequeueOption 
Qopts
U,
 m6�U!UR��`6
Uwhvm_size_t *
Qbcount
U,
t�UUR��`7
U��(IOChannelStatus *
Qchan_status
U,
ha�UUR��`8
Ue #IODmaStatus *
Qdma_status
U,
URUUR��`9
UcaBOOL *
Qeor
U,
tU
UR��`:
U aunsigned *
Qdma_id
U);
h1UUR��`;
UDESCRIPTION
BUUR�� <
V�CIODequeueDma
U dequeues a single DMA frame which was enqueued by OT�UR��<
V(`IOEnqueueDma
U. It will only dequeue frames that meet the criteria specified in 
Qopts
U. to\T�UR��<
Ue SIt unlocks the associated memory. It returns an indication if more descriptors are ueDiT�UR��@<
U��8available to dequeue by the criteria specified in opts.
ha�T�UR�� =
VmmOIODequeueDma
U will return an error (IO_CR_BUSY) if the IO_CDO_ALL option is &IO�T�UR��=
UIOSspecified, the channel is running, and no completed frames are available. In other ���T�UR��=
UQTwords, it is not possible to dequeue non-completed descriptors while the channel is U!�T�UR��@=
U	running.
�T�UR�� *
VUVIODequeueDma
U will also return IO_CR_BUSY if the specified channel is currently in �T�UR��@*
Uta;�DMA Frame Loop� mode (See IOSendChannelCommand(), above).
UR�T�UR��`)
Usi
dT�UR��`>
Q
h=devicePort
U is the kernel provided handle for the device.
uT�UR��`?
Qs /channelNumber
U is a logical channel number.
UR9T�UR��`@
Qqu=opts
U are options to 
VIODequeueDma
U, these include:
sST�UR��`A
Uts.IO_CDO_DONE -- dequeue only completed frames.
mT�UR��`B
U r"IO_CDO_ALL -- dequeue all frames.
d��av���th$6����T�$6���| tu erURUR��`C
Uf 1IO_CDO_ENABLE_INTR -- enable interrupt messages.
p!UMUR�� D
UelJIO_CDO_EI_IF_MT -- re-enables device interrupts for the device if no more .UHUR��@D
Ut frames may be dequeued.
 nHUCUR��`E
Uip The flags may be OR�d together.
URbU>UR�� F
Qin[bcount
U (returned) is the byte count of actually transferred data. It is only valid for el oU9UR��@F
UT�Ptransfer from the device into memory (i.e. DMA reads). Zero returned on writes.
T��U4UR�� G
Q
d]chan_status
U is the channel descriptor status (only valid for m88k). It is only valid for ��U/UR��G
UumTtransfer from the device into memory (i.e. DMA reads). Zero returned on writes. The 
�U*UR��@G
U, *meaning of this field is device-specific.
�U%UR�� H
Qnl\dma_status
U is machine-independent and indicates the current state of the channel (e.g., ��U UR��@H
U/running, idle, underrun). Only valid for m68k.
�UUR�� I
Q]eor
U is an end of record indication (only valid for certain device and only valid on �DMA t�UUR��@I
U,read� transactions). NO returned on writes.
viUUR�� J
Qth^dma_id
U is an integer, uninterpreted by the kernel, whose sole purpose is to identify this UUR��J
Uge]frame to the device driver. 
Qdma_id
U matches the dma_id of a frame previously enqueued a%UUR��J
Uid]via 
VIOEnqueueDma
U. If 
Qdma_id 
Uis DMA_ID_NULL, no descriptors are available for n2UUR��J
UU4Ndequeueing. (This is not an error - that is, 
VIODequeueDma
U will return ?T�UR��@J
UlyIO_CR_SUCCESS in this case.)
mt�N��UT`n
[e Privileged RPC�s
(�T�UR�� Q
UerWFrom User level, these RPCs are only executed by the Config program. Some of these are c.
�T�UR��Q
UnlXalso executed by Kernel-level drivers directly. The usage of these RPCs is described in g.�T�UR��@Q
UH]detail in the section entitled �Autoconfiguration�. These RPC are listed here for reference.
 ު;��UT`R
[onIOGetDeviceType()
�T�UR��`S
Uly>Determine IOSlotId and IODeviceType for a given deviceNumber.
T�UR��`T
Uvi
$T�UR��`U
Vdm"#import <driverkit/user_driver.h>
>T�UR��`W
Uho(IODeviceReturn 
VIOGetDeviceType
U(
URKT�UR��`X
Ue  port_t 
Qdevice_master
U,
UXT�UR��`Z
Ud 'IODeviceNumber 
QdeviceNumber
U,
��eT�UR��`\
UIO.IOSlotId *
QslotId
U,// returned
rT�UR��`^
Ure6IODeviceType *
QdeviceType
U,// returned
T�UR��`
Uth*BOOL *
Qin_use
U;// returned
d�� t���UT$6����UR$6���| ar eURUR��`_
UfiDESCRIPTION
e UMUR��  
UT�LConfig uses this RPC to during the initial autoconfiguration process to map  t%UHUR�� 
UibSIODeviceNumbers to device types. The 
Qin_use
U parameter is returned YES if a se 2UCUR�� 
Ue `devicePort currently exists for 
QdeviceNumber
U. This would be the case if an Kernel level nd?U>UR��@ 
U�Odriver attached to 
QdeviceNumber
U prior to User level autoconfiguration.
kitt����UT`a
[T�IOCreateDevicePort()
i�U5UR��`e
UDeCreate a devicePort.
R�U0UR��`h
Urt
�U+UR��`j
VU"#import <driverkit/user_driver.h>
�U&UR��`k
Uum#IODeviceReturn IOCreateDevicePort(
OSl�U!UR��`l
UU port_t 
Qdevice_master
U,
^�UUR��`m
Upetask_t 
Qtarget_task
U,
�UUR��`n
U��#IODeviceNumber 
QdeviceNumber,
UUR��`o
U%IODevicePort *
QdevicePort
U);
�(U
UR��`p
UDESCRIPTION
9UUR�� 
UTThis RPC causes the kernel to create a devicePort for a specified deviceNumber. The URFUUR��
UigYnew devicePort is created in 
Qtarget_task
U�s port space. This RPC returns an error bST�UR��@
UtoH(IO_DR_EXISTS) if a devicePort for 
QdeviceNumber
U already exists.
UR��O��UT`c
[ceIODestroyDevicePort
fo�T�UR��`g
U
Destroy a devicePort.
�T�UR��`"
Uve
d�T�UR��`#
V�"#import <driverkit/user_driver.h>
�T�UR��`$
Ur ,IODeviceReturn 
VIODestroyDevicePort
U(
T��T�UR��`%
Urtport_t 
Qdevice_master,
teT�UR��`&
UU0$IODevicePort 
QdevicePort
U);
U"T�UR��`'
UitDESCRIPTION
>
3T�UR�� (
UumbThis RPC causes all current state associated with the specified 
QdevicePort
U to be deleted. @T�UR��(
UMAny pending DMAs will be dequeued; registered interrupts will be deleted and mMT�UR��@(
U��
disabled.
d��
����DE$6����Th$6���|ePr ����UT`a
[Nu
IOInquire
&UNUR��`,
Uig@Determine IOUnitName and IOUnitType for specified IOUnitNumber.
hi=UIUR��`.
Urr
bNUDUR��`/
Vto"#import <driverkit/user_driver.h>
hU?UR��`0
U
U"IODeviceReturn 
VIOInquire
U(
uU:UR��`1
Uicport_t 
Qdevice_master,
De�U5UR��`2
U.
IOUnitNumber 
Qunit
U,
R�U0UR��`3
Uor;IOUnitType *
QdeviceType
U;              // returned
urn�U+UR��`4
Uce8IOUnitName *
QdeviceName
U);          // returned
er�U&UR��`5
U&DESCRIPTION
ce�U!UR�� 6
UtVThis RPC is used to determine the charactersistics of an arbitrary global kernel unit �UUR��6
UatQnumber (IOUnitNumber). Each instance of each IODevice subclasss in the kernel is e�UUR��6
U dQassigned a unique IOUnitNumber. This RPC and the IOLookup() RPC (below) are used 
�UUR��@6
U�9to determine the characterstics of kernel-level drivers.
�U
UR��`7
U
C�^��UT`8
[	IOLookup
aUUR�� 9
U��4Determine IOUnitNumber and IOUnitType for specified e nT�UR��@9
UniIOUnitName.
if�T�UR��`;
Uhi
I�T�UR��`<
V
b"#import <driverkit/user_driver.h>
�T�UR��`=
U>
!IODeviceReturn 
VIOLookup
U(
n�T�UR��`>
U(
port_t 
Qdevice_master,
 �T�UR��`@
UDeIOUnitName 
Qname
U,
tNu�T�UR��`:
UUR>IOUnitNumber *
Qunit
U;                     // returned
�T�UR��`A
Urn8IOUnitType *
QdeviceType
U);          // returned
  T�UR��`B
UerDESCRIPTION
5T�UR�� C
UcePThis RPC is used to determine the charactersistics of a kernel device, given an it"T�UR��C
U uOIOUnitName. This RPC and the IOInquire() RPC (above) are used to determine the ubc/T�UR��@C
Ul (characterstics of kernel-level drivers.
e d��oo���us$6����mi$6���|er
U
����UT`-
[
IOKernDeviceLookup
	IO&UNUR��`?
U��6Obtain id of a kernel IODevice given its IOUnitName..
=UIUR��`E
U��
9NUDUR��`F
Vif"#import <driverkit/kern_driver.h>
hU?UR��`G
U<d+IODeviceReturn 
VIOKernDeviceLookup
U(
!IOuU:UR��`H
UOLIOUnitName 
Qdevice_name,
�U5UR��`I
UicEid *
QdeviceId);             
U                    // returned
R�U0UR��`L
U#DESCRIPTION
un�U+UR��`M
U  6THIS FUNCTION IS ONLY AVAILABLE INSIDE OF THE KERNEL.
�U&UR�� D
U);UThis function provides a simple mapping of IOUnitName to id. It�s a rudimentary form R�U!UR��D
UrmTof a future remote object name-to-id mapping mechanism. Since this is only valid in me�UUR��D
U IUthe kernel, no security mechanism is provided; any kernel code can get the id of any s�UUR��@D
Urikernel IODevice.
d������$6����$6���| ��#UT
��
��UUhK
[vik
ZAutoconfiguration
B����UT`V
[ aUser Level Autoconfiguration
i]UMUR�� P
U��UThis section describes the mechanism by which user-level device drivers are bound to djUHUR��@P
U
VAspecific device registers and DMA channels at system boot time. 
d�������`Y
\URGeneral Scheme
d *�U@UR�� [
U  UThere exists one user-level task, called Config, which is executed early in the boot R�U;UR��[
U FOsequence. Config is a privileged task; it communicates with the kernel via the on �U6UR��[
UmaZdevice_master port. This port is currently obtained via a trap which can only be executed �U1UR��[
U mdby tasks with root privilege. Drivers themselves are 
Vnot
U privileged. (This is a key concept m �U,UR��[
UerYin the NRW Device Driver architecture - User-level device drivers are regular User level ��U'UR��[
UZexecutables with no special privileges whatsoever.) It is Config's job to examine various U"UR��[
U��^device registers and determine which device drivers, each of which is an executable file, are UUR��@[
U��/to be associated with which device registers. 
ser.UUR�� ]
UerbEach logical set of device registers (e.g., all of the SCSI registers) are associated with a port ;UUR��]
UY\called devicePort, which is created by the kernel. devicePort is the basic means by which a  wHUUR��]
Uar^device driver gains access to a device. Config obtains the devicePort for each device via the UU	UR��]
UheWIOCreateDevicePort() RPC (see the section entitled �Kernel Level Driver Support� for a whibUUR��]
UcuZdescription of this RPC as well as all of the other Kernel-Level RPCs referred to in this oT�UR��]
Us Wsection.) After obtaining the devicePort for a specific device, Config then exec's the dev|T�UR��]
UguYappropriate driver for that device and makes devicePort available to that driver via the t�T�UR��]
Uo _bootstrap server, thus enabling the driver to gain access to the registers and other resources f w�T�UR��@]
Ublassociated with the device.
���������``
\ w,Mapping Device Registers to Device Drivers 
]�T�UR�� b
U s^A logical device is a set of registers which are associated with one device (e.g., all of the �T�UR��b
UevWregisters associated with the SCSI port). Each logical device has associated with it a UR�T�UR��b
UceTdeviceNumber by which Config refers to it; deviceNumber is machine-dependent but is e T�UR��@b
Uhe6basically an index into an array of logical devices. 
&T�UR�� d
USuUEach logical device also has a 32-bit attribute called IODeviceType. The 16 msb's of e3T�UR��d
Us ZIODeviceType are called deviceIndex; the 16 lsb's are a revision number. For the purposes @T�UR��d
Uig\of this discussion, there are three basic types of devices. One is the type of device which orMT�UR��d
Ut Zconforms to the NRW model of 8 devices per NextBus slot; this device is referred to as an ZT�UR��d
Vrs`NRW DMA Device
U. Another type of device is a 
VNative m68k Device
U, which describes all MagT�UR��d
UteWdevices implemented internally on an m68k CPU board. The other type of device occupies h atT�UR��d
U o`an entire NextBus slot; this is a 
VSlot Device
U. Third party boards for m88k machines can og�T�UR��d
UsoZcontain either one Slot Device or up to eight NRW DMA Devices; third party boards for the d��e ���ba$6����lo$6���|  l( dURUR��d
U2-Rm68k contain one Slot Device (since no DMA is available for NextBus boards on the UMUR��d
UceNm68k). The kernel determines which type of device a NextBus board contains by !UHUR��d
Uon[examining the IOSlotId field of the board. If bits 9 through 7 (inclusive) of the IOSlotId Ut .UCUR��d
UNRYfield are 1, then the board is assumed to contain NRW DMA Devices; otherwise it contains s;U>UR��d
UUPone Slot Device. Native devices on both machines, by convention, are assigned a T�HU9UR��@d
Ude(hard-coded IOSlotId of NATIVE_SLOT_ID. 
U bU4UR�� f
UypNThere is one more significant difference between NRW DMA Devices, Native m68k oU/UR��f
U.WDevices, and Slot Devices; that is in the type and range of memory which can be mapped  De|U*UR��f
Ut Yin by the driver. The various ranges of memory which can be mapped in by various drivers ��U%UR��f
U`is described in the section entitled �Kernel Level Driver Support�. Suffice it to say here that 2-�U UR��f
U SVConfig neither knows nor cares about any of this memory space; mapping and allocating �UUR��@f
UteEthis memory is performed by RPCs between the drivers and the kernel.
d�UUR�� u
Ue VConfig obtains IODeviceType and IOSlotId for a given deviceNumber from the kernel via �UUR��u
Ud Uthe IOGetDeviceType() RPC. It is the responsibility of machine-dependent code in the >�UUR��u
UonXkernel to map deviceNumber to a IOSlotId and IODeviceType. This is done in one of three ���UUR��@u
Uedways:
�UUR�� v
UD.MThe IODeviceType for NRW DMA Devices is obtained from the hardware. A simple DT�UR��@v
U mMalgorithm maps deviceNumber to the hardware address containing IODeviceType.
n%T�UR�� x
UURQThe IODeviceType for Native m68k devices is faked by the kernel; the kernel must y2T�UR��@x
UedOmaintain a hard-coded map of deviceNumber to IODeviceType for native devices. 
d �LT�UR�� z
Ur VThe IODeviceType field for Slot Devices is defined as -1; the significant information YT�UR��@z
UthE(as far as device drivers and Config are concerned) is in IOSlotId. 
rsT�UR�� �
URPQOnce Config determines the IODeviceType for a given deviceNumber (and assuming a c�T�UR���
U fRvalid IOSlotId and IODeviceType), it obtains a devicePort for that device via the �T�UR���
U rVIOCreateDevicePort() RPC. Config must then locate a device driver which is capable of �T�UR���
UotZdealing with this particular IODeviceType or IOSlotId. This information is encoded in the �T�UR���
UviYfilename of every executable driver in the (TBD) device driver namespace (for now, let's l�T�UR���
UeNUassume some Unix directory). The filenames of all of these drivers are of one of the i�T�UR��@�
Um6following two formats:
e k�T�UR��`�
Umu2devr_<DEV_INDEX>_<REVISION>_<human_readable_name>
�T�UR��`�
U I0devs_<SLOT_ID>_<REVISION>_<human_readable_name>
zT�UR�� �
UTyTThe former is used for drivers for NRW DMA Devices and for Native m68k Devices; the zT�UR���
UevSlatter is for Slot Devices. DEV_INDEX, SLOT_ID, and REVISION are all in ASCII hex. nfi)T�UR���
UODNDEV_INDEX and REVISION are 4 hex characters; SLOT_ID is eight hex characters. 6T�UR���
UicV<human_readable_name> is something like �LaserPrinter�. For example, a printer driver CT�UR���
UnfSmight be named �devr_0002_0011_LaserPrinter�. A frame buffer driver might be named  wiPT�UR��@�
U I�devs_00112233_3456_BigFrame�.
ormjT�UR�� �
Un SWhen Config is looking for a driver to handle IODeviceType �abcdABCD� and IOSlotId verwT�UR���
Uw,O�_slot_�, it follows the following algorithm (DEV_INDEX, SLOT_ID, and REVISION f t�T�UR��@�
UUR1come from the filename of a prospective driver):
md��_<���<h$6�����$6���| da!meURUR��`�
U�VFor 
VNRW DMA Devices
U and for 
VNative m68k Devices
U (IODeviceType != -1):
!UMUR��`�
U�3only filenames starting with �devr_� are eligible.
 an;UHUR��`�
U i#DEV_INDEX must match abcd exactly.
NDEUUCUR��`�
UON9The filename with the highest value of REVISION is used.
�oU>UR��`�
U<hFor 
VSlot Devices
U:
�U9UR��`�
Uin3only filenames starting with �devs_� are eligible.
Unf�U4UR��`�
Ude#SLOT_ID must match _slot_ exactly.
uff�U/UR��`�
U n9The filename with the highest value of REVISION is used.
.�U*UR�� �
U�^If no driver with a filename which matches the above criteria is found, the device is skipped �U%UR��@�
U�_Vand the devicePort for that device is deallocated via the IODestroyDevicePort() RPC. 
�U UR��`�
ULWAssuming a driver is found the match is recorded by Config in a list of the following:
��������`�
Itypedef struct {
"������`�
Itypedef struct {
.������`�
IURIODevicePort devicePort;
DM:������`�
IfoIODeviceType deviceType;
(IF������`�
I:
IOSlotId slotId;
onR������`�
Iin IODeviceNumber deviceNumber;
UH^������`�
IDE} entry[many];
aj������`�
IUCint executable_fid;
v������`�
Ighchar *executable_file_name;
�������`�
I<h/* other cruft here */

�T�UR��`�
Iin} dev_entry;
U
a�T�UR��`�
U aWhere
�T�UR��`�
U��@devicePort is obtained from the kernel by IOCreateDevicePort().
 n�T�UR��`�
Uh =deviceType is obtained from the kernel by IOGetDeviceType().
fT�UR��`�
UfiFexecutable_fid is the File ID (inode number or its moral equivalent).
T�UR��`�
U�_Kexecutable_file_name is the name located in the algorithm described above.
rt(9T�UR�� �
U��[This mechanism allows multiple devicePort's to be associated with a single driver. In this ng:FT�UR���
U�Ycase, the namespace containing the device drivers would contain links to one executable, ST�UR���
UceTone link for each additional IODeviceType which that driver can handle. When config OS`T�UR���
U��adetects that a file which it is examining is a link to a file which it had already recorded in a �mT�UR���
Ut \dev_entry, it merely adds the new devicePort to that dev_entry.entry[]. This allows mapping  ozT�UR��@�
U

\multiple devicePorts to a single driver. The significance of this will be discussed later. 
ced��y ��� n$6����s $6���| e(T�������`�
\ex'Passing devicePort's to Device Drivers
 or"UOUR�� �
UenZOnce Config has mapped all available devices in the system to their associated executable /UJUR��@�
UURBdrivers it performs the following for each driver to be executed:
IUEUR��`�
UleECreate a bootstrap subset port which will be unique for this driver.
gcU@UR�� �
Us VAdvertise each devicePort associated with that driver with the bootstrap server under pU;UR���
UicSthe bootstrap subset port. The name to be advertised is �dev_port_<deviceNumber>�, ch }U6UR��@�
U aKwhere <deviceNumber> is the device's deviceNumber value, in ASCII decimal.
_en�U1UR�� �
Us WCreate a unique signature port for this driver; advertise this port with the bootstrap \mu�U,UR���
U tXserver under the bootstrap subset port with the name �driverSigPort�. This will be used ��U'UR��@�
UWby Config to authenticate the driver in subsequent RPCs between the driver and Config.
|�U"UR�� �
U��YFork and exec (or task_create or...) the driver; the driver task's bootstrap port is the i�UUR��@�
UvaCbootstrap subset port under which the devicePorts are advertised. 
���UUR�� �
U��^When a driver starts running, if first obtains its devicePorts by doing a bootstrap_info() on �UUR���
U w[its bootstrap port and then doing bootstrap_look_up() of all services found which have the th UUR���
Uhe\name �dev_port_*�. The result is the set of all devicePorts to which the driver has access. isU	UR���
UevLThe driver obtains the IODeviceType and IOSlotId of each devicePort via the ic&UUR��@�
UASdev_port_to_type() Kernel RPC.
Us @T�UR�� �
Usi[After this, it is up to the driver to perform the binding and memory mapping of the device XseMT�UR���
UtsRregisters and interrupt ports for its devices. This is performed via RPCs such as ZT�UR��@�
U a3IOMapDevicePage(), IOMapSlot(), and IOMapBoard(). 
 drtT�UR�� �
U`Since a driver can obtain access to multiple devicePorts, it is possible for one driver task to  p�T�UR���
UURWdeal with both multiple device types (e.g., Ethernet and Token Ring) and with multiple UR�T�UR��@�
UL<instances of the same IODeviceType (e.g., two SCSI ports). 
in�������`�
\()+Behavior of Config Subsequent to Boot Time
and�T�UR�� �
UraWOnce the procedure above is complete, Config enters a server loop in which a number of *�.�T�UR���
U sNRPCs are serviced which pertain to the maintenance of devicePorts and further �T�UR���
UheB(re-)configuration of the system. Config advertises a port called T�UR���
U_tPCONFIG_SERVER_NAME (a string constant defined in Devices/ConfigPublic.h) in the o T�UR���
Ug Vnmserver by which various tasks in the system can make requests of the Config server. T�UR���
Uhi[These RPCs are described below. Note that Config always maintains the state of all running apB+T�UR��@�
UUR>drivers; it is the central housekeeper for all driver tasks. 
d��ve�����$6����de$6���|  ah ����UT`�
[URIORegisterDriver()
es &UNUR��`�
Uce!Notify Config of driver startup.
�=UIUR��`�
UBe
iNUDUR��`�
Vqu##import <driverkit/ConfigPublic.h>
UrahU?UR��`�
Ure)IOConfigReturn 
VIORegisterDriver
U(
luU:UR��`�
Ubeport_t 
QconfigPort
U,
P�U5UR��`�
Uic port_t 
QdriverSigPort
U,
vi�U0UR��`�
Ur port_t 
QdriverPort
U);
�U+UR��`�
UstDESCRIPTION
er�U&UR�� �
Ud TThis is performed once by each driver. The purpose is to allow Config to detect the ub�U!UR���
UT�Zdeath of a driver via the notification of port death of driverPort, which is a port owned �UUR���
UURZby the driver. Upon such port death notification, Config is responsible for executing the �UUR���
UT�Uappropriate kernel RPC(s) such as IODestroyDevicePort() which instruct the kernel to �UUR���
URclean up any queued DMA requests and delete any interrupt bindings on devicePort. U
UR��@�
UXConfig will then attempt to restart the driver initially associated with devicePort.   
on6�^��UT`�
[tuIODeleteDriver()
�TUUR��`�
U��Shut down driver gracefully.
nkT�UR��`q
UU?
R|T�UR��`r
Vnf##import <driverkit/ConfigPublic.h>
uU:�T�UR��`�
U'IOConfigReturn 
VIODeleteDriver
U(
`��T�UR��`�
Udport_t 
QconfigPort
U,
��T�UR��`�
U !port_t 
QdriverSigPort
U);
��T�UR��`�
UerDESCRIPTION
��T�UR�� �
UorXThis allows for the graceful, controlled shutdown of a driver without causing Config to T��T�UR���
Ur Trestart the driver. Config merely deletes all of its internal state associated with ��T�UR��@�
Ur.PdriverSigPort. This is normally invoked by the driver which is being shut down.
URd��PC���ev$6����l $6���| uere����UT`s
[anIODeleteDevice()
s&UNUR��`t
UU
-Relinquish control over a single devicePort.
e=UIUR��`y
U#
lNUDUR��`{
V d##import <driverkit/ConfigPublic.h>
IOhU?UR��`�
UU'IOConfigReturn 
VIODeleteDevice
U(
ulluU:UR��`�
Uqport_t 
QconfigPort
U,
i�U5UR��`�
Uon$IODevicePort 
QdevicePort
U);
IO�U0UR��`�
UODDESCRIPTION
(�U+UR�� �
U�\This allows a driver to relinquish control over a single devicePort. This is typically used T��U&UR���
UDEUwhen a driver has ownership of multiple devices and wishes to give up some subset of a�U!UR���
UusRthem. A driver which wishes to relinquish control of all of its devices would use �UUR��@�
UatIODeleteDriver().
�UUR�� �
Ur.QNOTE: This function not supported in the current implementation. We�ll see if we RUUR��@�
U�really need this...
6�c��UT`�
[IORescanDriver()
TU	UR��`�
U$Repeat autoconfiguration procedure.
kUUR��`w
Us
n|T�UR��`|
V
s##import <driverkit/ConfigPublic.h>
rol�T�UR��`�
Uic'IOConfigReturn 
VIORescanDriver
U(
���T�UR��`�
U<dport_t 
QconfigPort
U);
�T�UR��`�
UIODESCRIPTION

V�T�UR�� �
U(PThis causes Config to perform the initial autoconfiguration procedure described De�T�UR���
UePOabove again, skipping deviceNumbers for which it currently has valid mappings.  a �T�UR��@�
Ush:<Is this safe for any old non-privileged task to invoke?>
d��r ���pl$6����me$6���| dr hi����UT`�
[quIOConfigDevice()
o&UNUR�� ~
Ud ?Attempt to find and launch a driver for specified IOSlotId and QNO3UIUR��@~
UnoIODeviceType.
JUDUR��`�
Unt
o[U?UR��`�
V R##import <driverkit/ConfigPublic.h>
s..uU:UR��`}
U�'IOConfigReturn 
VIOConfigDevice
U(
U�U5UR��`�
UguconfigPort,
�U0UR��`�
UwIOSlotId slotId,
`|�U+UR��`�
UveIODeviceType deviceType);
UR�U&UR��`�
Unf
e�U!UR��`�
U�DESCRIPTION
T��UUR�� �
UgThis causes Config to search for a device matching the 
QslotId
U and 
QdeviceType
U arguments to �UUR���
Ul Sby successive calls to IOGetDeviceType(). If such a device is found, an executable evi�UUR���
Uh Wdriver for the device is located using the same algorithm described previously and the rivU
UR���
UokTdriver is exec'd (or whatever). This is the means by which a driver can be launched UUR���
USsubsequent to boot time. A combination of IODeleteDriver() and IOConfigDevice() is &UNUUR���
UAtVthe means by which a new driver can be installed for a given device without rebooting (T�UR��@�
UUR
the system. 
o]�O��UT`
[ RKernel Level Autoconfiguration
.h>xT�UR��`
U}PThis section only applies to the m88k architecture. m68k implementation is TBD.
,
�T�UR�� E
UwUAutoconfiguring Kernel level drivers is much simpler than autoconfiguring User level ��T�UR��@E
UUR.drivers. There are two main reasons for this:
�T�UR�� n
UigZThere is no concept of �security� for Kernel level drivers. All kernel level drivers have �T�UR��@n
UbyMfull Kernel privileges and must be trusted as much as all other kernel Code.
e�T�UR�� �
U�[All Kernel level driver run as part of a single task, IOTask. IOTask is a �Kernel task�, a riv�T�UR��@�
UokDtask which shares the Kernel�s address space but not its IPC space.
caT�UR�� �
UUSAutoconfiguration of Kernel level device drivers is basically performed by mapping nfiT�UR���
UUSdeviceIndex values, which are obtained from the hardware on a per-device basis, to  wi!T�UR���
UT�WObjective C Class names. This mapping is performed by a static table which is compiled xT�.T�UR��@�
UThinto the kernel. 
b�j����`�
\ch
Driver types
i}T�UR��`�
UBD]For purposes of this discussion, there exist three types of device driver within the Kernel:
rd��UR���wo$6������$6���| � )rnURUR�� �
UAlRDirect Device Drivers. These operate directly on hardware. They get access to the UMUR���
Us Shardware via the IOCreateDevicePort() RPC. An example of a Direct Device Driver is a s!UHUR��@�
U. the SCSIController class. 
riv;UCUR�� �
UokQIndirect Device Drivers. These perform I/O through other drivers, usually Direct �HU>UR���
UigUDevice Drivers. An example of an Indirect Device Driver is the SCSIDisk class, which �UU9UR��@�
Ude+does its I/O via the SCSIController class.
e ooU4UR�� �
UisUPseudo Device Drivers. These do not perform physical I/O on the hardware and are not t|U/UR��@�
Us Uconnected to other drivers. An example of a Pseudo Device Driver would be a VM disk.
i�U*UR�� �
UBDOAll three driver types are enumerated into a static array in the kernel called n t�U%UR��@�
U:internalDevMap[]. This is an array of the following type:
�������`�
Itypedef struct {
�������`�
I�
�������`�
IURconst char      *className;
 �������`�
Ira$const char      **indirectDevices;
ss�������`�
I��unsigned short  deviceIndex;
�������`�
IC.
������`�
It } internalDevMap_t;
UHUUR�� �
UthXThere is one internalDevMap_t for each internal device which has a Kernel-level driver. /O+UUR���
UveXThe internalDevMap_t maps a class name not only to a deviceIndex but also to all of the  D8UUR��@�
Uis7Indirect Device Driver classes which use that device. 
e Sl������`�
\s.Probe methods
�T�UR�� �
UevXEach of the three driver types must implement a factory �probe� method which is invoked ��T�UR��@�
U o^during initialization. There are three formats of the probe method, one for each driver type.
�������`�
Ies/*
enu�������`�
Iti *
ay �������`�
Ied; * All probe methods return id of the instantiated driver 
of �������`�
I:
2 * on successful initialization; else return nil.
�������`�
I�� *
`��������`�
I  1 * Direct device driver (connected to hardware).
 �������`�
Ies */
��������`�
IuE+ probe:(IODeviceNumber)devNumber deviceMaster:(port_t)deviceMaster;
 ������`�
I_t
H������`�
Ith/*
re $�}����`�
IMa; * Indirect device driver (connected to another IODevice).
 /O0�z����`�
Ive */
in<�w����`�
Is + probe:directDriver;
H�t����`�
I a
 T�q����`�
IU/*
��`�n����`�
I D) * Pseudo device (connected to nothing).
 l�k����`�
I� */
Prx�h����`�
IUR	+ probe;
vd��us����p$6����T�$6���| he tURUR�� �
Ue YIn each case, on successful return, the appropriate object(s) have been instantiated and *UMUR���
U�^initialized and should be ready for I/O. A nil return indicates that the driver class can not !UHUR��@�
Uiz*deal with the specified hardware device. 
;UCUR�� �
U��YEarly in system initialization, a thread in the IOTask scans through all of the possible �HU>UR���
U+ Uhardware device slots in the system. For each NRW DMA device found, internalDevMap[] tUU9UR���
U�\is scanned; if an entry with the same deviceIndex and the current hardware device is found, /ObU4UR���
UveZthe driver class�s -probe:deviceMaster: method is called. If nil is returned, the scan of oU/UR���
U��NinternalDevMap continues; if another entry is found which matches the current |U*UR���
U�[deviceIndex, the associated class�s -probe:deviceMaster: method is invoked; this continues ���U%UR���
UQuntil either a non-nil value is returned from -probe:deviceMaster: or the end of  �U UR���
Urn^internalDevMap[] is reached. The latter case indicates that no Kernel Level driver exists for �UUR���
UI/athe current deviceIndex; in this case, a driver for this device is free to be configured at User e�UUR���
U 
Zlevel by the Config program. In the former (successful) case, the -probe: method for each �UUR���
U �cof the class�s associated indirect drivers is called; the id of the direct driver is passed as the Map�UUR���
Q�^directDriver
U argument. When this procedure is repeated for all hardware devices, one more �UUR���
U�Tscan of internalDevMap[] is made - all drivers with a deviceIndex of DEV_INDEX_NULL e �UUR��@�
U��Ware considered to be pseudo devices; these classes are probed with the -probe method. 
|U*�T�UR��`�
Ude
ed��be���is$6����UR$6���|  i.rn
��
��UUhh
[icl
ZCode Examples
'UQUR�� �
UrnNThis section contains examples of code which implement various algorithms and 4ULUR���
UUTprocedures described elsewhere in this document. These examples can be found in the reAUGUR��@�
U a/Examples/ subdirectory in the DEVICES project.
 prv����UT`�
[erI/O Thread Example
he �U>UR�� �
U eWThis example illustrates the use the thread-based I/O model. The example is a complete  th�U9UR���
U pUexecutable program. The example implements a very simple IODevice called a MyDevice.  �U4UR���
UarTMyDevice creates one I/O thread via IOForkThread(); the main thread passes commands ri�U/UR���
UInY(in the form of cmdBuf_t�s) to the I/O thread by enqueueing cmdBuf_t�s on a queue called a�U*UR���
UthPioQueue (one of MyDevice�s instance variables) and waking up the I/O thread via be�U%UR���
URioQueueLock. The I/O thread performs some work with the cmdBuf_t and notifies the �U UR��@�
UUU3client of I/O complete via the cmdBuf_t�s cmdLock.
NTh�������`�
Is /*
les������`�
Ile% * ioThread.m - I/O thread example. 
�������`�
Ies *
rib������`�
I�H * This example consists of a simple driver class with one I/O thread. 
pl'������`�
In H * Exported methods are invoked interactively via stdin. These methods 
UR3������`�
I e< * pass commands to the I/O thread, which performs various 
mp?������`�
Ith< * trivial tasks and then notifies the exported methods of 
tsK������`�
Iev * command complete.
 W������`�
Iar */
vic������`�
I t 
o������`�
I()H#define IOSERVER 1                // temporarily necessary for library 
cm{������`S
I/O5                                  //   compatibility
*�������`�
Iio
u�������`�
I�s#import <driverkit/IODevice.h>
p t�������`
Ibe#import <driverkit/libIO.h>
oc�������`
Ipe#import <mach/mach.h>
�������`
Iif#import <kernserv/queue.h>
3cl�������`
Ite&#import <driverkit/NXConditionLock.h>
�������`
Ies
��������`
I *)static void MyDeviceThread(id deviceId);
��������`
Iib
��������`
I�/*
 ex�������`
Ia ( * Commands to be passed to I/O thread.
pl������`	
In  */
xp�����`

Iintypedef enum {
ly #�|����`
Iet3IOC_GETNUM,            // get a number from stdin
 I//�y����`
Irf*IOC_PRINTNUM,          // print a number
;�v����`

In  IOC_QUIT               // exit
tsG�s����`
Iev} ioCmd_t;
comS�p����`
I��
�_�m����`
I��/*
`�k�j����`
I��< * This struct is the means by which exported methods pass 
esw�g����`
Icm * commands to the I/O thread.
   ��d����`
I   */
omd��
u���#i$6������$6���| .h6��������`
I#i
r������`
I��typedef struct {
i������`
Ieu>id              cmdLock;   // NXConditionLock. Clients await
)������`
I@                              //   completion notification via 
Id5������`
I.                              //   this lock.
A������`
Ind3ioCmd_t         cmd;      // operation to perform
 *M������`
I
(int             aNumber;  // some data
etY������`
I  8queue_chain_t   link;     // for enqueueing on ioQueue
Ie������`
I  } cmdBuf_t;
umq������`!
I

 }������`)
I  /*
 //�������`*
I��! * Condition values for cmdLock.
��������`+
I�� */
�������`,
I��#define CMD_BUSY0
 st�������`-
Iby#define CMD_COMPLETE1
ass�������`.
I
m�������`/
Ihe/*
thr�������`0
I�� * Simple driver class.
�������`1
I */
�������`2
I#i@interface MyDevice:IODevice
�������`3
I{
������`4
I>id ioQueueLock;        // NXConditionLock. Protects ioQueue;

������`5
I��<                       //   the ioThread awaits input via 
Cl������`6
I��(                       //   this lock.
  %������`7
Iti/queue_head_t ioQueue;  // queue of cmdBuf_t's
   1������`8
I  IOThread ioThread;
��=������`9
I  }
I������`:
Ier
oU������`;
I��/*
��a������`<
I  % * Condition values for ioQueueLock.
�m������`=
Iue */
_ty������`>
Ir #define QUEUE_EMPTY   0
���������`?
I} =#define QUEUE_FULL    1    // at least one element in queue
/�������`@
I��
*�������`A
Ifo/*
Loc�������`B
I+ * Initialization.
���������`C
ICM */
0�������`D
I-- myDeviceInit;
CO�������`E
I��
��������`F
I��/*
`/�������`G
I�� * Exported run-time methods.
�������`H
I�� */
�������`J
I��F- (int)getNumber;                    // have I/O thread get a number 
	�}����`I
Iio2                                     // from user
�z����`K
I5G- (void)printNumber : (int)aNumber;  // have I/O thread print a number
��!�w����`L
I  - free;
  -�t����`M
Ick
 9�q����`N
Iti/*
eueE�n����`O
I// * Private methods.
  Q�k����`P
I   */
hr]�h����`Q
I��- (cmdBuf_t *)cmdBufAlloc;
��i�e����`R
I��)- (void)cmdBufFree : (cmdBuf_t *)cmdBuf;
*u�b����`S
Ifo)- (void)cmdBufExec : (cmdBuf_t *)cmdBuf;
t��_����`T
Ir 
dd�������E_$6����en$6���| ��6A������`U
I��@end
B������`V
Iat
.������`W
IC/*
 *)������`X
ID@ * A regular old Unix-y program to exercise the MyDevice class.
��5������`Y
I�� */
��A������`Z
Iti int main(int argc, char **argv)
 *M������`[
IJ{
Y������`\
I; id devId;
   e������`]
Ieachar in_string[40];
�q������`^
I  int aNumber;
}������`_
Ifr
�������``
IK/*
- �������`a
I: C * Create and initialize one instance of MyDevice. Forget devPort
I  �������`b
I�� * for this example.
�������`c
Iue */
��������`d
IridevId = [MyDevice alloc];
`P�������`e
I��[devId myDeviceInit];
 *)�������`f
I�e
�������`g
Ioi/*
uf�������`h
I)cB * Main I/O loop. We'll invoke the exported methods on myDevice 
�������`i
IT * per user input.
������`j
I�� */

������`k
I 
������`l
Iwhile(1) {
%������`m
I�printf("Main Loop:\n");
1������`n
I
B!printf("  p  print number\n");
�=������`o
I��printf("  g  get number\n");
d UI������`p
Ixe#printf("  q  quit program\n\n");
��U������`q
I��printf("Enter Selection: ");
gc,a������`r
I��gets(in_string);
Y��m������`s
Iiswitch(in_string[0]) {
]y������`t
Iin   case 'p':
���������`u
Imb	   /*
��������`v
I��3 * Get a number, pass it throught to MyDevice's
ate�������`w
Ie  * I/O thread for display.
�������`x
I�� */
 �������`y
I.
8   printf("\nEnter number to pass to I/O thread: ");
 [�������`z
IPgets(in_string);
[�������`{
I];aNumber = atoi(in_string);
�������`|
I/ [devId printNumber:aNumber];
 I�������`}
Iok
break;
�������`~
Ivi
���������`
I    case 'g':

	�}����`�
I��	   /*
��z����`�
I . * Get a number via MyDevice's I/O thread.
!�w����`�
Iin */
Loo-�t����`�
I�� aNumber = [devId getNumber];
be9�q����`�
I��/printf("getNumber returned %d\n", aNumber);
��E�n����`�
Iin
break;
Q�k����`�
I��
��]�h����`�
I("   case 'q':
");i�e����`�
Ir	   /*
su�b����`�
I�� * Shut down.
��_����`�
I]) */
��d������� $6����t $6���| te4��������`�
I*    [devId free];
.
������`�
I��exit(0);
��������`�
I
in)������`�
I t   default:
5������`�
I��'   printf("**Illegal Selection\n");
��A������`�
INu
break;
M������`�
I��}
|Y������`�
Iin}
er:e������`�
I��
q������`�
I;
/* NOT REACHED */
}������`�
I}
�������`�
I
}�������`�
I/*
*
��������`�
I $ * Implementation of simple device.
O �������`�
I�� */
in�������`�
I��@implementation MyDevice
[�������`�
Ibe
q�������`�
I/*
tf(�������`�
Id  * Initialization.
E�n�������`�
I */
;
�������`�
I��- myDeviceInit
��������`�
I c{

������`�
I��/*
r������`�
I��# * Initialize instance variables.
��%������`�
I*/ */
1������`�
I&ioQueueLock = [NXConditionLock new];
=������`�
Iqueue_init(&ioQueue);
�I������`�
I
U������`�
I��/*
�a������`�
I f * Start up the I/O thread.
m������`�
I�� */
�y������`�
I��=ioThread = IOForkThread((IOThreadFcn)MyDeviceThread, self);
"�������`�
In\
;�������`�
I�/*
�������`�
I��' * Register with IODevice-level code.
er:�������`�
I�� */
��������`�
I/[super init:nil];
}���������`�
I}
[self registerDevice];
���������`�
I/*return self;
�������`�
Ime}
�������`�
Ice
 �������`�
I��/*

in�������`�
I�� * Run-time methods.
i	�}����`�
I� */

q�z����`�
I 
!�w����`�
I�/*
 *-�t����`�
I�n+ * Have I/O thread get a number from user.
I��9�q����`�
I�� */
��E�n����`�
I��- (int)getNumber
/Q�k����`�
I�{
]�h����`�
InscmdBuf_t *cmdBuf;
%��i�e����`�
I 
int result;
�d��io����$6����$6���| ��3�������`�
I f
������`�
I t/*

������`�
I�� * Set up a cmdBuf.
�)������`�
IIO */
e5������`�
I�cmdBuf = [self cmdBufAlloc];
A������`�
I��cmdBuf->cmd = IOC_GETNUM;
��M������`�
Ist
Y������`�
I c/*
r:e������`�
I��> * Pass the cmdBuf to the I/O thread. On return, the desired
q������`�
Ieg! * number is in cmdBuf.aNumber.
*}������`�
I�� */
��������`�
I��[self cmdBufExec:cmdBuf];
`��������`�
I��result = cmdBuf->aNumber;
hod�������`�
I�[self cmdBufFree:cmdBuf];
I�������`�
I�return result;
���������`�
Iav}
�������`�
Ibe
r�������`�
I��/*
`��������`�
I��# * Have I/O thread print a number.
���������`�
I�h */
���������`�
It #- (void)printNumber : (int)aNumber
t r������`�
I{

������`�
IiocmdBuf_t *cmdBuf;
��������`�
I�
%������`�
I/*
1������`�
I * Set up a cmdBuf.
�=������`�
I�� */
�I������`�
I��cmdBuf = [self cmdBufAlloc];
U������`�
I��cmdBuf->cmd = IOC_PRINTNUM;
�a������`�
IelcmdBuf->aNumber = aNumber;
�m������`�
I =
y������`�
I��/*
��������`�
I��' * Pass the cmdBuf to the I/O thread.
 Pa�������`�
Ihe */
r�������`�
Ie [self cmdBufExec:cmdBuf];
! �������`�
IBu[self cmdBufFree:cmdBuf];
I���������`�
I��	return;
[�������`�
IdB}
�������`�
I�
��������`�
I->/*
er;�������`�
I�& * Have I/O thread shut down cleanly.
�������`�
Ir */
re�������`�
I��- free
}
	�}����`�
Ibe{
�z����`�
I��cmdBuf_t *cmdBuf;
`�!�w����`�
Ith
-�t����`�
I��/*
��9�q����`�
I�� * Set up a cmdBuf.
 E�n����`�
I:  */
uQ�k����`�
I��cmdBuf = [self cmdBufAlloc];
]�h����`�
If;cmdBuf->cmd = IOC_QUIT;

d������up$6���� $6���| cm2lo������`�
I�
������`�
IOC/*
NU������`�
I�' * Pass the cmdBuf to the I/O thread.
��)������`�
I�� */
�5������`�
I��[self cmdBufExec:cmdBuf];
e cA������`�
Ihr[self cmdBufFree:cmdBuf];
 M������`�
I�
 Y������`�
Ic:/*
];e������`�
I� * Free instance variables.
;q������`�
I� */
}������`�
I��[ioQueueLock free];
��������`�
I��
�������`�
I��/*
���������`�
II/+ * Have superclass take care of the rest.
Ir�������`
I�� */
��������`
I��return [super free];
�������`
IBu}
�������`
I��
��������`
I��
��������`
I�q/*
���������`
Iup * Private methods.
��������`
I�k */
��
������`
I=  
������`	
I�h/*
��%������`

I>c) * Create and initialize a new cmdBuf_t.
1������`
I� */
=������`
I- (cmdBuf_t *)cmdBufAlloc
I������`

I{
U������`
IlocmdBuf_t *cmdBuf;

a������`
IOC
m������`
I�&cmdBuf = IOMalloc(sizeof(cmdBuf_t));
y������`
I��*cmdBuf->cmdLock = [NXConditionLock new];
�������`
I];[cmdBuf->cmdLock lock];
[�������`
IdB([cmdBuf->cmdLock unlockWith:CMD_BUSY];
���������`
I��return cmdBuf;
 �������`
Iri}
�������`
I�
��������`
I��/*
I���������`
Iee * Free a cmdBuf_t.
���������`
I� */
/�������`
I�(- (void)cmdBufFree : (cmdBuf_t *)cmdBuf
 r�������`
I��{
�������`
I��[cmdBuf->cmdLock free];
r	�}����`
I��#IOFree(cmdBuf, sizeof(cmdBuf_t));
����z����`
I
�}
!�w����`
I/*
�-�t����` 
Iup/*
Pri9�q����`!
I��< * Pass a cmdBuf to the I/O thread and wait for completion.
	E�n����`"
I�� */

Q�k����`#
Id (- (void)cmdBufExec : (cmdBuf_t *)cmdBuf
d��- ��c
$6������$6���| ��6OC������`$
I{
������`%
Ioc/*
f(������`&
I��D * Add the cmdBuf to the ioQueue and let the ioThread know it has 
)������`'
IdL * work to do.
��5������`(
IdB */
LA������`)
I_B[ioQueueLock lock];
M������`*
Iufqueue_enter(&ioQueue,
}
Y������`+
I�
cmdBuf,
e������`,
I��cmdBuf_t *,
q������`-
IdB	link);
�}������`.
I *&[ioQueueLock unlockWith:QUEUE_FULL];
�������`/
I)c
�������`0
I/*
{
�������`1
I�� * Wait for I/O complete.
	�}�������`2
II */
m�������`3
If_+[cmdBuf->cmdLock lockUntil:CMD_COMPLETE];
`�������`4
I��[cmdBuf->cmdLock unlock];
`!�������`5
IdB
�������`6
Ind	return;
o�������`7
I��}
�������`8
I�k
�������`9
Ioi/*
Buf
������`:
I)c  * Methods invoked by ioThread.
������`;
I� */
%������`<
I 
1������`=
I/*
=������`>
I�) * Wait for a work to appear in ioQueue.

I������`?
Ioc */
f(U������`@
I��- (cmdBuf_t *)waitForCmdBuf
Qua������`A
ITh{
m������`B
I��cmdBuf_t *cmdBuf;
 woy������`C
I��
�������`D
I��& [ioQueueLock lockUntil:QUEUE_FULL];
�������`E
Iuf
q�������`F
Ie,/*
���������`G
I7 * At this point, we still hold ioQueueLock'. Remove 
`-�������`H
I��" * the first element in ioQueue.
�������`I
I;
 */
��������`J
I��-cmdBuf = (cmdBuf_t *)queue_first(&ioQueue);
 �������`K
Iplqueue_remove(&ioQueue,
I�������`L
I��
cmdBuf,
�������`M
IckcmdBuf_t *,
�������`N
I��	link);
[	�}����`O
Ilo
`!�z����`P
IdB/*
��!�w����`Q
Ir= * Release ioQueueLock, updating its condition variable as 
�-�t����`R
Iuf< * appropriate, and return the new cmdBuf to the ioThread.
��9�q����`S
I */
�E�n����`T
I��if(queue_empty(&ioQueue))
��Q�k����`U
Iai([ioQueueLock unlockWith:QUEUE_EMPTY];
��]�h����`V
If(else
i�e����`W
Imd'[ioQueueLock unlockWith:QUEUE_FULL];
IThu�b����`X
IBreturn cmdBuf;
md��_����`Y
I��}
d��oQ��UE$6������$6���| 6At������`Z
Iil
o������`[
Iem/*
`-������`\
I��" * Notify client of I/O complete.
)������`]
I;
 */

�5������`^
I��,- (void)cmdBufComplete : (cmdBuf_t *)cmdBuf

 A������`_
Ipl{
M������``
Iue[cmdBuf->cmdLock lock];
Y������`a
I��,[cmdBuf->cmdLock unlockWith:CMD_COMPLETE];
e������`b
I��}
q������`c
I��
�}������`d
I�w@end
��������`e
Ias
o�������`f
Ig /*
ond�������`g
I
�E * The I/O thread. This thread sits around waiting for work to do on
 �������`h
I��* * the ioQueue, then behaves accordingly.
�������`i
Iue */
���������`j
Iai(static void MyDeviceThread(id deviceId)
���������`k
If({
�������`l
IWcmdBuf_t *cmdBuf;
unl�������`m
I];char in_string[40];
B�������`n
Imd
������`o
I}
while(1) {

������`p
IoQ
������`q
I/*
%������`r
I * Wait for something to do.
��1������`s
IAt */
=������`t
I��%cmdBuf = [deviceId waitForCmdBuf];
\I������`u
Iie
 I/U������`v
I��/*
]a������`w
I�� * OK, What's up?
cmm������`x
IdB */
y������`y
I��switch(cmdBuf->cmd) {
`�������`z
IdL    case IOC_GETNUM:
`a�������`{
IdL
    /*
�������`|
I3 * Get a number from user, pass back to client.
���������`}
I
� */
���������`~
I��1    printf("MyDeviceThread: Enter number: ");
O�������`
Iadgets(in_string);
or�������`�
I��&cmdBuf->aNumber = atoi(in_string);
�������`�
I.

break;
�������`�
I��
���������`�
Ioi    case IOC_PRINTNUM:
d�������`�
Ik
    /*
	�}����`�
Ic$ * Just display client's number.
];�z����`�
I40 */
��!�w����`�
I��8    printf("MyDeviceThread: cmdBuf->aNumber = %d\n",
-�t����`�
IcmdBuf->aNumber);
9�q����`�
Ir 
break;
E�n����`�
I��
AtQ�k����`�
I��    case IOC_QUIT:
e]�h����`�
Iuf
    /*
i�e����`�
II/4 * Time to die. First notify client that we got 
 Ou�b����`�
I��# * the command, then terminate.
`y��_����`�
IBu */

`d��OC����$6����|$6���| ac
li������`�
I��%[deviceId cmdBufComplete:cmdBuf];
�������`�
IyDIOExitThread();
mbe������`�
I�� 
d)������`�
Ig)}
��5������`�
I
uf-A������`�
I_s/*

M������`�
I.
$ * Notify client of I/O complete.
��Y������`�
Ioi */
e������`�
I�$[deviceId cmdBufComplete:cmdBuf];
��q������`�
I* }
dis}������`�
Ier
�������`�
I40/* NOT REACHED */
���������`�
Iri}
d�� %���$6������$6���| ��3At����UT`�
[��#Driver Initialization - User Level
`�#UNUR�� �
U�eZThis is an example of a trivial User Level driver which obtains a set of devicePorts from 0UIUR���
Ud,ZConfig (which is assumed to have launched this executable). No actual I/O is performed in =UDUR���
U��]this example; it just illustrates the relationship between Config and a User Level driver as �JU?UR���
Ude]far as obtaining devicePorts and registering the driver via IORegisterDriver() is concerned. �WU:UR���
U��UThe get_devr_port() function, which does the actual bootstrap_lookup()s necessary to �dU5UR��@�
UclMobtain devicePorts, will probably be added to the IODevice class eventually.
v|������`�
Ite/*
uf]�������`
I� * userDriver.m.
��������`�
I��) * sample user driver. Exec'd by Config.
��������`�
I}
 */
�������`�
I 
�������`�
I#import <sys/types.h>
�������`�
I��#import <mach/mach.h>
�������`�
I��#import <servers/bootstrap.h>
�������`�
In #import <servers/netname.h>
��������`�
Ixa#import <bsd/libc.h>
L�������`�
Iob#import <mach/mach_error.h>
m ������`�
Id,#import <bsd/syslog.h>
d t������`�
Iis"#import <driverkit/user_driver.h>
������`�
I��##import <driverkit/ConfigPublic.h>
tra$������`�
Iip#import <driverkit/IODevice.h>
dri0������`�
I��
�<������`�
Ini#define OUR_DEV_TYPE  0x0999
tH������`�
Igi#define NUM_DEVICES   2
 �T������`�
I��
h`������`�
Ifu9#define dprint(x,a,b,c,d,e)syslog(LOG_ERR, x,a,b,c,d,e)
 l������`�
I�
lx������`�
Its/static int get_devr_port(port_t *devicePorts, 
ent�������`�
I��int max_devices,
�������`�
I *const char *driver_name);
`��������`�
Ier
i�������`�
Ifi/*
����������`�
I *" * Simple driver class interface.
�������`�
Ior */
/t�������`�
I��@interface MyDevice:IODevice

�������`�
I��{
�������`�
Its?port_t   IOPort;      // interrupt notification received here
��������`�
Ior}
��|����`�
I��- MyDeviceInit;
or�y����`�
I.h
 �v����`�
Id,@end
r �s����`�
I t
�,�p����`�
I#i int main(int argc, char **argv)
��8�m����`�
I#i{
D�j����`�
IgPIOConfigReturn crtn;
P�g����`�
I<dkern_return_t   krtn;
0��\�d����`�
I
�port_t          configPort;
Uh�a����`�
I
t port_t          driverSigPort;
DEt�^����`�
I��+port_t          devicePorts[NUM_DEVICES];
 dp��[����`�
Isyport_t          driverPort;
�d�����ev$6����$6���| ��6�������`�
I*dint             i;
��������`�
I��id              myId;
���������`�
I *char            dev_name[30];
���)������`�
I *
5������`�
I��4dprint("driver %s: starting\n", argv[0], 2,3,4,5);
{
A������`�
Its
M������`�
I  /*
teY������`�
I r@ * Get some ports - Config server port, driver bootstrap port.
Dee������`�
I�� */
�q������`�
I��*krtn = netname_look_up(name_server_port,
}������`�
Iin4"",                                   // hostname
{
�������`�
IgPCONFIG_SERVER_NAME,
�������`�
I<d&configPort);
 k�������`�
I��if(krtn) {
t_�������`�
Ior$dprint("%s: can't find %s: %s\n",
  �������`�
IDE9argv[0], CONFIG_SERVER_NAME, mach_error_string(krtn),
C�������`�
I��	4,5);
p�������`�
Iveexit(1);
�������`�
I}
��������`�
I+krtn = bootstrap_look_up(bootstrap_port, 
6�������`�
ISIG_PORT_NAME,
������`�
I�&driverSigPort);
  i
������`�
I�if(krtn) {
  ������`�
I��$dprint("%s: can't find %s: %s\n",
_n%������`�
I��:argv[0], SIG_PORT_NAME, mach_error_string(krtn), 4,5);
1������`�
I, exit(1);
A��=������`�
I
}
��I������`�
Ite*port_allocate(task_self(), &driverPort);
U������`j
I d
ea������`k
IDe/*
��m������`l
I
�: * Get all of the devicePorts which Config has given us.
y������`m
I� */
�������`�
I  8if(get_devr_port(devicePorts, NUM_DEVICES, argv[0])) {
NF�������`�
I��/*
��������`�
IgP * Register with Config.
i�������`�
I�� */
�������`�
I: &crtn = IORegisterDriver(configPort,
�������`�
ICOdriverSigPort,
�������`�
ItndriverPort);
��������`�
I��
if(crtn) {
e�������`�
I��/dprint("%s: IORegisterDriver: crtn = %d\n",
tn �������`�
Iargv[0], crtn, 3,4,5);
���������`�
IRTexit(1);
��	�}����`�
Iri}
Po�z����`�
I��}
I�!�w����`�
I��
-�t����`�
Iri/*
: 9�q����`�
In"4 * Start up a driver instance for each devicePort.
acE�n����`�
In) */

Q�k����`
I,  for(i=0; i<NUM_DEVICES; i++) {

]�h����`
I��myId = [MyDevice alloc];
_sei�e����`
I;
$[myId setDevPort:devicePorts[i]];
ku�b����`
I��[myId setUnit:i];
al��_����`
Its)sprintf(dev_name, "%s%d", argv[0], i);
md��i��Po$6������$6���| gP6 R������`
Ig.[myId setDevName:dev_name];
������`
I: [myId MyDeviceInit];
er(������`
I��}
`�)������`
IPo
5������`	
Itn/*
riA������`

I�� * Sleep until killed.

eM������`
I�� */
rY������`
IrD
while(1)
e������`

I��sleep(1);
q������`
I,4
exit(0);
}������`
I}
�������`
I��
��������`
I��/*
`��������`
I��= * look up all of our devicePorts. returns # of ports found.
"�������`�
Iri? * This function will probably be standardized and provided in
Q�k�������`�
If" * the IODevice class eventually.
�������`
I */
 [�������`
Ise/static int get_devr_port(port_t *devicePorts, 
rts�������`
I��int max_devices,
�������`
I��const char *driver_name)
�������`
I[0{
������`
Iint i;

������`
I�name_array_t service_names;
�������`
Iunsigned int service_cnt;
|%������`
I��name_array_t server_names;
ev1������`
I��unsigned int server_cnt;
=������`
I��bool_array_t service_active;
I������`
I��"unsigned int service_active_cnt;
U������`
Ip kern_return_t krtn;
�a������` 
I
rint port_index = 0;
wm������`!
I��
y������`"
I(krtn = bootstrap_info(bootstrap_port, 
���������`#
I��&service_names, 
���������`$
I�&service_cnt,
���������`%
If &server_names, 
�������`&
Iun&server_cnt, 
��������`'
Iti&service_active, 
an�������`(
Ide&service_active_cnt);
f�������`)
Icl"if (krtn != BOOTSTRAP_SUCCESS) {
�������`*
I��$dprint("%s: bootstrap_info: %s", 
t_�������`+
Its1driver_name, mach_error_string(krtn), 3,4,5);
��������`,
Ihareturn(PORT_NULL);
��������`-
I��}
��	�}����`.
I
��z����`/
In/*
ra!�w����`0
I
�D * Search for devr_XXXX_XXXX. Later - versions and deviceIndex via
��-�t����`1
Irv * dev_port_to_type().
9�q����`2
It  */
cE�n����`3
IBdprint("%s: service_cnt %d\n", driver_name, service_cnt, 3,4,5);
Q�k����`4
I_c%for (i = 0; i < service_cnt; i++) {
t]�h����`5
I��#ifdef notdef
i�e����`6
I��Adprint("%s: service_name %s\n", driver_name, service_names[i],
ou�b����`7
I��	4,5);
#��_����`8
Iam#endif notdef
d������er$6����$6���| er2ct������`9
I�� if(strncmp(service_names[i], 
f������`:
Icl0    "dev_port_", strlen("dev_port_")) == 0) {
*������`;
I: "dprint("%s: port %s found\n", 
)������`<
Ir_+driver_name, service_names[i], 3,4,5);
��5������`=
Itu
T_A������`>
I��/*
M������`?
I�� * Get the devicePort. 
InY������`@
I�� */
D e������`A
IXX,krtn = bootstrap_look_up(bootstrap_port,
��q������`B
Irvservice_names[i],
}������`C
I2&devicePorts[port_index]);
Bd�������`D
I_cif(krtn) {
�������`E
I, (dprint("%s: bootstrap_look_up: %s",
 i�������`F
I+)+driver_name, mach_error_string(krtn),
���������`G
Iri
3,4,5);
_�������`H
Ireturn(0);
s[i�������`I
I7}
�������`J
I��
else {
�������`K
I&if(++port_index >= max_devices) {
�������`L
I*dprint("%s: num_devices exceeded\n",
�������`M
Idriver_name, 2,3,4,5);
9������`N
I(sreturn(port_index);
�
������`O
I  }
������`P
Ior}
=%������`Q
I��}
: 1������`R
Ior}
fou=������ S
I��?dprint("%s: %d devicePorts found\n", driver_name, port_index, ��I������@S
I��3,4,5);
>U������`T
I��return(port_index);
 a������`U
In}
m������`V
I
/y������`W
IA/*
,�������`X
Ilo * Simple driver class.
���������`Y
I */
ic�������`Z
I��@implementation MyDevice
r�������`[
Id
��������`\
I/*
rtn�������`]
IE: * Device-specific initialization. Assumes valid devPort.
�������`^
Ive */
, �������`_
Ikr- MyDeviceInit
���������``
I,5{
�������`a
I=dprint("MyDeviceInit: unit %d\n", [self getUnit], 2,3,4,5);
J�������`b
I��
	�}����`c
Iif/*
t_�z����`d
Ies! * ...initialization code here.
n!�w����`e
I e */
\-�t����`f
IMreturn self;
9�q����`g
I
9}
E�n����`h
I
rQ�k����`i
I
�@end
�d��P��	��$6����or$6���|  %/ce����UT`�
[iv%Driver Initialization - Kernel Level
S#UNUR��`�
U��LThis example is a trivial Kernel-level Direct Driver class. It illustrates:
V=UIUR��`�
U��$The -probe:deviceMaster: interface.
 *WUDUR�� �
UssOThe use of the IOCreateDevicePort(), IOMapDevicePage(), IOAttachChannel(), and ���dU?UR��@�
U
�IOAttachInterrupt() RPCs.
~U:UR�� �
UEVTypical initialization of NRW interrupt cause and mask registers using the methods in �U5UR��@�
Ukrthe NRW category of IODevice.
�������`n
I��/*
`a�������`o
Iev * probeAndInit.m.
[se�������`
I,5+ * probe: and init example, kernel driver.
Iif�������`p
I�� */
es�������`q
Iat
 �������`�
I��/*
`e�������`�
I��< * These are necessary to compile this as a user program...
���������`�
I��*/
`i������`r
I#define KERNEL 1
������`s
I�#define KERNEL_FEATURES 1
������`t
Ior
'������`u
I#import <driverkit/IODevice.h>
��3������`v
Ier'#import <driverkit/m88k/IODeviceNRW.h>
��?������`w
Imp!#import <mach//mach_interface.h>
 K������`x
Ill#import <bsd/dev/ldd.h>
�W������`y
Iev#import <driverkit/libIO.h>
URc������`z
Ius
fo������`{
IeP%#define MY_DEVICE_CHANNEL          0
e{������`|
IUR&#define MY_DEVICE_BUFSIZE          32
�������`}
IE,#define MY_DEVICE_CHAN_INTR_MASK   CI_INTR0
e �������`~
I u(#define MY_DEVICE_DEV_INTR_MASK    0x80
th�������`
IIO
i�������`�
In@interface MyDevice:IODevice
v�������`�
Im.{
�������`�
I,5?port_t IOPort;        // interrupt notification received here
I���������`�
I��}
�������`�
I��
��������`�
I��E+ probe:(IODeviceNumber)devNumber deviceMaster:(port_t)deviceMaster;
.�������`�
I�- myDeviceInit;
���������`�
Iin
E������`�
I��@end
������`�
IEA
E#�|����`�
It/*

/�y����`�
I; * Probe and initialization of direct device, kernel mode.
por;�v����`�
IIO */
NRG�s����`�
I��
wS�p����`�
Ih/static int myDeviceNum = 0;
��_�m����`�
I<b
dk�j����`�
I��@implementation MyDevice
ew�g����`�
I��
�d��eP��
AN$6����UR$6���| ��6��������`�
IMY/*
CE_������`�
II_: * Probe:deviceMaster: is called out during early system 
������`�
I��; * autoconfig when the autoconfig module finds a hardware 
evi)������`�
I�> * device with a valid mapping in the internalDevMap[] table.
5������`�
Iei */
reA������`�
I�D+ probe:(IODeviceNumber)devNumber deviceMaster:(port_t)deviceMaster
eNM������`�
Ivi{
Y������`�
IeM
id myId;
e������`�
I- IODeviceReturn drtn;
q������`�
I��IODevicePort localDevPort;
��}������`�
I�|char dev_name[20];

�������`�
I
�������`�
Iiz/*
of�������`�
Irn * Get a devicePort.
�������`�
I�s */
��������`�
I��)drtn = IOCreateDevicePort(deviceMaster,
��������`�
I<bIOTaskSelf(),
��������`�
Iio
devNumber,
g�������`�
I
�&localDevPort);
�������`�
Iif(drtn) {
�������`�
I6IOLog("MyDevice probe: Can't create devicePort\n");
������`�
I��return nil;

������`�
I��}
II_������`�
Ias
%������`�
Iin/*
y 1������`�
I��< * Instantiate and set common IODevice instance variables.
dw=������`o
I��$ * These are all IODevice methods.
ngI������`�
IvM */
bU������`�
I�myId = [self alloc];
a������`�
I(I$[myId setDevicePort:localDevPort];
pom������`�
IeN[myId setUnit:myDeviceNum];
�y������`�
Imy1sprintf(dev_name, "myDevice%d", myDeviceNum++);
��������`�
II [myId setDeviceName:dev_name];
���������`i
Ir +   [myId setDeviceType:"SomeDeviceType"];
���������`�
Iof
�������`�
I /*
a �������`�
I��1 * Proceed with device-specific initialization.
O�������`�
Iev */
e�������`�
I�return [myId myDeviceInit];
��������`�
IvN}
�������`�
I�
��������`�
I;
/*
���������`�
IdrH * Device-specific initialization. Returns nil on error. Assumes valid 
Po	�}����`�
I�� * devicevPort on entry.
��z����`�
I} */
��!�w����`�
I
- myDeviceInit
Iin-�t����`�
I��{
9�q����`�
IatIODeviceReturn drtn;
E�n����`�
IIODevicePage *dev_page_p;
 ThQ�k����`�
Iceunsigned intr;
��]�h����`�
I
b
i�e����`�
Im/*
[su�b����`�
I��- * ...Initialize instance variables here...
]��_����`�
I� */
[d������(d$6����++$6���| Na6_n������`�
I��0IOPort = port_allocate(IOTaskSelf(), &IOPort);
];������`�
I�
������`�
I�/*
/)������`�
I�A * Perform one-time only hardware initialization. First set up 
�5������`�
I�� * register pointer.
A������`�
Iit */
�M������`�
I}
+drtn = IOMapDevicePage([self devicePort],
/*Y������`�
I�IOVmTaskSelf(),
e������`�
In.(vm_offset_t *)&dev_page_p,
q������`�
I��YES);
 *}������`�
Itrif(drtn) {
���������`�
I�w<IOLog("MyDevice: Error on IOMapDevicePage (%d)\n", drtn);
�q�������`�
IIreturn nil;
�������`�
I�}
I�������`�
Iag"[self setDevicePage:dev_page_p];
�������`�
I��
�������`�
I��/*
��������`�
I��? * Clear and disable interrupts. These are all IODevice(NRW) 
���������`
I
[
 * methods.
�������`�
I�� */
�������`�
I3intr = [self channelIntrCause:MY_DEVICE_CHANNEL];
������`�
INa:[self setChannelIntrCause:MY_DEVICE_CHANNEL cause:intr];

������`�
I];5[self setChannelIntrMask:MY_DEVICE_CHANNEL mask:0];
�������`�
I [self setDeviceIntrMask:0];
e%������`�
Iir
1������`�
I��/*
��=������`�
Int. * Get a global interrupt and a DMA channel.
I������`�
IpD */
gU������`�
I],6drtn = IOAttachInterrupt([self devicePort], IOPort);
a������`�
Ifsif(drtn) {
gem������`�
I�>IOLog("MyDevice: Error on IOAttachInterrupt (%d)\n", drtn);
y������`�
I"Mreturn nil;
�������`�
I(%}
, d�������`�
I��+drtn = IOAttachChannel([self devicePort],
}�������`�
I�MY_DEVICE_CHANNEL,
a�������`�
I��,NO,                        // stream mode
��������`�
I��MY_DEVICE_BUFSIZE);
�������`�
Iarif(drtn) {
(N�������`�
I��<IOLog("MyDevice: Error on IOAttachChannel (%d)\n", drtn);
���������`�
I[sreturn nil;
�������`�
INN}
�������`�
INa
[�������`�
IrC/*
Y_	�}����`�
Ise2 * ...configure device-specific hardware here...
�z����`�
INE */
0!�w����`�
I� 
[-�t����`�
IMa/*

e9�q����`�
Iir6 * Enable interrupts at the device and kernel level.
E�n����`
Ier# * The are IODevice(NRW) methods.
`�Q�k����`�
I�� */
�]�h����`�
Ita,[self setChanelnIntrMask:MY_DEVICE_CHANNEL
��i�e����`
Idr*          mask:MY_DEVICE_CHAN_INTR_MASK];
u�b����`�
Ita3[self setDeviceIntrMask:MY_DEVICE_DEV_INTR_MASK];
etu��_����`�
I��
d��d��[s$6����$6���| �
������`�
I  /*
 /������`�
I��' * Register with IODevice-level code.
���������`�
Ii */
 )������`�
I�[super init];
Dev5������`�
Ita[self registerDevice];
��A������`�
I[sreturn self;
M������`�
INN}
Y������`
I�
ae������`�
I�@end
/q������`
I�
ed�� h��
��$6�����$6���| �q3������UT`�
[leGet/Set Parameters
vic#UNUR�� �
U.
VThe following code fragment shows how a user program would read a parameter from, and 0UIUR���
UtaXwrite an array of parameters to, a kernel device named �SomeDevice0�. The code below is VI=UDUR���
U;
Uusing RPCs provided by the kernel; these RPCs are documented in the section entitled �JU?UR���
UU�Kernel-Level Driver Support�. Bear in mind that the RPCs are mapped on to similarly WU:UR���
UUnamed methods which are applied to an instance with a deviceName of �SomeDevice0� in edU5UR��@�
Ucethe kernel.
��|������`�
Ii(#define SET_PARAM_NAME  �SomeParameter�
];�������`�
I�+#define GET_PARAM_NAME  �AnotherParameter�
`��������`�
I;
&#define DEVICE_NAME     �SomeDevice0�
�������`�
I��
��������`�
I��*int readWriteParams(port_t deviceMaster, 
�������`�
I�unsigned *paramArray, 
�������`�
I�unsigned paramSize)
�������`�
I�q{
�������`�
I�IODeviceReturn drtn;
vic�������`�
I.
IOUnitNumber unit;
a�������`�
IusIOUnitType deviceType;
a������`�
IUIIOUnitName deviceName;
a������`�
I tunsigned returnedCount;
������`
Ideunsigned returnedInt;
�$������`�
Iro
e0������`
Ihe/*
 <������`�
IthC  * First find the IOUnitNumber of a device named �SomeDevice0�.
t�.H������`�
I t */
T������`�
Iimunit = 0;
UR`������`�
Id do {
hicl������`�
In #drtn = IOInquire(deviceMaster,
vicx������`�
I��unit,
ke�������`�
I��&deviceType,
_PA�������`�
Iam&deviceName);
��������`�
IPA"if((drtn == IO_DR_SUCCESS) &&
�������`�
I#d0   (strcmp(DEVICE_NAME, deviceName) == 0)) 
��������`�
I��break;// success
�������`�
I 
unit++;
��������`�
Iar%} while (drtn != IO_DR_NODEVICES);
g�������`�
I��
��������`�
I�� if(drtn == IO_DR_NODEVICES) {
 d������`�
I��7IOLog(�readWriteParams: SomeDevice0 not found\n�);
OUn��|����`�
I
areturn -1;
IUI�y����`�
Iic}

a�v����`�
I t
 �s����`�
Iou/*
�,�p����`�
IE  * We found the device; it�s IOUnitNumber �unit�. Send an array  
8�m����`�
I� * of unsigned ints.
e ID�j����`�
Iev */
P�g����`�
I�.)drtn = IOSetParameterInt(deviceMaster,
�\�d����`�
IUR	unit,
�h�a����`�
IicSET_PARAM_NAME,
#t�^����`�
I(dparamSize,
��[����`�
I��paramArray);
��d��e,��am$6������$6���| &
��������`�
I  
if(drtn) {
_������`�
I==4IOLog(�IOSetParameterInt returned %d\n�, drtn);
cc������`�
I�return -1;

�)������`�
Iar}
wh5������`�
I_N
CESA������`�
I�/*
�M������`
I��  * Now get one parameter.
 Y������`
I� */
IOe������`
Ims)drtn = IOGetParameterInt(deviceMaster,
�q������`
Irn	unit,
y}������`
IGET_PARAM_NAME,
I t�������`
I�1,
�������`
I�&returnedInt,
d�������`

IIO&returnedCount);
d �������`
I��
if(drtn) {
�������`	
Is.4IOLog(�IOGetParameterInt returned %d\n�, drtn);
�������`

Ireturn -1;
,
��������`
IUR}
ni�������`
I�if(returnedCount != 1) {
t�^�������`
I3IOLog(�IOGetParameterInt: returnCount = %d\n�,
�������`
IreturnedCount);
������`
Ireturn -1;
�
������`
I}
������`
I
%������`
I�/*
1������`
I��  * Success.
IO=������`
IrI */
d I������`
I��return returnInt;
reU������`�
I��}
d��_N���$6���� $6���|
��
��UU`k
Z��Libraries and Header Files
ete'UQUR�� 
U
�_This section describes the various libraries and header files which are currently installed by 4ULUR��@
U3the driverkit project. This is fairly tentative...
urnNUGUR��`
U��XThe latest version of the driverkit project can be found in ~osdev/DRIVERKIT/driverkit.
\n�����UT`
[��
Libraries
�U>UR�� 
U
�`All libraries are installed in /usr/local/lib. There are two basic libraries, libIO and libDev. �U9UR��
UPa]There are several versions of each library, and currently all of them get installed when you �U4UR��
U1;Vdo a �make install� from the DEVICES project. There are 3 degrees of freedom for each �U/UR��@
U��8library, and all 8 combinations are currently supplied:
���U*UR��`
UtuUser or Kernel level.
�U%UR��`
URELEASE and DEBUG versions.
_NU UR��`
Um88k or m68k version.
-UUR��  
UaSo, in all, 16 (!) .a files are installed. The versions of libIO and libDev have the same naming e:UUR��@ 
U
�Wconventions. In the list below, �<libname>� is either libIO or libDev, as appropriate.
lleR������`!
I��+<libname>68k.a         m68k User   RELEASE
ly ^������`$
IUG)<libname>68k_g.a       m68k User   DEBUG
 j������`%
Ica+<libname>68k_kern.a    m68k Kernel RELEASE
���v������`&
ILi)<libname>68k_kern_g.a  m68k Kernel DEBUG
 �������`'
Ius+<libname>88k.a         m88k User   RELEASE
ibI�������`(
IU9)<libname>88k_g.a       m88k User   DEBUG
s�������`)
Ian+<libname>88k_kern.a    m88k Kernel RELEASE
u �������`*
I1;)<libname>88k_kern_g.a  m88k Kernel DEBUG
eܪO��UT`,
[gr
Header Files
f�T�UR�� #
U��TMachine-independent header files are installed in /NextDeveloper/Headers/driverkit. tuT�UR��#
Uev0Machine-dependent header files are installed in nsT�UR��@#
U0/NextDeveloper/Headers/driverkit/{m68k/m88k}/. 
So)������`"
Ia 
ed��ib�� s$6����co$6��|isr 
��
��UU`2
Zs Revision History
�%������`5
I<l>24-Sep-91Doug MitchellAdded IOInquire(), IOLookup(),
1������`K
I   IOKernDeviceLookup().
��=������`N
I>6
kI������`J
IelI10-Sep-91Doug MitchellMultitudinous name changes to conform to 
 U������`�
Ius next API guidlelines.
  a������`
I��,Added get/set parameters RPCs and 
  m������`
I��methods.
k_ky������`3
IelFixed misc. typos. 
;�������`�
In_
 �������`�
I
e306-Aug-91Doug MitchellFirst Distribution.
U���������`4
Iene�Xd�6exLeftd��tuRightR��d���ndd��� lld��4d��EriRightNo1HeadRight
Sod���9
eLeftBlankFooter�d���"d���*d���,d���$d���&��d���(tod���/	24d���1
d���<upd���>d���@
()d���B
kd���Depd���Guld���I cd���K�d���Muid���Od���Setd���U��d���Wd���Y3d���[ td���]n_d���_06d���ad���c��d���eXd���gLed���i tud���k!d���m" d���o#4d���q$Ed���s%ghd���u&
ed���w'd���y(d���{)d���}*d���+d����,d����-d����.d����/d����0d����1d����2d����3d����4d����5d����6d����7d����8d����9d����:d����;d����<d����=d����>d����?d����@d����Ad���Bd��Cd�Dd�Ed�Fd�Gd�Hd�Id�Jd	�Kd	
�Ld
	�Md
�Nd
�Od
�Pd
�Qd�Rd�S�
E
$G~~$

�@�
U 
1�����FunctVarDescll$

�@�
X�NoteBoldNote:  9�l$

�@�
Uq;��
FctLibrary	LIBRARY\t�FctSynopsisd��$
�@�
VPd
���V�	TableHeadD	TableBodyl$$

�@�
XA^�l�WarningBold\tWarning:\tBody~~$
�@�
Ud
���BodyIndented�l$

�@�
UqR�
FctLibrary	LIBRARY\tFctSynopsisll$

�@�
U�cl~���@Bodyll$

�@�
XoldNoteBoldNote:  ;ll$
�@�
]PctL
i	GlossTermGlossDefHH$'
�@�
[P


2HeadBodyea�@�
_	v���
FooterLeft
�@�
UPFigureFigureTitlell$�@�
UP
FctSubHeadBodyIndented~~$
�@�
Vp	LI
���@
U�
HeaderFileFunctionll$
�@�
VP
TroubleshootingBody$$$'
�@�
ZPe
1HeadBodyHH$

�@�
[	Gl

FctHeadShortll$
�@�
UCaFig1CaptionDefault   FontC:Figure <n>-<n=1>Body~l$�@�
U~��@
U��BulletShort�\tll$�@�
`CQ
ChapterNum
C:Chapter <n>ChapterTitlell$'
�@�
\P
3HeadBodyll$
�@�
UCa
FigCaptionDefault   FontC:Figure <n>-<n+>Body��$

�@�
U
���
BodyIndented2�~$

�@�
UNA	Gl�eaho���Num1Long
N:<n=1>.\t
NumberLong~l$

�@�
Uefay~���@
U�
BulletLong�\t$$$'
�@�
ZP
1HeadBodyHH$'
�@

[P


2HeadnBodyle�~$

�@

UN�d�Bo��NumLong	N:<n+>.\t�@

_	<�v��FooterRight
Ull$

�@

X
TiptBoldTip:  �l$
�@

Uq�
FctSummary	SUMMARY\t
FctLibraryll$A�@

`p�ChapterTitleBody��$
�@

U tLo�@V�	TableBodyll$A�@

`p�ChapterTitleBody��$

I	
CodeExamp3~l$

�@
	
Ung~��
_��
BulletLong�\tHH$'
�@

[Pl

X2HeadBodyll$'
�@

\P
3HeadBodyll$'
�@

]Py
4HeadBody@~l$�@


UNA~���
U�	Num1Short
N:<n=1>.\tNumberShort�~l$�@

UN~
`����NumShort	N:<n+>.\tTll$
�@

Uq
IFctSynopsisSYNOPSIS
HeaderFile��$

I	
CodeExamp2~~$
�@

U$���BodyIndentedll$

�@

Ul3H~��Body�~$

�@

UN
����
U�NumLong	N:<n+>.\t�l$
�@

Uqu�
FctSummary	SUMMARY\t
FctLibraryll$A�@

`p~ChapterTitleBodyll$
�@

UqFctSynopsispSYNOPSIS
HeaderFileFi�@

_	v�CoEx��
FooterLeft~~$
�@

]
�dy�ed�BodyIndented�HZ$'
�@

[@


FctHead�
FctSummary~~$
�@

Vp
����
HeaderFileFunctionHZ$'
�@

[@

U

FctHead
FctSummarytS~l$

�@

XNAA~���teStep1Bold
N:<n=1>.\t
NumberBold~~$

I0	�
ad�Fi����@
_�� 2v�DExVh
otz�����
]��	CodeExamp

�@

`tedl@
[~��Body�~$�@

U 
~������
�Fi�nc 2�D
[V
UhFunction
ll$�@
 
UP

FctSubHeadBodyIndented��$

�@
!
Utepd���
BodyIndented2�~$�@
"
U _~����v����ot 2DVhFunction~l$

�@
#
XN~�
[��StepBold	N:<n+>.\t�

�@
)
`l~��Body$l$

�@
*
K2lncon~
��Body
U$l$A�@
+
`pChapterTitleBody�@
-
_	v�dyde��
FooterLeft�@
3
_	�v��FooterRightll$
�@
;
U GlossDef~~$
B
I	����ep�Bo	�.\� @2DVhz������	CodeExamp
~~$
C
I	
��dy�
U���@� 2DVteithz����
_���	CodeExamp
I
y
O	��
I��
JEmphasis���
K��
LItalic��
MBookName��k<
N/��
P
Boldnw

Q
I���
TSymbol���
U��ģ
V
.\��ģ
X
Bold��ģ
Z

��ģ
[
��ģ
\
~l
]
	��
^	Subscript	nw

_���
`���
a	Trademark	���
dSuperscriptit��
m	GlossTermCourier	HelveticaSymbolTimesoRegularRegular
BoldRegularItalic��Xx�0̍��g��]e��JHX1��>��E0���8�ĉ-R�Bz�=*���������2�O���&R	�"9��_G��ԙ3KAtiA���Z��Nz�5e���RY?�߬e�!�c�D�H�O&��ECH;2�(,�����J������D�2G~���㥼Vk��<�Vc���1L�Jfǘ[,d����1,�
�����~���L��
G`]Pě�@����"�RR~����tn�yT�N1�j�c��4DQpC`��D�Tn;�oD�%��lr}���F�4��Y(��ڪ��mh��ys��:�YןEr�����+�|��m�3��Ta�x̅�)�I��x���a9U�����2W���p�T\�
0p|��	6��F�K��z�M��-��(%X6�5�Nɻ4r�J��a��@9���9˩����Z��n�Y��)��f�G�a4)%X�_c�
�͢:]�������T�4���N^y��U����Ǖ�(2.�J#OD,�)
��
^���q��"9x-G�����7�Ď�ϐ.m�^L�A������-8/$�X@���@o�0��Y?1xp��q��0`�SS7�ӄ�g�����ag�C"�u�(�
/�6J�<P���l��ɝ"���t�>X!`-�P�%NdHV��{Mh���[�/����fR�0iRH߇�Ll�u!/CV�z
��-�	��-��	ϸ���N~W�$�&�����ij�2�9�NS)��tH��0D-, `y0�Y��y�{���z�#<C�]��N���4�n����o�����J]B�kU���m0�K�?�w��}Z�~���|��b1�A���j�+LH��>;Hz�Hc$#��G��I��kq�ԩQ�J�8Q~�}0��������#�U�_-Q3����b�JAF1�[>0����1\�F��;�ۑT����$|��tT�H$#Q�;�[��<��

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.