Various and sundry cleanups to the sample PCI driver:
- Split the first section into sub-sections instead of just paragraphs. - Include a makefile for a kernel module for the sample driver and explain how to use 'make', 'make load', and 'make unload'. - Use 'struct cdev *' rather than 'dev_t'. - Add missing d_version to cdevsw. - Explain how to use si_drv1 in struct cdev to get from a cdev back to the softc. - Add a softc and move the cdev pointer into the softc. Given the cdev a unique name and minor number for each device. - Use better comments in several places. - Actually call device_set_desc() in probe, and use BUS_PROBE_DEFAULT rather than 0. - Add missing call to destroy_dev() in detach. - Use DEFINE_CLASS_0. PR: docs/90830 Submitted by: Marius Nuennerich marius dot nuennerich at gmx dot net
This commit is contained in:
parent
591b393168
commit
d5cc81900b
Notes:
svn2git
2020-12-08 03:00:23 +00:00
svn path=/head/; revision=26788
1 changed files with 102 additions and 52 deletions
|
@ -19,40 +19,48 @@
|
||||||
the unattached devices and see if a newly loaded kld will attach
|
the unattached devices and see if a newly loaded kld will attach
|
||||||
to any of them.</para>
|
to any of them.</para>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Sample Driver Source (<filename>mypci.c</filename>)</title>
|
||||||
|
|
||||||
<programlisting>/*
|
<programlisting>/*
|
||||||
* Simple KLD to play with the PCI functions.
|
* Simple KLD to play with the PCI functions.
|
||||||
*
|
*
|
||||||
* Murray Stokely
|
* Murray Stokely
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
#include <sys/param.h> /* defines used in kernel.h */
|
||||||
|
|
||||||
#include <sys/param.h> /* defines used in kernel.h */
|
|
||||||
#include <sys/module.h>
|
#include <sys/module.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
#include <sys/kernel.h> /* types used in module initialization */
|
#include <sys/kernel.h> /* types used in module initialization */
|
||||||
#include <sys/conf.h> /* cdevsw struct */
|
#include <sys/conf.h> /* cdevsw struct */
|
||||||
#include <sys/uio.h> /* uio struct */
|
#include <sys/uio.h> /* uio struct */
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#include <sys/bus.h> /* structs, prototypes for pci bus stuff */
|
#include <sys/bus.h> /* structs, prototypes for pci bus stuff */
|
||||||
|
|
||||||
#include <machine/bus.h>
|
#include <machine/bus.h>
|
||||||
#include <sys/rman.h>
|
#include <sys/rman.h>
|
||||||
#include <machine/resource.h>
|
#include <machine/resource.h>
|
||||||
|
|
||||||
#include <dev/pci/pcivar.h> /* For get_pci macros! */
|
#include <dev/pci/pcivar.h> /* For pci_get macros! */
|
||||||
#include <dev/pci/pcireg.h>
|
#include <dev/pci/pcireg.h>
|
||||||
|
|
||||||
|
/* The softc holds our per-instance data. */
|
||||||
|
struct mypci_softc {
|
||||||
|
device_t my_dev;
|
||||||
|
struct cdev *my_cdev;
|
||||||
|
};
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
d_open_t mypci_open;
|
static d_open_t mypci_open;
|
||||||
d_close_t mypci_close;
|
static d_close_t mypci_close;
|
||||||
d_read_t mypci_read;
|
static d_read_t mypci_read;
|
||||||
d_write_t mypci_write;
|
static d_write_t mypci_write;
|
||||||
|
|
||||||
/* Character device entry points */
|
/* Character device entry points */
|
||||||
|
|
||||||
static struct cdevsw mypci_cdevsw = {
|
static struct cdevsw mypci_cdevsw = {
|
||||||
|
.d_version = D_VERSION,
|
||||||
.d_open = mypci_open,
|
.d_open = mypci_open,
|
||||||
.d_close = mypci_close,
|
.d_close = mypci_close,
|
||||||
.d_read = mypci_read,
|
.d_read = mypci_read,
|
||||||
|
@ -60,62 +68,73 @@ static struct cdevsw mypci_cdevsw = {
|
||||||
.d_name = "mypci",
|
.d_name = "mypci",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* vars */
|
/*
|
||||||
static dev_t sdev;
|
* In the cdevsw routines, we find our softc by using the si_drv1 member
|
||||||
|
* of struct cdev. We set this variable to point to our softc in our
|
||||||
/* We're more interested in probe/attach than with
|
* attach routine when we create the /dev entry.
|
||||||
open/close/read/write at this point */
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
mypci_open(dev_t dev, int oflags, int devtype, d_thread_t *td)
|
mypci_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct mypci_softc *sc;
|
||||||
|
|
||||||
printf("Opened device \"mypci\" successfully.\n");
|
/* Look up our softc. */
|
||||||
return (err);
|
sc = dev->si_drv1;
|
||||||
|
device_printf(sc->my_dev, "Opened successfully.\n");
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
mypci_close(dev_t dev, int fflag, int devtype, d_thread_t *td)
|
mypci_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct mypci_softc *sc;
|
||||||
|
|
||||||
printf("Closing device \"mypci.\"\n");
|
/* Look up our softc. */
|
||||||
return (err);
|
sc = dev->si_drv1;
|
||||||
|
device_printf(sc->my_dev, "Closed.\n");
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
mypci_read(dev_t dev, struct uio *uio, int ioflag)
|
mypci_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct mypci_softc *sc;
|
||||||
|
|
||||||
printf("mypci read!\n");
|
/* Look up our softc. */
|
||||||
return (err);
|
sc = dev->si_drv1;
|
||||||
|
device_printf(sc->my_dev, "Asked to read %d bytes.\n", uio->uio_resid);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
mypci_write(dev_t dev, struct uio *uio, int ioflag)
|
mypci_write(struct cdev *dev, struct uio *uio, int ioflag)
|
||||||
{
|
{
|
||||||
int err = 0;
|
struct mypci_softc *sc;
|
||||||
|
|
||||||
printf("mypci write!\n");
|
/* Look up our softc. */
|
||||||
|
sc = dev->si_drv1;
|
||||||
|
device_printf(sc->my_dev, "Asked to write %d bytes.\n", uio->uio_resid);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PCI Support Functions */
|
/* PCI Support Functions */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return identification string if this is device is ours.
|
* Compare the device ID of this device against the IDs that this driver
|
||||||
|
* supports. If there is a match, set the description and return success.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
mypci_probe(device_t dev)
|
mypci_probe(device_t dev)
|
||||||
{
|
{
|
||||||
|
|
||||||
device_printf(dev, "MyPCI Probe\nVendor ID : 0x%x\nDevice ID : 0x%x\n",
|
device_printf(dev, "MyPCI Probe\nVendor ID : 0x%x\nDevice ID : 0x%x\n",
|
||||||
pci_get_vendor(dev), pci_get_device(dev));
|
pci_get_vendor(dev), pci_get_device(dev));
|
||||||
|
|
||||||
if (pci_get_vendor(dev) == 0x11c1) {
|
if (pci_get_vendor(dev) == 0x11c1) {
|
||||||
printf("We've got the Winmodem, probe successful!\n");
|
printf("We've got the Winmodem, probe successful!\n");
|
||||||
return (0);
|
device_set_desc(dev, "WinModem");
|
||||||
|
return (BUS_PROBE_DEFAULT);
|
||||||
}
|
}
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
@ -125,10 +144,22 @@ mypci_probe(device_t dev)
|
||||||
static int
|
static int
|
||||||
mypci_attach(device_t dev)
|
mypci_attach(device_t dev)
|
||||||
{
|
{
|
||||||
|
struct mypci_softc *sc;
|
||||||
|
|
||||||
printf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev));
|
printf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev));
|
||||||
sdev = make_dev(<literal>&</literal>mypci_cdevsw, 0, UID_ROOT,
|
|
||||||
GID_WHEEL, 0600, "mypci");
|
/* Look up our softc and initialize its fields. */
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
sc->my_dev = dev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a /dev entry for this device. The kernel will assign us
|
||||||
|
* a major number automatically. We use the unit number of this
|
||||||
|
* device as the minor number and name the character device
|
||||||
|
* "mypci<unit>".
|
||||||
|
*/
|
||||||
|
sc->my_cdev = make_dev(<literal>&</literal>mypci_cdevsw, device_get_unit(dev),
|
||||||
|
UID_ROOT, GID_WHEEL, 0600, "mypci%u", device_get_unit(dev));
|
||||||
printf("Mypci device loaded.\n");
|
printf("Mypci device loaded.\n");
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +169,11 @@ mypci_attach(device_t dev)
|
||||||
static int
|
static int
|
||||||
mypci_detach(device_t dev)
|
mypci_detach(device_t dev)
|
||||||
{
|
{
|
||||||
|
struct mypci_softc *sc;
|
||||||
|
|
||||||
|
/* Teardown the state in our softc created in our attach routine. */
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
destroy_dev(sc->my_cdev);
|
||||||
printf("Mypci detach!\n");
|
printf("Mypci detach!\n");
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -167,7 +202,6 @@ mypci_suspend(device_t dev)
|
||||||
/*
|
/*
|
||||||
* Device resume routine.
|
* Device resume routine.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mypci_resume(device_t dev)
|
mypci_resume(device_t dev)
|
||||||
{
|
{
|
||||||
|
@ -188,27 +222,43 @@ static device_method_t mypci_methods[] = {
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static driver_t mypci_driver = {
|
|
||||||
"mypci",
|
|
||||||
mypci_methods,
|
|
||||||
0,
|
|
||||||
/* sizeof(struct mypci_softc), */
|
|
||||||
};
|
|
||||||
|
|
||||||
static devclass_t mypci_devclass;
|
static devclass_t mypci_devclass;
|
||||||
|
|
||||||
|
DEFINE_CLASS_0(mypci, mypci_driver, mypci_methods, sizeof(struct mypci_softc));
|
||||||
DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0);</programlisting>
|
DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0);</programlisting>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<para>Additional Resources
|
<sect2>
|
||||||
<itemizedlist>
|
<title><filename>Makefile</filename> for Sample Driver</title>
|
||||||
<listitem><simpara><ulink url="http://www.pcisig.org/">PCI
|
|
||||||
Special Interest Group</ulink></simpara></listitem>
|
|
||||||
|
|
||||||
<listitem><simpara>PCI System Architecture, Fourth Edition by
|
<programlisting># Makefile for mypci driver
|
||||||
Tom Shanley, et al.</simpara></listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
KMOD= mypci
|
||||||
</para>
|
SRCS= mypci.c
|
||||||
|
SRCS+= device_if.h bus_if.h pci_if.h
|
||||||
|
|
||||||
|
.include <bsd.kmod.mk></programlisting>
|
||||||
|
|
||||||
|
<para>If you place the above source file and
|
||||||
|
<filename>Makefile</filename> into a directory, you may run
|
||||||
|
<command>make</command> to compile the sample driver.
|
||||||
|
Additionally, you may run <command>make load</command> to load
|
||||||
|
the driver into the currently running kernel and <command>make
|
||||||
|
unload</command> to unload the driver after it is
|
||||||
|
loaded.</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Additional Resources</title>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><simpara><ulink url="http://www.pcisig.org/">PCI
|
||||||
|
Special Interest Group</ulink></simpara></listitem>
|
||||||
|
|
||||||
|
<listitem><simpara>PCI System Architecture, Fourth Edition by
|
||||||
|
Tom Shanley, et al.</simpara></listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="pci-bus">
|
<sect1 id="pci-bus">
|
||||||
|
|
Loading…
Reference in a new issue