Example #1
0
/* 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);
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}