|
|
Darwin 0.2 Driver Kit
� W� " $ e� e� e| e� e� �� � 5, 7�d 9 9 � d H H d �/ d UG�6�J UG�6�J Dd �� X� X� X� �� TO " $ e� e� e| e� e� � � # %�d 9 9 � d H H d �/ d R� �#�2 R� �#�2 Dd UG UG UG ��
8 8 x H H �/ d[(� H H d d ' � @ �� Z
Z�0�� �
Driverkit
12 August, 1992
� Z
Z �@�`� ��0�P��
Agenda:
� Architecture Discussion
� Current Status
� Schedule and Priorities
� Z
Z�@�`� ��0�P��
� libIO Timer and Sleep Support Functions
� m
X �@�`� ��0�P��� �/*
* Sleep for indicated number of milliseconds.
*/
void � �IOSleep� �(unsigned milliseconds);
/*
* Spin for indicated number of microseconds.
*/
void � �IODelay� �(unsigned microseconds);
/*
* Call function fcn with argument arg in specified number
* of seconds.
*/
void � � IOTimeout� �(IOThreadFcn fcn, void *arg, int seconds);
/*
* Cancel callout requested in IOTimeout().
*/
void � �IOUntimeout� �(IOThreadFcn fcn, void *arg);
/*
* Obtain current time in ns.
*/
void � �IOTimeStamp� �(ns_time_t *nsp);
� m
X�@�`� ��0�P��� �
� libIO Standard Thread Functions
� m
X �@�`� ��0�P��� �/*
* These are opaque to the user.
*/
typedef void *� �IOThread� �;
typedef void (*� �IOThreadFcn� �)(void *arg);
/*
* Start a new thread starting execution at fcn with
* argument arg.
*/
IOThread � �IOForkThread� �(IOThreadFcn fcn, void *arg);
/*
* Suspend a thread started with IOThreadFork().
*/
void � �IOSuspendThread� �(IOThread thread);
/*
* Resume a thread started by IOThreadFork().
*/
void � �IOResumeThread� �(IOThread thread);
volatile void � �IOExitThread� �();
� m
X�@�`� ��0�P��� �
�#ifdef KERNEL
IODevToIdMap *_idMap; // provides dev_t to id
// mapping for this instance.
#endif KERNEL
id _LogicalDiskLock; // NXLock. Serializes
// operations whcih change
// LogicalDisks attached to
// this device.
char _driveName[MAXDNMLEN]; // for Unix 'drive_info'
// requests
/*
* The lastReadyState variable is initialized by device-specific
* subclass, but is subsequently only changed by the
* volCheck module.
*/
DiskReadyState _lastReadyState;
/*
* Statistics. Accessed en masse via
* getParameterInt(DISK_STATS_ARRAY).
* All times in ms.
*/
unsigned _readOps;
unsigned _bytesRead;
� Z
Z�@�`� ��0�P��� �� �IODiskDevice Class
� �
� Z
Z �@�`� ��0�P��� �@interface IODiskDevice: IODevic
{
@private
id _logicalDisk; // first LogicalDisk object
// attached to this raw disk.
// May be nil.
unsigned _blockSize; // in bytes
unsigned _deviceSize; // in blockSize's
unsigned _removable : 1, // removable media device
_formatted : 1, // disk is formatted
_diskIsOpen : 1,
_isPhysDevice : 1; // this is NOT a logical disk
huser_driver Server
� �� �
� m
X �@�`� ��0�P��� �� Kernel-level server providing:
� Device ownership and driver
authentication
� Mapping of device registers into driver's
VM space
� Interrupt notification via Mach messages
� DMA functions (enqueue, dequeue)
� Same RPC interface for User- and Kernel-level
drivers
� * channelNumber of the device represented by devicePort.
*/
IODeviceReturn � �IOAttachChannel� �(
IODevicePort devicePort,
int channelNumber,
BOOL streamMode,
int bufferSize);
/*
* Disassociate the dma channel channelNumber from the
* device represented by devicePort. Frees up all resources
* associated with specified DMA channel.
*/
IODeviceReturn � �IODetachChannel� �(
IODevicePort devicePort,
int channelNumber);
� �� Z
Z�@�`� ��0�P��
�� Z
Z �@�`� ��0�P��� �/*
* Build and enqueue a list of dma descriptors. The memory
* referenced by the descriptor will be locked. This returns
* IO_CR_ALIGNMENT if the channel has been configured as
* a streaming mode channel, rw is IO_DMA_DIR_READ, and
* the specified frame crosses a page boundary.
*/
IODeviceReturn � �IOEnqueueDma� �(
IODevicePort devicePort,
int channelNumber,
vm_task_t taskId,
vm_offset_t addr,
vm_size_t len,
IODmaDirection rw,
IODescriptorCommand cmd, // descriptor command (m88k only)
unsigned char index, // descriptor command region/index
// (m88k only)
IOChannelEnqueueOption opts,
unsigned dmaId, // must be non-zero
BOOL *running); // returned
�
/*
* Dequeue a dma frame enqueued via chan_dma_enqueue.
* A dma_id of DMA_ID_NULL indicates that no descriptors
* are available; IO_CR_SUCCESS is returned in that case.
* IO_CR_BUSY is returned if the channel is still enabled
* and no completed descriptors are available.
*/
IODeviceReturn � �IODequeueDma� �(
IODevicePort devicePort,
int channelNumber,
IOChannelDequeueOption opts,
vm_size_t *bcount, // RETURNED (except on
// m88k output devices)
IOUserStatus *userStatus, // RETURNED, m88k only
IODmaStatus *dmaStatus, // RETURNED
BOOL *eor, // RETURNED
unsigned *dmaId); // RETURNED
� �� Z
Z�@�`� ��0�P��
�Driverkit Architecture
� Z
Z �@�`� ��0�P��
� Class Hierarchy
� Thread-based model of I/O
� libIO
� user_driver Server
� Autoconfiguration
� UXPR tracing
� �� �
� */
- (int)registerDevice;
- (void)unregisterDevice;
/*
* Get/Set instance variables.
*/
- (void)� �setDeviceName� � : (const char *)name;
- (const char *)� �deviceName� �;
- (void)� �setDeviceType� � : (const char *)type;
- (const char *)� �deviceType� �;
- (void)� �setLocation� � : (const char *)location;
- (const char *)� �location� �;
- (void)� �setUnit� � : (unsigned)Unit;
- (unsigned)� �unit� �;� �� �
)� �/*
* Obtain device parameters.
*/
- (IODeviceReturn)� �getParameterInt� � :
(IOParameterName)parameterName
maxCount : (unsigned int)maxCount
parameterArray :
(unsigned int *)parameterArray
returnedCount :
(unsigned int *)returnedCount;
�
- (IODeviceReturn)� �getParameterChar� � :
(IOParameterName)parameterName
maxCount : (unsigned int)maxCount
parameterArray :
(unsigned char *)parameterArray
returnedCount :
(unsigned int *)returnedCount;
- (IODeviceReturn)� �setParameterInt� � :
(IOParameterName)parameterName
count : (unsigned int)count
parameterArray :
(unsigned int *)parameterArray;
- (IODeviceReturn)� �setParameterChar� � :
(IOParameterName)parameterName
count : (unsigned int)count
parameterArray :
(unsigned char *)parameterArray;
� libIO - Miscellaneous Functions
� m
X �@�`� ��0�P��� �
� Z
Z �@�`� ��0�P��� �/*
* Log a printf-style string to console.
*/
void � �IOLog� �(const char *format, ...);
/*
* Obtain environment-independent 'task_self' for Mach calls.
*/
task_t � �IOTaskSelf� �();
/*
* Panic (if in the kernel) or dump core (if user space).
*/
void � �IOPanic� �(const char *reason);
/*
* Convert a integer constant (typically a #define or enum)
* to a string.
*/
typedef struct {
int rvValue;
const char *rvName;
} � �regValues� �;
const char *� �IOIntToString� �(int value,
const regValues *regValueArray);
� Z
Z�@�`� ��0�P��� �
� Z
Z �@�`� ��0�P��� �/*
* Memory allocation functions. Both may block.
*/
void *� �IOMalloc� �(int size);
void � �IOFree� �(void *p, int size);
� �� Z
Z�@�`� ��0�P��
!� m
X�@�`� ��0�P��user_driver Server:
Device ownership and driver authentication
� m
X �@�`� ��0�P��
� Capability of accessing a hardware device is represented by a � �Device Port� �.
� All RPCs between a driver and the user_driver server are via Device Port.
� Device Ports are created by the user_driver server at boot time.
� Device ports given to kernel-level drivers directly (drivers are trusted)
� Device ports are given to user-level drivers by Config program, which runs at rc time.
� m
X�@�`� ��0�P��user_driver Server:
Mapping of device registers into driver's VM space
� m
X �@�`� ��0�P��
� �� �/*
* Map the device register page of the device associated with
* devicePort into the target task at addr.
*/
IODeviceReturn � �IOMapDevicePage� �(
IODevicePort devicePort,
task_t targetTask,
vm_offset_t *addr, /* in/out */
BOOL anywhere,
IOCacheSpec cache); /* DEV_CACHE_OFF,
* DEV_CACHE_WRITE_THRU, etc.
*/
/*
* Unmap the device register page of the device associated with
* devicePort.
*/
IODeviceReturn � �IOUnmapDevicePage� �(
IODevicePort devicePort,
task_t target_task,
vm_offset_t addr);
� �
� m
X�@�`� ��0�P��
� m
X �@�`� ��0�P��
4� �� m
X�@�`� ��0�P��user_driver Server:
DMA functions
� m
X �@�`� ��0�P��
� NRW DMA channels are dynamically allocated to devices - 32 total channels available.
� Z
Z�@�`� ��0�P��
� m
X �@�`� ��0�P��� Enqueue/dequeue memory as source/destination of DMA in quanta called 'frames'.
� One frame can cross page boundaries, but must (currently) follow hardware alignment restrictions (NRW only).
� �� Z
Z �@�`� ��0�P��/*
* Associate a hardware dma channel with the channel
Autoconfiguration of NRW Kernel drivers
� Z
Z �@�`� ��0�P��
� m
X �@�`� ��0�P��� No hard-coded list of addresses
� Hardware device identified by "deviceType"
� Kernel contains a table mapping deviceType to driver Class name
� Z
Z �@�`� ��0�P��
� user_driver server:
� scans hardware
� calls probe:deviceMaster: on each device
found, passing in the global device number.
� Drivers get their devicePort via
IOCreateDevicePort().
� m
X �@�`� ��0�P��� There is also a mechanism for starting up "pseudodevices", device drivers which are not attached to a piece of hardware.
� Indirect devices attach to another IODevice, not to a piece of hardware. E.g., SCSI Disk attaches to SCSIController.
�� Z
Z�@�`� ��0�P�� Autoconfiguration of User level drivers
� Z
Z �@�`� ��0�P��
� m
X �@�`� ��0�P��� Config, a privileged user-level program, is the caller of IOCreateDevicePort() for all devices which are not owned by kernel drivers.
� Config maps deviceType to a file name in /usr/Devices, execs driver if found, and passes Device Port to driver via bootstrap server.
� User level driver are NOT privileged
�
� Z
Z�@�`� ��0�P��� �Driverkit� � Class Hierarchy
� �
� Z
Z �@�`� ��0�P��
� Z
Z�@�`� ��0�P��
+� �� >@ClassHierarchy3.641598.eps�
9IODiskDevice Protocols
� Z
Z �@�`� ��0�P��� �/*
* Standard IODiskDevice read/write protocol. Offsets are in blocks.
* Lengths are in bytes.
*/
@protocol DiskDeviceRw
- (IOReturn) � �readAt� � : (unsigned)offset
length : (unsigned)length
buffer : (out unsigned char *)buffer
actualLength : (out unsigned *)actualLength
client : (vm_task_t)client;
- (IOReturn) � �readAsyncAt� � : (unsigned)offset
length : (unsigned)length
buffer : (out unsigned char *)buffer
pending : (unsigned)pending
client : (vm_task_t)client;
- (IOReturn) � �writeAt� � : (unsigned)offset
length : (unsigned)length
buffer : (in unsigned char *)buffer
actualLength : (out unsigned *)actualLength
client : (vm_task_t)client;
- (IOReturn) � �writeAsyncAt� � : (unsigned)offset
length : (unsigned)length
buffer : (in unsigned char *)buffer
pending : (unsigned)pending
client : (vm_task_t)client;
@end
� Z
Z�@�`� ��0�P��� �
A unsigned _readTotalTime;
unsigned _readLatentTime;
unsigned _readRetries;
unsigned _readErrors;
unsigned _writeOps;
unsigned _bytesWritten;
unsigned _writeTotalTime;
unsigned _writeLatentTime;
unsigned _writeRetries;
unsigned _writeErrors;
unsigned _otherRetries;
unsigned _otherErrors;
}� �
� �� Z
Z�@�`� ��0�P��
� Z
Z �@�`� ��0�P��� �/*
* Public methods to get and set disk parameters. These are
* implemented in the DiskObject class.
*/
- (unsigned)� �deviceSize� �;
- (unsigned)� �blockSize� �� �;
�- (IOReturn)� �setFormatted� �� � : (unsigned)formattedFlag;
- (unsigned)� �formatted� �� �;
- (unsigned)� �removable� �� �;
- (const char *)� �driveName� �� �;
- (unsigned)� �isPhysDevice� �� �;
- (unsigned)� �diskIsOpen� �� �;
/*
* Two forms of eject - one for use with logical disks attached
* (devEjectDisk), so that attached NXDisks can be polled for
* open state; this method is in the DiskDeviceSubclass protocol
* (below). The other, supported in IODiskDevice, is for an
* exported interface to the physical disk (which is not normally
* used in the kernel).
*/
- (IOReturn) � �ejectDisk� �� �;
@/*
* Get/set parameters used only by subclasses.
*/
- (void)� �setDeviceSize� �� � : (unsigned)size;
- (void)� �setBlockSize� �� � : (unsigned)size;
- (void)� �setIsPhysDevice� �� � : (unsigned)isPhysFlag;
- � �logicalDisk� �� �;
- (void)� �setRemovable� �� � : (unsigned)removableFlag;
- (void)� �setDriveName� �� � : (const char *)name;
- (DiskReadyState)� �lastReadyState� �� �;
- (void)� �setLastReadyState� �� � : (DiskReadyState)readyState;
- (void)� �setDiskIsOpen� �� � : (unsigned)isOpenFlag;
/*
* internal setFormatted - avoids logical disk interaction.
*/
- (void)� �setFormattedInt� �� �:(unsigned)formattedFlag� �;
/*
* Statistics support.
*
* These methods are invoked by subclass during I/O.
*/
- (void)� �readStats� �� � : (unsigned)bytesRead
totalTime : (ns_time_t)totalTime
latentTime : (ns_time_t)latentTime;
- (void)� �writeStats� �� � : (unsigned)bytesWritten
totalTime : (ns_time_t)totalTime
latentTime : (ns_time_t)latentTime;
- (void)� �didReadRetry� �� �;
- (void)� �gotReadError� �� �;
- (void)� �didWriteRetry� �� �;
- (void)� �gotWriteError� �� �;
- (void)� �didOtherRetry� �� �;
- (void)� �gotOtherError� �� �;
@end
� Z
Z�@�`� ��0�P��� �
T� Z
Z �@�`� ��0�P��� �/*
* The DiskDeviceSubclass protocol must be implemented by each
* bottom-level subclass of IODiskDevice.
*/
@protocol DiskDeviceSubclass
/*
* Get physical parameters (dev_size, block_size, etc.) from new
* disk. Called upon disk insertion detection or other transition to
* RS_READY.
*/
- (IOReturn)� �getPhysParams� �� �;
/*
* Called by volCheck thread when WS has told us that a requested
* disk is not present. Pending I/Os which require a disk to be present
* must be aborted.
*/
- (void)� �abortRequest� �� �;
�
/*
* Called by the volCheck thread when a transition to "ready" is
* detected. Pending I/Os which require a disk may proceed.
*/
- (void)� �diskPresent� �� �;
/*
* Inquire if disk is present; if not, and 'prompt' is TRUE, ask for it.
* Returns IO_R_NODISK if:
* prompt TRUE, disk not present, and user cancels request for
* disk.
* prompt FALSE, disk not present.
* Else returns IO_R_SUCCESS.
*/
- (IOReturn)� �isDiskPresent� �� � : (BOOL)prompt;
R/*
* Device-specific eject method.
*/
- (IOReturn) � �devEjectDisk� �� �;
$
/*
* Determine basic state of device. This method should NOT
* implement any retries. It also should not return RS_EJECTING
* (That's only used in the lastReadyState instance variable).
*/
- (DiskReadyState)� �checkReady� �� �;
@end
� Z
Z�@�`� ��0�P��� �
�� m
X�@�`� ��0�P��user_driver Server:
Interrupt notification via Mach messages
� m
X �@�`� ��0�P��
� No code in any driver runs at spl.
� All interrupt notification is via Mach message mechanism.
� �/*
* Request that interrupt notification messages for the device
* represented by devicePort be sent to the port interruptPort.
*/
IODeviceReturn � �IOAttachInterrupt� �(
IODevicePort devicePort,
port_t interruptPort);
/*
* Disassociate interrupt notification messages for the device
* represented by devicePort from being sent to intr_port.
*/
IODeviceReturn � �IODetachInterrupt� �(
IODevicePort devicePort,
port_t interruptPort);
�
/*
* Issue command on the dma channel identified by devicePort and
* channelNumber.
*
* IO_CHAN_NONE can be specified for channelNumber if no
* channels are attached; in this case the only legal
* IOChannelCommand bits are IO_CC_INTR_ENABLE and
* IO_CC_INTR_DISABLE.
*/
IODeviceReturn � �IOSendChannelCommand� �(
IODevicePort devicePort,
int channelNumber,
IOChannelCommand command);
/*
* Values for IOChannelCommand.
*/
#define � �IO_CC_INTR_ENABLE� � 0x0001 // enable interrrupts
#define � �IO_CC_INTR_DISABLE� � 0x0002 // disable interrupts
#define � �IO_CC_LOOP_FRAME� � 0x0004 // create DMA frame
// loop
#define � �IO_CC_UNLOOP_FRAME� � 0x0008 // disconnect DMA
// frame loop
� Z
Z�@�`� ��0�P��UXPR tracing
� m
X �@�`� ��0�P��� Like the 68k Kernel's xpr function - silent, cheap storing of sprintf strings in a circular buffer, evaluated subsequent to run time
� XPRViewer App allows displaying uxpr data in a scrollview on a separate machine
� XPRViewer also allows setting uxpr masks (filter bits) by name instead of by hex value
� XPRViewer runs on kernel drivers as well as on user-level drivers
� NRW kernel has multiple words of uxpr masks (m68k only had one word)
V� Z
Z�@�`� ��0�P��Current Status
� Z
Z �@�`� ��0�P��
� m
X �@�`� ��0�P��� All functionality is present in Alpha baseline release.
� Z
Z �@�`� ��0�P��
� m
X �@�`� ��0�P��� m88k Kernel level drivers completed:
� Z
Z �@�`� ��0�P�� � SCSIController, SCSIDisk
� FloppyController, FloppyDisk
� Ethernet
� adbDriver, adbDevice, adbKeyboard,
adbPointer
� kmDevice
� EventDriver
� m
X �@�`� ��0�P��� m88k User level drivers completed:
� Z
Z �@�`� ��0�P�� � Laser Printer
� m
X �@�`� ��0�P��� Config is working and released, but doesn't run from /etc/rc yet.
� Intend to modify kernloader to run all loaded servers in IOTask context.
� Z
Z �@�`� ��0�P��
� Z
Z�@�`� ��0�P��
�Current Status (continued)
� Z
Z �@�`� ��0�P��
� Drivers in development:
� zs (Serial) - Mike DeMoney
� Token Ring - Joel Greeblatt
� Sound - Mike Minnick
� ISDN - Morris Meyer and Rich Williamson
� SCSI Tape, SCSI Generic - dmitch
� m
X �@�`� ��0�P��� IONetDevice, the basis for Ethernet and Token Ring, is being extensively modifed. Serial driver will also be a subclass of this device.
IODevice Class
� �
� Z
Z �@�`� ��0�P��� �@interface IODevice: Object
{
@private
/*
* these fields must be initialized by the device-specific code prior
* calling registerDevice.
*/
int _unit; // like a minor number. Use
// is unique per device.
IOUnitName _deviceName; // E.g., "sd0a"
IOUnitType _location; // E.g., "0xf7f04000"
IOUnitType _deviceType; // E.g., "SCSIDisk"
}
/*
* Register/unregister instance in current namespace.
* _deviceName must be valid for both calls.
3libIO
� m
X �@�`� ��0�P��� C library
� Z
Z �@�`� ��0�P��
� m
X �@�`� ��0�P��� Allows writing driver code which is easily portable between kernel and user
� Supercedes "Kernel Internal API" specified in Loadable Kernel Server Tech Doc
� Z
Z �@�`� ��0�P��
� m
X �@�`� ��0�P��� Provides
� Timer and sleep support
� Standard Thread functions
� Error Logging
� Memory Allocation
� Machkit-compatible NXLock objects in the
kernel
� m
X�@�`� ��0�P��
�Thread-based model of I/O
� m
X �@�`� ��0�P��� One piece of hardware is associated with one thread.
� Interrupts are seen by drivers as Mach messages.
� Context:
� Kernel - all threads are part of one task
called IOTask. IOTask has:
� Kernel's physical memory map.
� Its own VM map.
� Its own IPC space.
� User - all threads part of driver's task_self().
� Z
Z�@�`� ��0�P��
�d �et .Nt ,r a% -
> -: t NX8$ �% � �$ �Pt E � ��d 1]$ 3�% 6_ �d 8��t -=�d 0x �t ;�@$ >% ?� @d @K �T R��T Pi�t m�t �t �Ot
J�t 6�t "Y�t Aq�% D5� G5 t %e[d �e �@d �ET '�7T *�T G8�T IR
T L�Z� m
X�@�`� ��0�P��user_driver Server:
Device ownership and driver authentication
� m
X �@�`� ��0�P��
� Capability of accessing a hardware device is represented by a � �Device Port� �.
� All RPCs between a driver and the user_driver server are via Device Port.
� Device Ports are created by the user_driver server at boot time for Kernel drivers and at rc time for User level drivers.
� Device ports given to kernel-level drivers directly (drivers are trusted)
� Device ports are given to user-level drivers by Config program, which runs at rc time.
�d �et .Nt ,r a% -
> -: t NX8$ �% � �$ �Pt E � ��d 1]$ 3�% 6_ �d 8��t -=�d 0x �t ;�@$ >% ?� @d @K �T R��T Pi�t m�t �t �Ot
J�t UG�t "Y�t Aq�% D5� G5 t %e[d �e �@d �ET '�7T *�T G8�T IR
T L�
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.