From: johann d. <jd...@us...> - 2002-03-06 23:03:01
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/usb In directory usw-pr-cvs1:/tmp/cvs-serv14841 Modified Files: Config.help Config.in hid-core.c hid-input.c hid.h Added Files: hid-ff.c Log Message: Added force feedback interface to hid (needed because different protocols are used). Added basic force feedback support for Logitech WingMan Cordless rumble pad. Updated Config files. --- NEW FILE: hid-ff.c --- /* * $Id: hid-ff.c,v 1.1 2002/03/06 23:02:58 jdeneux Exp $ * * Force feedback support for hid devices. * Not all hid devices use the same protocol. For example, some use PID, * other use their own proprietary procotol. * * Copyright (c) 2002 Johann Deneux */ /* * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so by * e-mail - mail your message to <de...@if...> */ #include <linux/input.h> #undef DEBUG #include <linux/usb.h> #include "hid.h" /* Drivers' initializing functions */ static int hid_lgff_init(struct hid_device* hid); struct hid_ff_initializer { __u16 idVendor; __u16 idProduct; int (*init)(struct hid_device*); }; static struct hid_ff_initializer inits[] = { #ifdef CONFIG_LOGITECH_RUMBLE {0x46d, 0xc211, hid_lgff_init}, #endif {0, 0, NULL} /* Terminating entry */ }; static struct hid_ff_initializer *hid_get_ff_init(__u16 idVendor, __u16 idProduct) { struct hid_ff_initializer *init; for (init = inits; init->idVendor && !(init->idVendor == idVendor && init->idProduct == idProduct); init++); return init->idVendor? init : NULL; } int hid_init_ff(struct hid_device* hid) { struct hid_ff_initializer *init; init = hid_get_ff_init(hid->dev->descriptor.idVendor, hid->dev->descriptor.idProduct); return init? init->init(hid) : -ENOSYS; } /* Implements the protocol used by the Logitech WingMan Cordless rumble pad */ #ifdef CONFIG_LOGITECH_RUMBLE #define LGFF_BUFFER_SIZE 8 struct hid_ff_logitech { struct urb* urbffout; /* Output URB used to send ff commands */ struct usb_ctrlrequest ffcr; /* ff commands are sent using control URBs */ char ffoutbuf[LGFF_BUFFER_SIZE]; signed char rumble_left; /* Magnitude of left motor */ signed char rumble_right; /* Magnitude of right motor */ int rumble_play; /* Enable rumbling */ }; static void hid_lgff_ctrl_out(struct urb *urb); static int hid_lgff_upload_effect(struct input_dev* input, struct ff_effect* effect); static void hid_lgff_exit(struct hid_device* hid); static int hid_lgff_event(struct input_dev* input, unsigned int type, unsigned int code, int value); static void hid_lgff_make_rumble(struct hid_device* hid); static int hid_lgff_init(struct hid_device* hid) { struct hid_ff_logitech *private; /* Private data */ private = hid->ff_private = kmalloc(sizeof(struct hid_ff_logitech), GFP_KERNEL); if (!hid->ff_private) return -1; /* Event and exit callbacks */ hid->exit_ff = hid_lgff_exit; hid->ff_event = hid_lgff_event; /* USB init */ if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) { kfree(hid->ff_private); return -1; } FILL_CONTROL_URB(private->urbffout, hid->dev, 0, (void*) &private->ffcr, private->ffoutbuf, 8, hid_lgff_ctrl_out, hid); dbg("Created ff output control urb"); /* Input init */ hid->input.upload_effect = hid_lgff_upload_effect; set_bit(FF_RUMBLE, hid->input.ffbit); set_bit(EV_FF, hid->input.evbit); hid->input.ff_effects_max = 1; return 0; } static void hid_lgff_exit(struct hid_device* hid) { struct hid_ff_logitech *lgff = hid->ff_private; if (lgff->urbffout) { usb_unlink_urb(lgff->urbffout); usb_free_urb(lgff->urbffout); } } static int hid_lgff_event(struct input_dev* input, unsigned int type, unsigned int code, int value) { struct hid_device *hid = input->private; struct hid_ff_logitech *lgff = hid->ff_private; if (type == EV_FF) { int old = lgff->rumble_play; lgff->rumble_play = (value!=0); if (old != lgff->rumble_play) hid_lgff_make_rumble(hid); return 0; } else return -EINVAL; } static void hid_lgff_make_rumble(struct hid_device* hid) { struct hid_ff_logitech *lgff = hid->ff_private; char packet[] = {0x03, 0x42, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00}; int err; dbg("in hid_make_rumble"); memcpy(lgff->ffoutbuf, packet, 8); if (lgff->rumble_play) { lgff->ffoutbuf[3] = lgff->rumble_left; lgff->ffoutbuf[4] = lgff->rumble_right; } else { lgff->ffoutbuf[3] = 0; lgff->ffoutbuf[4] = 0; } lgff->urbffout->pipe = usb_sndctrlpipe(hid->dev, 0); lgff->ffcr.bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE; lgff->urbffout->transfer_buffer_length = lgff->ffcr.wLength = 8; lgff->ffcr.bRequest = 9; lgff->ffcr.wValue = 0x0203; lgff->ffcr.wIndex = 0; lgff->urbffout->dev = hid->dev; if ((err=usb_submit_urb(lgff->urbffout, GFP_ATOMIC))) warn("usb_submit_urb returned %d", err); dbg("rumble urb submited"); } static void hid_lgff_ctrl_out(struct urb *urb) { struct hid_device *hid = urb->context; if (urb->status) warn("hid_irq_ffout status %d received", urb->status); } static int hid_lgff_upload_effect(struct input_dev* input, struct ff_effect* effect) { struct hid_device* hid = input->private; struct hid_ff_logitech *lgff = hid->ff_private; dbg("ioctl rumble"); if (!test_bit(effect->type, input->ffbit)) return -EINVAL; switch (effect->type) { case FF_RUMBLE: lgff->rumble_left = 0x80; lgff->rumble_right = 0x00; break; default: return -EINVAL; } return 0; } #endif /* CONFIG_LOGITECH_RUMBLE */ Index: Config.help =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/Config.help,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- Config.help 26 Jan 2002 19:20:37 -0000 1.1 +++ Config.help 6 Mar 2002 23:02:58 -0000 1.2 @@ -105,6 +105,18 @@ The module will be called hid.o. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. +CONFIG_HID_FF + Say Y here is you want force feedback support for a few hid devices. See + below for a list of supported devices. + See Documentation/input/ff.txt for a description of the force feedback API. + + If unsure, say N. + +CONFIG_LOGITECH_RUMBLE + Say Y here if you have a Logitech WingMan Cordless rumble pad and if you + want to enable force feedback. Note: if you say N here, this device will + still be supported, but without force feedback. + CONFIG_USB_HIDDEV Say Y here if you want to support HID devices (from the USB specification standpoint) that aren't strictly user interface @@ -519,6 +531,21 @@ The module will be called dabusb.o. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. +CONFIG_USB_KONICAWC + Say Y here if you want support for webcams based on a Konica + chipset. This is known to work with the Intel YC76 webcam. + + This driver uses the Video For Linux API. You must enable + (Y or M in config) Video For Linux (under Character Devices) + to use this driver. Information on this API and pointers to + "v4l" programs may be found on the WWW at + <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called konicawc.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + CONFIG_USB_USBNET This driver supports network links over USB with USB "Network" or "data transfer" cables, often used to network laptops to PCs. @@ -592,14 +619,14 @@ Support for anything but the X6 is experimental. Please report failures and successes. The scanner will appear as a scsi generic device to the rest - of the system. Scsi support is required for this driver to compile - and work. SANE 1.0.4 or newer is needed to make use of your scanner. - This driver can be compiled as a module. + of the system. Scsi support is required. + This driver can be compiled as a module, called microtek.o. CONFIG_USB_HPUSBSCSI Say Y here if you want support for the HP 53xx series of scanners and the Minolta Scan Dual. This driver is experimental. The scanner will be accessible as a SCSI device. + This can be compiled as a module, called hpusbscsi.o. CONFIG_USB_BLUETOOTH Say Y here if you want to connect a USB Bluetooth device to your Index: Config.in =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/Config.in,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- Config.in 26 Dec 2001 21:08:33 -0000 1.19 +++ Config.in 6 Mar 2002 23:02:58 -0000 1.20 @@ -18,7 +18,8 @@ bool ' Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT fi -comment 'USB Controllers' +comment 'USB Host Controller Drivers' +source drivers/usb/hcd/Config.in if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB fi @@ -32,6 +33,9 @@ comment 'USB Device Class drivers' dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL +if [ "$CONFIG_SCSI" = "n" ]; then + comment ' SCSI support is needed for USB Storage' +fi dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE dep_mbool ' Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL @@ -44,6 +48,22 @@ dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB +comment 'USB Human Interface Devices (HID)' +if [ "$CONFIG_INPUT" = "n" ]; then + comment ' Input core support is needed for USB HID' +else + dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT + dep_mbool ' /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID + if [ "$CONFIG_USB_HID" != "y" ]; then + dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT + dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT + fi + dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT + dep_tristate ' Griffin Technology PowerMate support' CONFIG_USB_POWERMATE $CONFIG_USB $CONFIG_INPUT + dep_mbool ' Force feedback support' CONFIG_HID_FF $CONFIG_USB_HID + dep_mbool ' Logitech RumblePad support' CONFIG_LOGITECH_RUMBLE $CONFIG_USB_HID $CONFIG_HID_FF +fi + comment 'USB Imaging devices' dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL @@ -59,8 +79,11 @@ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB + dep_tristate ' USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV fi comment 'USB Network adaptors' @@ -80,5 +103,6 @@ comment 'USB Miscellaneous drivers' dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL +dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL endmenu Index: hid-core.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/hid-core.c,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- hid-core.c 27 Feb 2002 22:26:58 -0000 1.46 +++ hid-core.c 6 Mar 2002 23:02:58 -0000 1.47 @@ -1374,7 +1374,10 @@ return hid; fail: - +#ifdef CONFIG_HID_FF + if (hid->exit_ff) + hid->exit_ff(hid); +#endif hid_free_device(hid); if (hid->urbin) usb_free_urb(hid->urbin); if (hid->urbout) usb_free_urb(hid->urbout); @@ -1399,6 +1402,13 @@ hid_init_reports(hid); hid_dump_device(hid); +#ifdef CONFIG_HID_FF + if (hid_init_ff(hid)) { + hid_free_device(hid); + return NULL; + } +#endif + if (!hidinput_connect(hid)) hid->claimed |= HID_CLAIMED_INPUT; #ifdef CONFIG_USB_HIDDEV @@ -1455,6 +1465,10 @@ if (hid->urbout) usb_free_urb(hid->urbout); +#ifdef CONFIG_HID_FF + if (hid->exit_ff) + hid->exit_ff(hid); +#endif hid_free_device(hid); } Index: hid-input.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/hid-input.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- hid-input.c 24 Jan 2002 19:51:26 -0000 1.20 +++ hid-input.c 6 Mar 2002 23:02:58 -0000 1.21 @@ -377,16 +377,28 @@ static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct hid_device *hid = dev->private; - struct hid_field *field = NULL; - int offset; - if ((offset = hid_find_field(hid, type, code, &field)) == -1) { - warn("event field not found"); - return -1; + warn("hid input event"); + +#ifdef CONFIG_HID_FF + if (type == EV_FF) { + return hid->ff_event? hid->ff_event(dev, type, code, value) : -1; } +#else + if (0) {} +#endif + else { + struct hid_field *field = NULL; + int offset; - hid_set_field(field, offset, value); - hid_submit_report(hid, field->report, USB_DIR_OUT); + if ((offset = hid_find_field(hid, type, code, &field)) == -1) { + warn("event field not found"); + return -1; + } + + hid_set_field(field, offset, value); + hid_submit_report(hid, field->report, USB_DIR_OUT); + } return 0; } @@ -428,7 +440,6 @@ hid->input.event = hidinput_input_event; hid->input.open = hidinput_open; hid->input.close = hidinput_close; - hid->input.name = hid->name; hid->input.phys = hid->phys; hid->input.uniq = hid->uniq; Index: hid.h =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/usb/hid.h,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- hid.h 24 Jan 2002 19:51:26 -0000 1.27 +++ hid.h 6 Mar 2002 23:02:58 -0000 1.28 @@ -356,6 +356,10 @@ char name[128]; /* Device name */ char phys[64]; /* Device physical location */ char uniq[64]; /* Device unique identifier (serial #) */ + + void *ff_private; /* Private data for the force-feedback driver */ + void (*exit_ff)(struct hid_device*); /* Called by hid_exit_ff(hid) */ + int (*ff_event)(struct input_dev*, unsigned int type, unsigned int code, int value); }; #define HID_GLOBAL_STACK_SIZE 4 @@ -410,3 +414,7 @@ int hid_set_field(struct hid_field *, unsigned, __s32); void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); void hid_init_reports(struct hid_device *hid); + +#ifdef CONFIG_HID_FF +int hid_init_ff(struct hid_device *hid); +#endif |