내 라즈베리 파이에 usb 타입 xbox360 패드를 붙여 보고싶다. 리눅스 커널 xpad.c에 마이크로소프트 거의 모든 제품 usb vendor, product id가 등록되어 있다. xpad.c가 조금 복작하여 usb 인터럽트 사용 방법을 잘 이해할 수 없다. 키 입력 설정을 어떻게 할지는 나중 문제고… usb-skeletion.c 문서 역시 어렵다. 여기는 인터럽트 대신 대용량 데이터 전송을 목표로 했다.
그 중 가장 비슷한 usb 마우스 드라이버를 커널에서 찾았다. 커널이 성경과 같아 모든 물음에 대한 답을 한다. 200줄 약간 넘어가는 코드로 정말 인터럽트 핵심만 작성했다.
대략 구성은 아래와 같이 된다.
- usb 구조체 선언.
- 사용가능한 usb 번호 찾음, 등록.
- 입력 설정.
- 인터럽트 설정.
usb_fill_int_urb로 call 함수를 등록하여 인터럽트를 사용하면 된다. usb 인터럽트가 일정 주기로 발생한다. 계속 실행하기 위해 인터럽트로 실행할 함수 안에 usb_submit_urb를 넣는다. 알고보면 참 쉬운데 처음 이해하기 어렵다. xpad.c도 같은 방식이다. 처음에 왜 안보였는지…아직 키 입력을 설정하지 않았고, 커널에 test를 출력하도록 했다.
usb 구조체는 여러 정보를 쉽게 사용하려 군더더기를 많이 붙이는 듯 하다.
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/usb/input.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/usb/input.h>
#include <linux/slab.h>
#define USB_XBOX_MINOR_BASE 1
//구조체 선언.
struct usb_xpad{
struct input_dev *dev; /* input device interface */
struct usb_device *udev; /* usb device */
struct usb_interface *intf; /* usb interface */
__u8 irq_in_endpointAddr; /* interrupt in address*/
__u8 irq_out_endpointAddr; /* interrupt out address*/
struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
signed char *data; /* input data */
struct urb *irq_in; /* urb for interrupt in report*/
struct work_struct work; /* init/remove device from callback */
};
static struct usb_xpad *myPad;
static int xpad_init_input(struct usb_xpad *xpad);
static void xpad_deinit_input(struct usb_xpad *xpad);
static void usb_xpad_irq(struct urb *urb){
pr_info("test\n");
usb_submit_urb(urb, GFP_KERNEL);
}
static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad);
static ssize_t xbox_read(struct file *file, char *buffer, size_t count,
loff_t *ppos)
{
pr_info("device was read.\n");
return 0;
}
static ssize_t xbox_write(struct file *file, const char *user_buffer,
size_t count, loff_t *ppos)
{
return 0;
}
static int xbox_open(struct inode *inode, struct file *file)
{
int retval;
struct urb *ptr_urb;
ptr_urb = usb_alloc_urb(0, GFP_KERNEL);
pr_info("device was opened.\n");
if (!ptr_urb) {
retval = -ENOMEM;
goto error;
}
return 0;
error:
if(ptr_urb)
{
usb_free_urb(ptr_urb);
}
return retval;
}
static int xbox_release(struct inode *inode, struct file *file)
{
pr_info("xbox was released\n");
return 0;
}
static int xbox_flush(struct file *file, fl_owner_t id)
{
return 0;
}
static const struct file_operations xboxtest_fops = {
.owner = THIS_MODULE,
.read = xbox_read,
.write = xbox_write,
.open = xbox_open,
.release = xbox_release,
.flush = xbox_flush,
.llseek = noop_llseek,
};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
static struct usb_class_driver xbox_class = {
.name = "xbox%d",
.fops = &xboxtest_fops,
.minor_base = USB_XBOX_MINOR_BASE,
};
static struct usb_driver xpad_test_driver;
static const struct usb_device_id xpad_table[] = {
//{ USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */
//XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */
{USB_DEVICE(0x045e, 0x028e)},
{ }
};
static const signed short xpad_common_btn[] = {
BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
-1 /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, xpad_table);
static int xpad_init_input(struct usb_xpad *xpad)
{
struct input_dev *input_dev;
int i, error;
int pipe, maxp;
input_dev = input_allocate_device();
if (!input_dev)
return -ENOMEM;
xpad->dev = input_dev;
usb_to_input_id(xpad->udev, &input_dev->id);
input_set_drvdata(input_dev, xpad);
/* set up standard buttons */
for (i = 0; xpad_common_btn[i] >= 0; i++)
input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]);
pipe = usb_rcvintpipe(xpad->udev, xpad->irq_in_endpointAddr);
maxp = usb_maxpacket(xpad->udev, pipe, usb_pipeout(pipe));
usb_fill_int_urb(xpad->irq_in, xpad->udev,
pipe, xpad->data,
(maxp > 8 ? 8 : maxp),
usb_xpad_irq, xpad,
xpad->endpoint_in->bInterval);
error = input_register_device(input_dev);
if (error)
goto err_free_dev;
pr_info("usb input was registered\n");
usb_submit_urb(xpad->irq_in, GFP_KERNEL);
return 0; //return ok;
err_free_dev:
input_free_device(input_dev);
return error;
}
static void xpad_deinit_input(struct usb_xpad *xpad)
{
pr_info("xpad is %p, ->dev is %p.\n",xpad, xpad->dev);
if(xpad->dev)
input_unregister_device(xpad->dev);
}
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_xpad *xpad;
struct usb_device *udev;
struct usb_endpoint_descriptor *ep_irq_in,*ep_irq_out;
struct usb_host_interface *intf_tmp;
int retval;
udev = interface_to_usbdev(intf);
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
if (!xpad)
return -ENOMEM;
//초기화
//kzallocd으로 0으로 초기화
//xpad->odata_serial = 0;
xpad->udev = udev;
xpad->intf = intf;
myPad = xpad;
pr_info("xpad is %p, myPad is %p\n", xpad->intf, myPad->intf);
pr_info("interface is %p\n", intf);
//if (intf->cur_altsetting->desc.bNumEndpoints != 2)
// return -ENODEV;
intf_tmp = intf->cur_altsetting;
// find common usb endpoint helper 사용
//https://lkml.org/lkml/2020/9/21/1239
/* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */
retval = usb_find_common_endpoints(intf_tmp,
NULL, NULL, &ep_irq_in, &ep_irq_out);
if (retval) {
dev_err(&intf->dev,
"Could not find both irq-in and irq-out endpoints\n");
goto error;
}
xpad->irq_in_endpointAddr = ep_irq_in->bEndpointAddress;
xpad->irq_out_endpointAddr = ep_irq_out->bEndpointAddress;
xpad->endpoint_in = ep_irq_in;
xpad->endpoint_out = ep_irq_out;
xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_in) {
retval = -ENOMEM;
goto err_free_in_urb;
}
usb_set_intfdata(intf, xpad);
pr_info("[info]: found interrupt end point, in: %d, out: %d", ep_irq_in->bEndpointAddress, ep_irq_out->bEndpointAddress);
pr_info("probe \n");
//pr_info("%04X:%04X pluged \n", id->idVendor, id->idProduct);
retval = usb_register_dev(intf, &xbox_class);
if (retval< 0) {
pr_err("usb_register failed for the "__FILE__ "driver."
"Error number %d", retval);
usb_set_intfdata(intf, NULL);
goto error;
}
/* let the user know what node this device is now attached to */
dev_info(&intf->dev,
"USB Skeleton device now attached to USBSkel-%d",
intf->minor);
//input으로 등록.
xpad_init_input(xpad);
return 0;
error:
kfree(xpad);
return retval;
err_free_in_urb:
usb_free_urb(xpad->irq_in);
return retval;
}
static void xpad_disconnect(struct usb_interface *intf)
{
struct usb_xpad *xpad;
xpad = usb_get_intfdata(intf);
pr_info("xpad address is %p\n", xpad);
xpad_deinit_input(xpad);
usb_deregister_dev(intf, &xbox_class);
usb_set_intfdata(intf, NULL);
kfree(xpad);
pr_info("disconnected\n");
}
static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
{
pr_info("suspendes\n");
return 0;
}
static int xpad_resume(struct usb_interface *intf)
{
pr_info("resumed\n");
return 0;
}
static struct usb_driver xpad_test_driver = {
.name = "xbox360_test",
.probe = xpad_probe,
.disconnect = xpad_disconnect,
.suspend = xpad_suspend,
.resume = xpad_resume,
.id_table = xpad_table,
};
static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad)
{
int retval;
xpad->irq_in= usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_in) {
retval = -ENOMEM;
goto error;
}
return 0;
error:
return retval;
}
// 모듈 loading, unloading 테스트를 위해 과거 방식으로 사용
//module_init(usb_xboxtest_init);
//module_exit(usb_xboxtest_exit);
//Macro
module_usb_driver(xpad_test_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("now0930");
MODULE_DESCRIPTION("Hello, xbox pad!");
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/usb/input.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/usb/input.h>
#include <linux/slab.h>
#define USB_XBOX_MINOR_BASE 1
//구조체 선언.
struct usb_xpad{
struct input_dev *dev; /* input device interface */
struct usb_device *udev; /* usb device */
struct usb_interface *intf; /* usb interface */
__u8 irq_in_endpointAddr; /* interrupt in address*/
__u8 irq_out_endpointAddr; /* interrupt out address*/
struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
signed char *data; /* input data */
struct urb *irq_in; /* urb for interrupt in report*/
struct work_struct work; /* init/remove device from callback */
};
static struct usb_xpad *myPad;
static int xpad_init_input(struct usb_xpad *xpad);
static void xpad_deinit_input(struct usb_xpad *xpad);
static void usb_xpad_irq(struct urb *urb){
pr_info("test\n");
usb_submit_urb(urb, GFP_KERNEL);
}
static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad);
static ssize_t xbox_read(struct file *file, char *buffer, size_t count,
loff_t *ppos)
{
pr_info("device was read.\n");
return 0;
}
static ssize_t xbox_write(struct file *file, const char *user_buffer,
size_t count, loff_t *ppos)
{
return 0;
}
static int xbox_open(struct inode *inode, struct file *file)
{
int retval;
struct urb *ptr_urb;
ptr_urb = usb_alloc_urb(0, GFP_KERNEL);
pr_info("device was opened.\n");
if (!ptr_urb) {
retval = -ENOMEM;
goto error;
}
return 0;
error:
if(ptr_urb)
{
usb_free_urb(ptr_urb);
}
return retval;
}
static int xbox_release(struct inode *inode, struct file *file)
{
pr_info("xbox was released\n");
return 0;
}
static int xbox_flush(struct file *file, fl_owner_t id)
{
return 0;
}
static const struct file_operations xboxtest_fops = {
.owner = THIS_MODULE,
.read = xbox_read,
.write = xbox_write,
.open = xbox_open,
.release = xbox_release,
.flush = xbox_flush,
.llseek = noop_llseek,
};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
static struct usb_class_driver xbox_class = {
.name = "xbox%d",
.fops = &xboxtest_fops,
.minor_base = USB_XBOX_MINOR_BASE,
};
static struct usb_driver xpad_test_driver;
static const struct usb_device_id xpad_table[] = {
//{ USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */
//XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */
{USB_DEVICE(0x045e, 0x028e)},
{ }
};
static const signed short xpad_common_btn[] = {
BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
-1 /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, xpad_table);
static int xpad_init_input(struct usb_xpad *xpad)
{
struct input_dev *input_dev;
int i, error;
int pipe, maxp;
input_dev = input_allocate_device();
if (!input_dev)
return -ENOMEM;
xpad->dev = input_dev;
usb_to_input_id(xpad->udev, &input_dev->id);
input_set_drvdata(input_dev, xpad);
/* set up standard buttons */
for (i = 0; xpad_common_btn[i] >= 0; i++)
input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]);
pipe = usb_rcvintpipe(xpad->udev, xpad->irq_in_endpointAddr);
maxp = usb_maxpacket(xpad->udev, pipe, usb_pipeout(pipe));
usb_fill_int_urb(xpad->irq_in, xpad->udev,
pipe, xpad->data,
(maxp > 8 ? 8 : maxp),
usb_xpad_irq, xpad,
xpad->endpoint_in->bInterval);
error = input_register_device(input_dev);
if (error)
goto err_free_dev;
pr_info("usb input was registered\n");
usb_submit_urb(xpad->irq_in, GFP_KERNEL);
return 0; //return ok;
err_free_dev:
input_free_device(input_dev);
return error;
}
static void xpad_deinit_input(struct usb_xpad *xpad)
{
pr_info("xpad is %p, ->dev is %p.\n",xpad, xpad->dev);
if(xpad->dev)
input_unregister_device(xpad->dev);
}
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_xpad *xpad;
struct usb_device *udev;
struct usb_endpoint_descriptor *ep_irq_in,*ep_irq_out;
struct usb_host_interface *intf_tmp;
int retval;
udev = interface_to_usbdev(intf);
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
if (!xpad)
return -ENOMEM;
//초기화
//kzallocd으로 0으로 초기화
//xpad->odata_serial = 0;
xpad->udev = udev;
xpad->intf = intf;
myPad = xpad;
pr_info("xpad is %p, myPad is %p\n", xpad->intf, myPad->intf);
pr_info("interface is %p\n", intf);
//if (intf->cur_altsetting->desc.bNumEndpoints != 2)
// return -ENODEV;
intf_tmp = intf->cur_altsetting;
// find common usb endpoint helper 사용
//https://lkml.org/lkml/2020/9/21/1239
/* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */
retval = usb_find_common_endpoints(intf_tmp,
NULL, NULL, &ep_irq_in, &ep_irq_out);
if (retval) {
dev_err(&intf->dev,
"Could not find both irq-in and irq-out endpoints\n");
goto error;
}
xpad->irq_in_endpointAddr = ep_irq_in->bEndpointAddress;
xpad->irq_out_endpointAddr = ep_irq_out->bEndpointAddress;
xpad->endpoint_in = ep_irq_in;
xpad->endpoint_out = ep_irq_out;
xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_in) {
retval = -ENOMEM;
goto err_free_in_urb;
}
usb_set_intfdata(intf, xpad);
pr_info("[info]: found interrupt end point, in: %d, out: %d", ep_irq_in->bEndpointAddress, ep_irq_out->bEndpointAddress);
pr_info("probe \n");
//pr_info("%04X:%04X pluged \n", id->idVendor, id->idProduct);
retval = usb_register_dev(intf, &xbox_class);
if (retval< 0) {
pr_err("usb_register failed for the "__FILE__ "driver."
"Error number %d", retval);
usb_set_intfdata(intf, NULL);
goto error;
}
/* let the user know what node this device is now attached to */
dev_info(&intf->dev,
"USB Skeleton device now attached to USBSkel-%d",
intf->minor);
//input으로 등록.
xpad_init_input(xpad);
return 0;
error:
kfree(xpad);
return retval;
err_free_in_urb:
usb_free_urb(xpad->irq_in);
return retval;
}
static void xpad_disconnect(struct usb_interface *intf)
{
struct usb_xpad *xpad;
xpad = usb_get_intfdata(intf);
pr_info("xpad address is %p\n", xpad);
xpad_deinit_input(xpad);
usb_deregister_dev(intf, &xbox_class);
usb_set_intfdata(intf, NULL);
kfree(xpad);
pr_info("disconnected\n");
}
static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
{
pr_info("suspendes\n");
return 0;
}
static int xpad_resume(struct usb_interface *intf)
{
pr_info("resumed\n");
return 0;
}
static struct usb_driver xpad_test_driver = {
.name = "xbox360_test",
.probe = xpad_probe,
.disconnect = xpad_disconnect,
.suspend = xpad_suspend,
.resume = xpad_resume,
.id_table = xpad_table,
};
static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad)
{
int retval;
xpad->irq_in= usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_in) {
retval = -ENOMEM;
goto error;
}
return 0;
error:
return retval;
}
// 모듈 loading, unloading 테스트를 위해 과거 방식으로 사용
//module_init(usb_xboxtest_init);
//module_exit(usb_xboxtest_exit);
//Macro
module_usb_driver(xpad_test_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("now0930");
MODULE_DESCRIPTION("Hello, xbox pad!");
#include <linux/kernel.h> #include <linux/input.h> #include <linux/module.h> #include <linux/usb/input.h> #include <linux/init.h> #include <linux/device.h> #include <linux/usb/input.h> #include <linux/slab.h> #define USB_XBOX_MINOR_BASE 1 //구조체 선언. struct usb_xpad{ struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ struct usb_interface *intf; /* usb interface */ __u8 irq_in_endpointAddr; /* interrupt in address*/ __u8 irq_out_endpointAddr; /* interrupt out address*/ struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; signed char *data; /* input data */ struct urb *irq_in; /* urb for interrupt in report*/ struct work_struct work; /* init/remove device from callback */ }; static struct usb_xpad *myPad; static int xpad_init_input(struct usb_xpad *xpad); static void xpad_deinit_input(struct usb_xpad *xpad); static void usb_xpad_irq(struct urb *urb){ pr_info("test\n"); usb_submit_urb(urb, GFP_KERNEL); } static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad); static ssize_t xbox_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { pr_info("device was read.\n"); return 0; } static ssize_t xbox_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) { return 0; } static int xbox_open(struct inode *inode, struct file *file) { int retval; struct urb *ptr_urb; ptr_urb = usb_alloc_urb(0, GFP_KERNEL); pr_info("device was opened.\n"); if (!ptr_urb) { retval = -ENOMEM; goto error; } return 0; error: if(ptr_urb) { usb_free_urb(ptr_urb); } return retval; } static int xbox_release(struct inode *inode, struct file *file) { pr_info("xbox was released\n"); return 0; } static int xbox_flush(struct file *file, fl_owner_t id) { return 0; } static const struct file_operations xboxtest_fops = { .owner = THIS_MODULE, .read = xbox_read, .write = xbox_write, .open = xbox_open, .release = xbox_release, .flush = xbox_flush, .llseek = noop_llseek, }; /* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with the driver core */ static struct usb_class_driver xbox_class = { .name = "xbox%d", .fops = &xboxtest_fops, .minor_base = USB_XBOX_MINOR_BASE, }; static struct usb_driver xpad_test_driver; static const struct usb_device_id xpad_table[] = { //{ USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ //XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ {USB_DEVICE(0x045e, 0x028e)}, { } }; static const signed short xpad_common_btn[] = { BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */ BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ -1 /* terminating entry */ }; MODULE_DEVICE_TABLE(usb, xpad_table); static int xpad_init_input(struct usb_xpad *xpad) { struct input_dev *input_dev; int i, error; int pipe, maxp; input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; xpad->dev = input_dev; usb_to_input_id(xpad->udev, &input_dev->id); input_set_drvdata(input_dev, xpad); /* set up standard buttons */ for (i = 0; xpad_common_btn[i] >= 0; i++) input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]); pipe = usb_rcvintpipe(xpad->udev, xpad->irq_in_endpointAddr); maxp = usb_maxpacket(xpad->udev, pipe, usb_pipeout(pipe)); usb_fill_int_urb(xpad->irq_in, xpad->udev, pipe, xpad->data, (maxp > 8 ? 8 : maxp), usb_xpad_irq, xpad, xpad->endpoint_in->bInterval); error = input_register_device(input_dev); if (error) goto err_free_dev; pr_info("usb input was registered\n"); usb_submit_urb(xpad->irq_in, GFP_KERNEL); return 0; //return ok; err_free_dev: input_free_device(input_dev); return error; } static void xpad_deinit_input(struct usb_xpad *xpad) { pr_info("xpad is %p, ->dev is %p.\n",xpad, xpad->dev); if(xpad->dev) input_unregister_device(xpad->dev); } static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_xpad *xpad; struct usb_device *udev; struct usb_endpoint_descriptor *ep_irq_in,*ep_irq_out; struct usb_host_interface *intf_tmp; int retval; udev = interface_to_usbdev(intf); xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); if (!xpad) return -ENOMEM; //초기화 //kzallocd으로 0으로 초기화 //xpad->odata_serial = 0; xpad->udev = udev; xpad->intf = intf; myPad = xpad; pr_info("xpad is %p, myPad is %p\n", xpad->intf, myPad->intf); pr_info("interface is %p\n", intf); //if (intf->cur_altsetting->desc.bNumEndpoints != 2) // return -ENODEV; intf_tmp = intf->cur_altsetting; // find common usb endpoint helper 사용 //https://lkml.org/lkml/2020/9/21/1239 /* set up the endpoint information */ /* use only the first bulk-in and bulk-out endpoints */ retval = usb_find_common_endpoints(intf_tmp, NULL, NULL, &ep_irq_in, &ep_irq_out); if (retval) { dev_err(&intf->dev, "Could not find both irq-in and irq-out endpoints\n"); goto error; } xpad->irq_in_endpointAddr = ep_irq_in->bEndpointAddress; xpad->irq_out_endpointAddr = ep_irq_out->bEndpointAddress; xpad->endpoint_in = ep_irq_in; xpad->endpoint_out = ep_irq_out; xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) { retval = -ENOMEM; goto err_free_in_urb; } usb_set_intfdata(intf, xpad); pr_info("[info]: found interrupt end point, in: %d, out: %d", ep_irq_in->bEndpointAddress, ep_irq_out->bEndpointAddress); pr_info("probe \n"); //pr_info("%04X:%04X pluged \n", id->idVendor, id->idProduct); retval = usb_register_dev(intf, &xbox_class); if (retval< 0) { pr_err("usb_register failed for the "__FILE__ "driver." "Error number %d", retval); usb_set_intfdata(intf, NULL); goto error; } /* let the user know what node this device is now attached to */ dev_info(&intf->dev, "USB Skeleton device now attached to USBSkel-%d", intf->minor); //input으로 등록. xpad_init_input(xpad); return 0; error: kfree(xpad); return retval; err_free_in_urb: usb_free_urb(xpad->irq_in); return retval; } static void xpad_disconnect(struct usb_interface *intf) { struct usb_xpad *xpad; xpad = usb_get_intfdata(intf); pr_info("xpad address is %p\n", xpad); xpad_deinit_input(xpad); usb_deregister_dev(intf, &xbox_class); usb_set_intfdata(intf, NULL); kfree(xpad); pr_info("disconnected\n"); } static int xpad_suspend(struct usb_interface *intf, pm_message_t message) { pr_info("suspendes\n"); return 0; } static int xpad_resume(struct usb_interface *intf) { pr_info("resumed\n"); return 0; } static struct usb_driver xpad_test_driver = { .name = "xbox360_test", .probe = xpad_probe, .disconnect = xpad_disconnect, .suspend = xpad_suspend, .resume = xpad_resume, .id_table = xpad_table, }; static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad) { int retval; xpad->irq_in= usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) { retval = -ENOMEM; goto error; } return 0; error: return retval; } // 모듈 loading, unloading 테스트를 위해 과거 방식으로 사용 //module_init(usb_xboxtest_init); //module_exit(usb_xboxtest_exit); //Macro module_usb_driver(xpad_test_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("now0930"); MODULE_DESCRIPTION("Hello, xbox pad!");
[45180.903315] xpad is ea6ce566, myPad is ea6ce566
[45180.903332] interface is ea6ce566
[45180.903349] [info]: found interrupt end point, in: 129, out: 1
[45180.903360] probe
[45180.903636] xbox360_test 1-1.2:1.0: USB Skeleton device now attached to USBSkel-1
[45180.903815] input: Unspecified device as /devices/virtual/input/input8
[45180.904290] usb input was registered
[45180.904475] xpad is 50c63d58, myPad is 50c63d58
[45180.904489] interface is 50c63d58
[45180.904506] [info]: found interrupt end point, in: 130, out: 2
[45180.904518] probe
[45180.904685] xbox360_test 1-1.2:1.1: USB Skeleton device now attached to USBSkel-2
[45180.904841] input: Unspecified device as /devices/virtual/input/input9
[45180.905155] usb input was registered
[45180.905310] xpad is 3bfd76ed, myPad is 3bfd76ed
[45180.905323] interface is 3bfd76ed
[45180.905342] xbox360_test 1-1.2:1.2: Could not find both irq-in and irq-out endpoints
[45180.905432] xpad is 07d8d175, myPad is 07d8d175
[45180.905451] interface is 07d8d175
[45180.905469] xbox360_test 1-1.2:1.3: Could not find both irq-in and irq-out endpoints
[45180.905585] usbcore: registered new interface driver xbox360_test
[45180.909177] test
[45180.913170] test
[45210.971462] test
[45210.984592] test
[45210.997466] test
[45211.010595] test
[45211.075485] test
[45211.088606] test
[45211.109483] test
[45211.130612] test
[45211.151488] test
[45211.168617] test
[45211.181493] test
[45211.754713] test
[45211.799598] test
[45211.812711] test
[45212.329679] test
[45217.545918] usbcore: deregistering interface driver xbox360_test
[45217.546248] test
[45217.546378] xpad address is 99d70f22
[45217.546411] xpad is 99d70f22, ->dev is 8784f33d.
[45217.699130] disconnected
[45217.699578] test
[45217.699674] xpad address is 0764c1af
[45217.699692] xpad is 0764c1af, ->dev is 379dff77.
[45217.779137] disconnected
[45180.903315] xpad is ea6ce566, myPad is ea6ce566
[45180.903332] interface is ea6ce566
[45180.903349] [info]: found interrupt end point, in: 129, out: 1
[45180.903360] probe
[45180.903636] xbox360_test 1-1.2:1.0: USB Skeleton device now attached to USBSkel-1
[45180.903815] input: Unspecified device as /devices/virtual/input/input8
[45180.904290] usb input was registered
[45180.904475] xpad is 50c63d58, myPad is 50c63d58
[45180.904489] interface is 50c63d58
[45180.904506] [info]: found interrupt end point, in: 130, out: 2
[45180.904518] probe
[45180.904685] xbox360_test 1-1.2:1.1: USB Skeleton device now attached to USBSkel-2
[45180.904841] input: Unspecified device as /devices/virtual/input/input9
[45180.905155] usb input was registered
[45180.905310] xpad is 3bfd76ed, myPad is 3bfd76ed
[45180.905323] interface is 3bfd76ed
[45180.905342] xbox360_test 1-1.2:1.2: Could not find both irq-in and irq-out endpoints
[45180.905432] xpad is 07d8d175, myPad is 07d8d175
[45180.905451] interface is 07d8d175
[45180.905469] xbox360_test 1-1.2:1.3: Could not find both irq-in and irq-out endpoints
[45180.905585] usbcore: registered new interface driver xbox360_test
[45180.909177] test
[45180.913170] test
[45210.971462] test
[45210.984592] test
[45210.997466] test
[45211.010595] test
[45211.075485] test
[45211.088606] test
[45211.109483] test
[45211.130612] test
[45211.151488] test
[45211.168617] test
[45211.181493] test
[45211.754713] test
[45211.799598] test
[45211.812711] test
[45212.329679] test
[45217.545918] usbcore: deregistering interface driver xbox360_test
[45217.546248] test
[45217.546378] xpad address is 99d70f22
[45217.546411] xpad is 99d70f22, ->dev is 8784f33d.
[45217.699130] disconnected
[45217.699578] test
[45217.699674] xpad address is 0764c1af
[45217.699692] xpad is 0764c1af, ->dev is 379dff77.
[45217.779137] disconnected
[45180.903315] xpad is ea6ce566, myPad is ea6ce566 [45180.903332] interface is ea6ce566 [45180.903349] [info]: found interrupt end point, in: 129, out: 1 [45180.903360] probe [45180.903636] xbox360_test 1-1.2:1.0: USB Skeleton device now attached to USBSkel-1 [45180.903815] input: Unspecified device as /devices/virtual/input/input8 [45180.904290] usb input was registered [45180.904475] xpad is 50c63d58, myPad is 50c63d58 [45180.904489] interface is 50c63d58 [45180.904506] [info]: found interrupt end point, in: 130, out: 2 [45180.904518] probe [45180.904685] xbox360_test 1-1.2:1.1: USB Skeleton device now attached to USBSkel-2 [45180.904841] input: Unspecified device as /devices/virtual/input/input9 [45180.905155] usb input was registered [45180.905310] xpad is 3bfd76ed, myPad is 3bfd76ed [45180.905323] interface is 3bfd76ed [45180.905342] xbox360_test 1-1.2:1.2: Could not find both irq-in and irq-out endpoints [45180.905432] xpad is 07d8d175, myPad is 07d8d175 [45180.905451] interface is 07d8d175 [45180.905469] xbox360_test 1-1.2:1.3: Could not find both irq-in and irq-out endpoints [45180.905585] usbcore: registered new interface driver xbox360_test [45180.909177] test [45180.913170] test [45210.971462] test [45210.984592] test [45210.997466] test [45211.010595] test [45211.075485] test [45211.088606] test [45211.109483] test [45211.130612] test [45211.151488] test [45211.168617] test [45211.181493] test [45211.754713] test [45211.799598] test [45211.812711] test [45212.329679] test [45217.545918] usbcore: deregistering interface driver xbox360_test [45217.546248] test [45217.546378] xpad address is 99d70f22 [45217.546411] xpad is 99d70f22, ->dev is 8784f33d. [45217.699130] disconnected [45217.699578] test [45217.699674] xpad address is 0764c1af [45217.699692] xpad is 0764c1af, ->dev is 379dff77. [45217.779137] disconnected