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