Home | History | Annotate | Download | only in kernel_space
      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 /*
     21  * This example module shows how a test driver
     22  * can be driven through various ioctl calls in
     23  * a user space program that has attained the
     24  * appropriate file descriptor for this device.
     25  *
     26  * author: Kai Zhao
     27  * date:   08/25/2003
     28  *
     29  * module: tagp
     30  */
     31 
     32 #include <linux/types.h>
     33 #include <linux/kernel.h>
     34 #include <linux/fs.h>
     35 #include <linux/ioctl.h>
     36 #include <linux/module.h>
     37 #include <linux/init.h>
     38 #include <asm/uaccess.h>
     39 
     40 #include <linux/pci.h>
     41 #include <linux/agp_backend.h>
     42 #include <linux/gfp.h>
     43 #include <linux/page-flags.h>
     44 #include <linux/mm.h>
     45 
     46 //#include "agp.h"
     47 
     48 #include "tagp.h"
     49 #include "str_agp.h"
     50 
     51 MODULE_AUTHOR("kai zhao <ltcd3 (at) cn.ibm.com>");
     52 MODULE_DESCRIPTION(tagp_DRIVER_NAME);
     53 MODULE_LICENSE("GPL");
     54 
     55 static int tagp_ioctl(struct inode *, struct file *, unsigned int,
     56 		      unsigned long);
     57 static int tagp_open(struct inode *, struct file *);
     58 static int tagp_close(struct inode *, struct file *);
     59 
     60 static int test_pci_find_device(void);
     61 static int test_agp_backend_acquire(void);
     62 static int test_agp_backend_release(void);
     63 static int test_agp_alloc_bridge(void);
     64 static int test_agp_put_bridge(void);
     65 static int test_agp_create_and_free_memory(void);
     66 //static int test_agp_free_memory(void);
     67 static int test_agp_num_entries(void);
     68 static int test_agp_copy_info(void);
     69 //static int test_agp_allocate_memory(void);
     70 static int test_get_agp_version(void);
     71 static int test_agp_generic_enable(void);
     72 static int test_agp_generic_create_gatt_table(void);
     73 static int test_agp_generic_free_gatt_table(void);
     74 static int test_agp_generic_insert_memory(void);
     75 static int test_agp_generic_alloc_by_type(void);
     76 static int test_agp_generic_alloc_page(void);
     77 //static int test_agp_generic_destroy_page(void);
     78 static int test_agp_enable(void);
     79 static int test_global_cache_flush(void);
     80 static int test_agp_generic_mask_memory(void);
     81 
     82 static int Major = TAGP_MAJOR;
     83 //static ltpmod_user_t ltp_mod;
     84 
     85 /*
     86  * File operations struct, to use operations find the
     87  * correct file descriptor
     88  */
     89 static struct file_operations tagp_fops = {
     90 open:	tagp_open,
     91 release:tagp_close,
     92 ioctl:	tagp_ioctl,
     93 };
     94 
     95 /*
     96  * open and close operations, just return 0 for
     97  * your test modules, need them for the file
     98  * operations structure
     99  */
    100 static int tagp_open(struct inode *ino, struct file *f)
    101 {
    102 	return 0;
    103 }
    104 
    105 static int tagp_close(struct inode *ino, struct file *f)
    106 {
    107 	return 0;
    108 }
    109 
    110 /*
    111  * tagp_ioctl:
    112  *      a user space program can drive the test functions
    113  *      through a call to ioctl once the correct file
    114  *      descriptor has been attained
    115  *
    116  * 	in user space the file descriptor that you attain
    117  * 	will represent the inode and file pointers in
    118  * 	the kernel ioctl function, and only 3 variables
    119  *	will be passed in, linux/ioctl.h should be
    120  *	included
    121  *
    122  */
    123 static int tagp_ioctl(struct inode *ino, struct file *f,
    124 		      unsigned int cmd, unsigned long l)
    125 {
    126 	int rc;
    127 	tagp_interface_t tif;
    128 	caddr_t *inparms;
    129 	caddr_t *outparms;
    130 
    131 	printk("Enter tagp_ioctl\n");
    132 
    133 	inparms = NULL;
    134 	outparms = NULL;
    135 	rc = 0;
    136 
    137 	/*
    138 	 * the following calls are used to setup the
    139 	 * parameters that might need to be passed
    140 	 * between user and kernel space, using the tif
    141 	 * pointer that is passed in as the last
    142 	 * parameter to the ioctl
    143 	 *
    144 	 */
    145 	if (copy_from_user(&tif, (void *)l, sizeof(tif))) {
    146 		/* Bad address */
    147 		return (-EFAULT);
    148 	}
    149 
    150 	/*
    151 	 * Setup inparms and outparms as needed
    152 	 */
    153 	if (tif.in_len > 0) {
    154 		inparms = (caddr_t *) kmalloc(tif.in_len, GFP_KERNEL);
    155 		if (!inparms) {
    156 			return (-ENOMEM);
    157 		}
    158 
    159 		rc = copy_from_user(inparms, tif.in_data, tif.in_len);
    160 		if (rc) {
    161 			kfree(inparms);
    162 			return (-EFAULT);
    163 		}
    164 	}
    165 	if (tif.out_len > 0) {
    166 		outparms = (caddr_t *) kmalloc(tif.out_len, GFP_KERNEL);
    167 		if (!outparms) {
    168 			kfree(inparms);
    169 			return (-ENOMEM);
    170 		}
    171 	}
    172 
    173 	/*
    174 	 * Use a switch statement to determine which function
    175 	 * to call, based on the cmd flag that is specified
    176 	 * in user space. Pass in inparms or outparms as
    177 	 * needed
    178 	 *
    179 	 */
    180 	switch (cmd) {
    181 	case TEST_PCI_FIND_DEV:
    182 		rc = test_pci_find_device();
    183 		break;
    184 	case TEST_BACKEND_ACQUIRE:
    185 		rc = test_agp_backend_acquire();
    186 		break;
    187 	case TEST_BACKEND_RELEASE:
    188 		rc = test_agp_backend_release();
    189 		break;
    190 	case TEST_ALLOC_BRIDGE:
    191 		rc = test_agp_alloc_bridge();
    192 		break;
    193 	case TEST_PUT_BRIDGE:
    194 		rc = test_agp_put_bridge();
    195 		break;
    196 	case TEST_CREATE_AND_FREE_MEMORY:
    197 		rc = test_agp_create_and_free_memory();
    198 		break;
    199 //              case TEST_FREE_MEMORY:                  rc = test_agp_free_memory();break;
    200 	case TEST_NUM_ENTRIES:
    201 		rc = test_agp_num_entries();
    202 		break;
    203 	case TEST_COPY_INFO:
    204 		rc = test_agp_copy_info();
    205 		break;
    206 //              case TEST_ALLOC_MEMORY_AND_BAND_UNBAND: rc = test_agp_allocate_memory();break;
    207 	case TEST_GET_VERSION:
    208 		rc = test_get_agp_version();
    209 		break;
    210 	case TEST_GENERIC_ENABLE:
    211 		rc = test_agp_generic_enable();
    212 		break;
    213 	case TEST_GENERIC_CREATE_GATT_TABLE:
    214 		rc = test_agp_generic_create_gatt_table();
    215 		break;
    216 	case TEST_GENERIC_FREE_GATT_TABLE:
    217 		rc = test_agp_generic_free_gatt_table();
    218 		break;
    219 	case TEST_GENERIC_INSERT_MEMROY:
    220 		rc = test_agp_generic_insert_memory();
    221 		break;
    222 	case TEST_GENERIC_ALLOC_BY_TYPE:
    223 		rc = test_agp_generic_alloc_by_type();
    224 		break;
    225 	case TEST_GENERIC_ALLOC_PAGE:
    226 		rc = test_agp_generic_alloc_page();
    227 		break;
    228 	case TEST_ENABLE:
    229 		rc = test_agp_enable();
    230 		break;
    231 	case TEST_GLOBAL_CACHE_FLUSH:
    232 		rc = test_global_cache_flush();
    233 		break;
    234 	case TEST_GENERIC_MASK_MEMORY:
    235 		rc = test_agp_generic_mask_memory();
    236 		break;
    237 
    238 	default:
    239 		printk("Mismatching ioctl command\n");
    240 		break;
    241 	}
    242 
    243 	/*
    244 	 * copy in the test return code, the reason we
    245 	 * this is so that in user space we can tell the
    246 	 * difference between an error in one of our test
    247 	 * calls or an error in the ioctl function
    248 	 */
    249 	tif.out_rc = rc;
    250 	rc = 0;
    251 
    252 	/*
    253 	 * setup the rest of tif pointer for returning to
    254 	 * to user space, using copy_to_user if needed
    255 	 */
    256 
    257 	/* if outparms then copy outparms into tif.out_data */
    258 	if (outparms) {
    259 		if (copy_to_user(tif.out_data, outparms, tif.out_len)) {
    260 			printk("tpci: Unsuccessful copy_to_user of outparms\n");
    261 			rc = -EFAULT;
    262 		}
    263 	}
    264 
    265 	/* copy tif structure into l so that can be used by user program */
    266 	if (copy_to_user((void *)l, &tif, sizeof(tif))) {
    267 		printk("tpci: Unsuccessful copy_to_user of tif\n");
    268 		rc = -EFAULT;
    269 	}
    270 
    271 	/*
    272 	 * free inparms and outparms
    273 	 */
    274 	if (inparms) {
    275 		kfree(inparms);
    276 	}
    277 	if (outparms) {
    278 		kfree(outparms);
    279 	}
    280 
    281 	return rc;
    282 }
    283 
    284 /*
    285  *  Function and structure needed by agp_bridge.
    286  */
    287 
    288 static struct aper_size_info_fixed test_core_agp_sizes[] = {
    289 	{0, 0, 0},
    290 };
    291 
    292 static int test_fetch_size(void)
    293 {
    294 	printk("<1> tagp : Enter test fetch size\n");
    295 	return 0;
    296 
    297 }
    298 
    299 static int test_configure(void)
    300 {
    301 	/* Do not config test_core_agp_size */
    302 	printk("<1> tagp : Enter test configure\n");
    303 	return 0;
    304 }
    305 
    306 static void test_cleanup(void)
    307 {
    308 	printk("<1> tagp : Enter test_cleanup\n");
    309 	return;
    310 }
    311 
    312 static void test_tlbflush(struct agp_memory *temp)
    313 {
    314 	printk("<1> tagp : Enter test tlbflush\n");
    315 	return;
    316 }
    317 
    318 /*
    319  *  structure used by agp_bridge
    320  */
    321 struct agp_bridge_driver test_driver = {
    322 	.owner = THIS_MODULE,
    323 	.aperture_sizes = test_core_agp_sizes,
    324 	.size_type = U8_APER_SIZE,
    325 	.num_aperture_sizes = 7,
    326 	.configure = test_configure,
    327 	.fetch_size = test_fetch_size,
    328 	.cleanup = test_cleanup,
    329 	.tlb_flush = test_tlbflush,
    330 	.mask_memory = agp_generic_mask_memory,
    331 	.masks = NULL,
    332 	.agp_enable = agp_generic_enable,
    333 	.cache_flush = global_cache_flush,
    334 	.create_gatt_table = agp_generic_create_gatt_table,
    335 	.free_gatt_table = agp_generic_free_gatt_table,
    336 	.insert_memory = agp_generic_insert_memory,
    337 	.remove_memory = agp_generic_remove_memory,
    338 	.alloc_by_type = agp_generic_alloc_by_type,
    339 	.free_by_type = agp_generic_free_by_type,
    340 	.agp_alloc_page = agp_generic_alloc_page,
    341 	.agp_destroy_page = agp_generic_destroy_page,
    342 };
    343 
    344 /*
    345  * test functions can go here or in a seperate file,
    346  * remember that the makefile will have to be  modified
    347  * as well as the header file will need the function
    348  * prototypes if the test calls go in another file
    349  *
    350  * functions should be static so that they may not
    351  * be called by outside functions, in the kernel
    352  * if a function is non_static and the symbol is
    353  * exported using EXPORT_SYMBOL(function_name)
    354  * then other parts of the kernel such as modules
    355  * may use that function
    356  *
    357  */
    358 
    359 static int test_agp_backend_acquire(void)
    360 {
    361 	printk("<1> tagp : Enter test_agp_backend_acquire\n");
    362 	agp_backend_acquire();
    363 	return 0;
    364 }
    365 
    366 static int test_agp_backend_release(void)
    367 {
    368 	printk("<1> tagp : Enter test_agp_backend_release\n");
    369 	agp_backend_release();
    370 	return 0;
    371 }
    372 
    373 static int test_agp_alloc_bridge(void)
    374 {
    375 //      struct agp_bridge_data *tmp_bridge;
    376 	tmp_bridge = agp_alloc_bridge();
    377 //      agp_put_bridge (tmp_bridge);
    378 //      tmp_bridge = NULL;
    379 	return 0;
    380 }
    381 
    382 static int test_agp_put_bridge(void)
    383 {
    384 	agp_put_bridge(tmp_bridge);
    385 	tmp_bridge = NULL;
    386 	return 0;
    387 }
    388 
    389 static int test_agp_create_and_free_memory(void)
    390 {
    391 	struct agp_memory *tmp_agp_memory = NULL;
    392 	/* int scratch_pages */
    393 	if (agp_bridge->scratch_page > 0) {
    394 		printk("<1> tagp : agp_bridge->scratch_page : %ld\n",
    395 		       agp_bridge->scratch_page);
    396 		tmp_agp_memory = agp_create_memory(agp_bridge->scratch_page);
    397 	} else {
    398 		printk("<1> tagp : agp_bridge->scratch_page : %ld\n",
    399 		       agp_bridge->scratch_page);
    400 		tmp_agp_memory = agp_create_memory(64);
    401 	}
    402 	if (tmp_agp_memory != NULL) {
    403 		agp_free_memory(tmp_agp_memory);
    404 		return 0;
    405 	}
    406 	return 1;
    407 }
    408 
    409 /*
    410 static int test_agp_free_memory(void)
    411 {
    412 	if (tmp_agp_memory != NULL)
    413 	{
    414 		agp_free_memory(tmp_agp_memory);
    415 		return 0;
    416 	}
    417 	return 1;
    418 }
    419 */
    420 static int test_agp_num_entries(void)
    421 {
    422 	int ret = agp_num_entries();
    423 	printk("<1> tagp : agp_num_entries return %d\n", ret);
    424 	return 0;
    425 }
    426 
    427 ////////////////////////////////////////////////////////////////////////////
    428 static int test_agp_copy_info(void)
    429 {
    430 	struct agp_kern_info *info;
    431 	int ret;
    432 
    433 	info =
    434 	    (struct agp_kern_info *)kmalloc(sizeof(struct agp_kern_info),
    435 					    GFP_KERNEL);
    436 	if (!info) {
    437 		printk("<1> tagp : can not alloc spece\n");
    438 		return 1;
    439 	}
    440 	ret = agp_copy_info(info);
    441 	if (ret) {
    442 		printk("<1> tagp : agp_copy_info failed\n");
    443 		return 1;
    444 	}
    445 	kfree(info);
    446 
    447 	return 0;
    448 }
    449 
    450 /*
    451 static int test_agp_allocate_memory(void)
    452 {
    453 	struct agp_memory * local_agp_memory = NULL;
    454 	int ret = 0 , i = 0;
    455 
    456 	local_agp_memory = agp_allocate_memory(8,AGP_NORMAL_MEMORY);
    457 
    458 	if (local_agp_memory == NULL)
    459 	{
    460 		printk("<1> tagp : agp_allocate_memory failed\n");
    461 		return 1;
    462 	}
    463 
    464 	ret = agp_bind_memory(local_agp_memory, 64);
    465 	if (ret)
    466 	{
    467 		agp_free_memory(local_agp_memory);
    468 		printk("<1> tagp : agp bind memory failed\n");
    469 		return 1;
    470 	}
    471 	printk("<1> tagp : agp bind memory success\n");
    472 	ret = agp_unbind_memory(local_agp_memory);
    473 	if (ret)
    474 	{
    475 		agp_free_memory(local_agp_memory);
    476 		printk("<1> tagp : agp unband memory failed\n");
    477 	}
    478 
    479 	for (i = 0; i < 8; i++) {
    480 		phys_to_virt(local_agp_memory->memory[i]);//virt_to_phys(addr);
    481 		local_agp_memory->page_count--;
    482 	}
    483 
    484 	agp_free_memory(local_agp_memory);
    485 	printk("<1> tagp : agp unband memory success\n");
    486 
    487 	return 0;
    488 }
    489 */
    490 static int test_get_agp_version(void)
    491 {
    492 	printk("<1> tagp : Enter test_get_agp_version\n");
    493 	get_agp_version(agp_bridge);
    494 	return 0;
    495 }
    496 
    497 static int test_agp_generic_enable(void)
    498 {
    499 	printk("<1> tagp : Enter test_agp_generic_enable\n");
    500 	agp_generic_enable(agp_bridge->mode);
    501 	return 0;
    502 }
    503 
    504 static int test_agp_generic_create_gatt_table(void)
    505 {
    506 	printk("<1> tagp : Enter test_agp_generic_create_gatt_table\n");
    507 	return agp_generic_create_gatt_table();
    508 }
    509 
    510 static int test_agp_generic_free_gatt_table(void)
    511 {
    512 	printk("<1> tagp : Enter test_agp_generic_free_gatt_table\n");
    513 	return agp_generic_free_gatt_table();
    514 }
    515 
    516 static int test_agp_generic_insert_memory(void)
    517 {
    518 	struct agp_memory *tmp_agp_memory = NULL;
    519 	/* int scratch_pages */
    520 	if (agp_bridge->scratch_page > 0)
    521 		tmp_agp_memory = agp_create_memory(agp_bridge->scratch_page);
    522 	else
    523 		tmp_agp_memory = agp_create_memory(64);
    524 	if (tmp_agp_memory != NULL) {
    525 		if (agp_generic_insert_memory(tmp_agp_memory, 16, 0)) {
    526 			printk("<1> tagp : agp_generic_insert_memory failed\n");
    527 			agp_free_memory(tmp_agp_memory);
    528 			return 1;
    529 		} else {
    530 			printk
    531 			    ("<1> tagp : agp_generic_insert_memory success\n");
    532 			agp_generic_remove_memory(tmp_agp_memory, 16, 0);
    533 			agp_free_memory(tmp_agp_memory);
    534 		}
    535 	}
    536 	return 0;
    537 }
    538 
    539 static int test_agp_generic_alloc_by_type(void)
    540 {
    541 	/* size_t page_count, int type */
    542 	agp_generic_alloc_by_type(0, 0);
    543 	return 0;
    544 }
    545 
    546 static int test_agp_generic_alloc_page(void)
    547 {
    548 	printk("<1> tagp : Enter test_agp_generic_alloc_page\n");
    549 	void *ppage = agp_generic_alloc_page();
    550 	if (ppage != NULL)
    551 		agp_generic_destroy_page(ppage);
    552 	return 0;
    553 }
    554 
    555 static int test_agp_enable(void)
    556 {
    557 	printk("<1> tagp : Enter test_agp_enable\n");
    558 	agp_enable(agp_bridge->mode);
    559 	return 0;
    560 }
    561 
    562 static int test_global_cache_flush(void)
    563 {
    564 	printk("<1> tagp : Enter test_global_cache_flush\n");
    565 	global_cache_flush();
    566 	return 0;
    567 }
    568 
    569 static int test_agp_generic_mask_memory(void)
    570 {
    571 	printk("<1> tagp : Enter test_agp_generic_mask_memory\n");
    572 	unsigned long temp;
    573 	temp = agp_generic_mask_memory(1000, agp_bridge->type);
    574 	return 0;
    575 }
    576 
    577 static int test_pci_find_device()
    578 {
    579 	struct pci_dev *pdev;	// = (struct pci_dev *)kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
    580 	struct agp_bridge_data *bridge = NULL;
    581 
    582 	pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, NULL);
    583 
    584 	if (pdev) {
    585 		printk("<1> tagp : pci find device success\n");
    586 
    587 		u8 cap_ptr;
    588 
    589 		cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
    590 		if (!cap_ptr) {
    591 			printk("<1> tagp : pci find capability Failed\n");
    592 			return -ENODEV;
    593 		}
    594 
    595 		printk("<1> tagp : pci find capability success \n");
    596 		bridge = agp_alloc_bridge();
    597 		if (!bridge) {
    598 			printk("<1> tagp : agp alloc bridge Failed\n");
    599 			return -ENOMEM;
    600 		}
    601 		printk("<1> tagp : agp alloc bridge success\n");
    602 		bridge->driver = &test_driver;
    603 		bridge->dev = pdev;
    604 		bridge->capndx = cap_ptr;
    605 
    606 		/* Fill in the mode register */
    607 		pci_read_config_dword(pdev,
    608 				      bridge->capndx + PCI_AGP_STATUS,
    609 				      &bridge->mode);
    610 		printk("<1> tagp : agp read config dword  success\n");
    611 		pci_set_drvdata(pdev, bridge);
    612 		printk("<1> tagp : agp set drvdata  success\n");
    613 		return agp_add_bridge(bridge);
    614 	}
    615 
    616 	return 1;
    617 }
    618 
    619 static int __init agp_test_probe(struct pci_dev *pdev,
    620 				 const struct pci_device_id *ent)
    621 {
    622 
    623 	printk("<1> tagp :Enter agp test probe\n");
    624 	return 0;
    625 
    626 }
    627 
    628 static void __devexit agp_test_remove(struct pci_dev *pdev)
    629 {
    630 	printk("<1> tagp: Enter agp test remove\n");
    631 	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
    632 
    633 	agp_remove_bridge(bridge);
    634 	agp_put_bridge(bridge);
    635 }
    636 
    637 static struct pci_device_id agp_test_pci_table[] __initdata = {
    638 	{
    639 	 .class = (PCI_CLASS_BRIDGE_HOST << 8),
    640 	 .class_mask = ~0,
    641 	 .vendor = PCI_ANY_ID,	//VENDOR_ID_ATI,
    642 	 .device = PCI_ANY_ID,
    643 	 .subvendor = PCI_ANY_ID,
    644 	 .subdevice = PCI_ANY_ID,
    645 	 },
    646 	{}
    647 };
    648 
    649 MODULE_DEVICE_TABLE(pci, agp_test_pci_table);
    650 
    651 static struct pci_driver agp_test_pci_driver = {
    652 	.name = "agp_test",
    653 	.id_table = agp_test_pci_table,
    654 	.probe = agp_test_probe,
    655 	.remove = agp_test_remove,
    656 };
    657 
    658 /*
    659  * tagp_init_module
    660  *      set the owner of tagp_fops, register the module
    661  *      as a char device, and perform any necessary
    662  *      initialization for pci devices
    663  */
    664 static int __init tagp_init_module(void)
    665 {
    666 	int rc;
    667 
    668 //      SET_MODULE_OWNER(&tagp_fops);
    669 	tagp_fops.owner = THIS_MODULE;
    670 
    671 	rc = register_chrdev(Major, DEVICE_NAME, &tagp_fops);
    672 	if (rc < 0) {
    673 		printk("tagp: Failed to register device.\n");
    674 		return rc;
    675 	}
    676 
    677 	if (Major == 0)
    678 		Major = rc;
    679 
    680 	rc = pci_module_init(&agp_test_pci_driver);
    681 
    682 	if (rc < 0) {
    683 		printk("tagp: pci_module_init failed.\n");
    684 		return rc;
    685 	}
    686 
    687 	printk("tagp: PCI module init success.\n");
    688 	printk("tagp: Registration success.\n");
    689 
    690 	return 0;
    691 }
    692 
    693 /*
    694  * tagp_exit_module
    695  *      unregister the device and any necessary
    696  *      operations to close devices
    697  */
    698 static void __exit tagp_exit_module(void)
    699 {
    700 	int rc;
    701 
    702 	/* free any pointers still allocated, using kfree */
    703 	rc = unregister_chrdev(Major, DEVICE_NAME);
    704 	if (rc < 0)
    705 		printk("tagp: unregister failed\n");
    706 	else
    707 		printk("tagp: unregister success\n");
    708 
    709 	pci_unregister_driver(&agp_test_pci_driver);
    710 }
    711 
    712 /* specify what that init is run when the module is first
    713 loaded and that exit is run when it is removed */
    714 
    715 module_init(tagp_init_module)
    716     module_exit(tagp_exit_module)
    717