- added xpram symlink to slram device nodes (bug #135733) - removed infiniband rules (bug #206224) - use newest path_id script (bug #207139)
142 lines
2.6 KiB
C
142 lines
2.6 KiB
C
/*
|
|
* A simple firmware helper program.
|
|
*
|
|
* Copyright 2005 Red Hat, Inc.
|
|
*
|
|
* This software may be freely redistributed under the terms of the GNU
|
|
* public license.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#define FIRMWARE_PATH "/lib/firmware"
|
|
|
|
|
|
void log_err(char *firmware, int err) {
|
|
char *driver;
|
|
|
|
driver = getenv("PHYSDEVDRIVER");
|
|
if (!driver)
|
|
driver = "(unknown)";
|
|
openlog("firmware_helper",LOG_PID,LOG_USER);
|
|
syslog(LOG_ERR,"Loading of %s for %s driver failed: %s",firmware, driver, strerror(err));
|
|
closelog();
|
|
}
|
|
|
|
/* Set the 'loading' attribute for a firmware device.
|
|
* 1 == currently loading
|
|
* 0 == done loading
|
|
* -1 == error
|
|
*/
|
|
int set_loading(char *device, int value) {
|
|
char *path;
|
|
int rc;
|
|
FILE *f;
|
|
|
|
path = alloca(strlen(device)+15);
|
|
sprintf(path,"/sys/%s/loading", device);
|
|
f = fopen(path, "w");
|
|
if (!f)
|
|
return 1;
|
|
rc = fprintf(f, "%d", value);
|
|
fclose(f);
|
|
if (rc < 0)
|
|
return rc;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
char *devpath, *firmware, *action;
|
|
struct stat sbuf;
|
|
int fw_fd, count;
|
|
int rc;
|
|
char *fw_path, *data_path;
|
|
char *fw_buffer;
|
|
|
|
devpath = getenv("DEVPATH");
|
|
if (!devpath) return 0;
|
|
|
|
firmware = getenv("FIRMWARE");
|
|
if (!firmware) return 0;
|
|
|
|
action = getenv("ACTION");
|
|
if (strcmp(action,"add"))
|
|
return 0;
|
|
|
|
set_loading(devpath, 1);
|
|
|
|
fw_path = malloc(strlen(FIRMWARE_PATH) + strlen(firmware) + 2);
|
|
if (!fw_path) {
|
|
rc = errno;
|
|
goto out_err;
|
|
}
|
|
|
|
sprintf(fw_path,"%s/%s", FIRMWARE_PATH, firmware);
|
|
fw_fd = open(fw_path, O_RDONLY);
|
|
if (fw_fd == -1) {
|
|
rc = errno;
|
|
goto out_err;
|
|
}
|
|
|
|
fstat(fw_fd, &sbuf);
|
|
fw_buffer = malloc(sbuf.st_size);
|
|
if (!fw_buffer) {
|
|
rc = errno;
|
|
goto out_err;
|
|
}
|
|
if (read(fw_fd, fw_buffer, sbuf.st_size) != sbuf.st_size) {
|
|
rc = errno;
|
|
goto out_err;
|
|
}
|
|
close(fw_fd);
|
|
|
|
data_path = malloc(strlen(devpath) + 12);
|
|
if (!data_path) {
|
|
rc = errno;
|
|
goto out_err;
|
|
}
|
|
|
|
sprintf(data_path,"/sys/%s/data", devpath);
|
|
|
|
fw_fd = open(data_path, O_RDWR);
|
|
if (fw_fd == -1) {
|
|
rc = errno;
|
|
fw_path = data_path;
|
|
goto out_err;
|
|
}
|
|
|
|
count = 0;
|
|
while (count < sbuf.st_size) {
|
|
int c;
|
|
|
|
c = write(fw_fd,fw_buffer+count,sbuf.st_size-count);
|
|
if (c <= 0) {
|
|
rc = errno;
|
|
goto out_err;
|
|
}
|
|
count += c;
|
|
}
|
|
close(fw_fd);
|
|
set_loading(devpath, 0);
|
|
return 0;
|
|
out_err:
|
|
if (fw_fd >= 0)
|
|
close(fw_fd);
|
|
set_loading(devpath, -1);
|
|
log_err(fw_path, rc);
|
|
return rc;
|
|
}
|