static int spi_mailbox_platform_remove(struct platform_device *pdev) { struct spi_mailbox *mailbox; /* Get a handle to the mailbox and begin shutting it down */ mailbox = platform_get_drvdata(pdev); if(!mailbox) return(-1); cdev_del(&mailbox->cdev); reset_mailbox(mailbox); iounmap(mailbox->virtualAddress); release_mem_region(mailbox->physicalAddress, mailbox->addressRangeSize); kfree(mailbox); return(0); }
static int mailbox_platform_remove(struct platform_device *pdev) { struct labx_mailbox *mailbox; /* Get a handle to the mailbox and begin shutting it down */ mailbox = platform_get_drvdata(pdev); if(!mailbox) return(-1); /* Release the IRQ */ if (mailbox->irq != NO_IRQ_SUPPLIED) { free_irq(mailbox->irq, mailbox); } kthread_stop(mailbox->netlinkTask); reset_mailbox(mailbox); iounmap(mailbox->virtualAddress); release_mem_region(mailbox->physicalAddress, mailbox->addressRangeSize); kfree(mailbox); return(0); }
/* Function containing the "meat" of the probe mechanism - this is used by * the OpenFirmware probe as well as the standard platform device mechanism. * @param name - Name of the instance * @param pdev - Platform device structure * @param addressRange - Resource describing the hardware's I/O range * @param irq - Resource describing the hardware's IRQ */ static int mailbox_probe(const char *name, struct platform_device *pdev, struct resource *addressRange, struct resource *irq) { struct labx_mailbox *mailbox; int returnValue; int i; /* Create and populate a device structure */ mailbox = (struct labx_mailbox*) kmalloc(sizeof(struct labx_mailbox), GFP_KERNEL); if(!mailbox) return(-ENOMEM); /* Request and map the device's I/O memory region into uncacheable space */ mailbox->physicalAddress = addressRange->start; mailbox->addressRangeSize = ((addressRange->end - addressRange->start) + 1); snprintf(mailbox->name, NAME_MAX_SIZE, "%s", name); mailbox->name[NAME_MAX_SIZE - 1] = '\0'; if(request_mem_region(mailbox->physicalAddress, mailbox->addressRangeSize, mailbox->name) == NULL) { returnValue = -ENOMEM; goto free; } mailbox->virtualAddress = (void*) ioremap_nocache(mailbox->physicalAddress, mailbox->addressRangeSize); if(!mailbox->virtualAddress) { returnValue = -ENOMEM; goto release; } /* Ensure that the mailbox and its interrupts are disabled */ disable_mailbox(mailbox); XIo_Out32(REGISTER_ADDRESS(mailbox, SUPRV_IRQ_MASK_REG), NO_IRQS); /* Clear the message ready flag for the first time */ mailbox->messageReadyFlag = MESSAGE_NOT_READY; /* Retain the IRQ and register our handler, if an IRQ resource was supplied. */ if(irq != NULL) { mailbox->irq = irq->start; returnValue = request_irq(mailbox->irq, &mailbox_interrupt, IRQF_DISABLED, mailbox->name, mailbox); if (returnValue) { printk(KERN_ERR "%s : Could not allocate Mailbox interrupt (%d).\n", mailbox->name, mailbox->irq); goto unmap; } } else mailbox->irq = NO_IRQ_SUPPLIED; /* Announce the device */ printk(KERN_INFO "%s: Found mailbox at 0x%08X, ", mailbox->name, (uint32_t)mailbox->physicalAddress); if(mailbox->irq == NO_IRQ_SUPPLIED) { printk("polled interlocks\n"); } else { printk("IRQ %d\n", mailbox->irq); } /* Initialize other resources */ spin_lock_init(&mailbox->mutex); mailbox->opened = true; /* Provide navigation between the device structures */ platform_set_drvdata(pdev, mailbox); mailbox->pdev = pdev; /* Reset the state of the mailbox */ reset_mailbox(mailbox); /* Initialize the waitqueue used for synchronized writes */ init_waitqueue_head(&(mailbox->messageReadQueue)); /* Initialize the netlink state and start the thread */ mailbox->netlinkSequence = 0; mailbox->netlinkTask = kthread_run(netlink_thread, (void*)mailbox, "%s:netlink", mailbox->name); if (IS_ERR(mailbox->netlinkTask)) { printk(KERN_ERR "Mailbox netlink task creation failed.\n"); returnValue = -EIO; goto free; } /* Now that the device is configured, enable interrupts if they are to be used */ if(mailbox->irq != NO_IRQ_SUPPLIED) { XIo_Out32(REGISTER_ADDRESS(mailbox, SUPRV_IRQ_MASK_REG), ALL_IRQS); XIo_Out32(REGISTER_ADDRESS(mailbox, SUPRV_IRQ_FLAGS_REG), ALL_IRQS); } // Add the mailbox instance to the list of current devices for(i=0;i<MAX_MAILBOX_DEVICES;i++) { if(NULL == labx_mailboxes[i]) { labx_mailboxes[i] = mailbox; printk("Adding mailbox: %s\n", labx_mailboxes[i]->name); break; } } DBG("Mailbox initialized\n"); /* Return success */ return(0); unmap: iounmap(mailbox->virtualAddress); release: release_mem_region(mailbox->physicalAddress, mailbox->addressRangeSize); free: kfree(mailbox); return(returnValue); }
/* Function containing the "meat" of the probe mechanism - this is used by * the OpenFirmware probe as well as the standard platform device mechanism. * @param name - Name of the instance * @param pdev - Platform device structure * @param addressRange - Resource describing the hardware's I/O range * @param irq - Resource describing the hardware's IRQ */ static int spi_mailbox_probe(const char *name, struct platform_device *pdev, struct resource *addressRange, struct resource *irq) { struct spi_mailbox *mailbox; int returnValue; /* Create and populate a device structure */ mailbox = (struct spi_mailbox*) kmalloc(sizeof(struct spi_mailbox), GFP_KERNEL); if(!mailbox) return(-ENOMEM); /* Request and map the device's I/O memory region into uncacheable space */ mailbox->physicalAddress = addressRange->start; mailbox->addressRangeSize = ((addressRange->end - addressRange->start) + 1); snprintf(mailbox->name, NAME_MAX_SIZE, "%s", name); mailbox->name[NAME_MAX_SIZE - 1] = '\0'; if(request_mem_region(mailbox->physicalAddress, mailbox->addressRangeSize, mailbox->name) == NULL) { returnValue = -ENOMEM; goto free; } mailbox->virtualAddress = (void*) ioremap_nocache(mailbox->physicalAddress, mailbox->addressRangeSize); if(!mailbox->virtualAddress) { returnValue = -ENOMEM; goto release; } /* Ensure that the mailbox and its interrupts are disabled */ disable_mailbox(mailbox); XIo_Out32(REGISTER_ADDRESS(mailbox, IRQ_MASK_REG), NO_IRQS); /* Retain the IRQ and register our handler, if an IRQ resource was supplied. */ if(irq != NULL) { mailbox->irq = irq->start; returnValue = request_irq(mailbox->irq, &biamp_spi_mailbox_interrupt, IRQF_DISABLED, mailbox->name, mailbox); if (returnValue) { printk(KERN_ERR "%s : Could not allocate Biamp SPI Mailbox interrupt (%d).\n", mailbox->name, mailbox->irq); goto unmap; } } else mailbox->irq = NO_IRQ_SUPPLIED; /* Announce the device */ printk(KERN_INFO "%s: Found Biamp mailbox at 0x%08X, ", mailbox->name, (uint32_t)mailbox->physicalAddress); if(mailbox->irq == NO_IRQ_SUPPLIED) { printk("polled interlocks\n"); } else { printk("IRQ %d\n", mailbox->irq); } /* Initialize other resources */ spin_lock_init(&mailbox->mutex); mailbox->opened = false; /* Provide navigation between the device structures */ platform_set_drvdata(pdev, mailbox); mailbox->pdev = pdev; /* Reset the state of the mailbox */ reset_mailbox(mailbox); /* Add as a character device to make the instance available for use */ cdev_init(&mailbox->cdev, &spi_mailbox_fops); mailbox->cdev.owner = THIS_MODULE; kobject_set_name(&mailbox->cdev.kobj, "%s%d", mailbox->name, mailbox->instanceNumber); mailbox->instanceNumber = instanceCount++; cdev_add(&mailbox->cdev, MKDEV(DRIVER_MAJOR, mailbox->instanceNumber), 1); /* Initialize the waitqueue used for synchronized writes */ init_waitqueue_head(&(mailbox->messageReadQueue)); /* Now that the device is configured, enable interrupts if they are to be used */ if(mailbox->irq != NO_IRQ_SUPPLIED) { XIo_Out32(REGISTER_ADDRESS(mailbox, IRQ_FLAGS_REG), ALL_IRQS); XIo_Out32(REGISTER_ADDRESS(mailbox, IRQ_MASK_REG), IRQ_S2H_MSG_RX); } DBG("Mailbox initialized\n"); /* Return success */ return(0); unmap: iounmap(mailbox->virtualAddress); release: release_mem_region(mailbox->physicalAddress, mailbox->addressRangeSize); free: kfree(mailbox); return(returnValue); }