1/* 2 * Roccat Lua driver for Linux 3 * 4 * Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net> 5 */ 6 7/* 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the Free 10 * Software Foundation; either version 2 of the License, or (at your option) 11 * any later version. 12 */ 13 14/* 15 * Roccat Lua is a gamer mouse which cpi, button and light settings can be 16 * configured. 17 */ 18 19#include <linux/device.h> 20#include <linux/input.h> 21#include <linux/hid.h> 22#include <linux/module.h> 23#include <linux/slab.h> 24#include <linux/hid-roccat.h> 25#include "hid-ids.h" 26#include "hid-roccat-common.h" 27#include "hid-roccat-lua.h" 28 29static ssize_t lua_sysfs_read(struct file *fp, struct kobject *kobj, 30 char *buf, loff_t off, size_t count, 31 size_t real_size, uint command) 32{ 33 struct device *dev = container_of(kobj, struct device, kobj); 34 struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev)); 35 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 36 int retval; 37 38 if (off >= real_size) 39 return 0; 40 41 if (off != 0 || count != real_size) 42 return -EINVAL; 43 44 mutex_lock(&lua->lua_lock); 45 retval = roccat_common2_receive(usb_dev, command, buf, real_size); 46 mutex_unlock(&lua->lua_lock); 47 48 return retval ? retval : real_size; 49} 50 51static ssize_t lua_sysfs_write(struct file *fp, struct kobject *kobj, 52 void const *buf, loff_t off, size_t count, 53 size_t real_size, uint command) 54{ 55 struct device *dev = container_of(kobj, struct device, kobj); 56 struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev)); 57 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 58 int retval; 59 60 if (off != 0 || count != real_size) 61 return -EINVAL; 62 63 mutex_lock(&lua->lua_lock); 64 retval = roccat_common2_send(usb_dev, command, buf, real_size); 65 mutex_unlock(&lua->lua_lock); 66 67 return retval ? retval : real_size; 68} 69 70#define LUA_SYSFS_W(thingy, THINGY) \ 71static ssize_t lua_sysfs_write_ ## thingy(struct file *fp, \ 72 struct kobject *kobj, struct bin_attribute *attr, \ 73 char *buf, loff_t off, size_t count) \ 74{ \ 75 return lua_sysfs_write(fp, kobj, buf, off, count, \ 76 LUA_SIZE_ ## THINGY, LUA_COMMAND_ ## THINGY); \ 77} 78 79#define LUA_SYSFS_R(thingy, THINGY) \ 80static ssize_t lua_sysfs_read_ ## thingy(struct file *fp, \ 81 struct kobject *kobj, struct bin_attribute *attr, \ 82 char *buf, loff_t off, size_t count) \ 83{ \ 84 return lua_sysfs_read(fp, kobj, buf, off, count, \ 85 LUA_SIZE_ ## THINGY, LUA_COMMAND_ ## THINGY); \ 86} 87 88#define LUA_BIN_ATTRIBUTE_RW(thingy, THINGY) \ 89LUA_SYSFS_W(thingy, THINGY) \ 90LUA_SYSFS_R(thingy, THINGY) \ 91static struct bin_attribute lua_ ## thingy ## _attr = { \ 92 .attr = { .name = #thingy, .mode = 0660 }, \ 93 .size = LUA_SIZE_ ## THINGY, \ 94 .read = lua_sysfs_read_ ## thingy, \ 95 .write = lua_sysfs_write_ ## thingy \ 96}; 97 98LUA_BIN_ATTRIBUTE_RW(control, CONTROL) 99 100static int lua_create_sysfs_attributes(struct usb_interface *intf) 101{ 102 return sysfs_create_bin_file(&intf->dev.kobj, &lua_control_attr); 103} 104 105static void lua_remove_sysfs_attributes(struct usb_interface *intf) 106{ 107 sysfs_remove_bin_file(&intf->dev.kobj, &lua_control_attr); 108} 109 110static int lua_init_lua_device_struct(struct usb_device *usb_dev, 111 struct lua_device *lua) 112{ 113 mutex_init(&lua->lua_lock); 114 115 return 0; 116} 117 118static int lua_init_specials(struct hid_device *hdev) 119{ 120 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 121 struct usb_device *usb_dev = interface_to_usbdev(intf); 122 struct lua_device *lua; 123 int retval; 124 125 lua = kzalloc(sizeof(*lua), GFP_KERNEL); 126 if (!lua) { 127 hid_err(hdev, "can't alloc device descriptor\n"); 128 return -ENOMEM; 129 } 130 hid_set_drvdata(hdev, lua); 131 132 retval = lua_init_lua_device_struct(usb_dev, lua); 133 if (retval) { 134 hid_err(hdev, "couldn't init struct lua_device\n"); 135 goto exit; 136 } 137 138 retval = lua_create_sysfs_attributes(intf); 139 if (retval) { 140 hid_err(hdev, "cannot create sysfs files\n"); 141 goto exit; 142 } 143 144 return 0; 145exit: 146 kfree(lua); 147 return retval; 148} 149 150static void lua_remove_specials(struct hid_device *hdev) 151{ 152 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 153 struct lua_device *lua; 154 155 lua_remove_sysfs_attributes(intf); 156 157 lua = hid_get_drvdata(hdev); 158 kfree(lua); 159} 160 161static int lua_probe(struct hid_device *hdev, 162 const struct hid_device_id *id) 163{ 164 int retval; 165 166 retval = hid_parse(hdev); 167 if (retval) { 168 hid_err(hdev, "parse failed\n"); 169 goto exit; 170 } 171 172 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 173 if (retval) { 174 hid_err(hdev, "hw start failed\n"); 175 goto exit; 176 } 177 178 retval = lua_init_specials(hdev); 179 if (retval) { 180 hid_err(hdev, "couldn't install mouse\n"); 181 goto exit_stop; 182 } 183 184 return 0; 185 186exit_stop: 187 hid_hw_stop(hdev); 188exit: 189 return retval; 190} 191 192static void lua_remove(struct hid_device *hdev) 193{ 194 lua_remove_specials(hdev); 195 hid_hw_stop(hdev); 196} 197 198static const struct hid_device_id lua_devices[] = { 199 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) }, 200 { } 201}; 202 203MODULE_DEVICE_TABLE(hid, lua_devices); 204 205static struct hid_driver lua_driver = { 206 .name = "lua", 207 .id_table = lua_devices, 208 .probe = lua_probe, 209 .remove = lua_remove 210}; 211module_hid_driver(lua_driver); 212 213MODULE_AUTHOR("Stefan Achatz"); 214MODULE_DESCRIPTION("USB Roccat Lua driver"); 215MODULE_LICENSE("GPL v2"); 216