diff options
Diffstat (limited to 'drivers/gpu/drm/drm_pci.c')
| -rw-r--r-- | drivers/gpu/drm/drm_pci.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 2ea9ad4a8d69..e20f78b542a7 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c | |||
| @@ -124,4 +124,147 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) | |||
| 124 | 124 | ||
| 125 | EXPORT_SYMBOL(drm_pci_free); | 125 | EXPORT_SYMBOL(drm_pci_free); |
| 126 | 126 | ||
| 127 | #ifdef CONFIG_PCI | ||
| 128 | /** | ||
| 129 | * Register. | ||
| 130 | * | ||
| 131 | * \param pdev - PCI device structure | ||
| 132 | * \param ent entry from the PCI ID table with device type flags | ||
| 133 | * \return zero on success or a negative number on failure. | ||
| 134 | * | ||
| 135 | * Attempt to gets inter module "drm" information. If we are first | ||
| 136 | * then register the character device and inter module information. | ||
| 137 | * Try and register, if we fail to register, backout previous work. | ||
| 138 | */ | ||
| 139 | int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | ||
| 140 | struct drm_driver *driver) | ||
| 141 | { | ||
| 142 | struct drm_device *dev; | ||
| 143 | int ret; | ||
| 144 | |||
| 145 | DRM_DEBUG("\n"); | ||
| 146 | |||
| 147 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 148 | if (!dev) | ||
| 149 | return -ENOMEM; | ||
| 150 | |||
| 151 | ret = pci_enable_device(pdev); | ||
| 152 | if (ret) | ||
| 153 | goto err_g1; | ||
| 154 | |||
| 155 | pci_set_master(pdev); | ||
| 156 | |||
| 157 | dev->pdev = pdev; | ||
| 158 | dev->dev = &pdev->dev; | ||
| 159 | |||
| 160 | dev->pci_device = pdev->device; | ||
| 161 | dev->pci_vendor = pdev->vendor; | ||
| 162 | |||
| 163 | #ifdef __alpha__ | ||
| 164 | dev->hose = pdev->sysdata; | ||
| 165 | #endif | ||
| 166 | |||
| 167 | if ((ret = drm_fill_in_dev(dev, ent, driver))) { | ||
| 168 | printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); | ||
| 169 | goto err_g2; | ||
| 170 | } | ||
| 171 | |||
| 172 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 173 | pci_set_drvdata(pdev, dev); | ||
| 174 | ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); | ||
| 175 | if (ret) | ||
| 176 | goto err_g2; | ||
| 177 | } | ||
| 178 | |||
| 179 | if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) | ||
| 180 | goto err_g3; | ||
| 181 | |||
| 182 | if (dev->driver->load) { | ||
| 183 | ret = dev->driver->load(dev, ent->driver_data); | ||
| 184 | if (ret) | ||
| 185 | goto err_g4; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* setup the grouping for the legacy output */ | ||
| 189 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 190 | ret = drm_mode_group_init_legacy_group(dev, | ||
| 191 | &dev->primary->mode_group); | ||
| 192 | if (ret) | ||
| 193 | goto err_g4; | ||
| 194 | } | ||
| 195 | |||
| 196 | list_add_tail(&dev->driver_item, &driver->device_list); | ||
| 197 | |||
| 198 | DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", | ||
| 199 | driver->name, driver->major, driver->minor, driver->patchlevel, | ||
| 200 | driver->date, pci_name(pdev), dev->primary->index); | ||
| 201 | |||
| 202 | return 0; | ||
| 203 | |||
| 204 | err_g4: | ||
| 205 | drm_put_minor(&dev->primary); | ||
| 206 | err_g3: | ||
| 207 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 208 | drm_put_minor(&dev->control); | ||
| 209 | err_g2: | ||
| 210 | pci_disable_device(pdev); | ||
| 211 | err_g1: | ||
| 212 | kfree(dev); | ||
| 213 | return ret; | ||
| 214 | } | ||
| 215 | EXPORT_SYMBOL(drm_get_pci_dev); | ||
| 216 | |||
| 217 | /** | ||
| 218 | * PCI device initialization. Called via drm_init at module load time, | ||
| 219 | * | ||
| 220 | * \return zero on success or a negative number on failure. | ||
| 221 | * | ||
| 222 | * Initializes a drm_device structures,registering the | ||
| 223 | * stubs and initializing the AGP device. | ||
| 224 | * | ||
| 225 | * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and | ||
| 226 | * after the initialization for driver customization. | ||
| 227 | */ | ||
| 228 | int drm_pci_init(struct drm_driver *driver) | ||
| 229 | { | ||
| 230 | struct pci_dev *pdev = NULL; | ||
| 231 | const struct pci_device_id *pid; | ||
| 232 | int i; | ||
| 233 | |||
| 234 | if (driver->driver_features & DRIVER_MODESET) | ||
| 235 | return pci_register_driver(&driver->pci_driver); | ||
| 236 | |||
| 237 | /* If not using KMS, fall back to stealth mode manual scanning. */ | ||
| 238 | for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) { | ||
| 239 | pid = &driver->pci_driver.id_table[i]; | ||
| 240 | |||
| 241 | /* Loop around setting up a DRM device for each PCI device | ||
| 242 | * matching our ID and device class. If we had the internal | ||
| 243 | * function that pci_get_subsys and pci_get_class used, we'd | ||
| 244 | * be able to just pass pid in instead of doing a two-stage | ||
| 245 | * thing. | ||
| 246 | */ | ||
| 247 | pdev = NULL; | ||
| 248 | while ((pdev = | ||
| 249 | pci_get_subsys(pid->vendor, pid->device, pid->subvendor, | ||
| 250 | pid->subdevice, pdev)) != NULL) { | ||
| 251 | if ((pdev->class & pid->class_mask) != pid->class) | ||
| 252 | continue; | ||
| 253 | |||
| 254 | /* stealth mode requires a manual probe */ | ||
| 255 | pci_dev_get(pdev); | ||
| 256 | drm_get_pci_dev(pdev, pid, driver); | ||
| 257 | } | ||
| 258 | } | ||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | #else | ||
| 263 | |||
| 264 | int drm_pci_init(struct drm_driver *driver) | ||
| 265 | { | ||
| 266 | return -1; | ||
| 267 | } | ||
| 268 | |||
| 269 | #endif | ||
| 127 | /*@}*/ | 270 | /*@}*/ |
