xref: /openbmc/skeleton/libopenbmc_intf/gpio.c (revision abe0f68b)
1 #define _GNU_SOURCE
2 
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <argp.h>
10 #include <sys/stat.h>
11 #include <sys/mman.h>
12 #include "openbmc_intf.h"
13 #include "gpio.h"
14 
15 
16 int gpio_writec(GPIO* gpio, char value)
17 {
18 	g_assert (gpio != NULL);
19 	int rc = GPIO_OK;
20 	char buf[1];
21 	buf[0] = value;
22 	if (write(gpio->fd, buf, 1) != 1)
23 	{
24 		rc = GPIO_WRITE_ERROR;
25 	}
26 	return rc;
27 }
28 
29 int gpio_write(GPIO* gpio, uint8_t value)
30 {
31 	g_assert (gpio != NULL);
32 	int rc = GPIO_OK;
33 	char buf[1];
34 	buf[0] = '0';
35 	if (value==1)
36 	{
37 		buf[0]='1';
38 	}
39 	if (write(gpio->fd, buf, 1) != 1)
40 	{
41 		rc = GPIO_WRITE_ERROR;
42 	}
43 	return rc;
44 }
45 
46 int gpio_read(GPIO* gpio, uint8_t *value)
47 {
48 	g_assert (gpio != NULL);
49 	char buf[1];
50 	int r = GPIO_OK;
51 	if (gpio->fd <= 0)
52 	{
53 		r = GPIO_ERROR;
54 	}
55 	else
56 	{
57 		if (read(gpio->fd,&buf,1) != 1)
58 		{
59 			r = GPIO_READ_ERROR;
60 		} else {
61 			if (buf[0]=='1') {
62 				*value = 1;
63 			} else {
64 				*value = 0;
65 			}
66 		}
67 	}
68 	return r;
69 }
70 int gpio_clock_cycle(GPIO* gpio, int num_clks) {
71 	g_assert (gpio != NULL);
72         int i=0;
73 	int r=GPIO_OK;
74         for (i=0;i<num_clks;i++) {
75                 if (gpio_writec(gpio,'0') == -1) {
76 			r = GPIO_WRITE_ERROR;
77 			break;
78 		}
79 		if (gpio_writec(gpio,'1') == -1) {
80 			r = GPIO_WRITE_ERROR;
81 			break;
82 		}
83         }
84 	return r;
85 }
86 
87 // Gets the gpio device path from gpio manager object
88 int gpio_init(GDBusConnection *connection, GPIO* gpio)
89 {
90 	int rc = GPIO_OK;
91 	GDBusProxy *proxy;
92 	GError *error;
93 	GVariant *result;
94 
95 	error = NULL;
96 	g_assert_no_error (error);
97 	error = NULL;
98 	proxy = g_dbus_proxy_new_sync (connection,
99                                  G_DBUS_PROXY_FLAGS_NONE,
100                                  NULL,                      /* GDBusInterfaceInfo */
101                                  "org.openbmc.managers.System", /* name */
102                                  "/org/openbmc/managers/System", /* object path */
103                                  "org.openbmc.managers.System",        /* interface */
104                                  NULL, /* GCancellable */
105                                  &error);
106 	if (error != NULL) {
107 		return GPIO_LOOKUP_ERROR;
108 	}
109 
110 	result = g_dbus_proxy_call_sync (proxy,
111                                    "gpioInit",
112                                    g_variant_new ("(s)", gpio->name),
113                                    G_DBUS_CALL_FLAGS_NONE,
114                                    -1,
115                                    NULL,
116                                    &error);
117 
118 	if (error != NULL) {
119 		return GPIO_LOOKUP_ERROR;
120 	}
121 	g_assert (result != NULL);
122 	g_variant_get (result, "(&si&s)", &gpio->dev,&gpio->num,&gpio->direction);
123 	g_print("GPIO Lookup:  %s = %d,%s\n",gpio->name,gpio->num,gpio->direction);
124 
125 	//export and set direction
126 	char dev[254];
127 	char data[4];
128 	int fd;
129 	do {
130 		struct stat st;
131 
132 		sprintf(dev,"%s/gpio%d/value",gpio->dev,gpio->num);
133 		//check if gpio is exported, if not export
134     		int result = stat(dev, &st);
135     		if (result)
136 		{
137 			sprintf(dev,"%s/export",gpio->dev);
138 			fd = open(dev, O_WRONLY);
139 			if (fd == GPIO_ERROR) {
140 				rc = GPIO_OPEN_ERROR;
141 				break;
142 			}
143 			sprintf(data,"%d",gpio->num);
144 			rc = write(fd,data,strlen(data));
145 			close(fd);
146 			if (rc != strlen(data)) {
147 				rc = GPIO_WRITE_ERROR;
148 				break;
149 			}
150 		}
151 		const char* file = "edge";
152 		const char* direction = gpio->direction;
153 		if (strcmp(direction, "in") == 0)
154 		{
155 			file = "direction";
156 		}
157 		else if (strcmp(direction, "out") == 0)
158 		{
159 			file = "direction";
160 
161 			// Read current value, so we can set 'high' or 'low'.
162 			// Setting direction directly to 'out' is the same as
163 			// setting to 'low' which can change the value in the
164 			// GPIO.
165 			uint8_t value = 0;
166 			rc = gpio_open(gpio);
167 			if (rc) break;
168 			rc = gpio_read(gpio, &value);
169 			if (rc) break;
170 			gpio_close(gpio);
171 
172 			direction = (value ? "high" : "low");
173 		}
174 		sprintf(dev,"%s/gpio%d/%s",gpio->dev,gpio->num,file);
175 		fd = open(dev,O_WRONLY);
176 		if (fd == GPIO_ERROR) {
177 			rc = GPIO_WRITE_ERROR;
178 			break;
179 		}
180 		rc = write(fd,direction,strlen(direction));
181 		if (rc != strlen(direction)) {
182 			rc = GPIO_WRITE_ERROR;
183 			break;
184 		}
185 
186 		close(fd);
187 		rc = GPIO_OK;
188 	} while(0);
189 
190 	return rc;
191 }
192 
193 
194 
195 
196 char* get_gpio_dev(GPIO* gpio)
197 {
198 	char* buf;
199 	asprintf(&buf, "%s/gpio%d/value", gpio->dev, gpio->num);
200 	return buf;
201 }
202 
203 int gpio_open_interrupt(GPIO* gpio, GIOFunc func, gpointer user_data)
204 {
205 	int rc = GPIO_OK;
206 	char buf[255];
207 	sprintf(buf, "%s/gpio%d/value", gpio->dev, gpio->num);
208 	gpio->fd = open(buf, O_RDONLY | O_NONBLOCK );
209 	gpio->irq_inited = false;
210 	if (gpio->fd == -1)
211 	{
212 		rc = GPIO_OPEN_ERROR;
213 	}
214 	else
215 	{
216 		GIOChannel* channel = g_io_channel_unix_new( gpio->fd);
217 		guint id = g_io_add_watch( channel, G_IO_PRI, func, user_data );
218 	}
219 	return rc;
220 }
221 
222 int gpio_open(GPIO* gpio)
223 {
224 	g_assert (gpio != NULL);
225 	// open gpio for writing or reading
226 	char buf[254];
227 	int rc = 0;
228 	gpio->fd = -1;
229 	if (gpio->direction == NULL) {
230 		return GPIO_OPEN_ERROR;
231 	}
232 	if (strcmp(gpio->direction,"in")==0)
233 	{
234 		sprintf(buf, "%s/gpio%d/value", gpio->dev, gpio->num);
235 		gpio->fd = open(buf, O_RDONLY);
236 	}
237 	else
238 	{
239 		sprintf(buf, "%s/gpio%d/value", gpio->dev, gpio->num);
240 		gpio->fd = open(buf, O_RDWR);
241 
242 	}
243 	if (gpio->fd == -1) {
244 		return GPIO_OPEN_ERROR;
245 	}
246 	return GPIO_OK;
247 }
248 
249 void gpio_close(GPIO* gpio)
250 {
251 	close(gpio->fd);
252 }
253