1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19
20 * This is a kernel module for testing usb
21 * kernel functions found in /usr/src/<linux_
22 * dir>/drivers/usb. The module is registered
23 * as a char device with the system so that
24 * ioctl calls can be made in a user space
25 * program that has attained the correct
26 * file descriptor for this module. A usb
27 * driver is registered with the system also
28 * so that it may be used in testing usb
29 * system calls.
30 *
31 * Reference: "Linux Device Drivers" by
32 * Alessandro Rubini and Jonathan Corbet
33 *
34 * Module name: tusb
35 * Author: Sean Ruyle (srruyle@us.ibm.com)
36 * Date: 6/2/2003
37 *
38 * tusb.c
39 */
40
41 #include <linux/autoconf.h>
42 #include <linux/types.h>
43 #include <linux/kernel.h>
44 #include <linux/ioctl.h>
45 #include <linux/fs.h>
46 #include <linux/module.h>
47 #include <linux/init.h>
48 #include <linux/slab.h>
49 #include <linux/usb.h>
50 #include <linux/pci.h>
51 #include <linux/input.h>
52 #include <linux/types.h>
53 #include <linux/kdev_t.h>
54 #include <asm/uaccess.h>
55
56 #include "tusb.h"
57 #include "st_tusb.h"
58
59 MODULE_AUTHOR("Sean Ruyle <srruyle@us.ibm.com>");
60 MODULE_DESCRIPTION(TEST_USB_DRIVER_NAME);
61 MODULE_LICENSE("GPL");
62
63 static int tusb_ioctl(struct inode *, struct file *, unsigned int,
64 unsigned long);
65 static int tusb_open(struct inode *, struct file *);
66 static int tusb_close(struct inode *, struct file *);
67
68 static int test_find_usbdev(void);
69 static int test_find_hcd(void);
70 static int test_hcd_probe(void);
71 static int test_hcd_remove(void);
72 static int test_hcd_suspend(void);
73 static int test_hcd_resume(void);
74 /*
75 * File operations stuff
76 */
77 static int Major = TUSB_MAJOR;
78 static tusb_user_t ltp_usb;
79
80 static struct file_operations tusb_fops = {
81 open: tusb_open,
82 release:tusb_close,
83 ioctl: tusb_ioctl,
84 };
85
tusb_open(struct inode * ino,struct file * f)86 static int tusb_open(struct inode *ino, struct file *f)
87 {
88 return 0;
89 }
90
tusb_close(struct inode * ino,struct file * f)91 static int tusb_close(struct inode *ino, struct file *f)
92 {
93 return 0;
94 }
95
96 /*
97 * usb stuff
98 */
99 struct tusb_device {
100 char name[128];
101 char phys[64];
102 struct usb_device *usbdev;
103 struct input_dev dev;
104 struct urb *irq;
105 int open;
106
107 signed char *data;
108 dma_addr_t data_dma;
109 };
110
tusb_disconnect(struct usb_interface * intf)111 static void tusb_disconnect(struct usb_interface *intf)
112 {
113 printk("tusb: Entered disconnect function\n");
114 }
115
tusb_probe(struct usb_interface * intf,const struct usb_device_id * id)116 static int tusb_probe(struct usb_interface *intf,
117 const struct usb_device_id *id)
118 {
119 printk("tusb: Entered probe function\n");
120 return 0;
121
122 }
123
124 static struct usb_device_id tusb_id_table[] = {
125 {
126 USB_INTERFACE_INFO(3, 1, 1),
127 driver_info:(unsigned long)"keyboard"},
128 {
129 USB_INTERFACE_INFO(3, 1, 2),
130 driver_info:(unsigned long)"mouse"},
131 {
132 0,
133 }
134 };
135
136 MODULE_DEVICE_TABLE(usb, tusb_id_table);
137
138 static struct usb_driver test_usb_driver = {
139 name: "tusb_two",
140 probe: tusb_probe,
141 disconnect:tusb_disconnect,
142 id_table:tusb_id_table,
143 };
144
145 #if 0
146 static int test_alloc_dev(struct usb_device *dev)
147 {
148 printk("Entered test_alloc_dev\n");
149 return 0;
150 }
151
152 static int test_dealloc_dev(struct usb_device *dev)
153 {
154 printk("Entered test_dealloc_dev\n");
155 return 0;
156 }
157
158 static int test_get_current_frame_number(struct usb_device *dev)
159 {
160 printk("Entered test_get_current_frame_number\n");
161 return 0;
162 }
163
164 static int test_submit_urb(struct urb *purb)
165 {
166 printk("Entered test_submit_urb\n");
167 return 0;
168 }
169
170 static int test_unlink_urb(struct urb *purb)
171 {
172 printk("Entered test_unlink_urb\n");
173 return 0;
174 }
175
176 static struct usb_operations test_device_operations = {
177 .allocate = test_alloc_dev,
178 .deallocate = test_dealloc_dev,
179 .get_frame_number = test_get_current_frame_number,
180 .submit_urb = test_submit_urb,
181 .unlink_urb = test_unlink_urb,
182 };
183 #endif
184
tusb_ioctl(struct inode * ino,struct file * f,unsigned int cmd,unsigned long l)185 static int tusb_ioctl(struct inode *ino, struct file *f,
186 unsigned int cmd, unsigned long l)
187 {
188 int rc;
189 tusb_interface_t tif;
190 caddr_t *inparms;
191 caddr_t *outparms;
192
193 printk("tusb: Entered the ioctl call\n");
194
195 rc = 0;
196 inparms = NULL;
197 outparms = NULL;
198
199 if (copy_from_user(&tif, (void *)l, sizeof(tif))) {
200 /* Bad address */
201 return (-EFAULT);
202 }
203
204 /*
205 * Setup inparms and outparms as needed
206 */
207 if (tif.in_len > 0) {
208 inparms = (caddr_t *) kmalloc(tif.in_len, GFP_KERNEL);
209 if (!inparms) {
210 return (-ENOMEM);
211 }
212
213 rc = copy_from_user(inparms, tif.in_data, tif.in_len);
214 if (rc) {
215 kfree(inparms);
216 return (-EFAULT);
217 }
218 }
219 if (tif.out_len > 0) {
220 outparms = (caddr_t *) kmalloc(tif.out_len, GFP_KERNEL);
221 if (!outparms) {
222 kfree(inparms);
223 return (-ENOMEM);
224 }
225 }
226
227 switch (cmd) {
228 case FIND_DEV:
229 rc = test_find_usbdev();
230 break;
231 case TEST_FIND_HCD:
232 rc = test_find_hcd();
233 break;
234 case TEST_HCD_PROBE:
235 rc = test_hcd_probe();
236 break;
237 case TEST_HCD_REMOVE:
238 rc = test_hcd_remove();
239 break;
240 case TEST_HCD_SUSPEND:
241 rc = test_hcd_suspend();
242 break;
243 case TEST_HCD_RESUME:
244 rc = test_hcd_resume();
245 break;
246 default:
247 printk("Mismatching ioctl command\n");
248 rc = 1;
249 break;
250 }
251
252 if (!ltp_usb.dev)
253 printk("tusb: After ioctl call dev DNE\n");
254
255 /*
256 * copy in the return data, and test return code
257 */
258 tif.out_rc = rc;
259 rc = 0;
260
261 /* if outparms then copy outparms into tif.out_data */
262 if (outparms) {
263 if (copy_to_user(tif.out_data, outparms, tif.out_len)) {
264 printk("tpci: Unsuccessful copy_to_user of outparms\n");
265 rc = -EFAULT;
266 }
267 }
268
269 /* copy tif structure into l so that can be used by user program */
270 if (copy_to_user((void *)l, &tif, sizeof(tif))) {
271 printk("tpci: Unsuccessful copy_to_user of tif\n");
272 rc = -EFAULT;
273 }
274
275 /*
276 * free inparms and outparms
277 */
278 if (inparms) {
279 kfree(inparms);
280 }
281 if (outparms) {
282 kfree(outparms);
283 }
284
285 return rc;
286 }
287
288 /*
289 * test_find_usbdev
290 * using our driver, attempt to find
291 * a usb device that our driver can use,
292 * and set the pointers in our test interface
293 * structure to the device pointer so that
294 * it can be used future test calls
295 */
test_find_usbdev()296 static int test_find_usbdev()
297 {
298 struct usb_device *udev =
299 (struct usb_device *)kmalloc(sizeof(struct usb_device), GFP_KERNEL);
300 struct usb_bus *bus =
301 (struct usb_bus *)kmalloc(sizeof(struct usb_bus), GFP_KERNEL);
302
303 /* Zero out the ltp_usb */
304 memset(<p_usb, 0, sizeof(tusb_user_t));
305
306 ltp_usb.bus = bus;
307 ltp_usb.dev = udev;
308
309 /* allocate the usb_bus pointer */
310 #if 0
311 bus = usb_alloc_bus(&test_device_operations);
312 if (!bus) {
313 printk("tusb: Did not allocate a bus\n");
314 return 1;
315 } else {
316 printk("tusb: Allocated a bus pointer\n");
317 memcpy(ltp_usb.bus, bus, sizeof(struct usb_bus));
318 printk("test1\n");
319 }
320
321 /* allocate the usb_device pointer */
322 udev = usb_alloc_dev(NULL, bus);
323 if (udev) {
324 printk("tusb: Found a usb device pointer\n");
325 memcpy(ltp_usb.dev, udev, sizeof(struct usb_device));
326 } else {
327 printk("tusb: Failed find usb device pointer\n");
328 return 1;
329 }
330
331 /* connect the new device and setup pointers */
332 usb_connect(udev);
333 usb_new_device(udev);
334 #endif
335
336 return 0;
337 }
338
339 /*
340 * test_find_hcd
341 * make call to pci_find_class with correct flags
342 * to attempt to find a usb hostcontroller, that
343 * we can later use to test hcd functions, must
344 * have either uchi or ohci usb options enabled
345 * or will not find a device
346 */
test_find_hcd()347 static int test_find_hcd()
348 {
349 struct pci_dev *pdev =
350 (struct pci_dev *)kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
351
352 ltp_usb.pdev = pdev;
353
354 #if 0
355 /* try and get a usb hostcontroller if possible */
356 pdev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, NULL);
357 if (pdev) {
358 printk("tusb: WOOT! Found a usb host controller!\n");
359 printk("tusb: Slot number: %d\n", pdev->devfn);
360
361 memcpy(ltp_usb.pdev, pdev, sizeof(struct pci_dev));
362
363 if (pdev->driver->id_table)
364 printk("tusb: id_table exists\n");
365
366 return 0;
367 } else {
368 printk("tusb: Failed to find host controller\n");
369 printk("tusb: Check kernel options enabled\n");
370 return 1;
371 }
372 #else
373 return 1;
374 #endif
375
376 }
377
378 /*
379 * test_hcd_probe
380 * make call to usb_hcd_pci_probe which will
381 * enable the usb hostcontroller, pass in a pci_dev
382 * and a pci_device_id
383 */
test_hcd_probe()384 static int test_hcd_probe()
385 {
386 int rc;
387 struct usb_hcd *hcd = NULL;
388 struct pci_dev *pdev = ltp_usb.pdev;
389 struct pci_device_id *id = NULL;
390
391 if (!pdev) {
392 printk("tusb: pdev pointer not set\n");
393 return 1;
394 }
395
396 id = (struct pci_device_id *)pdev->driver->id_table;
397
398 if (!id || !id->driver_data) {
399 printk("tusb: id_table not set\n");
400 return 1;
401 }
402
403 /* release regions before probe call */
404 hcd = pci_get_drvdata(pdev);
405
406 if (!hcd) {
407 printk("tusb: hcd pointer not found\n");
408 return 1;
409 } else
410 release_region(pci_resource_start(pdev, hcd->region),
411 pci_resource_len(pdev, hcd->region));
412
413 /* make test call */
414 rc = usb_hcd_pci_probe(pdev, id);
415
416 if (rc)
417 printk("tusb: retval hcd probe = %d\n", rc);
418 else
419 printk("tusb: Success for usb_hcd_pci_probe\n");
420
421 return rc;
422 }
423
424 /*
425 * test_hcd_remove
426 * make call to usb_hcd_pci_remove which will
427 * remove setup for the usb host controller
428 * from the system, attempting to call this
429 * before probe test call so that regions
430 * will be available to the probe test call
431 */
test_hcd_remove()432 static int test_hcd_remove()
433 {
434 struct pci_dev *pdev = NULL;
435 struct usb_hcd *hcd = NULL;
436 struct hc_driver *hdrv = NULL;
437
438 /* check that hcd pointer exists */
439 if (!ltp_usb.pdev) {
440 printk("tusb: pdev pointer not found\n");
441 return 1;
442 } else {
443 pdev = ltp_usb.pdev;
444 hcd = pci_get_drvdata(pdev);
445 }
446
447 if (!hdrv->stop) {
448 printk("tusb: stop function not found\n");
449 return 1;
450 } else
451 hcd->driver->stop(hcd);
452
453 return 0;
454 }
455
456 /*
457 * test_hcd_suspend
458 * make call to suspend with a dev pointer and
459 * a u32 state variable that is the state to
460 * move into
461 */
test_hcd_suspend()462 static int test_hcd_suspend()
463 {
464 int rc;
465 struct pci_dev *pdev = NULL;
466
467 /* check that pdev is set */
468 if (!(pdev = ltp_usb.pdev)) {
469 printk("tusb: Cant find host controller pci_dev pointer\n");
470 return 1;
471 }
472
473 /* make call and check return value */
474 rc = usb_hcd_pci_suspend(pdev, (u32) 2);
475 if (rc)
476 printk("tusb: Suspend retval failure\n");
477 else
478 printk("tusb: Suspend success\n");
479
480 return rc;
481 }
482
483 /*
484 * test_hcd_resume
485 * make call to resume device for power management
486 * so that device will be active and able to use
487 * again
488 */
test_hcd_resume()489 static int test_hcd_resume()
490 {
491 int rc;
492 struct pci_dev *pdev = NULL;
493
494 /* check that pdev is set */
495 if (!(pdev = ltp_usb.pdev)) {
496 printk("tusb: Cant find host controller pci_dev pointer\n");
497 return 1;
498 }
499
500 /* make call and check return value */
501 rc = usb_hcd_pci_resume(pdev);
502 if (rc)
503 printk("tusb: Resume got retval, failure\n");
504 else
505 printk("tusb: Resume success\n");
506
507 return rc;
508 }
509
tusb_init_module(void)510 static int tusb_init_module(void)
511 {
512 int rc;
513
514 SET_MODULE_OWNER(&tusb_fops);
515
516 rc = register_chrdev(Major, DEVICE_NAME, &tusb_fops);
517 if (rc < 0) {
518 printk("tusb: Failed to register tusb device\n");
519 return rc;
520 }
521
522 if (Major == 0)
523 Major = rc;
524
525 printk("tusb: Registration success at major number %i\n", Major);
526 return usb_register(&test_usb_driver);
527 }
528
tusb_exit_module(void)529 static void tusb_exit_module(void)
530 {
531
532 kfree(ltp_usb.dev);
533
534 #if 0
535 usb_free_bus(ltp_usb.bus);
536 #endif
537
538 unregister_chrdev(Major, DEVICE_NAME);
539
540 usb_deregister(&test_usb_driver);
541 }
542
543 module_init(tusb_init_module)
544 module_exit(tusb_exit_module)
545