diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-05-30 12:27:03 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-06-22 06:27:47 -0400 |
commit | b6a969155b04416185f368bd4e2f1d49b17c1ee1 (patch) | |
tree | c6db67bdc4b4d107902cf6ced9d66fb0ab15600c /sound/core | |
parent | 4d572776d4dfa2d5385a2ec3acec3cc059149e13 (diff) |
[ALSA] Add write support to snd-page-alloc proc file
Documentation,Memalloc module,RME HDSP driver,RME9652 driver
Add the write support to snd-page-alloc proc file for buffer pre-allocation.
Removed the pre-allocation codes via module options.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/memalloc.c | 201 |
1 files changed, 109 insertions, 92 deletions
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 344a83fd7c2e..dbc23e35fa06 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/mm.h> | 30 | #include <linux/mm.h> |
31 | #include <asm/uaccess.h> | ||
31 | #include <linux/dma-mapping.h> | 32 | #include <linux/dma-mapping.h> |
32 | #include <linux/moduleparam.h> | 33 | #include <linux/moduleparam.h> |
33 | #include <asm/semaphore.h> | 34 | #include <asm/semaphore.h> |
@@ -46,13 +47,6 @@ MODULE_LICENSE("GPL"); | |||
46 | #define SNDRV_CARDS 8 | 47 | #define SNDRV_CARDS 8 |
47 | #endif | 48 | #endif |
48 | 49 | ||
49 | /* FIXME: so far only some PCI devices have the preallocation table */ | ||
50 | #ifdef CONFIG_PCI | ||
51 | static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; | ||
52 | module_param_array(enable, bool, NULL, 0444); | ||
53 | MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); | ||
54 | #endif | ||
55 | |||
56 | /* | 50 | /* |
57 | */ | 51 | */ |
58 | 52 | ||
@@ -451,9 +445,13 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) | |||
451 | list_for_each(p, &mem_list_head) { | 445 | list_for_each(p, &mem_list_head) { |
452 | mem = list_entry(p, struct snd_mem_list, list); | 446 | mem = list_entry(p, struct snd_mem_list, list); |
453 | if (mem->id == id && | 447 | if (mem->id == id && |
454 | ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) { | 448 | (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || |
449 | ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { | ||
450 | struct device *dev = dmab->dev.dev; | ||
455 | list_del(p); | 451 | list_del(p); |
456 | *dmab = mem->buffer; | 452 | *dmab = mem->buffer; |
453 | if (dmab->dev.dev == NULL) | ||
454 | dmab->dev.dev = dev; | ||
457 | kfree(mem); | 455 | kfree(mem); |
458 | up(&list_mutex); | 456 | up(&list_mutex); |
459 | return dmab->bytes; | 457 | return dmab->bytes; |
@@ -508,91 +506,13 @@ static void free_all_reserved_pages(void) | |||
508 | } | 506 | } |
509 | 507 | ||
510 | 508 | ||
511 | |||
512 | /* | ||
513 | * allocation of buffers for pre-defined devices | ||
514 | */ | ||
515 | |||
516 | #ifdef CONFIG_PCI | ||
517 | /* FIXME: for pci only - other bus? */ | ||
518 | struct prealloc_dev { | ||
519 | unsigned short vendor; | ||
520 | unsigned short device; | ||
521 | unsigned long dma_mask; | ||
522 | unsigned int size; | ||
523 | unsigned int buffers; | ||
524 | }; | ||
525 | |||
526 | #define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000) | ||
527 | |||
528 | static struct prealloc_dev prealloc_devices[] __initdata = { | ||
529 | { | ||
530 | /* hammerfall */ | ||
531 | .vendor = 0x10ee, | ||
532 | .device = 0x3fc4, | ||
533 | .dma_mask = 0xffffffff, | ||
534 | .size = HAMMERFALL_BUFFER_SIZE, | ||
535 | .buffers = 2 | ||
536 | }, | ||
537 | { | ||
538 | /* HDSP */ | ||
539 | .vendor = 0x10ee, | ||
540 | .device = 0x3fc5, | ||
541 | .dma_mask = 0xffffffff, | ||
542 | .size = HAMMERFALL_BUFFER_SIZE, | ||
543 | .buffers = 2 | ||
544 | }, | ||
545 | { }, /* terminator */ | ||
546 | }; | ||
547 | |||
548 | static void __init preallocate_cards(void) | ||
549 | { | ||
550 | struct pci_dev *pci = NULL; | ||
551 | int card; | ||
552 | |||
553 | card = 0; | ||
554 | |||
555 | while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { | ||
556 | struct prealloc_dev *dev; | ||
557 | unsigned int i; | ||
558 | if (card >= SNDRV_CARDS) | ||
559 | break; | ||
560 | for (dev = prealloc_devices; dev->vendor; dev++) { | ||
561 | if (dev->vendor == pci->vendor && dev->device == pci->device) | ||
562 | break; | ||
563 | } | ||
564 | if (! dev->vendor) | ||
565 | continue; | ||
566 | if (! enable[card++]) { | ||
567 | printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device); | ||
568 | continue; | ||
569 | } | ||
570 | |||
571 | if (pci_set_dma_mask(pci, dev->dma_mask) < 0 || | ||
572 | pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) { | ||
573 | printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); | ||
574 | continue; | ||
575 | } | ||
576 | for (i = 0; i < dev->buffers; i++) { | ||
577 | struct snd_dma_buffer dmab; | ||
578 | memset(&dmab, 0, sizeof(dmab)); | ||
579 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
580 | dev->size, &dmab) < 0) | ||
581 | printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size); | ||
582 | else | ||
583 | snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | #else | ||
588 | #define preallocate_cards() /* NOP */ | ||
589 | #endif | ||
590 | |||
591 | |||
592 | #ifdef CONFIG_PROC_FS | 509 | #ifdef CONFIG_PROC_FS |
593 | /* | 510 | /* |
594 | * proc file interface | 511 | * proc file interface |
595 | */ | 512 | */ |
513 | #define SND_MEM_PROC_FILE "driver/snd-page-alloc" | ||
514 | struct proc_dir_entry *snd_mem_proc; | ||
515 | |||
596 | static int snd_mem_proc_read(char *page, char **start, off_t off, | 516 | static int snd_mem_proc_read(char *page, char **start, off_t off, |
597 | int count, int *eof, void *data) | 517 | int count, int *eof, void *data) |
598 | { | 518 | { |
@@ -621,6 +541,97 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, | |||
621 | up(&list_mutex); | 541 | up(&list_mutex); |
622 | return len; | 542 | return len; |
623 | } | 543 | } |
544 | |||
545 | /* FIXME: for pci only - other bus? */ | ||
546 | #ifdef CONFIG_PCI | ||
547 | #define gettoken(bufp) strsep(bufp, " \t\n") | ||
548 | |||
549 | static int snd_mem_proc_write(struct file *file, const char __user *buffer, | ||
550 | unsigned long count, void *data) | ||
551 | { | ||
552 | char buf[128]; | ||
553 | char *token, *p; | ||
554 | |||
555 | if (count > ARRAY_SIZE(buf) - 1) | ||
556 | count = ARRAY_SIZE(buf) - 1; | ||
557 | if (copy_from_user(buf, buffer, count)) | ||
558 | return -EFAULT; | ||
559 | buf[ARRAY_SIZE(buf) - 1] = '\0'; | ||
560 | |||
561 | p = buf; | ||
562 | token = gettoken(&p); | ||
563 | if (! token || *token == '#') | ||
564 | return (int)count; | ||
565 | if (strcmp(token, "add") == 0) { | ||
566 | char *endp; | ||
567 | int vendor, device, size, buffers; | ||
568 | long mask; | ||
569 | int i, alloced; | ||
570 | struct pci_dev *pci; | ||
571 | |||
572 | if ((token = gettoken(&p)) == NULL || | ||
573 | (vendor = simple_strtol(token, NULL, 0)) <= 0 || | ||
574 | (token = gettoken(&p)) == NULL || | ||
575 | (device = simple_strtol(token, NULL, 0)) <= 0 || | ||
576 | (token = gettoken(&p)) == NULL || | ||
577 | (mask = simple_strtol(token, NULL, 0)) < 0 || | ||
578 | (token = gettoken(&p)) == NULL || | ||
579 | (size = memparse(token, &endp)) < 64*1024 || | ||
580 | size > 16*1024*1024 /* too big */ || | ||
581 | (token = gettoken(&p)) == NULL || | ||
582 | (buffers = simple_strtol(token, NULL, 0)) <= 0 || | ||
583 | buffers > 4) { | ||
584 | printk(KERN_ERR "snd-page-alloc: invalid proc write format\n"); | ||
585 | return (int)count; | ||
586 | } | ||
587 | vendor &= 0xffff; | ||
588 | device &= 0xffff; | ||
589 | |||
590 | alloced = 0; | ||
591 | pci = NULL; | ||
592 | while ((pci = pci_find_device(vendor, device, pci)) != NULL) { | ||
593 | if (mask > 0 && mask < 0xffffffff) { | ||
594 | if (pci_set_dma_mask(pci, mask) < 0 || | ||
595 | pci_set_consistent_dma_mask(pci, mask) < 0) { | ||
596 | printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); | ||
597 | return (int)count; | ||
598 | } | ||
599 | } | ||
600 | for (i = 0; i < buffers; i++) { | ||
601 | struct snd_dma_buffer dmab; | ||
602 | memset(&dmab, 0, sizeof(dmab)); | ||
603 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
604 | size, &dmab) < 0) { | ||
605 | printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); | ||
606 | return (int)count; | ||
607 | } | ||
608 | snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); | ||
609 | } | ||
610 | alloced++; | ||
611 | } | ||
612 | if (! alloced) { | ||
613 | for (i = 0; i < buffers; i++) { | ||
614 | struct snd_dma_buffer dmab; | ||
615 | memset(&dmab, 0, sizeof(dmab)); | ||
616 | /* FIXME: We can allocate only in ZONE_DMA | ||
617 | * without a device pointer! | ||
618 | */ | ||
619 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL, | ||
620 | size, &dmab) < 0) { | ||
621 | printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); | ||
622 | break; | ||
623 | } | ||
624 | snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device)); | ||
625 | } | ||
626 | } | ||
627 | } else if (strcmp(token, "erase") == 0) | ||
628 | /* FIXME: need for releasing each buffer chunk? */ | ||
629 | free_all_reserved_pages(); | ||
630 | else | ||
631 | printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n"); | ||
632 | return (int)count; | ||
633 | } | ||
634 | #endif /* CONFIG_PCI */ | ||
624 | #endif /* CONFIG_PROC_FS */ | 635 | #endif /* CONFIG_PROC_FS */ |
625 | 636 | ||
626 | /* | 637 | /* |
@@ -630,15 +641,21 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, | |||
630 | static int __init snd_mem_init(void) | 641 | static int __init snd_mem_init(void) |
631 | { | 642 | { |
632 | #ifdef CONFIG_PROC_FS | 643 | #ifdef CONFIG_PROC_FS |
633 | create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL); | 644 | snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL); |
645 | if (snd_mem_proc) { | ||
646 | snd_mem_proc->read_proc = snd_mem_proc_read; | ||
647 | #ifdef CONFIG_PCI | ||
648 | snd_mem_proc->write_proc = snd_mem_proc_write; | ||
649 | #endif | ||
650 | } | ||
634 | #endif | 651 | #endif |
635 | preallocate_cards(); | ||
636 | return 0; | 652 | return 0; |
637 | } | 653 | } |
638 | 654 | ||
639 | static void __exit snd_mem_exit(void) | 655 | static void __exit snd_mem_exit(void) |
640 | { | 656 | { |
641 | remove_proc_entry("driver/snd-page-alloc", NULL); | 657 | if (snd_mem_proc) |
658 | remove_proc_entry(SND_MEM_PROC_FILE, NULL); | ||
642 | free_all_reserved_pages(); | 659 | free_all_reserved_pages(); |
643 | if (snd_allocated_pages > 0) | 660 | if (snd_allocated_pages > 0) |
644 | printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); | 661 | printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); |