너무나 돌아온 느낌이다. 시리얼 통신으로 터치스크린 이벤트 좌표값을 가져오기 위해서 구현하는 것인데... 원래는 USB로 할 예정이지만, 그 전에 시리얼로 한번 해보는 것이다. 특별한 설정 없이도 되는 줄 알고.. 하지만, 시리얼 디바이스 드라이버 구현보다는, 연결에 어려움이 꽤 있었다.
우선 kernel의 driver/input/touchscreen/mtouch.c 파일의 내용을 수정해서 새로운 uv_mtd 장치에 대한 시리얼 디바이스 드라이버를 작성하였다.
static int __init mtouch_init(void)
{
return serio_register_driver(&mtouch_drv);
}
static void __exit mtouch_exit(void)
{
serio_unregister_driver(&mtouch_drv);
}
module_init(mtouch_init);
module_exit(mtouch_exit);
위 소스는 모듈의 등록과 해제를 담당하는 루틴으로, 보면 insmod 해당모듈.ko를 하게 되면, 그냥 serio_register_driver이 호출되고, 드라이버가 새로이 등록되버린 상태로 가만히 있게 된다.
static irqreturn_t mtouch_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct mtouch* mtouch = serio_get_drvdata(serio);
mtouch->data[mtouch->idx] = data;
if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
mtouch_process_format_tablet(mtouch);
else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
mtouch_process_response(mtouch);
else
printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
return IRQ_HANDLED;
}
위 루틴은 해당 드라이버의 인터럽트 처리 부분이다. 즉, 시리얼 포트(ttyS0)를 통해 데이터가 들어오면, 위 루틴에서 처리를 담당하는 것이다. 이 말은, 데이터가 들어오게 되면 무조건 인터럽트가 걸리게 된다는 것으로, 이 함수에 들어와야 정상이다.. 하지만, 단순히 모듈을 적재하는 것으로 인터럽트를 연결하진 못했다. 이 전에 인터럽트 자체가 등록이 되지 않은 상황이었다. ㅡ.ㅜ
static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
{
struct mtouch *mtouch;
struct input_dev *input_dev;
int err;
mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL);
input_dev = input_allocate_device();
if (!mtouch || !input_dev) {
err = -ENOMEM;
goto fail1;
}
mtouch->serio = serio;
mtouch->dev = input_dev;
snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
input_dev->name = "MicroTouch Serial TouchScreen";
input_dev->phys = mtouch->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_MICROTOUCH;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
input_set_abs_params(mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0);
serio_set_drvdata(serio, mtouch);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(mtouch->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(mtouch);
return err;
}
우선 인터럽트를 등록하는 위 connect 함수가 호출되어야 한다. 하지만, 이 함수 역시 모듈 적재만으론 되지 않았다. 솔직히 이 문제를 해결하기 위해 약 3일간 밤낮없이 고생한 것 같다. 구글에 검색을 해봐도 이 문제에 봉착한 경우만 있지, 해결 방법에 대해선 별다른 말이 없었기 때문이다. 그 과정에서 알게 된 것이 setserial과 inputattach 프로그램 뿐이었고, 이것에 대한 자세한 설명도 없는 상황이었다.
/*
* The serio driver structure.
*/
static struct serio_device_id mtouch_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_MICROTOUCH,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, mtouch_serio_ids);
static struct serio_driver mtouch_drv = {
.driver = {
.name = "mtouch",
},
.description = DRIVER_DESC,
.id_table = mtouch_serio_ids,
.interrupt = mtouch_interrupt,
.connect = mtouch_connect,
.disconnect = mtouch_disconnect,
};
위 소스와 같이 mtouch_drv는 mtouch_init 함수에 의해서 시리얼 디바이스 드라이버로 등록이 되지만, 실제로 .connect로 정의된 mtouch_connect 함수는 호출이 되지 않는 문제...
결국은, 구글 검색의 힘(해커들의 질의응답... 검색어는 "lagacy serial driver .connect")으로 해결할 수 있었다.
- 참고사이트1 : http://kerneltrap.org/mailarchive/linux-kernel-mentors/2007/12/5/477437
- 참고사이트2 : http://lkml.org/lkml/2007/6/19/254 - Writing a driver for a legacy serial device
- 참고사이트3 : http://lkml.indiana.edu/hypermail/linux/kernel/0706.2/1755.html
The problem is that taos_connect is never called. I suppose that I need
different values for .type, .proto or .id, except that I just don't
know what to put there. I tried a few random values without success.
What's the trick?
참고로 위 질문에서 나의 문제와 똑같다는 것을 느끼게 되었다. 이 never called라는 메시지가 정말 반가웠다 ㅡ.ㅜ
해당 글의 쓰레드를 조금 추적해서 들어가면 inputattach.c 소스를 구할 수 있고(http://linuxconsole.cvs.sourceforge.net/viewvc/*checkout*/linuxconsole/ruby/utils/inputattach.c), 이 프로그램에 새로운 시리얼 디바이스의 속성을 지정하고, 실행하면 해당 시리얼 디바이스 드라이버와 연결된다는 것을 알게 되었다.
inputattach를 실제 실행하면, 키보드 입력을 받게 되어 있어서 어떻게 사용하는지 조금 난해했었다.
kernel/Documentation/input/joystick.txt 문서에서 inputattach -xxx /dev/tts/X & 를 보고, 이렇게 하니 잘 되었다;;
May 30 09:55:29 mola_server uv_mtd_init
May 30 09:55:59 mola_server serio: Serial port ttyS0
May 30 09:55:59 mola_server uv_mtd_connect
May 30 09:55:59 mola_server uv_mtd ttyS0/serio0/input0
May 30 09:55:59 mola_server input: UV Serial Multi-TouchScreen as /class/input/input13
May 30 09:56:12 mola_server uv_mtd_interrupt
May 30 09:56:12 mola_server uv_mtd unknown/unsynchronized data from device, byte 53
May 30 09:56:12 mola_server uv_mtd_interrupt
May 30 09:56:12 mola_server uv_mtd unknown/unsynchronized data from device, byte 63
May 30 09:56:12 mola_server uv_mtd_interrupt
May 30 09:56:12 mola_server uv_mtd unknown/unsynchronized data from device, byte 72
위 메시지는 커널의 메시지이며, insmod uv_mtd.ko를 하고 ./inputattach --uv_mtd /dev/ttyS0 & 를 한 후, 시리얼을 통해 데이터를 보낸 상태이다. 아직 인터럽트에서 제대로 처리를 하지 않아 위 메시지가 나왔지만, 인터럽트 내에 제대로 진입한 것을 볼 수 있다.;;
p.s.#1 이거 안되면 드라이버단에서 sys_open( /dev/ttyS0 )을 해서 처리하려고 했었다..
장치에서 값이 들어오든 안들어오든 무조건 blocking된 상태에서 말이다.;;; 그래도 다행이다. 드라이버 단에서 되서~
p.s.#2 앞으로는 이벤트 드라이버와 연결해서 시리얼에서 온 데이터를 이벤트화 하면 된다.
(이벤트 드라이버는 이미 테스트 종료 상태 ^^;;)