Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

it's a question.... Once you have X running... #1

Open
twobob opened this issue Sep 13, 2013 · 8 comments
Open

it's a question.... Once you have X running... #1

twobob opened this issue Sep 13, 2013 · 8 comments

Comments

@twobob
Copy link

twobob commented Sep 13, 2013

I have been searching for a solution to implement dithered one-bit in X on the kindle for a WHILE now.

This will enable many games to run very nicely once it is implemented.

Do you have any plans to make that a reality in the future?

Great work by the way.

@twobob
Copy link
Author

twobob commented Sep 13, 2013

Here's a FB based implementation from my mate Geeky.

It's MIT so no qualms using this.

But yeah. on the X layer not the FB layer.

//====================================================
// gmplay 1.5a - geekmaster's kindle video player
// Copyright (C) 2012 by geekmaster, with MIT license:
// http://www.opensource.org/licenses/mit-license.php
//----------------------------------------------------
// Tested on DX,DXG,K3,K4main,K4diags,K5main,K5diags.
//----------------------------------------------------
#include <sys/ioctl.h> // ioctl
#include <sys/mman.h> // mmap, munmap
#include <stdio.h> // printf
#include <stdlib.h> // malloc, free
#include <linux/fb.h> // screeninfo
#include <sys/time.h> // gettimeofday
#include <unistd.h> // usleep
#include <string.h> // memset, memcpy
#include <fcntl.h> // open, close, write
#include <time.h> // time
typedef unsigned long u64;
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
u32 __invalid_size_argument_for_IOC; // ioctl.h bug fix for tcc
//----- eink definitions from eink_fb.h and mxcfb.h -----
#define EU3 0x46dd
#define EU50 0x4040462e
#define EU51 0x4048462e
struct update_area_t {int x1,y1,x2,y2,which_fx;u8 _buffer;};
struct mxcfb_rect {u32 top,left,width,height;};
struct mxcfb_alt_buffer_data {u32 phys_addr,width,height;
struct mxcfb_rect alt_update_region;};
struct mxcfb_update_data {struct mxcfb_rect update_region;
u32 waveform_mode,update_mode,update_marker;int temp;uint flags;
struct mxcfb_alt_buffer_data alt_buffer_data;};
struct mxcfb_update_data51 {struct mxcfb_rect update_region;
u32 waveform_mode,update_mode,update_marker;
u32 hist_bw_waveform_mode,hist_gray_waveform_mode;
int temp;uint flags;struct mxcfb_alt_buffer_data alt_buffer_data;};
//----- function prototypes -----
void gmplay4(void);
void gmplay8(void);
int getmsec(void);
int gmlib(int);
//----- gmlib global vars -----
enum GMLIB_op {GMLIB_INIT,GMLIB_CLOSE,GMLIB_UPDATE,GMLIB_VSYNC};
u8 fb0=NULL; // framebuffer pointer
int fdFB=0; // fb0 file descriptor
int teu=0; // eink update time
u32 fs=0; // fb0 stride
u32 MX=0; // xres (visible)
u32 MY=0; // yres (visible)
u32 VY=0; // (VY>MY): mxcfb driver
u8 ppb=0; // pixels per byte
u32 fc=0; // frame counter
#define FBSIZE (600/8_800)
//==================================
// gmplay4 - play video on 4-bit fb0
//----------------------------------
void gmplay4(void) {
u32 i,x,y,b,p,off=(MY/2-400)_fs+MX/4-150,fbsize=FBSIZE; u8 fbt[FBSIZE];
while (fread(fbt,fbsize,1,stdin)) { teu+=130; // teu: next update time
if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind
gmlib(GMLIB_VSYNC); // wait for fb0 ready
for (y=0;y<800;y++) for (x=0;x<600;x+=8) {
b=fbt[600/8_y+x/8]; i=y_fs+x/2+off;
p=(b&1)_240; b>>=1; fb0[i]=p|(b&1)_15; b>>=1;
p=(b&1)_240; b>>=1; fb0[i+1]=p|(b&1)_15; b>>=1;
p=(b&1)_240; b>>=1; fb0[i+2]=p|(b&1)_15; b>>=1;
p=(b&1)_240; b>>=1; fb0[i+3]=p|(b&1)_15;
} fc++; gmlib(GMLIB_UPDATE);
}
}
//==================================
// gmplay8 - play video on 8-bit fb0
//----------------------------------
void gmplay8(void) {
u32 i,x,y,b,fbsize=FBSIZE; u8 fbt[FBSIZE];
while (fread(fbt,fbsize,1,stdin)) { teu+=130; // teu: next update time
if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind
gmlib(GMLIB_VSYNC); // wait for fb0 ready
for (y=0;y<800;y++) for (x=0;x<600;x+=8) {
b=fbt[600/8_y+x/8]; i=y_fs+x;
fb0[i]=(b&1)_255; b>>=1; fb0[i+1]=(b&1)_255; b>>=1;
fb0[i+2]=(b&1)_255; b>>=1; fb0[i+3]=(b&1)_255; b>>=1;
fb0[i+4]=(b&1)_255; b>>=1; fb0[i+5]=(b&1)_255; b>>=1;
fb0[i+6]=(b&1)_255; b>>=1; fb0[i+7]=(b&1)255;
} fc++; gmlib(GMLIB_UPDATE);
}
}
//====================================
// gmlib - geekmaster function library
// op (init, update, vsync, close)
//------------------------------------
int gmlib(int op) {
static struct update_area_t ua={0,0,600,800,21,NULL};
static struct mxcfb_update_data ur={
{0,0,600,800},257,0,1,0x1001,0,{0,0,0,{0,0,0,0}}};
static struct mxcfb_update_data51 ur51={
{0,0,600,800},257,0,1,0,0,0x1001,0,{0,0,0,{0,0,0,0}}};
static int eupcode; static void *eupdata=NULL;
struct fb_var_screeninfo screeninfo;
if (GMLIB_INIT==op) { teu=getmsec(); fdFB=open("/dev/fb0",O_RDWR);
ioctl(fdFB,FBIOGET_VSCREENINFO,&screeninfo);
ppb=8/screeninfo.bits_per_pixel; fs=screeninfo.xres_virtual/ppb;
VY=screeninfo.yres_virtual; MX=screeninfo.xres; MY=screeninfo.yres;
ua.x2=MX; ua.y2=MY; ur.update_region.width=MX; ur.update_region.height=MY;
fb0=(u8 *)mmap(0,MY_fs,PROT_READ|PROT_WRITE,MAP_SHARED,fdFB,0); // map fb0
if (VY>MY) { eupcode=EU50; eupdata=&ur; ur.update_mode=0;
if (ioctl(fdFB,eupcode,eupdata)<0) { eupcode=EU51; eupdata=&ur51; }
} else { eupcode=EU3; eupdata=&ua; }
system("eips -f -c;eips -c"); sleep(1);
} else if (GMLIB_UPDATE==op) {
if (ioctl(fdFB,eupcode,eupdata)<0) system("eips ''"); // 5.1.0 fallback
} else if (GMLIB_VSYNC==op) { while (teu>getmsec()) usleep(1000); // fb0 busy
} else if (GMLIB_CLOSE==op) { gmlib(GMLIB_UPDATE); sleep(1); // last screen
system("eips -f -c;eips -c"); munmap(fb0,MY_fs); close(fdFB);
} else { return -1; }
return 0;
}
//====================================
// getmsec - get msec since first call
// (tick counter wraps every 12 days)
//------------------------------------
int getmsec(void) {
int tc; static int ts=0; struct timeval tv;
gettimeofday(&tv,NULL); tc=tv.tv_usec/1000+1000
(0xFFFFF&tv.tv_sec);
if (0==ts) ts=tc;
return tc-ts;
}
//==================
// main - start here
//------------------
int main(void) {
int i;
gmlib(GMLIB_INIT);
if (ppb-1) { gmplay4(); } else { gmplay8(); }
i=getmsec()/100; printf("%d frames in %0.1f secs = %2.1f FPS\n",
fc,(double)i/10.0,(double)fc
10.0/i);
gmlib(GMLIB_CLOSE);
return 0;
}

