Jump to content

    

ADS7843 драйвер

Озадачился прикручиванием сабжевого контроллера тачскрина в linux ...

Вообще, в ядре уже есть драйвер ADS784X, но он расчитан на SPI соединение и уж очень громоздкий (черт ногу сломит), мой чип подключен не к SPI и соответственно буду эмулировать через GPIO.

Решил взять за основу "hp680_ts_input", он просто периодически опрашивает состояние и если определяет нажатие обновляет данные.

Итак, вырезал его специфическую часть, убрал анализ нажатия, сделав постоянное обновление координат.

Собираю, запускаю - драйвер встал нормально, но /proc/interrupts для моего драйвера не показывает постоянно увеличивающегося количества прерываний, оно вообще только один раз произошло, хотя должно 20 раз в секунду шпарить ...

#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/delay.h>
#define MODNAME "hp680_ts_input"
#define HP680_TS_ABS_X_MIN      40
#define HP680_TS_ABS_X_MAX      950
#define HP680_TS_ABS_Y_MIN      80
#define HP680_TS_ABS_Y_MAX      910
#define PHDR    0xa400012e
#define SCPDR   0xa4000136

#define HP680_TS_IRQ 35

static void do_softint(struct work_struct *work);
static struct input_dev *hp680_ts_dev;
static DECLARE_DELAYED_WORK(work, do_softint);

static void do_softint(struct work_struct *work)
{
        int absx = 0, absy = 0;
        u8 scpdr;
        int touched = 0;
                absx=100;
                absy=100;
                input_report_key(hp680_ts_dev, BTN_TOUCH, 1);
                input_report_abs(hp680_ts_dev, ABS_X, absx);
                input_report_abs(hp680_ts_dev, ABS_Y, absy);

        input_sync(hp680_ts_dev);
        enable_irq(HP680_TS_IRQ);
}
static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
{
        disable_irq_nosync(irq);
        schedule_delayed_work(&work, HZ / 20);
        return IRQ_HANDLED;
}
static int __init hp680_ts_init(void)
{
        int err;
        hp680_ts_dev = input_allocate_device();
        if (!hp680_ts_dev)
                return -ENOMEM;
        hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
        hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
        input_set_abs_params(hp680_ts_dev, ABS_X,
                HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
        input_set_abs_params(hp680_ts_dev, ABS_Y,
                HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
        hp680_ts_dev->name = "HP Jornada touchscreen";
        hp680_ts_dev->phys = "input0";

        if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
                        IRQF_DISABLED, MODNAME, 0) < 0) {
                printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
                       HP680_TS_IRQ);
                err = -EBUSY;
                goto fail1;
        }

        err = input_register_device(hp680_ts_dev);
        if (err)
                goto fail2;
        return 0;

fail2: free_irq(HP680_TS_IRQ, NULL);
        cancel_delayed_work(&work);
        flush_scheduled_work();
fail1: input_free_device(hp680_ts_dev);
        return err;
}
static void __exit hp680_ts_exit(void)
{
        free_irq(HP680_TS_IRQ, NULL);
        cancel_delayed_work(&work);
        flush_scheduled_work();
        input_unregister_device(hp680_ts_dev);
}
module_init(hp680_ts_init);
module_exit(hp680_ts_exit);
MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
MODULE_LICENSE("GPL");

Еще вопрос, как это хозяйство опрашивать, собрал либу tslib (сконфигурировав ее вход на input), при попытке запуска ts_print получаю ругань на отсутствующее устройство, которого действительно нет, созданием устройств у меня ведает mdev и оно почему то не создало устройство, хотя драй вер выдает при запуске:

input: HP Jornada touchscreen as /class/input/input0

Share this post


Link to post
Share on other sites

