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 test module is for executing and testing
21 * the kernel code from drivers/base. This module
22 * is driven by a user space program through
23 * calls to the ioctl
24 *
25 * author: Sean Ruyle
26 * date:   07/14/2003
27 *
28 * module: tbase
29 */
30
31#include <linux/types.h>
32#include <linux/kernel.h>
33#include <linux/fs.h>
34#include <linux/ioctl.h>
35#include <linux/module.h>
36#include <linux/init.h>
37#include <linux/device.h>
38#include <linux/pci.h>
39#include <linux/sysdev.h>
40#include <asm/uaccess.h>
41
42#include "tbase.h"
43#include "str_mod.h"
44
45MODULE_AUTHOR("Sean Ruyle <srruyle@us.ibm.com>");
46MODULE_DESCRIPTION(TMOD_DRIVER_NAME);
47MODULE_LICENSE("GPL");
48
49static int tbase_ioctl(struct inode *, struct file *, unsigned int,
50		       unsigned long);
51static int tbase_open(struct inode *, struct file *);
52static int tbase_close(struct inode *, struct file *);
53
54static int test_device_register(void);
55static int test_device_unregister(void);
56static int test_bus_add(void);
57static int test_get_drv(void);
58static int test_put_drv(void);
59static int test_reg_firm(void);
60static int test_create_file(void);
61static int test_dev_suspend(void);
62static int test_dev_file(void);
63static int test_bus_rescan(void);
64static int test_bus_file(void);
65static int test_class_reg(void);
66static int test_class_get(void);
67static int test_class_file(void);
68static int test_classdev_reg(void);
69static int test_classint_reg(void);
70static int test_sysdev_cls_reg(void);
71static int test_sysdev_reg(void);
72
73static int Major = TBASEMAJOR;
74static ltpmod_user_t ltp_mod;
75
76/*
77 * File operations struct, to use operations find the
78 * correct file descriptor
79 */
80static struct file_operations tbase_fops = {
81open:	tbase_open,
82release:tbase_close,
83ioctl:	tbase_ioctl,
84};
85
86static int tbase_open(struct inode *ino, struct file *f)
87{
88	return 0;
89}
90
91static int tbase_close(struct inode *ino, struct file *f)
92{
93	return 0;
94}
95
96/* my bus stuff */
97struct device_driver test_driver;
98struct device test_device;
99
100static int test_device_match(struct device *dev, struct device_driver *drv)
101{
102
103	printk("tbase: driver is %s\n", drv->name);
104//      printk("tbase: device is %s\n", dev->name);
105
106	if (drv == &test_driver && dev == &test_device) {
107		printk("tbase: match\n");
108		return 1;
109	} else {
110		printk("tbase: no match\n");
111		return 0;
112	}
113
114}
115
116struct bus_type test_bus_type = {
117	.name = "test_bus",
118	.match = test_device_match,
119};
120
121/* my driver stuff */
122int test_dev_probe(struct device *dev)
123{
124	printk("tbase: Entered test_dev_probe\n");
125	return 0;
126}
127
128int test_dev_remove(struct device *dev)
129{
130	printk("tbase: Entered test_dev_remove\n");
131	return 0;
132}
133
134struct device_driver test_driver = {
135	.name = "TestDriver",
136	.bus = &test_bus_type,
137	.probe = test_dev_probe,
138	.remove = test_dev_remove,
139};
140
141/* my device stuff */
142struct device test_device = {
143//      .name = "TestDevice",
144	.bus = &test_bus_type,
145	.bus_id = "test_bus",
146};
147
148/* my class stuff */
149static void test_class_release(struct class_device *class_dev)
150{
151	printk("tbase: Entered test_class_release\n");
152}
153
154int test_class_hotplug(struct class_device *dev, char **envp,
155		       int num_envp, char *buffer, int buffer_size)
156{
157	printk("tbase: Entered test_class_hotplug\n");
158	return 0;
159}
160
161struct class test_class = {
162	.name = "TestClass",
163	.hotplug = test_class_hotplug,
164	.release = test_class_release,
165};
166
167/* my class device stuff */
168struct class_device test_class_dev = {
169	.class_id = "test_bus",
170	.dev = &test_device,
171	.class = &test_class,
172};
173
174/* my class interface stuff */
175int test_intf_add(struct class_device *class_dev)
176{
177	printk("tbase: Entered test_intf_add for the test class_interface\n");
178	return 0;
179}
180
181void test_intf_rem(struct class_device *class_dev)
182{
183	printk("tbase: Entered test_intf_rem for the test class interface\n");
184}
185
186struct class_interface test_interface = {
187	.class = &test_class,
188	.add = &test_intf_add,
189	.remove = &test_intf_rem,
190};
191
192/* my sys_device stuff */
193int test_resume(struct sys_device *dev)
194{
195	printk("tbase: Entered test resume for sys device\n");
196	return 0;
197}
198
199struct sysdev_class test_sysclass = {
200	set_kset_name("TestSysclass"),
201	.resume = test_resume,
202};
203
204struct sys_device test_sys_device = {
205	.id = 0,
206	.cls = &test_sysclass,
207};
208
209/* my attribute stuff */
210static inline ssize_t
211store_new_id(struct device_driver *driver, const char *buf, size_t count)
212{
213	printk("tbase: Entered store new id\n");
214	return count;
215}
216
217/* create attribute driver_attr_new_id */
218DRIVER_ATTR(new_id, 0200, NULL, store_new_id);
219
220/* create attribute dev_attr_test_id */
221DEVICE_ATTR(test_id, S_IRUGO, NULL, NULL);
222
223/* create attribute bus_attr_test_id */
224BUS_ATTR(test_id, S_IRUGO, NULL, NULL);
225
226/* create attribute class_attr_test_id */
227CLASS_ATTR(test_id, 0644, NULL, NULL);
228
229/* create attribute class_device_attr_test_id */
230CLASS_DEVICE_ATTR(test_id, 0644, NULL, NULL);
231
232/*
233 * tbase_ioctl:
234 *      a user space program can drive the test functions
235 *      through a call to ioctl once the correct file
236 *      descriptor has been attained
237 */
238static int tbase_ioctl(struct inode *ino, struct file *f,
239		       unsigned int cmd, unsigned long l)
240{
241	int rc;
242	tmod_interface_t tif;
243	caddr_t *inparms;
244	caddr_t *outparms;
245
246	printk("Enter tbase_ioctl\n");
247
248	inparms = NULL;
249	outparms = NULL;
250	rc = 0;
251
252	/*
253	 * the following calls are used to setup the
254	 * parameters that might need to be passed
255	 * between user and kernel space, using the tif
256	 * pointer that is passed in as the last
257	 * parameter to the ioctl
258	 *
259	 */
260	if (copy_from_user(&tif, (void *)l, sizeof(tif))) {
261		/* Bad address */
262		return (-EFAULT);
263	}
264
265	/*
266	 * Setup inparms and outparms as needed
267	 */
268	if (tif.in_len > 0) {
269		inparms = (caddr_t *) kmalloc(tif.in_len, GFP_KERNEL);
270		if (!inparms) {
271			return (-ENOMEM);
272		}
273
274		rc = copy_from_user(inparms, tif.in_data, tif.in_len);
275		if (rc) {
276			kfree(inparms);
277			return (-EFAULT);
278		}
279	}
280	if (tif.out_len > 0) {
281		outparms = (caddr_t *) kmalloc(tif.out_len, GFP_KERNEL);
282		if (!outparms) {
283			kfree(inparms);
284			return (-ENOMEM);
285		}
286	}
287
288	/*
289	 * Use a switch statement to determine which function
290	 * to call, based on the cmd flag that is specified
291	 * in user space. Pass in inparms or outparms as
292	 * needed
293	 *
294	 */
295	switch (cmd) {
296	case REG_DEVICE:
297		rc = test_device_register();
298		break;
299	case UNREG_DEVICE:
300		rc = test_device_unregister();
301		break;
302	case BUS_ADD:
303		rc = test_bus_add();
304		break;
305	case GET_DRV:
306		rc = test_get_drv();
307		break;
308	case PUT_DRV:
309		rc = test_put_drv();
310		break;
311	case REG_FIRM:
312		rc = test_reg_firm();
313		break;
314	case CREATE_FILE:
315		rc = test_create_file();
316		break;
317	case DEV_SUSPEND:
318		rc = test_dev_suspend();
319		break;
320	case DEV_FILE:
321		rc = test_dev_file();
322		break;
323	case BUS_RESCAN:
324		rc = test_bus_rescan();
325		break;
326	case BUS_FILE:
327		rc = test_bus_file();
328		break;
329	case CLASS_REG:
330		rc = test_class_reg();
331		break;
332	case CLASS_UNREG:
333		class_unregister(&test_class);
334		break;
335	case CLASS_GET:
336		rc = test_class_get();
337		break;
338	case CLASS_FILE:
339		rc = test_class_file();
340		break;
341	case CLASSDEV_REG:
342		rc = test_classdev_reg();
343		break;
344	case CLASSINT_REG:
345		rc = test_classint_reg();
346		break;
347	case SYSDEV_CLS_REG:
348		rc = test_sysdev_cls_reg();
349		break;
350	case SYSDEV_CLS_UNREG:
351		sysdev_class_unregister(&test_sysclass);
352		break;
353	case SYSDEV_REG:
354		rc = test_sysdev_reg();
355		break;
356	case SYSDEV_UNREG:
357		sys_device_unregister(&test_sys_device);
358		break;
359	default:
360		printk("tbase: Mismatching ioctl command\n");
361		break;
362	}
363
364	/*
365	 * copy in the test return code, the reason we
366	 * this is so that in user space we can tell the
367	 * difference between an error in one of our test
368	 * calls or an error in the ioctl function
369	 */
370	tif.out_rc = rc;
371	rc = 0;
372
373	/*
374	 * setup the rest of tif pointer for returning to
375	 * to user space, using copy_to_user if needed
376	 */
377
378	/* if outparms then copy outparms into tif.out_data */
379	if (outparms) {
380		if (copy_to_user(tif.out_data, outparms, tif.out_len)) {
381			printk
382			    ("tbase: Unsuccessful copy_to_user of outparms\n");
383			rc = -EFAULT;
384		}
385	}
386
387	/* copy tif structure into l so that can be used by user program */
388	if (copy_to_user((void *)l, &tif, sizeof(tif))) {
389		printk("tbase: Unsuccessful copy_to_user of tif\n");
390		rc = -EFAULT;
391	}
392
393	/*
394	 * free inparms and outparms
395	 */
396	if (inparms) {
397		kfree(inparms);
398	}
399	if (outparms) {
400		kfree(outparms);
401	}
402
403	return rc;
404}
405
406/*
407 * test_device_register
408 *	makes call to device register passing in
409 *	the device pointer that we found in a previos
410 *	function, returns an error code
411 */
412static int test_device_register()
413{
414	struct device *dev = ltp_mod.dev;
415	struct device_driver *drv = dev->driver;
416
417	/* check if device register returns an error */
418	if (device_register(dev)) {
419		printk("tbase: Device not registered\n");
420		return 1;
421	} else
422		printk("tbase: Device registered\n");
423
424	driver_unregister(drv);
425
426	/* check if driver_register returns an error */
427	if (driver_register(drv)) {
428		printk("tbase: Driver not registered\n");
429		return 1;
430	} else
431		printk("tbase: Driver registered\n");
432
433	return 0;
434
435}
436
437/*
438 * test_device_unregister
439 * 	make test call to device_unregister which
440 * 	will in turn make calls that will decrememnt
441 * 	the reference count and clean up as required
442 */
443static int test_device_unregister()
444{
445	struct device *dev = ltp_mod.dev;
446
447	/* increment reference count */
448	get_device(dev);
449
450	/* reset remove pointer */
451	if (dev->driver->remove)
452		dev->driver->remove = NULL;
453
454	device_unregister(dev);
455	//check that reference count is smaller by one
456
457	return 0;
458}
459
460/*
461 * test_bus_add
462 *	make call to bus_add_device, which will
463 *	in turn add the device that is passed in
464 *	to the bus
465 */
466static int test_bus_add()
467{
468	/* check if device register returns an error */
469	if (bus_add_device(&test_device)) {
470		printk("tbase: Device not added to bus\n");
471		return 1;
472	} else {
473		printk("tbase: Device added to bus\n");
474		return 0;
475	}
476}
477
478/*
479 * test_get_drv
480 *	make test call to get_driver which should
481 *	return a pointer to the driver passed in
482 *	and increase the reference count to that
483 *	kobject
484 */
485static int test_get_drv()
486{
487	int a, rc;
488	struct device_driver *drv = &test_driver, *tmp = NULL;
489
490	/* get reference count before test call */
491	a = atomic_read(&drv->kobj.refcount);
492
493	/* make test call */
494	if ((tmp = get_driver(drv))) {
495		rc = 0;
496		printk("tbase: get driver returned driver\n");
497	} else {
498		rc = 1;
499		printk("tbase: get driver failed to return driver\n");
500	}
501
502	/* check reference count */
503	if ((a == (atomic_read(&drv->kobj.refcount) - 1))) {
504		rc = 0;
505		printk("tbase: correctly set ref count get driver\n");
506	} else {
507		rc = 1;
508		printk("tbase: incorrect ref count get driver\n");
509	}
510
511	return rc;
512}
513
514/*
515 * test_class_get
516 *	make test call to class_get which should return
517 *	a pointer to the class passed in and increase
518 *	the reference count to that kobject
519 */
520static int test_class_get()
521{
522	int rc;
523	struct class *tmp = NULL;
524
525	/* get reference count before test call */
526	tmp = class_get(&test_class);
527	if (tmp == &test_class) {
528		printk("tbase: Success get class\n");
529		rc = 0;
530	} else {
531		printk("tbase: Failure get class\n");
532		rc = 1;
533	}
534
535	class_put(&test_class);
536	return rc;
537}
538
539/*
540 * test_put_drv
541 *      make test call to put_driver which should
542 *      decrease the reference count to the kobject
543 *      pointer in the driver structure
544 */
545static int test_put_drv()
546{
547	int a, rc;
548	struct device_driver *drv = &test_driver;
549
550	/* get reference count before test call */
551	a = atomic_read(&drv->kobj.refcount);
552
553	/* make test call */
554	put_driver(drv);
555
556	/* check reference count */
557	if ((a == (atomic_read(&drv->kobj.refcount) + 1))) {
558		rc = 0;
559		printk("tbase: correctly set ref count put driver\n");
560	} else {
561		rc = 1;
562		printk("tbase: incorrect ref count put driver\n");
563	}
564
565	return rc;
566}
567
568/*
569 * test_reg_firm
570 *	test call to register_firmware, which will
571 *	register the subsystem, takes in a struct
572 *	subsystem pointer, we can use our bus pointer
573 *	that should have been found in a previous test
574 *	to pass in a subsystem pointer, returns an
575 *	error code
576 */
577static int test_reg_firm()
578{
579	struct subsystem *subsys = NULL;
580
581	/* check pointer exists */
582	if (!(subsys = &test_bus_type.subsys)) {
583		printk("tbase: subsys pointer not set in reg firmware\n");
584		return 1;
585	}
586
587	/* unregiser firmware */
588	firmware_unregister(subsys);
589
590	/* make test call */
591	if (firmware_register(subsys)) {
592		printk("tbase: failed register firmware\n");
593		return 1;
594	} else {
595		printk("tbase: regsitered firmware\n");
596		return 0;
597	}
598
599}
600
601/*
602 * test_create_file
603 *	make test call to create sysfs file for the
604 *	driver and if that call is successful then
605 *	make a call to remove the file
606 */
607static int test_create_file()
608{
609	struct device_driver *drv = &test_driver;
610
611	if (driver_create_file(drv, &driver_attr_new_id)) {
612		printk("tbase: failed create sysfs file\n");
613		return 1;
614	} else {
615		printk("tbase: created sysfs file\n");
616		driver_remove_file(drv, &driver_attr_new_id);
617		return 0;
618	}
619
620}
621
622/*
623 * test_dev_suspend
624 *	make test call to device_suspend and
625 *	if that call is successful then make
626 *	a call to device_resume
627 */
628static int test_dev_suspend()
629{
630	int error = 0;
631
632	error = device_suspend(SUSPEND_SAVE_STATE);
633	if (error)
634		printk("tbase: Failed on device suspend call\n");
635	else {
636		printk("tbase: Successful on device suspend call\n");
637		device_resume();
638	}
639
640	error = device_suspend(SUSPEND_DISABLE);
641	if (error)
642		printk("tbase: Failed on device suspend call\n");
643	else {
644		printk("tbase: Successful on device suspend call\n");
645		device_resume();
646	}
647
648	return error;
649
650}
651
652/*
653 * test_dev_file
654 *	make test call to device_create_file
655 *	and if that call is successful make
656 *	another call to device_remove_file
657 */
658static int test_dev_file()
659{
660	struct device *dev = &test_device;
661
662	if (device_create_file(dev, &dev_attr_test_id)) {
663		printk("tbase: failed to create dev sysfs file\n");
664		return 1;
665	} else {
666		printk("tbase: created dev sysfs file\n");
667		device_remove_file(dev, &dev_attr_test_id);
668		return 0;
669	}
670
671}
672
673/*
674 * test_bus_rescan
675 *	make test call to bus_rescan_devices which
676 *	will rescan the bus and attempt to match devices
677 *	to drivers, will return 0 for no matches or
678 *	the number of matches made, check that the
679 *	value returned is not negative
680 */
681static int test_bus_rescan()
682{
683	int count = 0;
684
685	count = bus_rescan_devices(&test_bus_type);
686	if (count == 0)
687		printk("tbase: found no device/driver matches\n");
688	else if (count > 0)
689		printk("tbase; found match\n");
690	else {
691		printk("tbase: bus rescan failed\n");
692		return count;
693	}
694
695	return 0;
696}
697
698/*
699 * test_bus_file
700 *      make test call to bus_create_file
701 *      and if that call is successful make
702 *      another call to bus_remove_file
703 */
704static int test_bus_file()
705{
706	struct bus_type *bus = &test_bus_type;
707
708	if (bus_create_file(bus, &bus_attr_test_id)) {
709		printk("tbase: failed to create bus sysfs file\n");
710		return 1;
711	} else {
712		printk("tbase: created bus sysfs file\n");
713		bus_remove_file(bus, &bus_attr_test_id);
714		return 0;
715	}
716
717}
718
719/*
720 * test_class_file
721 *      make test call to class_create_file
722 *      and if that call is successful make
723 *      another call to class_remove_file
724 */
725static int test_class_file()
726{
727	struct class *cls = &test_class;
728
729	if (class_create_file(cls, &class_attr_test_id)) {
730		printk("tbase: failed to create class sysfs file\n");
731		return 1;
732	} else {
733		printk("tbase: created class sysfs file\n");
734		class_remove_file(cls, &class_attr_test_id);
735		return 0;
736	}
737
738}
739
740/*
741 * test_class_reg
742 *	make test call to class_register
743 *	with the test_class that is defined
744 *	in this module, if that call is
745 *	successful then call unregister
746 */
747static int test_class_reg()
748{
749	int error;
750
751	error = class_register(&test_class);
752	if (error)
753		printk("tbase: class register failed\n");
754	else
755		printk("tbase: class register succeeded\n");
756
757	return error;
758}
759
760/*
761 * test_classdev_reg
762 *	make test call to class_device_register
763 *	and if that returns successful then
764 *	make call to class_device_unregister
765 */
766static int test_classdev_reg()
767{
768	int rc = 0;
769
770	if (class_device_register(&test_class_dev)) {
771		printk("tbase: Failed to register class device\n");
772		rc = 1;
773	} else {
774		printk("tbase: Registered class device\n");
775
776		/* make class device sysfs file */
777		if (class_device_create_file
778		    (&test_class_dev, &class_device_attr_test_id)) {
779			rc = 1;
780			printk
781			    ("tbase: Failed to create class device sysfs file\n");
782		} else {
783			printk("tbase: Created class device sysfs file\n");
784			class_device_remove_file(&test_class_dev,
785						 &class_device_attr_test_id);
786		}
787
788		class_device_unregister(&test_class_dev);
789	}
790
791	return rc;
792}
793
794/*
795 * test_classint_reg
796 *	make test call to class_interface_register
797 *	and if that returns successfule then
798 *	make call to class_interface_unregister
799 */
800static int test_classint_reg()
801{
802
803	if (class_interface_register(&test_interface)) {
804		printk("tbase: Failed to register class interface\n");
805		return 1;
806	} else {
807		printk("tbase: Registered class interface\n");
808		class_interface_unregister(&test_interface);
809		return 0;
810	}
811
812}
813
814/*
815 * test_sysdev_cls_reg
816 *	make test call to sysdev_class_register
817 *	to register the test_sysclass pointer
818 *	as a sysdev_class with the system, check
819 *	the return code
820 */
821static int test_sysdev_cls_reg()
822{
823
824	if (sysdev_class_register(&test_sysclass)) {
825		printk("tbase: Failed to register sysdev class\n");
826		return 1;
827	} else {
828		printk("tbase: Registered sysdev class\n");
829		return 0;
830	}
831
832}
833
834/*
835 * test_sysdev_reg
836 *      make test call to sys_device_register
837 *      to register the test_sysdev pointer
838 *      as a sys_device with the system, check
839 *      the return code
840 */
841static int test_sysdev_reg()
842{
843
844	if (sys_device_register(&test_sys_device)) {
845		printk("tbase: Failed to register sysdev \n");
846		return 1;
847	} else {
848		printk("tbase: Registered sysdev \n");
849		return 0;
850	}
851
852}
853
854/*
855 * tbase_init_module
856 *      set the owner of tbase_fops, register the module
857 *      as a char device, and perform any necessary
858 *      initialization
859 */
860static int tbase_init_module(void)
861{
862	int rc;
863
864	bus_register(&test_bus_type);
865	driver_register(&test_driver);
866	device_register(&test_device);
867
868	tbase_fops.owner = THIS_MODULE;
869
870	printk("tbase: *** Register device %s **\n", DEVICE_NAME);
871
872	rc = register_chrdev(Major, DEVICE_NAME, &tbase_fops);
873	if (rc < 0) {
874		printk("tbase: Failed to register device.\n");
875		return rc;
876	}
877
878	if (Major == 0)
879		Major = rc;
880
881	/* call any other init functions you might use here */
882
883	printk("tbase: Registration success.\n");
884	return 0;
885}
886
887/*
888 * tmod_exit_module
889 *      unregister the device and any necessary
890 *      operations to close devices
891 */
892static void tbase_exit_module(void)
893{
894	int rc;
895
896	device_unregister(&test_device);
897	driver_unregister(&test_driver);
898	bus_unregister(&test_bus_type);
899
900	/* free any pointers still allocated, using kfree */
901
902	rc = unregister_chrdev(Major, DEVICE_NAME);
903	if (rc < 0)
904		printk("tbase: unregister failed\n");
905	else
906		printk("tbase: unregister success\n");
907
908}
909
910/* specify what that init is run when the module is first
911loaded and that exit is run when it is removed */
912
913module_init(tbase_init_module)
914    module_exit(tbase_exit_module)
915