Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Aug 2015 10:00:26 -0400
From:      Brian Fundakowski Feldman <brianfundakowskifeldman@gmail.com>
To:        hackers@freebsd.org
Subject:   spigen(4) SPI Generic IO interface -- need comments
Message-ID:  <CAEv1%2BOU4cFpMpeQGfnCP7L4Q_k18rOSOA9JBnKUa99DS5dFnWA@mail.gmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
I'm woefully out-of-practice with my kernel hackery (but still pretty
proficient in jiggery-pokery) so I would like to get comments on a little
driver I just made for interfacing arbitrarily in userland with SPI
components.  The only thing I'm exposing is a /dev/spigenN node with a
single transfer ioctl and I put together a test circuit and program with an
MCP3008 10-bit ADC IC to validate that it basically works, other than the
limitation that the transfers must be octet-multiply-sized, but I haven't
looked at the SoC's (I'm using a Raspberry Pi 2) data sheet to tell whether
that's just a limit on the spibus(4) interface or the Broadcom SPI driver
or the Broadcom SoC itself.

I hit one snag in development where I simply called the ioctl wrong and
found copyin(9) to page fault HARD if given a bogus user address to copy
from, and panic the kernel.  I can post up the test program if anyone wants
but it's very trivial: I just align the start bit and the command data into
the least significant bits of the first octet, shift it up two positions so
the NULs get clocked out as part of the command field, and provide two
octets for the data field to retrieve back the 10-bit digital value.

Good to be back in the FreeBSD hacking!

Cheers,
Brian Fundakowski Feldman

