chiark / gitweb /
switch tools and volume_id from LGPL to GPLv2
[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_utils.h"
21 #include "../../logging.h"
22
23 #define FIRMWARE_PATH                   "/lib/firmware"
24 #define PATH_SIZE                       256
25
26 #ifdef USE_LOG
27 void log_message(int priority, const char *format, ...)
28 {
29         va_list args;
30         static int udev_log = -1;
31
32         if (udev_log == -1) {
33                 const char *value;
34
35                 value = getenv("UDEV_LOG");
36                 if (value)
37                         udev_log = log_priority(value);
38                 else
39                         udev_log = LOG_ERR;
40         }
41
42         if (priority > udev_log)
43                 return;
44
45         va_start(args, format);
46         vsyslog(priority, format, args);
47         va_end(args);
48 }
49 #endif
50
51 /* Set the 'loading' attribute for a firmware device.
52  * 1 == currently loading
53  * 0 == done loading
54  * -1 == error
55  */
56 static int set_loading(const char *device, int value) {
57         char loading_path[PATH_SIZE];
58         int rc;
59         FILE *f;
60
61         snprintf(loading_path, sizeof(loading_path), "/sys/%s/loading", device);
62         loading_path[sizeof(loading_path)-1] = '\0';
63         f = fopen(loading_path, "w");
64         if (!f)
65                 return -1;
66         rc = fprintf(f, "%d", value);
67         fclose(f);
68         if (rc < 0)
69                 return rc;
70         return 0;
71 }
72
73 int main(int argc, char **argv) {
74         char *devpath, *firmware, *action, *driver;
75         char fw_path[PATH_SIZE];
76         char data_path[PATH_SIZE];
77         int fw_fd;
78         char *fw_buffer;
79         size_t fw_buffer_size;
80         size_t count;
81         int rc = 0;
82
83         logging_init("firmware_helper");
84
85         driver = getenv("PHYSDEVDRIVER");
86         if (!driver)
87                 driver = "(unknown)";
88         devpath = getenv("DEVPATH");
89         firmware = getenv("FIRMWARE");
90         action = getenv("ACTION");
91         if (!devpath || !firmware || !action || strcmp(action,"add") != 0) {
92                 err("missing devpath, action or firmware");
93                 exit(1);
94         }
95
96         dbg("try to load firmware '%s' for '%s'", firmware, devpath);
97         set_loading(devpath, 1);
98
99         snprintf(fw_path, sizeof(fw_path), "%s/%s", FIRMWARE_PATH, firmware);
100         fw_path[sizeof(fw_path)-1] = '\0';
101         if (file_map(fw_path, &fw_buffer, &fw_buffer_size) != 0 || fw_buffer_size == 0) {
102                 err("could not load firmware '%s' for '%s'", fw_path, devpath);
103                 fw_buffer = NULL;
104                 goto out_err;
105         }
106
107         snprintf(data_path, sizeof(data_path), "/sys/%s/data", devpath);
108         data_path[sizeof(data_path)-1] = '\0';
109         fw_fd = open(data_path, O_RDWR);
110         if (fw_fd < 0) {
111                 rc = errno;
112                 goto out_err;
113         }
114
115         count = 0;
116         while (count < fw_buffer_size) {
117                 ssize_t c;
118
119                 c = write(fw_fd, fw_buffer+count, fw_buffer_size-count);
120                 if (c <= 0) {
121                         rc = errno;
122                         close(fw_fd);
123                         goto out_err;
124                 }
125                 count += c;
126         }
127
128         close(fw_fd);
129         file_unmap(fw_buffer, fw_buffer_size);
130         set_loading(devpath, 0);
131         info("loaded '%s' for device '%s'", fw_path, devpath);
132         logging_close();
133         return 0;
134
135 out_err:
136         if (fw_buffer)
137                 file_unmap(fw_buffer, fw_buffer_size);
138         set_loading(devpath, -1);
139
140         err("error loading '%s' for device '%s' with driver '%s'", fw_path, devpath, driver);
141         logging_close();
142         return rc;
143 }