diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-07-31 02:16:21 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-10-02 23:12:59 -0400 |
commit | 77145f1cbdf8d28b46ff8070ca749bad821e0774 (patch) | |
tree | b496d5d69ce4f5753028b07b09d8cf12025310f2 /drivers/gpu/drm/nouveau/nouveau_drm.c | |
parent | 2094dd82eddc468b53ee99d92c38b23a65efac03 (diff) |
drm/nouveau: port remainder of drm code, and rip out compat layer
v2: Ben Skeggs <bskeggs@redhat.com>
- fill in nouveau_pm.dev to prevent oops
- fix ppc issues (build + OF shadow)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 227 |
1 files changed, 190 insertions, 37 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 92ecf50a39d3..8b508cec65a2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/console.h> | ||
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
26 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
27 | 28 | ||
@@ -34,24 +35,22 @@ | |||
34 | #include <subdev/vm.h> | 35 | #include <subdev/vm.h> |
35 | 36 | ||
36 | #include "nouveau_drm.h" | 37 | #include "nouveau_drm.h" |
38 | #include "nouveau_irq.h" | ||
37 | #include "nouveau_dma.h" | 39 | #include "nouveau_dma.h" |
40 | #include "nouveau_ttm.h" | ||
41 | #include "nouveau_gem.h" | ||
38 | #include "nouveau_agp.h" | 42 | #include "nouveau_agp.h" |
43 | #include "nouveau_vga.h" | ||
44 | #include "nouveau_pm.h" | ||
45 | #include "nouveau_acpi.h" | ||
46 | #include "nouveau_bios.h" | ||
47 | #include "nouveau_ioctl.h" | ||
39 | #include "nouveau_abi16.h" | 48 | #include "nouveau_abi16.h" |
40 | #include "nouveau_fbcon.h" | 49 | #include "nouveau_fbcon.h" |
41 | #include "nouveau_fence.h" | 50 | #include "nouveau_fence.h" |
42 | 51 | ||
43 | #include "nouveau_ttm.h" | 52 | #include "nouveau_ttm.h" |
44 | 53 | ||
45 | int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *); | ||
46 | void nouveau_pci_remove(struct pci_dev *); | ||
47 | int nouveau_pci_suspend(struct pci_dev *, pm_message_t); | ||
48 | int nouveau_pci_resume(struct pci_dev *); | ||
49 | int __init nouveau_init(struct pci_driver *); | ||
50 | void __exit nouveau_exit(struct pci_driver *); | ||
51 | |||
52 | int nouveau_load(struct drm_device *, unsigned long); | ||
53 | int nouveau_unload(struct drm_device *); | ||
54 | |||
55 | MODULE_PARM_DESC(config, "option string to pass to driver core"); | 54 | MODULE_PARM_DESC(config, "option string to pass to driver core"); |
56 | static char *nouveau_config; | 55 | static char *nouveau_config; |
57 | module_param_named(config, nouveau_config, charp, 0400); | 56 | module_param_named(config, nouveau_config, charp, 0400); |
@@ -64,6 +63,12 @@ MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration"); | |||
64 | static int nouveau_noaccel = 0; | 63 | static int nouveau_noaccel = 0; |
65 | module_param_named(noaccel, nouveau_noaccel, int, 0400); | 64 | module_param_named(noaccel, nouveau_noaccel, int, 0400); |
66 | 65 | ||
66 | MODULE_PARM_DESC(modeset, "enable driver"); | ||
67 | int nouveau_modeset = -1; | ||
68 | module_param_named(modeset, nouveau_modeset, int, 0400); | ||
69 | |||
70 | static struct drm_driver driver; | ||
71 | |||
67 | static u64 | 72 | static u64 |
68 | nouveau_name(struct pci_dev *pdev) | 73 | nouveau_name(struct pci_dev *pdev) |
69 | { | 74 | { |
@@ -206,7 +211,7 @@ nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) | |||
206 | 211 | ||
207 | pci_set_master(pdev); | 212 | pci_set_master(pdev); |
208 | 213 | ||
209 | ret = nouveau_pci_probe(pdev, pent); | 214 | ret = drm_get_pci_dev(pdev, pent, &driver); |
210 | if (ret) { | 215 | if (ret) { |
211 | nouveau_object_ref(NULL, (struct nouveau_object **)&device); | 216 | nouveau_object_ref(NULL, (struct nouveau_object **)&device); |
212 | return ret; | 217 | return ret; |
@@ -224,13 +229,14 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
224 | int ret; | 229 | int ret; |
225 | 230 | ||
226 | ret = nouveau_cli_create(pdev, 0, sizeof(*drm), (void**)&drm); | 231 | ret = nouveau_cli_create(pdev, 0, sizeof(*drm), (void**)&drm); |
227 | dev->dev_private = drm; | ||
228 | if (ret) | 232 | if (ret) |
229 | return ret; | 233 | return ret; |
230 | 234 | ||
235 | dev->dev_private = drm; | ||
236 | drm->dev = dev; | ||
237 | |||
231 | INIT_LIST_HEAD(&drm->clients); | 238 | INIT_LIST_HEAD(&drm->clients); |
232 | spin_lock_init(&drm->tile.lock); | 239 | spin_lock_init(&drm->tile.lock); |
233 | drm->dev = dev; | ||
234 | 240 | ||
235 | /* make sure AGP controller is in a consistent state before we | 241 | /* make sure AGP controller is in a consistent state before we |
236 | * (possibly) execute vbios init tables (see nouveau_agp.h) | 242 | * (possibly) execute vbios init tables (see nouveau_agp.h) |
@@ -266,9 +272,15 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
266 | if (ret) | 272 | if (ret) |
267 | goto fail_device; | 273 | goto fail_device; |
268 | 274 | ||
275 | /* workaround an odd issue on nvc1 by disabling the device's | ||
276 | * nosnoop capability. hopefully won't cause issues until a | ||
277 | * better fix is found - assuming there is one... | ||
278 | */ | ||
269 | device = nv_device(drm->device); | 279 | device = nv_device(drm->device); |
280 | if (nv_device(drm->device)->chipset == 0xc1) | ||
281 | nv_mask(device, 0x00088080, 0x00000800, 0x00000000); | ||
270 | 282 | ||
271 | /* initialise AGP */ | 283 | nouveau_vga_init(drm); |
272 | nouveau_agp_init(drm); | 284 | nouveau_agp_init(drm); |
273 | 285 | ||
274 | if (device->card_type >= NV_50) { | 286 | if (device->card_type >= NV_50) { |
@@ -280,18 +292,43 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
280 | 292 | ||
281 | ret = nouveau_ttm_init(drm); | 293 | ret = nouveau_ttm_init(drm); |
282 | if (ret) | 294 | if (ret) |
283 | goto fail_device; | 295 | goto fail_ttm; |
296 | |||
297 | ret = nouveau_bios_init(dev); | ||
298 | if (ret) | ||
299 | goto fail_bios; | ||
300 | |||
301 | ret = nouveau_irq_init(dev); | ||
302 | if (ret) | ||
303 | goto fail_irq; | ||
284 | 304 | ||
285 | ret = nouveau_load(dev, flags); | 305 | ret = nouveau_display_create(dev); |
286 | if (ret) | 306 | if (ret) |
287 | goto fail_load; | 307 | goto fail_dispctor; |
308 | |||
309 | if (dev->mode_config.num_crtc) { | ||
310 | ret = nouveau_display_init(dev); | ||
311 | if (ret) | ||
312 | goto fail_dispinit; | ||
313 | } | ||
314 | |||
315 | nouveau_pm_init(dev); | ||
288 | 316 | ||
289 | nouveau_accel_init(drm); | 317 | nouveau_accel_init(drm); |
290 | nouveau_fbcon_init(dev); | 318 | nouveau_fbcon_init(dev); |
291 | return 0; | 319 | return 0; |
292 | 320 | ||
293 | fail_load: | 321 | fail_dispinit: |
322 | nouveau_display_destroy(dev); | ||
323 | fail_dispctor: | ||
324 | nouveau_irq_fini(dev); | ||
325 | fail_irq: | ||
326 | nouveau_bios_takedown(dev); | ||
327 | fail_bios: | ||
294 | nouveau_ttm_fini(drm); | 328 | nouveau_ttm_fini(drm); |
329 | fail_ttm: | ||
330 | nouveau_agp_fini(drm); | ||
331 | nouveau_vga_fini(drm); | ||
295 | fail_device: | 332 | fail_device: |
296 | nouveau_cli_destroy(&drm->client); | 333 | nouveau_cli_destroy(&drm->client); |
297 | return ret; | 334 | return ret; |
@@ -300,21 +337,23 @@ fail_device: | |||
300 | int | 337 | int |
301 | nouveau_drm_unload(struct drm_device *dev) | 338 | nouveau_drm_unload(struct drm_device *dev) |
302 | { | 339 | { |
303 | struct nouveau_drm *drm = nouveau_newpriv(dev); | 340 | struct nouveau_drm *drm = nouveau_drm(dev); |
304 | struct pci_dev *pdev = dev->pdev; | ||
305 | int ret; | ||
306 | 341 | ||
307 | nouveau_fbcon_fini(dev); | 342 | nouveau_fbcon_fini(dev); |
308 | nouveau_accel_fini(drm); | 343 | nouveau_accel_fini(drm); |
309 | 344 | ||
310 | ret = nouveau_unload(dev); | 345 | nouveau_pm_fini(dev); |
311 | if (ret) | 346 | |
312 | return ret; | 347 | nouveau_display_fini(dev); |
348 | nouveau_display_destroy(dev); | ||
349 | |||
350 | nouveau_irq_fini(dev); | ||
351 | nouveau_bios_takedown(dev); | ||
313 | 352 | ||
314 | nouveau_ttm_fini(drm); | 353 | nouveau_ttm_fini(drm); |
315 | nouveau_agp_fini(drm); | 354 | nouveau_agp_fini(drm); |
355 | nouveau_vga_fini(drm); | ||
316 | 356 | ||
317 | pci_set_drvdata(pdev, drm->client.base.device); | ||
318 | nouveau_cli_destroy(&drm->client); | 357 | nouveau_cli_destroy(&drm->client); |
319 | return 0; | 358 | return 0; |
320 | } | 359 | } |
@@ -322,9 +361,13 @@ nouveau_drm_unload(struct drm_device *dev) | |||
322 | static void | 361 | static void |
323 | nouveau_drm_remove(struct pci_dev *pdev) | 362 | nouveau_drm_remove(struct pci_dev *pdev) |
324 | { | 363 | { |
364 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
365 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
325 | struct nouveau_object *device; | 366 | struct nouveau_object *device; |
326 | nouveau_pci_remove(pdev); | 367 | |
327 | device = pci_get_drvdata(pdev); | 368 | device = drm->client.base.device; |
369 | drm_put_dev(dev); | ||
370 | |||
328 | nouveau_object_ref(NULL, &device); | 371 | nouveau_object_ref(NULL, &device); |
329 | nouveau_object_debug(); | 372 | nouveau_object_debug(); |
330 | } | 373 | } |
@@ -333,7 +376,7 @@ int | |||
333 | nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) | 376 | nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) |
334 | { | 377 | { |
335 | struct drm_device *dev = pci_get_drvdata(pdev); | 378 | struct drm_device *dev = pci_get_drvdata(pdev); |
336 | struct nouveau_drm *drm = nouveau_newpriv(dev); | 379 | struct nouveau_drm *drm = nouveau_drm(dev); |
337 | struct nouveau_cli *cli; | 380 | struct nouveau_cli *cli; |
338 | int ret; | 381 | int ret; |
339 | 382 | ||
@@ -344,8 +387,8 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) | |||
344 | NV_INFO(drm, "suspending fbcon...\n"); | 387 | NV_INFO(drm, "suspending fbcon...\n"); |
345 | nouveau_fbcon_set_suspend(dev, 1); | 388 | nouveau_fbcon_set_suspend(dev, 1); |
346 | 389 | ||
347 | NV_INFO(drm, "suspending drm...\n"); | 390 | NV_INFO(drm, "suspending display...\n"); |
348 | ret = nouveau_pci_suspend(pdev, pm_state); | 391 | ret = nouveau_display_suspend(dev); |
349 | if (ret) | 392 | if (ret) |
350 | return ret; | 393 | return ret; |
351 | 394 | ||
@@ -383,7 +426,8 @@ fail_client: | |||
383 | nouveau_client_init(&cli->base); | 426 | nouveau_client_init(&cli->base); |
384 | } | 427 | } |
385 | 428 | ||
386 | nouveau_pci_resume(pdev); | 429 | NV_INFO(drm, "resuming display...\n"); |
430 | nouveau_display_resume(dev); | ||
387 | return ret; | 431 | return ret; |
388 | } | 432 | } |
389 | 433 | ||
@@ -391,7 +435,7 @@ int | |||
391 | nouveau_drm_resume(struct pci_dev *pdev) | 435 | nouveau_drm_resume(struct pci_dev *pdev) |
392 | { | 436 | { |
393 | struct drm_device *dev = pci_get_drvdata(pdev); | 437 | struct drm_device *dev = pci_get_drvdata(pdev); |
394 | struct nouveau_drm *drm = nouveau_newpriv(dev); | 438 | struct nouveau_drm *drm = nouveau_drm(dev); |
395 | struct nouveau_cli *cli; | 439 | struct nouveau_cli *cli; |
396 | int ret; | 440 | int ret; |
397 | 441 | ||
@@ -419,7 +463,13 @@ nouveau_drm_resume(struct pci_dev *pdev) | |||
419 | if (drm->fence && nouveau_fence(drm)->resume) | 463 | if (drm->fence && nouveau_fence(drm)->resume) |
420 | nouveau_fence(drm)->resume(drm); | 464 | nouveau_fence(drm)->resume(drm); |
421 | 465 | ||
422 | return nouveau_pci_resume(pdev); | 466 | nouveau_run_vbios_init(dev); |
467 | nouveau_irq_postinstall(dev); | ||
468 | nouveau_pm_resume(dev); | ||
469 | |||
470 | NV_INFO(drm, "resuming display...\n"); | ||
471 | nouveau_display_resume(dev); | ||
472 | return 0; | ||
423 | } | 473 | } |
424 | 474 | ||
425 | int | 475 | int |
@@ -472,6 +522,90 @@ nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) | |||
472 | nouveau_cli_destroy(cli); | 522 | nouveau_cli_destroy(cli); |
473 | } | 523 | } |
474 | 524 | ||
525 | static struct drm_ioctl_desc | ||
526 | nouveau_ioctls[] = { | ||
527 | DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_abi16_ioctl_getparam, DRM_UNLOCKED|DRM_AUTH), | ||
528 | DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_abi16_ioctl_setparam, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | ||
529 | DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_abi16_ioctl_channel_alloc, DRM_UNLOCKED|DRM_AUTH), | ||
530 | DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_abi16_ioctl_channel_free, DRM_UNLOCKED|DRM_AUTH), | ||
531 | DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_abi16_ioctl_grobj_alloc, DRM_UNLOCKED|DRM_AUTH), | ||
532 | DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_UNLOCKED|DRM_AUTH), | ||
533 | DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_UNLOCKED|DRM_AUTH), | ||
534 | DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_UNLOCKED|DRM_AUTH), | ||
535 | DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_UNLOCKED|DRM_AUTH), | ||
536 | DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_UNLOCKED|DRM_AUTH), | ||
537 | DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_UNLOCKED|DRM_AUTH), | ||
538 | DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH), | ||
539 | }; | ||
540 | |||
541 | static const struct file_operations | ||
542 | nouveau_driver_fops = { | ||
543 | .owner = THIS_MODULE, | ||
544 | .open = drm_open, | ||
545 | .release = drm_release, | ||
546 | .unlocked_ioctl = drm_ioctl, | ||
547 | .mmap = nouveau_ttm_mmap, | ||
548 | .poll = drm_poll, | ||
549 | .fasync = drm_fasync, | ||
550 | .read = drm_read, | ||
551 | #if defined(CONFIG_COMPAT) | ||
552 | .compat_ioctl = nouveau_compat_ioctl, | ||
553 | #endif | ||
554 | .llseek = noop_llseek, | ||
555 | }; | ||
556 | |||
557 | static struct drm_driver | ||
558 | driver = { | ||
559 | .driver_features = | ||
560 | DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | | ||
561 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | | ||
562 | DRIVER_MODESET | DRIVER_PRIME, | ||
563 | |||
564 | .load = nouveau_drm_load, | ||
565 | .unload = nouveau_drm_unload, | ||
566 | .open = nouveau_drm_open, | ||
567 | .preclose = nouveau_drm_preclose, | ||
568 | .postclose = nouveau_drm_postclose, | ||
569 | .lastclose = nouveau_vga_lastclose, | ||
570 | |||
571 | .irq_preinstall = nouveau_irq_preinstall, | ||
572 | .irq_postinstall = nouveau_irq_postinstall, | ||
573 | .irq_uninstall = nouveau_irq_uninstall, | ||
574 | .irq_handler = nouveau_irq_handler, | ||
575 | |||
576 | .get_vblank_counter = drm_vblank_count, | ||
577 | .enable_vblank = nouveau_vblank_enable, | ||
578 | .disable_vblank = nouveau_vblank_disable, | ||
579 | |||
580 | .ioctls = nouveau_ioctls, | ||
581 | .fops = &nouveau_driver_fops, | ||
582 | |||
583 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
584 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
585 | .gem_prime_export = nouveau_gem_prime_export, | ||
586 | .gem_prime_import = nouveau_gem_prime_import, | ||
587 | |||
588 | .gem_init_object = nouveau_gem_object_new, | ||
589 | .gem_free_object = nouveau_gem_object_del, | ||
590 | .gem_open_object = nouveau_gem_object_open, | ||
591 | .gem_close_object = nouveau_gem_object_close, | ||
592 | |||
593 | .dumb_create = nouveau_display_dumb_create, | ||
594 | .dumb_map_offset = nouveau_display_dumb_map_offset, | ||
595 | .dumb_destroy = nouveau_display_dumb_destroy, | ||
596 | |||
597 | .name = DRIVER_NAME, | ||
598 | .desc = DRIVER_DESC, | ||
599 | #ifdef GIT_REVISION | ||
600 | .date = GIT_REVISION, | ||
601 | #else | ||
602 | .date = DRIVER_DATE, | ||
603 | #endif | ||
604 | .major = DRIVER_MAJOR, | ||
605 | .minor = DRIVER_MINOR, | ||
606 | .patchlevel = DRIVER_PATCHLEVEL, | ||
607 | }; | ||
608 | |||
475 | static struct pci_device_id | 609 | static struct pci_device_id |
476 | nouveau_drm_pci_table[] = { | 610 | nouveau_drm_pci_table[] = { |
477 | { | 611 | { |
@@ -500,19 +634,38 @@ nouveau_drm_pci_driver = { | |||
500 | static int __init | 634 | static int __init |
501 | nouveau_drm_init(void) | 635 | nouveau_drm_init(void) |
502 | { | 636 | { |
503 | return nouveau_init(&nouveau_drm_pci_driver); | 637 | driver.num_ioctls = ARRAY_SIZE(nouveau_ioctls); |
638 | |||
639 | if (nouveau_modeset == -1) { | ||
640 | #ifdef CONFIG_VGA_CONSOLE | ||
641 | if (vgacon_text_force()) | ||
642 | nouveau_modeset = 0; | ||
643 | else | ||
644 | #endif | ||
645 | nouveau_modeset = 1; | ||
646 | } | ||
647 | |||
648 | if (!nouveau_modeset) | ||
649 | return 0; | ||
650 | |||
651 | nouveau_register_dsm_handler(); | ||
652 | return drm_pci_init(&driver, &nouveau_drm_pci_driver); | ||
504 | } | 653 | } |
505 | 654 | ||
506 | static void __exit | 655 | static void __exit |
507 | nouveau_drm_exit(void) | 656 | nouveau_drm_exit(void) |
508 | { | 657 | { |
509 | nouveau_exit(&nouveau_drm_pci_driver); | 658 | if (!nouveau_modeset) |
659 | return; | ||
660 | |||
661 | drm_pci_exit(&driver, &nouveau_drm_pci_driver); | ||
662 | nouveau_unregister_dsm_handler(); | ||
510 | } | 663 | } |
511 | 664 | ||
512 | module_init(nouveau_drm_init); | 665 | module_init(nouveau_drm_init); |
513 | module_exit(nouveau_drm_exit); | 666 | module_exit(nouveau_drm_exit); |
514 | 667 | ||
515 | MODULE_DEVICE_TABLE(pci, nouveau_drm_pci_table); | 668 | MODULE_DEVICE_TABLE(pci, nouveau_drm_pci_table); |
516 | MODULE_AUTHOR("Nouveau Project"); | 669 | MODULE_AUTHOR(DRIVER_AUTHOR); |
517 | MODULE_DESCRIPTION("nVidia Riva/TNT/GeForce/Quadro/Tesla"); | 670 | MODULE_DESCRIPTION(DRIVER_DESC); |
518 | MODULE_LICENSE("GPL and additional rights"); | 671 | MODULE_LICENSE("GPL and additional rights"); |