> If this code is acceptable, may add SMP, multiple device support, auto
> calibration etc. features. If you are send your things, i'm can be very
> happy. See attachments (or expanded inline text) for calibration, usage
> details etc. 
> 
> After your oppinions, i make a diff file for latest kernel tree. 
> 
> Code: 

> static struct proc_dir_entry *proc_dir, *proc_file;
> static char file_write_buf[128];

must be protected with a semaphore

> static int _curr_x, _curr_y, _curr_x_raw, _curr_y_raw, _curr_button;
> static int c_mode, minx, maxx, miny, maxy, midx, midy, ratex, ratey,
> send_cdata;
> 
> #define USB_VENDOR_ID_DMC 0x0afa
> 
> #define TSC10_PACKET_LEN 5
> 
> struct tsc10 {
>        signed char data[TSC10_PACKET_LEN];

this violates DMA rules. Must use its own buffer

>        struct input_dev dev;
>        struct usb_device *usbdev;
>        struct urb *irq;
>        int open;
> };
> 
> 
> #define OK 0
> #define NOT_OK 1
> 
> typedef   int INT32;

The penalty for that is too terrible to be described in writing.

> typedef struct _point {
> int    x, y;
> } point ;
> 
> 
> typedef struct _matrix {
> int   An; 
> int   Bn;
> int   Cn;
> int   Dn;
> int           En;
> int   Fn;
> int     Div;
> } matrix ;
> 
> 
> 
> 
> static void tsc10_control (struct tsc10 *tsc10,
>                           __u8 requesttype, __u8 request, __u16 value,
>                           __u16 retlen)
> {
>        struct usb_device *dev = tsc10->usbdev;
>        int ret;
>        unsigned char buf[2];

DMA on stack. Invalid.

>        if (retlen > 2) {
>                printk (KERN_ERR
>                        "tsc10_control: retlen > 2 is not supported.");
>                retlen = 2;
>        }
> 
>        buf[0] = buf[1] = 0xFF;
>        ret = usb_control_msg (dev, usb_rcvctrlpipe (dev, 0),
>                               request, requesttype, value, 0,
>                               buf, retlen, 2*HZ);
>        //printk(KERN_INFO "DMC SEQ RET: %02x  %02x \n", buf[0], buf[1]);
> 
> }
> 
> static matrix calMatris;
> static point    calPts[6];
> static point    samplePts[6];
> 
> int setCalibrationMatrix(point * sample, point * real, matrix * matrix)
> {
> 
> 
>     matrix->Div = ((real[0].x - real[2].x) *
>                  (real[1].y - real[2].y)) - 
>                 ((real[1].x - real[2].x) *
>                 (real[0].y - real[2].y));
> 
>     if( matrix->Div == 0 )
>         return 1;
>     
>     matrix->An = ((sample[0].x - sample[2].x) * (real[1].y - real[2].y))
> -
>                     ((sample[1].x - sample[2].x) * (real[0].y -
> real[2].y));
> 
>     matrix->Bn = ((real[0].x - real[2].x) * (sample[1].x - sample[2].x))
> -
>                     ((sample[0].x - sample[2].x) * (real[1].x -
> real[2].x));
> 
>     matrix->Cn = (real[2].x * sample[1].x - real[1].x * sample[2].x) *
> real[0].y +
>                     (real[0].x * sample[2].x - real[2].x * sample[0].x)
> * real[1].y +
>                     (real[1].x * sample[0].x - real[0].x * sample[1].x)
> * real[2].y;
> 
>     matrix->Dn = ((sample[0].y - sample[2].y) * (real[1].y - real[2].y))
> -
>                     ((sample[1].y - sample[2].y) * (real[0].y -
> real[2].y));
> 
>     matrix->En = ((real[0].x - real[2].x) * (sample[1].y - sample[2].y))
> - 
>                     ((sample[0].y - sample[2].y) * (real[1].x -
> real[2].x));
> 
>     matrix->Fn = (real[2].x * sample[1].y - real[1].x * sample[2].y) *
> real[0].y +
>                     (real[0].x * sample[2].y - real[2].x * sample[0].y)
> * real[1].y +
>                     (real[1].x * sample[0].y - real[0].x * sample[1].y)
> * real[2].y;
>      
>     return 0;
> 
> }
> 
> 
> int getDisplayPoint(int *x, int *y, int raw_x, int raw_y, matrix *
> matrix)
> {
>     if( matrix->Div == 0 )
>       return 1;
> 
>     *x = ((matrix->An * raw_x) + (matrix->Bn * raw_y) + matrix->Cn) /
> matrix->Div;
>     *y = ((matrix->Dn * raw_x) + (matrix->En * raw_y) + matrix->Fn) /
> matrix->Div;
> 
>     return 0;
> 
> }
> 
> 
> 
> static void tsc10_reset (struct tsc10 *tsc10)
> {
>        tsc10_control (tsc10, 0xC0, 0x55, 0, 2);
> }
> 
> static void tsc10_set_rate (struct tsc10 *tsc10, int rate)
> {
>        tsc10_control (tsc10, 0xC0, 0x05, rate, 2);
> }
> 
> static void tsc10_start_1 (struct tsc10 *tsc10)
> {
>        tsc10_control (tsc10, 0x40, 0x21, 0, 0);
> }
> 
> struct usb_device_id tsc10_ids[] = {
>        { USB_DEVICE (USB_VENDOR_ID_DMC, 0x03e8) },
>        { }
> };
> 
> MODULE_DEVICE_TABLE (usb, tsc10_ids);
> 
> static void tsc10_irq (struct urb *urb, struct pt_regs *regs)
> {
>        struct tsc10 *tsc10 = urb->context;
>        unsigned char *data = tsc10->data;
>        struct input_dev *dev = &tsc10->dev;
>        int rep_x, rep_y, button;
> 
>        if (urb->status)
>                return;
> 
>        button = data[0];
>        
>        rep_x = data[1]+256*data[2];
>        rep_y = data[3]+256*data[4];

use the macros

>        if (inv || invx) 
>            rep_x = 1023 - rep_x;
>        if (inv || invy) 
>          rep_y = 1023 - rep_y;
> 
>        _curr_x_raw = rep_x;
>        _curr_y_raw = rep_y;       
> 
>        if (in_calibrate != 0) {       
>           /* On Calibration state, we only report Button Events.. */
>           if (_curr_button == 17 && button == 16) {
>               samplePts[in_calibrate-1].x = rep_x;
>               samplePts[in_calibrate-1].y = rep_y;            
>               if (debug)
>                   printk(KERN_INFO "Set Sample Point: %d on X:%d/Y:%d\n",
> in_calibrate, rep_x, rep_y);          
>               _curr_button = data[0];
>               if (debug) 
>                   printk(KERN_INFO "TSC10: Calibration mode ButtonPress\n");
>               input_report_key (dev, BTN_TOUCH, (data[0] & 0x01) != 0);
>               input_sync (dev);
>           } else {
>               if (_curr_button == 16 && button == 17) {
>                   _curr_button = data[0];
>                   input_report_key (dev, BTN_TOUCH,(data[0] & 0x01) != 0);
>                   input_sync (dev);               
>                   if (debug)
>                       printk(KERN_INFO "TSC10: Calibration mode ButtonRelease\n");   
>          
>               }
>           }
> 
>        } else {         
>             switch (c_mode) {
>               case 0:
>                   break;
>               case 1:         
>                   getDisplayPoint(&rep_x, &rep_y, rep_x, rep_y, &calMatris);
>                   break;
>               case 2:
>                   /* Translate for min/max values */
> 
>                   rep_x =  (rep_x - minx);
>                   rep_y =  (rep_y - miny);
>                   if (rep_x <= 0) rep_x = 1;
>                   if (rep_y <= 0) rep_y = 1;
>                   
>                   rep_x =  (ratex * rep_x) / 1000;
>                   rep_y =  (ratey * rep_y) / 1000;                
> 
>                   if (rep_x > 1024) rep_x = 1024;
>                   if (rep_x < 0) rep_x = 0;
>                   
>                   if (rep_y > 1024) rep_y = 1024;
>                   if (rep_y < 0) rep_y = 0;
> 
>                   if (debug && ((data[0] & 0x01) != 0))
>                       printk(KERN_INFO "TSC-10: Button = %d Translate min/max: X: %d 
> -> %d
> Y: %d -> %d\n", data[0],
>                           _curr_x_raw, rep_x,
>                           _curr_y_raw, rep_y);
>                   break;
>           }
>           input_regs (dev, regs);
>           input_report_abs (dev, ABS_X, rep_x);
>           input_report_abs (dev, ABS_Y, rep_y);
>           input_report_key (dev, BTN_TOUCH, (data[0] & 0x01) != 0);
>           input_sync (dev);
>           _curr_button = data[0];
>           _curr_x = rep_x;       
>           _curr_y = rep_y;
>        }     
> 
>        
>        usb_submit_urb (urb, GFP_ATOMIC);
> }
> 
> static int tsc10_open (struct input_dev *dev)
> {
>        struct tsc10 *tsc10 = dev->private;
> 
>        if (tsc10->open++)
>                return 0;
> 
>        tsc10->irq->dev = tsc10->usbdev;
>        if (usb_submit_urb (tsc10->irq, GFP_ATOMIC))

GFP_KERNEL will do.

>                return -EIO;

incorrect error handling. Must do 'open--' and should protect
against the race.

>        return 0;
> }
> 
> static void tsc10_close (struct input_dev *dev)
> {
>        struct tsc10 *tsc10 = dev->private;
> 
>        if (!--tsc10->open)
>                usb_unlink_urb (tsc10->irq);
> }
> 
> 
> static int tsc10_probe (struct usb_interface *intf,
>                        const struct usb_device_id *id)
> {
>        struct usb_device *dev = interface_to_usbdev (intf);
>        struct usb_endpoint_descriptor *endpoint;
>        struct tsc10 *tsc10;
> 
>        tsc10 = kmalloc (sizeof(struct tsc10), GFP_KERNEL);
>        if (tsc10 == NULL)
>                return -ENOMEM;
> 
>        memset (tsc10, 0, sizeof(struct tsc10));
> 
>        tsc10->irq = usb_alloc_urb (0, GFP_KERNEL);
>        if (!tsc10->irq) {
>                kfree (tsc10);
>                return -ENOMEM;
>        }
> 
>        tsc10->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
>        tsc10->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y);
>        tsc10->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
> 
>        tsc10->dev.absmax[ABS_X] = 1024;
>        tsc10->dev.absmax[ABS_Y] = 1024;
> 
>        tsc10->dev.absmin[ABS_X] = 0;
>        tsc10->dev.absmin[ABS_Y] = 0;
> 
>        tsc10->dev.absfuzz[ABS_X] = fuzz;
>        tsc10->dev.absfuzz[ABS_Y] = fuzz;
> 
>        tsc10->dev.private = tsc10;
>        tsc10->dev.open = tsc10_open;
>        tsc10->dev.close = tsc10_close;
> 
>        tsc10->dev.name = "tsc-10";
>        tsc10->dev.id.bustype = BUS_USB;
>        tsc10->dev.id.vendor = dev->descriptor.idVendor;
>        tsc10->dev.id.product = dev->descriptor.idProduct;
>        tsc10->dev.id.version = dev->descriptor.bcdDevice;
>        tsc10->usbdev = dev;       
> 
>        endpoint = &intf->altsetting[0].endpoint[0].desc;
> 
>        usb_fill_int_urb (tsc10->irq, dev,
>                          usb_rcvintpipe (dev,
> endpoint->bEndpointAddress),
>                          tsc10->data, TSC10_PACKET_LEN, tsc10_irq,
> tsc10,
>                          endpoint->bInterval);
> 
>        input_register_device (&tsc10->dev);
> 
>        {
>                char path[64];
>                usb_make_path (dev, path, 64);
>                printk(KERN_INFO "input: %s on %s\n", tsc10->dev.name,
> path);
>        }
> 
>        tsc10_reset (tsc10);
>        tsc10_set_rate (tsc10, TSC10_RATE_30);
>        tsc10_start_1 (tsc10);
> 
>        usb_set_intfdata (intf, tsc10);
> 
>        return 0;
> }
> 
> static void tsc10_disconnect (struct usb_interface *intf)
> {
>        struct tsc10 *tsc10 = usb_get_intfdata (intf);
> 
>        usb_set_intfdata(intf, NULL);
>        if (intf) {
>                usb_unlink_urb (tsc10->irq);
>                input_unregister_device (&tsc10->dev);
>                usb_free_urb (tsc10->irq);
>                kfree (tsc10);
>        }
> }
> 
> static struct usb_driver tsc10_driver = {
>        .owner      = THIS_MODULE,
>        .name       = "tsc-10",
>        .probe      = tsc10_probe,
>        .disconnect = tsc10_disconnect,
>        .id_table   = tsc10_ids
> };
> 
> struct tsc10packet {
> char  touch;
> char  x_hi;
> char  x_lo;
> char  y_hi;
> char  y_lo;
> char  raw_x_hi;
> char  raw_x_lo;
> char  raw_y_hi;
> char  raw_y_lo;
> char  cal_xmin_hi;
> char  cal_xmin_lo;
> char  cal_xmax_hi;
> char  cal_xmax_lo;
> char  cal_ymin_hi;
> char  cal_ymin_lo;
> char  cal_ymax_hi;
> char  cal_ymax_lo;
> };
> 
> int   proc_read(char *page, char **start, off_t off, int count, int *eof,
> void *data)
> {
>     struct tsc10packet *pk;
>     pk = (struct tsc10packetpage *) page;
>     pk->touch = _curr_button;
>     
>     if (in_calibrate) {
>       pk->touch += 32;
>       if (debug)
>           printk(KERN_INFO "TSC10: Send Calibrate Packet: %d\n", pk->touch);
>     }
> 
>     if (send_cdata) {
>       pk->touch = 64;
>       send_cdata = 0;
>       if (debug)
>           printk(KERN_INFO "TSC10: Send Calibration Values: %d\n",
> pk->touch);
>       pk->cal_xmin_hi = minx / 256;
>       pk->cal_xmin_lo = minx % 256;
>       pk->cal_xmax_hi = maxx / 256;
>       pk->cal_xmax_lo = maxx % 256;
> 
>       pk->cal_ymin_hi = miny / 256;
>       pk->cal_ymin_lo = miny % 256;
>       pk->cal_ymax_hi = maxy / 256;
>       pk->cal_ymax_lo = maxy % 256;
>     }
>     
>     pk->x_hi = _curr_x / 256;
>     pk->x_lo = _curr_x % 256;
>     pk->y_hi = _curr_y / 256;
>     pk->y_lo = _curr_y % 256;
>     pk->raw_x_hi = _curr_x_raw / 256;
>     pk->raw_x_lo = _curr_x_raw % 256;
>     pk->raw_y_hi = _curr_y_raw / 256;
>     pk->raw_y_lo = _curr_y_raw % 256;
> 
> 
>     int len = sizeof(struct tsc10packet);
>     return len;
> 
> }
> 
> 
> int   proc_write(struct file *file, const char *buffer, unsigned long
> count, void *data)
> {
>       char *buf = file_write_buf;
>       if (count > 127)
>           count = 127;
>       int x, y, i;
>       
>       copy_from_user(buf, buffer, count);

Must protect buf against race.
>       
> 
>       switch (buf[0]) {
>           case 'c':           
>               /* Calibration Mode 1
>                  In This mode, driver translate coordinates with internal calibrator
>                  You must set 3 sample points. This Points can be any point, but
>                  15 - 15, 50 - 85, 85 - 50 (all values in percent of 1024)
> coordinates
>                  a good start point..
>                  
>                  This mode usefull for correct unaligned/cross aligned touchpanels.
>                  
>                  Provided sample xtsc10cal.kernel uses this mode..
>                  
>                   Command Format:
>                   
>                   Cnxxx yyy
>                   n = Point Number
>                   xxx, yyy = X and Y coordinates for this point.
>               */
>               c_mode = 1;
>               
>               in_calibrate = buf[1] - '0';
>               if (in_calibrate < 1 || in_calibrate > 3) {
>                   in_calibrate = 0;

Report user errors

>                   break;
>               }
>               
> 
>               for (i = 2; i < count; i++) {
>                   if (buf[i] == ' ') {
>                       x = simple_strtol(&buf[2], NULL, 10);                   
>                       y = simple_strtol(&(buf[i+1]), NULL, 10);
>                       calPts[in_calibrate-1].x = x;
>                       calPts[in_calibrate-1].y = y;
>                       printk(KERN_INFO "CalPoint %d x: %d y:%d \n", in_calibrate, 
> x,y);
>                       break;
>                   }
>               }
>               break;
> 
>           case 'C':   
>               /*
>                   Calibration Mode 2
>                   In This mode, driver uses scaled calibrating.
>                   Calibration tool set 4 point with replace Upper-Left, 
>                   Upper-Right, Lower-Left and Lower-Right corners.
>                   
>                   This information used with mouse emulation device.
>                   
>                   Command Format:
>                   
>                   Cnxxx yyy
>                   n = Point Number
>                   xxx, yyy = X and Y coordinates for this point.
>               */      
> 
>               c_mode = 2;
>               printk(KERN_INFO "TSC-10: Enter UserSpace Calibration mode: %d\n",
> c_mode);
>               in_calibrate = buf[1] - '0';
>               if (in_calibrate < 1 || in_calibrate > 5) {
>                   in_calibrate = 0;
>                   break;
>               }
> 
>               for (i = 2; i < count; i++) {
>                   if (buf[i] == ' ') {
>                       x = simple_strtol(&buf[2], NULL, 10);                   
>                       y = simple_strtol(&(buf[i+1]), NULL, 10);
>                       calPts[in_calibrate-1].x = x;
>                       calPts[in_calibrate-1].y = y;
>                       printk(KERN_INFO "TSC-10: CalPoint (mode %d) %d x: %d y:%d \n",
> c_mode, in_calibrate, x,y);
>                       break;
>                   }
>               }
>               break;
>           case '2':
>               /* Read Mode 2 Calibration data 
> 
>                  After this command, driver send touch = 64 and fill 
>                  calibration values from internal max/min table.
>                  
>                  This command used with X11 driver.
>                   
>               */
>               
>               if (c_mode == 2)
>                   send_cdata = 1;
> 
>               break;
> 
>           case 'z':
>               /* Process Calibration values
>                   With this command, driver calculate new calibration values and
> exit calibration mode.
> 
>                   if calibration mode = 2 (Min/Max mode), driver send calibration 
>                   values with subsequent read call in proc file..
>               */
> 
>               printk(KERN_INFO "TSC10: Calibrate (%d) Point: %d Pos: X:%d->%d
> Y:%d->%d\n", 0, c_mode, calPts[0].x, samplePts[0].x, calPts[0].y,
> samplePts[0].y);
>               printk(KERN_INFO "TSC10:      Calibrate Point: %d Pos: X:%d->%d
> Y:%d->%d\n", 1, calPts[1].x, samplePts[1].x, calPts[1].y,
> samplePts[1].y);
>               printk(KERN_INFO "TSC10:      Calibrate Point: %d Pos: X:%d->%d
> Y:%d->%d\n", 2, calPts[2].x, samplePts[2].x, calPts[2].y,
> samplePts[2].y);
>               printk(KERN_INFO "TSC10:      Calibrate Point: %d Pos: X:%d->%d
> Y:%d->%d\n", 3, calPts[3].x, samplePts[3].x, calPts[3].y,
> samplePts[3].y);
>               printk(KERN_INFO "TSC10:      Calibrate Point: %d Pos: X:%d->%d
> Y:%d->%d\n", 4, calPts[4].x, samplePts[4].x, calPts[4].y,
> samplePts[4].y);
>               if (c_mode == 1)
>                   setCalibrationMatrix(&samplePts[0], &calPts[0], &calMatris);
>               else {
>                   send_cdata = 1;
>                   minx = samplePts[0].x;
>                   miny = samplePts[0].y;
>                   maxx = samplePts[3].x;
>                   maxy = samplePts[3].y;
>                   midx = (maxx - minx);
>                   midy = (maxy - miny);
>                   ratex = 1024000l / midx;
>                   ratey = 1024000l / midy;
>                   printk("TSC-10 Calibration: RateX = %d RateY = %d\n", ratex,
> ratey);
>               }
>               in_calibrate = 0;
>               break;
>       }
>       return count;
> }
> 
> static int __init tsc10_init (void)
> {
>        int result;
> 
>        result = usb_register (&tsc10_driver);
>        if (result == 0)
>                info (DRIVER_VERSION " : " DRIVER_DESC);
> 
>        proc_dir = proc_mkdir("calibrate", NULL);
> 
>        if (!proc_dir) 
>       return -ENOMEM;
>       
>        proc_file = create_proc_entry("tsc10usb", 0666, proc_dir);
>        if (!proc_file)  
>         return -ENOMEM;
>       
>        proc_file->read_proc = proc_read;
>        proc_file->write_proc = proc_write;
>        proc_file->owner = THIS_MODULE;
>        
> #define _SETSAMPLE(p) samplePts[p].x = sp##p##x;samplePts[p].y =
> sp##p##y;
>        
> 
>        _SETSAMPLE(0)
>        _SETSAMPLE(1)
>        _SETSAMPLE(2)
>        _SETSAMPLE(3)
> 
> #define _SETPOINT(n) calPts[n].x = p##n##x;calPts[n].y = p##n##y;
> 
>        _SETPOINT(0)
>        _SETPOINT(1)
>        _SETPOINT(2)
>        _SETPOINT(3)
> 
>        minx = 0;
>        miny = 0;
>        maxx = 1024;
>        maxy = 1024;
>        midx = 1024;
>        midy = 1024;
>        ratex = 1000;
>        ratex = 1000;
> 
>        if (calmode > -1 && calmode < 3) {
>           switch (calmode) {
>               case 0:
>                   break;
>               case 1:
>                   setCalibrationMatrix(&samplePts[0], &calPts[0], &calMatris);
>                   break;
>               case 2:
>                   send_cdata = 1;
>                   minx = samplePts[0].x;
>                   miny = samplePts[0].y;
>                   maxx = samplePts[3].x;
>                   maxy = samplePts[3].y;    
>                   midx = (maxx - minx);
>                   midy = (maxy - miny);
>                   ratex = 1024000l / midx;
>                   ratey = 1024000l / midy;
>                   printk("TSC-10 Calibration: RateX = %d RateY = %d\n", ratex,
> ratey);
>           }
>        }
>          
>        if (debug)
>           printk(KERN_INFO "TSC-10: Initialization completed..\n");
> 
>        return result;
> }
> 
> static void __exit tsc10_exit (void)
> {
>        usb_deregister (&tsc10_driver);
>        remove_proc_entry("tsc10usb", proc_dir);
>        remove_proc_entry("calibrate", NULL);
> }
> 
> module_init (tsc10_init);
> module_exit (tsc10_exit);
> 
> 
> 
> 


-------------------------------------------------------
This SF.Net email is sponsored by:
Sybase ASE Linux Express Edition - download now for FREE
LinuxWorld Reader's Choice Award Winner for best database on Linux.
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to