Created
February 25, 2017 18:12
-
-
Save alyssarosenzweig/f14b7bdc279bd726801347e42010998c to your computer and use it in GitHub Desktop.
Prelimininary framebuffer driver for Topaz signature pads
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig | |
index 1aeb80e52424..c8bd6991339a 100644 | |
--- a/drivers/hid/Kconfig | |
+++ b/drivers/hid/Kconfig | |
@@ -985,6 +985,12 @@ config HID_ALPS | |
Say Y here if you have a Alps touchpads over i2c-hid or usbhid | |
and want support for its special functionalities. | |
+config HID_TOPAZ | |
+ tristate "Topaz signature pad HID support" | |
+ depends on USB_HID | |
+ ---help--- | |
+ Support for Topaz signature pads that communicate over USB HID. | |
+ | |
endmenu | |
endif # HID | |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile | |
index 4d111f23e801..ee45eb6e70c6 100644 | |
--- a/drivers/hid/Makefile | |
+++ b/drivers/hid/Makefile | |
@@ -94,6 +94,7 @@ obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o | |
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o | |
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o | |
obj-$(CONFIG_HID_TIVO) += hid-tivo.o | |
+obj-$(CONFIG_HID_TOPAZ) += hid-topaz.o | |
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o | |
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o | |
obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o | |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h | |
index 86c95d30ac80..ed3fd69bb9c1 100644 | |
--- a/drivers/hid/hid-ids.h | |
+++ b/drivers/hid/hid-ids.h | |
@@ -1119,4 +1119,8 @@ | |
#define USB_VENDOR_ID_UGTIZER 0x2179 | |
#define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053 | |
+ | |
+#define USB_VENDOR_ID_TOPAZ 0x06A8 | |
+#define USB_DEVICE_ID_TOPAZ_LBK766 0x0043 | |
+ | |
#endif | |
diff --git a/drivers/hid/hid-topaz.c b/drivers/hid/hid-topaz.c | |
new file mode 100644 | |
index 000000000000..bb7a0af5ed7a | |
--- /dev/null | |
+++ b/drivers/hid/hid-topaz.c | |
@@ -0,0 +1,239 @@ | |
+/* | |
+ * HID driver for Topaz signature pads | |
+ * | |
+ * Copyright (c) 2017 Alyssa Rosenzweig | |
+ * | |
+ * Author: Alyssa Rosenzweig <alyssa@rosenzweig.io> | |
+ * | |
+ * This program 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 of the License, or (at your option) | |
+ * any later version. | |
+ */ | |
+ | |
+#include <linux/device.h> | |
+#include <linux/hid.h> | |
+#include <linux/input.h> | |
+#include <linux/module.h> | |
+#include <linux/string.h> | |
+#include <linux/mm.h> | |
+#include <linux/slab.h> | |
+#include <linux/delay.h> | |
+#include <linux/fb.h> | |
+#include <linux/init.h> | |
+ | |
+#include "hid-ids.h" | |
+ | |
+// names from Topaz API documentation | |
+ | |
+#define MODE_CLEAR 0 | |
+#define MODE_COMPLEMENT 1 | |
+#define MODE_OPAQUE 2 | |
+#define MODE_TRANSPARENT 3 | |
+ | |
+static int topaz_send(struct hid_device *dev, u8 *packet, size_t sz) | |
+{ | |
+ int ret; | |
+ | |
+ u8 *buf = kmemdup(packet, sz, GFP_KERNEL); | |
+ if(!buf) | |
+ return -ENOMEM; | |
+ | |
+ if(!dev->ll_driver->output_report) | |
+ return -ENODEV; | |
+ | |
+ ret = hid_hw_output_report(dev, buf, sz); | |
+ kfree(buf); | |
+ | |
+ return ret; | |
+} | |
+ | |
+static int topaz_blit8(struct hid_device *dev, u16 x, u16 y, void* data) | |
+{ | |
+ u8 packet[11 + 8] = {0xF2, 0x07, 0x02, 0, 0, 0, 0, 0, 8, 0, 8}; | |
+ | |
+ packet[3] = (x & 0xFF00) >> 8; | |
+ packet[4] = (x & 0x00FF); | |
+ packet[5] = (y & 0xFF00) >> 8; | |
+ packet[6] = (y & 0x00FF); | |
+ | |
+ memcpy(packet + 11, data, 8); | |
+ | |
+ return topaz_send(dev, packet, sizeof(packet)) & 0; | |
+} | |
+ | |
+static int topaz_bitmap(struct hid_device *dev, u16 xpos, u16 ypos, u16 width, u16 height, u8* data) | |
+{ | |
+ u8 block[8]; | |
+ | |
+ int ret; | |
+ int x, y, row; | |
+ | |
+ int awidth = ((width + 7) >> 3) << 3; | |
+ | |
+ for (x = 0; x < width; x += 8) { | |
+ for (y = 0; y < height; y += 8) { | |
+ /* blit 8x8 block */ | |
+ | |
+ memset(block, 0, sizeof(block)); | |
+ for (row = 0; row < 8 && y + row < height; ++row) { | |
+ block[row] = data[((y + row) * awidth + x) >> 3]; | |
+ } | |
+ | |
+ ret = topaz_blit8(dev, xpos + x, ypos + y, block); | |
+ | |
+ if(ret) | |
+ return ret; | |
+ } | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int topaz_rectangle(struct hid_device *dev, u16 x, u16 y, u16 w, u16 h, u8 mode) | |
+{ | |
+ u8 packet[11] = { 0xFF, 0x12, mode }; | |
+ | |
+ packet[3] = (x & 0xFF00) >> 8; | |
+ packet[4] = (x & 0x00FF); | |
+ packet[5] = (y & 0xFF00) >> 8; | |
+ packet[6] = (y & 0x00FF); | |
+ packet[7] = (w & 0xFF00) >> 8; | |
+ packet[8] = (w & 0x00FF); | |
+ packet[9] = (h & 0xFF00) >> 8; | |
+ packet[10] = (h & 0x00FF); | |
+ | |
+ return topaz_send(dev, packet, sizeof(packet)); | |
+} | |
+ | |
+static int topaz_clear(struct hid_device *dev) | |
+{ | |
+ return topaz_rectangle(dev, 0, 0, 320, 240, 2); | |
+} | |
+ | |
+static int topaz_backlight(struct hid_device *dev, bool on) | |
+{ | |
+ u8 packet[] = { 0x81, 0x02 | (!on) }; | |
+ return topaz_send(dev, packet, sizeof(packet)); | |
+} | |
+ | |
+static int topazfb_probe(struct hid_device *dev); | |
+ | |
+static int topaz_probe(struct hid_device *dev, const struct hid_device_id *id) | |
+{ | |
+ int ret; | |
+ | |
+ ret = hid_parse(dev); | |
+ if(ret) | |
+ goto done; | |
+ | |
+ ret = hid_hw_start(dev, HID_CONNECT_DEFAULT); | |
+ if(ret) | |
+ goto done; | |
+ | |
+ ret = hid_hw_open(dev); | |
+ if(ret) | |
+ goto done; | |
+ | |
+ ret = topaz_clear(dev); | |
+ //if(ret) | |
+ // goto done; | |
+ | |
+ ret = topazfb_probe(dev); | |
+ if(ret) | |
+ goto done; | |
+done: | |
+ return ret; | |
+} | |
+static void topaz_remove(struct hid_device *dev) | |
+{ | |
+ hid_hw_stop(dev); | |
+} | |
+ | |
+static struct fb_fix_screeninfo topazfb_fix = { | |
+ .id = "topaz", | |
+ .type = FB_TYPE_PACKED_PIXELS, | |
+ .visual = FB_VISUAL_MONO01, | |
+ .xpanstep = 0, | |
+ .ypanstep = 0, | |
+ .ywrapstep = 0, | |
+ .accel = FB_ACCEL_NONE | |
+}; | |
+ | |
+struct topazfb_par { | |
+ struct hid_device *hid; | |
+}; | |
+ | |
+static void topazfb_imageblit(struct fb_info *p, const struct fb_image *image) | |
+{ | |
+ if(image->depth != 1) { | |
+ printk("Bad image depth %d\n", image->depth); | |
+ return; | |
+ } | |
+ | |
+ topaz_bitmap(((struct topazfb_par*) p->par)->hid, | |
+ image->dx, image->dy, | |
+ image->width, image->height, | |
+ image->data); | |
+} | |
+ | |
+static void topazfb_fillrect(struct fb_info *p, const struct fb_fillrect *region) | |
+{ | |
+ int mode = region->rop == ROP_XOR ? MODE_COMPLEMENT : MODE_OPAQUE; | |
+ | |
+ topaz_rectangle(((struct topazfb_par*) p->par)->hid, | |
+ region->dx, region->dy, | |
+ region->width, region->height, | |
+ mode); | |
+} | |
+ | |
+static struct fb_ops topazfb_ops = { | |
+ .owner = THIS_MODULE, | |
+ .fb_fillrect = topazfb_fillrect, | |
+ .fb_imageblit = topazfb_imageblit | |
+}; | |
+ | |
+static int topazfb_probe(struct hid_device *dev) | |
+{ | |
+ struct fb_info *info; | |
+ | |
+ info = framebuffer_alloc(sizeof(struct topazfb_par), NULL); | |
+ | |
+ struct topazfb_par *par = info->par; | |
+ par->hid = dev; | |
+ | |
+ info->fbops = &topazfb_ops; | |
+ info->fix = topazfb_fix; | |
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT; | |
+ info->screen_base = kmalloc(320*240>>3, GFP_KERNEL); | |
+ | |
+ info->var.xres = 320; | |
+ info->var.yres = 240; | |
+ | |
+ if(register_framebuffer(info) < 0) { | |
+ return -EINVAL; | |
+ } | |
+ | |
+ return 0; | |
+ | |
+} | |
+ | |
+static const struct hid_device_id topaz_devices[] = { | |
+ { HID_USB_DEVICE(USB_VENDOR_ID_TOPAZ, USB_DEVICE_ID_TOPAZ_LBK766) }, | |
+ { } | |
+}; | |
+ | |
+MODULE_DEVICE_TABLE(hid, topaz_devices); | |
+ | |
+static struct hid_driver topaz_driver = { | |
+ .name = "topaz", | |
+ .id_table = topaz_devices, | |
+ .probe = topaz_probe, | |
+ .remove = topaz_remove | |
+}; | |
+ | |
+module_hid_driver(topaz_driver); | |
+ | |
+MODULE_AUTHOR("Alyssa Rosenzweig <alyssa@rosenzweig.io>"); | |
+MODULE_DESCRIPTION("HID driver for Topaz signature pads"); | |
+MODULE_LICENSE("GPL"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment