Serenity Operating System
at hosted 246 lines 7.2 kB view raw
1#ifdef __OpenBSD__ 2#include "FB.h" 3#include <AK/Assertions.h> 4#include <AK/LogStream.h> 5#include <sys/cdefs.h> 6#include <sys/ioctl.h> 7#include <sys/mman.h> 8#include <sys/time.h> 9#include <dev/wscons/wsconsio.h> 10 11/* XXX yuck - this doesn't live in /usr/include though */ 12#include "/usr/src/sys/dev/pci/drm/include/uapi/drm/i915_drm.h" 13 14static struct { 15 int width; 16 int height; 17 int pitch; 18 size_t size; 19 uint64_t res_conn_buf[10]; 20} drm_screen; 21 22#define MAX_FBS 2 23 24static struct openbsd_fb { 25 void *fb; 26 int crtc_id; 27 struct drm_mode_crtc crtc; 28} drm_fbs[MAX_FBS]; 29 30#define DRM_DEVICE "/dev/drm0" 31 32int fb_create_buffers(int fd); 33 34int fb_get_size_in_bytes(int fd, size_t* out) 35{ 36 if (!drm_fbs[0].fb) 37 fb_create_buffers(fd); 38 39 *out = drm_screen.size; 40 41 return 0; 42} 43 44int fb_get_resolution(int fd, FBResolution* info) 45{ 46 if (!drm_fbs[0].fb) 47 fb_create_buffers(fd); 48 49 info->pitch = drm_screen.pitch; 50 info->width = drm_screen.width; 51 info->height = drm_screen.height; 52 return 0; 53} 54 55int fb_set_resolution(int fd, FBResolution* info) 56{ 57 // we can't actually change the resolution, so just keep it at what it's at 58 if (fb_get_resolution(fd, info) != 0) 59 return -1; 60 61 // but take this opportunity to put wscons into dumb (non-text) mode to setup for mmap 62 int mode = WSDISPLAYIO_MODE_DUMBFB; 63 if (ioctl(fd, WSDISPLAYIO_SMODE, &mode) == -1) { 64 perror("WSDISPLAYIO_SMODE"); 65 return -1; 66 } 67 68 return 0; 69} 70 71void *fb_get_addr(int fd, int index) 72{ 73 if (!drm_fbs[0].fb) 74 fb_create_buffers(fd); 75 76 return drm_fbs[index].fb; 77} 78 79int fb_get_buffer(int fd, int* index) 80{ 81 dbg() << "fb_get_buffer not supported"; 82 (void)fd; 83 (void)index; 84 return -1; 85} 86 87int fb_set_buffer(int fd, int index) 88{ 89 struct drm_mode_crtc_page_flip flip; 90 91 if (index >= MAX_FBS) 92 return -1; 93 94 if (!drm_fbs[index].fb) 95 fb_create_buffers(fd); 96 97 memset(&flip, 0, sizeof(flip)); 98 flip.fb_id = drm_fbs[index].crtc.fb_id; 99 flip.crtc_id = drm_fbs[index].crtc.crtc_id; 100 flip.user_data = (u64)drm_fbs[index].fb; 101 // TODO: check for DRM_CAP_ASYNC_PAGE_FLIP and use DRM_MODE_PAGE_FLIP_ASYNC 102 flip.flags = 0; 103 104 if (ioctl(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip) != 0) { 105 if (errno != EBUSY) { 106 perror("DRM_IOCTL_MODE_PAGE_FLIP"); 107 return -1; 108 } 109 } 110 111 return 0; 112} 113 114int fb_create_buffers(int fd) 115{ 116 int ret = -1; 117 118 memset(&drm_screen, 0, sizeof(drm_screen)); 119 memset(&drm_fbs, 0, sizeof(drm_fbs)); 120 121 if (ioctl(fd, DRM_IOCTL_SET_MASTER, 0) != 0) { 122 perror("DRM_IOCTL_SET_MASTER"); 123 return -1; 124 } 125 126 struct drm_mode_card_res res; 127 memset(&res, 0, sizeof(res)); 128 if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0) { 129 perror("DRM_IOCTL_MODE_GETRESOURCES"); 130 return -1; 131 } 132 133 for (auto i = 0; i < (int)res.count_connectors; i++) { 134 uint64_t res_fb_buf[10] = { 0 }, res_crtc_buf[10] = { 0 }, res_enc_buf[10] = { 0 }; 135 res.fb_id_ptr = (u64)res_fb_buf; 136 res.crtc_id_ptr = (u64)res_crtc_buf; 137 res.connector_id_ptr = (u64)drm_screen.res_conn_buf; 138 res.encoder_id_ptr = (u64)res_enc_buf; 139 if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0) { 140 perror("DRM_IOCTL_MODE_GETRESOURCES"); 141 return -1; 142 } 143 144 struct drm_mode_modeinfo conn_mode_buf[20]; 145 uint64_t conn_prop_buf[20] = { 0 }, conn_propval_buf[20] = { 0 }, conn_enc_buf[20] = { 0 }; 146 struct drm_mode_get_connector conn; 147 memset(&conn_mode_buf, 0, sizeof(conn_mode_buf)); 148 memset(&conn, 0, sizeof(conn)); 149 conn.connector_id = (u64)drm_screen.res_conn_buf[i]; 150 if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) != 0) { 151 perror("DRM_IOCTL_MODE_GETCONNECTOR"); 152 continue; 153 } 154 155 conn.modes_ptr = (u64)conn_mode_buf; 156 conn.props_ptr = (u64)conn_prop_buf; 157 conn.prop_values_ptr = (u64)conn_propval_buf; 158 conn.encoders_ptr = (u64)conn_enc_buf; 159 if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) != 0) { 160 perror("DRM_IOCTL_MODE_GETCONNECTOR"); 161 continue; 162 } 163 164 if (conn.count_encoders < 1 || conn.count_modes < 1 || !conn.encoder_id || !conn.connection) 165 continue; 166 167 for (auto j = 0; j <= 1; j++) { 168 struct drm_mode_create_dumb create_dumb; 169 struct drm_mode_map_dumb map_dumb; 170 struct drm_mode_fb_cmd cmd_dumb; 171 172 memset(&create_dumb, 0, sizeof(create_dumb)); 173 174 create_dumb.width = conn_mode_buf[0].hdisplay; 175 create_dumb.height = conn_mode_buf[0].vdisplay; 176 create_dumb.bpp = 32; 177 if (ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) != 0) { 178 perror("DRM_IOCTL_MODE_CREATE_DUMB"); 179 goto bail; 180 } 181 182 cmd_dumb.width = create_dumb.width; 183 cmd_dumb.height = create_dumb.height; 184 cmd_dumb.bpp = create_dumb.bpp; 185 cmd_dumb.pitch = create_dumb.pitch; 186 cmd_dumb.depth = create_dumb.bpp; 187 cmd_dumb.handle = create_dumb.handle; 188 if (ioctl(fd, DRM_IOCTL_MODE_ADDFB, &cmd_dumb) != 0) { 189 perror("DRM_IOCTL_MODE_ADDFB"); 190 goto bail; 191 } 192 193 map_dumb.handle = create_dumb.handle; 194 if (ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb) != 0) { 195 perror("DRM_IOCTL_MODE_MAP_DUMB"); 196 goto bail; 197 } 198 199 drm_screen.width = create_dumb.width; 200 drm_screen.height = create_dumb.height; 201 drm_screen.pitch = create_dumb.pitch; 202 drm_screen.size = create_dumb.size; 203 204 drm_fbs[j].fb = mmap(nullptr, drm_screen.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map_dumb.offset); 205 206 struct drm_mode_get_encoder enc; 207 enc.encoder_id = conn.encoder_id; 208 if (ioctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc) != 0) { 209 perror("DRM_IOCTL_MODE_GETENCODER"); 210 munmap(drm_fbs[j].fb, drm_screen.size); 211 drm_fbs[j].fb = nullptr; 212 goto bail; 213 } 214 215 drm_fbs[j].crtc.crtc_id = enc.crtc_id; 216 if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &drm_fbs[j].crtc) != 0) { 217 perror("DRM_IOCTL_MODE_GETCRTC"); 218 munmap(drm_fbs[j].fb, drm_screen.size); 219 drm_fbs[j].fb = nullptr; 220 goto bail; 221 } 222 223 drm_fbs[j].crtc.fb_id = cmd_dumb.fb_id; 224 drm_fbs[j].crtc.set_connectors_ptr = (uint64_t)&drm_screen.res_conn_buf[i]; 225 drm_fbs[j].crtc.count_connectors = 1; 226 drm_fbs[j].crtc.mode = conn_mode_buf[0]; 227 drm_fbs[j].crtc.mode_valid = 1; 228 } 229 230 // we only need one set of buffers 231 ret = 0; 232 break; 233 } 234 235 if (ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &drm_fbs[0].crtc) != 0) 236 perror("DRM_IOCTL_MODE_SETCRTC"); 237 238bail: 239 if (ioctl(fd, DRM_IOCTL_DROP_MASTER, 0) != 0) { 240 perror("DRM_IOCTL_DROP_MASTER"); 241 ASSERT_NOT_REACHED(); 242 } 243 244 return ret; 245} 246#endif