Home | History | Annotate | Download | only in tusb
      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 (at) 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 (at) 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 
     86 static int tusb_open(struct inode *ino, struct file *f)
     87 {
     88 	return 0;
     89 }
     90 
     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 
    111 static void tusb_disconnect(struct usb_interface *intf)
    112 {
    113 	printk("tusb: Entered disconnect function\n");
    114 }
    115 
    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 
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    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 
    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