1/* 2 * PlayStation 2 Trance Vibrator driver 3 * 4 * Copyright (C) 2006 Sam Hocevar <sam@zoy.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21/* Standard include files */ 22#include <linux/kernel.h> 23#include <linux/errno.h> 24#include <linux/init.h> 25#include <linux/module.h> 26#include <linux/usb.h> 27 28/* Version Information */ 29#define DRIVER_VERSION "v1.1" 30#define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org" 31#define DRIVER_DESC "PlayStation 2 Trance Vibrator driver" 32 33#define TRANCEVIBRATOR_VENDOR_ID 0x0b49 /* ASCII Corporation */ 34#define TRANCEVIBRATOR_PRODUCT_ID 0x064f /* Trance Vibrator */ 35 36static struct usb_device_id id_table [] = { 37 { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) }, 38 { }, 39}; 40MODULE_DEVICE_TABLE (usb, id_table); 41 42/* Driver-local specific stuff */ 43struct trancevibrator { 44 struct usb_device *udev; 45 unsigned int speed; 46}; 47 48static ssize_t show_speed(struct device *dev, struct device_attribute *attr, 49 char *buf) 50{ 51 struct usb_interface *intf = to_usb_interface(dev); 52 struct trancevibrator *tv = usb_get_intfdata(intf); 53 54 return sprintf(buf, "%d\n", tv->speed); 55} 56 57static ssize_t set_speed(struct device *dev, struct device_attribute *attr, 58 const char *buf, size_t count) 59{ 60 struct usb_interface *intf = to_usb_interface(dev); 61 struct trancevibrator *tv = usb_get_intfdata(intf); 62 int temp, retval; 63 64 temp = simple_strtoul(buf, NULL, 10); 65 if (temp > 255) 66 temp = 255; 67 else if (temp < 0) 68 temp = 0; 69 tv->speed = temp; 70 71 dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed); 72 73 /* Set speed */ 74 retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0), 75 0x01, /* vendor request: set speed */ 76 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, 77 tv->speed, /* speed value */ 78 0, NULL, 0, USB_CTRL_GET_TIMEOUT); 79 if (retval) { 80 dev_dbg(&tv->udev->dev, "retval = %d\n", retval); 81 return retval; 82 } 83 return count; 84} 85 86static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed); 87 88static int tv_probe(struct usb_interface *interface, 89 const struct usb_device_id *id) 90{ 91 struct usb_device *udev = interface_to_usbdev(interface); 92 struct trancevibrator *dev; 93 int retval; 94 95 dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL); 96 if (dev == NULL) { 97 dev_err(&interface->dev, "Out of memory\n"); 98 retval = -ENOMEM; 99 goto error; 100 } 101 102 dev->udev = usb_get_dev(udev); 103 usb_set_intfdata(interface, dev); 104 retval = device_create_file(&interface->dev, &dev_attr_speed); 105 if (retval) 106 goto error_create_file; 107 108 return 0; 109 110error_create_file: 111 usb_put_dev(udev); 112 usb_set_intfdata(interface, NULL); 113error: 114 kfree(dev); 115 return retval; 116} 117 118static void tv_disconnect(struct usb_interface *interface) 119{ 120 struct trancevibrator *dev; 121 122 dev = usb_get_intfdata (interface); 123 device_remove_file(&interface->dev, &dev_attr_speed); 124 usb_set_intfdata(interface, NULL); 125 usb_put_dev(dev->udev); 126 kfree(dev); 127} 128 129/* USB subsystem object */ 130static struct usb_driver tv_driver = { 131 .name = "trancevibrator", 132 .probe = tv_probe, 133 .disconnect = tv_disconnect, 134 .id_table = id_table, 135}; 136 137static int __init tv_init(void) 138{ 139 int retval = usb_register(&tv_driver); 140 if (retval) { 141 err("usb_register failed. Error number %d", retval); 142 return retval; 143 } 144 145 info(DRIVER_VERSION ":" DRIVER_DESC); 146 return 0; 147} 148 149static void __exit tv_exit(void) 150{ 151 usb_deregister(&tv_driver); 152} 153 154module_init (tv_init); 155module_exit (tv_exit); 156 157MODULE_AUTHOR(DRIVER_AUTHOR); 158MODULE_DESCRIPTION(DRIVER_DESC); 159MODULE_LICENSE("GPL"); 160