一,SiS USB触摸简介
SiS USB 触摸屏通常是一种外接式触摸屏设备,通过 USB 接口连接到计算机或其他设备上。这种触摸屏设备可以提供触摸输入功能,用户可以通过手指或触控笔在屏幕上进行操作,实现点击、拖动、缩放等操作。
SiS USB 触摸屏通常需要安装相应的驱动程序才能正常工作,在计算机系统中被识别为触摸输入设备。驱动程序会将触摸屏输入转换为计算机可识别的信号,从而实现触摸屏在操作系统中的正常使用。
二,驱动文件配置
1. hid_sis内核模块驱动文件
hid-sis_ctrl.c :在Linux内核中,HID设备驱动程序负责与各种输入设备(如键盘、鼠标、游戏手柄等)进行通信和管理。包含与特定类型的HID设备通信的代码实现,包括设备的初始化、数据传输、事件处理等功能。这个文件可能会被编译到内核中,以便在系统启动时加载并与相应的HID设备进行交互。
/*
* Character device driver for SIS multitouch panels control
*
* Copyright (c) 2023 SIS, Ltd.
*
*/
/*
* 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/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
#include <linux/init.h>
//update FW
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h> //copy_from_user() & copy_to_user()
#include "hid-ids.h"
#include "hid-sis_ctrl.h"
static int sis_char_devs_count = 1; /* device count */
static int sis_char_major = 0;
static struct cdev sis_char_cdev;
static struct class *sis_char_class = NULL;
static struct hid_device *hid_dev_backup = NULL; //backup address
static struct urb *backup_urb = NULL;
#define REPORTID_21_LEN 64
#define REPORTID_25_LEN 320
#define REPORTID_29_LEN 576
#define REPORTID_2D_LEN 832
#ifdef CONFIG_DEBUG_HID_SIS_UPDATE_FW
#define DBG_FW(fmt, arg...) printk( fmt, ##arg )
void sis_dbg_dump_array( u8 *ptr, u32 size)
{
u32 i;
for (i=0; i<size; i++)
{
DBG_FW ("%02X ", ptr[i]);
if( ((i+1)&0xF) == 0)
DBG_FW ("\n");
}
if( size & 0xF)
DBG_FW ("\n");
}
#else
#define DBG_FW(...)
#define sis_dbg_dump_array(...)
#endif // CONFIG_DEBUG_HID_SIS_UPDATE_FW
int sis_cdev_open(struct inode *inode, struct file *filp) //20120306 Yuger ioctl for tool
{
struct usbhid_device *usbhid;
DBG_FW( "%s\n" , __FUNCTION__ );
//20110511, Yuger, kill current urb by method of usbhid_stop
if ( !hid_dev_backup )
{
printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
return -1;
}
usbhid = hid_dev_backup->driver_data;
printk( KERN_INFO "sys_sis_HID_stop\n" );
//printk( KERN_INFO "hid_dev_backup->vendor, hid_dev_backup->product = %x %x\n", hid_dev_backup->vendor, hid_dev_backup->product );
//20110602, Yuger, fix bug: not contact usb cause kernel panic
if( !usbhid )
{
printk( KERN_INFO "(stop)usbhid is not initialized yet" );
return -1;
}
else if ( !usbhid->urbin )
{
printk( KERN_INFO "(stop)usbhid->urbin is not initialized yet" );
return -1;
}
else if (hid_dev_backup->vendor == USB_VENDOR_ID_SIS_TOUCH)
{
usb_fill_int_urb(backup_urb, usbhid->urbin->dev, usbhid->urbin->pipe,
usbhid->urbin->transfer_buffer, usbhid->urbin->transfer_buffer_length,
usbhid->urbin->complete, usbhid->urbin->context, usbhid->urbin->interval);
clear_bit( HID_STARTED, &usbhid->iofl );
set_bit( HID_DISCONNECTED, &usbhid->iofl );
usb_kill_urb( usbhid->urbin );
usb_free_urb( usbhid->urbin );
usbhid->urbin = NULL;
return 0;
}
else
{
printk (KERN_INFO "This is not a SiS device");
return -801;
}
}
int sis_cdev_release(struct inode *inode, struct file *filp)
{
//20110505, Yuger, rebuild the urb which is at the same urb address, then re-submit it
int ret;
struct usbhid_device *usbhid;
unsigned long flags;
DBG_FW( "%s: " , __FUNCTION__ );
if ( !hid_dev_backup )
{
printk( KERN_INFO "(stop)hid_dev_backup is not initialized yet" );
return -1;
}
usbhid = hid_dev_backup->driver_data;
printk( KERN_INFO "sys_sis_HID_start" );
if( !usbhid )
{
printk( KERN_INFO "(start)usbhid is not initialized yet" );
return -1;
}
if( !backup_urb )
{
printk( KERN_INFO "(start)backup_urb is not initialized yet" );
return -1;
}
clear_bit( HID_DISCONNECTED, &usbhid->iofl );
usbhid->urbin = usb_alloc_urb( 0, GFP_KERNEL );
if( !backup_urb->interval )
{
printk( KERN_INFO "(start)backup_urb->interval does not exist" );
return -1;
}
usb_fill_int_urb(usbhid->urbin, backup_urb->dev, backup_urb->pipe,
backup_urb->transfer_buffer, backup_urb->transfer_buffer_length,
backup_urb->complete, backup_urb->context, backup_urb->interval);
usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
set_bit( HID_STARTED, &usbhid->iofl );
//method at hid_start_in
spin_lock_irqsave( &usbhid->lock, flags );
ret = usb_submit_urb( usbhid->urbin, GFP_ATOMIC );
spin_unlock_irqrestore( &usbhid->lock, flags );
//yy
DBG_FW( "ret = %d", ret );
return ret;
}
ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
int timeout = 0;
u8 *rep_data = NULL;
u8 *temp_data = NULL;
u16 size = 0;
long rep_ret;
struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf);
#if IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX)
u16 reportID = 0;
#else
int actual_length = 0;
#endif
DBG_FW( "%s\n", __FUNCTION__ );
temp_data = kzalloc(count, GFP_KERNEL);
if(!temp_data) {
printk( KERN_INFO "kzalloc temp_data fail\n");
return (-12);
}
if ( copy_from_user( temp_data, (void*)buf, count) ) {
printk( KERN_INFO "copy_from_user(temp_data) fail\n" );
//free allocated data
kfree( temp_data );
temp_data = NULL;
return -19;
}
#if IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX)
switch (temp_data[0]) {
case 0x21:
size = (((u16)(temp_data[REPORTID_21_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_21_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_21_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_21_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_21_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_21_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_21_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_21_LEN + 7] & 0xff);
reportID = 0x0321;
DBG_FW("%s Report ID : 0x21\n" , __FUNCTION__);
break;
case 0x25:
size = (((u16)(temp_data[REPORTID_25_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_25_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_25_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_25_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_25_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_25_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_25_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_25_LEN + 7] & 0xff);
reportID = 0x0325;
DBG_FW("%s Report ID : 0x25\n" , __FUNCTION__);
break;
case 0x29:
size = (((u16)(temp_data[REPORTID_29_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_29_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_29_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_29_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_29_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_29_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_29_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_29_LEN + 7] & 0xff);
reportID = 0x0329;
DBG_FW("%s Report ID : 0x29\n" , __FUNCTION__);
break;
case 0x2d:
size = (((u16)(temp_data[REPORTID_2D_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_2D_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_2D_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_2D_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_2D_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_2D_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_2D_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_2D_LEN + 7] & 0xff);
reportID = 0x032d;
DBG_FW( "%s Report ID : 0x2d\n" , __FUNCTION__ );
break;
default:
break;
}
#else
size = (((u16)(temp_data[64] & 0xff)) << 24) + (((u16)(temp_data[65] & 0xff)) << 16) +
(((u16)(temp_data[66] & 0xff)) << 8) + (u16)(temp_data[67] & 0xff);
timeout = (((int)(temp_data[68] & 0xff)) << 24) + (((int)(temp_data[69] & 0xff)) << 16) +
(((int)(temp_data[70] & 0xff)) << 8) + (int)(temp_data[71] & 0xff);
DBG_FW("%s Report ID : 0x0a\n" , __FUNCTION__);
#endif
kfree(temp_data);
temp_data = NULL;
DBG_FW("timeout = %d, size %d\n", timeout, size);
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
if (!access_ok(VERIFY_WRITE, buf, size)) {
#else
if (!access_ok(buf, size)) {
#endif
printk(KERN_INFO "cannot access user space memory\n");
return -11;
}
rep_data = kzalloc(size, GFP_KERNEL);
if (!rep_data) {
printk(KERN_INFO "kzalloc rep_data fail\n");
return -12;
}
if (copy_from_user(rep_data, (void*)buf, size)) {
printk(KERN_INFO "copy_to_user fail(rep_data)\n");
//free allocated data
kfree(rep_data);
rep_data = NULL;
return -19;
}
#if IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX)
rep_ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x01, (USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE),
reportID, 0, rep_data, size, timeout);
DBG_FW("%s: rep_data = ", __FUNCTION__);
sis_dbg_dump_array(rep_data, 8);
if (copy_to_user((void*)buf, rep_data, rep_ret)) {
printk(KERN_INFO "copy_to_user fail(buf)\n");
//free allocated data
kfree(rep_data);
rep_data = NULL;
return -19;
}
#else
rep_ret = usb_interrupt_msg(dev, backup_urb->pipe,
rep_data, size, &actual_length, timeout);
DBG_FW("%s: rep_data = ", __FUNCTION__);
sis_dbg_dump_array(rep_data, 8);
if (rep_ret == 0) {
if (copy_to_user((void*)buf, rep_data, actual_length)) {
printk(KERN_INFO "copy_to_user fail(buf)\n");
//free allocated data
kfree(rep_data);
rep_data = NULL;
return -19;
}
}
#endif
//free allocated data
kfree(rep_data);
rep_data = NULL;
DBG_FW("%s: rep_ret = %ld\n", __FUNCTION__, rep_ret);
return rep_ret;
}
ssize_t sis_cdev_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
int timeout = 0;
u8 *rep_data = NULL;
u8 *temp_data = NULL;
u16 size = 0;
long rep_ret;
struct usb_interface *intf = to_usb_interface(hid_dev_backup->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf);
#if IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX)
u16 reportID = 0;
#else
int actual_length = 0;
struct usbhid_device *usbhid = hid_dev_backup->driver_data;
#endif
DBG_FW( "%s\n", __FUNCTION__ );
temp_data = kzalloc(count, GFP_KERNEL);
if(!temp_data)
{
printk( KERN_INFO "kzalloc temp_data fail\n");
return (-12);
}
if ( copy_from_user( temp_data, (void*)buf, count) )
{
printk( KERN_INFO "copy_from_user(temp_data) fail\n" );
//free allocated data
kfree( temp_data );
temp_data = NULL;
return -19;
}
#if IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX)
switch (temp_data[0]) {
case 0x21:
size = (((u16)(temp_data[REPORTID_21_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_21_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_21_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_21_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_21_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_21_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_21_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_21_LEN + 7] & 0xff);
reportID = 0x0321;
DBG_FW("%s Report ID : 0x21\n" , __FUNCTION__);
break;
case 0x25:
size = (((u16)(temp_data[REPORTID_25_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_25_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_25_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_25_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_25_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_25_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_25_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_25_LEN + 7] & 0xff);
reportID = 0x0325;
DBG_FW("%s Report ID : 0x25\n" , __FUNCTION__);
break;
case 0x29:
size = (((u16)(temp_data[REPORTID_29_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_29_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_29_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_29_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_29_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_29_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_29_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_29_LEN + 7] & 0xff);
reportID = 0x0329;
DBG_FW("%s Report ID : 0x29\n" , __FUNCTION__);
break;
case 0x2d:
size = (((u16)(temp_data[REPORTID_2D_LEN] & 0xff)) << 24)
+ (((u16)(temp_data[REPORTID_2D_LEN + 1] & 0xff)) << 16)
+ (((u16)(temp_data[REPORTID_2D_LEN + 2] & 0xff)) << 8)
+ (u16)(temp_data[REPORTID_2D_LEN + 3] & 0xff);
timeout = (((int)(temp_data[REPORTID_2D_LEN + 4] & 0xff)) << 24)
+ (((int)(temp_data[REPORTID_2D_LEN + 5] & 0xff)) << 16)
+ (((int)(temp_data[REPORTID_2D_LEN + 6 ] & 0xff)) << 8)
+ (int)(temp_data[REPORTID_2D_LEN + 7] & 0xff);
reportID = 0x032d;
DBG_FW("%s Report ID : 0x2d\n" , __FUNCTION__);
break;
default:
break;
}
#else
size = (((u16)(temp_data[64] & 0xff)) << 24) + (((u16)(temp_data[65] & 0xff)) << 16) +
(((u16)(temp_data[66] & 0xff)) << 8) + (u16)(temp_data[67] & 0xff);
timeout = (((int)(temp_data[68] & 0xff)) << 24) + (((int)(temp_data[69] & 0xff)) << 16) +
(((int)(temp_data[70] & 0xff)) << 8) + (int)(temp_data[71] & 0xff);
DBG_FW("%s Report ID : 0x09\n" , __FUNCTION__);
#endif
DBG_FW("timeout = %d, size %d\n", timeout, size);
kfree(temp_data);
temp_data = NULL;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
if (!access_ok(VERIFY_WRITE, buf, size)) {
#else
if (!access_ok(buf, size)) {
#endif
printk(KERN_INFO "cannot access user space memory\n");
return -11;
}
rep_data = kzalloc(size, GFP_KERNEL);
if (!rep_data) {
printk(KERN_INFO "kzalloc rep_data fail\n");
return -12;
}
if (copy_from_user(rep_data, (void*)buf, size)) {
printk(KERN_INFO "copy_to_user fail(rep_data)\n");
//free allocated data
kfree(rep_data);
rep_data = NULL;
return -19;
}
#if IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX)
rep_ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0x09, (USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE),
reportID, 0, rep_data, size, timeout);
DBG_FW("%s: rep_data = ", __FUNCTION__);
sis_dbg_dump_array(rep_data, 8);
if (copy_to_user((void*)buf, rep_data, rep_ret)) {
printk(KERN_INFO "copy_to_user fail(buf)\n");
//free allocated data
kfree(rep_data);
rep_data = NULL;
return -19;
}
#else
rep_ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
rep_data, size, &actual_length, timeout);
DBG_FW("%s: rep_data = ", __FUNCTION__);
sis_dbg_dump_array(rep_data, size);
if (rep_ret == 0) {
if (copy_to_user((void*)buf, rep_data, actual_length)) {
printk(KERN_INFO "copy_to_user fail(buf)\n");
//free allocated data
kfree(rep_data);
rep_data = NULL;
return -19;
}
}
#endif
DBG_FW("%s: rep_ret = %ld\n", __FUNCTION__, rep_ret);
//free allocated data
kfree(rep_data);
rep_data = NULL;
DBG_FW("End of sys_sis_HID_IO\n");
return rep_ret;
}
//for ioctl
static const struct file_operations sis_cdev_fops = {
.owner = THIS_MODULE,
.read = sis_cdev_read,
.write = sis_cdev_write,
.open = sis_cdev_open,
.release= sis_cdev_release,
};
//for ioctl
int sis_setup_chardev(struct hid_device *hdev)
{
dev_t dev = MKDEV(sis_char_major, 0);
int alloc_ret = 0;
int cdev_err = 0;
int input_err = 0;
struct device *class_dev = NULL;
void *ptr_err;
printk("sis_setup_chardev.\n");
hid_dev_backup = hdev;
backup_urb = usb_alloc_urb(0, GFP_KERNEL); //0721test
if (!backup_urb) {
dev_err(&hdev->dev, "cannot allocate backup_urb\n");
return -ENOMEM;
}
// dynamic allocate driver handle
#ifdef SIS_BRIDGE_ENABLED
alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS_BRIDGE_DEVICE_NAME);
#else
alloc_ret = alloc_chrdev_region(&dev, 0, sis_char_devs_count, SIS_DEVICE_NAME);
#endif
if (alloc_ret)
goto error;
sis_char_major = MAJOR(dev);
cdev_init(&sis_char_cdev, &sis_cdev_fops);
sis_char_cdev.owner = THIS_MODULE;
cdev_err = cdev_add(&sis_char_cdev, MKDEV(sis_char_major, 0), sis_char_devs_count);
if (cdev_err)
goto error;
#ifdef SIS_BRIDGE_ENABLED
printk(KERN_INFO "%s driver(major %d) installed.\n", SIS_BRIDGE_DEVICE_NAME, sis_char_major);
#else
printk(KERN_INFO "%s driver(major %d) installed.\n", SIS_DEVICE_NAME, sis_char_major);
#endif
// register class
#ifdef SIS_BRIDGE_ENABLED
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
sis_char_class = class_create(THIS_MODULE, SIS_BRIDGE_DEVICE_NAME);
#else
sis_char_class = class_create(SIS_BRIDGE_DEVICE_NAME);
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
sis_char_class = class_create(THIS_MODULE, SIS_DEVICE_NAME);
#else
sis_char_class = class_create(SIS_DEVICE_NAME);
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
#endif //SIS_BRIDGE_ENABLED
if (IS_ERR(ptr_err = sis_char_class))
goto err2;
#ifdef SIS_BRIDGE_ENABLED
class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS_BRIDGE_DEVICE_NAME);
#else
class_dev = device_create(sis_char_class, NULL, MKDEV(sis_char_major, 0), NULL, SIS_DEVICE_NAME);
#endif
if (IS_ERR(ptr_err = class_dev))
goto err;
return 0;
error:
if (cdev_err == 0)
cdev_del(&sis_char_cdev);
if (alloc_ret == 0)
unregister_chrdev_region(MKDEV(sis_char_major, 0), sis_char_devs_count);
if (input_err != 0)
printk("sis_ts_bak error!\n");
err:
device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
err2:
class_destroy(sis_char_class);
return -1;
}
EXPORT_SYMBOL(sis_setup_chardev);
void sis_deinit_chardev(struct hid_device *hdev)
{
//for ioctl
dev_t dev;
printk(KERN_INFO "sis_deinit\n");
dev = MKDEV(sis_char_major, 0);
cdev_del(&sis_char_cdev);
unregister_chrdev_region(dev, sis_char_devs_count);
device_destroy(sis_char_class, MKDEV(sis_char_major, 0));
class_destroy(sis_char_class);
usb_kill_urb(backup_urb);
usb_free_urb(backup_urb);
backup_urb = NULL;
hid_dev_backup = NULL;
}
EXPORT_SYMBOL(sis_deinit_chardev);
MODULE_DESCRIPTION("SiS Touchscreen Control Driver");
MODULE_LICENSE("GPL");
hid-sis_ctrl.h :包含了与 HID 设备通信和控制相关的宏定义、结构体定义、函数声明等内容。这些内容通常用于描述 HID 设备的特性、命令格式、数据结构等,以便在驱动程序中使用。
#ifndef __HID_SIS_CTRL_H__
#define __HID_SIS_CTRL_H__
#include <linux/version.h> //LINUX_VERSION_CODE & KERNEL_VERSION
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)
#include <asm/uaccess.h> //copy_from_user() & copy_to_user()
#else
#include <linux/uaccess.h> //copy_from_user() & copy_to_user()
#endif
/* ID-table */
#define USB_VENDOR_ID_SIS_TOUCH 0x0457
#define USB_DEVICE_ID_SIS_TOUCH 0x1905
/* Device node name */
#define HID_SIS95XX // ON/OFF: SiS hydra(6596)/SiS aegis(817)
//#define DEBUG_HID_SIS_UPDATE_FW // ON/OFF
//#define SIS_BRIDGE_ENABLED // ON/OFF
#if IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX) //6596
#define SIS_DEVICE_NAME "sis_hydra_hid_touch_device"
#define SIS_BRIDGE_DEVICE_NAME "sis_hydra_hid_bridge_touch_device"
#else //817
#define SIS_DEVICE_NAME "sis_aegis_hid_touch_device"
#define SIS_BRIDGE_DEVICE_NAME "sis_aegis_hid_bridge_touch_device"
#endif
/* Report id length */
#define REPORTID_21_LEN 64
#define REPORTID_25_LEN 320
#define REPORTID_29_LEN 576
#define REPORTID_2D_LEN 832
#define CTRL 0
#define ENDP_01 1
#define ENDP_02 2
#define DIR_IN 0x1
int sis_cdev_open(struct inode *inode, struct file *filp);
int sis_cdev_release(struct inode *inode, struct file *filp);
ssize_t sis_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
ssize_t sis_cdev_write( struct file *file, const char __user *buf, size_t count, loff_t *f_pos );
int sis_setup_chardev(struct hid_device *hdev);
void sis_deinit_chardev(struct hid_device *hdev);
#endif // __HID_SIS_CTRL_H__
2. 修改专用驱动程序列表
kernel version is >= 4.16
a.hid-multitouch.c修改
引用文件,类定义,启动功能,完成功能,添加设备列表
diff --git a/kernel/drivers/hid/hid-multitouch.c b/kernel/drivers/hid/hid-multitouch.c
index 19dfd8acd0..66399569ce 100644
--- a/kernel/drivers/hid/hid-multitouch.c
+++ b/kernel/drivers/hid/hid-multitouch.c
@@ -43,7 +43,9 @@
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/timer.h>
-
+/* SiSdrv Start */
+#include "hid-sis_ctrl.h"
+/* SiSdrv End */
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
@@ -207,6 +209,9 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_VTL 0x0110
#define MT_CLS_GOOGLE 0x0111
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
+/* SiSdrv Start */
+#define MT_CLS_SIS 0x0457
+/* SiSdrv End */
#define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250
@@ -357,6 +362,12 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_WIN8_PTP_BUTTONS,
},
+ /* SiSdrv Start */
+ { .name = MT_CLS_SIS,
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+ MT_QUIRK_CONTACT_CNT_ACCURATE
+ },
+ /* SiSdrv End */
{ }
};
@@ -1716,6 +1727,18 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
mt_fix_const_fields(hdev, HID_DG_CONTACTID);
+ /* SiSdrv Start */
+ if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+ hdev->quirks |= HID_QUIRK_NOGET;
+ printk(KERN_INFO "sis:sis-probe: quirk = %x\n", hdev->quirks);
+ #ifdef CONFIG_HID_SIS_CTRL
+ ret = sis_setup_chardev(hdev);
+ if (ret)
+ printk( KERN_INFO "sis_setup_chardev fail\n");
+ #endif //CONFIG_HID_SIS_CTRL
+ }
+ /* SiSdrv End */
+
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
return ret;
@@ -1757,6 +1780,13 @@ static void mt_remove(struct hid_device *hdev)
del_timer_sync(&td->release_timer);
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
+
+ /* SiSdrv Start */
+ if (hdev->vendor == USB_VENDOR_ID_SIS_TOUCH) {
+ sis_deinit_chardev(hdev);
+ }
+ /* SiSdrv End */
+
hid_hw_stop(hdev);
}
@@ -2103,6 +2133,12 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) },
+ /* SiSdrv Start */
+ { .driver_data = MT_CLS_SIS,
+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_SIS_TOUCH,
+ HID_ANY_ID) },
+ /* SiSdrv End */
+
/* Generic MT device */
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
b.hid-quirks.c修改
将usb触摸vid添加特殊设备列表中
diff --git a/kernel/drivers/hid/hid-quirks.c b/kernel/drivers/hid/hid-quirks.c
index b9529bed4d..c913bfd889 100644
--- a/kernel/drivers/hid/hid-quirks.c
+++ b/kernel/drivers/hid/hid-quirks.c
@@ -720,6 +720,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
#if IS_ENABLED(CONFIG_HID_ZYDACRON)
{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
#endif
+/* SiSdrv Start */
+#if IS_ENABLED(CONFIG_HID_SIS92XX) || IS_ENABLED(CONFIG_HID_SIS95XX_SIS98XX)
+ { HID_USB_DEVICE(0x0457, HID_ANY_ID) },
+#endif
+/* SiSdrv End */
{ }
};
3. 移植hid_sis驱动
a. 将驱动(hid-sis_ctrl.c,hid-sis_ctrl.h)拷贝到下面的文件夹:
kernel/drivers/hid/
b. 在 Makefile 中添加hid-sis_ctrl设备
kernel/drivers/hid/Makefile:
#/ SiSdrv Start /
obj-$(CONFIG_HID_SIS_CTRL) += hid-sis_ctrl.o
#/ SiSdrv End /
c. 在 Kconfig 中添加hid-sis_ctrl
kernel/drivers/hid/Kconfig:
#/ SiSdrv Start /
config HID_SIS_CTRL
tristate "SiS Touch Device Controller"
depends on HID_MULTITOUCH
default y
help
Support for SiS Touch devices update FW.
menu "SiS touchscreen series"
choice
depends on USB_HID
depends on HID_SIS_CTRL
prompt "SiS controller select"
config HID_SIS95XX_SIS98XX
depends on HID_SIS_CTRL
tristate "SiS 95xx and 98xx series Touch Device"
help
Support for SiS Touch devices that are fully compliant with HID standard.
config HID_SIS92XX
depends on HID_SIS_CTRL
tristate "SiS 92xx series Touch Device"
help
Support for SiS Touch devices that are fully compliant with HID standard.
endchoice
config DEBUG_HID_SIS_UPDATE_FW
bool "SiS Touch device update firmware support debug message enable"
depends on HID_SIS_CTRL
default n
help
Say Y here if you want to enable debug message of
firmware updating for SiS Touch
devices.
endmenu
#/ SiSdrv End /
d. 内核中加载驱动
kernel/arch/arm64/configs/rockchip_defconfig:
CONFIG_HID_SIS95XX_SIS98XX=m
三,系统配置
1.授予sis节点权限
diff --git a/system/core/rootdir/ueventd.rc b/system/core/rootdir/ueventd.rc
index 451f5adf33..28c3d83eb7 100644
--- a/system/core/rootdir/ueventd.rc
+++ b/system/core/rootdir/ueventd.rc
@@ -40,6 +40,10 @@ subsystem sound
/dev/pmsg0 0222 root log
+#sis device SiS95xx
+/dev/sis_hydra_hid_touch_device 0666 root root
+/dev/sis_hydra_hid_bridge_touch_device 0666 root root
+
# kms driver for drm based gpu
/dev/dri/* 0666 root graphics
2. idc文件拷贝到 系统system/usr/idc/目录
rc文件中添加:
PRODUCT_COPY_FILES += \
device/rockchip/rk3399/Vendor_0457_Product_0819.idc:system/usr/idc/Vendor_0457_Product_0819.idc
Vendor_0457_Product_0819.idc:
# Basic Parameters
touch.deviceType = touchScreen
touch.orientationAware = 1
device.internal = 1
四,调试
1.dmesg日志
dmesg | grep sis //检查sis驱动程序加载
2.设备节点
ls -l /dev/sis*
cat /proc/bus/input/devices