Skip Navigation Links | |
Exit Print View | |
Device Driver Tutorial Oracle Solaris 11.1 Information Library |
1. Introduction to Device Drivers
Overview of the Template Driver Example
Writing the Loadable Module Configuration Entry Points
Declaring the Loadable Module Configuration Entry Points
Defining the Module Initialization Entry Point
Defining the Module Information Entry Point
Defining the Module Unload Entry Point
Including Loadable Module Configuration Header Files
Writing the Autoconfiguration Entry Points
Declaring the Autoconfiguration Entry Points
Defining the Device Attach Entry Point
Defining the Device Detach Entry Point
Defining the Get Driver Information Entry Point
Defining the Report Driver Property Information Entry Point
Including Autoconfiguration Header Files
Writing the User Context Entry Points
Declaring the User Context Entry Points
Defining the Open Device Entry Point
Defining the Close Device Entry Point
Defining the Read Device Entry Point
Defining the Write Device Entry Point
Including User Context Header Files
Writing the Driver Data Structures
Defining the Character and Block Operations Structure
Defining the Device Operations Structure
Defining the Module Linkage Structures
Including Data Structures Header Files
Writing the Device Configuration File
Building and Installing the Template Driver
Reading and Writing the Device
3. Reading and Writing Data in Kernel Memory
The following code is the complete source for the dummy driver described in this chapter:
/* * Minimalist pseudo-device. * Writes a message whenever a routine is entered. * * Build the driver: * cc -D_KERNEL -c dummy.c * ld -r -o dummy dummy.o * Copy the driver and the configuration file to /usr/kernel/drv: * cp dummy.conf /usr/kernel/drv * cp dummy /tmp * ln -s /tmp/dummy /usr/kernel/drv/dummy * Add the driver: * add_drv dummy * Test (1) read from driver (2) write to driver: * cat /devices/pseudo/dummy@* * echo hello > `ls /devices/pseudo/dummy@*` * Verify the tests in another window: * tail -f /var/adm/messages * Remove the driver: * rem_drv dummy */ #include <sys/devops.h> /* used by dev_ops */ #include <sys/conf.h> /* used by dev_ops and cb_ops */ #include <sys/modctl.h> /* used by modlinkage, modldrv, _init, _info, */ /* and _fini */ #include <sys/types.h> /* used by open, close, read, write, prop_op, */ /* and ddi_prop_op */ #include <sys/file.h> /* used by open, close */ #include <sys/errno.h> /* used by open, close, read, write */ #include <sys/open.h> /* used by open, close, read, write */ #include <sys/cred.h> /* used by open, close, read */ #include <sys/uio.h> /* used by read */ #include <sys/stat.h> /* defines S_IFCHR used by ddi_create_minor_node */ #include <sys/cmn_err.h> /* used by all entry points for this driver */ #include <sys/ddi.h> /* used by all entry points for this driver */ /* also used by cb_ops, ddi_get_instance, and */ /* ddi_prop_op */ #include <sys/sunddi.h> /* used by all entry points for this driver */ /* also used by cb_ops, ddi_create_minor_node, */ /* ddi_get_instance, and ddi_prop_op */ static int dummy_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); static int dummy_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); static int dummy_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp); static int dummy_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags, char *name, caddr_t valuep, int *lengthp); static int dummy_open(dev_t *devp, int flag, int otyp, cred_t *cred); static int dummy_close(dev_t dev, int flag, int otyp, cred_t *cred); static int dummy_read(dev_t dev, struct uio *uiop, cred_t *credp); static int dummy_write(dev_t dev, struct uio *uiop, cred_t *credp); /* cb_ops structure */ static struct cb_ops dummy_cb_ops = { dummy_open, dummy_close, nodev, /* no strategy - nodev returns ENXIO */ nodev, /* no print */ nodev, /* no dump */ dummy_read, dummy_write, nodev, /* no ioctl */ nodev, /* no devmap */ nodev, /* no mmap */ nodev, /* no segmap */ nochpoll, /* returns ENXIO for non-pollable devices */ dummy_prop_op, NULL, /* streamtab struct; if not NULL, all above */ /* fields are ignored */ D_NEW | D_MP, /* compatibility flags: see conf.h */ CB_REV, /* cb_ops revision number */ nodev, /* no aread */ nodev /* no awrite */ }; /* dev_ops structure */ static struct dev_ops dummy_dev_ops = { DEVO_REV, 0, /* reference count */ dummy_getinfo, /* no getinfo(9E) */ nulldev, /* no identify(9E) - nulldev returns 0 */ nulldev, /* no probe(9E) */ dummy_attach, dummy_detach, nodev, /* no reset - nodev returns ENXIO */ &dummy_cb_ops, (struct bus_ops *)NULL, nodev, /* no power(9E) */ ddi_quiesce_not_needed, /* no quiesce(9E) */ }; /* modldrv structure */ static struct modldrv md = { &mod_driverops, /* Type of module. This is a driver. */ "dummy driver", /* Name of the module. */ &dummy_dev_ops }; /* modlinkage structure */ static struct modlinkage ml = { MODREV_1, &md, NULL }; /* dev_info structure */ dev_info_t *dummy_dip; /* keep track of one instance */ /* Loadable module configuration entry points */ int _init(void) { cmn_err(CE_NOTE, "Inside _init"); return(mod_install(&ml)); } int _info(struct modinfo *modinfop) { cmn_err(CE_NOTE, "Inside _info"); return(mod_info(&ml, modinfop)); } int _fini(void) { cmn_err(CE_NOTE, "Inside _fini"); return(mod_remove(&ml)); } /* Device configuration entry points */ static int dummy_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { cmn_err(CE_NOTE, "Inside dummy_attach"); switch(cmd) { case DDI_ATTACH: dummy_dip = dip; if (ddi_create_minor_node(dip, "0", S_IFCHR, ddi_get_instance(dip), DDI_PSEUDO,0) != DDI_SUCCESS) { cmn_err(CE_NOTE, "%s%d: attach: could not add character node.", "dummy", 0); return(DDI_FAILURE); } else return DDI_SUCCESS; default: return DDI_FAILURE; } } static int dummy_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { cmn_err(CE_NOTE, "Inside dummy_detach"); switch(cmd) { case DDI_DETACH: dummy_dip = 0; ddi_remove_minor_node(dip, NULL); return DDI_SUCCESS; default: return DDI_FAILURE; } } static int dummy_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) { cmn_err(CE_NOTE, "Inside dummy_getinfo"); switch(cmd) { case DDI_INFO_DEVT2DEVINFO: *resultp = dummy_dip; return DDI_SUCCESS; case DDI_INFO_DEVT2INSTANCE: *resultp = 0; return DDI_SUCCESS; default: return DDI_FAILURE; } } /* Main entry points */ static int dummy_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags, char *name, caddr_t valuep, int *lengthp) { cmn_err(CE_NOTE, "Inside dummy_prop_op"); return(ddi_prop_op(dev,dip,prop_op,flags,name,valuep,lengthp)); } static int dummy_open(dev_t *devp, int flag, int otyp, cred_t *cred) { cmn_err(CE_NOTE, "Inside dummy_open"); return DDI_SUCCESS; } static int dummy_close(dev_t dev, int flag, int otyp, cred_t *cred) { cmn_err(CE_NOTE, "Inside dummy_close"); return DDI_SUCCESS; } static int dummy_read(dev_t dev, struct uio *uiop, cred_t *credp) { cmn_err(CE_NOTE, "Inside dummy_read"); return DDI_SUCCESS; } static int dummy_write(dev_t dev, struct uio *uiop, cred_t *credp) { cmn_err(CE_NOTE, "Inside dummy_write"); return DDI_SUCCESS; }