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