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