summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--init/Android.mk1
-rw-r--r--init/devices.cpp52
2 files changed, 38 insertions, 15 deletions
diff --git a/init/Android.mk b/init/Android.mk
index 71faede..99d12c2 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -66,6 +66,7 @@ endif
LOCAL_MODULE:= init
LOCAL_C_INCLUDES += \
+ external/zlib \
system/extras/ext4_utils \
system/core/mkbootimg
diff --git a/init/devices.cpp b/init/devices.cpp
index 0bc0df7..d8de450 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -48,6 +48,7 @@
#include "util.h"
#include "log.h"
#include "property_service.h"
+#include <zlib.h>
#define SYSFS_PREFIX "/sys"
static const char *firmware_dirs[] = { "/etc/firmware",
@@ -825,23 +826,20 @@ static void handle_device_event(struct uevent *uevent)
}
}
-static int load_firmware(int fw_fd, int loading_fd, int data_fd)
+static int load_firmware(int fw_fd, gzFile gz_fd, int loading_fd, int data_fd)
{
- struct stat st;
- long len_to_copy;
int ret = 0;
- if(fstat(fw_fd, &st) < 0)
- return -1;
- len_to_copy = st.st_size;
-
write(loading_fd, "1", 1); /* start transfer */
- while (len_to_copy > 0) {
+ while (1) {
char buf[PAGE_SIZE];
ssize_t nr;
- nr = read(fw_fd, buf, sizeof(buf));
+ if (gz_fd)
+ nr = gzread(gz_fd, buf, sizeof(buf));
+ else
+ nr = read(fw_fd, buf, sizeof(buf));
if(!nr)
break;
if(nr < 0) {
@@ -849,7 +847,6 @@ static int load_firmware(int fw_fd, int loading_fd, int data_fd)
break;
}
- len_to_copy -= nr;
while (nr > 0) {
ssize_t nw = 0;
@@ -865,8 +862,10 @@ static int load_firmware(int fw_fd, int loading_fd, int data_fd)
out:
if(!ret)
write(loading_fd, "0", 1); /* successful end of transfer */
- else
+ else {
+ ERROR("%s: aborted transfer\n", __func__);
write(loading_fd, "-1", 2); /* abort transfer */
+ }
return ret;
}
@@ -876,12 +875,29 @@ static int is_booting(void)
return access("/dev/.booting", F_OK) == 0;
}
+gzFile fw_gzopen(const char *fname, const char *mode)
+{
+ char *file1 = NULL;
+ int l;
+ gzFile gz_fd = NULL;
+
+ l = asprintf(&file1, "%s.gz", fname);
+ if (l == -1)
+ goto out;
+
+ gz_fd = gzopen(file1, mode);
+ free(file1);
+out:
+ return gz_fd;
+}
+
static void process_firmware_event(struct uevent *uevent)
{
char *root, *loading, *data;
int l, loading_fd, data_fd, fw_fd;
size_t i;
int booting = is_booting();
+ gzFile gz_fd = NULL;
INFO("firmware: loading '%s' for '%s'\n",
uevent->firmware, uevent->path);
@@ -914,15 +930,18 @@ try_loading_again:
goto data_free_out;
fw_fd = open(file, O_RDONLY|O_CLOEXEC);
free(file);
- if (fw_fd >= 0) {
- if(!load_firmware(fw_fd, loading_fd, data_fd))
+ if (fw_fd < 0){
+ gz_fd = fw_gzopen(file, "rb");
+ }
+ if (fw_fd >= 0 || gz_fd) {
+ if(!load_firmware(fw_fd, gz_fd, loading_fd, data_fd))
INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
else
INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
break;
}
}
- if (fw_fd < 0) {
+ if ((fw_fd < 0) && !gz_fd) {
if (booting) {
/* If we're not fully booted, we may be missing
* filesystems needed for firmware, wait and retry.
@@ -936,7 +955,10 @@ try_loading_again:
goto data_close_out;
}
- close(fw_fd);
+ if (gz_fd)
+ gzclose(gz_fd);
+ else
+ close(fw_fd);
data_close_out:
close(data_fd);
loading_close_out: