Entry Point | Description |
---|---|
_init(9E) | Initializes the loadable-driver module. |
_info(9E) | Returns the loadable-driver module information. |
_fini(9E) | Prepares a loadable-driver module for unloading. |
identify(9E) | Obsolete and no longer required. Set to nulldev(9F) |
probe(9E) | Determines if a device is present. |
attach(9E) | Performs device-specific initialization and/or power management resume functionality. |
detach(9E) | Removes device-specific state and/or power management suspend functionality. |
getinfo(9E) | Gets device driver information. |
power(9E) | Sets the power level of a device component. |
open(9E) | Gains access to a device. |
close(9E) | Relinquishes access to a device. |
read(9E) | Reads data from device. |
aread(9E) | Reads data asynchronously from device. |
write(9E) | Writes data to device. |
awrite(9E) | Writes data asynchronously to device. |
ioctl(9E) | Performs arbitrary operations. |
prop_op(9E) | Manages arbitrary driver properties. |
devmap(9E) | Validate and translate virtual mapping for a memory mapped device. |
Entry Point | Description |
---|---|
mmap(9E) | Checks virtual mapping for a memory-mapped device. For new drivers, use the devmap(9E) entry point. |
segmap(9E) | Maps device memory into user space. |
chpoll(9E) | Polls device for events. |
static int xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd) { switch (cmd) { case DDI_ATTACH: allocate a state structure and initialize it. map the device's registers. add the device driver's interrupt handler(s). initialize any mutexes and condition variables. create power manageable components. /* * Create the device's minor node. Note that the node_type * argument is set to DDI_NT_TAPE.
*/ if (ddi_create_minor_node(dip, "minor_name", S_IFCHR, minor_number, DDI_NT_TAPE, 0) == DDI_FAILURE) { free resources allocated so far. /* Remove any previously allocated minor nodes */ ddi_remove_minor_node(dip, NULL); return (DDI_FAILURE); } ... return (DDI_SUCCESS); case DDI_PM_RESUME:
case DDI_RESUME:
default: return (DDI_FAILURE); } }
int xxopen(dev_t *devp, int flag, int otyp, cred_t *credp);
*devp = makedevice(getmajor(*devp), new_minor);
static int xxopen(dev_t *devp, int flag, int otyp, cred_t *credp) { minor_t instance; if (getminor(*devp) is invalid) return (EINVAL); instance = getminor(*devp); /* one-to-one example mapping */ /* Is the instance attached? */ if (ddi_get_soft_state(statep, instance) == NULL) return (ENXIO); /* verify that otyp is appropriate */ if (otyp != OTYP_CHR) return (EINVAL);
if ((flag & FWRITE) && drv_priv(credp) == EPERM) return (EPERM); return (0); }
int xxclose(dev_t dev, int flag, int otyp, cred_t *credp);
char buffer[] = "python"; count = write(fd, buffer, strlen(buffer) + 1);
iovec_t *uio_iov; /* base address of the iovec */ /* buffer description array */ int uio_iovcnt; /* the number of iovec structures */ off_t uio_offset; /* offset into device where data */ /* is transferred from or to */ offset_t uio_loffset /* 64-bit offset into file where */ /* data is transferred from or to */ int uio_resid; /* amount (in bytes) not */ /* transferred on completion */
caddr_t iov_base; /* address of buffer */ int iov_len; /* amount to transfer */
static int xxread(dev_t dev, struct uio *uio_p, cred_t *cred_p) { offset_t off; ... off = uio_p->uio_loffset; /* save the offset */ /* do the transfer */ uio_p->uio_loffset = off; /* restore it */ }
uiomove( )
caddr_t ram; /* base address of ramdisk */ int ramsize; /* size of the ramdisk */
static int rd_read(dev_t dev, struct uio *uiop, cred_t *credp) { rd_devstate_t *rsp; rsp = ddi_get_soft_state(rd_statep, getminor(dev)); if (rsp == NULL) return (ENXIO); if (uiop->uio_offset >= rsp->ramsize) return (EINVAL); /* * uiomove takes the offset into the kernel buffer, * the data transfer count (minimum of the requested and * the remaining data), the UIO_READ flag, and a pointer
* to the uio structure. */ return (uiomove(rsp->ram + uiop->uio_offset, min(uiop->uio_resid, rsp->ramsize - uiop->uio_offset), UIO_READ, uiop)); }
static int xxwrite(dev_t dev, struct uio *uiop, cred_t *credp) { int value; struct xxstate *xsp; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO);
pm_busy_component(xsp->dip, 0); if (xsp->pm_suspended) ddi_dev_is_needed(xsp->dip, normal power); while (uiop->uio_resid > 0) { /* * do the programmed I/O access */ value = uwritec(uiop); if (value == -1) return (EFAULT); ddi_put8(xsp->data_access_handle, &xsp->regp->data, (uint8_t)value); ddi_put8(xsp->data_access_handle, &xsp->regp->csr, START_TRANSFER); /* * this device requires a ten microsecond delay * between writes
*/ drv_usecwait(10); } pm_idle_component(xsp->dip, 0); return (0); }
int physio(int (*strat)(struct buf *), struct buf *bp, dev_t dev, int rw, void (*mincnt)(struct buf *), struct uio *uio);
static int xxread(dev_t dev, struct uio *uiop, cred_t *credp) { struct xxstate *xsp; int ret; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO); ret = physio(xxstrategy, NULL, dev, B_READ, xxminphys, uiop); pm_idle_component(xsp->dip, 0); return (ret); } static int xxwrite(dev_t dev, struct uio *uiop, cred_t *credp) { struct xxstate *xsp; int ret;
xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO); ret = physio(xxstrategy, NULL, dev, B_WRITE, xxminphys, uiop); pm_idle_component(xsp->dip, 0); return (ret); }
int aphysio(int (*strat)(struct buf *), int (*cancel)(struct buf *), dev_t dev, int rw, void (*mincnt)(struct buf *), struct aio_req *aio_reqp);
static int xxaread(dev_t dev, struct aio_req *aiop, cred_t *cred_p) { struct xxstate *xsp; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO); return (aphysio(xxstrategy, anocancel, dev, B_READ, xxminphys, aiop)); } static int xxawrite(dev_t dev, struct aio_req *aiop, cred_t *cred_p) { struct xxstate *xsp; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO); return (aphysio(xxstrategy, anocancel, dev, B_WRITE, xxminphys,aiop)); }
#define XXMINVAL (512 << 10)/* 512 KB */ static void xxminphys(struct buf *bp) { if (bp->b_bcount > XXMINVAL) bp->b_bcount = XXMINVAL minphys(bp); }
static int xxstrategy(struct buf *bp) {
minor_t instance; struct xxstate *xsp; ddi_dma_cookie_t cookie; instance = getminor(bp->b_edev); xsp = ddi_get_soft_state(statep, instance); ...
set up DMA resources with ddi_dma_alloc_handle(9F) and ddi_dma_buf_bind_handle(9F). xsp->bp = bp; /* remember bp */
return (0); }
static u_int xxintr(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg;
return (DDI_INTR_UNCLAIMED); } if (error) {
}
(ddi_dma_unbind_handle(9F) and ddi_dma_free_handle(9F)) /* notify threads that the transfer is complete */ biodone(xsp->bp);
return (DDI_INTR_CLAIMED); }
int xxsegmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp);
static int xxsegmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp)
{ if (prot & PROT_READ) return (EINVAL); return (devmap_setup(dev, (offset_t)off, as, addrp, (size_t)len, prot, maxprot, flags, cred)); }
int xxdevmap(dev_t dev, devmap_cookie_t handle, offset_t off, size_t len, size_t *maplen, uint_t model);
struct pollhead pollhead; /* for chpoll(9E)/pollwakeup(9F) */
int xxchpoll(dev_t dev, short events, int anyyet, short *reventsp, struct pollhead **phpp);
if (events are satisfied now) {
*reventsp = mask of satisfied events;
} else { *reventsp = 0; if (!anyyet) *phpp = & local pollhead structure; } return (0);
static int xxchpoll(dev_t dev, short events, int anyyet, short *reventsp, struct pollhead **phpp) { uint8_t status; short revent; struct xxstate *xsp; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO); revent = 0; /* * Valid events are: * POLLIN | POLLOUT | POLLPRI | POLLHUP | POLLERR * This example checks only for POLLIN and POLLERR. */ status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr); if ((events & POLLIN) && data available to read) { revent |= POLLIN; } if ((events & POLLERR) && (status & DEVICE_ERROR)) { revent |= POLLERR; } /* if nothing has occurred */ if (revent == 0) { if (!anyyet) { *phpp = &xsp->pollhead; } } *reventsp = revent; return (0); }
static u_int xxintr(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg; uint8_t status;
... status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr); if (status & DEVICE_ERROR) { pollwakeup(&xsp->pollhead, POLLERR); } if (just completed a read) { pollwakeup(&xsp->pollhead, POLLIN); } ... return (DDI_INTR_CLAIMED); }
int xxioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp);
#define XXIOC ('x' << 8) /* 'x' is a character representing */ /* device xx */ #define XX_GET_STATUS (XXIOC | 1) /* get status register */ #define XX_SET_CMD (XXIOC | 2) /* send command */
static int xxioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) { uint8_t csr; struct xxstate *xsp; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) { return (ENXIO); } switch (cmd) { case XX_GET_STATUS: csr = ddi_get8(xsp->data_access_handle, &xsp->regp->csr); if (ddi_copyout(&csr, (void *)arg, sizeof (uint8_t), mode) != 0) { return (EFAULT); }
break; case XX_SET_CMD: if (ddi_copyin((void *)arg, &csr, sizeof (uint8_t), mode) != 0) { return (EFAULT); } ddi_put8(xsp->data_access_handle, &xsp->regp->csr, csr); break; default: /* generic "ioctl unknown" error */ return (ENOTTY); } return (0); }
#include <sys/types.h> #include "xxio.h"/* contains device's ioctl cmds and arguments */ int main(void) { uint8_t status; ... /* * read the device status */ if (ioctl(fd, XX_GET_STATUS, &status) == -1) { error handling
} printf("device status %x\n", status); exit(0); }
struct args32 { uint32_t addr;/* 32-bit address in LP64 */ int len; }
struct args { caddr_t addr;/* 64-bit address in LP64 */ int len; } static int xxioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) { struct xxstate *xsp; struct args a; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) { return (ENXIO); } switch (cmd) { case XX_COPYIN_DATA: switch(ddi_model_convert_from(mode & FMODELS)) { case DDI_MODEL_ILP32: { struct args32 a32; /* copy 32-bit args data shape */ if (ddi_copyin((void *)arg, &a32, sizeof (struct args32), mode) != 0) { return (EFAULT); } /* convert 32-bit to 64-bit args data shape */ a.addr = a32.addr; a.len = a32.len; break; } case DDI_MODEL_NONE: /* application and driver have same data model. */ if (ddi_copyin((void *)arg, &a, sizeof (struct args), mode) != 0) { return (EFAULT); } } /* continue using data shape in native driver data model. */ break; case XX_COPYOUT_DATA:
/* copyout handling */ break; default: /* generic "ioctl unknown" error */ return (ENOTTY); } return (0); }
Copyright 1997 Sun Microsystems, Inc. All rights reserved.
Comments on: Writing Device Drivers