Tue May 18 23:48:16 2021 UTC ()
Define a "spi-enumerate-devices" device call and use it for direct
configuration of SPI devices, rather than slinging arrays of dictionaries
around.  Implement this device call for OpenFirmware / FDT, following
the SPI bindings for Device Tree.


(thorpej)
diff -r1.2 -r1.2.2.1 src/sys/dev/fdt/fdt_spi.c
diff -r1.1 -r1.1.6.1 src/sys/dev/ofw/ofw_spi_subr.c
diff -r1.17 -r1.17.2.1 src/sys/dev/spi/spi.c
diff -r1.10 -r1.10.6.1 src/sys/dev/spi/spivar.h

cvs diff -r1.2 -r1.2.2.1 src/sys/dev/fdt/fdt_spi.c (expand / switch to unified diff)

--- src/sys/dev/fdt/fdt_spi.c 2021/04/24 23:36:53 1.2
+++ src/sys/dev/fdt/fdt_spi.c 2021/05/18 23:48:16 1.2.2.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: fdt_spi.c,v 1.2 2021/04/24 23:36:53 thorpej Exp $ */ 1/* $NetBSD: fdt_spi.c,v 1.2.2.1 2021/05/18 23:48:16 thorpej Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2019 The NetBSD Foundation, Inc. 4 * Copyright (c) 2019 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tobias Nygren. 8 * by Tobias Nygren.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -20,27 +20,27 @@ @@ -20,27 +20,27 @@
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: fdt_spi.c,v 1.2 2021/04/24 23:36:53 thorpej Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: fdt_spi.c,v 1.2.2.1 2021/05/18 23:48:16 thorpej Exp $");
34 34
35#include <sys/param.h> 35#include <sys/param.h>
36#include <sys/device.h> 36#include <sys/device.h>
37#include <sys/bus.h> 37#include <sys/bus.h>
38#include <sys/kmem.h> 38#include <sys/kmem.h>
39#include <sys/queue.h> 39#include <sys/queue.h>
40#include <dev/spi/spivar.h> 40#include <dev/spi/spivar.h>
41#include <libfdt.h> 41#include <libfdt.h>
42#include <dev/fdt/fdtvar.h> 42#include <dev/fdt/fdtvar.h>
43 43
44struct fdtbus_spi_controller { 44struct fdtbus_spi_controller {
45 device_t spi_dev; 45 device_t spi_dev;
46 int spi_phandle; 46 int spi_phandle;
@@ -74,43 +74,27 @@ fdtbus_get_spi_controller(int phandle) @@ -74,43 +74,27 @@ fdtbus_get_spi_controller(int phandle)
74 74
75 LIST_FOREACH(spi, &fdtbus_spi_controllers, spi_next) { 75 LIST_FOREACH(spi, &fdtbus_spi_controllers, spi_next) {
76 if (spi->spi_phandle == phandle) { 76 if (spi->spi_phandle == phandle) {
77 return spi->spi_funcs->get_controller(spi->spi_dev); 77 return spi->spi_funcs->get_controller(spi->spi_dev);
78 } 78 }
79 } 79 }
80 return NULL; 80 return NULL;
81} 81}
82 82
83device_t 83device_t
84fdtbus_attach_spibus(device_t dev, int phandle, cfprint_t print) 84fdtbus_attach_spibus(device_t dev, int phandle, cfprint_t print)
85{ 85{
86 struct spi_controller *spi; 86 struct spi_controller *spi;
87 struct spibus_attach_args sba; 
88 prop_dictionary_t devs; 
89 device_t ret; 
90 u_int address_cells; 
91 
92 devs = prop_dictionary_create(); 
93 if (of_getprop_uint32(phandle, "#address-cells", &address_cells)) 
94 address_cells = 1; 
95 of_enter_spi_devs(devs, phandle, address_cells * 4); 
96 87
97 spi = fdtbus_get_spi_controller(phandle); 88 spi = fdtbus_get_spi_controller(phandle);
98 KASSERT(spi != NULL); 89 KASSERT(spi != NULL);
99 memset(&sba, 0, sizeof(sba)); 
100 sba.sba_controller = spi; 
101 90
102 sba.sba_child_devices = prop_dictionary_get(devs, "spi-child-devices"); 91 struct spibus_attach_args sba = {
103 if (sba.sba_child_devices) 92 .sba_controller = spi,
104 prop_object_retain(sba.sba_child_devices); 93 };
105 prop_object_release(devs); 94 return config_found(dev, &sba, print,
106 
107 ret = config_found(dev, &sba, print, 
108 CFARG_IATTR, "spibus", 95 CFARG_IATTR, "spibus",
 96 CFARG_DEVHANDLE, device_handle(dev),
109 CFARG_EOL); 97 CFARG_EOL);
110 if (sba.sba_child_devices) 
111 prop_object_release(sba.sba_child_devices); 
112 
113 return ret; 
114} 98}
115 99
116 100

cvs diff -r1.1 -r1.1.6.1 src/sys/dev/ofw/ofw_spi_subr.c (expand / switch to unified diff)

--- src/sys/dev/ofw/ofw_spi_subr.c 2021/02/04 20:19:09 1.1
+++ src/sys/dev/ofw/ofw_spi_subr.c 2021/05/18 23:48:16 1.1.6.1
@@ -1,100 +1,96 @@ @@ -1,100 +1,96 @@
1/* $NetBSD: ofw_spi_subr.c,v 1.1 2021/02/04 20:19:09 thorpej Exp $ */ 1/* $NetBSD: ofw_spi_subr.c,v 1.1.6.1 2021/05/18 23:48:16 thorpej Exp $ */
2 2
3/* 3/*
4 * Copyright 1998 4 * Copyright (c) 2021 The NetBSD Foundation, Inc.
5 * Digital Equipment Corporation. All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This software is furnished under license and may be used and 7 * Redistribution and use in source and binary forms, with or without
8 * copied only in accordance with the following terms and conditions. 8 * modification, are permitted provided that the following conditions
9 * Subject to these conditions, you may download, copy, install, 9 * are met:
10 * use, modify and distribute this software in source and/or binary 10 * 1. Redistributions of source code must retain the above copyright
11 * form. No title or ownership is transferred hereby. 11 * notice, this list of conditions and the following disclaimer.
 12 * 2. Redistributions in binary form must reproduce the above copyright
 13 * notice, this list of conditions and the following disclaimer in the
 14 * documentation and/or other materials provided with the distribution.
12 * 15 *
13 * 1) Any source code used, modified or distributed must reproduce 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
14 * and retain this copyright notice and list of conditions as 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
15 * they appear in the source file. 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
17 * 2) No right is granted to use any trade name, trademark, or logo of 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * Digital Equipment Corporation. Neither the "Digital Equipment 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * Corporation" name nor any trademark or logo of Digital Equipment 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * Corporation may be used to endorse or promote products derived 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * from this software without the prior written permission of 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * Digital Equipment Corporation. 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23 * 26 * POSSIBILITY OF SUCH DAMAGE.
24 * 3) This software is provided "AS-IS" and any express or implied 
25 * warranties, including but not limited to, any implied warranties 
26 * of merchantability, fitness for a particular purpose, or 
27 * non-infringement are disclaimed. In no event shall DIGITAL be 
28 * liable for any damages whatsoever, and in particular, DIGITAL 
29 * shall not be liable for special, indirect, consequential, or 
30 * incidental damages or damages for lost profits, loss of 
31 * revenue or loss of use, whether such damages arise in contract, 
32 * negligence, tort, under statute, in equity, at law or otherwise, 
33 * even if advised of the possibility of such damage. 
34 */ 27 */
35 28
36#include <sys/cdefs.h> 29#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: ofw_spi_subr.c,v 1.1 2021/02/04 20:19:09 thorpej Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: ofw_spi_subr.c,v 1.1.6.1 2021/05/18 23:48:16 thorpej Exp $");
38 31
39#include <sys/param.h> 32#include <sys/param.h>
40#include <sys/device.h> 33#include <sys/device.h>
41#include <sys/kmem.h> 34#include <sys/kmem.h>
42#include <sys/systm.h> 35#include <sys/systm.h>
43#include <dev/ofw/openfirm.h> 36#include <dev/ofw/openfirm.h>
 37#include <dev/spi/spivar.h>