Попробовал подойти по другому - решил сначала обработчик интервального таймера запустить, взял пример отсюда, а он зараза на моем ядре (2,6,24) в принципе не работает (ядро в панике вылетает при попытке первого планирования) :( ...

Share this post


Link to post
Share on other sites
Попробовал подойти по другому - решил сначала обработчик интервального таймера запустить, взял пример отсюда, а он зараза на моем ядре (2,6,24) в принципе не работает (ядро в панике вылетает при попытке первого планирования) :( ...

 

А чем не устраивают обычные таймеры в ядре ? Имхо намного проще и главное - работают :) Например

 

#define REFR_TIME   (HZ / 20)

struct timer_list   timer;

static void my_timer(unsigned long param)
{
    struct my_param *par = (struct my_param *)param;

    /*
        делаем свои дела 
    */

    /* заряжаем таймер на следующий период */
    mod_timer(&timer, jiffies + REFR_TIME);    
}

    /* где-то в ф-ции инициализации */
    init_timer(&timer);
    timer.data = (unsigned long)param;
    timer.function = my_timer;
    timer.expires = jiffies + REFR_TIME;
    add_timer(&timer);

Edited by sasamy

Share this post


Link to post
Share on other sites
Собираю, запускаю - драйвер встал нормально, но /proc/interrupts для моего драйвера не показывает постоянно увеличивающегося количества прерываний, оно вообще только один раз произошло, хотя должно 20 раз в секунду шпарить ...

 

Кстати - с чего вы взяли что прерывания должны срабатывать 20 раз в секунду ? Насколько я понял прерывание срабатывает по внешнему событию а потом через 1/20 секунды заускается отложенное действие (по сути отложенная обработка прерывания), после чего прерывания от ts снова разрешены.

Share this post


Link to post
Share on other sites

Спасибо, буду разбираться ...

Share this post


Link to post
Share on other sites

Далее, прикрутил таймер:

#define REFR_TIME (HZ / 2)
struct timer_list timer;

static struct input_dev *hp680_ts_dev;

static DECLARE_DELAYED_WORK(work, do_softint);

static void my_timer(unsigned long param)
{
    struct my_param *par = (struct my_param *)param;
    int absx = 0, absy = 0;
    static unsigned int mtimer=0;
    static int touched = 0;
    
    touched=(touched+1)&1;
    if(touched)
    {
    input_report_key(hp680_ts_dev, BTN_TOUCH,1);
    input_report_abs(hp680_ts_dev, ABS_X, 0x10);
    input_report_abs(hp680_ts_dev, ABS_Y, 0x20);
    }
    else
    {
        input_report_key(hp680_ts_dev, BTN_TOUCH,0);
    }
        
    input_sync(hp680_ts_dev);
    mod_timer(&timer, jiffies + REFR_TIME);
}

static int __init hp680_ts_init(void)
{
    int err;
    init_timer(&timer);
//    timer.data=(unsigned long)param;
    timer.function= my_timer;
    timer.expires = jiffies + REFR_TIME;
    add_timer(&timer);        
    
    hp680_ts_dev = input_allocate_device();
    if (!hp680_ts_dev)
        return -ENOMEM;
    hp680_ts_dev->name = "HP Jornada touchscreen";
    hp680_ts_dev->phys = "hp680_ts/input0";
    hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
    hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    input_set_abs_params(hp680_ts_dev, ABS_X,
        HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
    input_set_abs_params(hp680_ts_dev, ABS_Y,
        HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
    err = input_register_device(hp680_ts_dev);
    if (err)
        goto fail2;
    return 0;
fail2:    free_irq(HP680_TS_IRQ, NULL);
    cancel_delayed_work(&work);
    flush_scheduled_work();
fail1:    input_free_device(hp680_ts_dev);
    return err;
}
static void __exit hp680_ts_exit(void)
{
    free_irq(HP680_TS_IRQ, NULL);
    cancel_delayed_work(&work);
    flush_scheduled_work();
    input_unregister_device(hp680_ts_dev);
}

При запуске ядра вижу

input: HP Jornada touchscreen as /class/input/input0

mdev создает в /dev устройство mouse0

Если пытаться читать устройство - получаю данные с периодичностью таймера, но сами данные явно не от туда, в вечном цикле получаю 08 00 00 09 00 00 ...

Собираю TSLIB, конфигурирую ее вход как input, запускаю ts_print - тишина (сам тест успешно запустился, но никаких данных не регистрирует).

Конфигурирую вход TSLIB как любое из других устройств из ей поддерживаемых, ts_print начинает регистрировать поступление данных, но опять явно не от туда, например:

TS_READ----> x = -22893336, y = -30062890, pressure = 94162884
3749682.875638252: -22893336 -30062890 94162884
TS_READ----> x = -22893336, y = 73416365, pressure = 49743714
3749682.875638252: -22893336 73416365 49743714
TS_READ----> x = -22893336, y = 63991277, pressure = 40343394

Перепробовал разные устройства, картина одинаковая, Х - постоянное значение (причем, при перезапуске теста меняется), остальные болтаются.

На лицо несоответствие каких то структур или указатель на них неверно передается, но в самом драйвере (причем и в некоторых других так же) ни слова об объявлении структуры данных, все через input_report_abs

Share this post


Link to post
Share on other sites

А у меня ругается на отсутствие определения BIT_MASK и BIT_WORD

в каком файле они дефайняться я так и не могу понять.

Подскажите где найти

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this