14a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin/*
24a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  ion.c
34a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *
44a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin * Memory Allocator functions for ion
54a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *
64a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *   Copyright 2011 Google, Inc
74a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *
84a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  Licensed under the Apache License, Version 2.0 (the "License");
94a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  you may not use this file except in compliance with the License.
104a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  You may obtain a copy of the License at
114a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *
124a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *      http://www.apache.org/licenses/LICENSE-2.0
134a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *
144a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  Unless required by applicable law or agreed to in writing, software
154a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  distributed under the License is distributed on an "AS IS" BASIS,
164a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
174a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  See the License for the specific language governing permissions and
184a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin *  limitations under the License.
194a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin */
201dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen#define LOG_TAG "ion"
211dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen
221dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen#include <cutils/log.h>
234a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin#include <errno.h>
244a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin#include <fcntl.h>
254a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin#include <stdio.h>
264a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin#include <sys/ioctl.h>
274a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin#include <sys/mman.h>
284a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin#include <sys/types.h>
294a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
301dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen#include <linux/ion.h>
311dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen#include <ion/ion.h>
324a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
334a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinint ion_open()
344a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
354a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int fd = open("/dev/ion", O_RDWR);
364a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (fd < 0)
374a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                ALOGE("open /dev/ion failed!\n");
384a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return fd;
394a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
404a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
414a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinint ion_close(int fd)
424a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
434a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return close(fd);
444a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
454a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
464a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinstatic int ion_ioctl(int fd, int req, void *arg)
474a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
484a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int ret = ioctl(fd, req, arg);
494a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (ret < 0) {
504a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                ALOGE("ioctl %d failed with code %d: %s\n", req,
514a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                       ret, strerror(errno));
524a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return -errno;
534a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        }
544a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return ret;
554a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
564a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
571dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chenint ion_alloc(int fd, size_t len, size_t align,
581dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen	      unsigned int flags, struct ion_handle **handle)
594a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
604a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int ret;
614a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        struct ion_allocation_data data = {
624a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .len = len,
634a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .align = align,
644a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .flags = flags,
654a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        };
664a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
674a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        ret = ion_ioctl(fd, ION_IOC_ALLOC, &data);
684a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (ret < 0)
694a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return ret;
704a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        *handle = data.handle;
714a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return ret;
724a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
734a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
744a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinint ion_alloc_tiler(int fd, size_t w, size_t h, int fmt, unsigned int flags,
754a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin            struct ion_handle **handle, size_t *stride)
764a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
774a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int ret;
784a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        struct omap_ion_tiler_alloc_data alloc_data = {
794a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .w = w,
804a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .h = h,
814a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .fmt = fmt,
824a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .flags = flags,
831dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .out_align = PAGE_SIZE,
841dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .token = 0,
854a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        };
864a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
874a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        struct ion_custom_data custom_data = {
884a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .cmd = OMAP_ION_TILER_ALLOC,
894a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .arg = (unsigned long)(&alloc_data),
904a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        };
914a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
924a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        ret = ion_ioctl(fd, ION_IOC_CUSTOM, &custom_data);
934a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (ret < 0)
944a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return ret;
954a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        *stride = alloc_data.stride;
964a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        *handle = alloc_data.handle;
974a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return ret;
984a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
994a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
1004a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinint ion_free(int fd, struct ion_handle *handle)
1014a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
1024a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        struct ion_handle_data data = {
1034a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .handle = handle,
1044a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        };
1054a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return ion_ioctl(fd, ION_IOC_FREE, &data);
1064a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
1074a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
1084a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinint ion_map(int fd, struct ion_handle *handle, size_t length, int prot,
1094a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin            int flags, off_t offset, unsigned char **ptr, int *map_fd)
1104a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
1114a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        struct ion_fd_data data = {
1124a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .handle = handle,
1134a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        };
1144a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int ret = ion_ioctl(fd, ION_IOC_MAP, &data);
1154a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (ret < 0)
1164a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return ret;
1174a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        *map_fd = data.fd;
1184a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (*map_fd < 0) {
1194a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                ALOGE("map ioctl returned negative fd\n");
1204a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return -EINVAL;
1214a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        }
1224a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
1234a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (*ptr == MAP_FAILED) {
1244a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                ALOGE("mmap failed: %s\n", strerror(errno));
1254a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return -errno;
1264a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        }
1274a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return ret;
1284a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
1294a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
1304a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinint ion_share(int fd, struct ion_handle *handle, int *share_fd)
1314a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
1324a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int map_fd;
1334a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        struct ion_fd_data data = {
1344a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .handle = handle,
1354a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        };
1364a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
1374a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (ret < 0)
1384a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return ret;
1394a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        *share_fd = data.fd;
1404a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (*share_fd < 0) {
1414a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                ALOGE("map ioctl returned negative fd\n");
1424a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return -EINVAL;
1434a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        }
1444a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return ret;
1454a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
1464a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin
1474a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavinint ion_import(int fd, int share_fd, struct ion_handle **handle)
1484a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin{
1494a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        struct ion_fd_data data = {
1504a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                .fd = share_fd,
1514a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        };
1524a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        int ret = ion_ioctl(fd, ION_IOC_IMPORT, &data);
1534a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        if (ret < 0)
1544a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin                return ret;
1554a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        *handle = data.handle;
1564a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin        return ret;
1574a35937fcb950ccd05af56c49214b88e393233e3Rebecca Schultz Zavin}
1581dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen
1591dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen#if 0
1601dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chenint ion_sync_fd(int fd, int handle_fd)
1611dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen{
1621dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen	struct ion_fd_data data = {
1631dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen		.fd = handle_fd,
1641dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen	};
1651dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen	return ion_ioctl(fd, ION_IOC_SYNC, &data);
1661dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen}
1671dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen#endif
1681dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen
1691dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chenint ion_map_cacheable(int fd, struct ion_handle *handle, size_t length, int prot,
1701dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen            int flags, off_t offset, unsigned char **ptr, int *map_fd)
1711dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen{
1721dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        struct ion_fd_data data = {
1731dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .handle = handle,
1741dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .cacheable = 1,
1751dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        };
1761dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        int ret = ion_ioctl(fd, ION_IOC_MAP, &data);
1771dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        if (ret < 0)
1781dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                return ret;
1791dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        *map_fd = data.fd;
1801dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        if (*map_fd < 0) {
1811dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                ALOGE("map ioctl returned negative fd\n");
1821dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                return -EINVAL;
1831dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        }
1841dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
1851dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        if (*ptr == MAP_FAILED) {
1861dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                ALOGE("mmap failed: %s\n", strerror(errno));
1871dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                return -errno;
1881dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        }
1891dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        return ret;
1901dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen}
1911dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen
1921dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chenint ion_flush_cached(int fd, struct ion_handle *handle, size_t length,
1931dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen            unsigned char *ptr)
1941dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen{
1951dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        struct ion_cached_user_buf_data data = {
1961dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .handle = handle,
1971dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .vaddr = (unsigned long)ptr,
1981dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .size = length,
1991dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        };
2001dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        return ion_ioctl(fd, ION_IOC_FLUSH_CACHED, &data);
2011dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen}
2021dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen
2031dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chenint ion_inval_cached(int fd, struct ion_handle *handle, size_t length,
2041dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen            unsigned char *ptr)
2051dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen{
2061dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        struct ion_cached_user_buf_data data = {
2071dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .handle = handle,
2081dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .vaddr = (unsigned long)ptr,
2091dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen                .size = length,
2101dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        };
2111dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen        return ion_ioctl(fd, ION_IOC_INVAL_CACHED, &data);
2121dac52160a4c982fbe3e08b633f5e24171bee2d8Mike J. Chen}
213