xref: /illumos-gate/usr/src/uts/common/io/gpio/kgpio.c (revision fd71220ba0fafcc9cf5ea0785db206f3f31336e7)
1*fd71220bSRobert Mustacchi /*
2*fd71220bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*fd71220bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*fd71220bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*fd71220bSRobert Mustacchi  * 1.0 of the CDDL.
6*fd71220bSRobert Mustacchi  *
7*fd71220bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*fd71220bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*fd71220bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*fd71220bSRobert Mustacchi  */
11*fd71220bSRobert Mustacchi 
12*fd71220bSRobert Mustacchi /*
13*fd71220bSRobert Mustacchi  * Copyright 2022 Oxide Computer Company
14*fd71220bSRobert Mustacchi  */
15*fd71220bSRobert Mustacchi 
16*fd71220bSRobert Mustacchi /*
17*fd71220bSRobert Mustacchi  * Kernel GPIO Framework
18*fd71220bSRobert Mustacchi  * ---------------------
19*fd71220bSRobert Mustacchi  *
20*fd71220bSRobert Mustacchi  * This driver, kgpio(4D), implements the general kernel general purpose I/O
21*fd71220bSRobert Mustacchi  * (GPIO) and dedicated purpose I/O (dpio) framework discussed in gpio(7).
22*fd71220bSRobert Mustacchi  * Before we jump into the organization and specifics here, let's go into a few
23*fd71220bSRobert Mustacchi  * definitions and overviews of what all is going on:
24*fd71220bSRobert Mustacchi  *
25*fd71220bSRobert Mustacchi  * GPIO -- General Purpose I/O
26*fd71220bSRobert Mustacchi  *
27*fd71220bSRobert Mustacchi  *	A GPIO is something that allows software to directly understand and
28*fd71220bSRobert Mustacchi  *	manipulate the state of a particular pin on an ASIC. For example, this
29*fd71220bSRobert Mustacchi  *	allows software to do things like to read the logical level on a pin or
30*fd71220bSRobert Mustacchi  *	to set the logical output value. In addition, there are often other
31*fd71220bSRobert Mustacchi  *	properties that can be changed such as things like whether internal pull
32*fd71220bSRobert Mustacchi  *	ups are used, controls around interrupt behavior, drive strength, etc.
33*fd71220bSRobert Mustacchi  *	Each of these different controls vary from controller to controller.
34*fd71220bSRobert Mustacchi  *	Each of these is represented as an 'attribute', which is defined below.
35*fd71220bSRobert Mustacchi  *
36*fd71220bSRobert Mustacchi  * GPIO CONTROLLER / PROVIDER
37*fd71220bSRobert Mustacchi  *
38*fd71220bSRobert Mustacchi  *	A GPIO controller is a piece of hardware that provides accesses to and
39*fd71220bSRobert Mustacchi  *	control over GPIOs. In the OS, we call a device driver for a GPIO
40*fd71220bSRobert Mustacchi  *	controller a kgpio provider, as it provides access to and the
41*fd71220bSRobert Mustacchi  *	functionality around this. Device drivers themselves use the
42*fd71220bSRobert Mustacchi  *	<sys/gpio/kgpio_provider.h> header and related functions.
43*fd71220bSRobert Mustacchi  *
44*fd71220bSRobert Mustacchi  *	Each controller is exposed to userland through its own character device
45*fd71220bSRobert Mustacchi  *	in /devices. There are not entries in /dev for these. The providing
46*fd71220bSRobert Mustacchi  *	device driver does not have to worry about this and this takes care of
47*fd71220bSRobert Mustacchi  *	ensuring that the provider is present, allowing them to detach like
48*fd71220bSRobert Mustacchi  *	other classes of loadable modules.
49*fd71220bSRobert Mustacchi  *
50*fd71220bSRobert Mustacchi  * ATTRIBUTE
51*fd71220bSRobert Mustacchi  *
52*fd71220bSRobert Mustacchi  *	An attribute refers to a setting or property of a GPIO. While many
53*fd71220bSRobert Mustacchi  *	controllers have similar attributes, in many cases the actual set of
54*fd71220bSRobert Mustacchi  *	valid values varies between them (or potentially even from GPIO to GPIO
55*fd71220bSRobert Mustacchi  *	on a device). Attributes are stored inside of nvlist_t's (more on that
56*fd71220bSRobert Mustacchi  *	later) and consist of a few different pieces of information:
57*fd71220bSRobert Mustacchi  *
58*fd71220bSRobert Mustacchi  *	  o Name	This is how software and humans generally refer to a
59*fd71220bSRobert Mustacchi  *			name for this attribute. The attribute name is generally
60*fd71220bSRobert Mustacchi  *			made up of two parts: the provider's name and then the
61*fd71220bSRobert Mustacchi  *			actual name. This allows different providers to not
62*fd71220bSRobert Mustacchi  *			conflict with one another. These are both separated by
63*fd71220bSRobert Mustacchi  *			a ':' character. Examples here are things like
64*fd71220bSRobert Mustacchi  *			'sim:pull' which is used by the gpio_sim driver. Here
65*fd71220bSRobert Mustacchi  *			'sim' refers to the provider and 'pull' the name.
66*fd71220bSRobert Mustacchi  *
67*fd71220bSRobert Mustacchi  *	  o Value	This is the actual value of the attribute for a given
68*fd71220bSRobert Mustacchi  *			GPIO. It generally is a uint32_t (representing an enum)
69*fd71220bSRobert Mustacchi  *			or a string.
70*fd71220bSRobert Mustacchi  *
71*fd71220bSRobert Mustacchi  *	  o Protection	This indicates whether the attribute is read-only or
72*fd71220bSRobert Mustacchi  *			read-write. A read-write attribute can be updated by a
73*fd71220bSRobert Mustacchi  *			consumer.
74*fd71220bSRobert Mustacchi  *
75*fd71220bSRobert Mustacchi  *	  o Possible	This is an array of values that are valid for this
76*fd71220bSRobert Mustacchi  *			particular attribute. This information is specific to a
77*fd71220bSRobert Mustacchi  *			GPIO.
78*fd71220bSRobert Mustacchi  *
79*fd71220bSRobert Mustacchi  * DPIO -- Dedicated Purpose I/O
80*fd71220bSRobert Mustacchi  *
81*fd71220bSRobert Mustacchi  *	A DPIO is a construct that wraps up a GPIO, constraining what it can do
82*fd71220bSRobert Mustacchi  *	and freezing the ability to set all of its attributes except a small
83*fd71220bSRobert Mustacchi  *	set. Their reason for existence is to try and solve the problem that
84*fd71220bSRobert Mustacchi  *	while a GPIO controller is specific to a given piece of hardware (like a
85*fd71220bSRobert Mustacchi  *	specific CPU or ASIC), what is safe to use depends entirely on the
86*fd71220bSRobert Mustacchi  *	specifics of the way that is used. For example, which GPIOs are safe to
87*fd71220bSRobert Mustacchi  *	use on a CPU depends on the specific motherboard it's found in and the
88*fd71220bSRobert Mustacchi  *	surrounding pieces. Instead, this is where we offer the idea of the DPIO
89*fd71220bSRobert Mustacchi  *	as its purpose is dedicated.
90*fd71220bSRobert Mustacchi  *
91*fd71220bSRobert Mustacchi  *	DPIOs show up to the system as their own character device with basic
92*fd71220bSRobert Mustacchi  *	semantics around read(2), write(2), and poll(2). The DPIO devices show
93*fd71220bSRobert Mustacchi  *	up in /dev/dpio/<name> and all of the specifics of them are defined in
94*fd71220bSRobert Mustacchi  *	their own header <sys/gpio/dpio.h>.
95*fd71220bSRobert Mustacchi  *
96*fd71220bSRobert Mustacchi  *	An important part that we'll get into in the driver organization is that
97*fd71220bSRobert Mustacchi  *	each DPIO points to its corresponding GPIO controller.
98*fd71220bSRobert Mustacchi  *
99*fd71220bSRobert Mustacchi  * IOMUX -- I/O Multiplexer
100*fd71220bSRobert Mustacchi  *
101*fd71220bSRobert Mustacchi  *	An I/O multiplexer is something that exists in hardware that maps which
102*fd71220bSRobert Mustacchi  *	peripherals are actually connected to which pins. Many SoCs are designed
103*fd71220bSRobert Mustacchi  *	such that an actual pin on the device can be pointed at one of several
104*fd71220bSRobert Mustacchi  *	different peripherals.
105*fd71220bSRobert Mustacchi  *
106*fd71220bSRobert Mustacchi  *	Right now, the GPIO framework is not integrated into any kind of I/O or
107*fd71220bSRobert Mustacchi  *	pin muxing framework. This means that GPIOs that are visible may or may
108*fd71220bSRobert Mustacchi  *	not do anything based on the state of that mux. This is a known missing
109*fd71220bSRobert Mustacchi  *	piece and is something that will see further consolidation.
110*fd71220bSRobert Mustacchi  *
111*fd71220bSRobert Mustacchi  * -------------------
112*fd71220bSRobert Mustacchi  * Driver Organization
113*fd71220bSRobert Mustacchi  * -------------------
114*fd71220bSRobert Mustacchi  *
115*fd71220bSRobert Mustacchi  * To understand how this driver is organized, it's worth going into a bit more
116*fd71220bSRobert Mustacchi  * detail about the framework and what entities we track.
117*fd71220bSRobert Mustacchi  *
118*fd71220bSRobert Mustacchi  * Fundamentally a GPIO controller and is mapped to its provider driver. More
119*fd71220bSRobert Mustacchi  * specifically, the dev_info_t is the key that we used to build up and manage a
120*fd71220bSRobert Mustacchi  * controller in the kgpio_t structure. These providers will register with the
121*fd71220bSRobert Mustacchi  * kgpio kernel module when they call attach(9E) and detach(9E).
122*fd71220bSRobert Mustacchi  *
123*fd71220bSRobert Mustacchi  * When a provider registers with us, they tell us how many GPIOs they support.
124*fd71220bSRobert Mustacchi  * This gives us a set of unsigned integer GPIO IDs that are in the set [0,
125*fd71220bSRobert Mustacchi  * kgpio_ngpios). The general framework always refers to a GPIO on a controller
126*fd71220bSRobert Mustacchi  * by its numeric ID.  This ID space is contiguous, which may not be true of the
127*fd71220bSRobert Mustacchi  * actual hardware. It is not our intent that this is the same thing. Instead,
128*fd71220bSRobert Mustacchi  * for more semantics, GPIOs have a common 'name' attribute which providers fill
129*fd71220bSRobert Mustacchi  * in that userland can consume. However, the kernel identifies all GPIOs by
130*fd71220bSRobert Mustacchi  * their controller and a provider-supplied opaque ID. The kgpio driver does
131*fd71220bSRobert Mustacchi  * not track individual GPIOs.
132*fd71220bSRobert Mustacchi  *
133*fd71220bSRobert Mustacchi  * Because we need to provide character devices ourselves, the kgpio driver has
134*fd71220bSRobert Mustacchi  * its own instance which is a child of the pseudo nexus. Importantly, krtld
135*fd71220bSRobert Mustacchi  * guarantees that our module is loaded before anything that would call into us;
136*fd71220bSRobert Mustacchi  * however, it does not guarantee anything about whether a particular instance
137*fd71220bSRobert Mustacchi  * will be present. This in turn leads to us keeping global structure and state
138*fd71220bSRobert Mustacchi  * in the driver which is independent from our actual instance because the
139*fd71220bSRobert Mustacchi  * instance may come and go.
140*fd71220bSRobert Mustacchi  *
141*fd71220bSRobert Mustacchi  * In turn, the framework does keep track of all of the DPIOs that are created
142*fd71220bSRobert Mustacchi  * because these are independent character devices and minors. These are stored
143*fd71220bSRobert Mustacchi  * in data that isn't tied to the instance mostly for the reason as the core of
144*fd71220bSRobert Mustacchi  * the GPIO framework. Each DPIO's information is tracked in a 'dpio_t'
145*fd71220bSRobert Mustacchi  * structure.
146*fd71220bSRobert Mustacchi  *
147*fd71220bSRobert Mustacchi  * To facilitate the fact that the character device entry points all operate in
148*fd71220bSRobert Mustacchi  * terms of minors, we have a shared structure that is embedded in both the
149*fd71220bSRobert Mustacchi  * kgpio_t and dpio_t called a kgpio_minor_t. These are stored in a global
150*fd71220bSRobert Mustacchi  * avl_tree_t and is how minors are mapped back to their device type and actual
151*fd71220bSRobert Mustacchi  * information.
152*fd71220bSRobert Mustacchi  *
153*fd71220bSRobert Mustacchi  * The organization of data is roughly as follows (some members elided):
154*fd71220bSRobert Mustacchi  *
155*fd71220bSRobert Mustacchi  *
156*fd71220bSRobert Mustacchi  *     +-----------------------+
157*fd71220bSRobert Mustacchi  *     | Global DPIO List      |
158*fd71220bSRobert Mustacchi  *     |                       |       +-------------+   +-------------+
159*fd71220bSRobert Mustacchi  *     | list_t kgpio_g_dpios -+------>| DPIO dpio_t |-->| DPIO dpio_t |--> ...
160*fd71220bSRobert Mustacchi  *     +-----------------------+       | "foo"       |   | "bar"       |
161*fd71220bSRobert Mustacchi  *                                     |             |   |             |
162*fd71220bSRobert Mustacchi  *                                     | gpio ID     |   | gpio ID     |
163*fd71220bSRobert Mustacchi  *  +--------------------------------->| kgpio_t *   |   | kgpio_t *   |
164*fd71220bSRobert Mustacchi  *  |                                  +-------------+   +-------------+
165*fd71220bSRobert Mustacchi  *  |                                      |                |
166*fd71220bSRobert Mustacchi  *  |  +------------------------+          |   +------------+
167*fd71220bSRobert Mustacchi  *  |  | Global Controller List |          v   v
168*fd71220bSRobert Mustacchi  *  |  |                        |     +-------------+   +-------------+
169*fd71220bSRobert Mustacchi  *  |  | list_t kgpio_g_gpios --+---->| kgpio_t     |-->| kgpio_t     |--> ...
170*fd71220bSRobert Mustacchi  *  |  +------------------------+     |             |   |             |
171*fd71220bSRobert Mustacchi  *  |                                 | dev_info_t  |   | dev_info_t  |
172*fd71220bSRobert Mustacchi  *  +-------------------------------->| kgpio_ops_t |   | kgpio_ops_t |
173*fd71220bSRobert Mustacchi  *  |                                 +-------------+   +-------------+
174*fd71220bSRobert Mustacchi  *  |                                                      |
175*fd71220bSRobert Mustacchi  *  |  +-------------------------+                         |
176*fd71220bSRobert Mustacchi  *  |  | Global Minor Tracking   |                         v
177*fd71220bSRobert Mustacchi  *  |  |                         |                    +---------------------+
178*fd71220bSRobert Mustacchi  *  +--| avl_tree_t kgpio_minors |                    | GPIO Provider       |
179*fd71220bSRobert Mustacchi  *     +-------------------------+                    |                     |
180*fd71220bSRobert Mustacchi  *                                                    | A hardware-specific |
181*fd71220bSRobert Mustacchi  *                                                    | driver              |
182*fd71220bSRobert Mustacchi  *                                                    +---------------------+
183*fd71220bSRobert Mustacchi  *
184*fd71220bSRobert Mustacchi  * In more detail, all of our global data is protected by the kgpio_g_mutex and
185*fd71220bSRobert Mustacchi  * all such data is prefixed with 'kgpio_g_'. As GPIO Provider drivers register
186*fd71220bSRobert Mustacchi  * with kgpio framework via kgpio_register(), we create a kgpio_t for them and
187*fd71220bSRobert Mustacchi  * insert them into the global kgpio_g_dpios list. At that point, we do a few
188*fd71220bSRobert Mustacchi  * additional things:
189*fd71220bSRobert Mustacchi  *
190*fd71220bSRobert Mustacchi  *   o If our main kgpio(4D) instance is attached, then we will go through and
191*fd71220bSRobert Mustacchi  *     create a minor node for the controller. If not, this will be deferred
192*fd71220bSRobert Mustacchi  *     until it does attach.
193*fd71220bSRobert Mustacchi  *
194*fd71220bSRobert Mustacchi  *   o We will register a DDI callback for when the module is removed from the
195*fd71220bSRobert Mustacchi  *     system, which is a step past being detached. This is what allows us to
196*fd71220bSRobert Mustacchi  *     call back a provider when someone wants to use it, just as the /devices
197*fd71220bSRobert Mustacchi  *     devfs file system normally does.
198*fd71220bSRobert Mustacchi  *
199*fd71220bSRobert Mustacchi  * At that point, we will flow data and back and forth via ioctls on the
200*fd71220bSRobert Mustacchi  * controller minor nodes. As information is asked for by userland, the kgpio
201*fd71220bSRobert Mustacchi  * driver will call back into the provider with the provided kgpio_ops_t
202*fd71220bSRobert Mustacchi  * operations vector and the driver's private data (both passed in at
203*fd71220bSRobert Mustacchi  * registration time).
204*fd71220bSRobert Mustacchi  *
205*fd71220bSRobert Mustacchi  * Only when a user comes and asks to create a DPIO via the
206*fd71220bSRobert Mustacchi  * KGPIO_IOC_DPIO_CREATE ioctl will we go through and at that point create a
207*fd71220bSRobert Mustacchi  * dpio_t. The dpio_t is stored in its own global list and each dpio_t points to
208*fd71220bSRobert Mustacchi  * the corresponding kgpio_t controller and contains the GPIO that it should
209*fd71220bSRobert Mustacchi  * use. In addition, there are a number of fields set at creation time which
210*fd71220bSRobert Mustacchi  * relate to the capabilities of the DPIO which are what govern whether the DPIO
211*fd71220bSRobert Mustacchi  * supports read(9E), write(9E), etc.
212*fd71220bSRobert Mustacchi  *
213*fd71220bSRobert Mustacchi  * When a DPIO is created a minor node is created with the type
214*fd71220bSRobert Mustacchi  * DDI_NT_GPIO_DPIO. While users can give a DPIO any name they want, we prefix
215*fd71220bSRobert Mustacchi  * each name in /devices with 'dpio:'. This ensures that a user's name for a
216*fd71220bSRobert Mustacchi  * DPIO will not conflict with any controllers that may come and go in the
217*fd71220bSRobert Mustacchi  * system. The devfsadm(8) plugs for GPIO subsystem will ensure that a DPIO is
218*fd71220bSRobert Mustacchi  * created under /dev/dpio with the user's requested name. The 'dpio:' leading
219*fd71220bSRobert Mustacchi  * portion of the /devices minor node will not be present.
220*fd71220bSRobert Mustacchi  *
221*fd71220bSRobert Mustacchi  * There is one final type of minor node that exists, which is called 'dpinfo'
222*fd71220bSRobert Mustacchi  * which is used to provide static, creation-time based information about DPIOs.
223*fd71220bSRobert Mustacchi  * This exists because we generally want to support the ability to both create
224*fd71220bSRobert Mustacchi  * DPIOs that honor O_EXCL/FEXCL and DPIOs that only the kernel can open. As
225*fd71220bSRobert Mustacchi  * such, this minor can be used to query about basic information about a DPIO
226*fd71220bSRobert Mustacchi  * without requiring one to be able to open it (which may not be possible).
227*fd71220bSRobert Mustacchi  *
228*fd71220bSRobert Mustacchi  * ---------
229*fd71220bSRobert Mustacchi  * Data Flow
230*fd71220bSRobert Mustacchi  * ---------
231*fd71220bSRobert Mustacchi  *
232*fd71220bSRobert Mustacchi  * There are two different high-leveling goals in the data design in this
233*fd71220bSRobert Mustacchi  * system:
234*fd71220bSRobert Mustacchi  *
235*fd71220bSRobert Mustacchi  *   o Hardware should be the single source of truth (where possible) for the
236*fd71220bSRobert Mustacchi  *     current values of a GPIO's attributes. That is why there is no caching of
237*fd71220bSRobert Mustacchi  *     data either in this driver or in the individual providers. Doing
238*fd71220bSRobert Mustacchi  *     anything else allows for things to get out of sync.
239*fd71220bSRobert Mustacchi  *
240*fd71220bSRobert Mustacchi  *   o Where possible, all data about a GPIO should be something that we can
241*fd71220bSRobert Mustacchi  *     atomically change. In general, it can be very hard to trace a series of
242*fd71220bSRobert Mustacchi  *     valid steps from point a to point b for a GPIO, if you cannot change
243*fd71220bSRobert Mustacchi  *     multiple attributes at once. While there are always complications here
244*fd71220bSRobert Mustacchi  *     because of pin and I/O muxing, this is why there is no individual
245*fd71220bSRobert Mustacchi  *     attribute get and set routines.
246*fd71220bSRobert Mustacchi  *
247*fd71220bSRobert Mustacchi  * When getting and setting information, a GPIO's attributes are all stored in a
248*fd71220bSRobert Mustacchi  * single nvlist_t. Here, each key is the name of an attribute which points to
249*fd71220bSRobert Mustacchi  * its corresponding value -- generally a string or uint32_t. In addition, there
250*fd71220bSRobert Mustacchi  * is an embedded metadata nvlist_t that has information such as the protection
251*fd71220bSRobert Mustacchi  * or supported values for a given GPIO.
252*fd71220bSRobert Mustacchi  *
253*fd71220bSRobert Mustacchi  * All of this information is considered GPIO-specific because each GPIO in a
254*fd71220bSRobert Mustacchi  * system may have readily different capabilities and functionality. While there
255*fd71220bSRobert Mustacchi  * are common attributes which are defined in <sys/gpio/kgpio_provider.h>, the
256*fd71220bSRobert Mustacchi  * expectation is that each provider defines its own attributes (other than
257*fd71220bSRobert Mustacchi  * name) in their own header file that generally should be found in
258*fd71220bSRobert Mustacchi  * <sys/gpio/driver.h>, where driver is the name of the driver. Let's look at an
259*fd71220bSRobert Mustacchi  * example of this structure if we had four attributes present:
260*fd71220bSRobert Mustacchi  *
261*fd71220bSRobert Mustacchi  * nvlist_t
262*fd71220bSRobert Mustacchi  *	"name"		-> string
263*fd71220bSRobert Mustacchi  *	"zen:output"	-> uint32
264*fd71220bSRobert Mustacchi  *	"zen:input"	-> uint32
265*fd71220bSRobert Mustacchi  *	"zen:pull"	-> uint32
266*fd71220bSRobert Mustacchi  *	"metadata"	-> nvlist_t
267*fd71220bSRobert Mustacchi  *			"name"		-> nvlist_t
268*fd71220bSRobert Mustacchi  *					"protection"	-> uint32
269*fd71220bSRobert Mustacchi  *			"zen:output":	-> nvlist_t
270*fd71220bSRobert Mustacchi  *					"protection"	-> uint32
271*fd71220bSRobert Mustacchi  *					"possible"	-> uint32[]
272*fd71220bSRobert Mustacchi  *			"zen:input":	-> nvlist_t
273*fd71220bSRobert Mustacchi  *					"protection"	-> uint32
274*fd71220bSRobert Mustacchi  *					"possible"	-> uint32[]
275*fd71220bSRobert Mustacchi  *			"zen:pull":	-> nvlist_t
276*fd71220bSRobert Mustacchi  *					"protection"	-> uint32
277*fd71220bSRobert Mustacchi  *					"possible"	-> uint32[]
278*fd71220bSRobert Mustacchi  *
279*fd71220bSRobert Mustacchi  * Basically what we see here is that every attribute is a top-level key. The
280*fd71220bSRobert Mustacchi  * metadata is an nvlist_t where each key is the of an attribute which points to
281*fd71220bSRobert Mustacchi  * an nvlist_t. The type of "possible" will match its underlying data type. The
282*fd71220bSRobert Mustacchi  * metadata information is only provided by providers themselves when getting an
283*fd71220bSRobert Mustacchi  * attribute. When an attribute is set, there is no metadata present. As in the
284*fd71220bSRobert Mustacchi  * case of "name", something like the possible values can be omitted (in this
285*fd71220bSRobert Mustacchi  * case because it's read-only). While metadata is strictly optional, it is
286*fd71220bSRobert Mustacchi  * useful to include as it helps users understand what is going on.
287*fd71220bSRobert Mustacchi  *
288*fd71220bSRobert Mustacchi  * When coming up with attributes, there is no need for there to be a strict 1:1
289*fd71220bSRobert Mustacchi  * mapping with hardware fields. In fact, providers should try to phrase things
290*fd71220bSRobert Mustacchi  * such that people cannot create a state that is unsupported. For example, some
291*fd71220bSRobert Mustacchi  * hardware may have two register settings: one for whether something is level
292*fd71220bSRobert Mustacchi  * triggered and one for which edges should generate the interrupt. In this
293*fd71220bSRobert Mustacchi  * case, if done simply, one could set an illegal value which is level triggered
294*fd71220bSRobert Mustacchi  * on both the rising and falling edge which the hardware warns against. Rather
295*fd71220bSRobert Mustacchi  * than allowing this to happen, the provider should instead come up with a
296*fd71220bSRobert Mustacchi  * single semantic attribute so that way users can't end up in illegal states.
297*fd71220bSRobert Mustacchi  *
298*fd71220bSRobert Mustacchi  * Next we should turn our attention to the data flow for DPIOs. Where as GPIOs
299*fd71220bSRobert Mustacchi  * allow the provider to define everything about them, DPIOs are different.
300*fd71220bSRobert Mustacchi  * Instead, our DPIO operation vectors are all about taking narrowly defined
301*fd71220bSRobert Mustacchi  * types in <sys/gpio/dpio.h> such as the dpio_input_t and the dpio_output_t and
302*fd71220bSRobert Mustacchi  * having the provider map that to hardware states. Right now we have a limited
303*fd71220bSRobert Mustacchi  * number of input and output values. Providers may not have a way to map every
304*fd71220bSRobert Mustacchi  * possible state to one of our values. Similarly, there may be values that they
305*fd71220bSRobert Mustacchi  * cannot represent in their hardware implementation. In these cases, providers
306*fd71220bSRobert Mustacchi  * must fail the various DPIO requests. We require that consumers always read
307*fd71220bSRobert Mustacchi  * and write a uint32_t value and that is enforced for providers. This is done
308*fd71220bSRobert Mustacchi  * to give us future flexibility in the set of values we may support.
309*fd71220bSRobert Mustacchi  *
310*fd71220bSRobert Mustacchi  * ------------------------------------------
311*fd71220bSRobert Mustacchi  * Provider Lifecycle, Locking, and Lifetimes
312*fd71220bSRobert Mustacchi  * ------------------------------------------
313*fd71220bSRobert Mustacchi  *
314*fd71220bSRobert Mustacchi  * The most nuanced piece of this driver and framework is that we have to refer
315*fd71220bSRobert Mustacchi  * to other driver's dev_info_t data structures and we want to allow those
316*fd71220bSRobert Mustacchi  * things to be detached normally. A normal driver would attach and create minor
317*fd71220bSRobert Mustacchi  * nodes, then detach when it no longer exists. However, when this detach is not
318*fd71220bSRobert Mustacchi  * the driver being removed, devfs would notice this and when a minor node is
319*fd71220bSRobert Mustacchi  * accessed bring it back to life. While this is a nice feature, like with the
320*fd71220bSRobert Mustacchi  * kernel sensor subsystem, we end up having to do a bunch of this ourselves
321*fd71220bSRobert Mustacchi  * because we are responsible for all the minors.
322*fd71220bSRobert Mustacchi  *
323*fd71220bSRobert Mustacchi  * This tradeoff centralizes the complexity in one spot rather than having each
324*fd71220bSRobert Mustacchi  * provider have to reimplement cb_ops and more that they otherwise wouldn't
325*fd71220bSRobert Mustacchi  * even need to or have to think about minors (which helps if they have their
326*fd71220bSRobert Mustacchi  * own for any reason). With that in mind, it's worth laying out some
327*fd71220bSRobert Mustacchi  * understanding of how this works and when we need to check and worry about
328*fd71220bSRobert Mustacchi  * this:
329*fd71220bSRobert Mustacchi  *
330*fd71220bSRobert Mustacchi  *   o If a GPIO controller is actively open, that is someone called open(9E) on
331*fd71220bSRobert Mustacchi  *     its minor, then we know that the dev_info_t is attached and present.
332*fd71220bSRobert Mustacchi  *
333*fd71220bSRobert Mustacchi  *   o Whenever a DPIO exists, it always has a hold on its underlying
334*fd71220bSRobert Mustacchi  *     controller, regardless of whether the controller is open or not.
335*fd71220bSRobert Mustacchi  *
336*fd71220bSRobert Mustacchi  *   o When a GPIO provider driver detaches, it will call back into us. At that
337*fd71220bSRobert Mustacchi  *     point we consider it invalid.
338*fd71220bSRobert Mustacchi  *
339*fd71220bSRobert Mustacchi  *   o When a GPIO provider driver registers with us, we know it is valid.
340*fd71220bSRobert Mustacchi  *
341*fd71220bSRobert Mustacchi  *   o The DDI will call back into us when the device driver is actually removed
342*fd71220bSRobert Mustacchi  *     from the system (e.g. rem_drv), giving us a cue as to when everything is
343*fd71220bSRobert Mustacchi  *     fully gone and we can finally tear down our state.
344*fd71220bSRobert Mustacchi  *
345*fd71220bSRobert Mustacchi  * With this in mind, our actual task and rules are fairly straightforward and
346*fd71220bSRobert Mustacchi  * can be summarized as: when we are in open(9E) and are opening a controller,
347*fd71220bSRobert Mustacchi  * we must check if it is valid (KGPIO_F_VALID) and if not, attempt to make it
348*fd71220bSRobert Mustacchi  * valid again. Any other character device operation that is coming in we don't
349*fd71220bSRobert Mustacchi  * have to worry about it because it is in that state by definition. This state
350*fd71220bSRobert Mustacchi  * diagram can be summarized as:
351*fd71220bSRobert Mustacchi  *
352*fd71220bSRobert Mustacchi  *           |
353*fd71220bSRobert Mustacchi  *           +-------<-----------------------------------<---------+
354*fd71220bSRobert Mustacchi  *           |                                                     |
355*fd71220bSRobert Mustacchi  *           | . . driver calls kgpio_register()                   |
356*fd71220bSRobert Mustacchi  *           v                                                     |
357*fd71220bSRobert Mustacchi  *       +-------+                                                 |
358*fd71220bSRobert Mustacchi  *       | Valid |                                                 |
359*fd71220bSRobert Mustacchi  *       +-------+                                                 ^
360*fd71220bSRobert Mustacchi  *           |                                                     |
361*fd71220bSRobert Mustacchi  *           | . . driver calls kgpio_unregister().                |
362*fd71220bSRobert Mustacchi  *           v                                                     |
363*fd71220bSRobert Mustacchi  *      +---------+                                                |
364*fd71220bSRobert Mustacchi  *      | Invalid |                                                |
365*fd71220bSRobert Mustacchi  *      +---------+                                                |
366*fd71220bSRobert Mustacchi  *        |     |                                                  |
367*fd71220bSRobert Mustacchi  *        |     | . . user calls open on a controller              |
368*fd71220bSRobert Mustacchi  *        |     |     minor node                                   |
369*fd71220bSRobert Mustacchi  *        |     +------------------+                               |
370*fd71220bSRobert Mustacchi  *        |                        |                               ^
371*fd71220bSRobert Mustacchi  *        |                        |                               |
372*fd71220bSRobert Mustacchi  *        |                        v                               |
373*fd71220bSRobert Mustacchi  *        |               +-------------------+                    |
374*fd71220bSRobert Mustacchi  *        |               | ndi_devi_config() |-->-.---------------+
375*fd71220bSRobert Mustacchi  *        |               +-------------------+    . . driver attach(9E) called
376*fd71220bSRobert Mustacchi  *        |                                |
377*fd71220bSRobert Mustacchi  *        | . . DDI's unbind callback      |
378*fd71220bSRobert Mustacchi  *        |     fires as driver is         |
379*fd71220bSRobert Mustacchi  *        |     being removed              |
380*fd71220bSRobert Mustacchi  *        v                                | . . attach failed or there
381*fd71220bSRobert Mustacchi  *   +---------+                           |     was no call to
382*fd71220bSRobert Mustacchi  *   | kgpio_t |<--------------------------+     kgpio_register() again
383*fd71220bSRobert Mustacchi  *   | Deleted |
384*fd71220bSRobert Mustacchi  *   +---------+
385*fd71220bSRobert Mustacchi  *
386*fd71220bSRobert Mustacchi  * The heavy lifting is done in the rather involved function, kgpio_hold_by_id.
387*fd71220bSRobert Mustacchi  * In that, if we find that the KGPIO_F_VALID and KGPIO_F_HELD are both present,
388*fd71220bSRobert Mustacchi  * then we're in the earlier simple case described above. Otherwise, if not, we
389*fd71220bSRobert Mustacchi  * then have to consider the fact that multiple threads may all be trying to get
390*fd71220bSRobert Mustacchi  * here for some reason (e.g. concurrent calls to open(9E)).
391*fd71220bSRobert Mustacchi  *
392*fd71220bSRobert Mustacchi  * The first thread that takes control of the process of validating something
393*fd71220bSRobert Mustacchi  * sets the KGPIO_F_META_WORK flag. Any other thread that finds this flag set
394*fd71220bSRobert Mustacchi  * simply waits on it to finish. When these blocked threads are signaled, they
395*fd71220bSRobert Mustacchi  * restart the entire validation process again. Once the meta flag is owned, we
396*fd71220bSRobert Mustacchi  * proceed to take the NDI hold which ensures that the dev_info_t shouldn't be
397*fd71220bSRobert Mustacchi  * able to go away. At that point, we will attempt to attach the driver if it's
398*fd71220bSRobert Mustacchi  * not attached. If it is, then we are done.
399*fd71220bSRobert Mustacchi  *
400*fd71220bSRobert Mustacchi  * The NDI hold will persist as long as the device is open. Similarly, as
401*fd71220bSRobert Mustacchi  * mentioned above, each DPIO that exists puts a similar NDI hold on the
402*fd71220bSRobert Mustacchi  * underlying dev_info_t.
403*fd71220bSRobert Mustacchi  *
404*fd71220bSRobert Mustacchi  * The benefit of this whole dance is that it guarantees that an open controller
405*fd71220bSRobert Mustacchi  * node cannot disappear at all during any other cb_ops, simplifying lifetime
406*fd71220bSRobert Mustacchi  * considerations. Basically when calling open(9E) we need to consider it, but
407*fd71220bSRobert Mustacchi  * once open, we're good until close(9E).
408*fd71220bSRobert Mustacchi  *
409*fd71220bSRobert Mustacchi  * This ties in directly into the locking hierarchy in the system. There are
410*fd71220bSRobert Mustacchi  * three classes of locks that exist, which are ordered by the order in which
411*fd71220bSRobert Mustacchi  * they should be taken.
412*fd71220bSRobert Mustacchi  *
413*fd71220bSRobert Mustacchi  *  1. The global kgpio_g_mutex, which protects all of the global data
414*fd71220bSRobert Mustacchi  *     structures.
415*fd71220bSRobert Mustacchi  *  2. The mutex embedded in the dpio_t structure.
416*fd71220bSRobert Mustacchi  *  3. The mutex embedded in the kgpio_t structure.
417*fd71220bSRobert Mustacchi  *
418*fd71220bSRobert Mustacchi  * When dealing with locking, one must always take the kgpio_g_mutex before one
419*fd71220bSRobert Mustacchi  * ever takes either of the kgpio_mutex or dpio_mutex inside the kgpio_t and
420*fd71220bSRobert Mustacchi  * dpio_t. Most of the data that is required for the DPIO to perform I/O on the
421*fd71220bSRobert Mustacchi  * underlying GPIO is read-only data. In general, one should not hold both a
422*fd71220bSRobert Mustacchi  * dpio_t and kgpio_t mutex at the same time. Finally, if you need to call into
423*fd71220bSRobert Mustacchi  * the NDI or enter a parent, none of our locks should be held.
424*fd71220bSRobert Mustacchi  *
425*fd71220bSRobert Mustacchi  * The lifetime of the dpio_t structure is tied to someone creating and
426*fd71220bSRobert Mustacchi  * destroying it with ioctls (KGPIO_IOC_DPIO_CREATE and KGPIO_IOC_DPIO_DESTROY).
427*fd71220bSRobert Mustacchi  * A DPIO cannot be destroyed if someone is using it. This means that like the
428*fd71220bSRobert Mustacchi  * kgpio_t, once you get through the open(9E) call, you can assume that it will
429*fd71220bSRobert Mustacchi  * always be valid. In addition, the kgpio_t that is attached to it always will
430*fd71220bSRobert Mustacchi  * be. Unlike the kgpio_t, the dpio_t hold process is much simpler. As long as
431*fd71220bSRobert Mustacchi  * the dpio is findable in the global list (with the global mutex held), then it
432*fd71220bSRobert Mustacchi  * is valid.
433*fd71220bSRobert Mustacchi  *
434*fd71220bSRobert Mustacchi  * Ideally, the combination of these two pieces leads to making the actual
435*fd71220bSRobert Mustacchi  * design and implementation here much simpler in other parts and ultimately,
436*fd71220bSRobert Mustacchi  * makes the system easier to reason about.
437*fd71220bSRobert Mustacchi  *
438*fd71220bSRobert Mustacchi  * ---------------------------------
439*fd71220bSRobert Mustacchi  * Future Integrations, Shortcomings
440*fd71220bSRobert Mustacchi  * ---------------------------------
441*fd71220bSRobert Mustacchi  *
442*fd71220bSRobert Mustacchi  * At this time, the implementation of the framework has been designed around
443*fd71220bSRobert Mustacchi  * erring on the side of simplicity and enabling end to end functionality.
444*fd71220bSRobert Mustacchi  * Several of the choices such as using nvlist_t's, the presence of metadata,
445*fd71220bSRobert Mustacchi  * and the design of DPIOs are focused on that. Here are things that this
446*fd71220bSRobert Mustacchi  * currently doesn't do and may have varying degrees of challenges:
447*fd71220bSRobert Mustacchi  *
448*fd71220bSRobert Mustacchi  *   o The attribute and DPIO interface are not designed around the need to
449*fd71220bSRobert Mustacchi  *     sometimes implement various peripherals via bit-banging GPIOs. For such
450*fd71220bSRobert Mustacchi  *     cases, an alternative set of interfaces which allows a consumer to batch
451*fd71220bSRobert Mustacchi  *     up a series of changes to a GPIO with any optional delays that are all
452*fd71220bSRobert Mustacchi  *     executed at once is probably what should be used. Because the initial
453*fd71220bSRobert Mustacchi  *     needs do not require this, we have not pretended to come up with a good
454*fd71220bSRobert Mustacchi  *     consumerless API.
455*fd71220bSRobert Mustacchi  *
456*fd71220bSRobert Mustacchi  *   o Right now we are using simple intrusive lists for DPIOs and GPIOs. There
457*fd71220bSRobert Mustacchi  *     is no easy way to go from a GPIO and see which DPIOs point into it. When
458*fd71220bSRobert Mustacchi  *     this becomes a bottelneck (e.g. as part of delivering polling results),
459*fd71220bSRobert Mustacchi  *     then that would be the time to improve things here and add something akin
460*fd71220bSRobert Mustacchi  *     to an AVL to the kgpio_t that includes all of its DPIOs.
461*fd71220bSRobert Mustacchi  *
462*fd71220bSRobert Mustacchi  *   o We currently don't support any chpoll(9E) interfaces. The intent here is
463*fd71220bSRobert Mustacchi  *     that there would be a single pollhead per dpio_t that is shared between
464*fd71220bSRobert Mustacchi  *     anyone who calls chpoll(9E) on the dpio_t. This would be paired with a
465*fd71220bSRobert Mustacchi  *     callback function for a provider to call back into us. Importantly
466*fd71220bSRobert Mustacchi  *     though, when that is added, we should ensure that the providers are
467*fd71220bSRobert Mustacchi  *     instructed not to hold any locks across the call.
468*fd71220bSRobert Mustacchi  *
469*fd71220bSRobert Mustacchi  *   o Right now there is no integration with pin and I/O muxing, meaning that
470*fd71220bSRobert Mustacchi  *     it is possible that anything set in the GPIO controller's hardware may
471*fd71220bSRobert Mustacchi  *     have no effect. This is an area of future research and work.
472*fd71220bSRobert Mustacchi  *
473*fd71220bSRobert Mustacchi  *   o There is currently a forced 1:1 relationship between the provider and the
474*fd71220bSRobert Mustacchi  *     dev_info_t. The provider also can't determine its own name. While these
475*fd71220bSRobert Mustacchi  *     are simpler problems to solve, the broader problem (which extends beyond
476*fd71220bSRobert Mustacchi  *     just the GPIO framework) is how to name and relate providers to semantic
477*fd71220bSRobert Mustacchi  *     things that a user actually knows about and may not have a stable
478*fd71220bSRobert Mustacchi  *     /devices path for the consumer to rely upon.
479*fd71220bSRobert Mustacchi  */
480*fd71220bSRobert Mustacchi 
481*fd71220bSRobert Mustacchi #include <sys/types.h>
482*fd71220bSRobert Mustacchi #include <sys/file.h>
483*fd71220bSRobert Mustacchi #include <sys/errno.h>
484*fd71220bSRobert Mustacchi #include <sys/open.h>
485*fd71220bSRobert Mustacchi #include <sys/cred.h>
486*fd71220bSRobert Mustacchi #include <sys/ddi.h>
487*fd71220bSRobert Mustacchi #include <sys/sunddi.h>
488*fd71220bSRobert Mustacchi #include <sys/stat.h>
489*fd71220bSRobert Mustacchi #include <sys/conf.h>
490*fd71220bSRobert Mustacchi #include <sys/devops.h>
491*fd71220bSRobert Mustacchi #include <sys/cmn_err.h>
492*fd71220bSRobert Mustacchi #include <sys/list.h>
493*fd71220bSRobert Mustacchi #include <sys/stddef.h>
494*fd71220bSRobert Mustacchi #include <sys/sunndi.h>
495*fd71220bSRobert Mustacchi #include <sys/esunddi.h>
496*fd71220bSRobert Mustacchi #include <sys/taskq.h>
497*fd71220bSRobert Mustacchi #include <sys/id_space.h>
498*fd71220bSRobert Mustacchi #include <sys/sysmacros.h>
499*fd71220bSRobert Mustacchi #include <sys/avl.h>
500*fd71220bSRobert Mustacchi #include <sys/stdbool.h>
501*fd71220bSRobert Mustacchi #include <sys/ctype.h>
502*fd71220bSRobert Mustacchi #include <sys/fs/dv_node.h>
503*fd71220bSRobert Mustacchi 
504*fd71220bSRobert Mustacchi #include <sys/gpio/kgpio_provider.h>
505*fd71220bSRobert Mustacchi #include <sys/gpio/kgpio.h>
506*fd71220bSRobert Mustacchi #include <sys/gpio/dpio.h>
507*fd71220bSRobert Mustacchi 
508*fd71220bSRobert Mustacchi #define	KGPIO_CTRL_NAMELEN	DPIO_NAMELEN
509*fd71220bSRobert Mustacchi 
510*fd71220bSRobert Mustacchi typedef enum {
511*fd71220bSRobert Mustacchi 	/*
512*fd71220bSRobert Mustacchi 	 * This flag is used to indicate that the minor node is registered. It
513*fd71220bSRobert Mustacchi 	 * is possible for this not to happen if a provider comes in before the
514*fd71220bSRobert Mustacchi 	 * kgpio instance is force attached.
515*fd71220bSRobert Mustacchi 	 */
516*fd71220bSRobert Mustacchi 	KGPIO_F_MINOR_VALID	= 1 << 0,
517*fd71220bSRobert Mustacchi 	/*
518*fd71220bSRobert Mustacchi 	 * This flag tracks the notion of whether or not we believe the
519*fd71220bSRobert Mustacchi 	 * underlying driver instance is active and attached. When the producer
520*fd71220bSRobert Mustacchi 	 * is deatching this will be cleared and this is our call to try to open
521*fd71220bSRobert Mustacchi 	 * it up again.
522*fd71220bSRobert Mustacchi 	 */
523*fd71220bSRobert Mustacchi 	KGPIO_F_VALID		= 1 << 1,
524*fd71220bSRobert Mustacchi 	/*
525*fd71220bSRobert Mustacchi 	 * This indicates that the underlying driver instance represented by the
526*fd71220bSRobert Mustacchi 	 * kgpio_t has a DDI hold on it. This is established in a controller's
527*fd71220bSRobert Mustacchi 	 * first open and removed when it is closed. Note, this is used as part
528*fd71220bSRobert Mustacchi 	 * of manipulating the controller node. DPIOs will also have holds on
529*fd71220bSRobert Mustacchi 	 * the underlying dev_info_t that are tracked with their lifetime.
530*fd71220bSRobert Mustacchi 	 */
531*fd71220bSRobert Mustacchi 	KGPIO_F_HELD		= 1 << 2,
532*fd71220bSRobert Mustacchi 	/*
533*fd71220bSRobert Mustacchi 	 * This flag is a stage beyond having cleared KGPIO_F_VALID. At this
534*fd71220bSRobert Mustacchi 	 * point, the driver this is associated with is actually going away and
535*fd71220bSRobert Mustacchi 	 * therefore this truly is getting cleaned up.
536*fd71220bSRobert Mustacchi 	 */
537*fd71220bSRobert Mustacchi 	KGPIO_F_REMOVED		= 1 << 3,
538*fd71220bSRobert Mustacchi 	/*
539*fd71220bSRobert Mustacchi 	 * This flag is used to synchronize the act of holding and/or attaching
540*fd71220bSRobert Mustacchi 	 * a given kgpio. There can only be one at a time. This is only ever
541*fd71220bSRobert Mustacchi 	 * used in open. close(9E) does not require this because of the
542*fd71220bSRobert Mustacchi 	 * exclusion guarantees of the kernel.
543*fd71220bSRobert Mustacchi 	 */
544*fd71220bSRobert Mustacchi 	KGPIO_F_META_WORK	= 1 << 4
545*fd71220bSRobert Mustacchi } kgpio_flags_t;
546*fd71220bSRobert Mustacchi 
547*fd71220bSRobert Mustacchi struct kgpio;
548*fd71220bSRobert Mustacchi struct dpio;
549*fd71220bSRobert Mustacchi 
550*fd71220bSRobert Mustacchi typedef enum {
551*fd71220bSRobert Mustacchi 	/*
552*fd71220bSRobert Mustacchi 	 * This is a GPIO controller. It is represented by a kgpio_t.
553*fd71220bSRobert Mustacchi 	 */
554*fd71220bSRobert Mustacchi 	KGPIO_MINOR_T_CTRL,
555*fd71220bSRobert Mustacchi 	/*
556*fd71220bSRobert Mustacchi 	 * This is a DPIO entry. It is represented by a dpio_t.
557*fd71220bSRobert Mustacchi 	 */
558*fd71220bSRobert Mustacchi 	KGPIO_MINOR_T_DPIO,
559*fd71220bSRobert Mustacchi 	/*
560*fd71220bSRobert Mustacchi 	 * This is a general interface that is used to get static information
561*fd71220bSRobert Mustacchi 	 * about DPIOs. Nothing in the kminor_data is valid.
562*fd71220bSRobert Mustacchi 	 */
563*fd71220bSRobert Mustacchi 	KGPIO_MINOR_T_DPINFO
564*fd71220bSRobert Mustacchi } kgpio_minor_type_t;
565*fd71220bSRobert Mustacchi 
566*fd71220bSRobert Mustacchi typedef struct kgpio_minor {
567*fd71220bSRobert Mustacchi 	avl_node_t kminor_avl;
568*fd71220bSRobert Mustacchi 	id_t kminor_id;
569*fd71220bSRobert Mustacchi 	kgpio_minor_type_t kminor_type;
570*fd71220bSRobert Mustacchi 	union {
571*fd71220bSRobert Mustacchi 		struct dpio *kminor_dpio;
572*fd71220bSRobert Mustacchi 		struct kgpio *kminor_ctrl;
573*fd71220bSRobert Mustacchi 	} kminor_data;
574*fd71220bSRobert Mustacchi } kgpio_minor_t;
575*fd71220bSRobert Mustacchi 
576*fd71220bSRobert Mustacchi typedef struct kgpio {
577*fd71220bSRobert Mustacchi 	kgpio_minor_t kgpio_minor;
578*fd71220bSRobert Mustacchi 	list_node_t kgpio_link;
579*fd71220bSRobert Mustacchi 	dev_info_t *kgpio_dip;
580*fd71220bSRobert Mustacchi 	uint32_t kgpio_ngpios;
581*fd71220bSRobert Mustacchi 	const kgpio_ops_t *kgpio_ops;
582*fd71220bSRobert Mustacchi 	void *kgpio_drv;
583*fd71220bSRobert Mustacchi 	ddi_unbind_callback_t kgpio_cb;
584*fd71220bSRobert Mustacchi 	char kgpio_mname[KGPIO_CTRL_NAMELEN];
585*fd71220bSRobert Mustacchi 	kmutex_t kgpio_mutex;
586*fd71220bSRobert Mustacchi 	kcondvar_t kgpio_cv;
587*fd71220bSRobert Mustacchi 	kgpio_flags_t kgpio_flags;
588*fd71220bSRobert Mustacchi 	uint32_t kgpio_ndpios;
589*fd71220bSRobert Mustacchi } kgpio_t;
590*fd71220bSRobert Mustacchi 
591*fd71220bSRobert Mustacchi /*
592*fd71220bSRobert Mustacchi  * This is designed to give us space for 'dpio:' and then whatever name
593*fd71220bSRobert Mustacchi  * the user gives us. This is done to avoid having someone try to create a dpio
594*fd71220bSRobert Mustacchi  * that would conflict with a controller name.
595*fd71220bSRobert Mustacchi  */
596*fd71220bSRobert Mustacchi #define	KGPIO_DPIO_INT_NAMELEN	(KGPIO_DPIO_NAMELEN + 8)
597*fd71220bSRobert Mustacchi 
598*fd71220bSRobert Mustacchi typedef enum {
599*fd71220bSRobert Mustacchi 	/*
600*fd71220bSRobert Mustacchi 	 * This is used to indicate that the dpio is actually open.
601*fd71220bSRobert Mustacchi 	 */
602*fd71220bSRobert Mustacchi 	DPIO_S_OPEN		= 1 << 0,
603*fd71220bSRobert Mustacchi 	/*
604*fd71220bSRobert Mustacchi 	 * This indicates that the DPIO is open exclusively right now.
605*fd71220bSRobert Mustacchi 	 */
606*fd71220bSRobert Mustacchi 	DPIO_S_EXCL		= 1 << 1
607*fd71220bSRobert Mustacchi } dpio_status_t;
608*fd71220bSRobert Mustacchi 
609*fd71220bSRobert Mustacchi typedef struct dpio {
610*fd71220bSRobert Mustacchi 	kgpio_minor_t dpio_minor;
611*fd71220bSRobert Mustacchi 	list_node_t dpio_link;
612*fd71220bSRobert Mustacchi 	char dpio_name[KGPIO_DPIO_INT_NAMELEN];
613*fd71220bSRobert Mustacchi 	kgpio_t *dpio_kgpio;
614*fd71220bSRobert Mustacchi 	uint32_t dpio_gpio_num;
615*fd71220bSRobert Mustacchi 	dpio_caps_t dpio_caps;
616*fd71220bSRobert Mustacchi 	dpio_flags_t dpio_flags;
617*fd71220bSRobert Mustacchi 	/*
618*fd71220bSRobert Mustacchi 	 * All fields above this point are read-only and set at DPIO creation
619*fd71220bSRobert Mustacchi 	 * time.
620*fd71220bSRobert Mustacchi 	 */
621*fd71220bSRobert Mustacchi 	kmutex_t dpio_mutex;
622*fd71220bSRobert Mustacchi 	hrtime_t dpio_last_intr;
623*fd71220bSRobert Mustacchi 	hrtime_t dpio_last_write;
624*fd71220bSRobert Mustacchi 	dpio_status_t dpio_status;
625*fd71220bSRobert Mustacchi } dpio_t;
626*fd71220bSRobert Mustacchi 
627*fd71220bSRobert Mustacchi /*
628*fd71220bSRobert Mustacchi  * Various definitions related to minor numbers. The first minor is what we use
629*fd71220bSRobert Mustacchi  * for the kgpio id_space. This starts at two as we reserve the minor number 1
630*fd71220bSRobert Mustacchi  * for the dpinfo entry and we assume that 0 is reserved to aid in debugging /
631*fd71220bSRobert Mustacchi  * initialization.
632*fd71220bSRobert Mustacchi  */
633*fd71220bSRobert Mustacchi #define	KGPIO_MINOR_DPINFO	1
634*fd71220bSRobert Mustacchi #define	KGPIO_MINOR_FIRST	2
635*fd71220bSRobert Mustacchi #define	KGPIO_MINOR_NAME_DPINFO	"dpinfo"
636*fd71220bSRobert Mustacchi 
637*fd71220bSRobert Mustacchi /*
638*fd71220bSRobert Mustacchi  * This is the maximum size of a user nvlist_t that we're willing to consider in
639*fd71220bSRobert Mustacchi  * the kernel. This value is a rough swag of what we think the maximum size
640*fd71220bSRobert Mustacchi  * nvlist would ever be for a single GPIO with headroom. This is here in case
641*fd71220bSRobert Mustacchi  * someone has need to tune it to unblock something.
642*fd71220bSRobert Mustacchi  */
643*fd71220bSRobert Mustacchi size_t kgpio_max_user_nvl = 512 * 1024;
644*fd71220bSRobert Mustacchi 
645*fd71220bSRobert Mustacchi static dev_info_t *kgpio_g_dip;
646*fd71220bSRobert Mustacchi static kmutex_t kgpio_g_mutex;
647*fd71220bSRobert Mustacchi static list_t kgpio_g_gpios;
648*fd71220bSRobert Mustacchi static list_t kgpio_g_dpios;
649*fd71220bSRobert Mustacchi static avl_tree_t kgpio_g_minors;
650*fd71220bSRobert Mustacchi static id_space_t *kgpio_g_ids;
651*fd71220bSRobert Mustacchi static kgpio_minor_t kgpio_g_dpinfo;
652*fd71220bSRobert Mustacchi 
653*fd71220bSRobert Mustacchi static int
kgpio_minor_comparator(const void * l,const void * r)654*fd71220bSRobert Mustacchi kgpio_minor_comparator(const void *l, const void *r)
655*fd71220bSRobert Mustacchi {
656*fd71220bSRobert Mustacchi 	const kgpio_minor_t *kml = l;
657*fd71220bSRobert Mustacchi 	const kgpio_minor_t *kmr = r;
658*fd71220bSRobert Mustacchi 
659*fd71220bSRobert Mustacchi 	if (kml->kminor_id > kmr->kminor_id) {
660*fd71220bSRobert Mustacchi 		return (1);
661*fd71220bSRobert Mustacchi 	} else if (kml->kminor_id < kmr->kminor_id) {
662*fd71220bSRobert Mustacchi 		return (-1);
663*fd71220bSRobert Mustacchi 	} else {
664*fd71220bSRobert Mustacchi 		return (0);
665*fd71220bSRobert Mustacchi 	}
666*fd71220bSRobert Mustacchi }
667*fd71220bSRobert Mustacchi 
668*fd71220bSRobert Mustacchi static kgpio_t *
kgpio_find_by_dip(dev_info_t * dip)669*fd71220bSRobert Mustacchi kgpio_find_by_dip(dev_info_t *dip)
670*fd71220bSRobert Mustacchi {
671*fd71220bSRobert Mustacchi 	kgpio_t *k;
672*fd71220bSRobert Mustacchi 
673*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio_g_mutex));
674*fd71220bSRobert Mustacchi 	for (k = list_head(&kgpio_g_gpios); k != NULL;
675*fd71220bSRobert Mustacchi 	    k = list_next(&kgpio_g_gpios, k)) {
676*fd71220bSRobert Mustacchi 		if (k->kgpio_dip == dip) {
677*fd71220bSRobert Mustacchi 			return (k);
678*fd71220bSRobert Mustacchi 		}
679*fd71220bSRobert Mustacchi 	}
680*fd71220bSRobert Mustacchi 
681*fd71220bSRobert Mustacchi 	return (NULL);
682*fd71220bSRobert Mustacchi }
683*fd71220bSRobert Mustacchi 
684*fd71220bSRobert Mustacchi static kgpio_minor_t *
kgpio_minor_find(id_t minor)685*fd71220bSRobert Mustacchi kgpio_minor_find(id_t minor)
686*fd71220bSRobert Mustacchi {
687*fd71220bSRobert Mustacchi 	kgpio_minor_t idx = { 0 };
688*fd71220bSRobert Mustacchi 
689*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio_g_mutex));
690*fd71220bSRobert Mustacchi 	idx.kminor_id = minor;
691*fd71220bSRobert Mustacchi 
692*fd71220bSRobert Mustacchi 	return (avl_find(&kgpio_g_minors, &idx, NULL));
693*fd71220bSRobert Mustacchi }
694*fd71220bSRobert Mustacchi 
695*fd71220bSRobert Mustacchi static void
kgpio_dpio_cleanup(dpio_t * dpio)696*fd71220bSRobert Mustacchi kgpio_dpio_cleanup(dpio_t *dpio)
697*fd71220bSRobert Mustacchi {
698*fd71220bSRobert Mustacchi 	if (dpio->dpio_minor.kminor_id > 0) {
699*fd71220bSRobert Mustacchi 		id_free(kgpio_g_ids, dpio->dpio_minor.kminor_id);
700*fd71220bSRobert Mustacchi 		dpio->dpio_minor.kminor_id = 0;
701*fd71220bSRobert Mustacchi 	}
702*fd71220bSRobert Mustacchi 	ddi_remove_minor_node(kgpio_g_dip, dpio->dpio_name);
703*fd71220bSRobert Mustacchi 	mutex_destroy(&dpio->dpio_mutex);
704*fd71220bSRobert Mustacchi 	kmem_free(dpio, sizeof (dpio_t));
705*fd71220bSRobert Mustacchi }
706*fd71220bSRobert Mustacchi 
707*fd71220bSRobert Mustacchi static void
kgpio_cleanup(kgpio_t * kgpio)708*fd71220bSRobert Mustacchi kgpio_cleanup(kgpio_t *kgpio)
709*fd71220bSRobert Mustacchi {
710*fd71220bSRobert Mustacchi 	if (kgpio->kgpio_minor.kminor_id > 0) {
711*fd71220bSRobert Mustacchi 		id_free(kgpio_g_ids, kgpio->kgpio_minor.kminor_id);
712*fd71220bSRobert Mustacchi 		kgpio->kgpio_minor.kminor_id = 0;
713*fd71220bSRobert Mustacchi 	}
714*fd71220bSRobert Mustacchi 	cv_destroy(&kgpio->kgpio_cv);
715*fd71220bSRobert Mustacchi 	mutex_destroy(&kgpio->kgpio_mutex);
716*fd71220bSRobert Mustacchi 	kmem_free(kgpio, sizeof (kgpio_t));
717*fd71220bSRobert Mustacchi }
718*fd71220bSRobert Mustacchi 
719*fd71220bSRobert Mustacchi static void
kgpio_unbind_taskq(void * arg)720*fd71220bSRobert Mustacchi kgpio_unbind_taskq(void *arg)
721*fd71220bSRobert Mustacchi {
722*fd71220bSRobert Mustacchi 	kgpio_t *kgpio = arg;
723*fd71220bSRobert Mustacchi 
724*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
725*fd71220bSRobert Mustacchi 	if ((kgpio->kgpio_flags & KGPIO_F_MINOR_VALID) != 0) {
726*fd71220bSRobert Mustacchi 		kgpio->kgpio_flags &= ~KGPIO_F_MINOR_VALID;
727*fd71220bSRobert Mustacchi 		(void) ddi_remove_minor_node(kgpio_g_dip, kgpio->kgpio_mname);
728*fd71220bSRobert Mustacchi 	}
729*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
730*fd71220bSRobert Mustacchi 
731*fd71220bSRobert Mustacchi 	kgpio_cleanup(kgpio);
732*fd71220bSRobert Mustacchi }
733*fd71220bSRobert Mustacchi 
734*fd71220bSRobert Mustacchi static void
kgpio_unbind_cb(void * arg,dev_info_t * dip)735*fd71220bSRobert Mustacchi kgpio_unbind_cb(void *arg, dev_info_t *dip)
736*fd71220bSRobert Mustacchi {
737*fd71220bSRobert Mustacchi 	kgpio_t *kgpio = arg;
738*fd71220bSRobert Mustacchi 
739*fd71220bSRobert Mustacchi 	/*
740*fd71220bSRobert Mustacchi 	 * We have reached here because a driver that was registered with us is
741*fd71220bSRobert Mustacchi 	 * actually going away. As such it is now time for us to finally let go
742*fd71220bSRobert Mustacchi 	 * of it and free it so as to no longer attempt to keep it around and
743*fd71220bSRobert Mustacchi 	 * reattach it. At this point in time we are still in the context of the
744*fd71220bSRobert Mustacchi 	 * detaching thread in the devinfo tree. As such, here we note that it
745*fd71220bSRobert Mustacchi 	 * is going away and in the system taskq do the work to finish cleaning
746*fd71220bSRobert Mustacchi 	 * it up. After this point it cannot be looked up and held, so only
747*fd71220bSRobert Mustacchi 	 * existing opens that are racing with us will be here.
748*fd71220bSRobert Mustacchi 	 */
749*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
750*fd71220bSRobert Mustacchi 	list_remove(&kgpio_g_gpios, kgpio);
751*fd71220bSRobert Mustacchi 	avl_remove(&kgpio_g_minors, &kgpio->kgpio_minor);
752*fd71220bSRobert Mustacchi 	kgpio->kgpio_flags |= KGPIO_F_REMOVED;
753*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
754*fd71220bSRobert Mustacchi 
755*fd71220bSRobert Mustacchi 	(void) taskq_dispatch(system_taskq, kgpio_unbind_taskq, kgpio,
756*fd71220bSRobert Mustacchi 	    TQ_SLEEP);
757*fd71220bSRobert Mustacchi }
758*fd71220bSRobert Mustacchi 
759*fd71220bSRobert Mustacchi int
kgpio_unregister(dev_info_t * dip)760*fd71220bSRobert Mustacchi kgpio_unregister(dev_info_t *dip)
761*fd71220bSRobert Mustacchi {
762*fd71220bSRobert Mustacchi 	kgpio_t *kgpio;
763*fd71220bSRobert Mustacchi 
764*fd71220bSRobert Mustacchi 	if (dip == NULL) {
765*fd71220bSRobert Mustacchi 		return (EINVAL);
766*fd71220bSRobert Mustacchi 	}
767*fd71220bSRobert Mustacchi 
768*fd71220bSRobert Mustacchi 	if (!DEVI_IS_ATTACHING(dip) && !DEVI_IS_DETACHING(dip)) {
769*fd71220bSRobert Mustacchi 		return (EAGAIN);
770*fd71220bSRobert Mustacchi 	}
771*fd71220bSRobert Mustacchi 
772*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
773*fd71220bSRobert Mustacchi 	kgpio = kgpio_find_by_dip(dip);
774*fd71220bSRobert Mustacchi 	if (kgpio == NULL) {
775*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
776*fd71220bSRobert Mustacchi 		return (ENOENT);
777*fd71220bSRobert Mustacchi 	}
778*fd71220bSRobert Mustacchi 	kgpio->kgpio_flags &= ~KGPIO_F_VALID;
779*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
780*fd71220bSRobert Mustacchi 
781*fd71220bSRobert Mustacchi 	return (0);
782*fd71220bSRobert Mustacchi }
783*fd71220bSRobert Mustacchi 
784*fd71220bSRobert Mustacchi /*
785*fd71220bSRobert Mustacchi  * Attempt to create a minor node for the kgpio. Because of the fact that the
786*fd71220bSRobert Mustacchi  * producer can register before we have a dev_info_t there's not a lot we can do
787*fd71220bSRobert Mustacchi  * other than complain and hope someone notices on failure.
788*fd71220bSRobert Mustacchi  */
789*fd71220bSRobert Mustacchi static void
kgpio_create_minor(kgpio_t * kgpio)790*fd71220bSRobert Mustacchi kgpio_create_minor(kgpio_t *kgpio)
791*fd71220bSRobert Mustacchi {
792*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio->kgpio_mutex));
793*fd71220bSRobert Mustacchi 
794*fd71220bSRobert Mustacchi 	if (ddi_create_minor_node(kgpio_g_dip, kgpio->kgpio_mname, S_IFCHR,
795*fd71220bSRobert Mustacchi 	    (minor_t)kgpio->kgpio_minor.kminor_id, DDI_NT_GPIO_CTRL, 0) != 0) {
796*fd71220bSRobert Mustacchi 		dev_err(kgpio_g_dip, CE_WARN, "failed to create minor node "
797*fd71220bSRobert Mustacchi 		    "%s", kgpio->kgpio_mname);
798*fd71220bSRobert Mustacchi 	} else {
799*fd71220bSRobert Mustacchi 		kgpio->kgpio_flags |= KGPIO_F_MINOR_VALID;
800*fd71220bSRobert Mustacchi 	}
801*fd71220bSRobert Mustacchi }
802*fd71220bSRobert Mustacchi 
803*fd71220bSRobert Mustacchi int
kgpio_register(dev_info_t * dip,const kgpio_ops_t * ops,void * arg,uint32_t ngpio)804*fd71220bSRobert Mustacchi kgpio_register(dev_info_t *dip, const kgpio_ops_t *ops, void *arg,
805*fd71220bSRobert Mustacchi     uint32_t ngpio)
806*fd71220bSRobert Mustacchi {
807*fd71220bSRobert Mustacchi 	kgpio_t *kgpio;
808*fd71220bSRobert Mustacchi 
809*fd71220bSRobert Mustacchi 	if (dip == NULL || ops == NULL || ops->kgo_get == NULL ||
810*fd71220bSRobert Mustacchi 	    ops->kgo_set == NULL || ngpio == 0) {
811*fd71220bSRobert Mustacchi 		return (EINVAL);
812*fd71220bSRobert Mustacchi 	}
813*fd71220bSRobert Mustacchi 
814*fd71220bSRobert Mustacchi 	if (!DEVI_IS_ATTACHING(dip)) {
815*fd71220bSRobert Mustacchi 		return (EAGAIN);
816*fd71220bSRobert Mustacchi 	}
817*fd71220bSRobert Mustacchi 
818*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
819*fd71220bSRobert Mustacchi 	kgpio = kgpio_find_by_dip(dip);
820*fd71220bSRobert Mustacchi 	if (kgpio != NULL) {
821*fd71220bSRobert Mustacchi 		mutex_enter(&kgpio->kgpio_mutex);
822*fd71220bSRobert Mustacchi 		if ((kgpio->kgpio_flags & KGPIO_F_VALID) != 0) {
823*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio->kgpio_mutex);
824*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio_g_mutex);
825*fd71220bSRobert Mustacchi 			return (EEXIST);
826*fd71220bSRobert Mustacchi 		}
827*fd71220bSRobert Mustacchi 
828*fd71220bSRobert Mustacchi 		if (kgpio->kgpio_ngpios != ngpio) {
829*fd71220bSRobert Mustacchi 			dev_err(dip, CE_WARN, "failed to register with gpio "
830*fd71220bSRobert Mustacchi 			    "framework, number of GPIOs changed from %u to %u",
831*fd71220bSRobert Mustacchi 			    kgpio->kgpio_ngpios, ngpio);
832*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio->kgpio_mutex);
833*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio_g_mutex);
834*fd71220bSRobert Mustacchi 			return (ESTALE);
835*fd71220bSRobert Mustacchi 		}
836*fd71220bSRobert Mustacchi 
837*fd71220bSRobert Mustacchi 		/*
838*fd71220bSRobert Mustacchi 		 * We've found a match for this gpio. Assume that the pointers
839*fd71220bSRobert Mustacchi 		 * it's given us have changed, but otherwise, we don't need to
840*fd71220bSRobert Mustacchi 		 * recreate anything in the kgpio_t.
841*fd71220bSRobert Mustacchi 		 */
842*fd71220bSRobert Mustacchi 		kgpio->kgpio_flags |= KGPIO_F_VALID;
843*fd71220bSRobert Mustacchi 		kgpio->kgpio_ops = ops;
844*fd71220bSRobert Mustacchi 		kgpio->kgpio_drv = arg;
845*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
846*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
847*fd71220bSRobert Mustacchi 		return (0);
848*fd71220bSRobert Mustacchi 	}
849*fd71220bSRobert Mustacchi 
850*fd71220bSRobert Mustacchi 	kgpio = kmem_zalloc(sizeof (kgpio_t), KM_SLEEP);
851*fd71220bSRobert Mustacchi 	kgpio->kgpio_dip = dip;
852*fd71220bSRobert Mustacchi 	kgpio->kgpio_ngpios = ngpio;
853*fd71220bSRobert Mustacchi 	kgpio->kgpio_ops = ops;
854*fd71220bSRobert Mustacchi 	kgpio->kgpio_drv = arg;
855*fd71220bSRobert Mustacchi 
856*fd71220bSRobert Mustacchi 	mutex_init(&kgpio->kgpio_mutex, NULL, MUTEX_DRIVER, NULL);
857*fd71220bSRobert Mustacchi 	cv_init(&kgpio->kgpio_cv, NULL, CV_DRIVER, NULL);
858*fd71220bSRobert Mustacchi 
859*fd71220bSRobert Mustacchi 	if (snprintf(kgpio->kgpio_mname, sizeof (kgpio->kgpio_mname), "%s%d",
860*fd71220bSRobert Mustacchi 	    ddi_driver_name(dip), ddi_get_instance(dip)) >=
861*fd71220bSRobert Mustacchi 	    sizeof (kgpio->kgpio_mname)) {
862*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
863*fd71220bSRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to register with gpio framework: "
864*fd71220bSRobert Mustacchi 		    "controller minor name overflow");
865*fd71220bSRobert Mustacchi 		kgpio_cleanup(kgpio);
866*fd71220bSRobert Mustacchi 		return (EOVERFLOW);
867*fd71220bSRobert Mustacchi 	}
868*fd71220bSRobert Mustacchi 
869*fd71220bSRobert Mustacchi 	kgpio->kgpio_minor.kminor_id = id_alloc_nosleep(kgpio_g_ids);
870*fd71220bSRobert Mustacchi 	if (kgpio->kgpio_minor.kminor_id == -1) {
871*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
872*fd71220bSRobert Mustacchi 		kgpio_cleanup(kgpio);
873*fd71220bSRobert Mustacchi 		return (ENOSPC);
874*fd71220bSRobert Mustacchi 	}
875*fd71220bSRobert Mustacchi 	kgpio->kgpio_minor.kminor_type = KGPIO_MINOR_T_CTRL;
876*fd71220bSRobert Mustacchi 	kgpio->kgpio_minor.kminor_data.kminor_ctrl = kgpio;
877*fd71220bSRobert Mustacchi 
878*fd71220bSRobert Mustacchi 	kgpio->kgpio_cb.ddiub_cb = kgpio_unbind_cb;
879*fd71220bSRobert Mustacchi 	kgpio->kgpio_cb.ddiub_arg = kgpio;
880*fd71220bSRobert Mustacchi 	e_ddi_register_unbind_callback(dip, &kgpio->kgpio_cb);
881*fd71220bSRobert Mustacchi 	kgpio->kgpio_flags |= KGPIO_F_VALID;
882*fd71220bSRobert Mustacchi 
883*fd71220bSRobert Mustacchi 	/*
884*fd71220bSRobert Mustacchi 	 * At this point the kgpio_t is set up. The last thing we need to see is
885*fd71220bSRobert Mustacchi 	 * if we actually have our dev_info_t so we can create minors. It is
886*fd71220bSRobert Mustacchi 	 * possible for this not to be the case when the first gpio provider is
887*fd71220bSRobert Mustacchi 	 * attaching because the krtld reference only guarantees that the kgpio
888*fd71220bSRobert Mustacchi 	 * _init() entry point has been called and not attach. We attempt to use
889*fd71220bSRobert Mustacchi 	 * a ddi-forceattach attribute to make this less likely.
890*fd71220bSRobert Mustacchi 	 */
891*fd71220bSRobert Mustacchi 	if (kgpio_g_dip != NULL) {
892*fd71220bSRobert Mustacchi 		mutex_enter(&kgpio->kgpio_mutex);
893*fd71220bSRobert Mustacchi 		kgpio_create_minor(kgpio);
894*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
895*fd71220bSRobert Mustacchi 	}
896*fd71220bSRobert Mustacchi 
897*fd71220bSRobert Mustacchi 	list_insert_tail(&kgpio_g_gpios, kgpio);
898*fd71220bSRobert Mustacchi 	avl_add(&kgpio_g_minors, &kgpio->kgpio_minor);
899*fd71220bSRobert Mustacchi 
900*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
901*fd71220bSRobert Mustacchi 
902*fd71220bSRobert Mustacchi 	return (0);
903*fd71220bSRobert Mustacchi }
904*fd71220bSRobert Mustacchi 
905*fd71220bSRobert Mustacchi void
kgpio_nvl_attr_fill_str(nvlist_t * nvl,nvlist_t * meta,const char * key,const char * val,uint_t npos,char * const * pos,kgpio_prot_t prot)906*fd71220bSRobert Mustacchi kgpio_nvl_attr_fill_str(nvlist_t *nvl, nvlist_t *meta, const char *key,
907*fd71220bSRobert Mustacchi     const char *val, uint_t npos, char *const *pos, kgpio_prot_t prot)
908*fd71220bSRobert Mustacchi {
909*fd71220bSRobert Mustacchi 	nvlist_t *info = fnvlist_alloc();
910*fd71220bSRobert Mustacchi 
911*fd71220bSRobert Mustacchi 	fnvlist_add_string(nvl, key, val);
912*fd71220bSRobert Mustacchi 
913*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(info, KGPIO_ATTR_PROT, (uint32_t)prot);
914*fd71220bSRobert Mustacchi 	if (npos > 0) {
915*fd71220bSRobert Mustacchi 		fnvlist_add_string_array(info, KGPIO_ATTR_POS, pos, npos);
916*fd71220bSRobert Mustacchi 	}
917*fd71220bSRobert Mustacchi 	fnvlist_add_nvlist(meta, key, info);
918*fd71220bSRobert Mustacchi 	fnvlist_free(info);
919*fd71220bSRobert Mustacchi 
920*fd71220bSRobert Mustacchi }
921*fd71220bSRobert Mustacchi 
922*fd71220bSRobert Mustacchi void
kgpio_nvl_attr_fill_u32(nvlist_t * nvl,nvlist_t * meta,const char * key,uint32_t val,uint_t npos,uint32_t * pos,kgpio_prot_t prot)923*fd71220bSRobert Mustacchi kgpio_nvl_attr_fill_u32(nvlist_t *nvl, nvlist_t *meta, const char *key,
924*fd71220bSRobert Mustacchi     uint32_t val, uint_t npos, uint32_t *pos, kgpio_prot_t prot)
925*fd71220bSRobert Mustacchi {
926*fd71220bSRobert Mustacchi 	nvlist_t *info = fnvlist_alloc();
927*fd71220bSRobert Mustacchi 
928*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(nvl, key, val);
929*fd71220bSRobert Mustacchi 
930*fd71220bSRobert Mustacchi 	fnvlist_add_uint32(info, KGPIO_ATTR_PROT, (uint32_t)prot);
931*fd71220bSRobert Mustacchi 	if (npos > 0) {
932*fd71220bSRobert Mustacchi 		fnvlist_add_uint32_array(info, KGPIO_ATTR_POS, pos, npos);
933*fd71220bSRobert Mustacchi 	}
934*fd71220bSRobert Mustacchi 	fnvlist_add_nvlist(meta, key, info);
935*fd71220bSRobert Mustacchi 	fnvlist_free(info);
936*fd71220bSRobert Mustacchi }
937*fd71220bSRobert Mustacchi 
938*fd71220bSRobert Mustacchi static void
kgpio_release(kgpio_t * kgpio)939*fd71220bSRobert Mustacchi kgpio_release(kgpio_t *kgpio)
940*fd71220bSRobert Mustacchi {
941*fd71220bSRobert Mustacchi 	ddi_release_devi(kgpio->kgpio_dip);
942*fd71220bSRobert Mustacchi 
943*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
944*fd71220bSRobert Mustacchi 	VERIFY(kgpio->kgpio_flags & KGPIO_F_HELD);
945*fd71220bSRobert Mustacchi 	kgpio->kgpio_flags &= ~KGPIO_F_HELD;
946*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
947*fd71220bSRobert Mustacchi }
948*fd71220bSRobert Mustacchi 
949*fd71220bSRobert Mustacchi static void
kgpio_release_meta(kgpio_t * kgpio)950*fd71220bSRobert Mustacchi kgpio_release_meta(kgpio_t *kgpio)
951*fd71220bSRobert Mustacchi {
952*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
953*fd71220bSRobert Mustacchi 	VERIFY(kgpio->kgpio_flags & KGPIO_F_META_WORK);
954*fd71220bSRobert Mustacchi 	kgpio->kgpio_flags &= ~KGPIO_F_META_WORK;
955*fd71220bSRobert Mustacchi 	cv_broadcast(&kgpio->kgpio_cv);
956*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
957*fd71220bSRobert Mustacchi }
958*fd71220bSRobert Mustacchi 
959*fd71220bSRobert Mustacchi static int
kgpio_hold_by_id(id_t id)960*fd71220bSRobert Mustacchi kgpio_hold_by_id(id_t id)
961*fd71220bSRobert Mustacchi {
962*fd71220bSRobert Mustacchi 	kgpio_t *kgpio;
963*fd71220bSRobert Mustacchi 	dev_info_t *pdip;
964*fd71220bSRobert Mustacchi 	kgpio_minor_t *minor;
965*fd71220bSRobert Mustacchi 
966*fd71220bSRobert Mustacchi restart:
967*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
968*fd71220bSRobert Mustacchi 	minor = kgpio_minor_find(id);
969*fd71220bSRobert Mustacchi 	if (minor == NULL) {
970*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
971*fd71220bSRobert Mustacchi 		return (ESTALE);
972*fd71220bSRobert Mustacchi 	}
973*fd71220bSRobert Mustacchi 	if (minor->kminor_type != KGPIO_MINOR_T_CTRL) {
974*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
975*fd71220bSRobert Mustacchi 		return (ENXIO);
976*fd71220bSRobert Mustacchi 	}
977*fd71220bSRobert Mustacchi 	kgpio = minor->kminor_data.kminor_ctrl;
978*fd71220bSRobert Mustacchi 
979*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
980*fd71220bSRobert Mustacchi 	if ((kgpio->kgpio_flags & KGPIO_F_REMOVED) != 0) {
981*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
982*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
983*fd71220bSRobert Mustacchi 		return (ESTALE);
984*fd71220bSRobert Mustacchi 	}
985*fd71220bSRobert Mustacchi 
986*fd71220bSRobert Mustacchi 	/*
987*fd71220bSRobert Mustacchi 	 * First, check if the node that we're looking at is both active and
988*fd71220bSRobert Mustacchi 	 * held. If it is then there is nothing more that we need to do and can
989*fd71220bSRobert Mustacchi 	 * acknowledge the open. We don't need to account for how many folks
990*fd71220bSRobert Mustacchi 	 * have opened it due to the kernel's accounting.
991*fd71220bSRobert Mustacchi 	 */
992*fd71220bSRobert Mustacchi 	if ((kgpio->kgpio_flags & (KGPIO_F_VALID | KGPIO_F_HELD)) ==
993*fd71220bSRobert Mustacchi 	    (KGPIO_F_VALID | KGPIO_F_HELD)) {
994*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
995*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
996*fd71220bSRobert Mustacchi 		return (0);
997*fd71220bSRobert Mustacchi 	}
998*fd71220bSRobert Mustacchi 
999*fd71220bSRobert Mustacchi 	/*
1000*fd71220bSRobert Mustacchi 	 * This driver is either inactive and needs to be attached or it's not
1001*fd71220bSRobert Mustacchi 	 * held. In either case we need to make sure that only one open(9E) can
1002*fd71220bSRobert Mustacchi 	 * end up in here at a time. Note, while doing all this we drop the
1003*fd71220bSRobert Mustacchi 	 * global and local lock. This will cause us to restart this entire
1004*fd71220bSRobert Mustacchi 	 * loop.
1005*fd71220bSRobert Mustacchi 	 */
1006*fd71220bSRobert Mustacchi 	if ((kgpio->kgpio_flags & KGPIO_F_META_WORK) != 0) {
1007*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1008*fd71220bSRobert Mustacchi 		while ((kgpio->kgpio_flags & KGPIO_F_META_WORK) != 0) {
1009*fd71220bSRobert Mustacchi 			int cv = cv_wait_sig(&kgpio->kgpio_cv,
1010*fd71220bSRobert Mustacchi 			    &kgpio->kgpio_mutex);
1011*fd71220bSRobert Mustacchi 			if (cv == 0) {
1012*fd71220bSRobert Mustacchi 				mutex_exit(&kgpio->kgpio_mutex);
1013*fd71220bSRobert Mustacchi 				return (EINTR);
1014*fd71220bSRobert Mustacchi 			}
1015*fd71220bSRobert Mustacchi 		}
1016*fd71220bSRobert Mustacchi 
1017*fd71220bSRobert Mustacchi 		/*
1018*fd71220bSRobert Mustacchi 		 * We're no longer waiting. However, we basically have to take
1019*fd71220bSRobert Mustacchi 		 * another lap through here to check through all the core state
1020*fd71220bSRobert Mustacchi 		 * again because we dropped the kgpio_g_mutex.
1021*fd71220bSRobert Mustacchi 		 */
1022*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
1023*fd71220bSRobert Mustacchi 		goto restart;
1024*fd71220bSRobert Mustacchi 	}
1025*fd71220bSRobert Mustacchi 
1026*fd71220bSRobert Mustacchi 	/*
1027*fd71220bSRobert Mustacchi 	 * At this point we can obtain ownership for performing meta work on
1028*fd71220bSRobert Mustacchi 	 * this kgpio. Once we claim this we will need to drop our locks and
1029*fd71220bSRobert Mustacchi 	 * related to perform all of the related NDI operations. However,
1030*fd71220bSRobert Mustacchi 	 * because the meta work flag is set, this structure can't disappear.
1031*fd71220bSRobert Mustacchi 	 */
1032*fd71220bSRobert Mustacchi 	kgpio->kgpio_flags |= KGPIO_F_META_WORK;
1033*fd71220bSRobert Mustacchi 	pdip = ddi_get_parent(kgpio->kgpio_dip);
1034*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
1035*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
1036*fd71220bSRobert Mustacchi 
1037*fd71220bSRobert Mustacchi 	/*
1038*fd71220bSRobert Mustacchi 	 * This is required to ensure that the driver can't go away.
1039*fd71220bSRobert Mustacchi 	 */
1040*fd71220bSRobert Mustacchi 	ndi_devi_enter(pdip);
1041*fd71220bSRobert Mustacchi 	e_ddi_hold_devi(kgpio->kgpio_dip);
1042*fd71220bSRobert Mustacchi 	ndi_devi_exit(pdip);
1043*fd71220bSRobert Mustacchi 
1044*fd71220bSRobert Mustacchi 	/*
1045*fd71220bSRobert Mustacchi 	 * Because we dropped the main lock, we need to see if we lost a race
1046*fd71220bSRobert Mustacchi 	 * again and if so unwind.
1047*fd71220bSRobert Mustacchi 	 */
1048*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
1049*fd71220bSRobert Mustacchi 	kgpio->kgpio_flags |= KGPIO_F_HELD;
1050*fd71220bSRobert Mustacchi 	if ((kgpio->kgpio_flags & KGPIO_F_REMOVED) != 0) {
1051*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
1052*fd71220bSRobert Mustacchi 		kgpio_release(kgpio);
1053*fd71220bSRobert Mustacchi 		kgpio_release_meta(kgpio);
1054*fd71220bSRobert Mustacchi 		return (ESTALE);
1055*fd71220bSRobert Mustacchi 	}
1056*fd71220bSRobert Mustacchi 
1057*fd71220bSRobert Mustacchi 	/*
1058*fd71220bSRobert Mustacchi 	 * If the instance isn't valid yet, try to go and prod it via the NDI to
1059*fd71220bSRobert Mustacchi 	 * wake up. This needs to happen if an instance gets detached, for
1060*fd71220bSRobert Mustacchi 	 * example.
1061*fd71220bSRobert Mustacchi 	 */
1062*fd71220bSRobert Mustacchi 	if ((kgpio->kgpio_flags & KGPIO_F_VALID) == 0) {
1063*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
1064*fd71220bSRobert Mustacchi 		(void) ndi_devi_config(pdip, NDI_NO_EVENT);
1065*fd71220bSRobert Mustacchi 		mutex_enter(&kgpio->kgpio_mutex);
1066*fd71220bSRobert Mustacchi 
1067*fd71220bSRobert Mustacchi 		/*
1068*fd71220bSRobert Mustacchi 		 * Check one last time for validity. If this has failed or its
1069*fd71220bSRobert Mustacchi 		 * been removed, finally give up.
1070*fd71220bSRobert Mustacchi 		 */
1071*fd71220bSRobert Mustacchi 		ASSERT(kgpio->kgpio_flags & KGPIO_F_META_WORK);
1072*fd71220bSRobert Mustacchi 		if ((kgpio->kgpio_flags & KGPIO_F_REMOVED) != 0 ||
1073*fd71220bSRobert Mustacchi 		    (kgpio->kgpio_flags & KGPIO_F_VALID) == 0) {
1074*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio->kgpio_mutex);
1075*fd71220bSRobert Mustacchi 			kgpio_release(kgpio);
1076*fd71220bSRobert Mustacchi 			kgpio_release_meta(kgpio);
1077*fd71220bSRobert Mustacchi 			return (ESTALE);
1078*fd71220bSRobert Mustacchi 		}
1079*fd71220bSRobert Mustacchi 	}
1080*fd71220bSRobert Mustacchi 
1081*fd71220bSRobert Mustacchi 	/*
1082*fd71220bSRobert Mustacchi 	 * OK, at this point we actually did it. We should be both VALID and
1083*fd71220bSRobert Mustacchi 	 * HELD. We can release the meta work flag and we now should be good to
1084*fd71220bSRobert Mustacchi 	 * go.
1085*fd71220bSRobert Mustacchi 	 */
1086*fd71220bSRobert Mustacchi 	ASSERT(kgpio->kgpio_flags & KGPIO_F_META_WORK);
1087*fd71220bSRobert Mustacchi 	ASSERT(kgpio->kgpio_flags & KGPIO_F_HELD);
1088*fd71220bSRobert Mustacchi 	ASSERT(kgpio->kgpio_flags & KGPIO_F_VALID);
1089*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
1090*fd71220bSRobert Mustacchi 
1091*fd71220bSRobert Mustacchi 	kgpio_release_meta(kgpio);
1092*fd71220bSRobert Mustacchi 
1093*fd71220bSRobert Mustacchi 	return (0);
1094*fd71220bSRobert Mustacchi }
1095*fd71220bSRobert Mustacchi 
1096*fd71220bSRobert Mustacchi static int
kgpio_open(dev_t * devp,int flag,int otyp,cred_t * credp)1097*fd71220bSRobert Mustacchi kgpio_open(dev_t *devp, int flag, int otyp, cred_t *credp)
1098*fd71220bSRobert Mustacchi {
1099*fd71220bSRobert Mustacchi 	kgpio_minor_t *minor;
1100*fd71220bSRobert Mustacchi 	dpio_t *dpio;
1101*fd71220bSRobert Mustacchi 
1102*fd71220bSRobert Mustacchi 	if (drv_priv(credp) != 0)
1103*fd71220bSRobert Mustacchi 		return (EPERM);
1104*fd71220bSRobert Mustacchi 
1105*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
1106*fd71220bSRobert Mustacchi 	minor = kgpio_minor_find((id_t)getminor(*devp));
1107*fd71220bSRobert Mustacchi 	if (minor == NULL) {
1108*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1109*fd71220bSRobert Mustacchi 		return (ESTALE);
1110*fd71220bSRobert Mustacchi 	}
1111*fd71220bSRobert Mustacchi 
1112*fd71220bSRobert Mustacchi 	switch (minor->kminor_type) {
1113*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_CTRL:
1114*fd71220bSRobert Mustacchi 		/*
1115*fd71220bSRobert Mustacchi 		 * Opening a controller is awkward. By definition we have a
1116*fd71220bSRobert Mustacchi 		 * valid minor number and we have kgpio; however, depending on
1117*fd71220bSRobert Mustacchi 		 * the state of the actual controller it may not be held right
1118*fd71220bSRobert Mustacchi 		 * now. In addition, while we have found a minor right now for
1119*fd71220bSRobert Mustacchi 		 * this, when we go to potentially reattach it, if required, it
1120*fd71220bSRobert Mustacchi 		 * may disappear. So, as weird as this is, now that we believe
1121*fd71220bSRobert Mustacchi 		 * that this is a controller, we're going to call into the kgpio
1122*fd71220bSRobert Mustacchi 		 * hold logic, which will itself end up taking and dropping the
1123*fd71220bSRobert Mustacchi 		 * global locks across ndi calls. This mean that we're going to
1124*fd71220bSRobert Mustacchi 		 * drop the lock and must ignore the minor we just found. This
1125*fd71220bSRobert Mustacchi 		 * is ok, because the hold logic will validate the type and
1126*fd71220bSRobert Mustacchi 		 * related again.
1127*fd71220bSRobert Mustacchi 		 */
1128*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1129*fd71220bSRobert Mustacchi 
1130*fd71220bSRobert Mustacchi 		if (otyp != OTYP_CHR)
1131*fd71220bSRobert Mustacchi 			return (ENOTSUP);
1132*fd71220bSRobert Mustacchi 
1133*fd71220bSRobert Mustacchi 		if ((flag & (FNDELAY | FNONBLOCK | FEXCL)) != 0)
1134*fd71220bSRobert Mustacchi 			return (EINVAL);
1135*fd71220bSRobert Mustacchi 
1136*fd71220bSRobert Mustacchi 		if ((flag & FREAD) != FREAD)
1137*fd71220bSRobert Mustacchi 			return (EINVAL);
1138*fd71220bSRobert Mustacchi 
1139*fd71220bSRobert Mustacchi 		return (kgpio_hold_by_id((id_t)getminor(*devp)));
1140*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_DPIO:
1141*fd71220bSRobert Mustacchi 		dpio = minor->kminor_data.kminor_dpio;
1142*fd71220bSRobert Mustacchi 		mutex_enter(&dpio->dpio_mutex);
1143*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1144*fd71220bSRobert Mustacchi 
1145*fd71220bSRobert Mustacchi 		/*
1146*fd71220bSRobert Mustacchi 		 * Verify the basics that we expect for a DPIO.
1147*fd71220bSRobert Mustacchi 		 *  o It must be a character device.
1148*fd71220bSRobert Mustacchi 		 *  o If a DPIO has been flagged with requiring kernel access
1149*fd71220bSRobert Mustacchi 		 *    then FKLYR must be specified. If it is not, then it is an
1150*fd71220bSRobert Mustacchi 		 *    error.
1151*fd71220bSRobert Mustacchi 		 *  o We don't care about FNDELAY | FNONBLOCK, they will be
1152*fd71220bSRobert Mustacchi 		 *    honored for read(9E) and write(9E) and checked in the
1153*fd71220bSRobert Mustacchi 		 *    uio(9S).
1154*fd71220bSRobert Mustacchi 		 *  o If the DPIO_S_EXCL status flag is set, then we have to
1155*fd71220bSRobert Mustacchi 		 *    return that this device is already busy.
1156*fd71220bSRobert Mustacchi 		 *  o If someone has asked for FEXCL, it is only allowed to
1157*fd71220bSRobert Mustacchi 		 *    succeed if the device isn't already open.
1158*fd71220bSRobert Mustacchi 		 */
1159*fd71220bSRobert Mustacchi 		if ((dpio->dpio_flags & DPIO_F_KERNEL) != 0 &&
1160*fd71220bSRobert Mustacchi 		    (flag & FKLYR) == 0) {
1161*fd71220bSRobert Mustacchi 			mutex_exit(&dpio->dpio_mutex);
1162*fd71220bSRobert Mustacchi 			return (EPERM);
1163*fd71220bSRobert Mustacchi 		}
1164*fd71220bSRobert Mustacchi 
1165*fd71220bSRobert Mustacchi 		if (otyp != OTYP_CHR) {
1166*fd71220bSRobert Mustacchi 			mutex_exit(&dpio->dpio_mutex);
1167*fd71220bSRobert Mustacchi 			return (ENOTSUP);
1168*fd71220bSRobert Mustacchi 		}
1169*fd71220bSRobert Mustacchi 
1170*fd71220bSRobert Mustacchi 		if ((dpio->dpio_status & DPIO_S_EXCL) != 0) {
1171*fd71220bSRobert Mustacchi 			mutex_exit(&dpio->dpio_mutex);
1172*fd71220bSRobert Mustacchi 			return (EBUSY);
1173*fd71220bSRobert Mustacchi 		}
1174*fd71220bSRobert Mustacchi 
1175*fd71220bSRobert Mustacchi 		if ((flag & FEXCL) != 0) {
1176*fd71220bSRobert Mustacchi 			if ((dpio->dpio_status & DPIO_S_OPEN) != 0) {
1177*fd71220bSRobert Mustacchi 				mutex_exit(&dpio->dpio_mutex);
1178*fd71220bSRobert Mustacchi 				return (EBUSY);
1179*fd71220bSRobert Mustacchi 			}
1180*fd71220bSRobert Mustacchi 			dpio->dpio_status |= DPIO_S_EXCL;
1181*fd71220bSRobert Mustacchi 		}
1182*fd71220bSRobert Mustacchi 
1183*fd71220bSRobert Mustacchi 		dpio->dpio_status |= DPIO_S_OPEN;
1184*fd71220bSRobert Mustacchi 		mutex_exit(&dpio->dpio_mutex);
1185*fd71220bSRobert Mustacchi 		return (0);
1186*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_DPINFO:
1187*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1188*fd71220bSRobert Mustacchi 
1189*fd71220bSRobert Mustacchi 		/*
1190*fd71220bSRobert Mustacchi 		 * For the DPIO Information device, this really just is used to
1191*fd71220bSRobert Mustacchi 		 * get information and read-only ioctls. There is no special
1192*fd71220bSRobert Mustacchi 		 * support for anything here. We do require read access as
1193*fd71220bSRobert Mustacchi 		 * without that there isn't much to really do.
1194*fd71220bSRobert Mustacchi 		 */
1195*fd71220bSRobert Mustacchi 		if (otyp != OTYP_CHR) {
1196*fd71220bSRobert Mustacchi 			return (ENOTSUP);
1197*fd71220bSRobert Mustacchi 		}
1198*fd71220bSRobert Mustacchi 
1199*fd71220bSRobert Mustacchi 		if ((flag & (FNDELAY | FNONBLOCK | FEXCL)) != 0) {
1200*fd71220bSRobert Mustacchi 			return (EINVAL);
1201*fd71220bSRobert Mustacchi 		}
1202*fd71220bSRobert Mustacchi 
1203*fd71220bSRobert Mustacchi 		if ((flag & FREAD) != FREAD) {
1204*fd71220bSRobert Mustacchi 			return (EINVAL);
1205*fd71220bSRobert Mustacchi 		}
1206*fd71220bSRobert Mustacchi 
1207*fd71220bSRobert Mustacchi 		return (0);
1208*fd71220bSRobert Mustacchi 	default:
1209*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1210*fd71220bSRobert Mustacchi 		return (ENXIO);
1211*fd71220bSRobert Mustacchi 	}
1212*fd71220bSRobert Mustacchi }
1213*fd71220bSRobert Mustacchi 
1214*fd71220bSRobert Mustacchi static int
kgpio_ioctl_ctrl_info(kgpio_t * kgpio,intptr_t arg,int mode)1215*fd71220bSRobert Mustacchi kgpio_ioctl_ctrl_info(kgpio_t *kgpio, intptr_t arg, int mode)
1216*fd71220bSRobert Mustacchi {
1217*fd71220bSRobert Mustacchi 	kgpio_ctrl_info_t info;
1218*fd71220bSRobert Mustacchi 
1219*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio->kgpio_mutex));
1220*fd71220bSRobert Mustacchi 
1221*fd71220bSRobert Mustacchi 	if ((mode & FREAD) == 0) {
1222*fd71220bSRobert Mustacchi 		return (EBADF);
1223*fd71220bSRobert Mustacchi 	}
1224*fd71220bSRobert Mustacchi 
1225*fd71220bSRobert Mustacchi 	bzero(&info, sizeof (info));
1226*fd71220bSRobert Mustacchi 	info.kci_ngroups = 0;
1227*fd71220bSRobert Mustacchi 	info.kci_ngpios = kgpio->kgpio_ngpios;
1228*fd71220bSRobert Mustacchi 	info.kci_ndpios = kgpio->kgpio_ndpios;
1229*fd71220bSRobert Mustacchi 	(void) ddi_pathname(kgpio->kgpio_dip, info.kci_devpath);
1230*fd71220bSRobert Mustacchi 
1231*fd71220bSRobert Mustacchi 	if (ddi_copyout(&info, (void *)arg, sizeof (info), mode & FKIOCTL) !=
1232*fd71220bSRobert Mustacchi 	    0) {
1233*fd71220bSRobert Mustacchi 		return (EFAULT);
1234*fd71220bSRobert Mustacchi 	}
1235*fd71220bSRobert Mustacchi 
1236*fd71220bSRobert Mustacchi 	return (0);
1237*fd71220bSRobert Mustacchi }
1238*fd71220bSRobert Mustacchi 
1239*fd71220bSRobert Mustacchi static int
kgpio_ioctl_gpio_info(kgpio_t * kgpio,intptr_t arg,int mode)1240*fd71220bSRobert Mustacchi kgpio_ioctl_gpio_info(kgpio_t *kgpio, intptr_t arg, int mode)
1241*fd71220bSRobert Mustacchi {
1242*fd71220bSRobert Mustacchi 	int ret;
1243*fd71220bSRobert Mustacchi 	uint_t model;
1244*fd71220bSRobert Mustacchi 	char *pack = NULL;
1245*fd71220bSRobert Mustacchi 	size_t pack_size = 0;
1246*fd71220bSRobert Mustacchi 	kgpio_gpio_info_t info;
1247*fd71220bSRobert Mustacchi #ifdef	_MULTI_DATAMODEL
1248*fd71220bSRobert Mustacchi 	kgpio_gpio_info32_t info32;
1249*fd71220bSRobert Mustacchi #endif
1250*fd71220bSRobert Mustacchi 
1251*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio->kgpio_mutex));
1252*fd71220bSRobert Mustacchi 
1253*fd71220bSRobert Mustacchi 	if ((mode & FREAD) == 0) {
1254*fd71220bSRobert Mustacchi 		return (EBADF);
1255*fd71220bSRobert Mustacchi 	}
1256*fd71220bSRobert Mustacchi 
1257*fd71220bSRobert Mustacchi 	model = ddi_model_convert_from(mode);
1258*fd71220bSRobert Mustacchi 	switch (model) {
1259*fd71220bSRobert Mustacchi #ifdef	_MULTI_DATAMODEL
1260*fd71220bSRobert Mustacchi 	case DDI_MODEL_ILP32:
1261*fd71220bSRobert Mustacchi 		if (ddi_copyin((void *)arg, &info32, sizeof (info32),
1262*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1263*fd71220bSRobert Mustacchi 			return (EFAULT);
1264*fd71220bSRobert Mustacchi 		}
1265*fd71220bSRobert Mustacchi 
1266*fd71220bSRobert Mustacchi 		info.kgi_id = info32.kgi_id;
1267*fd71220bSRobert Mustacchi 		info.kgi_flags = info32.kgi_flags;
1268*fd71220bSRobert Mustacchi 		info.kgi_attr = info32.kgi_attr;
1269*fd71220bSRobert Mustacchi 		info.kgi_attr_len = info32.kgi_attr_len;
1270*fd71220bSRobert Mustacchi 		break;
1271*fd71220bSRobert Mustacchi #endif	/* _MULTI_DATAMODEL */
1272*fd71220bSRobert Mustacchi 	case DDI_MODEL_NONE:
1273*fd71220bSRobert Mustacchi 		if (ddi_copyin((void *)arg, &info, sizeof (info),
1274*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1275*fd71220bSRobert Mustacchi 			return (EFAULT);
1276*fd71220bSRobert Mustacchi 		}
1277*fd71220bSRobert Mustacchi 		break;
1278*fd71220bSRobert Mustacchi 	default:
1279*fd71220bSRobert Mustacchi 		return (ENOTSUP);
1280*fd71220bSRobert Mustacchi 	}
1281*fd71220bSRobert Mustacchi 
1282*fd71220bSRobert Mustacchi 	if (info.kgi_id >= kgpio->kgpio_ngpios) {
1283*fd71220bSRobert Mustacchi 		return (ENOENT);
1284*fd71220bSRobert Mustacchi 	}
1285*fd71220bSRobert Mustacchi 
1286*fd71220bSRobert Mustacchi 	nvlist_t *attr = fnvlist_alloc();
1287*fd71220bSRobert Mustacchi 	ret = kgpio->kgpio_ops->kgo_get(kgpio->kgpio_drv, info.kgi_id, attr);
1288*fd71220bSRobert Mustacchi 	if (ret != 0) {
1289*fd71220bSRobert Mustacchi 		goto out;
1290*fd71220bSRobert Mustacchi 	}
1291*fd71220bSRobert Mustacchi 
1292*fd71220bSRobert Mustacchi 	pack = fnvlist_pack(attr, &pack_size);
1293*fd71220bSRobert Mustacchi 	if (info.kgi_attr_len >= pack_size) {
1294*fd71220bSRobert Mustacchi 		if (ddi_copyout(pack, (void *)info.kgi_attr, pack_size,
1295*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1296*fd71220bSRobert Mustacchi 			ret = EFAULT;
1297*fd71220bSRobert Mustacchi 			goto out;
1298*fd71220bSRobert Mustacchi 		}
1299*fd71220bSRobert Mustacchi 		ret = 0;
1300*fd71220bSRobert Mustacchi 	} else {
1301*fd71220bSRobert Mustacchi 		ret = EOVERFLOW;
1302*fd71220bSRobert Mustacchi 	}
1303*fd71220bSRobert Mustacchi 
1304*fd71220bSRobert Mustacchi 	info.kgi_attr_len = pack_size;
1305*fd71220bSRobert Mustacchi 	switch (model) {
1306*fd71220bSRobert Mustacchi #ifdef	_MULTI_DATAMODEL
1307*fd71220bSRobert Mustacchi 	case DDI_MODEL_ILP32:
1308*fd71220bSRobert Mustacchi 		if (info.kgi_attr_len > UINT32_MAX) {
1309*fd71220bSRobert Mustacchi 			info32.kgi_attr_len = UINT32_MAX;
1310*fd71220bSRobert Mustacchi 			ret = EOVERFLOW;
1311*fd71220bSRobert Mustacchi 		} else {
1312*fd71220bSRobert Mustacchi 			info32.kgi_attr_len = info.kgi_attr_len;
1313*fd71220bSRobert Mustacchi 		}
1314*fd71220bSRobert Mustacchi 
1315*fd71220bSRobert Mustacchi 		if (ddi_copyout(&info32, (void *)arg, sizeof (info32),
1316*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1317*fd71220bSRobert Mustacchi 			ret = EFAULT;
1318*fd71220bSRobert Mustacchi 			goto out;
1319*fd71220bSRobert Mustacchi 		}
1320*fd71220bSRobert Mustacchi 		break;
1321*fd71220bSRobert Mustacchi #endif	/* _MULTI_DATAMODEL */
1322*fd71220bSRobert Mustacchi 	case DDI_MODEL_NONE:
1323*fd71220bSRobert Mustacchi 		if (ddi_copyout(&info, (void *)arg, sizeof (info),
1324*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1325*fd71220bSRobert Mustacchi 			ret = EFAULT;
1326*fd71220bSRobert Mustacchi 			goto out;
1327*fd71220bSRobert Mustacchi 		}
1328*fd71220bSRobert Mustacchi 	}
1329*fd71220bSRobert Mustacchi 
1330*fd71220bSRobert Mustacchi out:
1331*fd71220bSRobert Mustacchi 	if (pack != NULL) {
1332*fd71220bSRobert Mustacchi 		ASSERT3U(pack_size, !=, 0);
1333*fd71220bSRobert Mustacchi 		fnvlist_pack_free(pack, pack_size);
1334*fd71220bSRobert Mustacchi 	}
1335*fd71220bSRobert Mustacchi 	nvlist_free(attr);
1336*fd71220bSRobert Mustacchi 	return (ret);
1337*fd71220bSRobert Mustacchi }
1338*fd71220bSRobert Mustacchi 
1339*fd71220bSRobert Mustacchi static int
kgpio_ioctl_gpio_update(kgpio_t * kgpio,intptr_t arg,int mode)1340*fd71220bSRobert Mustacchi kgpio_ioctl_gpio_update(kgpio_t *kgpio, intptr_t arg, int mode)
1341*fd71220bSRobert Mustacchi {
1342*fd71220bSRobert Mustacchi 	int ret;
1343*fd71220bSRobert Mustacchi 	uint_t model;
1344*fd71220bSRobert Mustacchi 	char *user_data = NULL;
1345*fd71220bSRobert Mustacchi 	nvlist_t *attr_nvl = NULL, *err_nvl = NULL;
1346*fd71220bSRobert Mustacchi 	kgpio_update_t kgu;
1347*fd71220bSRobert Mustacchi #ifdef	_MULTI_DATAMODEL
1348*fd71220bSRobert Mustacchi 	kgpio_update32_t kgu32;
1349*fd71220bSRobert Mustacchi #endif
1350*fd71220bSRobert Mustacchi 
1351*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio->kgpio_mutex));
1352*fd71220bSRobert Mustacchi 
1353*fd71220bSRobert Mustacchi 	if ((mode & FWRITE) == 0) {
1354*fd71220bSRobert Mustacchi 		return (EBADF);
1355*fd71220bSRobert Mustacchi 	}
1356*fd71220bSRobert Mustacchi 
1357*fd71220bSRobert Mustacchi 	model = ddi_model_convert_from(mode);
1358*fd71220bSRobert Mustacchi 	switch (model) {
1359*fd71220bSRobert Mustacchi #ifdef	_MULTI_DATAMODEL
1360*fd71220bSRobert Mustacchi 	case DDI_MODEL_ILP32:
1361*fd71220bSRobert Mustacchi 		if (ddi_copyin((void *)arg, &kgu32, sizeof (kgu32),
1362*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1363*fd71220bSRobert Mustacchi 			return (EFAULT);
1364*fd71220bSRobert Mustacchi 		}
1365*fd71220bSRobert Mustacchi 
1366*fd71220bSRobert Mustacchi 		kgu.kgu_id = kgu32.kgu_id;
1367*fd71220bSRobert Mustacchi 		kgu.kgu_flags = kgu32.kgu_flags;
1368*fd71220bSRobert Mustacchi 		kgu.kgu_attr = kgu32.kgu_attr;
1369*fd71220bSRobert Mustacchi 		kgu.kgu_attr_len = kgu32.kgu_attr_len;
1370*fd71220bSRobert Mustacchi 		kgu.kgu_err = kgu32.kgu_err;
1371*fd71220bSRobert Mustacchi 		kgu.kgu_err_len = kgu32.kgu_err_len;
1372*fd71220bSRobert Mustacchi 		break;
1373*fd71220bSRobert Mustacchi #endif	/* _MULTI_DATAMODEL */
1374*fd71220bSRobert Mustacchi 	case DDI_MODEL_NONE:
1375*fd71220bSRobert Mustacchi 		if (ddi_copyin((void *)arg, &kgu, sizeof (kgu),
1376*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1377*fd71220bSRobert Mustacchi 			return (EFAULT);
1378*fd71220bSRobert Mustacchi 		}
1379*fd71220bSRobert Mustacchi 		break;
1380*fd71220bSRobert Mustacchi 	default:
1381*fd71220bSRobert Mustacchi 		return (ENOTSUP);
1382*fd71220bSRobert Mustacchi 	}
1383*fd71220bSRobert Mustacchi 
1384*fd71220bSRobert Mustacchi 	/*
1385*fd71220bSRobert Mustacchi 	 * We need to go back and verify that this GPIO doesn't correspond to a
1386*fd71220bSRobert Mustacchi 	 * DPIO at all. This means we need the global mutex again. It's safe for
1387*fd71220bSRobert Mustacchi 	 * us to drop and reacquire the kgpio's lock as because we're in the
1388*fd71220bSRobert Mustacchi 	 * context of the open device, it can't go away.
1389*fd71220bSRobert Mustacchi 	 */
1390*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
1391*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
1392*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
1393*fd71220bSRobert Mustacchi 
1394*fd71220bSRobert Mustacchi 	for (dpio_t *dpio = list_head(&kgpio_g_dpios); dpio != NULL;
1395*fd71220bSRobert Mustacchi 	    dpio = list_next(&kgpio_g_dpios, dpio)) {
1396*fd71220bSRobert Mustacchi 		if (dpio->dpio_kgpio == kgpio &&
1397*fd71220bSRobert Mustacchi 		    dpio->dpio_gpio_num == kgu.kgu_id) {
1398*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio_g_mutex);
1399*fd71220bSRobert Mustacchi 			return (EROFS);
1400*fd71220bSRobert Mustacchi 		}
1401*fd71220bSRobert Mustacchi 	}
1402*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
1403*fd71220bSRobert Mustacchi 
1404*fd71220bSRobert Mustacchi 	if (kgu.kgu_attr_len > kgpio_max_user_nvl) {
1405*fd71220bSRobert Mustacchi 		return (E2BIG);
1406*fd71220bSRobert Mustacchi 	}
1407*fd71220bSRobert Mustacchi 
1408*fd71220bSRobert Mustacchi 	if (kgu.kgu_id >= kgpio->kgpio_ngpios) {
1409*fd71220bSRobert Mustacchi 		return (ENOENT);
1410*fd71220bSRobert Mustacchi 	}
1411*fd71220bSRobert Mustacchi 
1412*fd71220bSRobert Mustacchi 	user_data = kmem_alloc(kgpio_max_user_nvl, KM_NOSLEEP_LAZY);
1413*fd71220bSRobert Mustacchi 	if (user_data == NULL) {
1414*fd71220bSRobert Mustacchi 		return (ENOMEM);
1415*fd71220bSRobert Mustacchi 	}
1416*fd71220bSRobert Mustacchi 
1417*fd71220bSRobert Mustacchi 	if (ddi_copyin((void *)kgu.kgu_attr, user_data, kgu.kgu_attr_len,
1418*fd71220bSRobert Mustacchi 	    mode & FKIOCTL) != 0) {
1419*fd71220bSRobert Mustacchi 		ret = EFAULT;
1420*fd71220bSRobert Mustacchi 		goto err;
1421*fd71220bSRobert Mustacchi 	}
1422*fd71220bSRobert Mustacchi 
1423*fd71220bSRobert Mustacchi 	if (nvlist_unpack(user_data, kgu.kgu_attr_len, &attr_nvl, 0) != 0) {
1424*fd71220bSRobert Mustacchi 		ret = EINVAL;
1425*fd71220bSRobert Mustacchi 		goto err;
1426*fd71220bSRobert Mustacchi 	}
1427*fd71220bSRobert Mustacchi 
1428*fd71220bSRobert Mustacchi 	err_nvl = fnvlist_alloc();
1429*fd71220bSRobert Mustacchi 	ret = kgpio->kgpio_ops->kgo_set(kgpio->kgpio_drv, kgu.kgu_id, attr_nvl,
1430*fd71220bSRobert Mustacchi 	    err_nvl);
1431*fd71220bSRobert Mustacchi 	/*
1432*fd71220bSRobert Mustacchi 	 * If this failed and we had an error nvlist, then we don't return an
1433*fd71220bSRobert Mustacchi 	 * errno and instead translate this into the structure that we copy out.
1434*fd71220bSRobert Mustacchi 	 * We always zero out the flags and then will set what appropriate bits
1435*fd71220bSRobert Mustacchi 	 * we need. This next if statement will zero out ret, indicating to us
1436*fd71220bSRobert Mustacchi 	 * that we should attempt to copy out this structure. If anything in the
1437*fd71220bSRobert Mustacchi 	 * process of trying to copy out errors fails, then we don't worry about
1438*fd71220bSRobert Mustacchi 	 * that and return a larger error because that is indicative of failure
1439*fd71220bSRobert Mustacchi 	 * it just means userland can't get as much info as we wished.
1440*fd71220bSRobert Mustacchi 	 */
1441*fd71220bSRobert Mustacchi 	kgu.kgu_flags = 0;
1442*fd71220bSRobert Mustacchi 	if (ret != 0 && nvlist_next_nvpair(err_nvl, NULL) != NULL) {
1443*fd71220bSRobert Mustacchi 		size_t err_len;
1444*fd71220bSRobert Mustacchi 
1445*fd71220bSRobert Mustacchi 		kgu.kgu_flags |= KGPIO_UPDATE_ERROR;
1446*fd71220bSRobert Mustacchi 		ret = nvlist_size(err_nvl, &err_len, NV_ENCODE_NATIVE);
1447*fd71220bSRobert Mustacchi 
1448*fd71220bSRobert Mustacchi 		if (ret == 0 && err_len <= MIN(kgu.kgu_err_len,
1449*fd71220bSRobert Mustacchi 		    kgpio_max_user_nvl)) {
1450*fd71220bSRobert Mustacchi 			ret = nvlist_pack(err_nvl, &user_data, &err_len,
1451*fd71220bSRobert Mustacchi 			    NV_ENCODE_NATIVE, 0);
1452*fd71220bSRobert Mustacchi 			if (ret != 0) {
1453*fd71220bSRobert Mustacchi 				goto err;
1454*fd71220bSRobert Mustacchi 			}
1455*fd71220bSRobert Mustacchi 
1456*fd71220bSRobert Mustacchi 			kgu.kgu_err_len = err_len;
1457*fd71220bSRobert Mustacchi 			if (ddi_copyout(user_data, (void *)kgu.kgu_err, err_len,
1458*fd71220bSRobert Mustacchi 			    mode & FKIOCTL) != 0) {
1459*fd71220bSRobert Mustacchi 				ret = EFAULT;
1460*fd71220bSRobert Mustacchi 			} else {
1461*fd71220bSRobert Mustacchi 				kgu.kgu_flags |= KGPIO_UPDATE_ERR_NVL_VALID;
1462*fd71220bSRobert Mustacchi 				ret = 0;
1463*fd71220bSRobert Mustacchi 			}
1464*fd71220bSRobert Mustacchi 		}
1465*fd71220bSRobert Mustacchi 	}
1466*fd71220bSRobert Mustacchi 
1467*fd71220bSRobert Mustacchi 	if (ret != 0) {
1468*fd71220bSRobert Mustacchi 		goto err;
1469*fd71220bSRobert Mustacchi 	}
1470*fd71220bSRobert Mustacchi 
1471*fd71220bSRobert Mustacchi 	switch (model) {
1472*fd71220bSRobert Mustacchi #ifdef	_MULTI_DATAMODEL
1473*fd71220bSRobert Mustacchi 	case DDI_MODEL_ILP32:
1474*fd71220bSRobert Mustacchi 		/*
1475*fd71220bSRobert Mustacchi 		 * Other values should still hold from copyin, hence we only
1476*fd71220bSRobert Mustacchi 		 * update those that we would have changed here.
1477*fd71220bSRobert Mustacchi 		 */
1478*fd71220bSRobert Mustacchi 		kgu32.kgu_flags = kgu.kgu_flags;
1479*fd71220bSRobert Mustacchi 		kgu32.kgu_err_len = kgu.kgu_err_len;
1480*fd71220bSRobert Mustacchi 
1481*fd71220bSRobert Mustacchi 		if (ddi_copyout(&kgu32, (void *)arg, sizeof (kgu32),
1482*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1483*fd71220bSRobert Mustacchi 			ret = EFAULT;
1484*fd71220bSRobert Mustacchi 		}
1485*fd71220bSRobert Mustacchi 		break;
1486*fd71220bSRobert Mustacchi #endif	/* _MULTI_DATAMODEL */
1487*fd71220bSRobert Mustacchi 	case DDI_MODEL_NONE:
1488*fd71220bSRobert Mustacchi 		if (ddi_copyout(&kgu, (void *)arg, sizeof (kgu),
1489*fd71220bSRobert Mustacchi 		    mode & FKIOCTL) != 0) {
1490*fd71220bSRobert Mustacchi 			ret = EFAULT;
1491*fd71220bSRobert Mustacchi 		}
1492*fd71220bSRobert Mustacchi 		break;
1493*fd71220bSRobert Mustacchi 	default:
1494*fd71220bSRobert Mustacchi 		ret = ENOTSUP;
1495*fd71220bSRobert Mustacchi 	}
1496*fd71220bSRobert Mustacchi 
1497*fd71220bSRobert Mustacchi err:
1498*fd71220bSRobert Mustacchi 	if (err_nvl != NULL) {
1499*fd71220bSRobert Mustacchi 		nvlist_free(err_nvl);
1500*fd71220bSRobert Mustacchi 	}
1501*fd71220bSRobert Mustacchi 
1502*fd71220bSRobert Mustacchi 	if (attr_nvl != NULL) {
1503*fd71220bSRobert Mustacchi 		nvlist_free(attr_nvl);
1504*fd71220bSRobert Mustacchi 	}
1505*fd71220bSRobert Mustacchi 
1506*fd71220bSRobert Mustacchi 	if (user_data != NULL) {
1507*fd71220bSRobert Mustacchi 		kmem_free(user_data, kgpio_max_user_nvl);
1508*fd71220bSRobert Mustacchi 	}
1509*fd71220bSRobert Mustacchi 	return (ret);
1510*fd71220bSRobert Mustacchi }
1511*fd71220bSRobert Mustacchi 
1512*fd71220bSRobert Mustacchi static bool
kgpio_valid_name(const char * name,size_t buflen)1513*fd71220bSRobert Mustacchi kgpio_valid_name(const char *name, size_t buflen)
1514*fd71220bSRobert Mustacchi {
1515*fd71220bSRobert Mustacchi 	size_t i;
1516*fd71220bSRobert Mustacchi 
1517*fd71220bSRobert Mustacchi 	for (i = 0; i < buflen; i++) {
1518*fd71220bSRobert Mustacchi 		if (name[i] == '\0')
1519*fd71220bSRobert Mustacchi 			break;
1520*fd71220bSRobert Mustacchi 
1521*fd71220bSRobert Mustacchi 		/*
1522*fd71220bSRobert Mustacchi 		 * Right now we constrain GPIO names to be alphanumeric and
1523*fd71220bSRobert Mustacchi 		 * allow for separators to exist. However, for file system
1524*fd71220bSRobert Mustacchi 		 * simplicity we constrain the first character to be
1525*fd71220bSRobert Mustacchi 		 * alphanumeric.
1526*fd71220bSRobert Mustacchi 		 */
1527*fd71220bSRobert Mustacchi 		if (i == 0 && !isalnum(name[i])) {
1528*fd71220bSRobert Mustacchi 			return (false);
1529*fd71220bSRobert Mustacchi 		} else if (!isalnum(name[i]) && name[i] != '_' &&
1530*fd71220bSRobert Mustacchi 		    name[i] != '.' && name[i] != '-' && name[i] != '+') {
1531*fd71220bSRobert Mustacchi 			return (false);
1532*fd71220bSRobert Mustacchi 		}
1533*fd71220bSRobert Mustacchi 	}
1534*fd71220bSRobert Mustacchi 
1535*fd71220bSRobert Mustacchi 	if (i == 0 || i == buflen) {
1536*fd71220bSRobert Mustacchi 		return (false);
1537*fd71220bSRobert Mustacchi 	}
1538*fd71220bSRobert Mustacchi 
1539*fd71220bSRobert Mustacchi 	return (true);
1540*fd71220bSRobert Mustacchi }
1541*fd71220bSRobert Mustacchi 
1542*fd71220bSRobert Mustacchi static int
kgpio_ioctl_dpio_create(kgpio_t * kgpio,intptr_t arg,int mode)1543*fd71220bSRobert Mustacchi kgpio_ioctl_dpio_create(kgpio_t *kgpio, intptr_t arg, int mode)
1544*fd71220bSRobert Mustacchi {
1545*fd71220bSRobert Mustacchi 	int ret;
1546*fd71220bSRobert Mustacchi 	dpio_caps_t sup_caps, caps = 0;
1547*fd71220bSRobert Mustacchi 	const kgpio_dpio_flags_t all_flags = KGPIO_DPIO_F_READ |
1548*fd71220bSRobert Mustacchi 	    KGPIO_DPIO_F_WRITE | KGPIO_DPIO_F_KERNEL;
1549*fd71220bSRobert Mustacchi 	kgpio_dpio_create_t create;
1550*fd71220bSRobert Mustacchi 	char name[KGPIO_DPIO_INT_NAMELEN];
1551*fd71220bSRobert Mustacchi 	size_t namelen;
1552*fd71220bSRobert Mustacchi 
1553*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio->kgpio_mutex));
1554*fd71220bSRobert Mustacchi 
1555*fd71220bSRobert Mustacchi 	if ((mode & FWRITE) == 0) {
1556*fd71220bSRobert Mustacchi 		return (EBADF);
1557*fd71220bSRobert Mustacchi 	}
1558*fd71220bSRobert Mustacchi 
1559*fd71220bSRobert Mustacchi 	if (ddi_copyin((void *)arg, &create, sizeof (kgpio_dpio_create_t),
1560*fd71220bSRobert Mustacchi 	    mode & FKIOCTL) != 0) {
1561*fd71220bSRobert Mustacchi 		return (EFAULT);
1562*fd71220bSRobert Mustacchi 	}
1563*fd71220bSRobert Mustacchi 
1564*fd71220bSRobert Mustacchi 	if (create.kdc_id >= kgpio->kgpio_ngpios) {
1565*fd71220bSRobert Mustacchi 		return (ENOENT);
1566*fd71220bSRobert Mustacchi 	}
1567*fd71220bSRobert Mustacchi 
1568*fd71220bSRobert Mustacchi 	if (!kgpio_valid_name(create.kdc_name, sizeof (create.kdc_name))) {
1569*fd71220bSRobert Mustacchi 		return (EINVAL);
1570*fd71220bSRobert Mustacchi 	}
1571*fd71220bSRobert Mustacchi 	namelen = snprintf(name, sizeof (name), "dpio:%s", create.kdc_name);
1572*fd71220bSRobert Mustacchi 	ASSERT3U(namelen, <, KGPIO_DPIO_INT_NAMELEN);
1573*fd71220bSRobert Mustacchi 
1574*fd71220bSRobert Mustacchi 	/*
1575*fd71220bSRobert Mustacchi 	 * It is perfectly fine to create a DPIO with no flags. That is then
1576*fd71220bSRobert Mustacchi 	 * something which is constrained with its current attributes, providing
1577*fd71220bSRobert Mustacchi 	 * the system guarantees that it should not change, though it is a
1578*fd71220bSRobert Mustacchi 	 * little weird.
1579*fd71220bSRobert Mustacchi 	 */
1580*fd71220bSRobert Mustacchi 	if ((create.kdc_flags & ~all_flags) != 0) {
1581*fd71220bSRobert Mustacchi 		return (EINVAL);
1582*fd71220bSRobert Mustacchi 	}
1583*fd71220bSRobert Mustacchi 
1584*fd71220bSRobert Mustacchi 	if (kgpio->kgpio_ops->kgo_cap == NULL) {
1585*fd71220bSRobert Mustacchi 		return (ENOTSUP);
1586*fd71220bSRobert Mustacchi 	}
1587*fd71220bSRobert Mustacchi 	ret = kgpio->kgpio_ops->kgo_cap(kgpio->kgpio_drv, create.kdc_id,
1588*fd71220bSRobert Mustacchi 	    &sup_caps);
1589*fd71220bSRobert Mustacchi 	if (ret != 0) {
1590*fd71220bSRobert Mustacchi 		return (ret);
1591*fd71220bSRobert Mustacchi 	}
1592*fd71220bSRobert Mustacchi 
1593*fd71220bSRobert Mustacchi 	if ((create.kdc_flags & KGPIO_DPIO_F_READ) != 0) {
1594*fd71220bSRobert Mustacchi 		if (kgpio->kgpio_ops->kgo_input == NULL ||
1595*fd71220bSRobert Mustacchi 		    (sup_caps & DPIO_C_READ) == 0) {
1596*fd71220bSRobert Mustacchi 			return (ENOTSUP);
1597*fd71220bSRobert Mustacchi 		}
1598*fd71220bSRobert Mustacchi 		caps |= DPIO_C_READ;
1599*fd71220bSRobert Mustacchi 	}
1600*fd71220bSRobert Mustacchi 
1601*fd71220bSRobert Mustacchi 	if ((create.kdc_flags & KGPIO_DPIO_F_WRITE) != 0) {
1602*fd71220bSRobert Mustacchi 		if (kgpio->kgpio_ops->kgo_output_state == NULL ||
1603*fd71220bSRobert Mustacchi 		    kgpio->kgpio_ops->kgo_output == NULL ||
1604*fd71220bSRobert Mustacchi 		    (sup_caps & DPIO_C_WRITE) == 0) {
1605*fd71220bSRobert Mustacchi 			return (ENOTSUP);
1606*fd71220bSRobert Mustacchi 		}
1607*fd71220bSRobert Mustacchi 		caps |= DPIO_C_WRITE;
1608*fd71220bSRobert Mustacchi 	}
1609*fd71220bSRobert Mustacchi 
1610*fd71220bSRobert Mustacchi 	if ((caps & DPIO_C_READ) != 0 && (sup_caps & DPIO_C_POLL) != 0) {
1611*fd71220bSRobert Mustacchi 		caps |= DPIO_C_POLL;
1612*fd71220bSRobert Mustacchi 	}
1613*fd71220bSRobert Mustacchi 
1614*fd71220bSRobert Mustacchi 	/*
1615*fd71220bSRobert Mustacchi 	 * At this point, everything that we have for the DPIO is valid. The
1616*fd71220bSRobert Mustacchi 	 * remaining things we need to try and do are:
1617*fd71220bSRobert Mustacchi 	 *
1618*fd71220bSRobert Mustacchi 	 *  o Ensure that there isn't a DPIO with this name already.
1619*fd71220bSRobert Mustacchi 	 *  o Ensure that there isn't a DPIO already using this particular
1620*fd71220bSRobert Mustacchi 	 *    GPIO.
1621*fd71220bSRobert Mustacchi 	 *  o Create our DPIO structure, get underlying caps, and ultimately
1622*fd71220bSRobert Mustacchi 	 *    create our minor.
1623*fd71220bSRobert Mustacchi 	 *
1624*fd71220bSRobert Mustacchi 	 * To do this, we need to acquire the global lock to ensure that we
1625*fd71220bSRobert Mustacchi 	 * don't end up racing with anyone else. We've already gotten all
1626*fd71220bSRobert Mustacchi 	 * information that we need from the kgpio controller and because we
1627*fd71220bSRobert Mustacchi 	 * looked up and ensured the underlying controller is held, it should
1628*fd71220bSRobert Mustacchi 	 * not disappear on us as we drop the lock.
1629*fd71220bSRobert Mustacchi 	 */
1630*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
1631*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
1632*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
1633*fd71220bSRobert Mustacchi 
1634*fd71220bSRobert Mustacchi 	for (dpio_t *dpio = list_head(&kgpio_g_dpios); dpio != NULL;
1635*fd71220bSRobert Mustacchi 	    dpio = list_next(&kgpio_g_dpios, dpio)) {
1636*fd71220bSRobert Mustacchi 		if (dpio->dpio_kgpio == kgpio &&
1637*fd71220bSRobert Mustacchi 		    dpio->dpio_gpio_num == create.kdc_id) {
1638*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio_g_mutex);
1639*fd71220bSRobert Mustacchi 			return (EBUSY);
1640*fd71220bSRobert Mustacchi 		}
1641*fd71220bSRobert Mustacchi 
1642*fd71220bSRobert Mustacchi 		if (strcmp(name, dpio->dpio_name) == 0) {
1643*fd71220bSRobert Mustacchi 			mutex_exit(&kgpio_g_mutex);
1644*fd71220bSRobert Mustacchi 			return (EEXIST);
1645*fd71220bSRobert Mustacchi 		}
1646*fd71220bSRobert Mustacchi 	}
1647*fd71220bSRobert Mustacchi 
1648*fd71220bSRobert Mustacchi 	dpio_t *dpio = kmem_zalloc(sizeof (dpio_t), KM_NOSLEEP_LAZY);
1649*fd71220bSRobert Mustacchi 	if (dpio == NULL) {
1650*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1651*fd71220bSRobert Mustacchi 		return (ENOMEM);
1652*fd71220bSRobert Mustacchi 	}
1653*fd71220bSRobert Mustacchi 
1654*fd71220bSRobert Mustacchi 	dpio->dpio_kgpio = kgpio;
1655*fd71220bSRobert Mustacchi 	dpio->dpio_gpio_num = create.kdc_id;
1656*fd71220bSRobert Mustacchi 	dpio->dpio_caps = caps;
1657*fd71220bSRobert Mustacchi 	if ((create.kdc_flags & KGPIO_DPIO_F_KERNEL) != 0) {
1658*fd71220bSRobert Mustacchi 		dpio->dpio_flags |= DPIO_F_KERNEL;
1659*fd71220bSRobert Mustacchi 	}
1660*fd71220bSRobert Mustacchi 	/*
1661*fd71220bSRobert Mustacchi 	 * Note, we have a guarantee that the name length here is less than the
1662*fd71220bSRobert Mustacchi 	 * actual buffer size. The NUL termination comes from the kmem_zalloc
1663*fd71220bSRobert Mustacchi 	 * earlier.
1664*fd71220bSRobert Mustacchi 	 */
1665*fd71220bSRobert Mustacchi 	bcopy(name, dpio->dpio_name, namelen);
1666*fd71220bSRobert Mustacchi 	mutex_init(&dpio->dpio_mutex, NULL, MUTEX_DRIVER, NULL);
1667*fd71220bSRobert Mustacchi 
1668*fd71220bSRobert Mustacchi 	dpio->dpio_minor.kminor_id = id_alloc_nosleep(kgpio_g_ids);
1669*fd71220bSRobert Mustacchi 	if (dpio->dpio_minor.kminor_id == -1) {
1670*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1671*fd71220bSRobert Mustacchi 		kgpio_dpio_cleanup(dpio);
1672*fd71220bSRobert Mustacchi 		return (ENOSPC);
1673*fd71220bSRobert Mustacchi 	}
1674*fd71220bSRobert Mustacchi 	dpio->dpio_minor.kminor_type = KGPIO_MINOR_T_DPIO;
1675*fd71220bSRobert Mustacchi 	dpio->dpio_minor.kminor_data.kminor_dpio = dpio;
1676*fd71220bSRobert Mustacchi 
1677*fd71220bSRobert Mustacchi 	if (ddi_create_minor_node(kgpio_g_dip, dpio->dpio_name, S_IFCHR,
1678*fd71220bSRobert Mustacchi 	    (minor_t)dpio->dpio_minor.kminor_id, DDI_NT_GPIO_DPIO, 0) !=
1679*fd71220bSRobert Mustacchi 	    DDI_SUCCESS) {
1680*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1681*fd71220bSRobert Mustacchi 		kgpio_dpio_cleanup(dpio);
1682*fd71220bSRobert Mustacchi 		return (EIO);
1683*fd71220bSRobert Mustacchi 	}
1684*fd71220bSRobert Mustacchi 
1685*fd71220bSRobert Mustacchi 	list_insert_tail(&kgpio_g_dpios, dpio);
1686*fd71220bSRobert Mustacchi 	avl_add(&kgpio_g_minors, &dpio->dpio_minor);
1687*fd71220bSRobert Mustacchi 	kgpio->kgpio_ndpios++;
1688*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
1689*fd71220bSRobert Mustacchi 
1690*fd71220bSRobert Mustacchi 	/*
1691*fd71220bSRobert Mustacchi 	 * This was successful, there is one last dance that we must do. We must
1692*fd71220bSRobert Mustacchi 	 * place a hold on the kgpio's dip. And of course, no lock holding
1693*fd71220bSRobert Mustacchi 	 * across the ndi hold.
1694*fd71220bSRobert Mustacchi 	 */
1695*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
1696*fd71220bSRobert Mustacchi 	e_ddi_hold_devi(kgpio->kgpio_dip);
1697*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
1698*fd71220bSRobert Mustacchi 
1699*fd71220bSRobert Mustacchi 	return (0);
1700*fd71220bSRobert Mustacchi }
1701*fd71220bSRobert Mustacchi 
1702*fd71220bSRobert Mustacchi static int
kgpio_ioctl_dpio_destroy(kgpio_t * kgpio,intptr_t arg,int mode)1703*fd71220bSRobert Mustacchi kgpio_ioctl_dpio_destroy(kgpio_t *kgpio, intptr_t arg, int mode)
1704*fd71220bSRobert Mustacchi {
1705*fd71220bSRobert Mustacchi 	dpio_t *dpio;
1706*fd71220bSRobert Mustacchi 	kgpio_dpio_destroy_t destroy;
1707*fd71220bSRobert Mustacchi 
1708*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio->kgpio_mutex));
1709*fd71220bSRobert Mustacchi 
1710*fd71220bSRobert Mustacchi 	if ((mode & FWRITE) == 0) {
1711*fd71220bSRobert Mustacchi 		return (EBADF);
1712*fd71220bSRobert Mustacchi 	}
1713*fd71220bSRobert Mustacchi 
1714*fd71220bSRobert Mustacchi 	if (ddi_copyin((void *)arg, &destroy, sizeof (kgpio_dpio_destroy_t),
1715*fd71220bSRobert Mustacchi 	    mode & FKIOCTL) != 0) {
1716*fd71220bSRobert Mustacchi 		return (EFAULT);
1717*fd71220bSRobert Mustacchi 	}
1718*fd71220bSRobert Mustacchi 
1719*fd71220bSRobert Mustacchi 	if (destroy.kdd_id >= kgpio->kgpio_ngpios) {
1720*fd71220bSRobert Mustacchi 		return (ENOENT);
1721*fd71220bSRobert Mustacchi 	}
1722*fd71220bSRobert Mustacchi 
1723*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
1724*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
1725*fd71220bSRobert Mustacchi 	for (dpio = list_head(&kgpio_g_dpios); dpio != NULL;
1726*fd71220bSRobert Mustacchi 	    dpio = list_next(&kgpio_g_dpios, dpio)) {
1727*fd71220bSRobert Mustacchi 		if (dpio->dpio_kgpio == kgpio &&
1728*fd71220bSRobert Mustacchi 		    dpio->dpio_gpio_num == destroy.kdd_id) {
1729*fd71220bSRobert Mustacchi 			break;
1730*fd71220bSRobert Mustacchi 		}
1731*fd71220bSRobert Mustacchi 	}
1732*fd71220bSRobert Mustacchi 
1733*fd71220bSRobert Mustacchi 	if (dpio == NULL) {
1734*fd71220bSRobert Mustacchi 		mutex_enter(&kgpio->kgpio_mutex);
1735*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1736*fd71220bSRobert Mustacchi 		return (ENOENT);
1737*fd71220bSRobert Mustacchi 	}
1738*fd71220bSRobert Mustacchi 
1739*fd71220bSRobert Mustacchi 	if ((dpio->dpio_status & DPIO_S_OPEN) != 0) {
1740*fd71220bSRobert Mustacchi 		mutex_enter(&kgpio->kgpio_mutex);
1741*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1742*fd71220bSRobert Mustacchi 		return (EBUSY);
1743*fd71220bSRobert Mustacchi 	}
1744*fd71220bSRobert Mustacchi 
1745*fd71220bSRobert Mustacchi 	/*
1746*fd71220bSRobert Mustacchi 	 * OK, time to tear all this down. Remove it from global visibility as
1747*fd71220bSRobert Mustacchi 	 * it's not open. After this point, we no longer need the kgpio_g_lock.
1748*fd71220bSRobert Mustacchi 	 */
1749*fd71220bSRobert Mustacchi 	list_remove(&kgpio_g_dpios, dpio);
1750*fd71220bSRobert Mustacchi 	avl_remove(&kgpio_g_minors, &dpio->dpio_minor);
1751*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
1752*fd71220bSRobert Mustacchi 
1753*fd71220bSRobert Mustacchi 	/*
1754*fd71220bSRobert Mustacchi 	 * At this point, it should be safe to destroy the dpio and then clean
1755*fd71220bSRobert Mustacchi 	 * up the remaining tracking on the kgpio. Over there, we need to need
1756*fd71220bSRobert Mustacchi 	 * to drop our corresponding hold and decrement the overall count.
1757*fd71220bSRobert Mustacchi 	 *
1758*fd71220bSRobert Mustacchi 	 * To ensure that devfs notices that the minor goes away, we basically
1759*fd71220bSRobert Mustacchi 	 * have to flag the directory for rebuild. As such, we do this somewhat
1760*fd71220bSRobert Mustacchi 	 * via a constrained max power way -- by asking it to clean up after
1761*fd71220bSRobert Mustacchi 	 * ourselves. This will of course be busy, but it does mean that a
1762*fd71220bSRobert Mustacchi 	 * rebuild flag will show up.
1763*fd71220bSRobert Mustacchi 	 */
1764*fd71220bSRobert Mustacchi 	kgpio_dpio_cleanup(dpio);
1765*fd71220bSRobert Mustacchi 	(void) devfs_clean(ddi_get_parent(kgpio_g_dip), "kgpio@0", 0);
1766*fd71220bSRobert Mustacchi 	ddi_release_devi(kgpio->kgpio_dip);
1767*fd71220bSRobert Mustacchi 
1768*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
1769*fd71220bSRobert Mustacchi 	VERIFY3P(kgpio->kgpio_ndpios, >, 0);
1770*fd71220bSRobert Mustacchi 	kgpio->kgpio_ndpios--;
1771*fd71220bSRobert Mustacchi 
1772*fd71220bSRobert Mustacchi 	return (0);
1773*fd71220bSRobert Mustacchi }
1774*fd71220bSRobert Mustacchi 
1775*fd71220bSRobert Mustacchi static int
kgpio_ioctl_dpio_info_common(const dpio_t * dpio,dpio_info_t * infop,intptr_t arg,int mode)1776*fd71220bSRobert Mustacchi kgpio_ioctl_dpio_info_common(const dpio_t *dpio, dpio_info_t *infop,
1777*fd71220bSRobert Mustacchi     intptr_t arg, int mode)
1778*fd71220bSRobert Mustacchi {
1779*fd71220bSRobert Mustacchi 	if ((mode & FREAD) == 0) {
1780*fd71220bSRobert Mustacchi 		return (EBADF);
1781*fd71220bSRobert Mustacchi 	}
1782*fd71220bSRobert Mustacchi 
1783*fd71220bSRobert Mustacchi 	bcopy(dpio->dpio_kgpio->kgpio_mname, infop->dpi_ctrl,
1784*fd71220bSRobert Mustacchi 	    sizeof (dpio->dpio_kgpio->kgpio_mname));
1785*fd71220bSRobert Mustacchi 	infop->dpi_gpio = dpio->dpio_gpio_num;
1786*fd71220bSRobert Mustacchi 	infop->dpi_caps = dpio->dpio_caps;
1787*fd71220bSRobert Mustacchi 	infop->dpi_flags = dpio->dpio_flags;
1788*fd71220bSRobert Mustacchi 
1789*fd71220bSRobert Mustacchi 	if (ddi_copyout(infop, (void *)arg, sizeof (dpio_info_t),
1790*fd71220bSRobert Mustacchi 	    mode & FKIOCTL) != 0) {
1791*fd71220bSRobert Mustacchi 		return (EFAULT);
1792*fd71220bSRobert Mustacchi 	}
1793*fd71220bSRobert Mustacchi 
1794*fd71220bSRobert Mustacchi 	return (0);
1795*fd71220bSRobert Mustacchi }
1796*fd71220bSRobert Mustacchi 
1797*fd71220bSRobert Mustacchi static int
kgpio_ioctl_dpio_info_specific(dpio_t * dpio,intptr_t arg,int mode)1798*fd71220bSRobert Mustacchi kgpio_ioctl_dpio_info_specific(dpio_t *dpio, intptr_t arg, int mode)
1799*fd71220bSRobert Mustacchi {
1800*fd71220bSRobert Mustacchi 	dpio_info_t info;
1801*fd71220bSRobert Mustacchi 
1802*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&dpio->dpio_mutex));
1803*fd71220bSRobert Mustacchi 
1804*fd71220bSRobert Mustacchi 	bzero(&info, sizeof (info));
1805*fd71220bSRobert Mustacchi 	bcopy(dpio->dpio_name, info.dpi_dpio, sizeof (dpio->dpio_name));
1806*fd71220bSRobert Mustacchi 	return (kgpio_ioctl_dpio_info_common(dpio, &info, arg, mode));
1807*fd71220bSRobert Mustacchi }
1808*fd71220bSRobert Mustacchi 
1809*fd71220bSRobert Mustacchi static int
kgpio_ioctl_dpio_time(dpio_t * dpio,intptr_t arg,int mode)1810*fd71220bSRobert Mustacchi kgpio_ioctl_dpio_time(dpio_t *dpio, intptr_t arg, int mode)
1811*fd71220bSRobert Mustacchi {
1812*fd71220bSRobert Mustacchi 	dpio_timing_t time;
1813*fd71220bSRobert Mustacchi 
1814*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&dpio->dpio_mutex));
1815*fd71220bSRobert Mustacchi 
1816*fd71220bSRobert Mustacchi 	if ((mode & FREAD) == 0) {
1817*fd71220bSRobert Mustacchi 		return (EBADF);
1818*fd71220bSRobert Mustacchi 	}
1819*fd71220bSRobert Mustacchi 
1820*fd71220bSRobert Mustacchi 	bzero(&time, sizeof (time));
1821*fd71220bSRobert Mustacchi 	time.dpt_last_input_intr = dpio->dpio_last_intr;
1822*fd71220bSRobert Mustacchi 	time.dpt_last_write = dpio->dpio_last_write;
1823*fd71220bSRobert Mustacchi 
1824*fd71220bSRobert Mustacchi 	if (ddi_copyout(&time, (void *)arg, sizeof (dpio_timing_t),
1825*fd71220bSRobert Mustacchi 	    mode & FKIOCTL) != 0) {
1826*fd71220bSRobert Mustacchi 		return (EFAULT);
1827*fd71220bSRobert Mustacchi 	}
1828*fd71220bSRobert Mustacchi 
1829*fd71220bSRobert Mustacchi 	return (0);
1830*fd71220bSRobert Mustacchi }
1831*fd71220bSRobert Mustacchi 
1832*fd71220bSRobert Mustacchi static int
kgpio_ioctl_dpio_curout(dpio_t * dpio,intptr_t arg,int mode)1833*fd71220bSRobert Mustacchi kgpio_ioctl_dpio_curout(dpio_t *dpio, intptr_t arg, int mode)
1834*fd71220bSRobert Mustacchi {
1835*fd71220bSRobert Mustacchi 	int ret;
1836*fd71220bSRobert Mustacchi 	dpio_curout_t curout;
1837*fd71220bSRobert Mustacchi 	kgpio_t *kgpio = dpio->dpio_kgpio;
1838*fd71220bSRobert Mustacchi 
1839*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&dpio->dpio_mutex));
1840*fd71220bSRobert Mustacchi 
1841*fd71220bSRobert Mustacchi 	if ((mode & FREAD) == 0) {
1842*fd71220bSRobert Mustacchi 		return (EBADF);
1843*fd71220bSRobert Mustacchi 	}
1844*fd71220bSRobert Mustacchi 
1845*fd71220bSRobert Mustacchi 	bzero(&curout, sizeof (curout));
1846*fd71220bSRobert Mustacchi 	if ((dpio->dpio_caps & DPIO_C_WRITE) == 0) {
1847*fd71220bSRobert Mustacchi 		return (ENOTSUP);
1848*fd71220bSRobert Mustacchi 	}
1849*fd71220bSRobert Mustacchi 
1850*fd71220bSRobert Mustacchi 	mutex_exit(&dpio->dpio_mutex);
1851*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
1852*fd71220bSRobert Mustacchi 	ret = kgpio->kgpio_ops->kgo_output_state(kgpio->kgpio_drv,
1853*fd71220bSRobert Mustacchi 	    dpio->dpio_gpio_num, &curout.dps_curout);
1854*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
1855*fd71220bSRobert Mustacchi 	mutex_enter(&dpio->dpio_mutex);
1856*fd71220bSRobert Mustacchi 
1857*fd71220bSRobert Mustacchi 	if (ret != 0) {
1858*fd71220bSRobert Mustacchi 		return (ret);
1859*fd71220bSRobert Mustacchi 
1860*fd71220bSRobert Mustacchi 	}
1861*fd71220bSRobert Mustacchi 
1862*fd71220bSRobert Mustacchi 	if (ddi_copyout(&curout, (void *)arg, sizeof (dpio_curout_t),
1863*fd71220bSRobert Mustacchi 	    mode & FKIOCTL) != 0) {
1864*fd71220bSRobert Mustacchi 		return (EFAULT);
1865*fd71220bSRobert Mustacchi 	}
1866*fd71220bSRobert Mustacchi 
1867*fd71220bSRobert Mustacchi 	return (0);
1868*fd71220bSRobert Mustacchi }
1869*fd71220bSRobert Mustacchi 
1870*fd71220bSRobert Mustacchi static int
kgpio_ioctl_dpio_info_search(intptr_t arg,int mode)1871*fd71220bSRobert Mustacchi kgpio_ioctl_dpio_info_search(intptr_t arg, int mode)
1872*fd71220bSRobert Mustacchi {
1873*fd71220bSRobert Mustacchi 	size_t len;
1874*fd71220bSRobert Mustacchi 	dpio_info_t info;
1875*fd71220bSRobert Mustacchi 
1876*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio_g_mutex));
1877*fd71220bSRobert Mustacchi 
1878*fd71220bSRobert Mustacchi 	if (ddi_copyin((void *)arg, &info, sizeof (dpio_info_t),
1879*fd71220bSRobert Mustacchi 	    mode & FKIOCTL) != 0) {
1880*fd71220bSRobert Mustacchi 		return (EFAULT);
1881*fd71220bSRobert Mustacchi 	}
1882*fd71220bSRobert Mustacchi 
1883*fd71220bSRobert Mustacchi 	len = strnlen(info.dpi_dpio, sizeof (info.dpi_dpio));
1884*fd71220bSRobert Mustacchi 	if (len == 0 || len == sizeof (info.dpi_dpio)) {
1885*fd71220bSRobert Mustacchi 		return (EINVAL);
1886*fd71220bSRobert Mustacchi 	}
1887*fd71220bSRobert Mustacchi 
1888*fd71220bSRobert Mustacchi 	for (dpio_t *dpio = list_head(&kgpio_g_dpios); dpio != NULL;
1889*fd71220bSRobert Mustacchi 	    dpio = list_next(&kgpio_g_dpios, dpio)) {
1890*fd71220bSRobert Mustacchi 		if (strcmp(dpio->dpio_name, info.dpi_dpio) == 0) {
1891*fd71220bSRobert Mustacchi 			return (kgpio_ioctl_dpio_info_common(dpio, &info, arg,
1892*fd71220bSRobert Mustacchi 			    mode));
1893*fd71220bSRobert Mustacchi 		}
1894*fd71220bSRobert Mustacchi 	}
1895*fd71220bSRobert Mustacchi 
1896*fd71220bSRobert Mustacchi 	return (ENOENT);
1897*fd71220bSRobert Mustacchi }
1898*fd71220bSRobert Mustacchi 
1899*fd71220bSRobert Mustacchi static int
kgpio_ioctl_gpio_name2id(kgpio_t * kgpio,intptr_t arg,int mode)1900*fd71220bSRobert Mustacchi kgpio_ioctl_gpio_name2id(kgpio_t *kgpio, intptr_t arg, int mode)
1901*fd71220bSRobert Mustacchi {
1902*fd71220bSRobert Mustacchi 	int ret;
1903*fd71220bSRobert Mustacchi 	kgpio_ioc_name2id_t id;
1904*fd71220bSRobert Mustacchi 	size_t len;
1905*fd71220bSRobert Mustacchi 
1906*fd71220bSRobert Mustacchi 	ASSERT(MUTEX_HELD(&kgpio->kgpio_mutex));
1907*fd71220bSRobert Mustacchi 
1908*fd71220bSRobert Mustacchi 	if ((mode & FREAD) == 0) {
1909*fd71220bSRobert Mustacchi 		return (EBADF);
1910*fd71220bSRobert Mustacchi 	}
1911*fd71220bSRobert Mustacchi 
1912*fd71220bSRobert Mustacchi 	if (ddi_copyin((void *)arg, &id, sizeof (id), mode & FKIOCTL) != 0) {
1913*fd71220bSRobert Mustacchi 		return (EFAULT);
1914*fd71220bSRobert Mustacchi 	}
1915*fd71220bSRobert Mustacchi 
1916*fd71220bSRobert Mustacchi 	len = strnlen(id.kin_name, sizeof (id.kin_name));
1917*fd71220bSRobert Mustacchi 	if (len == 0 || len == sizeof (id.kin_name)) {
1918*fd71220bSRobert Mustacchi 		return (EINVAL);
1919*fd71220bSRobert Mustacchi 	}
1920*fd71220bSRobert Mustacchi 
1921*fd71220bSRobert Mustacchi 	ret = kgpio->kgpio_ops->kgo_name2id(kgpio->kgpio_drv, id.kin_name,
1922*fd71220bSRobert Mustacchi 	    &id.kin_id);
1923*fd71220bSRobert Mustacchi 	if (ret != 0) {
1924*fd71220bSRobert Mustacchi 		return (ret);
1925*fd71220bSRobert Mustacchi 	}
1926*fd71220bSRobert Mustacchi 
1927*fd71220bSRobert Mustacchi 	if (ddi_copyout(&id, (void *)arg, sizeof (id), mode & FKIOCTL) != 0) {
1928*fd71220bSRobert Mustacchi 		return (EFAULT);
1929*fd71220bSRobert Mustacchi 	}
1930*fd71220bSRobert Mustacchi 
1931*fd71220bSRobert Mustacchi 	return (0);
1932*fd71220bSRobert Mustacchi }
1933*fd71220bSRobert Mustacchi 
1934*fd71220bSRobert Mustacchi static int
kgpio_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1935*fd71220bSRobert Mustacchi kgpio_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1936*fd71220bSRobert Mustacchi     int *rvalp)
1937*fd71220bSRobert Mustacchi {
1938*fd71220bSRobert Mustacchi 	int ret;
1939*fd71220bSRobert Mustacchi 	kgpio_minor_t *minor;
1940*fd71220bSRobert Mustacchi 	kgpio_t *kgpio;
1941*fd71220bSRobert Mustacchi 	dpio_t *dpio;
1942*fd71220bSRobert Mustacchi 
1943*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
1944*fd71220bSRobert Mustacchi 	minor = kgpio_minor_find((id_t)getminor(dev));
1945*fd71220bSRobert Mustacchi 	VERIFY3P(minor, !=, NULL);
1946*fd71220bSRobert Mustacchi 	switch (minor->kminor_type) {
1947*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_CTRL:
1948*fd71220bSRobert Mustacchi 		kgpio = minor->kminor_data.kminor_ctrl;
1949*fd71220bSRobert Mustacchi 		VERIFY3P(kgpio, !=, NULL);
1950*fd71220bSRobert Mustacchi 
1951*fd71220bSRobert Mustacchi 		mutex_enter(&kgpio->kgpio_mutex);
1952*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1953*fd71220bSRobert Mustacchi 		ASSERT(kgpio->kgpio_flags & KGPIO_F_VALID);
1954*fd71220bSRobert Mustacchi 		ASSERT(kgpio->kgpio_flags & KGPIO_F_HELD);
1955*fd71220bSRobert Mustacchi 
1956*fd71220bSRobert Mustacchi 		switch (cmd) {
1957*fd71220bSRobert Mustacchi 		case KGPIO_IOC_CTRL_INFO:
1958*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_ctrl_info(kgpio, arg, mode);
1959*fd71220bSRobert Mustacchi 			break;
1960*fd71220bSRobert Mustacchi 		case KGPIO_IOC_GPIO_INFO:
1961*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_gpio_info(kgpio, arg, mode);
1962*fd71220bSRobert Mustacchi 			break;
1963*fd71220bSRobert Mustacchi 		case KGPIO_IOC_GPIO_UPDATE:
1964*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_gpio_update(kgpio, arg, mode);
1965*fd71220bSRobert Mustacchi 			break;
1966*fd71220bSRobert Mustacchi 		case KGPIO_IOC_DPIO_CREATE:
1967*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_dpio_create(kgpio, arg, mode);
1968*fd71220bSRobert Mustacchi 			break;
1969*fd71220bSRobert Mustacchi 		case KGPIO_IOC_DPIO_DESTROY:
1970*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_dpio_destroy(kgpio, arg, mode);
1971*fd71220bSRobert Mustacchi 			break;
1972*fd71220bSRobert Mustacchi 		case KGPIO_IOC_GPIO_NAME2ID:
1973*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_gpio_name2id(kgpio, arg, mode);
1974*fd71220bSRobert Mustacchi 			break;
1975*fd71220bSRobert Mustacchi 		default:
1976*fd71220bSRobert Mustacchi 			ret = ENOTTY;
1977*fd71220bSRobert Mustacchi 			break;
1978*fd71220bSRobert Mustacchi 		}
1979*fd71220bSRobert Mustacchi 
1980*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
1981*fd71220bSRobert Mustacchi 		break;
1982*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_DPIO:
1983*fd71220bSRobert Mustacchi 		dpio = minor->kminor_data.kminor_dpio;
1984*fd71220bSRobert Mustacchi 		VERIFY3P(dpio, !=, NULL);
1985*fd71220bSRobert Mustacchi 		mutex_enter(&dpio->dpio_mutex);
1986*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
1987*fd71220bSRobert Mustacchi 
1988*fd71220bSRobert Mustacchi 		switch (cmd) {
1989*fd71220bSRobert Mustacchi 		case DPIO_IOC_INFO:
1990*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_dpio_info_specific(dpio, arg, mode);
1991*fd71220bSRobert Mustacchi 			break;
1992*fd71220bSRobert Mustacchi 		case DPIO_IOC_TIMING:
1993*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_dpio_time(dpio, arg, mode);
1994*fd71220bSRobert Mustacchi 			break;
1995*fd71220bSRobert Mustacchi 		case DPIO_IOC_CUROUT:
1996*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_dpio_curout(dpio, arg, mode);
1997*fd71220bSRobert Mustacchi 			break;
1998*fd71220bSRobert Mustacchi 		default:
1999*fd71220bSRobert Mustacchi 			ret = ENOTTY;
2000*fd71220bSRobert Mustacchi 			break;
2001*fd71220bSRobert Mustacchi 		}
2002*fd71220bSRobert Mustacchi 		mutex_exit(&dpio->dpio_mutex);
2003*fd71220bSRobert Mustacchi 		break;
2004*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_DPINFO:
2005*fd71220bSRobert Mustacchi 		switch (cmd) {
2006*fd71220bSRobert Mustacchi 		case DPIO_IOC_INFO:
2007*fd71220bSRobert Mustacchi 			ret = kgpio_ioctl_dpio_info_search(arg, mode);
2008*fd71220bSRobert Mustacchi 			break;
2009*fd71220bSRobert Mustacchi 		default:
2010*fd71220bSRobert Mustacchi 			ret = ENOTTY;
2011*fd71220bSRobert Mustacchi 			break;
2012*fd71220bSRobert Mustacchi 		}
2013*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2014*fd71220bSRobert Mustacchi 		break;
2015*fd71220bSRobert Mustacchi 	default:
2016*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2017*fd71220bSRobert Mustacchi 		return (ENXIO);
2018*fd71220bSRobert Mustacchi 	}
2019*fd71220bSRobert Mustacchi 	return (ret);
2020*fd71220bSRobert Mustacchi }
2021*fd71220bSRobert Mustacchi 
2022*fd71220bSRobert Mustacchi static int
kgpio_read(dev_t dev,struct uio * uiop,cred_t * credp)2023*fd71220bSRobert Mustacchi kgpio_read(dev_t dev, struct uio *uiop, cred_t *credp)
2024*fd71220bSRobert Mustacchi {
2025*fd71220bSRobert Mustacchi 	int ret;
2026*fd71220bSRobert Mustacchi 	kgpio_minor_t *minor;
2027*fd71220bSRobert Mustacchi 	dpio_t *dpio;
2028*fd71220bSRobert Mustacchi 	kgpio_t *kgpio;
2029*fd71220bSRobert Mustacchi 	dpio_input_t input;
2030*fd71220bSRobert Mustacchi 	offset_t off;
2031*fd71220bSRobert Mustacchi 
2032*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
2033*fd71220bSRobert Mustacchi 	minor = kgpio_minor_find((id_t)getminor(dev));
2034*fd71220bSRobert Mustacchi 	VERIFY3P(minor, !=, NULL);
2035*fd71220bSRobert Mustacchi 
2036*fd71220bSRobert Mustacchi 	if (minor->kminor_type != KGPIO_MINOR_T_DPIO) {
2037*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2038*fd71220bSRobert Mustacchi 		return (ENXIO);
2039*fd71220bSRobert Mustacchi 	}
2040*fd71220bSRobert Mustacchi 
2041*fd71220bSRobert Mustacchi 	dpio = minor->kminor_data.kminor_dpio;
2042*fd71220bSRobert Mustacchi 	VERIFY3P(dpio, !=, NULL);
2043*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
2044*fd71220bSRobert Mustacchi 
2045*fd71220bSRobert Mustacchi 	if ((dpio->dpio_caps & DPIO_C_READ) == 0) {
2046*fd71220bSRobert Mustacchi 		return (ENOTSUP);
2047*fd71220bSRobert Mustacchi 	}
2048*fd71220bSRobert Mustacchi 
2049*fd71220bSRobert Mustacchi 	if (uiop->uio_resid <= 0) {
2050*fd71220bSRobert Mustacchi 		return (EINVAL);
2051*fd71220bSRobert Mustacchi 	}
2052*fd71220bSRobert Mustacchi 
2053*fd71220bSRobert Mustacchi 	if (uiop->uio_resid < sizeof (input)) {
2054*fd71220bSRobert Mustacchi 		return (EOVERFLOW);
2055*fd71220bSRobert Mustacchi 	}
2056*fd71220bSRobert Mustacchi 
2057*fd71220bSRobert Mustacchi 	kgpio = dpio->dpio_kgpio;
2058*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
2059*fd71220bSRobert Mustacchi 	ret = kgpio->kgpio_ops->kgo_input(kgpio->kgpio_drv, dpio->dpio_gpio_num,
2060*fd71220bSRobert Mustacchi 	    &input);
2061*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
2062*fd71220bSRobert Mustacchi 	if (ret != 0) {
2063*fd71220bSRobert Mustacchi 		return (ret);
2064*fd71220bSRobert Mustacchi 	}
2065*fd71220bSRobert Mustacchi 
2066*fd71220bSRobert Mustacchi 	off = uiop->uio_loffset;
2067*fd71220bSRobert Mustacchi 	ret = uiomove(&input, sizeof (input), UIO_READ, uiop);
2068*fd71220bSRobert Mustacchi 	uiop->uio_loffset = off;
2069*fd71220bSRobert Mustacchi 
2070*fd71220bSRobert Mustacchi 	return (ret);
2071*fd71220bSRobert Mustacchi }
2072*fd71220bSRobert Mustacchi 
2073*fd71220bSRobert Mustacchi static int
kgpio_write(dev_t dev,struct uio * uiop,cred_t * credp)2074*fd71220bSRobert Mustacchi kgpio_write(dev_t dev, struct uio *uiop, cred_t *credp)
2075*fd71220bSRobert Mustacchi {
2076*fd71220bSRobert Mustacchi 	int ret;
2077*fd71220bSRobert Mustacchi 	kgpio_minor_t *minor;
2078*fd71220bSRobert Mustacchi 	dpio_t *dpio;
2079*fd71220bSRobert Mustacchi 	kgpio_t *kgpio;
2080*fd71220bSRobert Mustacchi 	dpio_output_t output;
2081*fd71220bSRobert Mustacchi 	offset_t off;
2082*fd71220bSRobert Mustacchi 
2083*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
2084*fd71220bSRobert Mustacchi 	minor = kgpio_minor_find((id_t)getminor(dev));
2085*fd71220bSRobert Mustacchi 	VERIFY3P(minor, !=, NULL);
2086*fd71220bSRobert Mustacchi 
2087*fd71220bSRobert Mustacchi 	if (minor->kminor_type != KGPIO_MINOR_T_DPIO) {
2088*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2089*fd71220bSRobert Mustacchi 		return (ENXIO);
2090*fd71220bSRobert Mustacchi 	}
2091*fd71220bSRobert Mustacchi 
2092*fd71220bSRobert Mustacchi 	dpio = minor->kminor_data.kminor_dpio;
2093*fd71220bSRobert Mustacchi 	VERIFY3P(dpio, !=, NULL);
2094*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
2095*fd71220bSRobert Mustacchi 
2096*fd71220bSRobert Mustacchi 	if ((dpio->dpio_caps & DPIO_C_WRITE) == 0) {
2097*fd71220bSRobert Mustacchi 		return (ENOTSUP);
2098*fd71220bSRobert Mustacchi 	}
2099*fd71220bSRobert Mustacchi 
2100*fd71220bSRobert Mustacchi 	if (uiop->uio_resid < sizeof (output)) {
2101*fd71220bSRobert Mustacchi 		return (EINVAL);
2102*fd71220bSRobert Mustacchi 	}
2103*fd71220bSRobert Mustacchi 
2104*fd71220bSRobert Mustacchi 	off = uiop->uio_loffset;
2105*fd71220bSRobert Mustacchi 	ret = uiomove(&output, sizeof (output), UIO_WRITE, uiop);
2106*fd71220bSRobert Mustacchi 	uiop->uio_loffset = off;
2107*fd71220bSRobert Mustacchi 	if (ret != 0) {
2108*fd71220bSRobert Mustacchi 		return (ret);
2109*fd71220bSRobert Mustacchi 	}
2110*fd71220bSRobert Mustacchi 
2111*fd71220bSRobert Mustacchi 	switch (output) {
2112*fd71220bSRobert Mustacchi 	case DPIO_OUTPUT_LOW:
2113*fd71220bSRobert Mustacchi 	case DPIO_OUTPUT_HIGH:
2114*fd71220bSRobert Mustacchi 	case DPIO_OUTPUT_DISABLE:
2115*fd71220bSRobert Mustacchi 		break;
2116*fd71220bSRobert Mustacchi 	default:
2117*fd71220bSRobert Mustacchi 		return (EINVAL);
2118*fd71220bSRobert Mustacchi 	}
2119*fd71220bSRobert Mustacchi 
2120*fd71220bSRobert Mustacchi 	kgpio = dpio->dpio_kgpio;
2121*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio->kgpio_mutex);
2122*fd71220bSRobert Mustacchi 	ret = kgpio->kgpio_ops->kgo_output(kgpio->kgpio_drv,
2123*fd71220bSRobert Mustacchi 	    dpio->dpio_gpio_num, output);
2124*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio->kgpio_mutex);
2125*fd71220bSRobert Mustacchi 
2126*fd71220bSRobert Mustacchi 	if (ret == 0) {
2127*fd71220bSRobert Mustacchi 		mutex_enter(&dpio->dpio_mutex);
2128*fd71220bSRobert Mustacchi 		dpio->dpio_last_write = gethrtime();
2129*fd71220bSRobert Mustacchi 		mutex_exit(&dpio->dpio_mutex);
2130*fd71220bSRobert Mustacchi 	}
2131*fd71220bSRobert Mustacchi 
2132*fd71220bSRobert Mustacchi 	return (ret);
2133*fd71220bSRobert Mustacchi }
2134*fd71220bSRobert Mustacchi 
2135*fd71220bSRobert Mustacchi static int
kgpio_close(dev_t dev,int flag,int otyp,cred_t * credp)2136*fd71220bSRobert Mustacchi kgpio_close(dev_t dev, int flag, int otyp, cred_t *credp)
2137*fd71220bSRobert Mustacchi {
2138*fd71220bSRobert Mustacchi 	kgpio_minor_t *minor;
2139*fd71220bSRobert Mustacchi 	kgpio_t *kgpio;
2140*fd71220bSRobert Mustacchi 	dpio_t *dpio;
2141*fd71220bSRobert Mustacchi 
2142*fd71220bSRobert Mustacchi 	if (otyp != OTYP_CHR) {
2143*fd71220bSRobert Mustacchi 		return (EINVAL);
2144*fd71220bSRobert Mustacchi 	}
2145*fd71220bSRobert Mustacchi 
2146*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
2147*fd71220bSRobert Mustacchi 	minor = kgpio_minor_find((id_t)getminor(dev));
2148*fd71220bSRobert Mustacchi 	VERIFY3P(minor, !=, NULL);
2149*fd71220bSRobert Mustacchi 	switch (minor->kminor_type) {
2150*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_CTRL:
2151*fd71220bSRobert Mustacchi 		kgpio = minor->kminor_data.kminor_ctrl;
2152*fd71220bSRobert Mustacchi 		VERIFY3P(kgpio, !=, NULL);
2153*fd71220bSRobert Mustacchi 
2154*fd71220bSRobert Mustacchi 		mutex_enter(&kgpio->kgpio_mutex);
2155*fd71220bSRobert Mustacchi 		ASSERT(kgpio->kgpio_flags & KGPIO_F_VALID);
2156*fd71220bSRobert Mustacchi 		ASSERT(kgpio->kgpio_flags & KGPIO_F_HELD);
2157*fd71220bSRobert Mustacchi 
2158*fd71220bSRobert Mustacchi 		/*
2159*fd71220bSRobert Mustacchi 		 * The system guarantees that we are mutually exclusive with
2160*fd71220bSRobert Mustacchi 		 * open(9E).  As such, it's safe for us to go ahead and clear
2161*fd71220bSRobert Mustacchi 		 * this out. Note, we drop all of our locks to honor the general
2162*fd71220bSRobert Mustacchi 		 * lock ordering of no NDI activity with locks held.
2163*fd71220bSRobert Mustacchi 		 */
2164*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2165*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio->kgpio_mutex);
2166*fd71220bSRobert Mustacchi 
2167*fd71220bSRobert Mustacchi 		kgpio_release(kgpio);
2168*fd71220bSRobert Mustacchi 		return (0);
2169*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_DPIO:
2170*fd71220bSRobert Mustacchi 		dpio = minor->kminor_data.kminor_dpio;
2171*fd71220bSRobert Mustacchi 		VERIFY3P(dpio, !=, NULL);
2172*fd71220bSRobert Mustacchi 		mutex_enter(&dpio->dpio_mutex);
2173*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2174*fd71220bSRobert Mustacchi 
2175*fd71220bSRobert Mustacchi 		/*
2176*fd71220bSRobert Mustacchi 		 * Because of the last-close style behavior, the only thing that
2177*fd71220bSRobert Mustacchi 		 * we need to do is to make sure that we clear out our state
2178*fd71220bSRobert Mustacchi 		 * flags and indicate that we are no longer open and no longer
2179*fd71220bSRobert Mustacchi 		 * exclusive, if we were.
2180*fd71220bSRobert Mustacchi 		 */
2181*fd71220bSRobert Mustacchi 		dpio->dpio_status &= ~(DPIO_S_EXCL | DPIO_S_OPEN);
2182*fd71220bSRobert Mustacchi 		mutex_exit(&dpio->dpio_mutex);
2183*fd71220bSRobert Mustacchi 		return (0);
2184*fd71220bSRobert Mustacchi 	case KGPIO_MINOR_T_DPINFO:
2185*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2186*fd71220bSRobert Mustacchi 		/*
2187*fd71220bSRobert Mustacchi 		 * There is nothing special to do to close the dpio information
2188*fd71220bSRobert Mustacchi 		 * based minor device as there is no state or other logic
2189*fd71220bSRobert Mustacchi 		 * associated with it.
2190*fd71220bSRobert Mustacchi 		 */
2191*fd71220bSRobert Mustacchi 		return (0);
2192*fd71220bSRobert Mustacchi 	default:
2193*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2194*fd71220bSRobert Mustacchi 		return (ENXIO);
2195*fd71220bSRobert Mustacchi 	}
2196*fd71220bSRobert Mustacchi }
2197*fd71220bSRobert Mustacchi 
2198*fd71220bSRobert Mustacchi static int
kgpio_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2199*fd71220bSRobert Mustacchi kgpio_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2200*fd71220bSRobert Mustacchi {
2201*fd71220bSRobert Mustacchi 	switch (cmd) {
2202*fd71220bSRobert Mustacchi 	case DDI_ATTACH:
2203*fd71220bSRobert Mustacchi 		break;
2204*fd71220bSRobert Mustacchi 	case DDI_RESUME:
2205*fd71220bSRobert Mustacchi 		return (DDI_SUCCESS);
2206*fd71220bSRobert Mustacchi 	default:
2207*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2208*fd71220bSRobert Mustacchi 	}
2209*fd71220bSRobert Mustacchi 
2210*fd71220bSRobert Mustacchi 	if (ddi_get_instance(dip) != 0) {
2211*fd71220bSRobert Mustacchi 		dev_err(dip, CE_WARN, "asked to attach non-zero instance");
2212*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2213*fd71220bSRobert Mustacchi 	}
2214*fd71220bSRobert Mustacchi 
2215*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
2216*fd71220bSRobert Mustacchi 	if (kgpio_g_dip != NULL) {
2217*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2218*fd71220bSRobert Mustacchi 		dev_err(dip, CE_WARN, "asked to attach a second kgpio "
2219*fd71220bSRobert Mustacchi 		    "instance");
2220*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2221*fd71220bSRobert Mustacchi 	}
2222*fd71220bSRobert Mustacchi 
2223*fd71220bSRobert Mustacchi 	/*
2224*fd71220bSRobert Mustacchi 	 * Set up the dpio minor, which always uses minor number 1, note this is
2225*fd71220bSRobert Mustacchi 	 * reserved outside of the id_space, so we don't have to allocate or
2226*fd71220bSRobert Mustacchi 	 * worry about failure.
2227*fd71220bSRobert Mustacchi 	 */
2228*fd71220bSRobert Mustacchi 	if (ddi_create_minor_node(dip, KGPIO_MINOR_NAME_DPINFO, S_IFCHR,
2229*fd71220bSRobert Mustacchi 	    KGPIO_MINOR_DPINFO, DDI_PSEUDO, 0) != 0) {
2230*fd71220bSRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to create dpinfo minor");
2231*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2232*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2233*fd71220bSRobert Mustacchi 	}
2234*fd71220bSRobert Mustacchi 
2235*fd71220bSRobert Mustacchi 	kgpio_g_dpinfo.kminor_id = KGPIO_MINOR_DPINFO;
2236*fd71220bSRobert Mustacchi 	kgpio_g_dpinfo.kminor_type = KGPIO_MINOR_T_DPINFO;
2237*fd71220bSRobert Mustacchi 	avl_add(&kgpio_g_minors, &kgpio_g_dpinfo);
2238*fd71220bSRobert Mustacchi 	kgpio_g_dip = dip;
2239*fd71220bSRobert Mustacchi 
2240*fd71220bSRobert Mustacchi 	/*
2241*fd71220bSRobert Mustacchi 	 * At this point, we need to check for any drivers that beat us and
2242*fd71220bSRobert Mustacchi 	 * register them.
2243*fd71220bSRobert Mustacchi 	 */
2244*fd71220bSRobert Mustacchi 	for (kgpio_t *k = list_head(&kgpio_g_gpios); k != NULL;
2245*fd71220bSRobert Mustacchi 	    k = list_next(&kgpio_g_gpios, k)) {
2246*fd71220bSRobert Mustacchi 		mutex_enter(&k->kgpio_mutex);
2247*fd71220bSRobert Mustacchi 		ASSERT0(k->kgpio_flags & KGPIO_F_MINOR_VALID);
2248*fd71220bSRobert Mustacchi 		kgpio_create_minor(k);
2249*fd71220bSRobert Mustacchi 		mutex_exit(&k->kgpio_mutex);
2250*fd71220bSRobert Mustacchi 	}
2251*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
2252*fd71220bSRobert Mustacchi 	return (DDI_SUCCESS);
2253*fd71220bSRobert Mustacchi }
2254*fd71220bSRobert Mustacchi 
2255*fd71220bSRobert Mustacchi static int
kgpio_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)2256*fd71220bSRobert Mustacchi kgpio_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
2257*fd71220bSRobert Mustacchi {
2258*fd71220bSRobert Mustacchi 	switch (cmd) {
2259*fd71220bSRobert Mustacchi 	case DDI_INFO_DEVT2DEVINFO:
2260*fd71220bSRobert Mustacchi 		*resultp = kgpio_g_dip;
2261*fd71220bSRobert Mustacchi 		break;
2262*fd71220bSRobert Mustacchi 	case DDI_INFO_DEVT2INSTANCE:
2263*fd71220bSRobert Mustacchi 		*resultp = (void *)(uintptr_t)ddi_get_instance(kgpio_g_dip);
2264*fd71220bSRobert Mustacchi 		break;
2265*fd71220bSRobert Mustacchi 	default:
2266*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2267*fd71220bSRobert Mustacchi 	}
2268*fd71220bSRobert Mustacchi 
2269*fd71220bSRobert Mustacchi 	return (DDI_SUCCESS);
2270*fd71220bSRobert Mustacchi }
2271*fd71220bSRobert Mustacchi 
2272*fd71220bSRobert Mustacchi static int
kgpio_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2273*fd71220bSRobert Mustacchi kgpio_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2274*fd71220bSRobert Mustacchi {
2275*fd71220bSRobert Mustacchi 	switch (cmd) {
2276*fd71220bSRobert Mustacchi 	case DDI_DETACH:
2277*fd71220bSRobert Mustacchi 		break;
2278*fd71220bSRobert Mustacchi 	case DDI_SUSPEND:
2279*fd71220bSRobert Mustacchi 		return (DDI_SUCCESS);
2280*fd71220bSRobert Mustacchi 	default:
2281*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2282*fd71220bSRobert Mustacchi 	}
2283*fd71220bSRobert Mustacchi 
2284*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
2285*fd71220bSRobert Mustacchi 	if (dip != kgpio_g_dip) {
2286*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2287*fd71220bSRobert Mustacchi 		dev_err(dip, CE_WARN, "asked to detach dip that is not the "
2288*fd71220bSRobert Mustacchi 		    "current kgpio dip");
2289*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2290*fd71220bSRobert Mustacchi 	}
2291*fd71220bSRobert Mustacchi 
2292*fd71220bSRobert Mustacchi 	if (list_is_empty(&kgpio_g_gpios) == 0) {
2293*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2294*fd71220bSRobert Mustacchi 		return (DDI_FAILURE);
2295*fd71220bSRobert Mustacchi 	}
2296*fd71220bSRobert Mustacchi 
2297*fd71220bSRobert Mustacchi 	avl_remove(&kgpio_g_minors, &kgpio_g_dpinfo);
2298*fd71220bSRobert Mustacchi 	ddi_remove_minor_node(dip, KGPIO_MINOR_NAME_DPINFO);
2299*fd71220bSRobert Mustacchi 	kgpio_g_dip = NULL;
2300*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
2301*fd71220bSRobert Mustacchi 	return (DDI_SUCCESS);
2302*fd71220bSRobert Mustacchi }
2303*fd71220bSRobert Mustacchi 
2304*fd71220bSRobert Mustacchi static struct cb_ops kgpio_cb_ops = {
2305*fd71220bSRobert Mustacchi 	.cb_open = kgpio_open,
2306*fd71220bSRobert Mustacchi 	.cb_close = kgpio_close,
2307*fd71220bSRobert Mustacchi 	.cb_strategy = nodev,
2308*fd71220bSRobert Mustacchi 	.cb_print = nodev,
2309*fd71220bSRobert Mustacchi 	.cb_dump = nodev,
2310*fd71220bSRobert Mustacchi 	.cb_read = kgpio_read,
2311*fd71220bSRobert Mustacchi 	.cb_write = kgpio_write,
2312*fd71220bSRobert Mustacchi 	.cb_ioctl = kgpio_ioctl,
2313*fd71220bSRobert Mustacchi 	.cb_devmap = nodev,
2314*fd71220bSRobert Mustacchi 	.cb_mmap = nodev,
2315*fd71220bSRobert Mustacchi 	.cb_segmap = nodev,
2316*fd71220bSRobert Mustacchi 	.cb_chpoll = nochpoll,
2317*fd71220bSRobert Mustacchi 	.cb_prop_op = ddi_prop_op,
2318*fd71220bSRobert Mustacchi 	.cb_flag = D_MP,
2319*fd71220bSRobert Mustacchi 	.cb_rev = CB_REV,
2320*fd71220bSRobert Mustacchi 	.cb_aread = nodev,
2321*fd71220bSRobert Mustacchi 	.cb_awrite = nodev
2322*fd71220bSRobert Mustacchi };
2323*fd71220bSRobert Mustacchi 
2324*fd71220bSRobert Mustacchi static struct dev_ops kgpio_dev_ops = {
2325*fd71220bSRobert Mustacchi 	.devo_rev = DEVO_REV,
2326*fd71220bSRobert Mustacchi 	.devo_refcnt = 0,
2327*fd71220bSRobert Mustacchi 	.devo_getinfo = kgpio_getinfo,
2328*fd71220bSRobert Mustacchi 	.devo_identify = nulldev,
2329*fd71220bSRobert Mustacchi 	.devo_probe = nulldev,
2330*fd71220bSRobert Mustacchi 	.devo_attach = kgpio_attach,
2331*fd71220bSRobert Mustacchi 	.devo_detach = kgpio_detach,
2332*fd71220bSRobert Mustacchi 	.devo_reset = nodev,
2333*fd71220bSRobert Mustacchi 	.devo_quiesce = ddi_quiesce_not_needed,
2334*fd71220bSRobert Mustacchi 	.devo_cb_ops = &kgpio_cb_ops
2335*fd71220bSRobert Mustacchi };
2336*fd71220bSRobert Mustacchi 
2337*fd71220bSRobert Mustacchi static struct modldrv kgpio_modldrv = {
2338*fd71220bSRobert Mustacchi 	.drv_modops = &mod_driverops,
2339*fd71220bSRobert Mustacchi 	.drv_linkinfo = "Kernel GPIO Framework",
2340*fd71220bSRobert Mustacchi 	.drv_dev_ops = &kgpio_dev_ops
2341*fd71220bSRobert Mustacchi };
2342*fd71220bSRobert Mustacchi 
2343*fd71220bSRobert Mustacchi static struct modlinkage kgpio_modlinkage = {
2344*fd71220bSRobert Mustacchi 	.ml_rev = MODREV_1,
2345*fd71220bSRobert Mustacchi 	.ml_linkage = { &kgpio_modldrv, NULL }
2346*fd71220bSRobert Mustacchi };
2347*fd71220bSRobert Mustacchi 
2348*fd71220bSRobert Mustacchi static void
kgpio_init(void)2349*fd71220bSRobert Mustacchi kgpio_init(void)
2350*fd71220bSRobert Mustacchi {
2351*fd71220bSRobert Mustacchi 	mutex_init(&kgpio_g_mutex, NULL, MUTEX_DRIVER, NULL);
2352*fd71220bSRobert Mustacchi 	list_create(&kgpio_g_gpios, sizeof (kgpio_t),
2353*fd71220bSRobert Mustacchi 	    offsetof(kgpio_t, kgpio_link));
2354*fd71220bSRobert Mustacchi 	list_create(&kgpio_g_dpios, sizeof (dpio_t),
2355*fd71220bSRobert Mustacchi 	    offsetof(dpio_t, dpio_link));
2356*fd71220bSRobert Mustacchi 	avl_create(&kgpio_g_minors, kgpio_minor_comparator,
2357*fd71220bSRobert Mustacchi 	    sizeof (kgpio_minor_t), offsetof(kgpio_minor_t, kminor_avl));
2358*fd71220bSRobert Mustacchi 	kgpio_g_ids = id_space_create("kgpios", KGPIO_MINOR_FIRST, L_MAXMIN32);
2359*fd71220bSRobert Mustacchi }
2360*fd71220bSRobert Mustacchi 
2361*fd71220bSRobert Mustacchi static void
kgpio_fini(void)2362*fd71220bSRobert Mustacchi kgpio_fini(void)
2363*fd71220bSRobert Mustacchi {
2364*fd71220bSRobert Mustacchi 	id_space_destroy(kgpio_g_ids);
2365*fd71220bSRobert Mustacchi 	avl_destroy(&kgpio_g_minors);
2366*fd71220bSRobert Mustacchi 	list_destroy(&kgpio_g_dpios);
2367*fd71220bSRobert Mustacchi 	list_destroy(&kgpio_g_gpios);
2368*fd71220bSRobert Mustacchi 	mutex_destroy(&kgpio_g_mutex);
2369*fd71220bSRobert Mustacchi }
2370*fd71220bSRobert Mustacchi 
2371*fd71220bSRobert Mustacchi int
_init(void)2372*fd71220bSRobert Mustacchi _init(void)
2373*fd71220bSRobert Mustacchi {
2374*fd71220bSRobert Mustacchi 	int err;
2375*fd71220bSRobert Mustacchi 
2376*fd71220bSRobert Mustacchi 	kgpio_init();
2377*fd71220bSRobert Mustacchi 	err = mod_install(&kgpio_modlinkage);
2378*fd71220bSRobert Mustacchi 	if (err != 0) {
2379*fd71220bSRobert Mustacchi 		kgpio_fini();
2380*fd71220bSRobert Mustacchi 		return (err);
2381*fd71220bSRobert Mustacchi 	}
2382*fd71220bSRobert Mustacchi 
2383*fd71220bSRobert Mustacchi 	return (0);
2384*fd71220bSRobert Mustacchi }
2385*fd71220bSRobert Mustacchi 
2386*fd71220bSRobert Mustacchi int
_info(struct modinfo * modinfop)2387*fd71220bSRobert Mustacchi _info(struct modinfo *modinfop)
2388*fd71220bSRobert Mustacchi {
2389*fd71220bSRobert Mustacchi 	return (mod_info(&kgpio_modlinkage, modinfop));
2390*fd71220bSRobert Mustacchi }
2391*fd71220bSRobert Mustacchi 
2392*fd71220bSRobert Mustacchi int
_fini(void)2393*fd71220bSRobert Mustacchi _fini(void)
2394*fd71220bSRobert Mustacchi {
2395*fd71220bSRobert Mustacchi 	int err;
2396*fd71220bSRobert Mustacchi 
2397*fd71220bSRobert Mustacchi 	mutex_enter(&kgpio_g_mutex);
2398*fd71220bSRobert Mustacchi 	if (list_is_empty(&kgpio_g_gpios) == 0) {
2399*fd71220bSRobert Mustacchi 		mutex_exit(&kgpio_g_mutex);
2400*fd71220bSRobert Mustacchi 		return (EBUSY);
2401*fd71220bSRobert Mustacchi 	}
2402*fd71220bSRobert Mustacchi 	mutex_exit(&kgpio_g_mutex);
2403*fd71220bSRobert Mustacchi 
2404*fd71220bSRobert Mustacchi 
2405*fd71220bSRobert Mustacchi 	err = mod_remove(&kgpio_modlinkage);
2406*fd71220bSRobert Mustacchi 	if (err != 0) {
2407*fd71220bSRobert Mustacchi 		return (err);
2408*fd71220bSRobert Mustacchi 	}
2409*fd71220bSRobert Mustacchi 
2410*fd71220bSRobert Mustacchi 	kgpio_fini();
2411*fd71220bSRobert Mustacchi 	return (0);
2412*fd71220bSRobert Mustacchi }
2413