44 38
45void 39static int
46of_enter_spi_devs(prop_dictionary_t props, int ofnode, size_t cell_size) 40of_spi_enumerate_devices(device_t dev, devhandle_t call_handle, void *v)
47{ 41{
48 int node, len; 42 struct spi_enumerate_devices_args *args = v;
49 char name[32]; 43 int spi_node, node;
50 uint64_t reg64; 44 char name[32], compat_buf[32];
51 uint32_t reg32; 45 uint32_t chip_select;
52 uint32_t slave; 46 char *clist;
53 u_int32_t maxfreq; 47 int clist_size;
54 prop_array_t array = NULL; 48 bool cbrv;
55 prop_dictionary_t dev; 49
56 int mode; 50 spi_node = devhandle_to_of(call_handle);
57 51
58 for (node = OF_child(ofnode); node; node = OF_peer(node)) { 52 for (node = OF_child(spi_node); node != 0; node = OF_peer(node)) {
59 if (OF_getprop(node, "name", name, sizeof(name)) <= 0) 53 if (OF_getprop(node, "name", name, sizeof(name)) <= 0) {
60 continue; 54 continue;
61 len = OF_getproplen(node, "reg"); 55 }
62 slave = 0; 56
63 if (cell_size == 8 && len >= sizeof(reg64)) { 57 if (of_getprop_uint32(node, "reg", &chip_select) != 0) {
64 if (OF_getprop(node, "reg", &reg64, sizeof(reg64)) 
65 < sizeof(reg64)) 
66 continue; 
67 slave = be64toh(reg64); 
68 } else if (cell_size == 4 && len >= sizeof(reg32)) { 
69 if (OF_getprop(node, "reg", &reg32, sizeof(reg32)) 
70 < sizeof(reg32)) 
71 continue; 
72 slave = be32toh(reg32); 
73 } else { 
74 continue; 58 continue;
75 } 59 }
76 if (of_getprop_uint32(node, "spi-max-frequency", &maxfreq)) { 60
77 maxfreq = 0; 61 /* Device Tree bindings specify a max chip select of 256. */
 62 if (chip_select > 256) {
 63 continue;
78 } 64 }
79 mode = ((int)of_hasprop(node, "cpol") << 1) | (int)of_hasprop(node, "cpha"); 
80 65
81 if (array == NULL) 66 clist_size = OF_getproplen(node, "compatible");
82 array = prop_array_create(); 67 if (clist_size <= 0) {
 68 continue;
 69 }
83 70
84 dev = prop_dictionary_create(); 71 clist = kmem_tmpbuf_alloc(clist_size,
85 prop_dictionary_set_string(dev, "name", name); 72 compat_buf, sizeof(compat_buf), KM_SLEEP);
86 prop_dictionary_set_uint32(dev, "slave", slave); 73 if (OF_getprop(node, "compatible", clist, clist_size) <
87 prop_dictionary_set_uint32(dev, "mode", mode); 74 clist_size) {
88 if (maxfreq > 0) 75 kmem_tmpbuf_free(clist, clist_size, compat_buf);
89 prop_dictionary_set_uint32(dev, "spi-max-frequency", maxfreq); 76 continue;
90 prop_dictionary_set_uint64(dev, "cookie", node); 77 }
91 of_to_dataprop(dev, node, "compatible", "compatible"); 78
92 prop_array_add(array, dev); 79 args->chip_select = (int)chip_select;
93 prop_object_release(dev); 80 args->sa->sa_name = name;
94 } 81 args->sa->sa_clist = clist;
 82 args->sa->sa_clist_size = clist_size;
 83 args->sa->sa_devhandle = devhandle_from_of(node);
95 84
96 if (array != NULL) { 85 cbrv = args->callback(dev, args);
97 prop_dictionary_set(props, "spi-child-devices", array); 86
98 prop_object_release(array); 87 kmem_tmpbuf_free(clist, clist_size, compat_buf);
 88
 89 if (!cbrv) {
 90 break;
 91 }
99 } 92 }
 93
 94 return 0;
100} 95}
 96OF_DEVICE_CALL_REGISTER("spi-enumerate-devices", of_spi_enumerate_devices);

