예제 #1
0
/* Resets the state of the passed instance */
static void reset_mailbox(struct labx_mailbox *mailbox) {
  /* Disable the instance, and wipe its registers */
  disable_mailbox(mailbox);
}
예제 #2
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 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);
}
예제 #3
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);
}
예제 #4
0
/* I/O control operations for the driver */
static int spi_mailbox_ioctl(struct inode *inode, struct file *flip,
                             unsigned int command, unsigned long arg)
{
  // Switch on the request
  int returnValue = 0;
  struct spi_mailbox *mailbox = (struct spi_mailbox*)flip->private_data;

  switch(command) {
  case IOC_START_MBOX:
    enable_mailbox(mailbox);
    break;

  case IOC_STOP_MBOX:
    disable_mailbox(mailbox);
    break;

  case IOC_READ_MBOX:
    {  
      MessageData userMessage;
      MessageData localMessage;
    
      /* Copy into our local descriptor, then obtain buffer pointer from userland */
      if(copy_from_user(&userMessage, (void __user*)arg, sizeof(userMessage)) != 0) {
        return(-EFAULT);
      }

      returnValue = await_message_ready(mailbox);
     
      if(returnValue < 0) {
        return(returnValue);
      }

      localMessage.length = read_mailbox_message(mailbox, messageBuffer);
     
      if(copy_to_user((void __user*)userMessage.messageContent, messageBuffer,
                      (min(userMessage.length, localMessage.length))) != 0) {
        return(-EFAULT);
      }

      if(copy_to_user((void __user*)arg, &localMessage.length, sizeof(localMessage.length)) != 0 ) {
        return(-EFAULT);
      }
    }  
    break;
  
  case IOC_WRITE_RESP:
    {  
      MessageData userMessage;

      /* Copy into our local descriptor, then obtain buffer pointer from userland */
      if(copy_from_user(&userMessage, (void __user*)arg, sizeof(userMessage)) != 0) {
        return(-EFAULT);
      }
      if(userMessage.length > MAX_MESSAGE_DATA) {
        return(-EINVAL);
      }
      if(copy_from_user(messageBuffer, (void __user*)userMessage.messageContent, 
                        userMessage.length) != 0) {
        return(-EFAULT);
      }
      userMessage.messageContent = messageBuffer;
      send_message_response(mailbox, &userMessage);
    }  
    break;
  
  case IOC_SET_SPI_IRQ_FLAGS:
    {
      set_spi_irq_flags(mailbox, ((uint8_t)arg));
    }
    break;

  case IOC_CLEAR_SPI_IRQ_FLAGS:
    {
      clear_spi_irq_flags(mailbox, ((uint8_t)arg));
    }

  case IOC_READ_SPI_IRQ_FLAGS:
    {
      uint32_t returnValue = read_spi_irq_flags(mailbox);
     
      if(copy_to_user((void __user*)arg, &returnValue, sizeof(returnValue)) != 0 ) {
        return(-EFAULT);
      }
    }

  case IOC_SET_SPI_IRQ_MASK:
    {
      set_spi_irq_mask(mailbox, ((uint8_t)arg));
    }

  case IOC_READ_SPI_IRQ_MASK:
    {
      uint32_t returnValue = read_spi_irq_mask(mailbox);
    
      if(copy_to_user((void __user*)arg, &returnValue, sizeof(returnValue)) != 0 ) {
        return(-EFAULT);
      }
    }

  default:
    /* We don't recognize this command.
     */
    returnValue = -EINVAL;
  }

  /* Return an error code appropriate to the command */
  return(returnValue);
}