|
|
The ioctl(D2) entry point routine is called in response to an ioctl system call from a user-level process or a do_drvctl(D3) function issued by another driver. Note that the DDI 8 syntax has the same modifications from earlier DDI versions and the OpenServer ODDI version as do the read(D2) and write(D2) entry points discussed above.
The ioctl( ) entry point is the only DDI 8 entry point that executes in user context. User context is a special case of the blockable context, with the additional property that the associated user-level process is guaranteed to be on the stack at the time of execution, so functions such as copyin(D3) and copyout(D3) can be called to move data between user level and kernel level. See ``Context of a driver'' for more information.
The samp_ioctl( ) entry point begins with an ASSERT(D3) call to verify that the requested channel is within the range of channels defined for the device. It then provides two cases, one for reading and one for writing.
The CMOSWRITE case must first verify that the driver has write access for this device. It does this by checking whether the FWRITE flag was set in the driver's open(D2) entry point routine.
The code verifies that the user channel is less than SAMP_DEVSIZE (the device size) and, for writing, is also no smaller than SAMP_MINWRITE (the first writable byte). Note that these checks are coded to execute even on production drivers, as opposed to the ASSERT(D3) calls that execute only for debugging; the user channel is set each time the ioctl( ) request is made and so an error condition is always possible, whereas issues such as the pl(D5) priority level at which a section of code is entered is a factor of the driver code itself and is not affected by the specifics of each operation.
The code then calls the same
samp_start_io( )
subordinate driver routine
that the
samp_biostart( )
routine calls.
For DDI drivers,
all I/O requests are tracked through
the instance's in_progress
counter
rather than having separate tracking for
block and character access.
The code calls either the
samp_read_cmos( )
or
samp_write_cmos( )
subordinate driver routine to issue the actual
programmed I/O request for the device
and write the data to a local variable,
then calls the same
samp_end_io( )
subordinate driver routine that the
samp_biostart( )
routine calls to decrement the in_progress
counter.
The CMOSREAD case calls the copyout(D3) function and the CMOSWRITE case calls the copyin(D3) function to transfer the data from the local variable to user space or the data from user space into the local variable.
If any other ioctl requests are sent to the driver, the default case defines that the EINVAL error will be returned to the user-level process through the errno mechanism.