• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&ltp_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