chiark / gitweb /
ca1c43814f754a21709a93f6cedbd6eef264c491
[elogind.git] / extras / firmware / firmware_helper.c
1 /*
2  * A simple firmware helper program.
3  * 
4  * Copyright 2005 Red Hat, Inc.
5  *
6  *      This program is free software; you can redistribute it and/or modify it
7  *      under the terms of the GNU General Public License as published by the
8  *      Free Software Foundation version 2 of the License.
9  */
10
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <syslog.h>
17 #include <unistd.h>
18 #include <sys/stat.h>
19
20 #include "../../udev.h"
21
22 #define FIRMWARE_PATH                   "/lib/firmware"
23 #define PATH_SIZE                       256
24
25 #ifdef USE_LOG
26 void log_message(int priority, const char *format, ...)
27 {
28         va_list args;
29         static int udev_log = -1;
30
31         if (udev_log == -1) {
32                 const char *value;
33
34                 value = getenv("UDEV_LOG");
35                 if (value)
36                         udev_log = log_priority(value);
37                 else
38                         udev_log = LOG_ERR;
39         }
40
41         if (priority > udev_log)
42                 return;
43
44         va_start(args, format);
45         vsyslog(priority, format, args);
46         va_end(args);
47 }
48 #endif
49
50 /* Set the 'loading' attribute for a firmware device.
51  * 1 == currently loading
52  * 0 == done loading
53  * -1 == error
54  */
55 static int set_loading(const char *device, int value) {
56         char loading_path[PATH_SIZE];
57         int rc;
58         FILE *f;
59
60         snprintf(loading_path, sizeof(loading_path), "/sys/%s/loading", device);
61         loading_path[sizeof(loading_path)-1] = '\0';
62         f = fopen(loading_path, "w");
63         if (!f)
64                 return -1;
65         rc = fprintf(f, "%d", value);
66         fclose(f);
67         if (rc < 0)
68                 return rc;
69         return 0;
70 }
71
72 int main(int argc, char **argv) {
73         char *devpath, *firmware, *action, *driver;
74         char fw_path[PATH_SIZE];
75         char data_path[PATH_SIZE];
76         int fw_fd;
77         char *fw_buffer;
78         size_t fw_buffer_size;
79         size_t count;
80         int rc = 0;
81
82         logging_init("firmware_helper");
83
84         driver = getenv("PHYSDEVDRIVER");
85         if (!driver)
86                 driver = "(unknown)";
87         devpath = getenv("DEVPATH");
88         firmware = getenv("FIRMWARE");
89         action = getenv("ACTION");
90         if (!devpath || !firmware || !action || strcmp(action,"add") != 0) {
91                 err("missing devpath, action or firmware");
92                 exit(1);
93         }
94
95         dbg("try to load firmware '%s' for '%s'", firmware, devpath);
96         set_loading(devpath, 1);
97
98         snprintf(fw_path, sizeof(fw_path), "%s/%s", FIRMWARE_PATH, firmware);
99         fw_path[sizeof(fw_path)-1] = '\0';
100         if (file_map(fw_path, &fw_buffer, &fw_buffer_size) != 0 || fw_buffer_size == 0) {
101                 err("could not load firmware '%s' for '%s'", fw_path, devpath);
102                 fw_buffer = NULL;
103                 goto out_err;
104         }
105
106         snprintf(data_path, sizeof(data_path), "/sys/%s/data", devpath);
107         data_path[sizeof(data_path)-1] = '\0';
108         fw_fd = open(data_path, O_RDWR);
109         if (fw_fd < 0) {
110                 rc = errno;
111                 goto out_err;
112         }
113
114         count = 0;
115         while (count < fw_buffer_size) {
116                 ssize_t c;
117
118                 c = write(fw_fd, fw_buffer+count, fw_buffer_size-count);
119                 if (c <= 0) {
120                         rc = errno;
121                         close(fw_fd);
122                         goto out_err;
123                 }
124                 count += c;
125         }
126
127         close(fw_fd);
128         file_unmap(fw_buffer, fw_buffer_size);
129         set_loading(devpath, 0);
130         info("loaded '%s' for device '%s'", fw_path, devpath);
131         logging_close();
132         return 0;
133
134 out_err:
135         if (fw_buffer)
136                 file_unmap(fw_buffer, fw_buffer_size);
137         set_loading(devpath, -1);
138
139         err("error loading '%s' for device '%s' with driver '%s'", fw_path, devpath, driver);
140         logging_close();
141         return rc;
142 }