@twobob
Copy link
Author

twobob commented Sep 15, 2013

I did note and build the framebuffer tools.To have a look.

@marek-g
Copy link
Owner

marek-g commented Sep 16, 2013

Yes! I was thinking about it. Thanks for the sample code!

It would enable not only games but also movies (like on youtube - embedded on web pages etc). Without sound of course :) I don't know if the resolution is enough to see what's on the movie but it's worth a try. Dithering will be nice to have here of course! (I'm thinking about some kind of more sophisticated but still fast dithering algorithm here).

I was even thinking about automatic movement detection. With updating selective regions only. Imagine you are watching movie on a web page. Movie is black & white while rest of the page is in shadows of gray. If you scroll page - it's scrolling smoothly in black & white and after you stop it converts to gray (and movie is playing in black & white all the time). It's all possible inside eink's framebuffer driver.

The first thing I'm missing is automatic full screen refresh (with the inversion effect) - to make reading books experience better :) But it's related and I may do both things at the same time. Both needs detection of what's moving and what's not.

I know I cannot stop myself from trying it (it will be so much fun!!) but I'm a little busy lately so I don't know when. Anyway - that's why I've shared the code - fell free if you want to try before me :)

@marek-g
Copy link
Owner

marek-g commented Sep 16, 2013

Especially I would like to see this feature combined with multitouch properly configured (pinch to zoom etc). But it's confusing / not clear for me what needs to be implemented / how to configure multitouch on X11. I'm afraid X11 and applications are not ready for it, yet. You can have substitute as simulating keystrokes (ctrl + numpadplus) but it's not the same.

