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