Need advice on USB device interaction
From: Dmitriy Geels <hidden>
Date: 2009-01-21 16:07:33
Hello everybody! I'm working on force feedback support for Saitek gamepad devices. I base my work on Jérôme Poisson (goffi@goffi.org) Saitek P2500 driver, which was written pretty dirty and should be loaded before usbhid to work. Logitech/Thrustmaster/ZeroPlus/etc force feedback drivers are informative enough to build my own driver, but there are still 2 things that I need to clear up: 1. there is always some init code in _probe() function, e.g. for hid-zpff:
zpff->report = report; zpff->report->field[0]->value[0] = 0x00; zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
Jérôme used this code in open() function (input_dev::open field):
struct usb_device *udev; char buf[2]; ... buf[0]=0x15; buf[1]=0x01; usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x09, 0x21, 0x315, 0, &buf, 2, 50);
May this be replaced by usbhid_submit_report() call and how report should look like then? 2. in kernell FF drivers all interaction with the device made using usbhid_submit_report() call, but Jérôme used usb_submit_urb():
static int SP2500_playback(struct input_dev *dev, int code, int value)
{
struct usb_SP2500* sp2500 = (struct usb_SP2500*)(dev->private);
struct urb *urb = NULL;
char *buf = NULL;
int count=4;
int retval;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
}
buf = usb_buffer_alloc(sp2500->udev, count, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
if (code < 0 || code >= MAX_FF)
return -EINVAL;
buf[0]=0x51;
buf[1]=(__u8)code;
if (value > 0)
buf[2]=02; //play
else
buf[2]=01; //stop
buf[3]=01;
count=4;
usb_fill_int_urb(urb, sp2500->udev,
usb_sndintpipe(sp2500->udev, sp2500->int_out_endpointAddr),
buf, count, SP2500_write_int_callback, sp2500, 20);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
}
usb_free_urb(urb);
return 0;
error:
err ("playback error");
usb_buffer_free(sp2500->udev, count, buf, urb->transfer_dma);
usb_free_urb(urb);
return retval;
}Is following my replacement for this function correct? Mainly, I want to know, if data packet is formed correctly.
static int stff_play(struct input_dev *idev, int code, int value)
{
struct hid_device *hid = input_get_drvdata(idev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
report->field[0]->value[0] = 0x51;
report->field[0]->value[1] = (__u8)code;
if (value > 0)
report->field[0]->value[2] = 02; //play
else
report->field[0]->value[2] = 01; //stop
report->field[0]->value[3]=01;
usbhid_submit_report(hid, report, USB_DIR_OUT);
return 0;
}P.S. you can find SP2500 driver source here: http://www.goffi.org/index.php?post/2006/09/14/Pilote-Linux-pour-le-joypad-Saitek-P2501 P.P.S. original driver contains quirk from original saitek driver -- d-pad and first analog stick swap on button press; I don't wan't to implement this quirk at the moment -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html