1 /* 2 * core.c - contains all core device and protocol registration functions 3 * 4 * Copyright 2002 Adam Belay <ambx1@neo.rr.com> 5 * 6 */ 7 8 #include <linux/pnp.h> 9 #include <linux/types.h> 10 #include <linux/list.h> 11 #include <linux/device.h> 12 #include <linux/module.h> 13 #include <linux/init.h> 14 #include <linux/string.h> 15 #include <linux/slab.h> 16 #include <linux/errno.h> 17 #include <linux/dma-mapping.h> 18 19 #include "base.h" 20 21 22 static LIST_HEAD(pnp_protocols); 23 LIST_HEAD(pnp_global); 24 DEFINE_SPINLOCK(pnp_lock); 25 26 void *pnp_alloc(long size) 27 { 28 void *result; 29 30 result = kmalloc(size, GFP_KERNEL); 31 if (!result){ 32 printk(KERN_ERR "pnp: Out of Memory\n"); 33 return NULL; 34 } 35 memset(result, 0, size); 36 return result; 37 } 38 39 /** 40 * pnp_protocol_register - adds a pnp protocol to the pnp layer 41 * @protocol: pointer to the corresponding pnp_protocol structure 42 * 43 * Ex protocols: ISAPNP, PNPBIOS, etc 44 */ 45 46 int pnp_register_protocol(struct pnp_protocol *protocol) 47 { 48 int nodenum; 49 struct list_head * pos; 50 51 if (!protocol) 52 return -EINVAL; 53 54 INIT_LIST_HEAD(&protocol->devices); 55 INIT_LIST_HEAD(&protocol->cards); 56 nodenum = 0; 57 spin_lock(&pnp_lock); 58 59 /* assign the lowest unused number */ 60 list_for_each(pos,&pnp_protocols) { 61 struct pnp_protocol * cur = to_pnp_protocol(pos); 62 if (cur->number == nodenum){ 63 pos = &pnp_protocols; 64 nodenum++; 65 } 66 } 67 68 list_add_tail(&protocol->protocol_list, &pnp_protocols); 69 spin_unlock(&pnp_lock); 70 71 protocol->number = nodenum; 72 sprintf(protocol->dev.bus_id, "pnp%d", nodenum); 73 return device_register(&protocol->dev); 74 } 75 76 /** 77 * pnp_protocol_unregister - removes a pnp protocol from the pnp layer 78 * @protocol: pointer to the corresponding pnp_protocol structure 79 * 80 */ 81 void pnp_unregister_protocol(struct pnp_protocol *protocol) 82 { 83 spin_lock(&pnp_lock); 84 list_del(&protocol->protocol_list); 85 spin_unlock(&pnp_lock); 86 device_unregister(&protocol->dev); 87 } 88 89 90 static void pnp_free_ids(struct pnp_dev *dev) 91 { 92 struct pnp_id * id; 93 struct pnp_id * next; 94 if (!dev) 95 return; 96 id = dev->id; 97 while (id) { 98 next = id->next; 99 kfree(id); 100 id = next; 101 } 102 } 103 104 static void pnp_release_device(struct device *dmdev) 105 { 106 struct pnp_dev * dev = to_pnp_dev(dmdev); 107 pnp_free_option(dev->independent); 108 pnp_free_option(dev->dependent); 109 pnp_free_ids(dev); 110 kfree(dev); 111 } 112 113 int __pnp_add_device(struct pnp_dev *dev) 114 { 115 int ret; 116 pnp_fixup_device(dev); 117 dev->dev.bus = &pnp_bus_type; 118 dev->dev.dma_mask = &dev->dma_mask; 119 dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK; 120 dev->dev.release = &pnp_release_device; 121 dev->status = PNP_READY; 122 spin_lock(&pnp_lock); 123 list_add_tail(&dev->global_list, &pnp_global); 124 list_add_tail(&dev->protocol_list, &dev->protocol->devices); 125 spin_unlock(&pnp_lock); 126 127 ret = device_register(&dev->dev); 128 if (ret == 0) 129 pnp_interface_attach_device(dev); 130 return ret; 131 } 132 133 /* 134 * pnp_add_device - adds a pnp device to the pnp layer 135 * @dev: pointer to dev to add 136 * 137 * adds to driver model, name database, fixups, interface, etc. 138 */ 139 140 int pnp_add_device(struct pnp_dev *dev) 141 { 142 if (!dev || !dev->protocol || dev->card) 143 return -EINVAL; 144 dev->dev.parent = &dev->protocol->dev; 145 sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, dev->number); 146 return __pnp_add_device(dev); 147 } 148 149 void __pnp_remove_device(struct pnp_dev *dev) 150 { 151 spin_lock(&pnp_lock); 152 list_del(&dev->global_list); 153 list_del(&dev->protocol_list); 154 spin_unlock(&pnp_lock); 155 device_unregister(&dev->dev); 156 } 157 158 /** 159 * pnp_remove_device - removes a pnp device from the pnp layer 160 * @dev: pointer to dev to add 161 * 162 * this function will free all mem used by dev 163 */ 164 #if 0 165 void pnp_remove_device(struct pnp_dev *dev) 166 { 167 if (!dev || dev->card) 168 return; 169 __pnp_remove_device(dev); 170 } 171 #endif /* 0 */ 172 173 static int __init pnp_init(void) 174 { 175 printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n"); 176 return bus_register(&pnp_bus_type); 177 } 178 179 subsys_initcall(pnp_init); 180 181 #if 0 182 EXPORT_SYMBOL(pnp_register_protocol); 183 EXPORT_SYMBOL(pnp_unregister_protocol); 184 EXPORT_SYMBOL(pnp_add_device); 185 EXPORT_SYMBOL(pnp_remove_device); 186 #endif /* 0 */ 187