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 <unistd.h> 23 24 #include <sys/cdefs.h> 25 #include <sys/mman.h> 26 27 #include <adf/adf.h> 28 29 #include "graphics.h" 30 31 struct adf_surface_pdata { 32 GRSurface base; 33 int fd; 34 __u32 offset; 35 __u32 pitch; 36 }; 37 38 struct adf_pdata { 39 minui_backend base; 40 int intf_fd; 41 adf_id_t eng_id; 42 __u32 format; 43 44 unsigned int current_surface; 45 unsigned int n_surfaces; 46 struct adf_surface_pdata surfaces[2]; 47 }; 48 49 static gr_surface adf_flip(struct minui_backend *backend); 50 static void adf_blank(struct minui_backend *backend, bool blank); 51 52 static int adf_surface_init(struct adf_pdata *pdata, 53 struct drm_mode_modeinfo *mode, struct adf_surface_pdata *surf) 54 { 55 memset(surf, 0, sizeof(*surf)); 56 57 surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay, 58 mode->vdisplay, pdata->format, &surf->offset, &surf->pitch); 59 if (surf->fd < 0) 60 return surf->fd; 61 62 surf->base.width = mode->hdisplay; 63 surf->base.height = mode->vdisplay; 64 surf->base.row_bytes = surf->pitch; 65 surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4; 66 67 surf->base.data = mmap(NULL, 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(struct adf_pdata *pdata) 78 { 79 struct 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(struct adf_pdata *pdata, struct 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 gr_surface adf_init(minui_backend *backend) 138 { 139 struct adf_pdata *pdata = (struct adf_pdata *)backend; 140 adf_id_t *dev_ids = NULL; 141 ssize_t n_dev_ids, i; 142 gr_surface ret; 143 144 #if defined(RECOVERY_BGRA) 145 pdata->format = DRM_FORMAT_BGRA8888; 146 #elif defined(RECOVERY_RGBX) 147 pdata->format = DRM_FORMAT_RGBX8888; 148 #else 149 pdata->format = DRM_FORMAT_RGB565; 150 #endif 151 152 n_dev_ids = adf_devices(&dev_ids); 153 if (n_dev_ids == 0) { 154 return NULL; 155 } else if (n_dev_ids < 0) { 156 fprintf(stderr, "enumerating adf devices failed: %s\n", 157 strerror(-n_dev_ids)); 158 return NULL; 159 } 160 161 pdata->intf_fd = -1; 162 163 for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { 164 struct adf_device dev; 165 166 int err = adf_device_open(dev_ids[i], O_RDWR, &dev); 167 if (err < 0) { 168 fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i], 169 strerror(-err)); 170 continue; 171 } 172 173 err = adf_device_init(pdata, &dev); 174 if (err < 0) 175 fprintf(stderr, "initializing adf device %u failed: %s\n", 176 dev_ids[i], strerror(-err)); 177 178 adf_device_close(&dev); 179 } 180 181 free(dev_ids); 182 183 if (pdata->intf_fd < 0) 184 return NULL; 185 186 ret = adf_flip(backend); 187 188 adf_blank(backend, true); 189 adf_blank(backend, false); 190 191 return ret; 192 } 193 194 static gr_surface adf_flip(struct minui_backend *backend) 195 { 196 struct adf_pdata *pdata = (struct adf_pdata *)backend; 197 struct adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface]; 198 199 int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id, 200 surf->base.width, surf->base.height, pdata->format, surf->fd, 201 surf->offset, surf->pitch, -1); 202 if (fence_fd >= 0) 203 close(fence_fd); 204 205 pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces; 206 return &pdata->surfaces[pdata->current_surface].base; 207 } 208 209 static void adf_blank(struct minui_backend *backend, bool blank) 210 { 211 struct adf_pdata *pdata = (struct adf_pdata *)backend; 212 adf_interface_blank(pdata->intf_fd, 213 blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); 214 } 215 216 static void adf_surface_destroy(struct adf_surface_pdata *surf) 217 { 218 munmap(surf->base.data, surf->pitch * surf->base.height); 219 close(surf->fd); 220 } 221 222 static void adf_exit(struct minui_backend *backend) 223 { 224 struct adf_pdata *pdata = (struct adf_pdata *)backend; 225 unsigned int i; 226 227 for (i = 0; i < pdata->n_surfaces; i++) 228 adf_surface_destroy(&pdata->surfaces[i]); 229 if (pdata->intf_fd >= 0) 230 close(pdata->intf_fd); 231 free(pdata); 232 } 233 234 minui_backend *open_adf() 235 { 236 struct adf_pdata *pdata = calloc(1, sizeof(*pdata)); 237 if (!pdata) { 238 perror("allocating adf backend failed"); 239 return NULL; 240 } 241 242 pdata->base.init = adf_init; 243 pdata->base.flip = adf_flip; 244 pdata->base.blank = adf_blank; 245 pdata->base.exit = adf_exit; 246 return &pdata->base; 247 } 248