mirror of
https://github.com/netfun2000/lcd4linux.git
synced 2026-02-27 09:44:34 +08:00
git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@1199 3ae390bd-cb1e-0410-b409-cd5a39f66f1f
727 lines
18 KiB
C
727 lines
18 KiB
C
/* $Id: drv_dpf.c 980 2009-01-28 21:18:52Z michux $
|
|
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_dpf.c $
|
|
*
|
|
* Driver for hacked digital picture frames. Uses *NO* external libraries.
|
|
* See http://dpf-ax.sourceforge.net/ for more information.
|
|
*
|
|
* Copyright (C) 2008 Jeroen Domburg <picframe@spritesmods.com>
|
|
* Modified from sample code by:
|
|
* Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
|
|
* Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
|
|
*
|
|
* Mods by <hackfin@section5.ch>
|
|
* Complete rewrite 05/2013 by superelchi <superelchi AT wolke7.net>
|
|
*
|
|
*
|
|
* This file is part of LCD4Linux.
|
|
*
|
|
* LCD4Linux is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* LCD4Linux is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* exported fuctions:
|
|
*
|
|
* struct DRIVER drv_DPF
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "debug.h"
|
|
#include "cfg.h"
|
|
#include "qprintf.h"
|
|
#include "udelay.h"
|
|
#include "plugin.h"
|
|
#include "widget.h"
|
|
#include "widget_text.h"
|
|
#include "widget_icon.h"
|
|
#include "widget_bar.h"
|
|
#include "drv.h"
|
|
|
|
#include "drv_generic_graphic.h"
|
|
|
|
//###################################################################
|
|
// Start dpfcore4driver.h
|
|
// See http://dpf-ax.sourceforge.net/
|
|
//###################################################################
|
|
|
|
#define DPFAXHANDLE void * // Handle needed for dpf_ax access
|
|
#define DPF_BPP 2 //bpp for dfp-ax is currently always 2!
|
|
|
|
/**
|
|
* Open DPF device.
|
|
*
|
|
* Device must be string in the form "usbX" or "dpfX", with X = 0 .. number of connected dpfs.
|
|
* The open function will scan the USB bus and return a handle to access dpf #X.
|
|
* If dpf #X is not found, returns NULL.
|
|
*
|
|
* \param dev device name to open
|
|
* \return device handle or NULL
|
|
*/
|
|
DPFAXHANDLE dpf_ax_open(const char *device);
|
|
|
|
/**
|
|
* Close DPF device.
|
|
*/
|
|
void dpf_ax_close(DPFAXHANDLE h);
|
|
|
|
/** Blit data to screen.
|
|
*
|
|
* \param buf buffer to 16 bpp RGB 565 image data
|
|
* \param rect rectangle tuple: [x0, y0, x1, y1]
|
|
*/
|
|
void dpf_ax_screen_blit(DPFAXHANDLE h, const unsigned char *buf, short rect[4]);
|
|
|
|
/** Set backlight brightness.
|
|
*
|
|
* \param value Backlight value 0..7 (0 = off, 7 = max brightness)
|
|
*/
|
|
void dpf_ax_setbacklight(DPFAXHANDLE h, int value);
|
|
|
|
/** Get screen width.
|
|
*
|
|
* \return width in pixel
|
|
*/
|
|
int dpf_ax_getwidth(DPFAXHANDLE h);
|
|
|
|
/** Get screen height.
|
|
*
|
|
* \return height in pixel
|
|
*/
|
|
int dpf_ax_getheight(DPFAXHANDLE h);
|
|
|
|
//###################################################################
|
|
// End dpfcore4driver.h
|
|
//###################################################################
|
|
|
|
|
|
static char Name[] = "DPF";
|
|
|
|
|
|
/*
|
|
* Dpf status
|
|
*/
|
|
static struct {
|
|
unsigned char *lcdBuf; // Display data buffer
|
|
unsigned char *xferBuf; // USB transfer buffer
|
|
DPFAXHANDLE dpfh; // Handle for dpf access
|
|
int pwidth; // Physical display width
|
|
int pheight; // Physical display height
|
|
|
|
// Flags to translate logical to physical orientation
|
|
int isPortrait;
|
|
int rotate90;
|
|
int flip;
|
|
|
|
// Current dirty rectangle
|
|
int minx, maxx;
|
|
int miny, maxy;
|
|
|
|
// Config properties
|
|
int orientation;
|
|
int backlight;
|
|
} dpf;
|
|
|
|
|
|
// Convert RGBA pixel to RGB565 pixel(s)
|
|
|
|
#define _RGB565_0(p) (( ((p.R) & 0xf8) ) | (((p.G) & 0xe0) >> 5))
|
|
#define _RGB565_1(p) (( ((p.G) & 0x1c) << 3 ) | (((p.B) & 0xf8) >> 3))
|
|
|
|
/*
|
|
* Set one pixel in lcdBuf.
|
|
*
|
|
* Respects orientation and updates dirty rectangle.
|
|
*
|
|
* in: x, y - pixel coordinates
|
|
* pix - RGBA pixel value
|
|
* out: -
|
|
*/
|
|
static void drv_set_pixel(int x, int y, RGBA pix)
|
|
{
|
|
int changed = 0;
|
|
|
|
int sx = DCOLS;
|
|
int sy = DROWS;
|
|
int lx = x % sx;
|
|
int ly = y % sy;
|
|
|
|
if (dpf.flip) {
|
|
// upside down orientation
|
|
lx = DCOLS - 1 - lx;
|
|
ly = DROWS - 1 - ly;
|
|
}
|
|
|
|
if (dpf.rotate90) {
|
|
// wrong Orientation, rotate
|
|
int i = ly;
|
|
ly = dpf.pheight - 1 - lx;
|
|
lx = i;
|
|
}
|
|
|
|
if (lx < 0 || lx >= (int) dpf.pwidth || ly < 0 || ly >= (int) dpf.pheight) {
|
|
error("dpf: x/y out of bounds (x=%d, y=%d, rot=%d, flip=%d, lx=%d, ly=%d)\n", x, y, dpf.rotate90, dpf.flip, lx,
|
|
ly);
|
|
return;
|
|
}
|
|
|
|
unsigned char c1 = _RGB565_0(pix);
|
|
unsigned char c2 = _RGB565_1(pix);
|
|
unsigned int i = (ly * dpf.pwidth + lx) * DPF_BPP;
|
|
if (dpf.lcdBuf[i] != c1 || dpf.lcdBuf[i + 1] != c2) {
|
|
dpf.lcdBuf[i] = c1;
|
|
dpf.lcdBuf[i + 1] = c2;
|
|
changed = 1;
|
|
}
|
|
|
|
if (changed) {
|
|
if (lx < dpf.minx)
|
|
dpf.minx = lx;
|
|
if (lx > dpf.maxx)
|
|
dpf.maxx = lx;
|
|
if (ly < dpf.miny)
|
|
dpf.miny = ly;
|
|
if (ly > dpf.maxy)
|
|
dpf.maxy = ly;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send pixel data to dpf
|
|
*/
|
|
static void drv_dpf_blit(const int row, const int col, const int height, const int width)
|
|
{
|
|
int x, y;
|
|
|
|
// Set pixels one by one
|
|
// Note: here is room for optimization :-)
|
|
for (y = row; y < row + height; y++)
|
|
for (x = col; x < col + width; x++)
|
|
drv_set_pixel(x, y, drv_generic_graphic_rgb(y, x));
|
|
|
|
// If nothing has changed, skip transfer
|
|
if (dpf.minx > dpf.maxx || dpf.miny > dpf.maxy)
|
|
return;
|
|
|
|
// Copy data in dirty rectangle from data buffer to temp transfer buffer
|
|
unsigned int cpylength = (dpf.maxx - dpf.minx + 1) * DPF_BPP;
|
|
unsigned char *ps = dpf.lcdBuf + (dpf.miny * dpf.pwidth + dpf.minx) * DPF_BPP;
|
|
unsigned char *pd = dpf.xferBuf;
|
|
for (y = dpf.miny; y <= dpf.maxy; y++) {
|
|
memcpy(pd, ps, cpylength);
|
|
ps += dpf.pwidth * DPF_BPP;
|
|
pd += cpylength;
|
|
}
|
|
|
|
// Send the buffer
|
|
short rect[4];
|
|
rect[0] = dpf.minx;
|
|
rect[1] = dpf.miny;
|
|
rect[2] = dpf.maxx + 1;
|
|
rect[3] = dpf.maxy + 1;
|
|
dpf_ax_screen_blit(dpf.dpfh, dpf.xferBuf, rect);
|
|
|
|
// Reset dirty rectangle
|
|
dpf.minx = dpf.pwidth - 1;
|
|
dpf.maxx = 0;
|
|
dpf.miny = dpf.pheight - 1;
|
|
dpf.maxy = 0;
|
|
}
|
|
|
|
|
|
/* start graphic display */
|
|
static int drv_dpf_start(const char *section)
|
|
{
|
|
int i;
|
|
char *dev;
|
|
char *s;
|
|
|
|
// Check if config is valid
|
|
|
|
// Get the device
|
|
dev = cfg_get(section, "Port", NULL);
|
|
if (dev == NULL || *dev == '\0') {
|
|
error("dpf: no '%s.Port' entry from %s", section, cfg_source());
|
|
return -1;
|
|
}
|
|
// Get font
|
|
s = cfg_get(section, "Font", "6x8");
|
|
if (s == NULL || *s == '\0') {
|
|
error("%s: no '%s.Font' entry from %s", Name, section, cfg_source());
|
|
return -1;
|
|
}
|
|
|
|
XRES = -1;
|
|
YRES = -1;
|
|
if (sscanf(s, "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) {
|
|
error("%s: bad Font '%s' from %s", Name, s, cfg_source());
|
|
return -1;
|
|
}
|
|
|
|
/* we dont want fonts below 6 width */
|
|
if (XRES < 6) {
|
|
error("%s: bad Font '%s' width '%d' using minimum of 6)", Name, s, XRES);
|
|
XRES = 6;
|
|
}
|
|
|
|
/* we dont want fonts below 8 height */
|
|
if (YRES < 8) {
|
|
error("%s: bad Font '%s' height '%d' using minimum of 8)", Name, s, YRES);
|
|
YRES = 8;
|
|
}
|
|
// Get the logical orientation (0 = landscape, 1 = portrait, 2 = reverse landscape, 3 = reverse portrait)
|
|
if (cfg_number(section, "Orientation", 0, 0, 3, &i) > 0)
|
|
dpf.orientation = i;
|
|
else
|
|
dpf.orientation = 0;
|
|
|
|
// Get the backlight value (0 = off, 7 = max brightness)
|
|
if (cfg_number(section, "Backlight", 0, 0, 7, &i) > 0)
|
|
dpf.backlight = i;
|
|
else
|
|
dpf.backlight = 7;
|
|
|
|
/* open communication with the display */
|
|
dpf.dpfh = dpf_ax_open(dev);
|
|
if (dpf.dpfh == NULL) {
|
|
error("dpf: cannot open dpf device %s", dev);
|
|
return -1;
|
|
}
|
|
// Get dpfs physical dimensions
|
|
dpf.pwidth = dpf_ax_getwidth(dpf.dpfh);
|
|
dpf.pheight = dpf_ax_getheight(dpf.dpfh);
|
|
|
|
|
|
// See, if we have to rotate the display
|
|
dpf.isPortrait = dpf.pwidth < dpf.pheight;
|
|
if (dpf.isPortrait) {
|
|
if (dpf.orientation == 0 || dpf.orientation == 2)
|
|
dpf.rotate90 = 1;
|
|
} else if (dpf.orientation == 1 || dpf.orientation == 3)
|
|
dpf.rotate90 = 1;
|
|
dpf.flip = (!dpf.isPortrait && dpf.rotate90); // adjust to make rotate por/land = physical por/land
|
|
if (dpf.orientation > 1)
|
|
dpf.flip = !dpf.flip;
|
|
|
|
// allocate display buffer + temp transfer buffer
|
|
dpf.lcdBuf = malloc(dpf.pwidth * dpf.pheight * DPF_BPP);
|
|
dpf.xferBuf = malloc(dpf.pwidth * dpf.pheight * DPF_BPP);
|
|
|
|
// clear display buffer + set it to "dirty"
|
|
memset(dpf.lcdBuf, 0, dpf.pwidth * dpf.pheight * DPF_BPP); //Black
|
|
dpf.minx = 0;
|
|
dpf.maxx = dpf.pwidth - 1;
|
|
dpf.miny = 0;
|
|
dpf.maxy = dpf.pheight - 1;
|
|
|
|
// set the logical width/height for lcd4linux
|
|
DCOLS = ((!dpf.rotate90) ? dpf.pwidth : dpf.pheight);
|
|
DROWS = ((!dpf.rotate90) ? dpf.pheight : dpf.pwidth);
|
|
|
|
// Set backlight (brightness)
|
|
dpf_ax_setbacklight(dpf.dpfh, dpf.backlight);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/****************************************/
|
|
/*** plugins ***/
|
|
/****************************************/
|
|
|
|
static void plugin_backlight(RESULT * result, RESULT * arg1)
|
|
{
|
|
int b = R2N(arg1);
|
|
if (b < 0)
|
|
b = 0;
|
|
if (b > 7)
|
|
b = 7;
|
|
|
|
dpf_ax_setbacklight(dpf.dpfh, b);
|
|
SetResult(&result, R_NUMBER, &b);
|
|
}
|
|
|
|
|
|
/****************************************/
|
|
/*** exported functions ***/
|
|
/****************************************/
|
|
|
|
|
|
/* list models */
|
|
int drv_dpf_list(void)
|
|
{
|
|
printf("Hacked dpf-ax digital photo frame");
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* initialize driver & display */
|
|
int drv_dpf_init(const char *section, const int quiet)
|
|
{
|
|
int ret;
|
|
|
|
/* real worker functions */
|
|
drv_generic_graphic_real_blit = drv_dpf_blit;
|
|
|
|
/* start display */
|
|
if ((ret = drv_dpf_start(section)) != 0)
|
|
return ret;
|
|
|
|
/* initialize generic graphic driver */
|
|
if ((ret = drv_generic_graphic_init(section, Name)) != 0)
|
|
return ret;
|
|
|
|
if (!quiet) {
|
|
char buffer[40];
|
|
qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
|
|
if (drv_generic_graphic_greet(buffer, NULL)) {
|
|
sleep(3);
|
|
drv_generic_graphic_clear();
|
|
}
|
|
}
|
|
|
|
/* register plugins */
|
|
AddFunction("LCD::backlight", 1, plugin_backlight);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* close driver & display */
|
|
int drv_dpf_quit(const int quiet)
|
|
{
|
|
info("%s: shutting down.", Name);
|
|
|
|
/* clear display */
|
|
drv_generic_graphic_clear();
|
|
|
|
/* say goodbye... */
|
|
if (!quiet) {
|
|
drv_generic_graphic_greet("goodbye!", NULL);
|
|
}
|
|
|
|
drv_generic_graphic_quit();
|
|
|
|
debug("closing connection");
|
|
dpf_ax_close(dpf.dpfh);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
DRIVER drv_DPF = {
|
|
.name = Name,
|
|
.list = drv_dpf_list,
|
|
.init = drv_dpf_init,
|
|
.quit = drv_dpf_quit,
|
|
};
|
|
|
|
//###################################################################
|
|
// Start dpfcore4driver.c
|
|
// See http://dpf-ax.sourceforge.net/
|
|
//###################################################################
|
|
|
|
#include <usb.h>
|
|
|
|
#define AX206_VID 0x1908 // Hacked frames USB Vendor ID
|
|
#define AX206_PID 0x0102 // Hacked frames USB Product ID
|
|
|
|
#define USBCMD_SETPROPERTY 0x01 // USB command: Set property
|
|
#define USBCMD_BLIT 0x12 // USB command: Blit to screen
|
|
|
|
/* Generic SCSI device stuff */
|
|
|
|
#define DIR_IN 0
|
|
#define DIR_OUT 1
|
|
|
|
/* The DPF context structure */
|
|
typedef
|
|
struct dpf_context {
|
|
usb_dev_handle *udev;
|
|
unsigned int width;
|
|
unsigned int height;
|
|
} DPFContext;
|
|
|
|
static int wrap_scsi(DPFContext * h, unsigned char *cmd, int cmdlen, char out,
|
|
unsigned char *data, unsigned long block_len);
|
|
|
|
/**
|
|
* Open DPF device.
|
|
*
|
|
* Device must be string in the form "usbX" or "dpfX", with X = 0 .. number of connected dpfs.
|
|
* The open function will scan the USB bus and return a handle to access dpf #X.
|
|
* If dpf #X is not found, returns NULL.
|
|
*
|
|
* \param dev device name to open
|
|
* \return device handle or NULL
|
|
*/
|
|
DPFAXHANDLE dpf_ax_open(const char *dev)
|
|
{
|
|
DPFContext *dpf;
|
|
int index = -1;
|
|
usb_dev_handle *u;
|
|
|
|
if (dev && strlen(dev) == 4 && (strncmp(dev, "usb", 3) == 0 || strncmp(dev, "dpf", 3) == 0))
|
|
index = dev[3] - '0';
|
|
|
|
if (index < 0 || index > 9) {
|
|
fprintf(stderr, "dpf_ax_open: wrong device '%s'. Please specify a string like 'usb0'\n", dev);
|
|
return NULL;
|
|
}
|
|
|
|
usb_init();
|
|
usb_find_busses();
|
|
usb_find_devices();
|
|
|
|
struct usb_bus *b = usb_get_busses();
|
|
struct usb_device *d = NULL;
|
|
int enumeration = 0;
|
|
int found = 0;
|
|
|
|
while (b && !found) {
|
|
d = b->devices;
|
|
while (d) {
|
|
if ((d->descriptor.idVendor == AX206_VID) && (d->descriptor.idProduct == AX206_PID)) {
|
|
fprintf(stderr, "dpf_ax_open: found AX206 #%d\n", enumeration + 1);
|
|
if (enumeration == index) {
|
|
found = 1;
|
|
break;
|
|
} else
|
|
enumeration++;
|
|
}
|
|
d = d->next;
|
|
}
|
|
b = b->next;
|
|
}
|
|
|
|
if (!d) {
|
|
fprintf(stderr, "dpf_ax_open: no matching USB device '%s' found!\n", dev);
|
|
return NULL;
|
|
}
|
|
|
|
dpf = (DPFContext *) malloc(sizeof(DPFContext));
|
|
if (!dpf) {
|
|
fprintf(stderr, "dpf_ax_open: error allocation memory.\n");
|
|
return NULL;
|
|
}
|
|
|
|
u = usb_open(d);
|
|
if (u == NULL) {
|
|
fprintf(stderr, "dpf_ax_open: failed to open usb device '%s'!\n", dev);
|
|
free(dpf);
|
|
return NULL;
|
|
}
|
|
|
|
if (usb_claim_interface(u, 0) < 0) {
|
|
fprintf(stderr, "dpf_ax_open: failed to claim usb device!\n");
|
|
usb_close(u);
|
|
free(dpf);
|
|
return NULL;
|
|
}
|
|
|
|
dpf->udev = u;
|
|
|
|
static unsigned char buf[5];
|
|
static unsigned char cmd[16] = {
|
|
0xcd, 0, 0, 0,
|
|
0, 2, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0
|
|
};
|
|
cmd[5] = 2; // get LCD parameters
|
|
if (wrap_scsi(dpf, cmd, sizeof(cmd), DIR_IN, buf, 5) == 0) {
|
|
dpf->width = (buf[0]) | (buf[1] << 8);
|
|
dpf->height = (buf[2]) | (buf[3] << 8);
|
|
fprintf(stderr, "dpf_ax_open: got LCD dimensions: %dx%d\n", dpf->width, dpf->height);
|
|
} else {
|
|
fprintf(stderr, "dpf_ax_open: error reading LCD dimensions!\n");
|
|
dpf_ax_close(dpf);
|
|
return NULL;
|
|
}
|
|
return (DPFAXHANDLE) dpf;
|
|
}
|
|
|
|
/**
|
|
* Close DPF device
|
|
*/
|
|
|
|
void dpf_ax_close(DPFAXHANDLE h)
|
|
{
|
|
DPFContext *dpf = (DPFContext *) h;
|
|
|
|
usb_release_interface(dpf->udev, 0);
|
|
usb_close(dpf->udev);
|
|
free(dpf);
|
|
}
|
|
|
|
/** Get screen width.
|
|
*
|
|
* \return width in pixel
|
|
*/
|
|
int dpf_ax_getwidth(DPFAXHANDLE h)
|
|
{
|
|
return ((DPFContext *) h)->width;
|
|
}
|
|
|
|
/** Get screen height.
|
|
*
|
|
* \return height in pixel
|
|
*/
|
|
int dpf_ax_getheight(DPFAXHANDLE h)
|
|
{
|
|
return ((DPFContext *) h)->height;
|
|
}
|
|
|
|
static
|
|
unsigned char g_excmd[16] = {
|
|
0xcd, 0, 0, 0,
|
|
0, 6, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0
|
|
};
|
|
|
|
/** Blit data to screen.
|
|
*
|
|
* \param buf buffer to 16 bpp RGB 565 image data
|
|
* \param rect rectangle tuple: [x0, y0, x1, y1]
|
|
*/
|
|
void dpf_ax_screen_blit(DPFAXHANDLE h, const unsigned char *buf, short rect[4])
|
|
{
|
|
unsigned long len = (rect[2] - rect[0]) * (rect[3] - rect[1]);
|
|
len <<= 1;
|
|
unsigned char *cmd = g_excmd;
|
|
|
|
cmd[6] = USBCMD_BLIT;
|
|
cmd[7] = rect[0];
|
|
cmd[8] = rect[0] >> 8;
|
|
cmd[9] = rect[1];
|
|
cmd[10] = rect[1] >> 8;
|
|
cmd[11] = rect[2] - 1;
|
|
cmd[12] = (rect[2] - 1) >> 8;
|
|
cmd[13] = rect[3] - 1;
|
|
cmd[14] = (rect[3] - 1) >> 8;
|
|
cmd[15] = 0;
|
|
|
|
wrap_scsi((DPFContext *) h, cmd, sizeof(g_excmd), DIR_OUT, (unsigned char *) buf, len);
|
|
}
|
|
|
|
/** Set backlight
|
|
*
|
|
* \param value Backlight value 0..7 (0 = off, 7 = max brightness)
|
|
*/
|
|
void dpf_ax_setbacklight(DPFAXHANDLE h, int b)
|
|
{
|
|
unsigned char *cmd = g_excmd;
|
|
|
|
if (b < 0)
|
|
b = 0;
|
|
if (b > 7)
|
|
b = 7;
|
|
|
|
cmd[6] = USBCMD_SETPROPERTY;
|
|
cmd[7] = 0x01; // PROPERTY_BRIGHTNESS
|
|
cmd[8] = 0x00; //PROPERTY_BRIGHTNESS >> 8;
|
|
cmd[9] = b;
|
|
cmd[10] = b >> 8;
|
|
|
|
wrap_scsi((DPFContext *) h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0);
|
|
}
|
|
|
|
|
|
static unsigned char g_buf[] = {
|
|
0x55, 0x53, 0x42, 0x43, // dCBWSignature
|
|
0xde, 0xad, 0xbe, 0xef, // dCBWTag
|
|
0x00, 0x80, 0x00, 0x00, // dCBWLength
|
|
0x00, // bmCBWFlags: 0x80: data in (dev to host), 0x00: Data out
|
|
0x00, // bCBWLUN
|
|
0x10, // bCBWCBLength
|
|
|
|
// SCSI cmd:
|
|
0xcd, 0x00, 0x00, 0x00,
|
|
0x00, 0x06, 0x11, 0xf8,
|
|
0x70, 0x00, 0x40, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
#define ENDPT_OUT 1
|
|
#define ENDPT_IN 0x81
|
|
|
|
static int wrap_scsi(DPFContext * h, unsigned char *cmd, int cmdlen, char out,
|
|
unsigned char *data, unsigned long block_len)
|
|
{
|
|
int len;
|
|
int ret;
|
|
static unsigned char ansbuf[13]; // Do not change size.
|
|
|
|
g_buf[14] = cmdlen;
|
|
memcpy(&g_buf[15], cmd, cmdlen);
|
|
|
|
g_buf[8] = block_len;
|
|
g_buf[9] = block_len >> 8;
|
|
g_buf[10] = block_len >> 16;
|
|
g_buf[11] = block_len >> 24;
|
|
|
|
ret = usb_bulk_write(h->udev, ENDPT_OUT, (const char *) g_buf, sizeof(g_buf), 1000);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (out == DIR_OUT) {
|
|
if (data) {
|
|
ret = usb_bulk_write(h->udev, ENDPT_OUT, (const char *) data, block_len, 3000);
|
|
if (ret != (int) block_len) {
|
|
fprintf(stderr, "dpf_ax ERROR: bulk write.\n");
|
|
return ret;
|
|
}
|
|
}
|
|
} else if (data) {
|
|
ret = usb_bulk_read(h->udev, ENDPT_IN, (char *) data, block_len, 4000);
|
|
if (ret != (int) block_len) {
|
|
fprintf(stderr, "dpf_ax ERROR: bulk read.\n");
|
|
return ret;
|
|
}
|
|
}
|
|
// get ACK:
|
|
len = sizeof(ansbuf);
|
|
int retry = 0;
|
|
int timeout = 0;
|
|
do {
|
|
timeout = 0;
|
|
ret = usb_bulk_read(h->udev, ENDPT_IN, (char *) ansbuf, len, 5000);
|
|
if (ret != len) {
|
|
fprintf(stderr, "dpf_ax ERROR: bulk ACK read.\n");
|
|
timeout = 1;
|
|
}
|
|
retry++;
|
|
} while (timeout && retry < 5);
|
|
if (strncmp((char *) ansbuf, "USBS", 4)) {
|
|
fprintf(stderr, "dpf_ax ERROR: got invalid reply\n.");
|
|
return -1;
|
|
}
|
|
// pass back return code set by peer:
|
|
return ansbuf[12];
|
|
}
|
|
|
|
//###################################################################
|
|
// End dpfcore4driver.c
|
|
//###################################################################
|