FreeBSD Device Driver Writer's Guide : Types of drivers. : Character : Entry Points
Previous: Data Structures
Next: Header Files

2.1.2. Entry Points

2.1.2.1. d_open()

d_open() takes several arguments, the formal list looks something like:


int
d_open(dev_t dev, int flag, int mode, struct proc *p)

d_open() is called on every open of the device.

The dev argument contains the major and minor number of the device opened. These are available through the macros major() and minor()

The flag and mode arguments are as described in the open(2) manual page. It is recommended that you check these for access modes in <sys/fcntl.h> and do what is required. For example if flag is (O_NONBLOCK | O_EXLOCK) the open should fail if either it would block, or exclusive access cannot be granted.

The p argument contains all the information about the current process.

2.1.2.2. d_close()

d_close() takes the same argument list as d_open():


int
d_close(dev_t dev , int flag , int mode , struct proc *p)

d_close() is only called on the last close of your device (per minor device). For example in the following code fragment, d_open() is called 3 times, but d_close() is called only once.


 ...
    fd1=open("/dev/mydev", O_RDONLY);
    fd2=open("/dev/mydev", O_RDONLY);
    fd3=open("/dev/mydev", O_RDONLY);
 ...
   <useful stuff with fd1, fd2, fd3 here>
 ...
    close(fd1);
    close(fd2);
    close(fd3);
 ...

The arguments are similar to those described above for d_open().

2.1.2.3. d_read() and d_write()

d_read() and d_write take the following argument lists:


int
d_read(dev_t dev, struct uio *uio, int flat)
int
d_write(dev_t dev, struct uio *uio, int flat)

The d_read() and d_write() entry points are called when read(2) and write(2) are called on your device from user-space. The transfer of data can be handled through the kernel support routine uiomove().

2.1.2.4. d_ioctl()

It's argument list is as follows:


int
d_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *p)

d_ioctl() is a catch-all for operations which don't make sense in a read/write paradigm. Probably the most famous of all ioctl's is on tty devices, through stty(1). The ioctl entry point is called from ioctl() in sys/kern/sys_generic.c

There are four different types of ioctl's which can be implemented. <sys/ioccom.h> contains convenience macros for defining these ioctls.

_IO(g,n) for control type operations.

_IOR(g,n,t) for operations that read data from a device.

_IOW(g,n,t) for operations that write data to a device.

_IOWR(g,n,t) for operations that write to a device, and then read data back.

Here g refers to a group. This is an 8-bit value, typically indicative of the device; for example, 't' is used in tty ioctls. n refers to the number of the ioctl within the group. On SCO, this number alone denotes the ioctl. t is the data type which will get passed to the driver; this gets handed to a sizeof() operator in the kernel. The ioctl() system call will either copyin() or copyout() or both for your driver, then hand you a pointer to the data structure in the arg argument of the d_ioctl call. Currently the data size is limited to one page (4k on the i386).

2.1.2.5. d_stop()

2.1.2.6. d_reset()

2.1.2.7. d_devtotty()

2.1.2.8. d_poll() (3.0+) or d_select() (2.2)

d_poll()'s argument list is as follows:


void
d_poll(dev_t dev, int events, struct proc *p)

d_poll() is used to find out if a device is ready for IO. An example is waiting for data to become available from the network, or waiting for the user to press a key. This correspond to the poll() call in userland.

The d_poll() call should check for the events specified in the event mask. If none of the requested events are active, but they may become active later, it should record this for the kernel's later persual. d_poll() does this by calling selrecord() with a selinfo structure for this device. The sum of all these activities look something like this:


static struct my_softc {
	struct queue rx_queue;  /* As example only - not required */
	struct queue tx_queue;  /* As example only - not required */
	struct selinfo selp;    /* Required */
} my_softc[NMYDEV];

...

static int
mydevpoll(dev_t dev, int events, struct proc *p)
{
	int revents = 0;	/* Events we found */
	int s;
	struct my_softc *sc = &my_softc[dev];

	/* We can only check for IN and OUT */
	if ((events & (POLLIN|POLLOUT)) == 0)
		return(POLLNVAL);
	
	s = splhigh();
	/* Writes are if the transmit queue can take them */
	if ((events & POLLOUT) &&
	    !IF_QFULL(sc->tx_queue))
		revents |= POLLOUT;
	/* ... while reads are OK if we have any data */
	if ((events & POLLIN) &&
	    !IF_QEMPTY(sc->rx_queue))
		revents |= POLLIN;
	if (revents == 0)
		selrecord(p, &sc->selp);
	splx(s);
	return revents;
}

d_select() is used in 2.2 and previous versions of FreeBSD. Instead of 'events' it take a single int 'rw', which can be FREAD for reads (as in POLLIN above), FWRITE for write (as in POLLOUT above), and 0 for 'exception' - something exceptional happened, like a card being inserted or removed for the pccard driver.

For select, the above code fragment would look like this:


static int
mydevselect(dev_t dev, int rw, struct proc *p)
{
	int ret = 0;
	int s;
	struct my_softc *sc = &my_softc[dev];

	s = splhigh();
	switch (rw) {
	case FWRITE:
		/* Writes are if the transmit queue can take them */
		if (!IF_QFULL(sc->tx_queue))
			ret = 1;
		break;
	case FREAD:
		/* ... while reads are OK if we have any data */
		if (!IF_QEMPTY(sc->rx_queue))
			ret = 1;
		break;
	case 0:
		/* This driver never get any exceptions */
		break;
        }
	if(ret == 0)
		selrecord(p, &sc->selp);
	splx(s);
	return(revents);
}

2.1.2.9. d_mmap()

2.1.2.10. d_strategy()

d_strategy()'s argument list is as follows:


void
d_strategy(struct buf *bp)

d_strategy() is used for devices which use some form of scatter-gather io. It is most common in a block device. This is significantly different than the System V model, where only the block driver performs scatter-gather io. Under BSD, character devices are sometimes requested to perform scatter-gather io via the readv() and writev() system calls.


FreeBSD Device Driver Writer's Guide : Types of drivers. : Character : Entry Points
Previous: Data Structures
Next: Header Files
freebsd-questions@freebsd.org