diff options
Diffstat (limited to 'kstars/kstars/indi/fli/libfli-camera-parport.c')
-rw-r--r-- | kstars/kstars/indi/fli/libfli-camera-parport.c | 753 |
1 files changed, 753 insertions, 0 deletions
diff --git a/kstars/kstars/indi/fli/libfli-camera-parport.c b/kstars/kstars/indi/fli/libfli-camera-parport.c new file mode 100644 index 00000000..bd5343ce --- /dev/null +++ b/kstars/kstars/indi/fli/libfli-camera-parport.c @@ -0,0 +1,753 @@ +/* + + Copyright (c) 2002 Finger Lakes Instrumentation (FLI), L.L.C. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + Neither the name of Finger Lakes Instrumentation (FLI), LLC + nor the names of its contributors may be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + ====================================================================== + + Finger Lakes Instrumentation, L.L.C. (FLI) + web: http://www.fli-cam.com + email: support@fli-cam.com + +*/ + +#ifdef WIN32 +#include <winsock.h> +#else +#include <sys/param.h> +#include <netinet/in.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include "libfli-libfli.h" +#include "libfli-mem.h" +#include "libfli-debug.h" +#include "libfli-camera.h" +#include "libfli-camera-parport.h" + +long fli_camera_parport_open(flidev_t dev) +{ + flicamdata_t *cam; + long rlen, wlen; + unsigned short buf; + int id; + + cam = DEVICE->device_data; + + /* Set timeout values */ + cam->readto = 1000; + cam->writeto = 1000; + cam->dirto = 1000; + + rlen = 2; + wlen = 2; + buf = htons(C_ADDRESS(1, EPARAM_ECHO)); + IO(dev, &buf, &wlen, &rlen); + if (buf != htons(C_ADDRESS(1, EPARAM_ECHO))) + { + debug(FLIDEBUG_FAIL, "Echo back from camera failed."); + return -EIO; + } + + rlen = 2; wlen = 2; + buf = htons(C_ADDRESS(1, EPARAM_DEVICE)); + IO(dev, &buf, &wlen, &rlen); + DEVICE->devinfo.hwrev = ntohs(buf) & 0x00ff; + + rlen = 2; wlen = 2; + buf = htons(C_ADDRESS(1, EPARAM_CCDID)); + IO(dev, &buf, &wlen, &rlen); + DEVICE->devinfo.devid = ntohs(buf) & 0x00ff; + + for (id = 0; knowndev[id].index != 0; id++) + if (knowndev[id].index == DEVICE->devinfo.devid) + break; + + if (knowndev[id].index == 0) + return -ENODEV; + + cam->ccd.array_area.ul.x = knowndev[id].array_area.ul.x; + cam->ccd.array_area.ul.y = knowndev[id].array_area.ul.y; + cam->ccd.array_area.lr.x = knowndev[id].array_area.lr.x; + cam->ccd.array_area.lr.y = knowndev[id].array_area.lr.y; + cam->ccd.visible_area.ul.x = knowndev[id].visible_area.ul.x; + cam->ccd.visible_area.ul.y = knowndev[id].visible_area.ul.y; + cam->ccd.visible_area.lr.x = knowndev[id].visible_area.lr.x; + cam->ccd.visible_area.lr.y = knowndev[id].visible_area.lr.y; + cam->ccd.pixelwidth = knowndev[id].pixelwidth; + cam->ccd.pixelheight = knowndev[id].pixelheight; + + if ((DEVICE->devinfo.model = + (char *)xmalloc(strlen(knowndev[id].model) + 1)) == NULL) + return -ENOMEM; + strcpy(DEVICE->devinfo.model, knowndev[id].model); + + debug(FLIDEBUG_INFO, " Name: %s", DEVICE->devinfo.devnam); + debug(FLIDEBUG_INFO, " Array: (%4d,%4d),(%4d,%4d)", + cam->ccd.array_area.ul.x, + cam->ccd.array_area.ul.y, + cam->ccd.array_area.lr.x, + cam->ccd.array_area.lr.y); + debug(FLIDEBUG_INFO, " Visible: (%4d,%4d),(%4d,%4d)", + cam->ccd.visible_area.ul.x, + cam->ccd.visible_area.ul.y, + cam->ccd.visible_area.lr.x, + cam->ccd.visible_area.lr.y); + + rlen = 2; wlen = 2; + buf = htons(C_ADDRESS(1, EPARAM_SNHIGH)); + IO(dev, &buf, &wlen, &rlen); + DEVICE->devinfo.serno = (ntohs(buf) & 0x00ff) << 8; + + rlen = 2; wlen = 2; + buf = htons(C_ADDRESS(1, EPARAM_SNLOW)); + IO(dev, &buf, &wlen, &rlen); + DEVICE->devinfo.serno |= (ntohs(buf) & 0x00ff); + + rlen = 2; wlen = 2; + buf = htons(C_ADDRESS(1, EPARAM_FIRM)); + IO(dev, &buf, &wlen, &rlen); + DEVICE->devinfo.fwrev = (ntohs(buf) & 0x00ff); + + /* Initialize all varaibles to something */ + switch(DEVICE->devinfo.hwrev) + { + case 0x01: + cam->tempslope = (100.0 / 201.1); + cam->tempintercept = (-61.613); + break; + + case 0x02: + cam->tempslope = (70.0 / 215.75); + cam->tempintercept = (-52.5681); + break; + + default: + debug(FLIDEBUG_WARN, "Could not set temperature parameters."); + break; + } + + cam->vflushbin = 4; + cam->hflushbin = 4; + cam->vbin = 1; + cam->hbin = 1; + cam->image_area.ul.x = cam->ccd.visible_area.ul.x; + cam->image_area.ul.y = cam->ccd.visible_area.ul.y; + cam->image_area.lr.x = cam->ccd.visible_area.lr.x; + cam->image_area.lr.y = cam->ccd.visible_area.lr.y; + cam->exposure = 100; + cam->frametype = FLI_FRAME_TYPE_NORMAL; + cam->flushes = 0; + cam->bitdepth = FLI_MODE_16BIT; + cam->exttrigger = 0; + + cam->grabrowwidth = + (cam->image_area.lr.x - cam->image_area.ul.x) / cam->hbin; + cam->grabrowcount = 1; + cam->grabrowcounttot = cam->grabrowcount; + cam->grabrowindex = 0; + cam->grabrowbatchsize = 1; + cam->grabrowbufferindex = cam->grabrowcount; + cam->flushcountbeforefirstrow = 0; + cam->flushcountafterlastrow = 0; + + return 0; +} + +long fli_camera_parport_get_array_area(flidev_t dev, long *ul_x, long *ul_y, + long *lr_x, long *lr_y) +{ + flicamdata_t *cam; + + cam = DEVICE->device_data; + + *ul_x = cam->ccd.array_area.ul.x; + *ul_y = cam->ccd.array_area.ul.y; + *lr_x = cam->ccd.array_area.lr.x; + *lr_y = cam->ccd.array_area.lr.y; + + return 0; +} + +long fli_camera_parport_get_visible_area(flidev_t dev, long *ul_x, long *ul_y, + long *lr_x, long *lr_y) +{ + flicamdata_t *cam; + + cam = DEVICE->device_data; + + *ul_x = cam->ccd.visible_area.ul.x; + *ul_y = cam->ccd.visible_area.ul.y; + *lr_x = cam->ccd.visible_area.lr.x; + *lr_y = cam->ccd.visible_area.lr.y; + + return 0; +} + +long fli_camera_parport_set_exposure_time(flidev_t dev, long exptime) +{ + flicamdata_t *cam; + + cam = DEVICE->device_data; + + if (exptime < 0) + return -EINVAL; + + cam->exposure = exptime; + + if (exptime <= 15000) /* Less than thirty seconds..., 8.192e-3 sec */ + { + cam->expdur = 1; + cam->expmul = (long) (((double) exptime) / 8.192); + } + else if (exptime <= 2000000) /* Less than one hour */ + { + cam->expdur = (long) (1.0 / 8.192e-3); + cam->expmul = (long) (exptime / 1000); + } + else + { + cam->expdur = (long) (10.0 / 8.192e-3); + cam->expmul = (long) (exptime / 10000); + } + + return 0; +} + +long fli_camera_parport_set_image_area(flidev_t dev, long ul_x, long ul_y, + long lr_x, long lr_y) +{ + flicamdata_t *cam; + + cam = DEVICE->device_data; + + if ((ul_x < cam->ccd.visible_area.ul.x) || + (ul_y < cam->ccd.visible_area.ul.y) || + (lr_x > cam->ccd.visible_area.lr.x) || + (lr_y > cam->ccd.visible_area.lr.y)) + return -EINVAL; + + cam->image_area.ul.x = ul_x; + cam->image_area.ul.y = ul_y; + cam->image_area.lr.x = lr_x; + cam->image_area.lr.y = lr_y; + + return 0; +} + +long fli_camera_parport_set_hbin(flidev_t dev, long hbin) +{ + flicamdata_t *cam; + + cam = DEVICE->device_data; + + if ((hbin < 1) || (hbin > 16)) + return -EINVAL; + + cam->hbin = hbin; + return 0; +} + +long fli_camera_parport_set_vbin(flidev_t dev, long vbin) +{ + flicamdata_t *cam; + + cam = DEVICE->device_data; + + if ((vbin < 1) || (vbin > 16)) + return -EINVAL; + + cam->vbin = vbin; + return 0; +} + +long fli_camera_parport_get_exposure_status(flidev_t dev, long *timeleft) +{ + flicamdata_t *cam; + long rlen, wlen; + unsigned short buf; + + cam = DEVICE->device_data; + + rlen = 2; wlen = 2; + buf = htons(C_SHUTTER(1,0)); + IO(dev, &buf, &wlen, &rlen); + if ((ntohs(buf) & 0xf000) != C_SHUTTER(0,0)) + { + debug(FLIDEBUG_FAIL, "(exposurestatus) echo back from camera failed."); + return -EIO; + } + + *timeleft = (long)((double)(ntohs(buf) & 0x07ff) * + ((double)cam->expdur * 8.192)); + + return 0; +} + +long fli_camera_parport_set_temperature(flidev_t dev, double temperature) +{ + flicamdata_t *cam; + long rlen, wlen; + unsigned short buf; + + cam = DEVICE->device_data; + + rlen = 2; wlen = 2; + buf = (unsigned short)((temperature - cam->tempintercept) / + cam->tempslope); + buf = htons((unsigned short) C_TEMP(buf)); + IO(dev, &buf, &wlen, &rlen); + if ((ntohs(buf) & 0xf000) != C_TEMP(0)) + { + debug(FLIDEBUG_FAIL, "(settemperature) echo back from camera failed."); + return -EIO; + } + + return 0; +} + +long fli_camera_parport_get_temperature(flidev_t dev, double *temperature) +{ + flicamdata_t *cam; + long rlen, wlen; + unsigned short buf; + + cam = DEVICE->device_data; + + rlen = 2; wlen = 2; + buf = htons(C_TEMP(0x0800)); + IO(dev, &buf, &wlen, &rlen); + if ((ntohs(buf) & 0xf000) != C_TEMP(0)) + { + debug(FLIDEBUG_FAIL, "(settemperature) echo back from camera failed."); + return -EIO; + } + *temperature = cam->tempslope * (double)(ntohs(buf) & 0x00ff) + + cam->tempintercept; + + return 0; +} + +long fli_camera_parport_grab_row(flidev_t dev, void *buff, size_t width) +{ + flicamdata_t *cam; + long r; + double dTm; + long rlen, wlen; + unsigned short buf; + + cam = DEVICE->device_data; + + if (cam->flushcountbeforefirstrow > 0) + { + if ((r = fli_camera_parport_flush_rows(dev, + cam->flushcountbeforefirstrow, 1))) + return r; + + cam->flushcountbeforefirstrow = 0; + } + + dTm = (25.0e-6) * cam->ccd.array_area.lr.x + 1e-3; + dTm = dTm / 1e-6; + cam->readto = (long)dTm; + cam->writeto = (long)dTm; + + rlen = 0; wlen = 2; + buf = htons((unsigned short) C_SEND(cam->grabrowwidth)); + IO(dev, &buf, &wlen, &rlen); + + if (cam->bitdepth == FLI_MODE_8BIT) + { + unsigned char *cbuf; + int x; + + if ((cbuf = xmalloc(cam->grabrowwidth)) == NULL) + { + debug(FLIDEBUG_FAIL, "Failed memory allocation during row grab."); + return -ENOMEM; + } + + rlen = cam->grabrowwidth; wlen = 0; + r = DEVICE->fli_io(dev, cbuf, &wlen, &rlen); + if (r != 0) + { + debug(FLIDEBUG_WARN, "Couldn't grab entire row, got %d of %d bytes.", + rlen, cam->grabrowwidth); + } + for (x = 0; x < (int)width; x++) + { + ((char *)buff)[x] = (((cbuf[x]) + 128) & 0x00ff); + } + xfree(cbuf); + } + else + { + unsigned short *sbuf; + int x; + + if ((sbuf = xmalloc(cam->grabrowwidth * sizeof(unsigned short))) == NULL) + { + debug(FLIDEBUG_FAIL, "Failed memory allocation during row grab."); + return -ENOMEM; + } + + rlen = cam->grabrowwidth * sizeof(unsigned short); wlen = 0; + r = DEVICE->fli_io(dev, sbuf, &wlen, &rlen); + if (r != 0) + { + debug(FLIDEBUG_WARN, "Couldn't grab entire row, got %d of %d bytes.", + rlen, cam->grabrowwidth); + } + for (x = 0; x < (int)width; x++) + { + if (DEVICE->devinfo.hwrev == 0x01) /* IMG camera */ + { + ((unsigned short *)buff)[x] = ntohs(sbuf[x]) + 32768; + } + else + { + ((unsigned short *)buff)[x] = ntohs(sbuf[x]); + } + } + xfree(sbuf); + } + + rlen = 2; wlen = 0; + IO(dev, &buf, &wlen, &rlen); + if (ntohs(buf) != C_SEND(width)) + { + debug(FLIDEBUG_WARN, "Width: %d, requested %d.", + width, cam->grabrowwidth * sizeof(unsigned short)); + debug(FLIDEBUG_WARN, "Got 0x%04x instead of 0x%04x.", ntohs(buf), C_SEND(width)); + debug(FLIDEBUG_WARN, "Didn't get command echo at end of row."); + } + + if (cam->grabrowcount > 0) + { + cam->grabrowcount--; + if (cam->grabrowcount == 0) + { + if ((r = fli_camera_parport_flush_rows(dev, + cam->flushcountafterlastrow, 1))) + return r; + + cam->flushcountafterlastrow = 0; + cam->grabrowbatchsize = 1; + } + } + + cam->readto = 1000; + cam->writeto = 1000; + + return 0; +} + +long fli_camera_parport_expose_frame(flidev_t dev) +{ + flicamdata_t *cam; + long rlen, wlen; + unsigned short buf; + + cam = DEVICE->device_data; + + debug(FLIDEBUG_INFO, "Setting X Row Offset."); + rlen = 2; wlen = 2; + buf = htons((unsigned short) D_XROWOFF(cam->image_area.ul.x)); + IO(dev, &buf, &wlen, &rlen); + + debug(FLIDEBUG_INFO, "Setting X Row Width to %d.", cam->ccd.array_area.lr.x - cam->ccd.array_area.ul.x); + buf = htons((unsigned short) D_XROWWID(cam->ccd.array_area.lr.x - cam->ccd.array_area.ul.x)); + IO(dev, &buf, &wlen, &rlen); + + debug(FLIDEBUG_INFO, "Setting X Flush Bin."); + buf = htons((unsigned short) D_XFLBIN(cam->hflushbin)); + IO(dev, &buf, &wlen, &rlen); + + debug(FLIDEBUG_INFO, "Setting Y Flush Bin."); + buf = htons((unsigned short) D_YFLBIN(cam->vflushbin)); + IO(dev, &buf, &wlen, &rlen); + + debug(FLIDEBUG_INFO, "Setting X Bin."); + buf = htons((unsigned short) D_XBIN(cam->hbin)); + IO(dev, &buf, &wlen, &rlen); + + debug(FLIDEBUG_INFO, "Setting Y Bin."); + buf = htons((unsigned short) D_YBIN(cam->vbin)); + IO(dev, &buf, &wlen, &rlen); + + debug(FLIDEBUG_INFO, "Setting Exposure Duration."); + buf = htons((unsigned short) D_EXPDUR(cam->expdur)); + IO(dev, &buf, &wlen, &rlen); + + if (cam->bitdepth == FLI_MODE_8BIT) + { + debug(FLIDEBUG_INFO, "Eight Bit."); + buf = htons((unsigned short)((cam->exttrigger > 0) ? + C_RESTCFG(0,0,1,7) : C_RESTCFG(0,0,0,7))); + } + else + { + debug(FLIDEBUG_INFO, "Sixteen Bit."); + buf = htons((unsigned short)((cam->exttrigger > 0) ? + C_RESTCFG(0,0,1,15) : + C_RESTCFG(0,0,0,15))); + } + IO(dev, &buf, &wlen, &rlen); + + if (cam->flushes > 0) + { + int r; + + debug(FLIDEBUG_INFO, "Flushing array."); + if ((r = fli_camera_parport_flush_rows(dev, + cam->ccd.array_area.lr.y - cam->ccd.array_area.ul.y, + cam->flushes))) + return r; + } + + debug(FLIDEBUG_INFO, "Exposing."); + buf = htons((unsigned short) C_SHUTTER((cam->frametype == FLI_FRAME_TYPE_DARK)?0:1, + cam->expmul)); + IO(dev, &buf, &wlen, &rlen); + + cam->grabrowwidth = cam->image_area.lr.x - cam->image_area.ul.x; + cam->flushcountbeforefirstrow = cam->image_area.ul.y; + cam->flushcountafterlastrow = + (cam->ccd.array_area.lr.y - cam->ccd.array_area.ul.y) - + ((cam->image_area.lr.y - cam->image_area.ul.y) * cam->vbin) - + cam->image_area.ul.y; + + if (cam->flushcountafterlastrow < 0) + cam->flushcountafterlastrow = 0; + + cam->grabrowcount = cam->image_area.lr.y - cam->image_area.ul.y; + + return 0; +} + +long fli_camera_parport_flush_rows(flidev_t dev, long rows, long repeat) +{ + flicamdata_t *cam; + double dTm; + long rlen, wlen; + unsigned short buf; + + if (rows < 0) + return -EINVAL; + + if (rows == 0) + return 0; + + cam = DEVICE->device_data; + + dTm = ((25e-6) / (cam->hflushbin / 2)) * cam->ccd.array_area.lr.x + 1e-3; + dTm = dTm * rows; + dTm = dTm / 1e-6; + cam->readto = (long)dTm; + cam->writeto = (long)dTm; + + while (repeat>0) + { + long retval; + + rlen = 2; wlen = 2; + buf = htons((unsigned short) C_FLUSH(rows)); + retval = DEVICE->fli_io(dev, &buf, &wlen, &rlen); + if (retval != 0) + { + cam->readto = 1000; + cam->writeto = 1000; + return retval; + } + repeat--; + } + + return 0; +} + +long fli_camera_parport_set_bit_depth(flidev_t dev, flibitdepth_t bitdepth) +{ + flicamdata_t *cam; + + cam = DEVICE->device_data; + + if (DEVICE->devinfo.type != 0x01) /* IMG cameras only support this */ + return -EINVAL; + + if ((bitdepth != FLI_MODE_8BIT) && (bitdepth != FLI_MODE_16BIT)) + { + debug(FLIDEBUG_FAIL, "Invalid bit depth setting."); + return -EINVAL; + } + + cam->bitdepth = bitdepth; + + return 0; +} + +static void correctioportdatawrite(flidev_t dev, unsigned short *Data) +{ + unsigned short data; + + data = 0; + + switch(DEVICE->devinfo.hwrev) + { + case 0x01: + data |= (*Data & FLICCD_IO_P0)?0x01:0; + data |= (*Data & FLICCD_IO_P1)?0x02:0; + data |= (*Data & FLICCD_IO_P2)?0x04:0; + data |= (*Data & FLICCD_IO_P3)?0x80:0; + break; + + case 0x02: + data |= (*Data & FLICCD_IO_P0)?0x08:0; + data |= (*Data & FLICCD_IO_P1)?0x10:0; + data |= (*Data & FLICCD_IO_P2)?0x20:0; + data |= (*Data & FLICCD_IO_P3)?0x40:0; + break; + + default: + break; + } + + *Data = data; + + return; +} + +static void correctioportdataread(flidev_t dev, unsigned short *Data) +{ + unsigned short data; + + data = 0; + + switch (DEVICE->devinfo.hwrev) + { + case 0x01: + data |= (*Data & 0x01)?FLICCD_IO_P0:0; + data |= (*Data & 0x02)?FLICCD_IO_P1:0; + data |= (*Data & 0x04)?FLICCD_IO_P2:0; + data |= (*Data & 0x80)?FLICCD_IO_P3:0; + break; + + case 0x02: + data |= (*Data & 0x08)?FLICCD_IO_P0:0; + data |= (*Data & 0x10)?FLICCD_IO_P1:0; + data |= (*Data & 0x20)?FLICCD_IO_P2:0; + data |= (*Data & 0x40)?FLICCD_IO_P3:0; + break; + + default: + break; + } + + *Data = data; + + return; +} + +long fli_camera_parport_read_ioport(flidev_t dev, long *ioportset) +{ + long rlen, wlen; + unsigned short buf; + + rlen = 2; wlen = 2; + buf = htons(0x7900); + IO(dev, &buf, &wlen, &rlen); + + *ioportset = ntohs(buf) & 0x00ff; + correctioportdataread(dev, (unsigned short *) ioportset); + + return 0; +} + +long fli_camera_parport_write_ioport(flidev_t dev, long ioportset) +{ + long rlen, wlen; + unsigned short buf = (unsigned short) ioportset; + + correctioportdatawrite(dev, &buf); + buf = htons((unsigned short) (0x7100 | (buf & 0x00ff))); + + rlen = 2; wlen = 2; + IO(dev, &buf, &wlen, &rlen); + + return 0; +} + +long fli_camera_parport_configure_ioport(flidev_t dev, long ioportset) +{ + long rlen, wlen; + unsigned short buf = (unsigned short) ioportset; + + correctioportdatawrite(dev, &buf); + buf = htons((unsigned short) (0x7000 | (buf & 0x00ff))); + + rlen = 2; wlen = 2; + IO(dev, &buf, &wlen, &rlen); + + return 0; +} + +long fli_camera_parport_control_shutter(flidev_t dev, long shutter) +{ + long rlen, wlen; + unsigned short buf; + + rlen = 2; wlen = 2; + buf = htons(D_EXPDUR(0)); + IO(dev, &buf, &wlen, &rlen); + + switch (shutter) + { + case FLI_SHUTTER_CLOSE: + debug(FLIDEBUG_INFO, "Closing shutter."); + buf = htons(C_SHUTTER(0, 0)); + IO(dev, &buf, &wlen, &rlen); + break; + + case FLI_SHUTTER_OPEN: + buf = htons(C_SHUTTER(1, 1)); + IO(dev, &buf, &wlen, &rlen); + break; + + default: + return -EINVAL; + } + + return 0; +} |