1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <stdbool.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include <sys/cdefs.h> 26 #include <sys/mman.h> 27 28 #include <adf/adf.h> 29 30 #include "graphics.h" 31 32 struct adf_surface_pdata { 33 GRSurface base; 34 int fd; 35 __u32 offset; 36 __u32 pitch; 37 }; 38 39 struct adf_pdata { 40 minui_backend base; 41 int intf_fd; 42 adf_id_t eng_id; 43 __u32 format; 44 45 unsigned int current_surface; 46 unsigned int n_surfaces; 47 adf_surface_pdata surfaces[2]; 48 }; 49 50 static GRSurface* adf_flip(minui_backend *backend); 51 static void adf_blank(minui_backend *backend, bool blank); 52 53 static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surface_pdata *surf) { 54 memset(surf, 0, sizeof(*surf)); 55 56 surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay, 57 mode->vdisplay, pdata->format, &surf->offset, &surf->pitch); 58 if (surf->fd < 0) 59 return surf->fd; 60 61 surf->base.width = mode->hdisplay; 62 surf->base.height = mode->vdisplay; 63 surf->base.row_bytes = surf->pitch; 64 surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4; 65 66 surf->base.data = reinterpret_cast<uint8_t*>(mmap(NULL, 67 surf->pitch * surf->base.height, PROT_WRITE, 68 MAP_SHARED, surf->fd, surf->offset)); 69 if (surf->base.data == MAP_FAILED) { 70 close(surf->fd); 71 return -errno; 72 } 73 74 return 0; 75 } 76 77 static int adf_interface_init(adf_pdata *pdata) 78 { 79 adf_interface_data intf_data; 80 int ret = 0; 81 int err; 82 83 err = adf_get_interface_data(pdata->intf_fd, &intf_data); 84 if (err < 0) 85 return err; 86 87 err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]); 88 if (err < 0) { 89 fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err)); 90 ret = err; 91 goto done; 92 } 93 94 err = adf_surface_init(pdata, &intf_data.current_mode, 95 &pdata->surfaces[1]); 96 if (err < 0) { 97 fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err)); 98 memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1])); 99 pdata->n_surfaces = 1; 100 } else { 101 pdata->n_surfaces = 2; 102 } 103 104 done: 105 adf_free_interface_data(&intf_data); 106 return ret; 107 } 108 109 static int adf_device_init(adf_pdata *pdata, adf_device *dev) 110 { 111 adf_id_t intf_id; 112 int intf_fd; 113 int err; 114 115 err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id, 116 &pdata->eng_id); 117 if (err < 0) 118 return err; 119 120 err = adf_device_attach(dev, pdata->eng_id, intf_id); 121 if (err < 0 && err != -EALREADY) 122 return err; 123 124 pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR); 125 if (pdata->intf_fd < 0) 126 return pdata->intf_fd; 127 128 err = adf_interface_init(pdata); 129 if (err < 0) { 130 close(pdata->intf_fd); 131 pdata->intf_fd = -1; 132 } 133 134 return err; 135 } 136 137 static GRSurface* adf_init(minui_backend *backend) 138 { 139 adf_pdata *pdata = (adf_pdata *)backend; 140 adf_id_t *dev_ids = NULL; 141 ssize_t n_dev_ids, i; 142 GRSurface* ret; 143 144 #if defined(RECOVERY_ABGR) 145 pdata->format = DRM_FORMAT_ABGR8888; 146 #elif defined(RECOVERY_BGRA) 147 pdata->format = DRM_FORMAT_BGRA8888; 148 #elif defined(RECOVERY_RGBX) 149 pdata->format = DRM_FORMAT_RGBX8888; 150 #else 151 pdata->format = DRM_FORMAT_RGB565; 152 #endif 153 154 n_dev_ids = adf_devices(&dev_ids); 155 if (n_dev_ids == 0) { 156 return NULL; 157 } else if (n_dev_ids < 0) { 158 fprintf(stderr, "enumerating adf devices failed: %s\n", 159 strerror(-n_dev_ids)); 160 return NULL; 161 } 162 163 pdata->intf_fd = -1; 164 165 for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { 166 adf_device dev; 167 168 int err = adf_device_open(dev_ids[i], O_RDWR, &dev); 169 if (err < 0) { 170 fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i], 171 strerror(-err)); 172 continue; 173 } 174 175 err = adf_device_init(pdata, &dev); 176 if (err < 0) 177 fprintf(stderr, "initializing adf device %u failed: %s\n", 178 dev_ids[i], strerror(-err)); 179 180 adf_device_close(&dev); 181 } 182 183 free(dev_ids); 184 185 if (pdata->intf_fd < 0) 186 return NULL; 187 188 ret = adf_flip(backend); 189 190 adf_blank(backend, true); 191 adf_blank(backend, false); 192 193 return ret; 194 } 195 196 static GRSurface* adf_flip(minui_backend *backend) 197 { 198 adf_pdata *pdata = (adf_pdata *)backend; 199 adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface]; 200 201 int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id, 202 surf->base.width, surf->base.height, pdata->format, surf->fd, 203 surf->offset, surf->pitch, -1); 204 if (fence_fd >= 0) 205 close(fence_fd); 206 207 pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces; 208 return &pdata->surfaces[pdata->current_surface].base; 209 } 210 211 static void adf_blank(minui_backend *backend, bool blank) 212 { 213 adf_pdata *pdata = (adf_pdata *)backend; 214 adf_interface_blank(pdata->intf_fd, 215 blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); 216 } 217 218 static void adf_surface_destroy(adf_surface_pdata *surf) 219 { 220 munmap(surf->base.data, surf->pitch * surf->base.height); 221 close(surf->fd); 222 } 223 224 static void adf_exit(minui_backend *backend) 225 { 226 adf_pdata *pdata = (adf_pdata *)backend; 227 unsigned int i; 228 229 for (i = 0; i < pdata->n_surfaces; i++) 230 adf_surface_destroy(&pdata->surfaces[i]); 231 if (pdata->intf_fd >= 0) 232 close(pdata->intf_fd); 233 free(pdata); 234 } 235 236 minui_backend *open_adf() 237 { 238 adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata))); 239 if (!pdata) { 240 perror("allocating adf backend failed"); 241 return NULL; 242 } 243 244 pdata->base.init = adf_init; 245 pdata->base.flip = adf_flip; 246 pdata->base.blank = adf_blank; 247 pdata->base.exit = adf_exit; 248 return &pdata->base; 249 } 250