/* Function containing the "meat" of the probe mechanism - this is used by * the OpenFirmware probe as well as the standard platform device mechanism. * This is exported to allow polymorphic drivers to invoke it. * @param name - Name of the instance * @param pdev - Platform device structure * @param addressRange - Resource describing the hardware's I/O range * @param interfaceType - String identifying the interface type * @param numChannels - Number of channels of output * @param derivedFops - File operations to delegate to, NULL if unused * @param derivedData - Pointer for derived driver to make use of * @param newInstance - Pointer to the new driver instance, NULL if unused */ int labx_local_audio_probe(const char *name, struct platform_device *pdev, struct resource *addressRange, const char *interfaceType, u32 numChannels, struct file_operations *derivedFops, void *derivedData, struct labx_local_audio_pdev **newInstance) { struct labx_local_audio_pdev *local_audio_pdev; uint32_t deviceIndex; int32_t ret; /* Create and populate a device structure */ local_audio_pdev = (struct labx_local_audio_pdev*) kzalloc(sizeof(struct labx_local_audio_pdev), GFP_KERNEL); if(!local_audio_pdev) return(-ENOMEM); /* Request and map the device's I/O memory region into uncacheable space */ local_audio_pdev->physicalAddress = addressRange->start; local_audio_pdev->addressRangeSize = ((addressRange->end - addressRange->start) + 1); snprintf(local_audio_pdev->name, NAME_MAX_SIZE, "%s%d", name, instanceCount++); local_audio_pdev->name[NAME_MAX_SIZE - 1] = '\0'; if(request_mem_region(local_audio_pdev->physicalAddress, local_audio_pdev->addressRangeSize, local_audio_pdev->name) == NULL) { ret = -ENOMEM; goto free; } //printk("DMA Physical %08X\n", local_audio_pdev->physicalAddress); local_audio_pdev->virtualAddress = (void*) ioremap_nocache(local_audio_pdev->physicalAddress, local_audio_pdev->addressRangeSize); if(!local_audio_pdev->virtualAddress) { ret = -ENOMEM; goto release; } printk("LA virtualAddress = 0x%08X, phys = 0x%08X, size = 0x%08X\n", (uint32_t) local_audio_pdev->virtualAddress, (uint32_t) local_audio_pdev->physicalAddress, local_audio_pdev->addressRangeSize); /* Allocate and probe for a DMA if the hardware contains one */ if(strcmp(interfaceType, LA_DMA_INTERFACE_EXTERNAL) != 0) { local_audio_pdev->dma = (struct labx_dma*) kzalloc(sizeof(struct labx_dma), GFP_KERNEL); local_audio_pdev->dma->virtualAddress = local_audio_pdev->virtualAddress; //printk("DMA Virtual %p\n", local_audio_pdev->dma.virtualAddress); } else local_audio_pdev->dma = NULL; local_audio_pdev->numChannels = numChannels; printk(" Local Audio interface found at 0x%08X: %d channels, %s DMA\n", (uint32_t) local_audio_pdev->physicalAddress, local_audio_pdev->numChannels, ((local_audio_pdev->dma == NULL) ? "no" : "internal")); local_audio_pdev->miscdev.minor = MISC_DYNAMIC_MINOR; local_audio_pdev->miscdev.name = local_audio_pdev->name; local_audio_pdev->miscdev.fops = &labx_local_audio_fops; ret = misc_register(&local_audio_pdev->miscdev); if (ret) { printk(KERN_WARNING DRIVER_NAME ": Unable to register misc device.\n"); goto unmap; } platform_set_drvdata(pdev, local_audio_pdev); local_audio_pdev->pdev = pdev; dev_set_drvdata(local_audio_pdev->miscdev.this_device, local_audio_pdev); /* Continue with DMA setup if appropriate */ if(local_audio_pdev->dma != NULL) { /* Point the DMA at our name */ local_audio_pdev->dma->name = local_audio_pdev->name; /* Call the general-purpose probe function for the Lab X Dma_Coprocessor. * Provide our device name, and assign no IRQ to the encapsulated DMA; it * does not require one for this application. Ask the underlying driver * code to infer the microcode RAM size for us. */ ret = labx_dma_probe(local_audio_pdev->dma, MISC_MAJOR, local_audio_pdev->miscdev.minor, local_audio_pdev->name, DMA_UCODE_SIZE_UNKNOWN, DMA_NO_IRQ_SUPPLIED, NULL); if(ret) { printk(KERN_WARNING DRIVER_NAME ": Probe of encapsulated DMA failed\n"); goto unmap_dereg; } } /* Locate and occupy the first available device index for future navigation in * the call to labx_local_audio_open() */ for (deviceIndex = 0; deviceIndex < MAX_LA_DEVICES; deviceIndex++) { if (NULL == devices[deviceIndex]) { devices[deviceIndex] = local_audio_pdev; break; } } /* Ensure that we haven't been asked to probe for too many devices */ if(deviceIndex >= MAX_LA_DEVICES) { printk(KERN_WARNING DRIVER_NAME ": Maximum device count (%d) exceeded during probe\n", MAX_LA_DEVICES); goto unmap_dereg; } /* Retain any derived file operations & data to dispatch to */ local_audio_pdev->derivedFops = derivedFops; local_audio_pdev->derivedData = derivedData; /* Return success, setting the return pointer if valid */ if(newInstance != NULL) *newInstance = local_audio_pdev; return(0); unmap_dereg: misc_deregister(&local_audio_pdev->miscdev); unmap: iounmap(local_audio_pdev->virtualAddress); release: release_mem_region(local_audio_pdev->physicalAddress, local_audio_pdev->addressRangeSize); free: kfree(local_audio_pdev->dma); kfree(local_audio_pdev); return(ret); }
static int labx_dma_of_probe(struct of_device *ofdev, const struct of_device_id *match) { struct resource r_mem_struct = {}; struct resource r_irq_struct = {}; struct resource *addressRange = &r_mem_struct; struct resource *irq = &r_irq_struct; struct labx_dma_pdev *dma_pdev; int32_t irqParam; int32_t *int32Ptr; int32_t microcodeWords; int ret; int i; struct platform_device *pdev = to_platform_device(&ofdev->dev); printk(KERN_INFO "Device Tree Probing \'%s\' %d (%s)\n", ofdev->node->name, pdev->id, ofdev->node->full_name); /* Obtain the resources for this instance */ ret = of_address_to_resource(ofdev->node, 0, addressRange); if (ret) { dev_warn(&ofdev->dev, "invalid address\n"); return ret; } /* Create and populate a device structure */ dma_pdev = (struct labx_dma_pdev*) kzalloc(sizeof(struct labx_dma_pdev), GFP_KERNEL); if(!dma_pdev) return(-ENOMEM); /* Request and map the device's I/O memory region into uncacheable space */ dma_pdev->physicalAddress = addressRange->start; dma_pdev->addressRangeSize = ((addressRange->end - addressRange->start) + 1); snprintf(dma_pdev->name, NAME_MAX_SIZE, "%s%d", ofdev->node->name, instanceCount++); dma_pdev->name[NAME_MAX_SIZE - 1] = '\0'; if(request_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize, dma_pdev->name) == NULL) { ret = -ENOMEM; goto free; } //printk("DMA Physical %08X\n", dma_pdev->physicalAddress); dma_pdev->dma.virtualAddress = (void*) ioremap_nocache(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); if(!dma_pdev->dma.virtualAddress) { ret = -ENOMEM; goto release; } //printk("DMA Virtual %p\n", dma_pdev->dma.virtualAddress); /* Obtain the interrupt request number for the instance */ ret = of_irq_to_resource(ofdev->node, 0, irq); if(ret == NO_IRQ) { /* No IRQ was defined; indicate as much */ irqParam = DMA_NO_IRQ_SUPPLIED; } else { irqParam = irq->start; } dma_pdev->miscdev.minor = MISC_DYNAMIC_MINOR; dma_pdev->miscdev.name = dma_pdev->name; dma_pdev->miscdev.fops = &labx_dma_fops; ret = misc_register(&dma_pdev->miscdev); if (ret) { printk(KERN_WARNING DRIVER_NAME ": Unable to register misc device.\n"); goto unmap; } platform_set_drvdata(pdev, dma_pdev); dma_pdev->pdev = pdev; dev_set_drvdata(dma_pdev->miscdev.this_device, dma_pdev); /* See if the device tree has a valid parameter to tell us our microcode size */ int32Ptr = (int32_t *) of_get_property(ofdev->node, "xlnx,microcode-words", NULL); if(int32Ptr == NULL) { /* Allow the DMA driver to infer its microcode size */ microcodeWords = DMA_UCODE_SIZE_UNKNOWN; } else { /* Specify the known size */ microcodeWords = *int32Ptr; } /* Invoke the base device driver's probe function */ labx_dma_probe(&dma_pdev->dma, MISC_MAJOR, dma_pdev->miscdev.minor, dma_pdev->name, microcodeWords, irqParam, NULL); for (i=0; i<MAX_DMA_DEVICES; i++) { if (NULL == devices[i]) { /* printk(DRIVER_NAME ": Device %d = %p\n", i, dma_pdev);*/ /* printk(DRIVER_NAME ": Misc minor is %d\n", dma_pdev->miscdev.minor);*/ devices[i] = dma_pdev; break; } } return(0); unmap: iounmap(dma_pdev->dma.virtualAddress); release: release_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); free: kfree(dma_pdev); return ret; }
static int labx_dma_of_probe(struct of_device *ofdev, const struct of_device_id *match) { struct resource r_mem_struct; struct resource *addressRange = &r_mem_struct; struct labx_dma_pdev *dma_pdev; int ret; int i; struct platform_device *pdev = to_platform_device(&ofdev->dev); printk(KERN_INFO "Device Tree Probing \'%s\' %d (%s)\n", ofdev->node->name, pdev->id, ofdev->node->full_name); /* Obtain the resources for this instance */ ret = of_address_to_resource(ofdev->node, 0, addressRange); if (ret) { dev_warn(&ofdev->dev, "invalid address\n"); return ret; } /* Create and populate a device structure */ dma_pdev = (struct labx_dma_pdev*) kzalloc(sizeof(struct labx_dma_pdev), GFP_KERNEL); if(!dma_pdev) return(-ENOMEM); /* Request and map the device's I/O memory region into uncacheable space */ dma_pdev->physicalAddress = addressRange->start; dma_pdev->addressRangeSize = ((addressRange->end - addressRange->start) + 1); snprintf(dma_pdev->name, NAME_MAX_SIZE, "%s%d", ofdev->node->name, pdev->id); dma_pdev->name[NAME_MAX_SIZE - 1] = '\0'; if(request_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize, dma_pdev->name) == NULL) { ret = -ENOMEM; goto free; } //printk("DMA Physical %08X\n", dma_pdev->physicalAddress); dma_pdev->dma.virtualAddress = (void*) ioremap_nocache(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); if(!dma_pdev->dma.virtualAddress) { ret = -ENOMEM; goto release; } //printk("DMA Virtual %p\n", dma_pdev->dma.virtualAddress); dma_pdev->miscdev.minor = MISC_DYNAMIC_MINOR; dma_pdev->miscdev.name = dma_pdev->name; dma_pdev->miscdev.fops = &labx_dma_fops; ret = misc_register(&dma_pdev->miscdev); if (ret) { printk(KERN_WARNING DRIVER_NAME ": Unable to register misc device.\n"); goto unmap; } platform_set_drvdata(pdev, dma_pdev); dma_pdev->pdev = pdev; dev_set_drvdata(dma_pdev->miscdev.this_device, dma_pdev); labx_dma_probe(&dma_pdev->dma); for (i=0; i<MAX_DMA_DEVICES; i++) { if (NULL == devices[i]) { //printk(DRIVER_NAME ": Device %d = %p\n", i, dma_pdev); devices[i] = dma_pdev; break; } } return 0; unmap: iounmap(dma_pdev->dma.virtualAddress); release: release_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); free: kfree(dma_pdev); return ret; }
static int labx_dma_pdev_probe(struct platform_device *pdev) { struct resource *addressRange; struct resource *irq; struct labx_dma_pdev *dma_pdev; int32_t irqParam; int ret; int i; /* Obtain the resources for this instance */ addressRange = platform_get_resource(pdev, IORESOURCE_MEM, LABX_DMA_ADDRESS_RANGE_RESOURCE); if (!addressRange) return(-ENXIO); /* Create and populate a device structure */ dma_pdev = (struct labx_dma_pdev*) kzalloc(sizeof(struct labx_dma_pdev), GFP_KERNEL); if(!dma_pdev) return(-ENOMEM); /* Attempt to obtain the IRQ; if none is specified, the resource pointer is * NULL, and polling will be used. */ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if(irq == NULL) { irqParam = DMA_NO_IRQ_SUPPLIED; } else { irqParam = irq->start; } /* Request and map the device's I/O memory region into uncacheable space */ dma_pdev->physicalAddress = addressRange->start; dma_pdev->addressRangeSize = ((addressRange->end - addressRange->start) + 1); snprintf(dma_pdev->name, NAME_MAX_SIZE, "%s.%d", pdev->name, pdev->id); dma_pdev->name[NAME_MAX_SIZE - 1] = '\0'; if(request_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize, dma_pdev->name) == NULL) { ret = -ENOMEM; goto free; } //printk("DMA Physical %08X\n", dma_pdev->physicalAddress); instanceCount++; dma_pdev->dma.virtualAddress = (void*) ioremap_nocache(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); if(!dma_pdev->dma.virtualAddress) { ret = -ENOMEM; goto release; } //printk("DMA Virtual %p\n", dma_pdev->dma.virtualAddress); dma_pdev->miscdev.minor = MISC_DYNAMIC_MINOR; dma_pdev->miscdev.name = dma_pdev->name; dma_pdev->miscdev.fops = &labx_dma_fops; ret = misc_register(&dma_pdev->miscdev); if (ret) { printk(KERN_WARNING DRIVER_NAME ": Unable to register misc device.\n"); goto unmap; } platform_set_drvdata(pdev, dma_pdev); dma_pdev->pdev = pdev; dev_set_drvdata(dma_pdev->miscdev.this_device, dma_pdev); /* Call the base driver probe function, passing our name and IRQ selection. * Since we have no "platform data" structure defined, there is no mechanism * for allowing the platform to specify the exact amount of microcode RAM; the * DMA driver will assume the entire microcode address space is backed with RAM. */ labx_dma_probe(&dma_pdev->dma, MISC_MAJOR, dma_pdev->miscdev.minor, dma_pdev->name, DMA_UCODE_SIZE_UNKNOWN, irqParam, NULL); for (i=0; i<MAX_DMA_DEVICES; i++) { if (NULL == devices[i]) { //printk(DRIVER_NAME ": Device %d = %p\n", i, dma_pdev); devices[i] = dma_pdev; break; } } return 0; unmap: iounmap(dma_pdev->dma.virtualAddress); release: release_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); free: kfree(dma_pdev); return ret; }
static int labx_dma_pdev_probe(struct platform_device *pdev) { struct resource *addressRange; struct labx_dma_pdev *dma_pdev; int ret; int i; /* Obtain the resources for this instance */ addressRange = platform_get_resource(pdev, IORESOURCE_MEM, LABX_DMA_ADDRESS_RANGE_RESOURCE); if (!addressRange) return(-ENXIO); /* Create and populate a device structure */ dma_pdev = (struct labx_dma_pdev*) kzalloc(sizeof(struct labx_dma_pdev), GFP_KERNEL); if(!dma_pdev) return(-ENOMEM); /* Request and map the device's I/O memory region into uncacheable space */ dma_pdev->physicalAddress = addressRange->start; dma_pdev->addressRangeSize = ((addressRange->end - addressRange->start) + 1); snprintf(dma_pdev->name, NAME_MAX_SIZE, "%s%d", pdev->name, pdev->id); dma_pdev->name[NAME_MAX_SIZE - 1] = '\0'; if(request_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize, dma_pdev->name) == NULL) { ret = -ENOMEM; goto free; } //printk("DMA Physical %08X\n", dma_pdev->physicalAddress); dma_pdev->dma.virtualAddress = (void*) ioremap_nocache(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); if(!dma_pdev->dma.virtualAddress) { ret = -ENOMEM; goto release; } //printk("DMA Virtual %p\n", dma_pdev->dma.virtualAddress); dma_pdev->miscdev.minor = MISC_DYNAMIC_MINOR; dma_pdev->miscdev.name = dma_pdev->name; dma_pdev->miscdev.fops = &labx_dma_fops; ret = misc_register(&dma_pdev->miscdev); if (ret) { printk(KERN_WARNING DRIVER_NAME ": Unable to register misc device.\n"); goto unmap; } platform_set_drvdata(pdev, dma_pdev); dma_pdev->pdev = pdev; dev_set_drvdata(dma_pdev->miscdev.this_device, dma_pdev); labx_dma_probe(&dma_pdev->dma); for (i=0; i<MAX_DMA_DEVICES; i++) { if (NULL == devices[i]) { //printk(DRIVER_NAME ": Device %d = %p\n", i, dma_pdev); devices[i] = dma_pdev; break; } } return 0; unmap: iounmap(dma_pdev->dma.virtualAddress); release: release_mem_region(dma_pdev->physicalAddress, dma_pdev->addressRangeSize); free: kfree(dma_pdev); return ret; }