cvs diff -r1.17 -r1.17.2.1 src/sys/dev/spi/spi.c (expand / switch to unified diff)

--- src/sys/dev/spi/spi.c 2021/04/24 23:36:59 1.17
+++ src/sys/dev/spi/spi.c 2021/05/18 23:48:16 1.17.2.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: spi.c,v 1.17 2021/04/24 23:36:59 thorpej Exp $ */ 1/* $NetBSD: spi.c,v 1.17.2.1 2021/05/18 23:48:16 thorpej Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore. 5 * Copyright (c) 2006 Garrett D'Amore.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Portions of this code were written by Garrett D'Amore for the 8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project. 9 * Champaign-Urbana Community Wireless Network Project.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or 11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following 12 * without modification, are permitted provided that the following
13 * conditions are met: 13 * conditions are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -32,52 +32,54 @@ @@ -32,52 +32,54 @@
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT, 34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */ 42 */
43 43
44#include <sys/cdefs.h> 44#include <sys/cdefs.h>
45__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.17 2021/04/24 23:36:59 thorpej Exp $"); 45__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.17.2.1 2021/05/18 23:48:16 thorpej Exp $");
46 46
47#include "locators.h" 47#include "locators.h"
48 48
49#include <sys/param.h> 49#include <sys/param.h>
50#include <sys/systm.h> 50#include <sys/systm.h>
51#include <sys/device.h> 51#include <sys/device.h>
52#include <sys/conf.h> 52#include <sys/conf.h>
53#include <sys/malloc.h> 53#include <sys/kmem.h>
54#include <sys/mutex.h> 54#include <sys/mutex.h>
55#include <sys/condvar.h> 55#include <sys/condvar.h>
56#include <sys/errno.h> 56#include <sys/errno.h>
57 57
58#include <dev/spi/spivar.h> 58#include <dev/spi/spivar.h>
59#include <dev/spi/spi_io.h> 59#include <dev/spi/spi_io.h>
60 60
61#include "ioconf.h" 61#include "ioconf.h"
62#include "locators.h" 62#include "locators.h"
63 63
64struct spi_softc { 64struct spi_softc {
 65 device_t sc_dev;
65 struct spi_controller sc_controller; 66 struct spi_controller sc_controller;
66 int sc_mode; 67 int sc_mode;
67 int sc_speed; 68 int sc_speed;
68 int sc_slave; 69 int sc_slave;
69 int sc_nslaves; 70 int sc_nslaves;
70 struct spi_handle *sc_slaves; 71 struct spi_handle *sc_slaves;
 72 kmutex_t sc_slave_state_lock;
71 kmutex_t sc_lock; 73 kmutex_t sc_lock;
72 kcondvar_t sc_cv; 74 kcondvar_t sc_cv;
73 int sc_flags; 75 int sc_flags;
74#define SPIC_BUSY 1 76#define SPIC_BUSY 1
75}; 77};
76 78
77static dev_type_open(spi_open); 79static dev_type_open(spi_open);
78static dev_type_close(spi_close); 80static dev_type_close(spi_close);
79static dev_type_ioctl(spi_ioctl); 81static dev_type_ioctl(spi_ioctl);
80 82
81const struct cdevsw spi_cdevsw = { 83const struct cdevsw spi_cdevsw = {
82 .d_open = spi_open, 84 .d_open = spi_open,
83 .d_close = spi_close, 85 .d_close = spi_close,
@@ -87,33 +89,34 @@ const struct cdevsw spi_cdevsw = { @@ -87,33 +89,34 @@ const struct cdevsw spi_cdevsw = {
87 .d_stop = nostop, 89 .d_stop = nostop,
88 .d_tty = notty, 90 .d_tty = notty,
89 .d_poll = nopoll, 91 .d_poll = nopoll,
90 .d_mmap = nommap, 92 .d_mmap = nommap,
91 .d_kqfilter = nokqfilter, 93 .d_kqfilter = nokqfilter,
92 .d_discard = nodiscard, 94 .d_discard = nodiscard,
93 .d_flag = D_OTHER 95 .d_flag = D_OTHER
94}; 96};
95 97
96/* 98/*
97 * SPI slave device. We have one of these per slave. 99 * SPI slave device. We have one of these per slave.
98 */ 100 */
99struct spi_handle { 101struct spi_handle {
100 struct spi_softc *sh_sc; 102 struct spi_softc *sh_sc; /* static */
101 struct spi_controller *sh_controller; 103 struct spi_controller *sh_controller; /* static */
102 int sh_slave; 104 int sh_slave; /* static */
103 int sh_mode; 105 int sh_mode; /* locked by owning child */
104 int sh_speed; 106 int sh_speed; /* locked by owning child */
105 int sh_flags; 107 int sh_flags; /* ^^ slave_state_lock ^^ */
106#define SPIH_ATTACHED 1 108#define SPIH_ATTACHED __BIT(0)
 109#define SPIH_DIRECT __BIT(1)
107}; 110};
108 111
109#define SPI_MAXDATA 4096 112#define SPI_MAXDATA 4096
110 113
111/* 114/*
112 * API for bus drivers. 115 * API for bus drivers.
113 */ 116 */
114 117
115int 118int
116spibus_print(void *aux, const char *pnp) 119spibus_print(void *aux, const char *pnp)
117{ 120{
118 121
119 if (pnp != NULL) 122 if (pnp != NULL)
@@ -121,214 +124,219 @@ spibus_print(void *aux, const char *pnp) @@ -121,214 +124,219 @@ spibus_print(void *aux, const char *pnp)
121 124
122 return (UNCONF); 125 return (UNCONF);
123} 126}
124 127
125 128
126static int 129static int
127spi_match(device_t parent, cfdata_t cf, void *aux) 130spi_match(device_t parent, cfdata_t cf, void *aux)
128{ 131{
129 132
130 return 1; 133 return 1;
131} 134}
132 135
133static int 136static int
134spi_print(void *aux, const char *pnp) 137spi_print_direct(void *aux, const char *pnp)
135{ 138{
136 struct spi_attach_args *sa = aux; 139 struct spi_attach_args *sa = aux;
137 140
138 if (sa->sa_handle->sh_slave != -1) 141 if (pnp != NULL) {
 142 aprint_normal("%s%s%s%s at %s slave %d",
 143 sa->sa_name ? sa->sa_name : "(unknown)",
 144 sa->sa_clist ? " (" : "",
 145 sa->sa_clist ? sa->sa_clist : "",
 146 sa->sa_clist ? ")" : "",
 147 pnp, sa->sa_handle->sh_slave);
 148 } else {
139 aprint_normal(" slave %d", sa->sa_handle->sh_slave); 149 aprint_normal(" slave %d", sa->sa_handle->sh_slave);
 150 }
140 151
141 return (UNCONF); 152 return UNCONF;
142} 153}
143 154
144static int 155static int
145spi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 156spi_print(void *aux, const char *pnp)
146{ 157{
147 struct spi_softc *sc = device_private(parent); 158 struct spi_attach_args *sa = aux;
148 struct spi_attach_args sa; 
149 int addr; 
150 
151 addr = cf->cf_loc[SPICF_SLAVE]; 
152 if ((addr < 0) || (addr >= sc->sc_controller.sct_nslaves)) { 
153 return -1; 
154 } 
155 
156 memset(&sa, 0, sizeof sa); 
157 sa.sa_handle = &sc->sc_slaves[addr]; 
158 if (ISSET(sa.sa_handle->sh_flags, SPIH_ATTACHED)) 
159 return -1; 
160 159
161 if (config_probe(parent, cf, &sa)) { 160 aprint_normal(" slave %d", sa->sa_handle->sh_slave);
162 SET(sa.sa_handle->sh_flags, SPIH_ATTACHED); 
163 config_attach(parent, cf, &sa, spi_print, CFARG_EOL); 
164 } 
165 161
166 return 0; 162 return UNCONF;
167} 163}
168 164
169/* 165/*
170 * XXX this is the same as i2c_fill_compat. It could be refactored into a 166 * Direct and indrect for SPI are pretty similar, so we can collapse
171 * common fill_compat function with pointers to compat & ncompat instead 167 * them into a single function.
172 * of attach_args as the first parameter. 
173 */ 168 */
174static void 169static void
175spi_fill_compat(struct spi_attach_args *sa, const char *compat, size_t len, 170spi_attach_child(struct spi_softc *sc, struct spi_attach_args *sa,
176 char **buffer) 171 int chip_select, cfdata_t cf)
177{ 172{
178 int count, i; 173 struct spi_handle *sh;
179 const char *c, *start, **ptr; 174 device_t newdev = NULL;
 175 bool is_direct = cf == NULL;
 176 const int skip_flags = is_direct ? SPIH_ATTACHED
 177 : (SPIH_ATTACHED | SPIH_DIRECT);
 178 const int claim_flags = skip_flags ^ SPIH_DIRECT;
 179 int locs[SPICF_NLOCS] = { 0 };
180 180
181 *buffer = NULL; 181 if (chip_select < 0 ||
182 for (i = count = 0, c = compat; i < len; i++, c++) 182 chip_select >= sc->sc_controller.sct_nslaves) {
183 if (*c == 0) 
184 count++; 
185 count += 2; 
186 ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK); 
187 if (!ptr) 
188 return; 183 return;
 184 }
189 185
190 for (i = count = 0, start = c = compat; i < len; i++, c++) { 186 sh = &sc->sc_slaves[chip_select];
191 if (*c == 0) { 187
192 ptr[count++] = start; 188 mutex_enter(&sc->sc_slave_state_lock);
193 start = c + 1; 189 if (ISSET(sh->sh_flags, skip_flags)) {
194 } 190 mutex_exit(&sc->sc_slave_state_lock);
 191 return;
195 } 192 }
196 if (start < compat + len) { 193
197 /* last string not 0 terminated */ 194 /* Keep others off of this chip select. */
198 size_t l = c - start; 195 SET(sh->sh_flags, claim_flags);
199 *buffer = malloc(l + 1, M_TEMP, M_WAITOK); 196 mutex_exit(&sc->sc_slave_state_lock);
200 memcpy(*buffer, start, l); 197
201 (*buffer)[l] = 0; 198 locs[SPICF_SLAVE] = chip_select;
202 ptr[count++] = *buffer; 199 sa->sa_handle = sh;
 200
 201 if (is_direct) {
 202 newdev = config_found(sc->sc_dev, sa, spi_print_direct,
 203 /* CFARG_SUBMATCH, config_stdsubmatch, XXX */
 204 CFARG_LOCATORS, locs,
 205 CFARG_DEVHANDLE, sa->sa_devhandle,
 206 CFARG_EOL);
 207 } else {
 208 if (config_probe(sc->sc_dev, cf, &sa)) {
 209 newdev = config_attach(sc->sc_dev, cf, &sa, spi_print,
 210 CFARG_LOCATORS, locs,
 211 CFARG_EOL);
 212 }
203 } 213 }
204 ptr[count] = NULL; 
205 214
206 sa->sa_compat = ptr; 215 if (newdev == NULL) {
207 sa->sa_ncompat = count; 216 /*
 217 * Clear our claim on this chip select (yes, just
 218 * the ATTACHED flag; we want to keep indirects off
 219 * of chip selects for which there is a device tree
 220 * node).
 221 */
 222 mutex_enter(&sc->sc_slave_state_lock);
 223 CLR(sh->sh_flags, SPIH_ATTACHED);
 224 mutex_exit(&sc->sc_slave_state_lock);
 225 }
208} 226}
209 227
210static void 228static int
211spi_direct_attach_child_devices(device_t parent, struct spi_softc *sc, 229spi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
212 prop_array_t child_devices) 
213{ 230{
214 unsigned int count; 231 struct spi_softc *sc = device_private(parent);
215 prop_dictionary_t child; 
216 prop_data_t cdata; 
217 uint32_t slave; 
218 uint64_t cookie; 
219 struct spi_attach_args sa; 232 struct spi_attach_args sa;
220 int loc[SPICF_NLOCS]; 
221 char *buf; 
222 int i; 
223 
224 memset(loc, 0, sizeof loc); 
225 count = prop_array_count(child_devices); 
226 for (i = 0; i < count; i++) { 
227 child = prop_array_get(child_devices, i); 
228 if (!child) 
229 continue; 
230 if (!prop_dictionary_get_uint32(child, "slave", &slave)) 
231 continue; 
232 if(slave >= sc->sc_controller.sct_nslaves) 
233 continue; 
234 if (!prop_dictionary_get_uint64(child, "cookie", &cookie)) 
235 continue; 
236 if (!(cdata = prop_dictionary_get(child, "compatible"))) 
237 continue; 
238 loc[SPICF_SLAVE] = slave; 
239 
240 memset(&sa, 0, sizeof sa); 
241 sa.sa_handle = &sc->sc_slaves[i]; 
242 sa.sa_prop = child; 
243 sa.sa_cookie = cookie; 
244 if (ISSET(sa.sa_handle->sh_flags, SPIH_ATTACHED)) 
245 continue; 
246 SET(sa.sa_handle->sh_flags, SPIH_ATTACHED); 
247 
248 buf = NULL; 
249 spi_fill_compat(&sa, 
250 prop_data_value(cdata), 
251 prop_data_size(cdata), &buf); 
252 config_found(parent, &sa, spi_print, 
253 CFARG_LOCATORS, loc, 
254 CFARG_EOL); 
255 233
256 if (sa.sa_compat) 234 if (cf->cf_loc[SPICF_SLAVE] == SPICF_SLAVE_DEFAULT) {
257 free(sa.sa_compat, M_TEMP); 235 /* No wildcards for indirect on SPI. */
258 if (buf) 236 return 0;
259 free(buf, M_TEMP); 
260 } 237 }
 238
 239 memset(&sa, 0, sizeof(sa));
 240 spi_attach_child(sc, &sa, cf->cf_loc[SPICF_SLAVE], cf);
 241
 242 return 0;
 243}
 244
 245static bool
 246spi_enumerate_devices_callback(device_t self,
 247 struct spi_enumerate_devices_args *args)
 248{
 249 struct spi_softc *sc = device_private(self);
 250
 251 spi_attach_child(sc, args->sa, args->chip_select, NULL);
 252
 253 return true; /* keep enumerating */
261} 254}
262 255
263int 256int
264spi_compatible_match(const struct spi_attach_args *sa, const cfdata_t cf, 257spi_compatible_match(const struct spi_attach_args *sa, const cfdata_t cf,
265 const struct device_compatible_entry *compats) 258 const struct device_compatible_entry *compats)
266{ 259{
267 if (sa->sa_ncompat > 0) 260 if (sa->sa_clist != NULL) {
268 return device_compatible_match(sa->sa_compat, sa->sa_ncompat, 261 return device_compatible_match_strlist(sa->sa_clist,
269 compats); 262 sa->sa_clist_size, compats);
 263 }
270 264
 265 /*
 266 * In this case, we're using indirect configuration, but SPI
 267 * has no real addressing system, and we've filtered out
 268 * wildcarded chip selects in spi_search(), so we have no
 269 * choice but to trust the user-specified config.
 270 */
271 return 1; 271 return 1;
272} 272}
273 273
274/* 
275 * API for device drivers. 
276 * 
277 * We provide wrapper routines to decouple the ABI for the SPI 
278 * device drivers from the ABI for the SPI bus drivers. 
279 */ 
280static void 274static void
281spi_attach(device_t parent, device_t self, void *aux) 275spi_attach(device_t parent, device_t self, void *aux)
282{ 276{
283 struct spi_softc *sc = device_private(self); 277 struct spi_softc *sc = device_private(self);
284 struct spibus_attach_args *sba = aux; 278 struct spibus_attach_args *sba = aux;
285 int i; 279 int i;
286 280
 281 sc->sc_dev = self;
 282
287 aprint_naive(": SPI bus\n"); 283 aprint_naive(": SPI bus\n");
288 aprint_normal(": SPI bus\n"); 284 aprint_normal(": SPI bus\n");
289 285
290 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); 286 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
 287 mutex_init(&sc->sc_slave_state_lock, MUTEX_DEFAULT, IPL_NONE);
291 cv_init(&sc->sc_cv, "spictl"); 288 cv_init(&sc->sc_cv, "spictl");
292 289
293 sc->sc_controller = *sba->sba_controller; 290 sc->sc_controller = *sba->sba_controller;
294 sc->sc_nslaves = sba->sba_controller->sct_nslaves; 291 sc->sc_nslaves = sba->sba_controller->sct_nslaves;
 292
295 /* allocate slave structures */ 293 /* allocate slave structures */
296 sc->sc_slaves = malloc(sizeof (struct spi_handle) * sc->sc_nslaves, 294 sc->sc_slaves = kmem_zalloc(sizeof(*sc->sc_slaves) * sc->sc_nslaves,
297 M_DEVBUF, M_WAITOK | M_ZERO); 295 KM_SLEEP);
298 296
299 sc->sc_speed = 0; 297 sc->sc_speed = 0;
300 sc->sc_mode = -1; 298 sc->sc_mode = -1;
301 sc->sc_slave = -1; 299 sc->sc_slave = -1;
302 300
303 /* 301 /*
304 * Initialize slave handles 302 * Initialize slave handles
305 */ 303 */
306 for (i = 0; i < sc->sc_nslaves; i++) { 304 for (i = 0; i < sc->sc_nslaves; i++) {
307 sc->sc_slaves[i].sh_slave = i; 305 sc->sc_slaves[i].sh_slave = i;
308 sc->sc_slaves[i].sh_sc = sc; 306 sc->sc_slaves[i].sh_sc = sc;
309 sc->sc_slaves[i].sh_controller = &sc->sc_controller; 307 sc->sc_slaves[i].sh_controller = &sc->sc_controller;
310 } 308 }
311 309
312 /* First attach devices known to be present via fdt */ 310 /*
313 if (sba->sba_child_devices) { 311 * Attempt to enumerate the devices on the bus using the
314 spi_direct_attach_child_devices(self, sc, sba->sba_child_devices); 312 * platform device tree.
315 } 313 */
 314 struct spi_attach_args sa = { 0 };
 315 struct spi_enumerate_devices_args enumargs = {
 316 .sa = &sa,
 317 .callback = spi_enumerate_devices_callback,
 318 };
 319 device_call(self, "spi-enumerate-devices", &enumargs);
 320
316 /* Then do any other devices the user may have manually wired */ 321 /* Then do any other devices the user may have manually wired */
317 config_search(self, NULL, 322 config_search(self, NULL,
318 CFARG_SEARCH, spi_search, 323 CFARG_SEARCH, spi_search,
319 CFARG_EOL); 324 CFARG_EOL);
320} 325}
321 326
 327CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc),
 328 spi_match, spi_attach, NULL, NULL);
 329