@twobob
Copy link
Author

twobob commented Sep 27, 2013

We're on the same page.
I think the best youtube project would be http://flavio.tordini.org/minitube (the kindles have sound)

Multitouch huh. OOTB the kindles have it, Let me post the modification that were done to the nook kernel to enable it...hmm... here somewhere

@twobob
Copy link
Author

twobob commented Sep 27, 2013


diff -Nur kernel/drivers/input/touchscreen/zforce.c /opt/nook/distro/kernel/drivers/input/touchscreen/zforce.c
--- kernel/drivers/input/touchscreen/zforce.c   2011-09-30 22:01:48.000000000 +0200
+++ /opt/nook/distro/kernel/drivers/input/touchscreen/zforce.c  2012-09-24 13:18:18.000000000 +0200
@@ -47,11 +47,13 @@
 #define COMMAND_SETCONFIGN 0x03
 #define COMMAND_DATAREQUEST    0x04
 #define COMMAND_SCANFREQ   0x08
-#define COMMAND_VERSION        0x0A
+#define COMMAND_VERSION        0x0A
 #define COMMAND_PULSESTRENG    0x0F
 #define COMMAND_LEVEL      0x1C
 #define COMMAND_FORCECAL   0X1A
 #define COMMAND_STATUS     0X1E
+#define COMMAND_BIST       0X21
+

 // Responses
 #define RESPONSE_DEACTIVATE    0x00
@@ -64,11 +66,19 @@
 #define RESPONSE_PULSESTRENG   0x0F
 #define RESPONSE_LEVEL     0x1C
 #define RESPONSE_STATUS        0X1E
+#define RESPONSE_BIST      0X21
 #define RESPONSE_INVALID   0xFE

 // Platform specific
 #define ZF_COORDATA_SIZE 7

+#define ZF_BIST_XDATA_LEN 7
+#define ZF_BIST_YDATA_LEN 9
+
+DEFINE_MUTEX(zForce_sysfs_mutex);
+
+static int zforce_synchronized_wait_for_completion_timeout(struct completion *res);
+
 static struct workqueue_struct *zforce_wq;

 struct zforce {
@@ -80,6 +90,8 @@
    struct work_struct  work;
    char            phys[32];
    u8  zf_status_info[64];
+   u8  zf_bist_xresult[ZF_BIST_XDATA_LEN]; //include the axis in 1st byte
+   u8  zf_bist_yresult[ZF_BIST_YDATA_LEN]; //TODO make it more generic; once comm spec is finalized.
    int err_cnt;
 };

@@ -124,7 +136,7 @@
 // #######
 static int send_data_request(struct zforce *tsc)
 {
-   int ret;
+   int ret = 0;
    int retry = 3;

    dev_dbg(&tsc->client->dev, "%s()\n", __FUNCTION__);
@@ -169,11 +181,11 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

-   // I2C opperations was successful
-   // Return the results from the controler. (0 == success)
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
    return tsc->command_result;
 }

@@ -203,11 +215,11 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

-   // I2C opperations was successful
-   // Return the results from the controler. (0 == success)
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
    return tsc->command_result;
 }

@@ -236,11 +248,11 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

