Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
PROTO(4)		 BSD Kernel Interfaces Manual		      PROTO(4)

     proto -- Generic prototyping and diagnostics driver

     To	compile	this driver into the kernel, place the following line in your
     kernel configuration file:

	   device proto

     Alternatively, to load the	driver as a module at boot time, place the
     following line in loader.conf(5):


     To	have the driver	attach to a device instead of its regular driver, men-
     tion it in	the list of devices assigned to	the following loader variable:


     The proto device driver attaches to PCI or	ISA devices when no other de-
     vice drivers are present for those	devices	and it creates device special
     files for all resources associated	with the device.  The driver itself
     has no knowledge of the device it attaches	to.  Programs can open these
     device special files and perform register-level reads and writes.	As
     such, the proto device driver is nothing but a conduit or gateway between
     user space	programs and the hardware device.

     Examples for why this is useful include hardware diagnostics and proto-
     typing.  In both these use	cases, it is far more convenient to develop
     and run the logic in user space.  Especially hardware diagnostics re-
     quires a somewhat user-friendly interface and adequate reporting.	Nei-
     ther is done easily as kernel code.

   I/O port resources
     Device special files created for I/O port resources allow lseek(2),
     read(2), write(2) and ioctl(2) operations to be performed on them.	 The
     read(2) and write(2) system calls are used	to perform input and output
     (resp.) on	the port.  The amount of data that can be read or written at
     any single	time is	either 1, 2 or 4 bytes.	 While the proto driver	does
     not prevent reading or writing 8 bytes at a time for some architectures,
     it	should not be assumed that such	actually produces correct results.
     The lseek(2) system call is used to select	the port number, relative to
     the I/O port region being represented by the device special file.	If,
     for example, the device special file corresponds to an I/O	port region
     from 0x3f8	to 0x3ff inclusive, then an offset of 4	given to lseek with a
     whence value of SEEK_SET will target port 0x3fc on	the next read or write
     operation.	 The ioctl(2) system call can be used for the PROTO_IOC_REGION
     request.  This ioctl request returns the extend of	the resource covered
     by	this device special file.  The extend is returned in the following

     struct proto_ioc_region {
	     unsigned long   address;
	     unsigned long   size;

   Memory mapped I/O resources
     The device	special	files created for memory mapped	I/O resources behave
     in	the same way as	those created for I/O port resources.  Additionally,
     device special files for memory mapped I/O	resources allow	the memory to
     be	mapped into the	process' address space using mmap(2).  Reads and
     writes to the memory address returned by mmap(2) go directly to the hard-
     ware.  As such the	use of read(2) and write(2) can	be avoided, reducing
     the access	overhead significantly.	 Alignment and access width con-
     straints put forth	by the underlying device apply.	 Also, make sure the
     compiler does not optimize	memory accesses	away or	has them coalesced
     into bigger accesses.

   DMA pseudo resource
     A device special file named busdma	is created for the purpose of doing
     DMA.  It only supports ioctl(2) and only for the PROTO_IOC_BUSDMA re-
     quest.  This device special file does not support read(2) nor write(2).
     The PROTO_IOC_BUSDMA request has an argument that is both in and out and
     is	defined	as follows:

     struct proto_ioc_busdma {
	     unsigned int    request;
	     unsigned long   key;
	     union {
		     struct {
			     unsigned long   align;
			     unsigned long   bndry;
			     unsigned long   maxaddr;
			     unsigned long   maxsz;
			     unsigned long   maxsegsz;
			     unsigned int    nsegs;
			     unsigned int    datarate;
			     unsigned int    flags;
		     } tag;
		     struct {
			     unsigned long   tag;
			     unsigned int    flags;
			     unsigned long   virt_addr;
			     unsigned long   virt_size;
			     unsigned int    phys_nsegs;
			     unsigned long   phys_addr;
			     unsigned long   bus_addr;
			     unsigned int    bus_nsegs;
		     } md;
		     struct {
			     unsigned int    op;
			     unsigned long   base;
			     unsigned long   size;
		     } sync;
	     } u;
	     unsigned long   result;
     The request field is used to specify which	DMA operation is to be per-
     formed.  The key field is used to specify which object the	operation ap-
     plies to.	An object is either a tag or a memory descriptor (md).	The
     following DMA operations are defined:

	   Create a root tag.  The result field	is set on output with the key
	   of the DMA tag.  The	tag is created with the	constraints given by
	   the tag sub-structure.  These constraints correspond	roughly	to
	   those that can be given to the bus_dma_tag_create(9)	function.

	   Create a derived tag.  The key field	is used	to identify the	parent
	   tag from which to derive the	new tag.  The key of the derived tag
	   is returned in the result field.  The derived tag combines the con-
	   straints of the parent tag with those given by the tag sub-struc-
	   ture.  The combined constraints are written back to the tag sub-
	   structure on	return.

	   Destroy a root or derived tag previously created.  The key field
	   specifies the tag to	destroy.  A tag	can only be destroyed when not
	   referenced anymore.	This means that	derived	tags that have this
	   tag as a parent and memory descriptors created from this tag	must
	   be destroyed	first.

	   Allocate memory that	satisfies the constraints put forth by the tag
	   given in the	tag field of the md sub-structure.  The	key of the
	   memory descriptor for this memory is	returned in the	result field.
	   The md sub-structure	is filled on return with details of the	allo-
	   cation.  The	kernel virtual address and the size of the allocated
	   memory are returned in the virt_addr	and virt_size fields.  The
	   number of contigous physical	memory segments	and the	address	of the
	   first segment are returned in the phys_nsegs	and phys_addr fields.
	   Allocated memory is automatically loaded and	thus mapped into bus
	   space.  The number of bus segments and the address of the first
	   segment are returned	in the bus_nsegs and bus_addr fields.  The be-
	   haviour of this operation banks heavily on how bus_dmamem_alloc(9)
	   is implemented, which means that memory is currently	always allo-
	   cated as a single contigous region of physical memory.  In practice
	   this	also tends to give a single contigous region in	bus space.
	   This	may change over	time.

	   Free	previously allocated memory and	destroy	the memory desciptor.
	   The proto driver is not in a	position to track whether the memory
	   has been mapped in the process' address space, so the application
	   is responsible for unmapping	the memory before it is	freed.	The
	   proto driver	also cannot protect against the	hardware writing to or
	   reading from	the memory, even after it has been freed.  When	the
	   memory is reused for	other purposes it can be corrupted or cause
	   the hardware	to behave in unpredictable ways	when DMA has not
	   stopped completely before freeing.

	   Create an empty memory descriptor with the tag specified in the tag
	   field of the	md sub-structure.  The key of the memory descriptor is
	   returned in the result field.

	   Destroy the previously created memory descriptor specified by the
	   key field.  When the	memory descriptor is still loaded, it is un-
	   loaded first.

	   Load	a contigous region of memory in	the memory descriptor speci-
	   fied	by the key field.  The size and	address	in the process'	vir-
	   tual	address	space are specified by the virt_size and virt_addr
	   fields.  On return, the md sub-structure contains the result	of the
	   operation.  The number of physical segments and the address of the
	   first segment is returned in	the phys_nsegs and phys_addr fields.
	   The number of bus space segments and	the address of the first seg-
	   ment	in bus space is	returned in the	bus_nsegs and bus_addr fields.

	   Unload the memory descriptor	specified by the key field.

	   Guarantee that all hardware components have a coherent view of the
	   memory tracked by the memory	descriptor, specified by the key
	   field.  A sub-section of the	memory can be targeted by specifying
	   the relative	offset and size	of the memory to make coherent.	 The
	   offset and size are given by	the base and size fields of the	sync
	   sub-structure.  The op field	holds the sync operation to be per-
	   formed.  This is similar to the bus_dmamap_sync(9) function.

   PCI configuration space
     Access to PCI configuration space is possible through the pcicfg device
     special file.  The	device special file supports lseek(2), read(2) and
     write(2).	Usage is the asme as for I/O port resources.

     All device	special	files corresponding to a PCI device are	located	under
     /dev/proto/pci_d_:_b_:_s_:_f_ with	pci_d_:_b_:_s_:_f_ representing	the
     location of the PCI device	in the PCI hierarchy.  A PCI location in-

	   <d>	   The PCI domain number
	   <b>	   The PCI bus number
	   <s>	   The PCI slot	or device number
	   <f>	   The PCI function number

     Every PCI device has a device special file	called pcicfg.	This device
     special file gives	access to the PCI configuration	space.	A device spe-
     cial file called busdma is	also created.  This device special file	pro-
     vides the interfaces needed for doing DMA.	 For each valid	base address
     register (BAR), a device special file is created that contains the	BAR
     offset and	the resource type.  A resource type can	be either io or	mem
     representing I/O port or memory mapped I/O	space (resp.)

     ISA devices do not	have a location.  Instead, they	are identified by the
     first I/O port address or first memory mapped I/O address.	 Consequently,
     all device	special	files corresponding to an ISA device are located under
     /dev/proto/isa:_addr_ with	addr the address in hexadecimal	notation.  For
     each I/O port or memory mapped I/O	address, a device special file is cre-
     ated that contains	the resource identification used by the	kernel and the
     resource type.  The resource type can be either io	or mem representing
     I/O port or memory	mapped I/O space (resp.)  When the device has a	DMA
     channel assigned to it, a device special file with	the name busdma	is
     created as	well.  This device special file	provides the interfaces	needed
     for doing DMA.

     If	the ISA	device is not a	Plug-and-Play device nor present in the	ACPI
     device tree, it must have the appropriate hints so	that the kernel	can
     reserve the resources for it.

     A single function PCI device in domain 0, on bus 1, in slot 2 and having
     a single memory mapped I/O	region will have the following device special


     A legacy floppy controller	will have the following	device files:


     ioctl(2), lseek(2), mmap(2), read(2), write(2), bus_dma_tag_create(9),
     bus_dmamap_sync(9), bus_dmamem_alloc(9)

     The proto device driver and this manual page were written by Marcel
     Moolenaar <>.

     Because programs have direct access to the	hardware, the proto driver is
     inherently	insecure.  It is not advisable to use this driver on a produc-
     tion machine.

     The proto driver does not fully support memory descriptors	that need mul-
     tiple physical memory segments or multiple	bus space segments.  At	the
     very least, an operation is needed	on the DMA pseudo resource for the ap-
     plication to obtain all segments.

     The proto driver does not yet support interrupts.	Since interrupts can-
     not be handled by the driver itself, they must be converted into signals
     and delivered to the program that has registered for interrupts.  A sat-
     isfactory mechanism for keeping the interrupt masked during the signal
     handling is still being worked out.

     DMA support for devices other than	busmaster devices is not present yet.
     The details of how	a program is to	interact with the DMA controller still
     need to be	fleshed	out.

BSD				August 7, 2015				   BSD


Want to link to this manual page? Use this URL:

home | help