1ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include <stdio.h> 2ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include <stdlib.h> 3ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include <string.h> 4ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 5ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include <xf86drm.h> 6ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include <xf86drmMode.h> 7ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include <drm_fourcc.h> 8ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 9ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include "modeset.h" 10ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include "bo.h" 11ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul#include "dev.h" 12ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 13085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paulstatic int set_crtc_mode(struct sp_dev *dev, struct sp_crtc *crtc, 14085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul struct sp_connector *conn, drmModeModeInfoPtr mode) 15085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul{ 16085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul int ret; 17085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul struct drm_mode_create_blob create_blob; 18085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul drmModePropertySetPtr pset; 19085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 20085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul memset(&create_blob, 0, sizeof(create_blob)); 21085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul create_blob.length = sizeof(struct drm_mode_modeinfo); 22606d743d4cc85a2db272e33700837f622b53c6edVincent Palatin create_blob.data = (__u64)(uintptr_t)mode; 23085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 24085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); 25085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (ret) { 26085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul printf("Failed to create mode property blob %d", ret); 27085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul return ret; 28085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul } 29085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 30085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul pset = drmModePropertySetAlloc(); 31085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (!pset) { 32085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul printf("Failed to allocate property set"); 33085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul return -1; 34085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul } 35085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 36085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul ret = drmModePropertySetAdd(pset, crtc->crtc->crtc_id, 37085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul crtc->mode_pid, create_blob.blob_id) || 389d5cde03d9c5499e29a12541087f4dff31141e70Sean Paul drmModePropertySetAdd(pset, crtc->crtc->crtc_id, 399d5cde03d9c5499e29a12541087f4dff31141e70Sean Paul crtc->active_pid, 1) || 40085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul drmModePropertySetAdd(pset, conn->conn->connector_id, 41085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul conn->crtc_id_pid, crtc->crtc->crtc_id); 42085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (ret) { 43085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul printf("Failed to add blob %d to pset", create_blob.blob_id); 44085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul drmModePropertySetFree(pset); 45085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul return ret; 46085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul } 47085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 48085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul ret = drmModePropertySetCommit(dev->fd, DRM_MODE_ATOMIC_ALLOW_MODESET, 49085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul NULL, pset); 50085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 51085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul drmModePropertySetFree(pset); 52085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 53085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (ret) { 54085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul printf("Failed to commit pset ret=%d\n", ret); 55085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul return ret; 56085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul } 57085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 58085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul memcpy(&crtc->crtc->mode, mode, sizeof(struct drm_mode_modeinfo)); 59085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul crtc->crtc->mode_valid = 1; 60085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul return 0; 61085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul} 62085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul 63ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paulint initialize_screens(struct sp_dev *dev) 64ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul{ 65ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul int ret, i, j; 661db37e417b4f90772f53588ff13fb6960496177fSean Paul unsigned crtc_mask = 0; 67ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 68ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul for (i = 0; i < dev->num_connectors; i++) { 69085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul struct sp_connector *c = &dev->connectors[i]; 70ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul drmModeModeInfoPtr m = NULL; 71ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul drmModeEncoderPtr e = NULL; 72ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul struct sp_crtc *cr = NULL; 73ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 74085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (c->conn->connection != DRM_MODE_CONNECTED) 75ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 76ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 77085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (!c->conn->count_modes) { 78ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul printf("connector has no modes, skipping\n"); 79ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 80ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 81ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 82ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul /* Take the first unless there's a preferred mode */ 83085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul m = &c->conn->modes[0]; 84085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul for (j = 0; j < c->conn->count_modes; j++) { 85085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul drmModeModeInfoPtr tmp_m = &c->conn->modes[j]; 86ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 87ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (!(tmp_m->type & DRM_MODE_TYPE_PREFERRED)) 88ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 89ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 90ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul m = tmp_m; 91ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul break; 92ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 93ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 94085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (!c->conn->count_encoders) { 95ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul printf("no possible encoders for connector\n"); 96ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 97ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 98ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 99ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul for (j = 0; j < dev->num_encoders; j++) { 100ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul e = dev->encoders[j]; 101085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul if (e->encoder_id == c->conn->encoders[0]) 102ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul break; 103ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 104ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (j == dev->num_encoders) { 105ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul printf("could not find encoder for the connector\n"); 106ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 107ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 108ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 109ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul for (j = 0; j < dev->num_crtcs; j++) { 1101db37e417b4f90772f53588ff13fb6960496177fSean Paul if ((1 << j) & crtc_mask) 1111db37e417b4f90772f53588ff13fb6960496177fSean Paul continue; 1121db37e417b4f90772f53588ff13fb6960496177fSean Paul 113ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul cr = &dev->crtcs[j]; 114ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 115ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if ((1 << j) & e->possible_crtcs) 116ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul break; 117ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 118ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (j == dev->num_crtcs) { 119ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul printf("could not find crtc for the encoder\n"); 120ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 121ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 122ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 123085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul ret = set_crtc_mode(dev, cr, c, m); 124ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (ret) { 125085db961ef8c2b6d7c939fe1fda8152e40b23071Sean Paul printf("failed to set mode!\n"); 126ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 127ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 1281db37e417b4f90772f53588ff13fb6960496177fSean Paul crtc_mask |= 1 << j; 129ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 130ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul return 0; 131ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul} 132ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 133ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paulstruct sp_plane *get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc) 134ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul{ 135ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul int i; 136ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 137ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul for(i = 0; i < dev->num_planes; i++) { 138ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul struct sp_plane *p = &dev->planes[i]; 139ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 140ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (p->in_use) 141ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 142ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 143ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (!(p->plane->possible_crtcs & (1 << crtc->pipe))) 144ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul continue; 145ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 146ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul p->in_use = 1; 147ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul return p; 148ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 149ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul return NULL; 150ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul} 151ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 152ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paulvoid put_sp_plane(struct sp_plane *plane) 153ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul{ 154ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul drmModePlanePtr p; 155ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 156ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul /* Get the latest plane information (most notably the crtc_id) */ 157ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul p = drmModeGetPlane(plane->dev->fd, plane->plane->plane_id); 158ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (p) 159ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->plane = p; 160ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 161ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (plane->bo) { 162ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul free_sp_bo(plane->bo); 163ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->bo = NULL; 164ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 165ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->in_use = 0; 166ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul} 167ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 168ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paulint set_sp_plane(struct sp_dev *dev, struct sp_plane *plane, 169ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul struct sp_crtc *crtc, int x, int y) 170ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul{ 171ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul int ret; 172ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul uint32_t w, h; 173ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 174ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul w = plane->bo->width; 175ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul h = plane->bo->height; 176ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 177ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if ((w + x) > crtc->crtc->mode.hdisplay) 178ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul w = crtc->crtc->mode.hdisplay - x; 179ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if ((h + y) > crtc->crtc->mode.vdisplay) 180ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul h = crtc->crtc->mode.vdisplay - y; 181ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 182ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul ret = drmModeSetPlane(dev->fd, plane->plane->plane_id, 183ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul crtc->crtc->crtc_id, plane->bo->fb_id, 0, x, y, w, h, 184ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 0, 0, w << 16, h << 16); 185ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (ret) { 186ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul printf("failed to set plane to crtc ret=%d\n", ret); 187ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul return ret; 188ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 189ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 190ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul return ret; 191ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul} 192ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paulint set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane, 193ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul drmModePropertySetPtr pset, struct sp_crtc *crtc, int x, int y) 194ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul{ 195ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul int ret; 196ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul uint32_t w, h; 197ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 198ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul w = plane->bo->width; 199ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul h = plane->bo->height; 200ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 201ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if ((w + x) > crtc->crtc->mode.hdisplay) 202ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul w = crtc->crtc->mode.hdisplay - x; 203ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if ((h + y) > crtc->crtc->mode.vdisplay) 204ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul h = crtc->crtc->mode.vdisplay - y; 205ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 206ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul ret = drmModePropertySetAdd(pset, plane->plane->plane_id, 207ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->crtc_pid, crtc->crtc->crtc_id) 208ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 209ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->fb_pid, plane->bo->fb_id) 210ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 211ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->crtc_x_pid, x) 212ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 213ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->crtc_y_pid, y) 214ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 215ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->crtc_w_pid, w) 216ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 217ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->crtc_h_pid, h) 218ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 219ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->src_x_pid, 0) 220ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 221ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->src_y_pid, 0) 222ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 223ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->src_w_pid, w << 16) 224ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul || drmModePropertySetAdd(pset, plane->plane->plane_id, 225ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul plane->src_h_pid, h << 16); 226ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul if (ret) { 227ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul printf("failed to add properties to the set\n"); 228ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul return -1; 229ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul } 230ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul 231ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul return ret; 232ef6e8f241ab759e3f707c33d5c700baadae5badbSean Paul} 233