-   // I2C opperations was successful
-   // Return the results from the controler. (0 == success)
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
    return tsc->command_result;
 }

@@ -269,14 +281,45 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

-   // I2C opperations was successful
-   // Return the results from the controler. (0 == success)
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
    return tsc->command_result;
 }

+// BIST Request
+// ############################
+static int send_bist_request(struct zforce *tsc, u8 axis)
+{
+   struct i2c_msg msg[2];
+   u8 request[2];
+   int ret;
+
+   dev_info(&tsc->client->dev, "%s\n", __FUNCTION__);
+
+   request[0] = COMMAND_BIST;
+   request[1] = axis;
+   msg[0].addr = tsc->client->addr;
+   msg[0].flags = 0;
+   msg[0].len = 2;
+   msg[0].buf = request;
+
+   ret = i2c_transfer(tsc->client->adapter, msg, 1);
+   if (ret < 0)
+   {
+       dev_err(&tsc->client->dev, "i2c send status error: %d\n", ret);
+       return ret;
+   }
+
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;
+
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
+   return tsc->command_result;
+}
 // DEACTIVATE Request
 // [0:cmd]
 // #######
@@ -299,11 +342,11 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

-   // I2C opperations was successful
-   // Return the results from the controler. (0 == success)
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
    return tsc->command_result;
 }

@@ -329,11 +372,11 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

-   // I2C opperations was successful
-   // Return the results from the controler. (0 == success)
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
    return tsc->command_result;
 }

@@ -343,7 +386,7 @@
 // #######
 static int send_activate_request(struct zforce *tsc)
 {
-   int ret;
+   int ret = 0 ;
    int retry = 3;

    dev_dbg(&tsc->client->dev, "%s()\n", __FUNCTION__);
@@ -360,11 +403,11 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

-   // I2C opperations was successful
-   // Return the results from the controler. (0 == success)
+   // I2C operations was successful
+   // Return the results from the controller. (0 == success)
    return tsc->command_result;
 }

@@ -403,8 +446,8 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

    return tsc->command_result;
 }
@@ -449,13 +492,15 @@
        return ret;
    }

-   if (wait_for_completion_timeout(&tsc->command_done, WAIT_TIMEOUT) == 0)
-       return -1;
+   if (zforce_synchronized_wait_for_completion_timeout(&tsc->command_done) == 0)
+       return -ETIMEDOUT;

    return tsc->command_result;
 }
 #define ZF_NUMX 11
 #define ZF_NUMY 15
+#define ZF_X_AXIS 0
+#define ZF_Y_AXIS 1
 #define ZF_LEDDATA_LEN (2+(ZF_NUMX + ZF_NUMY)*3)
 static u8 ledlevel[ZF_LEDDATA_LEN];

@@ -610,6 +655,60 @@
    return ZF_STATUS_SIZE;
 }

+static int process_bist_response(struct zforce *tsc, const u8* payload)
+{
+   u8 *pyld =  NULL;
+   u8 len = 0;
+
+   dev_dbg(&tsc->client->dev, "%s()\n", __FUNCTION__);
+
+   if( payload[0] == ZF_X_AXIS )
+   {
+       pyld = (u8 *)tsc->zf_bist_xresult;
+       len = ZF_BIST_XDATA_LEN;
+   }
+   else if( payload[0] == ZF_Y_AXIS )
+   {
+       pyld = (u8 *)tsc->zf_bist_yresult;
+       len = ZF_BIST_YDATA_LEN;
+   }
+   else
+   {
+       return 1;
+   }
+   memcpy(pyld, payload, len);
+   return len;
+}
+static void update_tinfo(struct zforce *tsc, u8* payload)
+{
+   int count = payload[0];
+   int i;
+
+   if (count > ZF_NUM_FINGER_SUPPORT)
+   {
+       dev_dbg(&tsc->client->dev, "Invalid finger count %d\n", count);
+       return;
+   }
+
+   for (i = 0; i < count; i++)
+   {
+       u8 *data = payload + 1 + i * ZF_COORDATA_SIZE;
+       int state = (data[4] & 0xC0) >> 6;
+       int id = (data[4] & 0x3C) >> 2;
+       if (id != 1 && id != 2)
+       {
+           dev_dbg(&tsc->client->dev, "Invalid touch id %d\n", id);
+           continue;
+       }
+
+       tinfo[id - 1].x = data[1] << 8 | data[0];
+       tinfo[id - 1].y = data[3] << 8 | data[2];
+       tinfo[id - 1].z = state == STATE_UP ? 0 : 20;
+       tinfo[id - 1].state = state;
+       tinfo[id - 1].valid = 1;
+   }
+}
+

 // Touch Payload Results
 // [1:count] [2:x] [2:y] [1:state]
