Index: sys/conf/files
===================================================================
--- sys/conf/files	(revision 281862)
+++ sys/conf/files	(working copy)
@@ -2295,6 +2295,7 @@
 dev/spibus/spibus.c		optional spibus				\
 	dependency	"spibus_if.h"
 dev/spibus/spibus_if.m		optional spibus
+dev/spibus/spidev.c		optional spibus
 dev/ste/if_ste.c		optional ste pci
 dev/stg/tmc18c30.c		optional stg
 dev/stg/tmc18c30_isa.c		optional stg isa
Index: sys/dev/spibus/spi.h
===================================================================
--- sys/dev/spibus/spi.h	(revision 281862)
+++ sys/dev/spibus/spi.h	(working copy)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2006 M. Warner Losh
+ * Copyright (c) 2014 Tom Jones <jones@sdf.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,3 +39,23 @@
 };
 
 #define	SPI_CHIP_SELECT_HIGH	0x1		/* Chip select high (else low) */
+
+struct spi_ioc_transfer {
+	void *tx_buf;
+	void *rx_buf;
+
+	uint32_t len;
+	uint32_t speed_hz;
+
+	uint16_t delay_usecs;
+	uint8_t  bits_per_word;
+	uint8_t  cs_change;
+	uint32_t pad;
+};
+
+struct spi_rdwr_data {
+	struct spi_ioc_transfer *msgs;
+	uint32_t nmsgs;
+};
+
+#define SPIRDWR _IOW('S', 1, struct spi_rdwr_data)
Index: sys/dev/spibus/spidev.c
===================================================================
--- sys/dev/spibus/spidev.c	(revision 0)
+++ sys/dev/spibus/spidev.c	(working copy)
@@ -0,0 +1,310 @@
+/*-
+ * Copyright (c) 2015 Tom Jones <jones@sdf.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/types.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/ioccom.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/spibus/spibusvar.h>
+#include <dev/spibus/spi.h>
+
+#include "spibus_if.h"
+
+#define BUFSIZE 1024
+
+static MALLOC_DEFINE(M_SPIDEV, "spidev", "SPI data");
+
+struct spidev_softc {
+
+	device_t sc_dev;
+	device_t spi_dev;
+	int sc_count;			/* >0 if device opened */
+
+	char sc_buffer[BUFSIZE];	/* output buffer */
+	char sc_inbuf[BUFSIZE];		/* input buffer */
+
+	struct cdev *sc_devnode;
+	struct sx sc_lock;
+};
+
+static int spidev_probe(device_t);
+static int spidev_attach(device_t);
+static int spidev_detach(device_t);
+static void spidev_identify(driver_t *driver, device_t parent);
+
+static devclass_t spidev_devclass;
+
+static device_method_t spidev_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_identify,	spidev_identify),
+	DEVMETHOD(device_probe,		spidev_probe),
+	DEVMETHOD(device_attach,	spidev_attach),
+	DEVMETHOD(device_detach,	spidev_detach),
+
+	{ 0, 0 }
+};
+
+static driver_t spidev_driver = {
+	"spidev",
+	spidev_methods,
+	sizeof(struct spidev_softc),
+};
+
+static	d_open_t	spidevopen;
+static	d_close_t	spidevclose;
+static	d_write_t	spidevwrite;
+static	d_read_t	spidevread;
+static	d_ioctl_t	spidevioctl;
+
+static struct cdevsw spidev_cdevsw = {
+	.d_version =	D_VERSION,
+	.d_flags =	D_TRACKCLOSE,
+	.d_open =	spidevopen,
+	.d_close =	spidevclose,
+	.d_read =	spidevread,
+	.d_write =	spidevwrite,
+	.d_ioctl =	spidevioctl,
+	.d_name =	"spidev",
+};
+
+static void
+spidev_identify(driver_t *driver, device_t parent)
+{
+	if (device_find_child(parent, "spidev", -1) == NULL)
+		BUS_ADD_CHILD(parent, 0, "spidev", -1);	
+	else
+		uprintf("SPIDEV IDENTIFY nothing found\n");
+}
+
+static int
+spidev_probe(device_t dev)
+{
+	device_set_desc(dev, "SPI generic I/O");
+	return (0);
+}
+	
+static int
+spidev_attach(device_t dev)
+{
+	struct spidev_softc *sc = (struct spidev_softc *)device_get_softc(dev);
+	sc->sc_dev = dev;
+	
+	device_t spibus = device_get_parent(dev);
+	sc->spi_dev = device_get_parent(spibus);
+
+	if(sc->spi_dev == NULL) {
+		device_printf(dev, "failed to attach to spi device\n");
+		return (ENXIO);
+	}
+	sc->sc_devnode = make_dev(&spidev_cdevsw, device_get_unit(dev),
+			UID_ROOT, GID_WHEEL,
+			0600, "spi%d", device_get_unit(dev));
+
+	if (sc->sc_devnode == NULL) {
+		device_printf(dev, "failed to create character device\n");
+		return (ENXIO);
+	}
+	sc->sc_devnode->si_drv1 = sc;
+
+	return (0);
+}
+
+static int
+spidev_detach(device_t dev)
+{
+	struct spidev_softc *sc = (struct spidev_softc *)device_get_softc(dev);
+
+	if (sc->sc_devnode)
+		destroy_dev(sc->sc_devnode);
+
+	return (0);
+}
+
+static int
+spidevopen(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+	struct spidev_softc *sc = dev->si_drv1;
+
+	if(sc->sc_count > 0)
+		return (EBUSY);
+	sc->sc_count++;
+
+	return (0);
+}
+
+static int
+spidevclose(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+	struct spidev_softc *sc = dev->si_drv1;
+
+	sc->sc_count--;
+	if(sc->sc_count < 0)
+		panic("%s: spidev_count < 0!",__func__);
+
+	return (0);
+}
+
+static int
+spidevwrite(struct cdev *dev, struct uio * uio, int ioflag)
+{
+	struct spidev_softc *sc = dev->si_drv1;
+	device_t spi_hw = sc->spi_dev;	
+	int error;
+
+	struct spi_command cmd;
+	size_t size = MIN(uio->uio_resid,BUFSIZE);
+
+	cmd.rx_cmd_sz = cmd.tx_cmd_sz = 0;
+
+	cmd.tx_data = sc->sc_inbuf;
+	cmd.rx_data = sc->sc_buffer;
+	cmd.rx_data_sz = cmd.tx_data_sz = size;
+
+	memset(sc->sc_buffer, 0, size);
+
+	error = uiomove(sc->sc_inbuf, size, uio);
+	if(error == 0)
+		error = SPIBUS_TRANSFER(spi_hw, sc->sc_dev, &cmd);
+
+	return (error);
+}
+
+static int
+spidevread(struct cdev *dev, struct uio * uio, int ioflag)
+{
+	struct spidev_softc *sc = dev->si_drv1;
+	struct spi_command cmd;
+	device_t spi_hw = sc->spi_dev;	
+	int error;
+
+	size_t size = MIN(uio->uio_resid,BUFSIZE);
+
+	cmd.rx_cmd_sz = cmd.tx_cmd_sz = 0;
+
+	cmd.tx_data = sc->sc_inbuf;
+	cmd.rx_data = sc->sc_buffer;
+	cmd.rx_data_sz = cmd.tx_data_sz = size;
+
+	error = SPIBUS_TRANSFER(spi_hw,sc->sc_dev, &cmd);
+
+	if(error == 0)
+		error = uiomove(sc->sc_buffer, size, uio);
+
+	return (error);
+}
+
+static int
+spidevioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
+{ 
+	struct spidev_softc *sc = dev->si_drv1;
+	struct spi_command spicmd;
+	struct spi_ioc_transfer *s, *operations = NULL;
+	struct spi_rdwr_data *spi_data = (struct spi_rdwr_data *)data;
+	device_t spi_hw = sc->spi_dev;	
+	int error;
+
+	switch (cmd) {
+	case SPIRDWR:
+		if(spi_data->nmsgs <= 0)
+			return EINVAL;
+
+		operations = malloc(spi_data->nmsgs * sizeof(struct spi_ioc_transfer),
+			M_SPIDEV,
+			M_WAITOK);
+
+		error = copyin(spi_data->msgs, operations,
+			spi_data->nmsgs * sizeof(struct spi_ioc_transfer));
+
+		if(error)
+			goto errout;
+	
+		for(int i = 0; i < spi_data->nmsgs; i++) {
+			s = &operations[i];
+
+			spicmd.tx_cmd_sz = spicmd.rx_cmd_sz = 0;
+
+			spicmd.tx_data_sz = s->len;
+			spicmd.rx_data_sz = s->len;
+
+			spicmd.tx_data = malloc(s->len, M_SPIDEV, M_WAITOK);
+			spicmd.rx_data = malloc(s->len, M_SPIDEV, M_WAITOK);
+
+			error = copyin(s->tx_buf, spicmd.tx_data, spicmd.tx_data_sz);
+
+			if(error)
+				goto errout;
+
+			error = SPIBUS_TRANSFER(spi_hw,sc->sc_dev, &spicmd);
+
+			if(error)
+				goto errout;
+
+			error = copyout(spicmd.rx_data, s->rx_buf, spicmd.rx_data_sz);
+
+			if(error)
+				goto errout;
+
+			if(spicmd.tx_data) {
+				free(spicmd.tx_data, M_SPIDEV);
+				spicmd.tx_data = NULL;
+			}
+			if(spicmd.rx_data) {
+				free(spicmd.rx_data, M_SPIDEV);
+				spicmd.rx_data = NULL;
+			}
+		}		
+		
+		break;
+	default:
+		error = ENOTTY;
+	}
+
+	errout:
+		if(operations != NULL)
+			free(operations, M_SPIDEV);
+		if(spicmd.tx_data)
+			free(spicmd.tx_data, M_SPIDEV);
+		if(spicmd.rx_data)
+			free(spicmd.rx_data, M_SPIDEV);
+	return (error);
+}
+
+DRIVER_MODULE(spidev, spibus, spidev_driver, spidev_devclass, 0, 0);
+MODULE_VERSION(spidev, 1);

Property changes on: sys/dev/spibus/spidev.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
