Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-1
Chapter
4
Writing CharacterDrivers
• I/O system interface to a character driver.
• Driver initialization.
• Character device driver entry points.
• Supporting select( ) in a driver.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-2
Writing Character Drivers
4.1 Introduction
Writing Character Drivers
Development Support Routines
Supporting Select
• Writing an I/O system vs. non-I/O system driver.
• Block vs. character device drivers.
• I/O system interface to driver.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-3
Standard I/O System Interface
• UNIX compatible
• Routines:
● open (filename, flags, mode)
● creat (filename, flags)
● read (fd, &buf, nBytes)
● write (fd, &buf, nBytes)
● ioctl (fd, command, arg)
● close (fd)
● remove (filename)
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-4
A Note on delete( )
• The delete entry point is accessed by an application
program calling remove( ).
• The delete entry point is intended to remove files; it is
not used by most drivers.
• Two types of “drivers” use it:
● File systems, e.g. dosFsLib uses it to remove files ona DOS file system
● Network drivers, e.g. netDrv uses it to request that aremote file be removed
• The delete entry is not intended to be used to remove
drivers or devices.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-5
I/O System Overview
Application
ioLib
open() close() read() write() ioctl()creat()
Driver A Driver B Driver C
• The I/O system provides an application some degree of device
independence.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-6
When to Write A Driver With AStandard Interface
• Flexible input/output to multiple devices with the
same interface is needed.
• Stream devices require support.
• Use of I/O redirection. is desired
• An interface familiar to application programmers is
desired.
• Support for select( ) is desired.
• The VxWorks shell calls creat( ), read( ) or write( ), and close( ) when
performing redirection.
• I/O redirection allows tasks to specify input or output sources at run
time. In VxWorks, see ioGlobalStdSet( ) and ioTaskStdSet( ) for details.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-7
When NOT to Write A Driver With AStandard Interface
• Device does not lend itself to I/O system model (not
stream oriented).
• Speed is very critical.
• While there is little overhead in the VxWorks I/O system, there is some
additional code which must be executed.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-8
Drivers Using The Standard Interface
• Block Drivers
● File system-based
● Random access and sequential
● Transfer data in multi-byte blocks
● Examples: floppy or hard disks, ramdisk
• Non-block Drivers
● Any other device
● Examples: serial or graphical input device such asmouse or graphics tablet
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-9
Block Devices
• Block devices are designed to support a file system.
• VxWorks-supported file systems:
● MS-DOS
● Raw
● Tape
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-10
I/O System Overview
Ap
pli
cati
on
I/O System
opencreatreadwriteioctlclosedelete
Devices
A
B
C
D
Blo
ckD
riv
ers
No
n-B
lock
Dri
ver
s
File Systems
DOS
------
Raw
• For block devices, the I/O system calls file system routines which in
turn make driver calls.
• For non-block devices, the I/O system directly calls driver routines.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-11
Device Reference
• Application references device by file name and file
descriptor
• Device driver references device by device descriptor
and device ID
filename device descriptor
deviceIdfd
Application I/O System Device Driver
• Device drivers typically do not know (or care) about the file name
(device name) or file descriptor.
• The I/O system communicates with the driver via device descriptors
and device IDs (defined by the driver).
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-12
Driver Table
Use iosDrvShow( ) to display the driver table.
creat delete open close read write ioctl
0
12 myOpen myOpenNULL myClose myRead myWrite myIoctl
3
Driver Number
• Used by I/O system to access driver entry points
• Fixed in size, but configurable by the NUM_DRIVERS definition in
configAll.h.
• Commonly contains the same routine for both the creat( ) and open( )entry points.
• Normally contains a null entry point for the delete( ) routine .
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-13
Device List
Use devs( ) to see list
“/pipe/abc”2
“/pipe/xyz”2
“/tyCo/0”1
“sacto:”4
pipedriverdata
pipedriverdata
netDrvdriverdata
serialdriverdata
• Used by I/O system to match a device name to a driver for open( ),creat( ) and delete( ) — the 3 routines that identify a file by filename (not
file descriptor)
• Doubly linked list of structures
• One structure per device
• Number of entries on list is dynamic
• Multiple device list structures may access the same driver (i.e. a driver
may support multiple devices).
The matching above is done by comparing file name; the access is bydrvNum. Only accessed by I/O system during an open(), creat() andremove().
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-14
The Device Descriptor Structure
• Every device has a device descriptor linked to the
device list.
• The first member of the structure is a DEV_HDR.
• The driver-dependent portion contains device specific
information.
DL_NODE
device name
driver #
devicespecific
data
Index into Driver Table
Driver dependent
Driver independentDEV_HDR
• The first member of the device descriptor struct is a DEV_HDR:
typedef struct{DL_NODE node;short drvNum;char * name;} DEV_HDR;
• Typical driver declaration:
#include "iosLib.h"...typedef struct
{DEV_HDR devHdr;/* driver specific information follows */...} XX_DEV;
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-15
File Descriptor Table
Use iosFdShow( ) to see table.
3
4
5
6
7
...
Driver # Device ID
Index intoDriver Table
Driverdependent
value
• Used by I/O system to identify driver after a device or file is opened.
• A file descriptor — obtained by a successful open( ) or creat( ) — is an
index into this table.
• Fixed in size, but configurable by the NUM_FILES defininition in
configAll.h.
• The above description is simplified.
Defined in iosLib.c (not the header file!) as a FD_ENTRY, it alsocontains the filename, an inuse flag, and a pointer to the DEV_HDR.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-16
Writing Character Drivers
Introduction
4.2 Writing Character Drivers
Development Support Routines
Supporting Select
• Installing a driver
• Driver entry points
• Removing a driver
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-17
Opening A Device
fd = open (“/myDevice”, O_READ, 0)
creat delete open close read write ioctl
0
1
2
myOpen myOpenNULL myClose
myOpen (pDevHdr, NULL, O_READ, 0)
Device List
Driver Table
myRead myWrite myIoctl
• Searches through device list for longest string match of name “/
myDevice”. Let’s say finds a match for “/myDevice”...
• Using the driver number stored in the DEV_HDR of the matching device
descriptor, the I/O system indexes the driver table to call the
appropriate driver xxOpen routine.
• The pDevHdr is a pointer to the matching device descriptor structure.
• Driver xxOpen( ) routine, i.e. myOpen( ), returns a device identifier.
• The sequence above applies as well for creat( ).
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-18
Returning from Driver’s xxOpen( )
File Descriptor Table
deviceId = myOpen (pDevHdr, ... )
fd = open (“/myDevice”, O_READ, 0)
deviceIddrivernumber5
file descriptor
• On successful return from driver’s xxOpen:
● I/O system adds driver number and device ID to the file descriptortable:
● Device ID returned from driver’s xxOpen (usually it is pDevHdr, theaddress of the device descriptor)
• Thereafter, fd identifies the device.
• The file descriptor is in index into the file descriptor table (hence,
alleviating the need for searches).
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-19
Reading from A Device
creat delete open close read write ioctl
0
1
2
myOpen myOpenNULL myClose
File Descriptor
Driver Table
myRead (devId, &buf, nBytes)
read (fd, &buf, nBytes)
Table
myRead myWrite myIoctl
• he fd, returned from open( ), is used as an index into the File Descriptor
Table.
• The driver number from the File Descriptor Table is used as an index
into the Driver Table, allowing invocation of the driver’s xxRead( )routine.
• The devId is the device ID (stored in the File Descriptor Table) defined by
the return value of the driver’s xxOpen( ).
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-20
Writing to A Device
creat delete open close read write ioctl
0
1
2
myOpen myOpenNULL myClose
File Descriptor
Driver Table
myWrite (devId, &buf, nBytes)
write (fd, &buf, nBytes)
Table
myRead myWrite myIoctl
• The mechanism for write (as well as ioctl and close) is identical to read.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-21
I/O System Overview
Application
ioLibopen() close() read() write() ioctl()creat()
iosLibiosDrvInstall()
iosDevAdd()
xxDrvxxDrv() xxDevCreate() xxOpen() xxClose() xxRead() xxWrite() xxIoctl()
Startup Code
• The xxDrv( ) and xxDevCreate( ) driver entry points are not accessed
through ioLib. These routines install the driver and devices into the I/O
system.
• The xxDrv( ) and xxDevCreate( ) routines are normally called during
system startup (often from the usrRoot task).
• The xx in xxDrv denotes the driver handler name, typically the same as
the name prefixing any global variable (including function names), e.g.,
xxDrv( ), xxOpen( ), xxDrvNum.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-22
Device Driver Functions
• xxDrv( )
● Installs driver in driver table -- iosDrvInstall( )● Performs any driver initialization
● Called once and once only
• xxDevCreate( )
● Adds device to the system device list -- iosDevAdd( )● Performs any device initialization
● Called once for each device
• Any of the 6 driver entry points
● These are optional
Driver initialization may include allocating memory andinitialization data structures to default values. Device initializationmay include actually writing to the device.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-23
Initializing A Driver
STATUS xxDrv (args...)
• xx is the driver handler, e.g. pipeDrv or tyCoDrv.
• The arguments are driver dependent.
• Calls iosDrvInstall( ) to add driver to I/O system
driver table.
• Should be called once only.
• Often called from user initialization code.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-24
Adding Driver into Driver Table
iosDrvInstall (xxCreat, xxDelete, xxOpen,xxClose, xxRead, xxWrite, xxIoctl)
• All routines are optional — use NULL if routine not
provided.
• Returns ERROR or driver number on success.
• Example:
fooDrvNum = iosDrvInstall (fooOpen, NULL, fooOpen, fooClose, fooRead, fooWrite, fooIoctl)
• Remember this should only be called once for driver.
• Driver number should be stored in global variable for future reference.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-25
Example xxDrv( ) Routine
1 LOCAL int fooDrvNum;23 STATUS fooDrv (void)4 {5 /* If driver already installed, just return */6 if (fooDrvNum > 0)7 return (OK);89 /* driver initialization, if any, here */1011 /* add driver to driver table */12 if ((fooDrvNum = iosDrvInstall (fooOpen, NULL,13 fooOpen, fooClose, fooRead,
fooWrite,14 fooIoctl)) == ERROR)15 return (ERROR);16 return (OK);17 }
• As shown above, installing a driver open( ) routine in the creat( ) entry
point is a common practice.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-26
Creating an Instance of Device
STATUS xxDevCreate (devName, args...)
• Args are driver dependent.
• Adds the specified device name to the system device list
by calling iosDevAdd( ).
• Performs any device specific initialization.
• Typically, allocates memory for device descriptor
structure.
• If the driver is not installed (xxDrvNum < 1), sets errnoto S_ioLib_NO_DRIVER and returns ERROR.
• The args are used for device-specific information such as board address,
channel number or other identifier.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-27
Adding to the Device List
STATUS iosDevAdd (pDevHdr, devName,drvNum)
pDevHdr Pointer to DEV_HDR
devName Name of device
drvNum Driver number returnedfrom iosDrvInstall( )
• Adds the device descriptor to the device list.
• Initializes the DEV_HDR with the device name and
driver number.
• Fails if devName already exists in the device list.
This routine malloc’s memory to hold devName. It initializes theDEV_HDR with the drvNum and devName and adds it to the linkedlist.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-28
Example Device Creation
1 LOCAL int fooDrvNum; /* initialized in fooDrv()*/...
2 STATUS fooDevCreate (char * devName)3 {4 FOO_DEV * pFooDev;
5 /* Check if driver is installed */6 if (fooDrvNum < 1)7 {8 errno = S_ioLib_NO_DRIVER;9 return (ERROR);10 }
11 /* Allocate and zero device structure */12 if ((pFooDev = (FOO_DEV *) malloc (sizeof (FOO_DEV))) =
= NULL)13 return (ERROR);14 bzero (pFooDev, sizeof (FOO_DEV));
• xxDevCreate( ) may take optional device-specific arguments.
• If you dynamically allocate the device descriptor structure (FOO_DEV),
remember to zero out its contents.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-29
Example (cont‘d)
15 /* Init device specific portion of FOO_DEV here*/
16 /* Perform any device-specific initialization here*/
17 /* Add device to the device list */18 if (iosDevAdd (&pFooDev->devHdr, devName,
fooDrvNum) ==ERROR)
19 {20 free ((char *) pFooDev);21 return (ERROR);22 }23 return (OK);24 }
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-30
Driver Open Routine
int xxOpen (pDevHdr, name, flags, mode)
pDevHdr Pointer to device descriptor
name Pointer to device name remainder
flags Flags from open( ): O_RDONLY, etc.
mode Permissions from open( ) — notnormally used in character driver
• Returns ERROR or device identifier, usually pDevHdr.
• Initializes the specific channel, if appropriate.
• Optionally, fails multiple attempts to open the same
device.
• Name is a pointer to the characters remaining after the device name —
specified in the xxDevCreate( ). For example, if the device was create
with
xx DevCreate ("/myDev",...)
and opened withfd = open ("/myDev/4", 0)
then name would be a pointer to “/4”. For most drivers, this will be anull pointer.
• If return value from xxOpen( ) is ERROR, then the open has failed and
nothing is added to the file descriptor table.
The file descriptor table holds a pointer to the DEV_HDR, pointer to filename,an “inuse” flag, and a “value”. The value holds the driver’s return fromxxOpen(). This value is the first argument passed to read, write, ioctl, andclose. The inuse flag is a BOOL to indicate whether this is a valid entry, likezeroing the inode number in a UNIX directory.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-31
Return Value from xxOpen()
• ERROR to cause application open to fail.
• Pointer to the device descriptor, when information is
maintained only by device.
• A driver-specific identifier, typically a pointer to a
private driver structure.
• To confirm that the return value from xxOpen( ) is being saved in file
descriptor table, use iosFdValue( ).
If a driver specific structure is chosen, there are two choices: 1. mallocmemory as needed, this is good in that it does not limit the number ofopen’s, bad in that if many open/closes are made, memory willbecome fragmented. 2. Declare a fixed sized array of structures, this isgood because it avoids the memory fragmentation problem, bad inthat if the number of open’s are limited and if structure is large orarray large then memory is wasted. This approach is also slightlyfaster.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-32
Example
1 typedef struct2 {3 MY_DEV * pMyDev;4 int offset;5 } MY_DEV_PER_FD:
...6 int myOpen (DEV_HDR * pDevHdr, char * name, int
flags)7 ...8 if ((pMyDevPerFd = (MY_DEV_PER_FD *) malloc
(sizeof9 (MY_DEV_PER_FD)) == NULL)10 return (ERROR);11 pMyDevPerFd->pMyDev = (MY_DEV *) pDevHdr;12 pMyDevPerFd->offset = 0;13 return ((int) pMyDevPerFd);14 }
• Consequences of using the code above:
● Must supply a myClose( ) to free memory allocated in myOpen( ).● To maintain current device offset, driver would have to modify offset
on each myRead( ), myWrite( ), and myIoctl( ), if an FIOSEEKcommand is implemented.
● Remember that the first parameter to each I/O call will now be apointer to your MY_DEV_PER_FD structure and not to MY_DEV:
int myRead (int deviceId, char * buf, int nBytes){MY_DEV_PER_FD *pMyDevPerFd = (MY_DEV_PER_FD *)
deviceId;MY_DEV * pMyDev = pMyDevPerFd->pMyDev;...
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-33
Read/Write Routine
int xxWrite (deviceId, pBuf, nBytes)
int xxRead (deviceId, pBuf, nBytes)
deviceId Value returned from driver xxOpen()
pBuf Pointer to buffer to read or write
nBytes The number of bytes to read or write
• These routines should return:
● the number of bytes successfully read or written, or● ERROR on failure, or● zero to indicate end-of-file or end-of-device (if meaningful)
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-34
Ioctl Routine
int xxIoctl (deviceId, cmd, arg)
deviceId Value returned from driver xxOpen()
cmd Action to perform
arg Optional cmd-specific int, often usedas a pointer
• Return value is cmd specific, except that ERROR is
reserved to indicate failure.
• Unknown commands should be failed and errno set to
S_ioLib_UNKNOWN_REQUEST.
• The cmd‘s are usually defined in a header file used by the driver and the
application program.
• The I/O system itself handles the FIOGETNAME command which copies
the filename associated with file descriptor to arg.
• Include ioLib.h.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-35
Ioctl Arguments
• Arg may be defined as:
● an integer value
● an address to input data
● an address to output data
● not used
• When arg is used as an address, it is often an address of
a structure.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-36
Ioctl Example
1 LOCAL FOO_STATE fooState;2 LOCAL int fooSpeed;3 LOCAL SEM_ID fooSem;4 ...5 int fooIoctl (int fooDevId, int cmd, int arg)6 {7 int status;89 switch (cmd)10 {11 case FOO_SPEED_SET:12 fooSpeed = arg;13 status = OK;14 break;15 case FOO_SPEED_GET:16 if (arg)17 *(int *)arg = fooSpeed;18 status = fooSpeed;19 break;
• Example demonstrates
● Passing an int (FOO_SPEED_SET) to a driver
● Returning an int (FOO_SPEED_GET) from a driver
● Passing the contents of a structure (FOO_STATE_SET) to a driver
● Returning the contents of a structure (FOO_STATE_GET) from a driver
• Line 16-17: For demonstration purposes, these lines show how fooSpeedmay be either returned or stored at the address of arg. Normally, a driver
passes fooSpeed back one way or the other (not both ways as shown).
This assumes that fooSpeed can not have a value of -1 (ERROR). The test
(line 16) for non-zero arg is precautionary.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-37
Ioctl Example (cont’d)
20 case FOO_STATE_SET:21 semTake (fooSem, WAIT_FOREVER);22 fooState = * (FOO_STATE *) arg;23 semGive (fooSem);24 status = OK;25 break;26 case FOO_STATE_GET:27 semTake (fooSem, WAIT_FOREVER);28 * (FOO_STATE *) arg = fooState;29 semGive (fooSem);30 status = OK;31 break;32 default:33 errno = S_ioLib_UNKNOWN_REQUEST;34 status = ERROR;35 }36 return (status);37 }
• In this example, the use of arg is cmd dependent:
FOO_SPEED_SET int
FOO_SPEED_GET Pointer to an int
FOO_STATE_SET Pointer to a structure
FOO_STATE_GET Pointer to a structure
• Since assignment of structures is non-atomic, the FOO_STATE_SET and
FOO_STATE_GET commands are protected by a mutex semaphore.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-38
The xxClose Routine
STATUS xxClose (devId)
• If driver is managing a private structure referenced by
devId, perform any reset action if necessary.
• Free memory allocated in your xxOpen( ), if any.
• Most drivers do not have a close routine.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-39
Writing Character Drivers
Introduction
Writing Character Drivers
4.3 Development Support Routines
Supporting Select
• Routines that may be useful for developing and debugging character
drivers.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-40
Deleting a Device
void iosDevDelete (pDevHdr)
• Removes the device descriptor addressed by pDevHdrfrom the device list.
• Inverse of iosDevAdd( ).
• Prevents any new opens on the device.
• Any file descriptors already opened remain unaffected
(as long as the device descriptor itself is not freed or
modified).
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-41
Removing a Driver
iosDrvRemove (drvNum, forceClose)
• Removes driver from driver table and deletes any
associated devices from the device list.
• If forceClose is TRUE, closes all open files associated with
driver.
• If forceClose is FALSE, returns ERROR if any files are open.
• If forceClose is TRUE and driver has an xxClose( ) routine, routine will be
called for each open file.
• This routine does not free memory allocated for a device list structure.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-42
Getting A Device Descriptor
DEV_HDR * iosDevFind (name, pNameTail)
name Device namepNameTail Pointer to string of name
remainder
• Returns a pointer to the DEV_HDR associated with nameor, if not found, to the default device, or NULL if no
default device defined.
• Routine initializes pNameTail with a pointer to the part
of name which was not matched with the device name.
• Sometimes useful in debugging or removing a device.
• If pNameTail points to a null character, the match was exact.
• If pNameTail points to name, there was no match.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-43
Example Remove Device Routine
1 #include "vxWorks.h"2 #include "iosLib.h"34 STATUS rmDev (char * devName)5 {6 DEV_HDR *pDevHdr;7 char * pNameTail;89 pDevHdr = iosDevFind (devName, &pNameTail);1011 if (pDevHdr == NULL || *pNameTail != ’\0’)12 return (ERROR);1314 iosDevDelete (pDevHdr);15 return (OK);16 }
• Important limitations in above routine:
● Does not free the device descriptor● If the device descriptors are dynamically allocated in the
xxDevCreate( ) routine, using this routine alone would create amemory leak
● Does not close files — there may still be open file descriptorsreferencing this device
● It would be safe to free the device descriptor only after all referencingfile descriptors were closed
● The device descriptor itself may reference resources which would notbe freed, e.g. semaphores, message queues, or private buffers
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-44
File Descriptor to Device IDConversion
int iosFdValue (fd)
• Returns the Device ID (return value from driver’s
xxOpen) for the device associated with the file
descriptor fd.
• Returns ERROR if fd is invalid.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-45
Writing Character Drivers
Introduction
Writing Character Drivers
Development Support Routines
4.4 Supporting Select
• Select initialization
• Supporting select’s ioctl commands
• Notifying select when device has data to read or is ready to write
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-46
Supporting select( )
• The select( ) call permits tasks to pend on multiple file
descriptors.
• Task can block until data is available, or device can be
written to.
• Allows for pending with a timeout.
• Supporting select( ) is optional.
• Appropriate only for I/O system character drivers.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-47
Select() Tools
• Select uses a struct fd_set which may be viewed as an
array of bits:
• Each bit represents a file descriptor of interest.
• Macros to help manipulate a struct fd_set:
FD_SET (fd, &fdset) Sets the fd bit in fdset
FD_CLR (fd, &fdset) Clears the fd bit in fdset
FD_ZERO (&fdset) Clears all bits in fdset
FD_ISSET (fd, &fdset) Tests if the fd bit is set in fdset
891011121314... 01234567
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-48
Using select( )
int select (width, pReadFds, pWriteFds,pExceptFds, pTimeOut)
width Number of bits to examine in the structfd_set’s below
pReadFds Pointer to a struct fd_set which holdsthe read file descriptors of interest
pWriteFds Pointer to a struct fd_set which holdsthe write file descriptors of interest
pExceptFds Pointer to a struct fd_set which holdsthe exception file descriptors of interest— not implemented
pTimeOut Pointer to a struct timeval, NULL implieswait forever
• The fd_set holds a bit per file descriptor, i.e. file descriptor 0 is bit 0, file
descriptor 1 is bit 1 and so forth.
• Returns number of fds that are ready, zero on time out, or ERROR (e.g. ifdriver does not support select).
• On return, select has modified the struct fd_set so that only those bitscorresponding to the file descriptors which meet the requestedcondition are set.
• The selectLib is UNIX BSD 4.3 compatible. VxWorks namingconventions are violated to maintain compatibility.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-49
Select Example
1 struct fd_set readFds;2 int fds[NUM_FDS], width = 0;
...3 FD_ZERO (&readFds);4 for (i=0; i<NUM_FDS; i++)5 {6 FD_SET (fds[i], &readFds);7 width = (fds[i] > width) ? fds[i] : width;8 }9 width++;10 if (select(width, &readFds,NULL,NULL,NULL) == ERROR)11 return (ERROR);12 for (i=0; i<NUM_FDS; i++)13 {14 if (FD_ISSET (fds[i], &readFds))15 {16 /* do something now that fds[i] is ready */17 }18 }
• When select( ) returns, the struct fd_set has been modified so that only
the bits corresponding to the file descriptors that are ready are set.
• If a read, write, or exception argument is NULL, that argument is
ignored.
• Must include selectLib.h.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-50
Select Overview
xxDevCreate( )
selWakeupListInit( )
select( )
xxIoctl (...,FIOSELECT,...)
selNodeAdd( )
selWakeup( )
xxIoctl (...,FIOUNSELECT,...)
selNodeDelete( )
selWakeupAll (...,SELWRITE)
selWakeupAll (...,SELREAD)
Ap
plic
atio
n
ready to write
data to read
selectLib Driver
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-51
Select Initialization
• Driver must declare a SEL_WAKEUP_LIST structure,
typically in the device descriptor structure.
• xxDevCreate( ) must call:
selWakeupListInit (pWakeupList)SEL_WAKEUP_LIST * pWakeupList;
• When device becomes available for writes, call:
selWakeupAll (pWakeupList, SELWRITE);
• When device obtains data for reads, call:
selWakeupAll (pWakeupList, SELREAD);
• The SEL_WAKEUP_LIST structure is usually declared as part of the device
descriptor structure:
typedef struct{DEV_HDR devHdr;...SEL_WAKEUP_LIST selWakeupList;...} FOO_DEV;...STATUS fooDevCreate (...)
{...pFooDev = (FOO_DEV *) malloc (sizeof (FOO_DEV));selWakeupListInit (&pFooDev->selWakeupList);...}
• The selWakeupAll( ) routine may be called at interrupt time.
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-52
Select Commands in ioctl
• Command FIOSELECT
selNodeAdd (pSelWakeupList, (SEL_WAKEUP_NODE *)arg);if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) ==
SELREAD) && thereIsDataToRead )selWakeup ((SEL_WAKEUP_NODE *) arg);
if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELWRITE) && deviceCanBeWrittenTo )selWakeup ((SEL_WAKEUP_NODE *) arg);
• Command FIOUNSELECT
selNodeDelete (pSelWakeupList, (SEL_WAKEUP_NODE *)arg);
• In FIOSELECT code, thereIsDataToRead and deviceCanBeWrittenTo must be
replaced with appropriate device-dependent code.
• Example:
int fooIoctl (int deviceId, int cmd, int arg){FOO_DEV * pFooDev = (FOO_DEV *) deviceId;
switch (cmd){
case FIOSELECT:selNodeAdd (&pFooDev->selWakeupList,
(SEL_WAKEUP_NODE *) arg);...
}}
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-53
Summary
• xxDrv( ) — called once per driver
● call iosDrvInstall( )● return STATUS
• xxDevCreate( ) — called once per device
● allocate and initialize a device descriptor structure● call iosDevAdd( )● return STATUS
Wind River SystemsTornado Device Driver Workshop © Copyright Wind River Systems 4-54
Summary
• xxOpen( )
● initialize any per-open structure● return device ID or ERROR on failure
• xxClose( )
● reset any per open structure● free any memory allocated during xxOpen( )
• xxRead( ) / xxWrite( )
• xxIoctl( )
● process known commands● fail unknown commands