322static int 330static int
323spi_open(dev_t dev, int flag, int fmt, lwp_t *l) 331spi_open(dev_t dev, int flag, int fmt, lwp_t *l)
324{ 332{
325 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev)); 333 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev));
326 334
327 if (sc == NULL) 335 if (sc == NULL)
328 return ENXIO; 336 return ENXIO;
329 337
330 return 0; 338 return 0;
331} 339}
332 340
333static int 341static int
334spi_close(dev_t dev, int flag, int fmt, lwp_t *l) 342spi_close(dev_t dev, int flag, int fmt, lwp_t *l)
@@ -365,64 +373,68 @@ spi_ioctl(dev_t dev, u_long cmd, void *d @@ -365,64 +373,68 @@ spi_ioctl(dev_t dev, u_long cmd, void *d
365 if (sit->sit_addr < 0 || sit->sit_addr >= sc->sc_nslaves) { 373 if (sit->sit_addr < 0 || sit->sit_addr >= sc->sc_nslaves) {
366 error = EINVAL; 374 error = EINVAL;
367 break; 375 break;
368 } 376 }
369 if ((sit->sit_send && sit->sit_sendlen == 0) 377 if ((sit->sit_send && sit->sit_sendlen == 0)
370 || (sit->sit_recv && sit->sit_recv == 0)) { 378 || (sit->sit_recv && sit->sit_recv == 0)) {
371 error = EINVAL; 379 error = EINVAL;
372 break; 380 break;
373 } 381 }
374 sh = &sc->sc_slaves[sit->sit_addr]; 382 sh = &sc->sc_slaves[sit->sit_addr];
375 sbuf = rbuf = NULL; 383 sbuf = rbuf = NULL;
376 error = 0; 384 error = 0;
377 if (sit->sit_send && sit->sit_sendlen <= SPI_MAXDATA) { 385 if (sit->sit_send && sit->sit_sendlen <= SPI_MAXDATA) {
378 sbuf = malloc(sit->sit_sendlen, M_DEVBUF, M_WAITOK); 386 sbuf = kmem_alloc(sit->sit_sendlen, KM_SLEEP);
379 error = copyin(sit->sit_send, sbuf, sit->sit_sendlen); 387 error = copyin(sit->sit_send, sbuf, sit->sit_sendlen);
380 } 388 }
381 if (sit->sit_recv && sit->sit_recvlen <= SPI_MAXDATA) { 389 if (sit->sit_recv && sit->sit_recvlen <= SPI_MAXDATA) {
382 rbuf = malloc(sit->sit_recvlen, M_DEVBUF, M_WAITOK); 390 rbuf = kmem_alloc(sit->sit_recvlen, KM_SLEEP);
383 } 391 }
384 if (error == 0) { 392 if (error == 0) {
385 if (sbuf && rbuf) 393 if (sbuf && rbuf)
386 error = spi_send_recv(sh, 394 error = spi_send_recv(sh,
387 sit->sit_sendlen, sbuf, 395 sit->sit_sendlen, sbuf,
388 sit->sit_recvlen, rbuf); 396 sit->sit_recvlen, rbuf);
389 else if (sbuf) 397 else if (sbuf)
390 error = spi_send(sh, 398 error = spi_send(sh,
391 sit->sit_sendlen, sbuf); 399 sit->sit_sendlen, sbuf);
392 else if (rbuf) 400 else if (rbuf)
393 error = spi_recv(sh, 401 error = spi_recv(sh,
394 sit->sit_recvlen, rbuf); 402 sit->sit_recvlen, rbuf);
395 } 403 }
396 if (rbuf) { 404 if (rbuf) {
397 if (error == 0) 405 if (error == 0)
398 error = copyout(rbuf, sit->sit_recv, 406 error = copyout(rbuf, sit->sit_recv,
399 sit->sit_recvlen); 407 sit->sit_recvlen);
400 free(rbuf, M_DEVBUF); 408 kmem_free(rbuf, sit->sit_recvlen);
401 } 409 }
402 if (sbuf) { 410 if (sbuf) {
403 free(sbuf, M_DEVBUF); 411 kmem_free(sbuf, sit->sit_sendlen);
404 } 412 }
405 break; 413 break;
406 default: 414 default:
407 error = ENODEV; 415 error = ENODEV;
408 break; 416 break;
409 } 417 }
410 418
411 return error; 419 return error;
412} 420}
413 421
414CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc), 422/*
415 spi_match, spi_attach, NULL, NULL); 423 * API for device drivers.
 424 *
 425 * We provide wrapper routines to decouple the ABI for the SPI
 426 * device drivers from the ABI for the SPI bus drivers.
 427 */
