| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: drm_drv.c,v 1.1.2.14 2013/07/24 03:55:00 riastradh Exp $ */ | | 1 | /* $NetBSD: drm_drv.c,v 1.1.2.15 2013/07/24 03:55:17 riastradh Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Taylor R. Campbell. | | 8 | * by Taylor R. Campbell. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -20,27 +20,27 @@ | | | @@ -20,27 +20,27 @@ |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.1.2.14 2013/07/24 03:55:00 riastradh Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.1.2.15 2013/07/24 03:55:17 riastradh Exp $"); |
34 | | | 34 | |
35 | #include <sys/param.h> | | 35 | #include <sys/param.h> |
36 | #include <sys/types.h> | | 36 | #include <sys/types.h> |
37 | #include <sys/conf.h> | | 37 | #include <sys/conf.h> |
38 | #include <sys/device.h> | | 38 | #include <sys/device.h> |
39 | #include <sys/file.h> | | 39 | #include <sys/file.h> |
40 | #include <sys/filedesc.h> | | 40 | #include <sys/filedesc.h> |
41 | #include <sys/ioccom.h> | | 41 | #include <sys/ioccom.h> |
42 | #include <sys/kauth.h> | | 42 | #include <sys/kauth.h> |
43 | #if 0 /* XXX drm event poll */ | | 43 | #if 0 /* XXX drm event poll */ |
44 | #include <sys/poll.h> | | 44 | #include <sys/poll.h> |
45 | #include <sys/select.h> | | 45 | #include <sys/select.h> |
46 | #endif | | 46 | #endif |
| @@ -48,26 +48,27 @@ __KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v | | | @@ -48,26 +48,27 @@ __KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v |
48 | #include <drm/drmP.h> | | 48 | #include <drm/drmP.h> |
49 | | | 49 | |
50 | static int drm_minor_types[] = { | | 50 | static int drm_minor_types[] = { |
51 | DRM_MINOR_LEGACY, | | 51 | DRM_MINOR_LEGACY, |
52 | DRM_MINOR_CONTROL, | | 52 | DRM_MINOR_CONTROL, |
53 | #if 0 /* XXX Nothing seems to use this? */ | | 53 | #if 0 /* XXX Nothing seems to use this? */ |
54 | DRM_MINOR_RENDER, | | 54 | DRM_MINOR_RENDER, |
55 | #endif | | 55 | #endif |
56 | }; | | 56 | }; |
57 | | | 57 | |
58 | struct drm_softc { | | 58 | struct drm_softc { |
59 | struct drm_device *sc_drm_dev; | | 59 | struct drm_device *sc_drm_dev; |
60 | struct drm_minor sc_minor[__arraycount(drm_minor_types)]; | | 60 | struct drm_minor sc_minor[__arraycount(drm_minor_types)]; |
| | | 61 | unsigned int sc_opencount; |
61 | }; | | 62 | }; |
62 | | | 63 | |
63 | static int drm_match(device_t, cfdata_t, void *); | | 64 | static int drm_match(device_t, cfdata_t, void *); |
64 | static void drm_attach(device_t, device_t, void *); | | 65 | static void drm_attach(device_t, device_t, void *); |
65 | static int drm_detach(device_t, int); | | 66 | static int drm_detach(device_t, int); |
66 | | | 67 | |
67 | static struct drm_softc *drm_dev_softc(dev_t); | | 68 | static struct drm_softc *drm_dev_softc(dev_t); |
68 | static struct drm_minor *drm_dev_minor(dev_t); | | 69 | static struct drm_minor *drm_dev_minor(dev_t); |
69 | | | 70 | |
70 | static dev_type_open(drm_open); | | 71 | static dev_type_open(drm_open); |
71 | | | 72 | |
72 | static int drm_close(struct file *); | | 73 | static int drm_close(struct file *); |
73 | static int drm_read(struct file *, off_t *, struct uio *, kauth_cred_t, | | 74 | static int drm_read(struct file *, off_t *, struct uio *, kauth_cred_t, |
| @@ -249,26 +250,27 @@ drm_attach(device_t parent, device_t sel | | | @@ -249,26 +250,27 @@ drm_attach(device_t parent, device_t sel |
249 | struct drm_softc *sc = device_private(self); | | 250 | struct drm_softc *sc = device_private(self); |
250 | struct drm_device *dev = aux; | | 251 | struct drm_device *dev = aux; |
251 | unsigned int i; | | 252 | unsigned int i; |
252 | int error; | | 253 | int error; |
253 | | | 254 | |
254 | KASSERT(sc != NULL); | | 255 | KASSERT(sc != NULL); |
255 | KASSERT(dev != NULL); | | 256 | KASSERT(dev != NULL); |
256 | KASSERT(dev->driver != NULL); | | 257 | KASSERT(dev->driver != NULL); |
257 | KASSERT(device_unit(self) >= 0); | | 258 | KASSERT(device_unit(self) >= 0); |
258 | | | 259 | |
259 | aprint_normal("\n"); | | 260 | aprint_normal("\n"); |
260 | | | 261 | |
261 | sc->sc_drm_dev = dev; | | 262 | sc->sc_drm_dev = dev; |
| | | 263 | sc->sc_opencount = 0; |
262 | | | 264 | |
263 | if (device_unit(self) >= 64) { /* XXX Need to do something here! */ | | 265 | if (device_unit(self) >= 64) { /* XXX Need to do something here! */ |
264 | aprint_error_dev(self, "can't handle >=64 drm devices!"); | | 266 | aprint_error_dev(self, "can't handle >=64 drm devices!"); |
265 | return; | | 267 | return; |
266 | } | | 268 | } |
267 | | | 269 | |
268 | for (i = 0; i < __arraycount(drm_minor_types); i++) { | | 270 | for (i = 0; i < __arraycount(drm_minor_types); i++) { |
269 | sc->sc_minor[i].index = (i * 64) + device_unit(self); | | 271 | sc->sc_minor[i].index = (i * 64) + device_unit(self); |
270 | sc->sc_minor[i].type = drm_minor_types[i]; | | 272 | sc->sc_minor[i].type = drm_minor_types[i]; |
271 | sc->sc_minor[i].device = | | 273 | sc->sc_minor[i].device = |
272 | makedev(cdevsw_lookup_major(&drm_cdevsw), | | 274 | makedev(cdevsw_lookup_major(&drm_cdevsw), |
273 | sc->sc_minor[i].index); | | 275 | sc->sc_minor[i].index); |
274 | sc->sc_minor[i].kdev = self; | | 276 | sc->sc_minor[i].kdev = self; |
| @@ -295,26 +297,29 @@ drm_attach(device_t parent, device_t sel | | | @@ -295,26 +297,29 @@ drm_attach(device_t parent, device_t sel |
295 | #endif | | 297 | #endif |
296 | } | | 298 | } |
297 | | | 299 | |
298 | static int | | 300 | static int |
299 | drm_detach(device_t self, int flags) | | 301 | drm_detach(device_t self, int flags) |
300 | { | | 302 | { |
301 | struct drm_softc *const sc = device_private(self); | | 303 | struct drm_softc *const sc = device_private(self); |
302 | KASSERT(sc != NULL); | | 304 | KASSERT(sc != NULL); |
303 | struct drm_device *const dev = sc->sc_drm_dev; | | 305 | struct drm_device *const dev = sc->sc_drm_dev; |
304 | KASSERT(dev != NULL); | | 306 | KASSERT(dev != NULL); |
305 | const struct drm_driver *const driver = dev->driver; | | 307 | const struct drm_driver *const driver = dev->driver; |
306 | KASSERT(driver != NULL); | | 308 | KASSERT(driver != NULL); |
307 | | | 309 | |
| | | 310 | if (sc->sc_opencount != 0) |
| | | 311 | return EBUSY; |
| | | 312 | |
308 | /* | | 313 | /* |
309 | * XXX Synchronize with drm_fill_in_dev, perhaps with reference | | 314 | * XXX Synchronize with drm_fill_in_dev, perhaps with reference |
310 | * to drm_put_dev. | | 315 | * to drm_put_dev. |
311 | */ | | 316 | */ |
312 | | | 317 | |
313 | if (ISSET(driver->driver_features, DRIVER_GEM)) | | 318 | if (ISSET(driver->driver_features, DRIVER_GEM)) |
314 | drm_gem_destroy(dev); | | 319 | drm_gem_destroy(dev); |
315 | | | 320 | |
316 | drm_ctxbitmap_cleanup(dev); | | 321 | drm_ctxbitmap_cleanup(dev); |
317 | | | 322 | |
318 | /* XXX Move to dev->driver->bus->agp_destroy. */ | | 323 | /* XXX Move to dev->driver->bus->agp_destroy. */ |
319 | if (drm_core_has_MTRR(dev) && | | 324 | if (drm_core_has_MTRR(dev) && |
320 | drm_core_has_AGP(dev) && | | 325 | drm_core_has_AGP(dev) && |
| @@ -349,69 +354,83 @@ drm_dev_minor(dev_t d) | | | @@ -349,69 +354,83 @@ drm_dev_minor(dev_t d) |
349 | if (sc == NULL) | | 354 | if (sc == NULL) |
350 | return NULL; | | 355 | return NULL; |
351 | | | 356 | |
352 | const unsigned int i = minor(d) / 64; | | 357 | const unsigned int i = minor(d) / 64; |
353 | if (i >= __arraycount(drm_minor_types)) | | 358 | if (i >= __arraycount(drm_minor_types)) |
354 | return NULL; | | 359 | return NULL; |
355 | | | 360 | |
356 | return &sc->sc_minor[i]; | | 361 | return &sc->sc_minor[i]; |
357 | } | | 362 | } |
358 | | | 363 | |
359 | static int | | 364 | static int |
360 | drm_open(dev_t d, int flags, int fmt, struct lwp *l) | | 365 | drm_open(dev_t d, int flags, int fmt, struct lwp *l) |
361 | { | | 366 | { |
| | | 367 | struct drm_softc *const sc = drm_dev_softc(d); |
362 | struct drm_minor *const dminor = drm_dev_minor(d); | | 368 | struct drm_minor *const dminor = drm_dev_minor(d); |
363 | int fd; | | 369 | int fd; |
364 | struct file *fp; | | 370 | struct file *fp; |
| | | 371 | unsigned int opencount; |
365 | int error; | | 372 | int error; |
366 | | | 373 | |
367 | if (dminor == NULL) { | | 374 | if (dminor == NULL) { |
368 | error = ENXIO; | | 375 | error = ENXIO; |
369 | goto fail0; | | 376 | goto fail0; |
370 | } | | 377 | } |
371 | | | 378 | |
372 | if (flags & O_EXCL) { | | 379 | if (flags & O_EXCL) { |
373 | error = EBUSY; | | 380 | error = EBUSY; |
374 | goto fail0; | | 381 | goto fail0; |
375 | } | | 382 | } |
376 | | | 383 | |
377 | if (dminor->dev->switch_power_state != DRM_SWITCH_POWER_ON) { | | 384 | if (dminor->dev->switch_power_state != DRM_SWITCH_POWER_ON) { |
378 | error = EINVAL; | | 385 | error = EINVAL; |
379 | goto fail0; | | 386 | goto fail0; |
380 | } | | 387 | } |
381 | | | 388 | |
| | | 389 | do { |
| | | 390 | opencount = sc->sc_opencount; |
| | | 391 | if (opencount == UINT_MAX) { |
| | | 392 | error = EBUSY; |
| | | 393 | goto fail0; |
| | | 394 | } |
| | | 395 | } while (atomic_cas_uint(&sc->sc_opencount, opencount, (opencount + 1)) |
| | | 396 | != opencount); |
| | | 397 | |
382 | error = fd_allocfile(&fp, &fd); | | 398 | error = fd_allocfile(&fp, &fd); |
383 | if (error) | | 399 | if (error) |
384 | goto fail0; | | 400 | goto fail1; |
385 | | | 401 | |
386 | struct drm_file *const file = kmem_zalloc(sizeof(*file), KM_SLEEP); | | 402 | struct drm_file *const file = kmem_zalloc(sizeof(*file), KM_SLEEP); |
387 | | | 403 | |
388 | /* XXX errno Linux->NetBSD */ | | 404 | /* XXX errno Linux->NetBSD */ |
389 | error = -drm_open_file(file, fp, dminor); | | 405 | error = -drm_open_file(file, fp, dminor); |
390 | if (error) | | 406 | if (error) |
391 | goto fail2; | | 407 | goto fail3; |
392 | | | 408 | |
393 | error = fd_clone(fp, fd, flags, &drm_fileops, file); | | 409 | error = fd_clone(fp, fd, flags, &drm_fileops, file); |
394 | KASSERT(error == EMOVEFD); /* XXX */ | | 410 | KASSERT(error == EMOVEFD); /* XXX */ |
395 | | | 411 | |
396 | /* Success! (But error has to be EMOVEFD, not 0.) */ | | 412 | /* Success! (But error has to be EMOVEFD, not 0.) */ |
397 | return error; | | 413 | return error; |
398 | | | 414 | |
399 | fail2: | | 415 | fail3: |
400 | kmem_free(file, sizeof(*file)); | | 416 | kmem_free(file, sizeof(*file)); |
401 | | | 417 | |
402 | fail1: __unused | | 418 | fail2: __unused |
403 | fd_abort(curproc, fp, fd); | | 419 | fd_abort(curproc, fp, fd); |
404 | | | 420 | |
| | | 421 | fail1: |
| | | 422 | atomic_dec_uint(&sc->sc_opencount); |
| | | 423 | |
405 | fail0: | | 424 | fail0: |
406 | return error; | | 425 | return error; |
407 | } | | 426 | } |
408 | | | 427 | |
409 | static int | | 428 | static int |
410 | drm_close(struct file *fp) | | 429 | drm_close(struct file *fp) |
411 | { | | 430 | { |
412 | struct drm_file *const file = fp->f_data; | | 431 | struct drm_file *const file = fp->f_data; |
413 | | | 432 | |
414 | /* XXX errno Linux->NetBSD */ | | 433 | /* XXX errno Linux->NetBSD */ |
415 | return -drm_close_file(file); | | 434 | return -drm_close_file(file); |
416 | } | | 435 | } |
417 | | | 436 | |