Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / common / xf86platformBus.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright © 2012 Red Hat.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * Author: Dave Airlie <airlied@redhat.com>
23 */
24
25/*
26 * This file contains the interfaces to the bus-specific code
27 */
28
29#ifdef HAVE_XORG_CONFIG_H
30#include <xorg-config.h>
31#endif
32
33#ifdef XSERVER_PLATFORM_BUS
34#include <errno.h>
35
36#include <pciaccess.h>
37#include <fcntl.h>
38#include <unistd.h>
39#include "os.h"
40#include "hotplug.h"
41
42#include "xf86.h"
43#include "xf86_OSproc.h"
44#include "xf86Priv.h"
45#include "xf86str.h"
46#include "xf86Bus.h"
47#include "Pci.h"
48#include "xf86platformBus.h"
49
50#include "randrstr.h"
51int platformSlotClaimed;
52
53int xf86_num_platform_devices;
54
55static struct xf86_platform_device *xf86_platform_devices;
56
57int
58xf86_add_platform_device(struct OdevAttributes *attribs)
59{
60 xf86_platform_devices = xnfrealloc(xf86_platform_devices,
61 (sizeof(struct xf86_platform_device)
62 * (xf86_num_platform_devices + 1)));
63
64 xf86_platform_devices[xf86_num_platform_devices].attribs = attribs;
65 xf86_platform_devices[xf86_num_platform_devices].pdev = NULL;
66
67 xf86_num_platform_devices++;
68 return 0;
69}
70
71int
72xf86_remove_platform_device(int dev_index)
73{
74 int j;
75
76 config_odev_free_attribute_list(xf86_platform_devices[dev_index].attribs);
77
78 for (j = dev_index; j < xf86_num_platform_devices - 1; j++)
79 memcpy(&xf86_platform_devices[j], &xf86_platform_devices[j + 1], sizeof(struct xf86_platform_device));
80 xf86_num_platform_devices--;
81 return 0;
82}
83
84Bool
85xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_name)
86{
87 struct xf86_platform_device *device = &xf86_platform_devices[index];
88
89 return config_odev_add_attribute(device->attribs, attrib_id, attrib_name);
90}
91
92char *
93xf86_get_platform_attrib(int index, int attrib_id)
94{
95 struct xf86_platform_device *device = &xf86_platform_devices[index];
96 struct OdevAttribute *oa;
97
98 xorg_list_for_each_entry(oa, &device->attribs->list, member) {
99 if (oa->attrib_id == attrib_id)
100 return oa->attrib_name;
101 }
102 return NULL;
103}
104
105char *
106xf86_get_platform_device_attrib(struct xf86_platform_device *device, int attrib_id)
107{
108 struct OdevAttribute *oa;
109
110 xorg_list_for_each_entry(oa, &device->attribs->list, member) {
111 if (oa->attrib_id == attrib_id)
112 return oa->attrib_name;
113 }
114 return NULL;
115}
116
117Bool
118xf86_get_platform_device_unowned(int index)
119{
120 return xf86_platform_devices[index].attribs->unowned;
121}
122
123/*
124 * xf86IsPrimaryPlatform() -- return TRUE if primary device
125 * is a platform device and it matches this one.
126 */
127
128static Bool
129xf86IsPrimaryPlatform(struct xf86_platform_device *plat)
130{
131 return ((primaryBus.type == BUS_PLATFORM) && (plat == primaryBus.id.plat));
132}
133
134static void
135platform_find_pci_info(struct xf86_platform_device *pd, char *busid)
136{
137 struct pci_slot_match devmatch;
138 struct pci_device *info;
139 struct pci_device_iterator *iter;
140 int ret;
141
142 ret = sscanf(busid, "pci:%04x:%02x:%02x.%u",
143 &devmatch.domain, &devmatch.bus, &devmatch.dev,
144 &devmatch.func);
145 if (ret != 4)
146 return;
147
148 iter = pci_slot_match_iterator_create(&devmatch);
149 info = pci_device_next(iter);
150 if (info) {
151 pd->pdev = info;
152 pci_device_probe(info);
153 if (pci_device_is_boot_vga(info)) {
154 primaryBus.type = BUS_PLATFORM;
155 primaryBus.id.plat = pd;
156 }
157 }
158 pci_iterator_destroy(iter);
159
160}
161
162static Bool
163xf86_check_platform_slot(const struct xf86_platform_device *pd)
164{
165 int i;
166
167 for (i = 0; i < xf86NumEntities; i++) {
168 const EntityPtr u = xf86Entities[i];
169
170 if (pd->pdev && u->bus.type == BUS_PCI)
171 return !MATCH_PCI_DEVICES(pd->pdev, u->bus.id.pci);
172 if ((u->bus.type == BUS_PLATFORM) && (pd == u->bus.id.plat)) {
173 return FALSE;
174 }
175 }
176 return TRUE;
177}
178
179/**
180 * @return The numbers of found devices that match with the current system
181 * drivers.
182 */
183int
184xf86PlatformMatchDriver(char *matches[], int nmatches)
185{
186 int i, j = 0;
187 struct pci_device *info = NULL;
188 int pass = 0;
189
190 for (pass = 0; pass < 2; pass++) {
191 for (i = 0; i < xf86_num_platform_devices; i++) {
192
193 if (xf86IsPrimaryPlatform(&xf86_platform_devices[i]) && (pass == 1))
194 continue;
195 else if (!xf86IsPrimaryPlatform(&xf86_platform_devices[i]) && (pass == 0))
196 continue;
197
198 info = xf86_platform_devices[i].pdev;
199#ifdef __linux__
200 if (info)
201 xf86MatchDriverFromFiles(matches, info->vendor_id, info->device_id);
202#endif
203
204 for (j = 0; (j < nmatches) && (matches[j]); j++) {
205 /* find end of matches list */
206 }
207
208 if ((info != NULL) && (j < nmatches)) {
209 j += xf86VideoPtrToDriverList(info, &(matches[j]), nmatches - j);
210 }
211 }
212 }
213 return j;
214}
215
216int
217xf86platformProbe(void)
218{
219 int i;
220 Bool pci = TRUE;
221
222 config_odev_probe(xf86PlatformDeviceProbe);
223
224 if (!xf86scanpci()) {
225 pci = FALSE;
226 }
227
228 for (i = 0; i < xf86_num_platform_devices; i++) {
229 char *busid = xf86_get_platform_attrib(i, ODEV_ATTRIB_BUSID);
230
231 if (pci && (strncmp(busid, "pci:", 4) == 0)) {
232 platform_find_pci_info(&xf86_platform_devices[i], busid);
233 }
234 }
235 return 0;
236}
237
238static int
239xf86ClaimPlatformSlot(struct xf86_platform_device * d, DriverPtr drvp,
240 int chipset, GDevPtr dev, Bool active)
241{
242 EntityPtr p = NULL;
243 int num;
244
245 if (xf86_check_platform_slot(d)) {
246 num = xf86AllocateEntity();
247 p = xf86Entities[num];
248 p->driver = drvp;
249 p->chipset = chipset;
250 p->bus.type = BUS_PLATFORM;
251 p->bus.id.plat = d;
252 p->active = active;
253 p->inUse = FALSE;
254 if (dev)
255 xf86AddDevToEntity(num, dev);
256
257 platformSlotClaimed++;
258 return num;
259 }
260 else
261 return -1;
262}
263
264static int
265xf86UnclaimPlatformSlot(struct xf86_platform_device *d, GDevPtr dev)
266{
267 int i;
268
269 for (i = 0; i < xf86NumEntities; i++) {
270 const EntityPtr p = xf86Entities[i];
271
272 if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat == d)) {
273 if (dev)
274 xf86RemoveDevFromEntity(i, dev);
275 platformSlotClaimed--;
276 p->bus.type = BUS_NONE;
277 return 0;
278 }
279 }
280 return 0;
281}
282
283
284#define END_OF_MATCHES(m) \
285 (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0))
286
287static Bool doPlatformProbe(struct xf86_platform_device *dev, DriverPtr drvp,
288 GDevPtr gdev, int flags, intptr_t match_data)
289{
290 Bool foundScreen = FALSE;
291 int entity;
292
293 if (gdev->screen == 0 && !xf86_check_platform_slot(dev))
294 return FALSE;
295
296 entity = xf86ClaimPlatformSlot(dev, drvp, 0,
297 gdev, gdev->active);
298
299 if ((entity == -1) && (gdev->screen > 0)) {
300 unsigned nent;
301
302 for (nent = 0; nent < xf86NumEntities; nent++) {
303 EntityPtr pEnt = xf86Entities[nent];
304
305 if (pEnt->bus.type != BUS_PLATFORM)
306 continue;
307 if (pEnt->bus.id.plat == dev) {
308 entity = nent;
309 xf86AddDevToEntity(nent, gdev);
310 break;
311 }
312 }
313 }
314 if (entity != -1) {
315 if (drvp->platformProbe(drvp, entity, flags, dev, match_data))
316 foundScreen = TRUE;
317 else
318 xf86UnclaimPlatformSlot(dev, gdev);
319 }
320 return foundScreen;
321}
322
323static Bool
324probeSingleDevice(struct xf86_platform_device *dev, DriverPtr drvp, GDevPtr gdev, int flags)
325{
326 int k;
327 Bool foundScreen = FALSE;
328 struct pci_device *pPci;
329 const struct pci_id_match *const devices = drvp->supported_devices;
330
331 if (dev->pdev && devices) {
332 int device_id = dev->pdev->device_id;
333 pPci = dev->pdev;
334 for (k = 0; !END_OF_MATCHES(devices[k]); k++) {
335 if (PCI_ID_COMPARE(devices[k].vendor_id, pPci->vendor_id)
336 && PCI_ID_COMPARE(devices[k].device_id, device_id)
337 && ((devices[k].device_class_mask & pPci->device_class)
338 == devices[k].device_class)) {
339 foundScreen = doPlatformProbe(dev, drvp, gdev, flags, devices[k].match_data);
340 if (foundScreen)
341 break;
342 }
343 }
344 }
345 else if (dev->pdev && !devices)
346 return FALSE;
347 else
348 foundScreen = doPlatformProbe(dev, drvp, gdev, flags, 0);
349 return foundScreen;
350}
351
352int
353xf86platformProbeDev(DriverPtr drvp)
354{
355 Bool foundScreen = FALSE;
356 GDevPtr *devList;
357 const unsigned numDevs = xf86MatchDevice(drvp->driverName, &devList);
358 int i, j;
359
360 /* find the main device or any device specificed in xorg.conf */
361 for (i = 0; i < numDevs; i++) {
362 for (j = 0; j < xf86_num_platform_devices; j++) {
363 if (devList[i]->busID && *devList[i]->busID) {
364 if (xf86PlatformDeviceCheckBusID(&xf86_platform_devices[j], devList[i]->busID))
365 break;
366 }
367 else {
368 /* for non-seat0 servers assume first device is the master */
369 if (ServerIsNotSeat0())
370 break;
371 if (xf86_platform_devices[j].pdev) {
372 if (xf86IsPrimaryPlatform(&xf86_platform_devices[j]))
373 break;
374 }
375 }
376 }
377
378 if (j == xf86_num_platform_devices)
379 continue;
380
381 foundScreen = probeSingleDevice(&xf86_platform_devices[j], drvp, devList[i], 0);
382 if (!foundScreen)
383 continue;
384 }
385
386 /* if autoaddgpu devices is enabled then go find a few more and add them as GPU screens */
387 if (xf86Info.autoAddGPU && numDevs) {
388 for (j = 0; j < xf86_num_platform_devices; j++) {
389 probeSingleDevice(&xf86_platform_devices[j], drvp, devList[0], PLATFORM_PROBE_GPU_SCREEN);
390 }
391 }
392
393 return foundScreen;
394}
395
396int
397xf86platformAddDevice(int index)
398{
399 int i, old_screens, scr_index;
400 DriverPtr drvp = NULL;
401 int entity;
402 screenLayoutPtr layout;
403 static char *hotplug_driver_name = "modesetting";
404
405 /* force load the driver for now */
406 xf86LoadOneModule(hotplug_driver_name, NULL);
407
408 for (i = 0; i < xf86NumDrivers; i++) {
409 if (!xf86DriverList[i])
410 continue;
411
412 if (!strcmp(xf86DriverList[i]->driverName, hotplug_driver_name)) {
413 drvp = xf86DriverList[i];
414 break;
415 }
416 }
417 if (i == xf86NumDrivers)
418 return -1;
419
420 old_screens = xf86NumGPUScreens;
421 entity = xf86ClaimPlatformSlot(&xf86_platform_devices[index],
422 drvp, 0, 0, 0);
423 if (!drvp->platformProbe(drvp, entity, PLATFORM_PROBE_GPU_SCREEN, &xf86_platform_devices[index], 0)) {
424 xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
425 }
426 if (old_screens == xf86NumGPUScreens)
427 return -1;
428 i = old_screens;
429
430 for (layout = xf86ConfigLayout.screens; layout->screen != NULL;
431 layout++) {
432 xf86GPUScreens[i]->confScreen = layout->screen;
433 break;
434 }
435
436 if (xf86GPUScreens[i]->PreInit &&
437 xf86GPUScreens[i]->PreInit(xf86GPUScreens[i], 0))
438 xf86GPUScreens[i]->configured = TRUE;
439
440 if (!xf86GPUScreens[i]->configured) {
441 ErrorF("hotplugged device %d didn't configure\n", i);
442 xf86DeleteScreen(xf86GPUScreens[i]);
443 return -1;
444 }
445
446 scr_index = AddGPUScreen(xf86GPUScreens[i]->ScreenInit, 0, NULL);
447 if (scr_index == -1) {
448 xf86DeleteScreen(xf86GPUScreens[i]);
449 xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
450 xf86NumGPUScreens = old_screens;
451 return -1;
452 }
453 dixSetPrivate(&xf86GPUScreens[i]->pScreen->devPrivates,
454 xf86ScreenKey, xf86GPUScreens[i]);
455
456 CreateScratchPixmapsForScreen(xf86GPUScreens[i]->pScreen);
457
458 if (xf86GPUScreens[i]->pScreen->CreateScreenResources &&
459 !(*xf86GPUScreens[i]->pScreen->CreateScreenResources) (xf86GPUScreens[i]->pScreen)) {
460 RemoveGPUScreen(xf86GPUScreens[i]->pScreen);
461 xf86DeleteScreen(xf86GPUScreens[i]);
462 xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
463 xf86NumGPUScreens = old_screens;
464 return -1;
465 }
466 /* attach unbound to 0 protocol screen */
467 AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen);
468
469 RRResourcesChanged(xf86Screens[0]->pScreen);
470 RRTellChanged(xf86Screens[0]->pScreen);
471
472 return 0;
473}
474
475void
476xf86platformRemoveDevice(int index)
477{
478 EntityPtr entity;
479 int ent_num, i, j;
480 Bool found;
481
482 for (ent_num = 0; ent_num < xf86NumEntities; ent_num++) {
483 entity = xf86Entities[ent_num];
484 if (entity->bus.type == BUS_PLATFORM &&
485 entity->bus.id.plat == &xf86_platform_devices[index])
486 break;
487 }
488 if (ent_num == xf86NumEntities)
489 goto out;
490
491 found = FALSE;
492 for (i = 0; i < xf86NumGPUScreens; i++) {
493 for (j = 0; j < xf86GPUScreens[i]->numEntities; j++)
494 if (xf86GPUScreens[i]->entityList[j] == ent_num) {
495 found = TRUE;
496 break;
497 }
498 if (found)
499 break;
500 }
501 if (!found) {
502 ErrorF("failed to find screen to remove\n");
503 goto out;
504 }
505
506 xf86GPUScreens[i]->pScreen->CloseScreen(xf86GPUScreens[i]->pScreen);
507
508 RemoveGPUScreen(xf86GPUScreens[i]->pScreen);
509 xf86DeleteScreen(xf86GPUScreens[i]);
510
511 xf86UnclaimPlatformSlot(&xf86_platform_devices[index], NULL);
512
513 xf86_remove_platform_device(index);
514
515 RRResourcesChanged(xf86Screens[0]->pScreen);
516 RRTellChanged(xf86Screens[0]->pScreen);
517 out:
518 return;
519}
520
521/* called on return from VT switch to find any new devices */
522void xf86platformVTProbe(void)
523{
524 int i;
525
526 for (i = 0; i < xf86_num_platform_devices; i++) {
527 if (xf86_platform_devices[i].attribs->unowned == FALSE)
528 continue;
529
530 xf86_platform_devices[i].attribs->unowned = FALSE;
531 xf86PlatformReprobeDevice(i, xf86_platform_devices[i].attribs);
532 }
533}
534#endif