[-- Attachment #2 --]
Index: sys/conf/files
===================================================================
--- sys/conf/files	(revision 286786)
+++ sys/conf/files	(working copy)
@@ -2450,6 +2450,7 @@
 dev/spibus/ofw_spibus.c		optional fdt spibus
 dev/spibus/spibus.c		optional spibus				\
 	dependency	"spibus_if.h"
+dev/spibus/spigen.c		optional spibus
 dev/spibus/spibus_if.m		optional spibus
 dev/ste/if_ste.c		optional ste pci
 dev/stg/tmc18c30.c		optional stg
Index: sys/dev/spibus/spigen.c
===================================================================
--- sys/dev/spibus/spigen.c	(revision 0)
+++ sys/dev/spibus/spigen.c	(working copy)
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 2015 Brian Fundakowski Feldman.  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/malloc.h>
+#include <sys/module.h>
+#include <sys/spigenio.h>
+
+#include <dev/spibus/spi.h>
+#include "spibus_if.h"
+
+struct spigen_softc {
+	device_t sc_dev;
+	struct cdev *sc_cdev;
+};
+
+static int
+spigen_probe(device_t dev)
+{
+	device_set_desc(dev, "SPI Generic IO");
+	return (0);
+}
+
+static int spigen_open(struct cdev *, int, int, struct thread *);
+static int spigen_ioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
+static int spigen_close(struct cdev *, int, int, struct thread *);
+
+static struct cdevsw spigen_cdevsw = {
+	.d_version = D_VERSION,
+	.d_name = "spigen",
+	.d_open = spigen_open,
+	.d_ioctl = spigen_ioctl,
+	.d_close = spigen_close
+};
+
+static int
+spigen_attach(device_t dev)
+{
+	struct spigen_softc *sc;
+	const int unit = device_get_unit(dev);
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_cdev = make_dev(&spigen_cdevsw, unit,
+	    UID_ROOT, GID_OPERATOR, 0660, "spigen%d", unit);
+	sc->sc_cdev->si_drv1 = dev;
+
+	return (0);
+}
+
+static int 
+spigen_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+
+	return (0);
+}
+
+static int
+spigen_transfer(struct cdev *cdev, struct spigen_transfer *st)
+{
+	struct spi_command transfer;
+	device_t dev = cdev->si_drv1;
+	int error;
+
+	if (st->st_command.iov_len == 0 || st->st_data.iov_len == 0)
+		return (EINVAL);
+	if (st->st_command.iov_len > PAGE_SIZE ||
+	    st->st_data.iov_len > PAGE_SIZE)
+		return (ENOMEM);
+#if 0
+	device_printf(dev, "cmd %p %u data %p %u\n", st->st_command.iov_base,
+	    st->st_command.iov_len, st->st_data.iov_base, st->st_data.iov_len);
+#endif
+	transfer.tx_cmd = transfer.rx_cmd = malloc(st->st_command.iov_len,
+	    M_DEVBUF, M_WAITOK);
+	if (transfer.tx_cmd == NULL)
+		return (ENOMEM);
+	transfer.tx_data = transfer.rx_data = malloc(st->st_data.iov_len,
+	    M_DEVBUF, M_WAITOK);
+	if (transfer.tx_data == NULL) {
+		free(transfer.tx_cmd, M_DEVBUF);
+		return (ENOMEM);
+	}
+
+	error = copyin(st->st_command.iov_base, transfer.tx_cmd,
+	    transfer.tx_cmd_sz = transfer.rx_cmd_sz = st->st_command.iov_len);	
+	if (error == 0)
+		error = copyin(st->st_data.iov_base, transfer.tx_data,
+		    transfer.tx_data_sz = transfer.rx_data_sz =
+		                          st->st_data.iov_len);	
+	if (error == 0)
+		error = SPIBUS_TRANSFER(device_get_parent(dev), dev, &transfer);
+	if (error == 0) {
+		error = copyout(transfer.rx_cmd, st->st_command.iov_base,
+		    transfer.rx_cmd_sz);
+		if (error == 0)
+			error = copyout(transfer.rx_data, st->st_data.iov_base,
+			    transfer.rx_data_sz);
+	}
+
+	free(transfer.tx_cmd, M_DEVBUF);
+	free(transfer.tx_data, M_DEVBUF);
+	return (error);
+}
+
+static int
+spigen_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+    struct thread *td)
+{
+	int error;
+
+	switch (cmd) {
+	case SPIGENIOC_TRANSFER:
+		error = spigen_transfer(dev, (struct spigen_transfer *)data);
+		break;
+	default:
+		error = EOPNOTSUPP;
+	}
+	return error;
+}
+
+static int 
+spigen_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+
+	return (0);
+}
+
+static int
+spigen_detach(device_t dev)
+{
+
+	return (EIO);
+}
+
+static devclass_t spigen_devclass;
+
+static device_method_t spigen_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		spigen_probe),
+	DEVMETHOD(device_attach,	spigen_attach),
+	DEVMETHOD(device_detach,	spigen_detach),
+
+	{ 0, 0 }
+};
+
+static driver_t spigen_driver = {
+	"spigen",
+	spigen_methods,
+	sizeof(struct spigen_softc),
+};
+
+DRIVER_MODULE(spigen, spibus, spigen_driver, spigen_devclass, 0, 0);

Property changes on: sys/dev/spibus/spigen.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
Index: sys/sys/spigenio.h
===================================================================
--- sys/sys/spigenio.h	(revision 0)
+++ sys/sys/spigenio.h	(working copy)
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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.
+ *
+ *	$FreeBSD$
+ */
+
+#ifndef _SYS_SPIGENIO_H_
+#define _SYS_SPIGENIO_H_
+
+#include <sys/_iovec.h>
+
+struct spigen_transfer {
+	struct iovec st_command; /* master to slave */
+	struct iovec st_data;    /* slave to master */
+};
+
+#define SPIGENIOC_BASE     'S'
+#define SPIGENIOC_TRANSFER _IOW(SPIGENIOC_BASE, 0, struct spigen_transfer)
+
+#endif /* !_SYS_SPIGENIO_H_ */

Property changes on: sys/sys/spigenio.h
___________________________________________________________________
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

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAEv1%2BOU4cFpMpeQGfnCP7L4Q_k18rOSOA9JBnKUa99DS5dFnWA>