Add proto(4): A driver for prototyping and diagnostics.
It exposes I/O resources to user space, so that programs can peek and poke at the hardware. It does not itself have knowledge about the hardware device it attaches to. Sponsored by: Juniper Networks, Inc.
This commit is contained in:
parent
dea1e22600
commit
67fb10f30c
@ -378,6 +378,7 @@ MAN= aac.4 \
|
||||
ppc.4 \
|
||||
ppi.4 \
|
||||
procdesc.4 \
|
||||
proto.4 \
|
||||
psm.4 \
|
||||
pst.4 \
|
||||
pt.4 \
|
||||
|
121
share/man/man4/proto.4
Normal file
121
share/man/man4/proto.4
Normal file
@ -0,0 +1,121 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2014 Marcel Moolenaar
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\"
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 21, 2014
|
||||
.Dt PROTO 4
|
||||
.Os
|
||||
.\"
|
||||
.Sh NAME
|
||||
.Nm proto
|
||||
.Nd Driver for prototyping and H/W diagnostics
|
||||
.\"
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device proto"
|
||||
.\"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
device driver attaches to PCI devices when no other device drivers are
|
||||
present and 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 peform register-level
|
||||
reads and writes.
|
||||
As such, the
|
||||
.Nm
|
||||
device driver is nothing but a conduit or gateway between user space
|
||||
programs and the hardware device.
|
||||
.Pp
|
||||
Examples for why this is useful include hardware diagnostics and prototyping.
|
||||
In both these use cases, it's far more convenient to develop and run the
|
||||
logic in user space.
|
||||
Especially hardware diagnostics requires a somewhat user-friendly interface
|
||||
and adequate reporting.
|
||||
Neither is done easily as kernel code.
|
||||
.\"
|
||||
.Sh FILES
|
||||
All device special files corresponding to a PCI device are located under
|
||||
.Pa /dev/proto/pci<d>:<b>:<s>:<f>
|
||||
with
|
||||
.Pa pci<d>:<b>:<s>:<f>
|
||||
representing the location of the PCI device in the PCI hierarchy.
|
||||
A location includes:
|
||||
.Bl -tag -width XXXXXX -compact
|
||||
.It <d>
|
||||
The PCI domain number
|
||||
.It <b>
|
||||
The PCI bus number
|
||||
.It <s>
|
||||
The PCI slot or device number
|
||||
.It <f>
|
||||
The PCI function number
|
||||
.El
|
||||
.Pp
|
||||
Every PCI device has a device special file called
|
||||
.Pa pcicfg .
|
||||
This device special file gives access to the PCI configuration space.
|
||||
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
|
||||
.Pa io
|
||||
or
|
||||
.Pa mem
|
||||
representing I/O port or memory mapped I/O space (resp.)
|
||||
.\"
|
||||
.Sh EXAMPLES
|
||||
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 files:
|
||||
.Bl -tag -compact
|
||||
.It Pa /dev/proto/pci0:1:2:0/10.mem
|
||||
.It Pa /dev/proto/pci0:1:2:0/pcicfg
|
||||
.El
|
||||
.\"
|
||||
.Sh SECURITY CONSIDERATIONS
|
||||
Because programs have direct access to the hardware, the
|
||||
.Nm
|
||||
driver is inherently insecure.
|
||||
It is not advisable to use this driver on a production machine.
|
||||
.\"
|
||||
.Sh MISSING FUNCTIONALITY
|
||||
The
|
||||
.Nm
|
||||
driver does not yet support interrupts.
|
||||
Since interrupts cannot be handled by the driver itself, they must be converted
|
||||
into signals and delivered to the program that has registered for interrupts.
|
||||
.Pp
|
||||
In order to test the transmission or reception of data, some means of doing
|
||||
direct memory access (DMA) by the device must be possible. This too much be
|
||||
under the control of the program. The details of how a program can setup and
|
||||
initiate DMA still need to be fleshed out.
|
||||
.Pp
|
||||
Support for non-PCI devices has not been implemented yet.
|
||||
.\"
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
device driver and this manual page were written by
|
||||
.An Marcel Moolenaar Aq marcel@xcllnt.net .
|
63
sys/dev/proto/proto.h
Normal file
63
sys/dev/proto/proto.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DEV_PROTO_H_
|
||||
#define _DEV_PROTO_H_
|
||||
|
||||
#define PROTO_RES_MAX 16
|
||||
|
||||
#define PROTO_RES_UNUSED 0
|
||||
#define PROTO_RES_PCICFG 10
|
||||
|
||||
struct proto_res {
|
||||
int r_type;
|
||||
int r_rid;
|
||||
struct resource *r_res;
|
||||
u_long r_size;
|
||||
union {
|
||||
void *cookie;
|
||||
struct cdev *cdev;
|
||||
} r_u;
|
||||
uintptr_t r_opened;
|
||||
};
|
||||
|
||||
struct proto_softc {
|
||||
device_t sc_dev;
|
||||
struct proto_res sc_res[PROTO_RES_MAX];
|
||||
int sc_rescnt;
|
||||
};
|
||||
|
||||
extern devclass_t proto_devclass;
|
||||
extern char proto_driver_name[];
|
||||
|
||||
int proto_add_resource(struct proto_softc *, int, int, struct resource *);
|
||||
|
||||
int proto_attach(device_t dev);
|
||||
int proto_detach(device_t dev);
|
||||
|
||||
#endif /* _DEV_PROTO_H_ */
|
112
sys/dev/proto/proto_bus_pci.c
Normal file
112
sys/dev/proto/proto_bus_pci.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/sbuf.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/proto/proto.h>
|
||||
|
||||
static int proto_pci_probe(device_t dev);
|
||||
static int proto_pci_attach(device_t dev);
|
||||
|
||||
static device_method_t proto_pci_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, proto_pci_probe),
|
||||
DEVMETHOD(device_attach, proto_pci_attach),
|
||||
DEVMETHOD(device_detach, proto_detach),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t proto_pci_driver = {
|
||||
proto_driver_name,
|
||||
proto_pci_methods,
|
||||
sizeof(struct proto_softc),
|
||||
};
|
||||
|
||||
static int
|
||||
proto_pci_probe(device_t dev)
|
||||
{
|
||||
struct sbuf *sb;
|
||||
|
||||
/* For now we only attach to function 0 devices. */
|
||||
if (pci_get_function(dev) != 0)
|
||||
return (ENXIO);
|
||||
|
||||
sb = sbuf_new_auto();
|
||||
sbuf_printf(sb, "pci%d:%d:%d:%d", pci_get_domain(dev),
|
||||
pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
|
||||
sbuf_finish(sb);
|
||||
device_set_desc_copy(dev, sbuf_data(sb));
|
||||
sbuf_delete(sb);
|
||||
return (BUS_PROBE_HOOVER);
|
||||
}
|
||||
|
||||
static int
|
||||
proto_pci_attach(device_t dev)
|
||||
{
|
||||
struct proto_softc *sc;
|
||||
struct resource *res;
|
||||
int bar, rid, type;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
proto_add_resource(sc, PROTO_RES_PCICFG, 0, NULL);
|
||||
|
||||
for (bar = 0; bar < PCIR_MAX_BAR_0; bar++) {
|
||||
rid = PCIR_BAR(bar);
|
||||
type = SYS_RES_MEMORY;
|
||||
res = bus_alloc_resource_any(dev, type, &rid, RF_ACTIVE);
|
||||
if (res == NULL) {
|
||||
type = SYS_RES_IOPORT;
|
||||
res = bus_alloc_resource_any(dev, type, &rid,
|
||||
RF_ACTIVE);
|
||||
}
|
||||
if (res != NULL)
|
||||
proto_add_resource(sc, type, rid, res);
|
||||
}
|
||||
|
||||
rid = 0;
|
||||
type = SYS_RES_IRQ;
|
||||
res = bus_alloc_resource_any(dev, type, &rid, RF_ACTIVE | RF_SHAREABLE);
|
||||
if (res != NULL)
|
||||
proto_add_resource(sc, type, rid, res);
|
||||
return (proto_attach(dev));
|
||||
}
|
||||
|
||||
DRIVER_MODULE(proto, pci, proto_pci_driver, proto_devclass, NULL, NULL);
|
384
sys/dev/proto/proto_core.c
Normal file
384
sys/dev/proto/proto_core.c
Normal file
@ -0,0 +1,384 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/uio.h>
|
||||
#include <machine/resource.h>
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/proto/proto.h>
|
||||
#include <dev/proto/proto_dev.h>
|
||||
|
||||
CTASSERT(SYS_RES_IRQ != PROTO_RES_UNUSED &&
|
||||
SYS_RES_MEMORY != PROTO_RES_UNUSED &&
|
||||
SYS_RES_IOPORT != PROTO_RES_UNUSED);
|
||||
CTASSERT(SYS_RES_IRQ != PROTO_RES_PCICFG &&
|
||||
SYS_RES_MEMORY != PROTO_RES_PCICFG &&
|
||||
SYS_RES_IOPORT != PROTO_RES_PCICFG);
|
||||
|
||||
devclass_t proto_devclass;
|
||||
char proto_driver_name[] = "proto";
|
||||
|
||||
static d_open_t proto_open;
|
||||
static d_close_t proto_close;
|
||||
static d_read_t proto_read;
|
||||
static d_write_t proto_write;
|
||||
static d_ioctl_t proto_ioctl;
|
||||
static d_mmap_t proto_mmap;
|
||||
|
||||
struct cdevsw proto_devsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_flags = 0,
|
||||
.d_name = proto_driver_name,
|
||||
.d_open = proto_open,
|
||||
.d_close = proto_close,
|
||||
.d_read = proto_read,
|
||||
.d_write = proto_write,
|
||||
.d_ioctl = proto_ioctl,
|
||||
.d_mmap = proto_mmap,
|
||||
};
|
||||
|
||||
static MALLOC_DEFINE(M_PROTO, "PROTO", "PROTO driver");
|
||||
|
||||
int
|
||||
proto_add_resource(struct proto_softc *sc, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
struct proto_res *r;
|
||||
|
||||
if (type == PROTO_RES_UNUSED)
|
||||
return (EINVAL);
|
||||
if (sc->sc_rescnt == PROTO_RES_MAX)
|
||||
return (ENOSPC);
|
||||
|
||||
r = sc->sc_res + sc->sc_rescnt++;
|
||||
r->r_type = type;
|
||||
r->r_rid = rid;
|
||||
r->r_res = res;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef notyet
|
||||
static int
|
||||
proto_intr(void *arg)
|
||||
{
|
||||
struct proto_softc *sc = arg;
|
||||
|
||||
/* XXX TODO */
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
proto_attach(device_t dev)
|
||||
{
|
||||
struct proto_softc *sc;
|
||||
struct proto_res *r;
|
||||
u_int res;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
|
||||
for (res = 0; res < sc->sc_rescnt; res++) {
|
||||
r = sc->sc_res + res;
|
||||
switch (r->r_type) {
|
||||
case SYS_RES_IRQ:
|
||||
/* XXX TODO */
|
||||
break;
|
||||
case SYS_RES_MEMORY:
|
||||
case SYS_RES_IOPORT:
|
||||
r->r_size = rman_get_size(r->r_res);
|
||||
r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0666,
|
||||
"proto/%s/%02x.%s", device_get_desc(dev), r->r_rid,
|
||||
(r->r_type == SYS_RES_IOPORT) ? "io" : "mem");
|
||||
r->r_u.cdev->si_drv1 = sc;
|
||||
r->r_u.cdev->si_drv2 = r;
|
||||
break;
|
||||
case PROTO_RES_PCICFG:
|
||||
r->r_size = 4096;
|
||||
r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0666,
|
||||
"proto/%s/pcicfg", device_get_desc(dev));
|
||||
r->r_u.cdev->si_drv1 = sc;
|
||||
r->r_u.cdev->si_drv2 = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
proto_detach(device_t dev)
|
||||
{
|
||||
struct proto_softc *sc;
|
||||
struct proto_res *r;
|
||||
u_int res;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* Don't detach if we have open device filess. */
|
||||
for (res = 0; res < sc->sc_rescnt; res++) {
|
||||
r = sc->sc_res + res;
|
||||
if (r->r_opened)
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
for (res = 0; res < sc->sc_rescnt; res++) {
|
||||
r = sc->sc_res + res;
|
||||
switch (r->r_type) {
|
||||
case SYS_RES_IRQ:
|
||||
/* XXX TODO */
|
||||
break;
|
||||
case SYS_RES_MEMORY:
|
||||
case SYS_RES_IOPORT:
|
||||
case PROTO_RES_PCICFG:
|
||||
destroy_dev(r->r_u.cdev);
|
||||
break;
|
||||
}
|
||||
if (r->r_res != NULL) {
|
||||
bus_release_resource(dev, r->r_type, r->r_rid,
|
||||
r->r_res);
|
||||
r->r_res = NULL;
|
||||
}
|
||||
r->r_type = PROTO_RES_UNUSED;
|
||||
}
|
||||
sc->sc_rescnt = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device functions
|
||||
*/
|
||||
|
||||
static int
|
||||
proto_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
|
||||
{
|
||||
struct proto_res *r;
|
||||
|
||||
r = cdev->si_drv2;
|
||||
if (!atomic_cmpset_acq_ptr(&r->r_opened, 0UL, (uintptr_t)td->td_proc))
|
||||
return (EBUSY);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
proto_close(struct cdev *cdev, int fflag, int devtype, struct thread *td)
|
||||
{
|
||||
struct proto_res *r;
|
||||
|
||||
r = cdev->si_drv2;
|
||||
if (!atomic_cmpset_acq_ptr(&r->r_opened, (uintptr_t)td->td_proc, 0UL))
|
||||
return (ENXIO);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
proto_read(struct cdev *cdev, struct uio *uio, int ioflag)
|
||||
{
|
||||
union {
|
||||
uint8_t x1[8];
|
||||
uint16_t x2[4];
|
||||
uint32_t x4[2];
|
||||
uint64_t x8[1];
|
||||
} buf;
|
||||
struct proto_softc *sc;
|
||||
struct proto_res *r;
|
||||
device_t dev;
|
||||
off_t ofs;
|
||||
u_long width;
|
||||
int error;
|
||||
|
||||
sc = cdev->si_drv1;
|
||||
dev = sc->sc_dev;
|
||||
r = cdev->si_drv2;
|
||||
|
||||
width = uio->uio_resid;
|
||||
if (width < 1 || width > 8 || bitcount16(width) > 1)
|
||||
return (EIO);
|
||||
ofs = uio->uio_offset;
|
||||
if (ofs + width > r->r_size)
|
||||
return (EIO);
|
||||
|
||||
switch (width) {
|
||||
case 1:
|
||||
buf.x1[0] = (r->r_type == PROTO_RES_PCICFG) ?
|
||||
pci_read_config(dev, ofs, 1) : bus_read_1(r->r_res, ofs);
|
||||
break;
|
||||
case 2:
|
||||
buf.x2[0] = (r->r_type == PROTO_RES_PCICFG) ?
|
||||
pci_read_config(dev, ofs, 2) : bus_read_2(r->r_res, ofs);
|
||||
break;
|
||||
case 4:
|
||||
buf.x4[0] = (r->r_type == PROTO_RES_PCICFG) ?
|
||||
pci_read_config(dev, ofs, 4) : bus_read_4(r->r_res, ofs);
|
||||
break;
|
||||
#ifndef __i386__
|
||||
case 8:
|
||||
if (r->r_type == PROTO_RES_PCICFG)
|
||||
return (EINVAL);
|
||||
buf.x8[0] = bus_read_8(r->r_res, ofs);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
error = uiomove(&buf, width, uio);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
proto_write(struct cdev *cdev, struct uio *uio, int ioflag)
|
||||
{
|
||||
union {
|
||||
uint8_t x1[8];
|
||||
uint16_t x2[4];
|
||||
uint32_t x4[2];
|
||||
uint64_t x8[1];
|
||||
} buf;
|
||||
struct proto_softc *sc;
|
||||
struct proto_res *r;
|
||||
device_t dev;
|
||||
off_t ofs;
|
||||
u_long width;
|
||||
int error;
|
||||
|
||||
sc = cdev->si_drv1;
|
||||
dev = sc->sc_dev;
|
||||
r = cdev->si_drv2;
|
||||
|
||||
width = uio->uio_resid;
|
||||
if (width < 1 || width > 8 || bitcount16(width) > 1)
|
||||
return (EIO);
|
||||
ofs = uio->uio_offset;
|
||||
if (ofs + width > r->r_size)
|
||||
return (EIO);
|
||||
|
||||
error = uiomove(&buf, width, uio);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
switch (width) {
|
||||
case 1:
|
||||
if (r->r_type == PROTO_RES_PCICFG)
|
||||
pci_write_config(dev, ofs, buf.x1[0], 1);
|
||||
else
|
||||
bus_write_1(r->r_res, ofs, buf.x1[0]);
|
||||
break;
|
||||
case 2:
|
||||
if (r->r_type == PROTO_RES_PCICFG)
|
||||
pci_write_config(dev, ofs, buf.x2[0], 2);
|
||||
else
|
||||
bus_write_2(r->r_res, ofs, buf.x2[0]);
|
||||
break;
|
||||
case 4:
|
||||
if (r->r_type == PROTO_RES_PCICFG)
|
||||
pci_write_config(dev, ofs, buf.x4[0], 4);
|
||||
else
|
||||
bus_write_4(r->r_res, ofs, buf.x4[0]);
|
||||
break;
|
||||
#ifndef __i386__
|
||||
case 8:
|
||||
if (r->r_type == PROTO_RES_PCICFG)
|
||||
return (EINVAL);
|
||||
bus_write_8(r->r_res, ofs, buf.x8[0]);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
proto_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
|
||||
struct thread *td)
|
||||
{
|
||||
struct proto_ioc_region *region;
|
||||
struct proto_res *r;
|
||||
int error;
|
||||
|
||||
r = cdev->si_drv2;
|
||||
|
||||
error = 0;
|
||||
switch (cmd) {
|
||||
case PROTO_IOC_REGION:
|
||||
region = (struct proto_ioc_region *)data;
|
||||
region->size = r->r_size;
|
||||
if (r->r_type == PROTO_RES_PCICFG)
|
||||
region->address = 0;
|
||||
else
|
||||
region->address = rman_get_start(r->r_res);
|
||||
break;
|
||||
default:
|
||||
error = ENOIOCTL;
|
||||
break;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
proto_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
|
||||
int prot, vm_memattr_t *memattr)
|
||||
{
|
||||
struct proto_res *r;
|
||||
|
||||
r = cdev->si_drv2;
|
||||
|
||||
if (r->r_type != SYS_RES_MEMORY)
|
||||
return (ENXIO);
|
||||
if (offset & PAGE_MASK)
|
||||
return (EINVAL);
|
||||
if (prot & PROT_EXEC)
|
||||
return (EACCES);
|
||||
if (offset >= r->r_size)
|
||||
return (EINVAL);
|
||||
*paddr = rman_get_start(r->r_res) + offset;
|
||||
#ifndef __sparc64__
|
||||
*memattr = VM_MEMATTR_UNCACHEABLE;
|
||||
#endif
|
||||
return (0);
|
||||
}
|
43
sys/dev/proto/proto_dev.h
Normal file
43
sys/dev/proto/proto_dev.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DEV_PROTO_DEV_H_
|
||||
#define _DEV_PROTO_DEV_H_
|
||||
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
#define PROTO_IOC_CLASS 'h'
|
||||
|
||||
struct proto_ioc_region {
|
||||
unsigned long address;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
#define PROTO_IOC_REGION _IOWR(PROTO_IOC_CLASS, 1, struct proto_ioc_region)
|
||||
|
||||
#endif /* _DEV_PROTO_H_ */
|
@ -272,6 +272,7 @@ SUBDIR= \
|
||||
ppi \
|
||||
pps \
|
||||
procfs \
|
||||
proto \
|
||||
pseudofs \
|
||||
${_pst} \
|
||||
pty \
|
||||
|
20
sys/modules/proto/Makefile
Normal file
20
sys/modules/proto/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../dev/proto
|
||||
|
||||
KMOD= proto
|
||||
SRCS= \
|
||||
proto_bus_pci.c \
|
||||
proto_core.c
|
||||
|
||||
SRCS+= \
|
||||
bus_if.h \
|
||||
device_if.h \
|
||||
pci_if.h \
|
||||
|
||||
MFILES= \
|
||||
dev/pci/pci_if.m \
|
||||
kern/bus_if.m \
|
||||
kern/device_if.m
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
x
Reference in New Issue
Block a user