@@ -663,32 +762,19 @@
        printk("\n");
    }
    #endif
-   if (count != 1)
-   {
-       dev_dbg(&tsc->client->dev, "Invalid number of coordinates: %d\n", count);
-   }
-   memcpy(&x, &payload[1], sizeof(u16));
-   memcpy(&y, &payload[3], sizeof(u16));
-   status = payload[5];

    if (major == 1)
    {
+       memcpy(&x, &payload[1], sizeof(u16));
+       memcpy(&y, &payload[3], sizeof(u16));
+       status = payload[5];
        state = status & 0x03;
        id = 1;
-   }
-   else
-   {
-       state = (status & 0xC0) >> 6;
-       id =    (status & 0x3C) >> 2;
-   }
-
-   //x = 600 - x;
-   if (major == 1)
        y = 800 - y;

-   // Process
-   switch (state)
-   {
+       // Process
+       switch (state)
+       {
        case STATE_MOVE:
            dev_dbg(&tsc->client->dev, "%d move(%d,%d)\n", id, x, y);
            input_report_abs(tsc->input, ABS_X, x);
@@ -712,8 +798,29 @@
        default:
            dev_err(&tsc->client->dev, "Invalid state: %d\n", state);
            return (count * size) + 1;
+       }
+       input_sync(tsc->input);
    }
-   input_sync(tsc->input);
+   else
+   {
+       int i;
+       update_tinfo(tsc, payload);
+       for (i = 0; i < ZF_NUM_FINGER_SUPPORT; i++)
+       {
+           if (!tinfo[i].valid)
+               continue;
+
+           input_report_abs(tsc->input, ABS_MT_POSITION_X, tinfo[i].x);
+           input_report_abs(tsc->input, ABS_MT_POSITION_Y, tinfo[i].y);
+           input_report_abs(tsc->input, ABS_MT_TOUCH_MAJOR, tinfo[i].z);
+           input_mt_sync(tsc->input);
+
+           if (tinfo[i].state == STATE_UP)
+               tinfo[i].valid = 0;
+       }
+       input_sync(tsc->input);
+   }
+
    return (count * size) + 1;
 }

@@ -761,6 +868,20 @@
    return 0;
 }

+static int zforce_synchronized_wait_for_completion_timeout(struct completion *res)
+{
+   int ret = 0;
+
+   mutex_lock(&zForce_sysfs_mutex);
+   ret = wait_for_completion_timeout(res, WAIT_TIMEOUT);
+   mutex_unlock(&zForce_sysfs_mutex);
+
+   if (ret)
+       return 1;
+
+   return 0;
+}
+
 // Response Bytes
 // [1:0xEE] [1:len] [len:payload]
 // ##############################
@@ -821,6 +942,12 @@
            complete(&tsc->command_done);
            break;

+       case  RESPONSE_BIST:
+           cmd_len = process_bist_response(tsc, &payload[RESPONSE_DATA]);
+           tsc->command_result = 0;
+           complete(&tsc->command_done);
+           break;
+
        case  RESPONSE_INVALID:
            cmd_len = 1;
            dev_err(&tsc->client->dev, "Invalid Command ID: %d\n(TC%d)", payload[RESPONSE_DATA], ++(tsc->err_cnt) );
