static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev) { int i, ret; u64 lpar_addr, lpar_size; BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND); the_card.ps3_dev = dev; ret = ps3_open_hv_device(dev); if (ret) return -ENXIO; /* setup MMIO */ ret = lv1_gpu_device_map(2, &lpar_addr, &lpar_size); if (ret) { pr_info("%s: device map 2 failed %d\n", __func__, ret); goto clean_open; } ps3_mmio_region_init(dev, dev->m_region, lpar_addr, lpar_size, PAGE_SHIFT); ret = snd_ps3_map_mmio(); if (ret) goto clean_dev_map; /* setup DMA area */ ps3_dma_region_init(dev, dev->d_region, PAGE_SHIFT, /* use system page size */ 0, /* dma type; not used */ NULL, _ALIGN_UP(SND_PS3_DMA_REGION_SIZE, PAGE_SIZE)); dev->d_region->ioid = PS3_AUDIO_IOID; ret = ps3_dma_region_create(dev->d_region); if (ret) { pr_info("%s: region_create\n", __func__); goto clean_mmio; } snd_ps3_audio_set_base_addr(dev->d_region->bus_addr); /* CONFIG_SND_PS3_DEFAULT_START_DELAY */ the_card.start_delay = snd_ps3_start_delay; /* irq */ if (snd_ps3_allocate_irq()) { ret = -ENXIO; goto clean_dma_region; } /* create card instance */ ret = snd_card_create(index, id, THIS_MODULE, 0, &the_card.card); if (ret < 0) goto clean_irq; strcpy(the_card.card->driver, "PS3"); strcpy(the_card.card->shortname, "PS3"); strcpy(the_card.card->longname, "PS3 sound"); /* create control elements */ for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) { ret = snd_ctl_add(the_card.card, snd_ctl_new1(&spdif_ctls[i], &the_card)); if (ret < 0) goto clean_card; } /* create PCM devices instance */ /* NOTE:this driver works assuming pcm:substream = 1:1 */ ret = snd_pcm_new(the_card.card, "SPDIF", 0, /* instance index, will be stored pcm.device*/ 1, /* output substream */ 0, /* input substream */ &(the_card.pcm)); if (ret) goto clean_card; the_card.pcm->private_data = &the_card; strcpy(the_card.pcm->name, "SPDIF"); /* set pcm ops */ snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ps3_pcm_spdif_ops); the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED; /* pre-alloc PCM DMA buffer*/ ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm, SNDRV_DMA_TYPE_DEV, &dev->core, SND_PS3_PCM_PREALLOC_SIZE, SND_PS3_PCM_PREALLOC_SIZE); if (ret < 0) { pr_info("%s: prealloc failed\n", __func__); goto clean_card; } /* * allocate null buffer * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2 * PAGE_SIZE is enogh */ the_card.null_buffer_start_vaddr = dma_alloc_coherent(&the_card.ps3_dev->core, PAGE_SIZE, &the_card.null_buffer_start_dma_addr, GFP_KERNEL); if (!the_card.null_buffer_start_vaddr) { pr_info("%s: nullbuffer alloc failed\n", __func__); goto clean_preallocate; } pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__, the_card.null_buffer_start_vaddr, the_card.null_buffer_start_dma_addr); /* set default sample rate/word width */ snd_ps3_init_avsetting(&the_card); /* register the card */ snd_card_set_dev(the_card.card, &dev->core); ret = snd_card_register(the_card.card); if (ret < 0) goto clean_dma_map; pr_info("%s started. start_delay=%dms\n", the_card.card->longname, the_card.start_delay); return 0; clean_dma_map: dma_free_coherent(&the_card.ps3_dev->core, PAGE_SIZE, the_card.null_buffer_start_vaddr, the_card.null_buffer_start_dma_addr); clean_preallocate: snd_pcm_lib_preallocate_free_for_all(the_card.pcm); clean_card: snd_card_free(the_card.card); clean_irq: snd_ps3_free_irq(); clean_dma_region: ps3_dma_region_free(dev->d_region); clean_mmio: snd_ps3_unmap_mmio(); clean_dev_map: lv1_gpu_device_unmap(2); clean_open: ps3_close_hv_device(dev); /* * there is no destructor function to pcm. * midlayer automatically releases if the card removed */ return ret; }; /* snd_ps3_probe */
static int __ref ps3_setup_uhc_device( const struct ps3_repository_device *repo, enum ps3_match_id match_id, enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type) { int result; struct layout { struct ps3_system_bus_device dev; struct ps3_dma_region d_region; struct ps3_mmio_region m_region; } *p; u64 bus_addr; u64 len; pr_debug(" -> %s:%d\n", __func__, __LINE__); BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB); BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_USB); p = kzalloc(sizeof(struct layout), GFP_KERNEL); if (!p) { result = -ENOMEM; goto fail_malloc; } p->dev.match_id = match_id; p->dev.dev_type = PS3_DEVICE_TYPE_SB; p->dev.bus_id = repo->bus_id; p->dev.dev_id = repo->dev_id; p->dev.d_region = &p->d_region; p->dev.m_region = &p->m_region; result = ps3_repository_find_interrupt(repo, interrupt_type, &p->dev.interrupt_id); if (result) { pr_debug("%s:%d ps3_repository_find_interrupt failed\n", __func__, __LINE__); goto fail_find_interrupt; } result = ps3_repository_find_reg(repo, reg_type, &bus_addr, &len); if (result) { pr_debug("%s:%d ps3_repository_find_reg failed\n", __func__, __LINE__); goto fail_find_reg; } result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K, PS3_DMA_INTERNAL, NULL, 0); if (result) { pr_debug("%s:%d ps3_dma_region_init failed\n", __func__, __LINE__); goto fail_dma_init; } result = ps3_mmio_region_init(&p->dev, p->dev.m_region, bus_addr, len, PS3_MMIO_4K); if (result) { pr_debug("%s:%d ps3_mmio_region_init failed\n", __func__, __LINE__); goto fail_mmio_init; } result = ps3_system_bus_device_register(&p->dev); if (result) { pr_debug("%s:%d ps3_system_bus_device_register failed\n", __func__, __LINE__); goto fail_device_register; } pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; fail_device_register: fail_mmio_init: fail_dma_init: fail_find_reg: fail_find_interrupt: kfree(p); fail_malloc: pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__); return result; }
static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev) { int i, ret; u64 lpar_addr, lpar_size; BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND); the_card.ps3_dev = dev; ret = ps3_open_hv_device(dev); if (ret) return -ENXIO; ret = lv1_gpu_device_map(2, &lpar_addr, &lpar_size); if (ret) { pr_info("%s: device map 2 failed %d\n", __func__, ret); goto clean_open; } ps3_mmio_region_init(dev, dev->m_region, lpar_addr, lpar_size, PAGE_SHIFT); ret = snd_ps3_map_mmio(); if (ret) goto clean_dev_map; ps3_dma_region_init(dev, dev->d_region, PAGE_SHIFT, 0, NULL, _ALIGN_UP(SND_PS3_DMA_REGION_SIZE, PAGE_SIZE)); dev->d_region->ioid = PS3_AUDIO_IOID; ret = ps3_dma_region_create(dev->d_region); if (ret) { pr_info("%s: region_create\n", __func__); goto clean_mmio; } snd_ps3_audio_set_base_addr(dev->d_region->bus_addr); the_card.start_delay = snd_ps3_start_delay; if (snd_ps3_allocate_irq()) { ret = -ENXIO; goto clean_dma_region; } ret = snd_card_create(index, id, THIS_MODULE, 0, &the_card.card); if (ret < 0) goto clean_irq; strcpy(the_card.card->driver, "PS3"); strcpy(the_card.card->shortname, "PS3"); strcpy(the_card.card->longname, "PS3 sound"); for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) { ret = snd_ctl_add(the_card.card, snd_ctl_new1(&spdif_ctls[i], &the_card)); if (ret < 0) goto clean_card; } ret = snd_pcm_new(the_card.card, "SPDIF", 0, 1, 0, &(the_card.pcm)); if (ret) goto clean_card; the_card.pcm->private_data = &the_card; strcpy(the_card.pcm->name, "SPDIF"); snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ps3_pcm_spdif_ops); the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED; ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm, SNDRV_DMA_TYPE_DEV, &dev->core, SND_PS3_PCM_PREALLOC_SIZE, SND_PS3_PCM_PREALLOC_SIZE); if (ret < 0) { pr_info("%s: prealloc failed\n", __func__); goto clean_card; } the_card.null_buffer_start_vaddr = dma_alloc_coherent(&the_card.ps3_dev->core, PAGE_SIZE, &the_card.null_buffer_start_dma_addr, GFP_KERNEL); if (!the_card.null_buffer_start_vaddr) { pr_info("%s: nullbuffer alloc failed\n", __func__); goto clean_preallocate; } pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__, the_card.null_buffer_start_vaddr, the_card.null_buffer_start_dma_addr); snd_ps3_init_avsetting(&the_card); snd_card_set_dev(the_card.card, &dev->core); ret = snd_card_register(the_card.card); if (ret < 0) goto clean_dma_map; pr_info("%s started. start_delay=%dms\n", the_card.card->longname, the_card.start_delay); return 0; clean_dma_map: dma_free_coherent(&the_card.ps3_dev->core, PAGE_SIZE, the_card.null_buffer_start_vaddr, the_card.null_buffer_start_dma_addr); clean_preallocate: snd_pcm_lib_preallocate_free_for_all(the_card.pcm); clean_card: snd_card_free(the_card.card); clean_irq: snd_ps3_free_irq(); clean_dma_region: ps3_dma_region_free(dev->d_region); clean_mmio: snd_ps3_unmap_mmio(); clean_dev_map: lv1_gpu_device_unmap(2); clean_open: ps3_close_hv_device(dev); return ret; };