> 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