@@ -976,12 +1103,26 @@
 {
    int cnt = 0;
    struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-   struct zforce *tsc = i2c_get_clientdata(client); 
+   struct zforce *tsc = NULL;
+   int ret = 0;
+
+
+   if (client){
+       tsc  = i2c_get_clientdata(client);
+   }

    zforce_info("Request fw ver from zforce\n");
-   if (send_version_request(tsc))
-   {
-       dev_err(&client->dev, "UnableToRequestVersion\n");
+
+   if (!zforce_wq){/*DRIVER PROBE FAILED */
+       cnt = cnt + sprintf(&buf[cnt],"%04x:%04x %04x:%04x\n", 0, 0, 0, 0);
+       printk("sending touch firmware version 00000\n");
+       return cnt;
+   }
+   else if (tsc){
+       ret = send_version_request(tsc);
+       if (ret){
+           dev_err(&client->dev, "UnableToRequestVersion\n");
+       }
    }
    cnt = cnt + sprintf(&buf[cnt],"%04x:%04x %04x:%04x\n", major, minor, build, rev);

@@ -1261,16 +1402,61 @@
    return cnt;
 }

+// =-=-=-=-=-=-=-=-=-=-=-=-=
+//  Zforce BIST
+// =-=-=-=-=-=-=-=-=-=-=-=-=
+static ssize_t zforce_bist_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+   int i, cnt = 0, ret = 0;
+   struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+   struct zforce *tsc = i2c_get_clientdata(client);
+   u8 *payload = (u8 *)tsc->zf_bist_xresult;
+
+   zforce_info("Zforce internal status strength\n");
+
+   // run open and short test for x axis
+   ret = send_bist_request(tsc, ZF_X_AXIS);
+   if(ret)
+   {
+       dev_err(&client->dev, "Unable to retrieve zforce status: %x.\n", ret);
+       return -EINVAL;
+   }
+
+   // run open and short test for y axis
+   ret = send_bist_request(tsc, ZF_Y_AXIS);
+   if(ret)
+   {
+       dev_err(&client->dev, "Unable to retrieve zforce status: %x.\n", ret);
+       return -EINVAL;
+   }
+
+   cnt = cnt + sprintf(&buf[cnt],"BISTX:");
+   for( i=0; i<ZF_BIST_XDATA_LEN; i++ )
+   {
+       cnt = cnt + sprintf(&buf[cnt]," %02X", payload[i] );
+   }
+
+   payload = (u8 *)tsc->zf_bist_yresult;
+   cnt = cnt + sprintf(&buf[cnt],"\nBISTY:");
+   for( i=0; i<ZF_BIST_YDATA_LEN; i++ )
+   {
+       cnt = cnt + sprintf(&buf[cnt]," %02X", payload[i] );
+   }
+   cnt = cnt + sprintf(&buf[cnt], "\n");
+   return cnt;
+}
+
+

 static DEVICE_ATTR(ledlevel, S_IRUGO|S_IWUSR, zforce_ledlevel_show, zforce_ledlevel_store);
 static DEVICE_ATTR(versions, S_IRUGO|S_IWUSR, zforce_versions_show, zforce_versions_store);
 static DEVICE_ATTR(forcecal, S_IRUGO|S_IWUSR, zforce_forcecal_show, zforce_forcecal_store);
 static DEVICE_ATTR(fixps, S_IRUGO|S_IWUSR, zforce_pulsestrength_show, zforce_pulsestrength_store);
-static DEVICE_ATTR(zfstatus,   S_IRUGO, zforce_zfstatus_show, NULL);
-static DEVICE_ATTR(on_off,     S_IWUSR, NULL, zforce_on_off_store);
-static DEVICE_ATTR(cmd,        S_IWUSR, NULL, zforce_cmd_store);
-
-
+static DEVICE_ATTR(zfstatus, S_IRUGO, zforce_zfstatus_show, NULL);
+static DEVICE_ATTR(bist, S_IRUGO, zforce_bist_show, NULL);
+static DEVICE_ATTR(on_off, S_IWUSR, NULL, zforce_on_off_store);
+static DEVICE_ATTR(cmd,    S_IWUSR, NULL, zforce_cmd_store);

 static struct attribute *zforce_attributes[] = {
    &dev_attr_ledlevel.attr,
@@ -1278,6 +1464,7 @@
    &dev_attr_forcecal.attr,
    &dev_attr_fixps.attr,
    &dev_attr_zfstatus.attr,
+   &dev_attr_bist.attr,
    &dev_attr_on_off.attr,
    &dev_attr_cmd.attr,
    NULL
@@ -1348,6 +1535,7 @@

    input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, pdata->width, 0, 0);
    input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, pdata->height, 0, 0);
+   input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 1000, 0, 0);

    tsc->irq = client->irq;
    tsc->err_cnt = 0;


@twobob
Copy link
Author

twobob commented Sep 27, 2013

SO that reads pretty much like they shoved an extra axis (bit) in the zforce driver then modified the method that services said data. I am no expert. Hope it helps.

@twobob
Copy link
Author

twobob commented Sep 27, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants