aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hidraw.c
diff options
context:
space:
mode:
authorAlan Ott <alan@signal11.us>2011-01-18 03:04:39 -0500
committerJiri Kosina <jkosina@suse.cz>2011-02-11 09:05:49 -0500
commitb4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddb (patch)
treefde6ca709962906877c25e0910d67ca5c00beb74 /drivers/hid/hidraw.c
parent0825411ade21a39ac63b3e011d092b1f95b5f3f5 (diff)
HID: Add Support for Setting and Getting Feature Reports from hidraw
Per the HID Specification, Feature reports must be sent and received on the Configuration endpoint (EP 0) through the Set_Report/Get_Report interfaces. This patch adds two ioctls to hidraw to set and get feature reports to and from the device. Modifications were made to hidraw and usbhid. New hidraw ioctls: HIDIOCSFEATURE - Perform a Set_Report transfer of a Feature report. HIDIOCGFEATURE - Perform a Get_Report transfer of a Feature report. Signed-off-by: Alan Ott <alan@signal11.us> Signed-off-by: Antonio Ospite <ospite@studenti.unina.it> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hidraw.c')
-rw-r--r--drivers/hid/hidraw.c106
1 files changed, 100 insertions, 6 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 468e87b53ed2..8f06044a3e3e 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -102,15 +102,14 @@ out:
102} 102}
103 103
104/* the first byte is expected to be a report number */ 104/* the first byte is expected to be a report number */
105static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 105/* This function is to be called with the minors_lock mutex held */
106static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
106{ 107{
107 unsigned int minor = iminor(file->f_path.dentry->d_inode); 108 unsigned int minor = iminor(file->f_path.dentry->d_inode);
108 struct hid_device *dev; 109 struct hid_device *dev;
109 __u8 *buf; 110 __u8 *buf;
110 int ret = 0; 111 int ret = 0;
111 112
112 mutex_lock(&minors_lock);
113
114 if (!hidraw_table[minor]) { 113 if (!hidraw_table[minor]) {
115 ret = -ENODEV; 114 ret = -ENODEV;
116 goto out; 115 goto out;
@@ -148,14 +147,92 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
148 goto out_free; 147 goto out_free;
149 } 148 }
150 149
151 ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); 150 ret = dev->hid_output_raw_report(dev, buf, count, report_type);
152out_free: 151out_free:
153 kfree(buf); 152 kfree(buf);
154out: 153out:
154 return ret;
155}
156
157/* the first byte is expected to be a report number */
158static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
159{
160 ssize_t ret;
161 mutex_lock(&minors_lock);
162 ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
155 mutex_unlock(&minors_lock); 163 mutex_unlock(&minors_lock);
156 return ret; 164 return ret;
157} 165}
158 166
167
168/* This function performs a Get_Report transfer over the control endpoint
169 per section 7.2.1 of the HID specification, version 1.1. The first byte
170 of buffer is the report number to request, or 0x0 if the defice does not
171 use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
172 or HID_INPUT_REPORT. This function is to be called with the minors_lock
173 mutex held. */
174static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
175{
176 unsigned int minor = iminor(file->f_path.dentry->d_inode);
177 struct hid_device *dev;
178 __u8 *buf;
179 int ret = 0, len;
180 unsigned char report_number;
181
182 dev = hidraw_table[minor]->hid;
183
184 if (!dev->hid_get_raw_report) {
185 ret = -ENODEV;
186 goto out;
187 }
188
189 if (count > HID_MAX_BUFFER_SIZE) {
190 printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
191 task_pid_nr(current));
192 ret = -EINVAL;
193 goto out;
194 }
195
196 if (count < 2) {
197 printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
198 task_pid_nr(current));
199 ret = -EINVAL;
200 goto out;
201 }
202
203 buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
204 if (!buf) {
205 ret = -ENOMEM;
206 goto out;
207 }
208
209 /* Read the first byte from the user. This is the report number,
210 which is passed to dev->hid_get_raw_report(). */
211 if (copy_from_user(&report_number, buffer, 1)) {
212 ret = -EFAULT;
213 goto out_free;
214 }
215
216 ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type);
217
218 if (ret < 0)
219 goto out_free;
220
221 len = (ret < count) ? ret : count;
222
223 if (copy_to_user(buffer, buf, len)) {
224 ret = -EFAULT;
225 goto out_free;
226 }
227
228 ret = len;
229
230out_free:
231 kfree(buf);
232out:
233 return ret;
234}
235
159static unsigned int hidraw_poll(struct file *file, poll_table *wait) 236static unsigned int hidraw_poll(struct file *file, poll_table *wait)
160{ 237{
161 struct hidraw_list *list = file->private_data; 238 struct hidraw_list *list = file->private_data;
@@ -295,7 +372,24 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
295 default: 372 default:
296 { 373 {
297 struct hid_device *hid = dev->hid; 374 struct hid_device *hid = dev->hid;
298 if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) { 375 if (_IOC_TYPE(cmd) != 'H') {
376 ret = -EINVAL;
377 break;
378 }
379
380 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
381 int len = _IOC_SIZE(cmd);
382 ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
383 break;
384 }
385 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
386 int len = _IOC_SIZE(cmd);
387 ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
388 break;
389 }
390
391 /* Begin Read-only ioctls. */
392 if (_IOC_DIR(cmd) != _IOC_READ) {
299 ret = -EINVAL; 393 ret = -EINVAL;
300 break; 394 break;
301 } 395 }
@@ -327,7 +421,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
327 -EFAULT : len; 421 -EFAULT : len;
328 break; 422 break;
329 } 423 }
330 } 424 }
331 425
332 ret = -ENOTTY; 426 ret = -ENOTTY;
333 } 427 }