--- /dev/null
+#include "evas_common.h"
+#include "evas_private.h"
+#include "evas_engine.h"
+#include "rsxutil.h"
+#include "Evas_Engine_PSL1GHT.h"
+
+#include <malloc.h>
+
+int _evas_engine_psl1ght_log_dom = -1;
+
+/* function tables - filled in later (func and parent func) */
+static Evas_Func func, pfunc;
+
+/* engine struct data */
+typedef struct _Render_Engine Render_Engine;
+
+#define MAX_BUFFERS 2
+
+struct _Render_Engine
+{
+ Tilebuf *tb;
+ Tilebuf_Rect *rects;
+ Eina_Inlist *cur_rect;
+
+ /* RSX device context */
+ gcmContextData *context;
+ void *host_addr;
+
+ /* The buffers we will be drawing into. */
+ rsxBuffer buffers[MAX_BUFFERS];
+ int currentBuffer;
+ int width;
+ int height;
+ RGBA_Image *rgba_image;
+ uint32_t rgba_image_offset;
+
+ int end : 1;
+};
+
+/* prototypes we will use here */
+static void *_output_setup(int w, int h);
+
+static void *eng_info(Evas *e);
+static void
+ eng_info_free(Evas *e, void *info);
+static int
+ eng_setup(Evas *e, void *info);
+static void
+ eng_output_free(void *data);
+static void
+ eng_output_resize(void *data, int w, int h);
+static void
+ eng_output_tile_size_set(void *data, int w, int h);
+static void
+ eng_output_redraws_rect_add(void *data, int x, int y, int w, int h);
+static void
+ eng_output_redraws_rect_del(void *data, int x, int y, int w, int h);
+static void
+ eng_output_redraws_clear(void *data);
+static void *eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch);
+static void
+ eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h);
+static void
+ eng_output_flush(void *data);
+static void
+ eng_output_idle_flush(void *data);
+
+/* internal engine routines */
+static void *
+_output_setup(int w, int h)
+{
+ Render_Engine *re;
+ int i;
+ u16 width, height;
+ DATA32 *image_data = NULL;
+ int image_size;
+
+ printf ("_output_setup called : %dx%d\n", w, h);
+ re = calloc(1, sizeof(Render_Engine));
+ if (!re)
+ return NULL;
+
+ /* Allocate a 1Mb buffer, alligned to a 1Mb boundary
+ * to be our shared IO memory with the RSX. */
+ re->host_addr = memalign (1024 * 1024, HOST_SIZE);
+ if (re->host_addr == NULL)
+ {
+ free (re);
+ return NULL;
+ }
+ re->context = initScreen (re->host_addr, HOST_SIZE);
+ if (re->context == NULL)
+ {
+ free (re->host_addr);
+ free (re);
+ return NULL;
+ }
+ width = w;
+ height = h;
+ setResolution (re->context, &width, &height);
+ re->currentBuffer = 0;
+ re->width = width;
+ re->height = height;
+
+ for (i = 0; i < MAX_BUFFERS; i++)
+ makeBuffer (&re->buffers[i], width, height, i);
+
+ flipBuffer(re->context, MAX_BUFFERS - 1);
+
+ /* if we haven't initialized - init (automatic abort if already done) */
+ evas_common_cpu_init();
+ evas_common_blend_init();
+ evas_common_image_init();
+ evas_common_convert_init();
+ evas_common_scale_init();
+ evas_common_rectangle_init();
+ evas_common_polygon_init();
+ evas_common_line_init();
+ evas_common_font_init();
+ evas_common_draw_init();
+ evas_common_tilebuf_init();
+
+ re->tb = evas_common_tilebuf_new(w, h);
+
+ /* in preliminary tests 16x16 gave highest framerates */
+ evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
+
+ /* Allocate our memaligned backbuffer */
+ image_size = ((w * h * sizeof(u32)) + 0xfffff) & - 0x100000;
+ image_data = memalign (1024 * 1024, image_size);
+ re->rgba_image = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
+ w, h, image_data, 1, EVAS_COLORSPACE_ARGB8888);
+ gcmMapMainMemory(image_data, image_size, &re->rgba_image_offset);
+
+ return re;
+}
+
+/* engine api this module provides */
+static void *
+eng_info(Evas *e)
+{
+ Evas_Engine_Info_PSL1GHT *info;
+
+ printf ("eng_info called\n");
+ info = calloc(1, sizeof(Evas_Engine_Info_PSL1GHT));
+ if (!info)
+ return NULL;
+
+ info->magic.magic = rand();
+ info->render_mode = EVAS_RENDER_MODE_BLOCKING;
+
+ return info;
+}
+
+static void
+eng_info_free(Evas *e __UNUSED__, void *info)
+{
+ Evas_Engine_Info_PSL1GHT *in;
+
+ printf ("eng_info_free called\n");
+ in = (Evas_Engine_Info_PSL1GHT *)info;
+ free(in);
+}
+
+static int
+eng_setup(Evas *e, void *in)
+{
+ Evas_Engine_Info_PSL1GHT *info;
+
+ printf ("eng_setup called\n");
+ info = (Evas_Engine_Info_PSL1GHT *)in;
+
+ e->engine.data.output = _output_setup(e->output.w, e->output.h);
+ if (!e->engine.data.output)
+ return 0;
+
+ e->engine.func = &func;
+ e->engine.data.context = e->engine.func->context_new(e->engine.data.output);
+
+ return 1;
+}
+
+static void
+eng_output_free(void *data)
+{
+ Render_Engine *re;
+ int i;
+
+ printf ("eng_output_free called\n");
+ re = (Render_Engine *)data;
+
+ gcmSetWaitFlip(re->context);
+ for (i = 0; i < MAX_BUFFERS; i++)
+ rsxFree (re->buffers[i].ptr);
+
+ if (re->rgba_image)
+ {
+ DATA32 *image_data;
+
+ image_data = re->rgba_image->image.data;
+ evas_cache_image_drop(&re->rgba_image->cache_entry);
+ free (image_data);
+ }
+
+ freeScreen (re->context);
+ free (re->host_addr);
+
+ evas_common_tilebuf_free(re->tb);
+ if (re->rects)
+ evas_common_tilebuf_free_render_rects(re->rects);
+
+ free(re);
+
+ evas_common_font_shutdown();
+ evas_common_image_shutdown();
+}
+
+static void
+eng_output_resize(void *data, int w, int h)
+{
+ Render_Engine *re;
+ int i;
+ u16 width, height;
+ DATA32 *image_data;
+ int image_size;
+
+ printf ("eng_output_resize called : %dx%d\n", w, h);
+ re = (Render_Engine *)data;
+
+ width = w;
+ height = h;
+ if (setResolution (re->context, &width, &height))
+ {
+ re->width = width;
+ re->height = height;
+
+ gcmSetWaitFlip(re->context);
+ for (i = 0; i < MAX_BUFFERS; i++) {
+ rsxFree (re->buffers[i].ptr);
+ makeBuffer (&re->buffers[i], width, height, i);
+ }
+
+ flipBuffer(re->context, MAX_BUFFERS - 1);
+
+ evas_common_tilebuf_free(re->tb);
+ re->tb = evas_common_tilebuf_new(w, h);
+ evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
+
+ /* Realloc our backbuf image */
+ if (re->rgba_image)
+ {
+ image_data = re->rgba_image->image.data;
+ evas_cache_image_drop(&re->rgba_image->cache_entry);
+ free (image_data);
+ }
+ image_size = ((w * h * sizeof(u32)) + 0xfffff) & - 0x100000;
+ image_data = memalign (1024 * 1024, image_size);
+ re->rgba_image = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
+ w, h, image_data, 1, EVAS_COLORSPACE_ARGB8888);
+ gcmMapMainMemory(image_data, image_size, &re->rgba_image_offset);
+ }
+}
+
+static void
+eng_output_tile_size_set(void *data, int w, int h)
+{
+ Render_Engine *re;
+
+ printf ("eng_output_tile_size_set called : %dx%d\n", w, h);
+ re = (Render_Engine *)data;
+ evas_common_tilebuf_set_tile_size(re->tb, w, h);
+}
+
+static void
+eng_output_redraws_rect_add(void *data, int x, int y, int w, int h)
+{
+ Render_Engine *re;
+
+ //printf ("eng_output_redraws_rect_add called : %d,%d %dx%d\n", x, y, w, h);
+ re = (Render_Engine *)data;
+ evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
+}
+
+static void
+eng_output_redraws_rect_del(void *data, int x, int y, int w, int h)
+{
+ Render_Engine *re;
+
+ //printf ("eng_output_redraws_rect_del called : %d,%d %dx%d\n", x, y, w, h);
+ re = (Render_Engine *)data;
+ evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
+}
+
+static void
+eng_output_redraws_clear(void *data)
+{
+ Render_Engine *re;
+
+ //printf ("eng_output_redraws_clear called\n");
+ re = (Render_Engine *)data;
+ evas_common_tilebuf_clear(re->tb);
+}
+
+static void *
+eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch)
+{
+ Render_Engine *re;
+ Tilebuf_Rect *rect;
+ int ux, uy, uw, uh;
+
+ re = (Render_Engine *)data;
+ /*printf ("eng_output_redraws_next_update_get called : %d,%d %dx%d -- %d,%d %dx%d\n",
+ *x, *y, *w, *h, *cx, *cy, *cw, *ch);*/
+ if (re->end)
+ {
+ re->end = 0;
+ return NULL;
+ }
+ if (!re->rects)
+ {
+ re->rects = evas_common_tilebuf_get_render_rects(re->tb);
+ re->cur_rect = EINA_INLIST_GET(re->rects);
+ }
+ if (!re->cur_rect)
+ return NULL;
+
+ rect = (Tilebuf_Rect *)re->cur_rect;
+ ux = rect->x; uy = rect->y; uw = rect->w; uh = rect->h;
+ re->cur_rect = re->cur_rect->next;
+ if (!re->cur_rect)
+ {
+ evas_common_tilebuf_free_render_rects(re->rects);
+ re->rects = NULL;
+ re->end = 1;
+ }
+
+ *x = *cx = ux;
+ *y = *cy = uy;
+ *w = *cw = uw;
+ *h = *ch = uh;
+ /*printf ("eng_output_redraws_next_update_get returning : %d,%d %dx%d -- %d,%d %dx%d\n",
+ *x, *y, *w, *h, *cx, *cy, *cw, *ch);*/
+
+ return re->rgba_image;
+}
+
+static void
+eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h)
+{
+ /* Don't do anything, we'll just coy the whole buffer when it's time to flush */
+}
+
+static void
+eng_output_flush(void *data)
+{
+ Render_Engine *re;
+ rsxBuffer *buffer;
+ int width;
+ int height;
+
+ //printf ("eng_output_flush called\n");
+ re = (Render_Engine *)data;
+ buffer = &re->buffers[re->currentBuffer];
+ width = re->rgba_image->cache_entry.w;
+ height = re->rgba_image->cache_entry.h;
+
+ /* Wait for the flip before copying the buffer */
+ waitFlip ();
+
+ if (re->width == width &&
+ re->height == height)
+ {
+ /* DMA the back buffer into the rsx buffer */
+ rsxSetTransferImage (re->context,
+ GCM_TRANSFER_MAIN_TO_LOCAL,
+ buffer->offset, buffer->width * sizeof(u32),
+ 0, 0,
+ re->rgba_image_offset, re->width * sizeof(u32),
+ 0, 0, re->width, re->height, sizeof(u32));
+ }
+ else
+ {
+ gcmTransferScale gcm_scale;
+ gcmTransferSurface gcm_surface;
+
+ gcm_surface.format = GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8;
+ gcm_surface.pitch = buffer->width * sizeof(u32);
+ gcm_surface._pad0[0] = gcm_surface._pad0[1] = 0;
+ gcm_surface.offset = buffer->offset;
+
+ gcm_scale.interp = GCM_TRANSFER_INTERPOLATOR_LINEAR;
+ gcm_scale.conversion = GCM_TRANSFER_CONVERSION_TRUNCATE;
+ gcm_scale.format = GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8;
+ gcm_scale.origin = GCM_TRANSFER_ORIGIN_CORNER;
+ gcm_scale.operation = GCM_TRANSFER_OPERATION_SRCCOPY;
+ gcm_scale.offset = re->rgba_image_offset;
+ gcm_scale.clipX = 0;
+ gcm_scale.clipY = 0;
+ gcm_scale.clipW = re->width;
+ gcm_scale.clipH = re->height;
+ gcm_scale.outX = 0;
+ gcm_scale.outY = 0;
+ gcm_scale.outW = re->width;
+ gcm_scale.outH = re->height;
+ gcm_scale.ratioX = rsxGetFixedSint32 ((float)width / (float)re->width);
+ gcm_scale.ratioY = rsxGetFixedSint32 ((float)height / (float)re->height);
+ gcm_scale.inX = 0;
+ gcm_scale.inY = 0;
+ gcm_scale.inW = (width & ~1); // Width must be a multiple of 2
+ gcm_scale.inH = height;
+ if (gcm_scale.inW < 2) // Minimum inW value is 2
+ gcm_scale.inW = 2;
+ if (gcm_scale.inW > 2046) // Maximum inW value is 2046
+ gcm_scale.inW = 2046;
+ if (gcm_scale.inH < 1) // Minimum inH value is 1
+ gcm_scale.inH = 1;
+ if (gcm_scale.inH > 2047) // Maximum inW value is 2047
+ gcm_scale.inH = 2047;
+ gcm_scale.pitch = sizeof(u32) * width;
+
+ rsxSetTransferScaleMode (re->context, GCM_TRANSFER_MAIN_TO_LOCAL, GCM_TRANSFER_SURFACE);
+ rsxSetTransferScaleSurface (re->context, &gcm_scale, &gcm_surface);
+ }
+ /* Wait for the DMA to finish */
+ flushRSX (re->context);
+
+ /* Flip buffer onto screen */
+ flipBuffer (re->context, re->currentBuffer);
+ re->currentBuffer = (re->currentBuffer + 1) % MAX_BUFFERS;
+}
+
+static void
+eng_output_idle_flush(void *data)
+{
+ Render_Engine *re;
+
+ printf ("eng_output_idle_flush called\n");
+ re = (Render_Engine *)data;
+}
+
+static Eina_Bool
+eng_canvas_alpha_get(void *data, void *context __UNUSED__)
+{
+ Render_Engine *re;
+
+ // printf ("eng_output_alpha_get called\n");
+ re = (Render_Engine *)data;
+ return EINA_TRUE;
+}
+
+/* module advertising code */
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ /* get whatever engine module we inherit from */
+ if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0;
+ _evas_engine_psl1ght_log_dom = eina_log_domain_register
+ ("evas-psl1ght", EVAS_DEFAULT_LOG_COLOR);
+ if (_evas_engine_psl1ght_log_dom < 0)
+ {
+ EINA_LOG_ERR("Can not create a module log domain.");
+ return 0;
+ }
+
+ /* store it for later use */
+ func = pfunc;
+ /* now to override methods */
+#define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_)
+ ORD(info);
+ ORD(info_free);
+ ORD(setup);
+ ORD(canvas_alpha_get);
+ ORD(output_free);
+ ORD(output_resize);
+ ORD(output_tile_size_set);
+ ORD(output_redraws_rect_add);
+ ORD(output_redraws_rect_del);
+ ORD(output_redraws_clear);
+ ORD(output_redraws_next_update_get);
+ ORD(output_redraws_next_update_push);
+ ORD(output_flush);
+ ORD(output_idle_flush);
+
+ /* now advertise out own api */
+ em->functions = (void *)(&func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em __UNUSED__)
+{
+ eina_log_domain_unregister(_evas_engine_psl1ght_log_dom);
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "psl1ght",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, psl1ght);
+
+#ifndef EVAS_STATIC_BUILD_PSL1GHT
+EVAS_EINA_MODULE_DEFINE(engine, psl1ght);
+#endif
--- /dev/null
+/*
+ * This software is distributed under the terms of the MIT License
+ */
+
+#include <ppu-lv2.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysutil/video.h>
+#include <rsx/gcm_sys.h>
+#include <rsx/rsx.h>
+#include <io/pad.h>
+#include <time.h>
+#include <cairo/cairo.h>
+#include <math.h>
+
+#include "rsxutil.h"
+
+#define GCM_LABEL_INDEX 255
+
+static void
+waitRSXIdle(gcmContextData *context);
+
+static int flipped = FALSE;
+
+void
+waitFlip()
+{
+ if (flipped)
+ {
+ while (gcmGetFlipStatus () != 0)
+ usleep (200); /* Sleep, to not stress the cpu. */
+ gcmResetFlipStatus ();
+ flipped = FALSE;
+ }
+}
+
+int
+flipBuffer(gcmContextData *context, s32 buffer)
+{
+ if (gcmSetFlip (context, buffer) == 0)
+ {
+ rsxFlushBuffer (context);
+ // Prevent the RSX from continuing until the flip has finished.
+ gcmSetWaitFlip (context);
+
+ flipped = TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+makeBuffer(rsxBuffer *buffer, u16 width, u16 height, int id)
+{
+ int depth = sizeof(u32);
+ int pitch = depth * width;
+ int size = depth * width * height;
+
+ buffer->ptr = (uint32_t *)rsxMemalign (64, size);
+
+ if (buffer->ptr == NULL)
+ goto error;
+
+ if (rsxAddressToOffset (buffer->ptr, &buffer->offset) != 0)
+ goto error;
+
+ /* Register the display buffer with the RSX */
+ if (gcmSetDisplayBuffer (id, buffer->offset, pitch, width, height) != 0)
+ goto error;
+
+ buffer->width = width;
+ buffer->height = height;
+ buffer->id = id;
+
+ return TRUE;
+
+error:
+ if (buffer->ptr != NULL)
+ rsxFree (buffer->ptr);
+
+ return FALSE;
+}
+
+int
+copyBuffer(gcmContextData *context, rsxBuffer *source, rsxBuffer *destination)
+{
+ rsxSetTransferData(context, GCM_TRANSFER_LOCAL_TO_LOCAL,
+ destination->offset,
+ destination->width * sizeof(u32),
+ source->offset,
+ source->width * sizeof(u32),
+ source->width * sizeof(u32),
+ source->height);
+}
+
+int
+getResolution(u16 *width, u16 *height)
+{
+ videoState state;
+ videoResolution resolution;
+
+ /* Get the state of the display */
+ if (videoGetState (0, 0, &state) == 0 &&
+ videoGetResolution (state.displayMode.resolution, &resolution) == 0)
+ {
+ if (width)
+ *width = resolution.width;
+ if (height)
+ *height = resolution.height;
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static u8
+getPreferredResolution(u16 width, u16 height)
+{
+ videoDeviceInfo info;
+ videoResolution res;
+ int area = width * height;
+ int mode_area;
+ int min_area_diff = abs (area - (720 * 480));
+ int area_diff;
+ u8 resolution = VIDEO_RESOLUTION_480;
+ int i;
+
+ videoGetDeviceInfo(0, 0, &info);
+
+ for (i = 0; i < info.availableModeCount; i++) {
+ videoGetResolution (info.availableModes[i].resolution, &res);
+ mode_area = res.width * res.height;
+ area_diff = abs (area - mode_area);
+ if (area_diff < min_area_diff)
+ {
+ min_area_diff = area_diff;
+ resolution = info.availableModes[i].resolution;
+ }
+ }
+
+ return resolution;
+}
+
+int
+setResolution(gcmContextData *context, u16 *width, u16 *height)
+{
+ videoState state;
+ videoConfiguration vconfig;
+ videoResolution res;
+ u8 resolution;
+
+ resolution = getPreferredResolution (*width, *height);
+
+ /* Get the state of the display */
+ if (videoGetState (0, 0, &state) != 0)
+ return FALSE;
+
+ /* Make sure display is enabled */
+ if (state.state != 0)
+ return FALSE;
+
+ if (videoGetResolution (resolution, &res) != 0)
+ return FALSE;
+
+ /* Configure the buffer format to xRGB */
+ memset (&vconfig, 0, sizeof(videoConfiguration));
+ vconfig.resolution = resolution;
+ vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
+ vconfig.pitch = res.width * sizeof(u32);
+ vconfig.aspect = VIDEO_ASPECT_AUTO;
+
+ flushRSX(context);
+
+ if (videoConfigure (0, &vconfig, NULL, 0) != 0)
+ return FALSE;
+
+ *width = res.width;
+ *height = res.height;
+
+ return TRUE;
+}
+
+gcmContextData *
+initScreen(void *host_addr, u32 size)
+{
+ gcmContextData *context = NULL; /* Context to keep track of the RSX buffer. */
+ videoState state;
+ videoConfiguration vconfig;
+ videoResolution res; /* Screen Resolution */
+
+ /* Initilise Reality, which sets up the command buffer and shared IO memory */
+ context = rsxInit (CB_SIZE, size, host_addr);
+ if (context == NULL)
+ goto error;
+
+ /* Get the state of the display */
+ if (videoGetState (0, 0, &state) != 0)
+ goto error;
+
+ /* Make sure display is enabled */
+ if (state.state != 0)
+ goto error;
+
+ /* Get the current resolution */
+ if (videoGetResolution (state.displayMode.resolution, &res) != 0)
+ goto error;
+
+ /* Configure the buffer format to xRGB */
+ memset (&vconfig, 0, sizeof(videoConfiguration));
+ vconfig.resolution = state.displayMode.resolution;
+ vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
+ vconfig.pitch = res.width * sizeof(u32);
+ vconfig.aspect = state.displayMode.aspect;
+
+ flushRSX(context);
+
+ if (videoConfigure (0, &vconfig, NULL, 0) != 0)
+ goto error;
+
+ if (videoGetState (0, 0, &state) != 0)
+ goto error;
+
+ gcmSetFlipMode (GCM_FLIP_VSYNC); // Wait for VSYNC to flip
+
+ gcmResetFlipStatus();
+
+ return context;
+
+error:
+ if (context)
+ rsxFinish (context, 0);
+
+ return NULL;
+}
+
+void
+freeScreen(gcmContextData *context)
+{
+ rsxFinish (context, 0);
+}
+
+static void
+waitFinish(gcmContextData *context, u32 sLabelVal)
+{
+ rsxSetWriteBackendLabel (context, GCM_LABEL_INDEX, sLabelVal);
+
+ rsxFlushBuffer (context);
+
+ while (*(vu32 *)gcmGetLabelAddress (GCM_LABEL_INDEX) != sLabelVal)
+ usleep(30);
+}
+
+static void
+waitRSXIdle(gcmContextData *context)
+{
+ static u32 sLabelVal = 1;
+
+ rsxSetWriteBackendLabel (context, GCM_LABEL_INDEX, sLabelVal);
+ rsxSetWaitLabel (context, GCM_LABEL_INDEX, sLabelVal);
+
+ sLabelVal++;
+
+ waitFinish(context, sLabelVal++);
+}
+
+void
+flushRSX(gcmContextData *context)
+{
+ if (flipped)
+ waitFlip ();
+ waitRSXIdle(context);
+}
+