416 428
417/* 429/*
418 * Configure. This should be the first thing that the SPI driver 430 * Configure. This should be the first thing that the SPI driver
419 * should do, to configure which mode (e.g. SPI_MODE_0, which is the 431 * should do, to configure which mode (e.g. SPI_MODE_0, which is the
420 * same as Philips Microwire mode), and speed. If the bus driver 432 * same as Philips Microwire mode), and speed. If the bus driver
421 * cannot run fast enough, then it should just configure the fastest 433 * cannot run fast enough, then it should just configure the fastest
422 * mode that it can support. If the bus driver cannot run slow 434 * mode that it can support. If the bus driver cannot run slow
423 * enough, then the device is incompatible and an error should be 435 * enough, then the device is incompatible and an error should be
424 * returned. 436 * returned.
425 */ 437 */
426int 438int
427spi_configure(struct spi_handle *sh, int mode, int speed) 439spi_configure(struct spi_handle *sh, int mode, int speed)
428{ 440{
@@ -652,14 +664,13 @@ spi_send_recv(struct spi_handle *sh, int @@ -652,14 +664,13 @@ spi_send_recv(struct spi_handle *sh, int
652 spi_chunk_init(&chunk2, rcnt, NULL, rcv); 664 spi_chunk_init(&chunk2, rcnt, NULL, rcv);
653 spi_transfer_add(&trans, &chunk1); 665 spi_transfer_add(&trans, &chunk1);
654 spi_transfer_add(&trans, &chunk2); 666 spi_transfer_add(&trans, &chunk2);
655 667
656 /* enqueue it and wait for it to complete */ 668 /* enqueue it and wait for it to complete */
657 spi_transfer(sh, &trans); 669 spi_transfer(sh, &trans);
658 spi_wait(&trans); 670 spi_wait(&trans);
659 671
660 if (trans.st_flags & SPI_F_ERROR) 672 if (trans.st_flags & SPI_F_ERROR)
661 return trans.st_errno; 673 return trans.st_errno;
662 674
663 return 0; 675 return 0;
664} 676}
665 

cvs diff -r1.10 -r1.10.6.1 src/sys/dev/spi/spivar.h (expand / switch to unified diff)

--- src/sys/dev/spi/spivar.h 2020/08/04 13:20:45 1.10
+++ src/sys/dev/spi/spivar.h 2021/05/18 23:48:16 1.10.6.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: spivar.h,v 1.10 2020/08/04 13:20:45 kardel Exp $ */ 1/* $NetBSD: spivar.h,v 1.10.6.1 2021/05/18 23:48:16 thorpej Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore. 5 * Copyright (c) 2006 Garrett D'Amore.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Portions of this code were written by Garrett D'Amore for the 8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project. 9 * Champaign-Urbana Community Wireless Network Project.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or 11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following 12 * without modification, are permitted provided that the following
13 * conditions are met: 13 * conditions are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -67,38 +67,50 @@ struct spi_transfer; @@ -67,38 +67,50 @@ struct spi_transfer;
67 67
68struct spi_controller { 68struct spi_controller {
69 void *sct_cookie; /* controller private data */ 69 void *sct_cookie; /* controller private data */
70 int sct_nslaves; 70 int sct_nslaves;
71 int (*sct_configure)(void *, int, int, int); 71 int (*sct_configure)(void *, int, int, int);
72 int (*sct_transfer)(void *, struct spi_transfer *); 72 int (*sct_transfer)(void *, struct spi_transfer *);
73}; 73};
74 74
75int spibus_print(void *, const char *); 75int spibus_print(void *, const char *);
76 76
77/* one per chip select */ 77/* one per chip select */
78struct spibus_attach_args { 78struct spibus_attach_args {
79 struct spi_controller *sba_controller; 79 struct spi_controller *sba_controller;
80 prop_array_t sba_child_devices; 
81}; 80};
82 81
83struct spi_attach_args { 82struct spi_attach_args {
84 struct spi_handle *sa_handle; 83 struct spi_handle *sa_handle;
 84
85 /* only set if using direct config */ 85 /* only set if using direct config */
86 int sa_ncompat; /* number of pointers in the 86 const char *sa_name; /* name of the device */
87 ia_compat array */ 87 const char *sa_clist; /* compatible strlist */
88 const char ** sa_compat; /* chip names */ 88 size_t sa_clist_size; /* size of compatible strlist */
89 prop_dictionary_t sa_prop; /* dictionary for this device */ 89 devhandle_t sa_devhandle; /* device handle for the device */
 90};
90 91
91 uintptr_t sa_cookie; /* OF node in openfirmware machines */ 92/*
 93 * spi-enumerate-devices device call
 94 *
 95 * Enumerates the devices connected to the SPI bus, filling out
 96 * the spi_attach_args and invoking the callback for each one.
 97 * If the callback returns true, then enumeration continues. If
 98 * the callback returns false, enumeration is stopped.
 99 */
 100struct spi_enumerate_devices_args {
 101 struct spi_attach_args *sa;
 102 bool (*callback)(device_t, struct spi_enumerate_devices_args *);
 103 int chip_select;
92}; 104};
93 105
94/* 106/*
95 * This is similar in some respects to struct buf, but we cannot use 107 * This is similar in some respects to struct buf, but we cannot use
96 * that structure because it was not designed to support full-duplex 108 * that structure because it was not designed to support full-duplex
97 * IO. 109 * IO.
98 */ 110 */
99struct spi_chunk { 111struct spi_chunk {
100 struct spi_chunk *chunk_next; 112 struct spi_chunk *chunk_next;
101 int chunk_count; 113 int chunk_count;
102 uint8_t *chunk_read; 114 uint8_t *chunk_read;
103 const uint8_t *chunk_write; 115 const uint8_t *chunk_write;
104 /* for private use by framework and bus driver */ 116 /* for private use by framework and bus driver */