| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * PlayStation 2 Trance Vibrator driver | |
| * | |
| * Copyright (C) 2006 Sam Hocevar <sam@zoy.org> | |
| */ | |
| /* Standard include files */ | |
| #include <linux/kernel.h> | |
| #include <linux/errno.h> | |
| #include <linux/slab.h> | |
| #include <linux/module.h> | |
| #include <linux/usb.h> | |
| #define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org" | |
| #define DRIVER_DESC "PlayStation 2 Trance Vibrator driver" | |
| #define TRANCEVIBRATOR_VENDOR_ID 0x0b49 /* ASCII Corporation */ | |
| #define TRANCEVIBRATOR_PRODUCT_ID 0x064f /* Trance Vibrator */ | |
| static const struct usb_device_id id_table[] = { | |
| { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) }, | |
| { }, | |
| }; | |
| MODULE_DEVICE_TABLE (usb, id_table); | |
| /* Driver-local specific stuff */ | |
| struct trancevibrator { | |
| struct usb_device *udev; | |
| unsigned int speed; | |
| }; | |
| static ssize_t speed_show(struct device *dev, struct device_attribute *attr, | |
| char *buf) | |
| { | |
| struct usb_interface *intf = to_usb_interface(dev); | |
| struct trancevibrator *tv = usb_get_intfdata(intf); | |
| return sprintf(buf, "%d\n", tv->speed); | |
| } | |
| static ssize_t speed_store(struct device *dev, struct device_attribute *attr, | |
| const char *buf, size_t count) | |
| { | |
| struct usb_interface *intf = to_usb_interface(dev); | |
| struct trancevibrator *tv = usb_get_intfdata(intf); | |
| int temp, retval, old; | |
| retval = kstrtoint(buf, 10, &temp); | |
| if (retval) | |
| return retval; | |
| if (temp > 255) | |
| temp = 255; | |
| else if (temp < 0) | |
| temp = 0; | |
| old = tv->speed; | |
| tv->speed = temp; | |
| dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed); | |
| /* Set speed */ | |
| retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0), | |
| 0x01, /* vendor request: set speed */ | |
| USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | |
| tv->speed, /* speed value */ | |
| 0, NULL, 0, USB_CTRL_SET_TIMEOUT); | |
| if (retval) { | |
| tv->speed = old; | |
| dev_dbg(&tv->udev->dev, "retval = %d\n", retval); | |
| return retval; | |
| } | |
| return count; | |
| } | |
| static DEVICE_ATTR_RW(speed); | |
| static struct attribute *tv_attrs[] = { | |
| &dev_attr_speed.attr, | |
| NULL, | |
| }; | |
| ATTRIBUTE_GROUPS(tv); | |
| static int tv_probe(struct usb_interface *interface, | |
| const struct usb_device_id *id) | |
| { | |
| struct usb_device *udev = interface_to_usbdev(interface); | |
| struct trancevibrator *dev; | |
| int retval; | |
| dev = kzalloc_obj(struct trancevibrator); | |
| if (!dev) { | |
| retval = -ENOMEM; | |
| goto error; | |
| } | |
| dev->udev = udev; | |
| usb_set_intfdata(interface, dev); | |
| return 0; | |
| error: | |
| kfree(dev); | |
| return retval; | |
| } | |
| static void tv_disconnect(struct usb_interface *interface) | |
| { | |
| struct trancevibrator *dev; | |
| dev = usb_get_intfdata (interface); | |
| usb_set_intfdata(interface, NULL); | |
| kfree(dev); | |
| } | |
| /* USB subsystem object */ | |
| static struct usb_driver tv_driver = { | |
| .name = "trancevibrator", | |
| .probe = tv_probe, | |
| .disconnect = tv_disconnect, | |
| .id_table = id_table, | |
| .dev_groups = tv_groups, | |
| }; | |
| module_usb_driver(tv_driver); | |
| MODULE_AUTHOR(DRIVER_AUTHOR); | |
| MODULE_DESCRIPTION(DRIVER_DESC); | |
| MODULE_LICENSE("GPL"); |