예제 #1
0
static void stmhdmi_connect_display(struct stm_hdmi *hdmi)
{
  if(!hdmi->disable)
  {
    stm_meta_data_result_t res;

    DPRINTK("HDMI Output connected, signalling for authentication hdmi = %p queue = %p\n",hdmi,&(hdmi->auth_wait_queue));
    hdmi->auth = 0;
    wake_up(&(hdmi->auth_wait_queue));
    /*
     * Schedule the sending of the product identifier HDMI info frame.
     */
    if(hdmi->spd_frame->data[HDMI_SPD_INFOFRAME_SPI_OFFSET] != HDMI_SPD_INFOFRAME_SPI_DISABLE)
      (void)stm_display_output_queue_metadata(hdmi->hdmi_output, hdmi->spd_metadata, &res);
    /*
     * Signal the hotplug sysfs attribute now the output is alive.
     */
    sysfs_notify(&(hdmi->class_device->kobj), NULL, "hotplug");
  }
  else
  {
    DPRINTK("HDMI Output disabled\n");
    stm_display_output_stop(hdmi->hdmi_output);
  }
}
예제 #2
0
/*******************************************************************************
 * Kernel management thread state machine helper functions.
 */
static void stmhdmi_handle_wait_queue_timeout(struct stm_hdmi *hdmi)
{
  switch(hdmi->status)
  {
    case STM_DISPLAY_CONNECTED:
    {
      stm_meta_data_result_t res;

      /*
       * We are deliberately ignoring any errors when queuing SPD data as
       * (a) they really shouldn't happen and (b) there is nothing we can
       * do about it anyway.
       */
      if(hdmi->spd_frame->data[HDMI_SPD_INFOFRAME_SPI_OFFSET] != HDMI_SPD_INFOFRAME_SPI_DISABLE)
        (void)stm_display_output_queue_metadata(hdmi->hdmi_output, hdmi->spd_metadata, &res);

      break;
    }
    case STM_DISPLAY_DISCONNECTED:
    {
      if(hdmi->deferred_disconnect > 0)
      {
        hdmi->deferred_disconnect--;

        if(hdmi->deferred_disconnect == 0)
        {
          DPRINTK("Doing deferred output disable due to HPD de-assert timeout\n");
          stm_display_output_stop(hdmi->hdmi_output);
          hdmi->disable = true;
          sysfs_notify(&(hdmi->class_device->kobj), NULL, "hotplug");
        }
      }
      break;
    }
    default:
      break;
  }
}
예제 #3
0
파일: hdmidev.c 프로젝트: Niptok/tdt-amiko
static int stmhdmi_set_audio_iframe_data(struct stm_hdmi *dev, unsigned long arg)
{
  stm_meta_data_result_t res;
  stm_meta_data_t       *metadata;
  stm_hdmi_info_frame_t *iframe;
  struct stmhdmiio_audio audiocfg;

  if (copy_from_user(&audiocfg,(void*)arg,sizeof(audiocfg)))
    return -EFAULT;

  if((metadata = kzalloc(sizeof(stm_meta_data_t)+sizeof(stm_hdmi_info_frame_t),GFP_KERNEL)) == 0)
    return -ENOMEM;

  metadata->size    = sizeof(stm_meta_data_t)+sizeof(stm_hdmi_info_frame_t);
  metadata->release = (void(*)(struct stm_meta_data_s*))kfree;
  metadata->type    = STM_METADATA_TYPE_AUDIO_IFRAME;

  iframe          = (stm_hdmi_info_frame_t*)&metadata->data[0];
  iframe->type    = HDMI_AUDIO_INFOFRAME_TYPE;
  iframe->version = HDMI_AUDIO_INFOFRAME_VERSION;
  iframe->length  = HDMI_AUDIO_INFOFRAME_LENGTH;
  iframe->data[1] = (audiocfg.channel_count    << HDMI_AUDIO_INFOFRAME_CHANNEL_COUNT_SHIFT) & HDMI_AUDIO_INFOFRAME_CHANNEL_COUNT_MASK;
  iframe->data[2] = (audiocfg.sample_frequency << HDMI_AUDIO_INFOFRAME_FREQ_SHIFT) & HDMI_AUDIO_INFOFRAME_FREQ_MASK;
  iframe->data[4] = audiocfg.speaker_mapping;
  iframe->data[5] = audiocfg.downmix_info & (HDMI_AUDIO_INFOFRAME_LEVELSHIFT_MASK|
                                             HDMI_AUDIO_INFOFRAME_DOWNMIX_INHIBIT);

  if(stm_display_output_queue_metadata(dev->hdmi_output, metadata, &res)<0)
  {
    kfree(metadata);
    if(signal_pending(current))
      return -ERESTARTSYS;
    else
      return -EIO;
  }

  return stmhdmi_convert_metadata_result_to_errno(res);
}
예제 #4
0
static int stmfb_set_picture_configuration(struct stmfbio_picture_configuration *cfg, struct stmfb_info *i)
{
  stm_meta_data_result_t res;
  stm_meta_data_t *metadata;
  stm_picture_format_info_t *pic_info;
  unsigned long flags;
  int ret = 0;

  if((cfg->flags & STMFBIO_PICTURE_FLAGS_PICUTRE_ASPECT) &&
     (cfg->picture_aspect > STMFBIO_PIC_PICTURE_ASPECT_16_9))
    return -EINVAL;

  if((cfg->flags & STMFBIO_PICTURE_FLAGS_VIDEO_ASPECT) &&
     (cfg->video_aspect > STMFBIO_PIC_VIDEO_ASPECT_GT_16_9))
    return -EINVAL;

  if((cfg->flags & STMFBIO_PICTURE_FLAGS_LETTERBOX) &&
     (cfg->letterbox_style > STMFBIO_PIC_LETTERBOX_SAP_4_3))
    return -EINVAL;

  if((cfg->flags & STMFBIO_PICTURE_FLAGS_RESCALE_INFO) &&
     (cfg->picture_rescale > STMFBIO_PIC_RESCALE_BOTH))
    return -EINVAL;

  if((metadata = kzalloc(sizeof(stm_meta_data_t)+sizeof(stm_picture_format_info_t),GFP_KERNEL)) == 0)
    return -ENOMEM;

  metadata->size      = sizeof(stm_meta_data_t)+sizeof(stm_picture_format_info_t);
  metadata->type      = STM_METADATA_TYPE_PICTURE_INFO;
  /*
   * We need to hold a reference for the metadata as we need to queue
   * the same thing twice (to analogue and HDMI outputs) and need to ensure we
   * do not get any race conditions in the lifetime of the object. We use the
   * metadata addref/release internal helpers to manage this. We must use
   * the release under interrupt lock once a queue has been successful to
   * ensure it is atomic with the VTG interrupt processing, but we actually do
   * this all the time to make the point and stop the code from
   * breaking in future changes.
   */
  spin_lock_irqsave(&i->framebufferSpinLock,flags);
  stm_meta_data_addref(metadata);
  spin_unlock_irqrestore(&i->framebufferSpinLock,flags);

  metadata->release   = (void(*)(struct stm_meta_data_s*))kfree;
  metadata->presentationTime = ((TIME64)cfg->timestamp.tv_sec * USEC_PER_SEC) +
                                (TIME64)cfg->timestamp.tv_usec;

  pic_info = (stm_picture_format_info_t*)&metadata->data[0];
  pic_info->flags           = cfg->flags;
  pic_info->pictureAspect   = (stm_wss_t)cfg->picture_aspect;
  pic_info->videoAspect     = (stm_wss_t)cfg->video_aspect;
  pic_info->letterboxStyle  = (stm_letterbox_t)cfg->letterbox_style;
  pic_info->pictureRescale  = (stm_picture_rescale_t)cfg->picture_rescale;
  pic_info->barEnable       = cfg->bar_enable;
  pic_info->topEndLine      = cfg->top_bar_end;
  pic_info->bottomStartLine = cfg->bottom_bar_start;
  pic_info->leftEndPixel    = cfg->left_bar_end;
  pic_info->rightStartPixel = cfg->right_bar_start;

  if(stm_display_output_queue_metadata(i->pFBMainOutput, metadata, &res)<0)
  {
    ret = signal_pending(current)?-EINTR:-EIO;
    goto exit;
  }

  /*
   * Set first stab at the wanted return value, this is likely to be revised
   * below.
   */
  ret = stmfb_convert_metadata_result_to_errno(res);

  if(i->hdmi == NULL)
  {
    /*
     * Display pipeline has no HDMI transmitter so just return this result.
     */
    goto exit;
  }

  switch(res)
  {
    case STM_METADATA_RES_OK:
    case STM_METADATA_RES_QUEUE_UNAVAILABLE:
      /*
       * If the DENC isn't in use the queue will not be available,
       * but that is fine we can continue to HDMI.
       */
      break;
    default:
      goto exit;
  }

  if(mutex_lock_interruptible(&i->hdmi->lock))
  {
    ret = -EINTR;
    goto exit;
  }

  /*
   * DVI or undetermined sink does not have InfoFrames.
   */
  if(i->hdmi->edid_info.display_type != STM_DISPLAY_HDMI)
    goto mutex_exit;


  if((i->hdmi->status != STM_DISPLAY_CONNECTED) &&
     (metadata->presentationTime == 0LL))
  {
    /*
     * This is a slight of hand for the usual case that a change
     * is required immediately but the HDMI output is currently
     * stopped and will not process its metadata queues. Flush the queue
     * because we know this request will be the valid data as soon
     * as the HDMI output is started again.
     */
    stm_display_output_flush_metadata(i->hdmi->hdmi_output,STM_METADATA_TYPE_PICTURE_INFO);
  }


  if(stm_display_output_queue_metadata(i->hdmi->hdmi_output, metadata, &res)<0)
  {
    ret = signal_pending(current)?-EINTR:-EIO;
    goto mutex_exit;
  }

  ret = stmfb_convert_metadata_result_to_errno(res);

mutex_exit:
  mutex_unlock(&i->hdmi->lock);
exit:
  spin_lock_irqsave(&i->framebufferSpinLock,flags);
  stm_meta_data_release(metadata);
  spin_unlock_irqrestore(&i->framebufferSpinLock,flags);

  return ret;
}
예제 #5
0
파일: hdmidev.c 프로젝트: Niptok/tdt-amiko
static int stmhdmi_set_isrc_data(struct stm_hdmi *dev, unsigned long arg)
{
  stm_meta_data_result_t res;
  stm_meta_data_t       *metadata;
  stm_hdmi_isrc_data_t  *isrc;
  struct stmhdmiio_isrc_data isrcdata;

  if (copy_from_user(&isrcdata,(void*)arg,sizeof(isrcdata)))
    return -EFAULT;

  /*
   * Don't allow the configuration of ISRC packets unless the
   * connected TV has the supports AI flag set in its EDID.
   */
  if((dev->edid_info.display_type != STM_DISPLAY_HDMI) ||
     (dev->edid_info.hdmi_vsdb_flags & STM_HDMI_VSDB_SUPPORTS_AI) == 0)
  {
    DPRINTK("Not Sending ISRC Datapackets, sink does not support AI\n");
    return -EPERM;
  }

  if((metadata = kzalloc(sizeof(stm_meta_data_t)+sizeof(stm_hdmi_isrc_data_t),GFP_KERNEL)) == 0)
    return -ENOMEM;

  metadata->size    = sizeof(stm_meta_data_t)+sizeof(stm_hdmi_isrc_data_t);
  metadata->release = (void(*)(struct stm_meta_data_s*))kfree;
  metadata->type    = STM_METADATA_TYPE_ISRC_DATA;
  metadata->presentationTime = ((TIME64)isrcdata.timestamp.tv_sec * USEC_PER_SEC) +
                                (TIME64)isrcdata.timestamp.tv_usec;

  isrc = (stm_hdmi_isrc_data_t*)&metadata->data[0];
  isrc->isrc1.type = HDMI_ISRC1_PACKET_TYPE;
  isrc->isrc2.type = HDMI_ISRC2_PACKET_TYPE;

  if(isrcdata.status != ISRC_STATUS_DISABLE)
  {
    int i;
    isrc->isrc1.version = (isrcdata.status & HDMI_ISRC1_STATUS_MASK) | HDMI_ISRC1_VALID;
    /*
     * Just copy the first 16 bytes of information to ISRC1
     */
    memcpy(isrc->isrc1.data,&isrcdata.upc_ean_isrc[0],16);
    /*
     * For the second 16 bytes we need to see if there is any non-zero data in
     * there. If not then the second ISRC packet will not be transmitted.
     */
    for(i=16;i<32;i++)
    {
      if(isrcdata.upc_ean_isrc[i] != 0)
      {
        isrc->isrc1.version |= HDMI_ISRC1_CONTINUED;
        isrc->isrc2.data[i-16] = isrcdata.upc_ean_isrc[i];
      }
    }
  }

  DPRINTK("Sending ISRC Datapackets\n");

  if(stm_display_output_queue_metadata(dev->hdmi_output, metadata, &res)<0)
  {
    kfree(metadata);
    if(signal_pending(current))
      return -ERESTARTSYS;
    else
      return -EIO;
  }

  return stmhdmi_convert_metadata_result_to_errno(res);
}
예제 #6
0
파일: hdmidev.c 프로젝트: Niptok/tdt-amiko
static int stmhdmi_send_data_packet(struct stm_hdmi *dev, unsigned long arg)
{
  stm_meta_data_result_t res;
  stm_meta_data_t *metadata;
  stm_hdmi_info_frame_t *iframe;
  struct stmhdmiio_data_packet packet;

  if (copy_from_user(&packet,(void*)arg,sizeof(packet)))
    return -EFAULT;

  if((metadata = kzalloc(sizeof(stm_meta_data_t)+sizeof(stm_hdmi_info_frame_t),GFP_KERNEL)) == 0)
    return -ENOMEM;

  metadata->size      = sizeof(stm_meta_data_t)+sizeof(stm_hdmi_info_frame_t);
  metadata->release   = (void(*)(struct stm_meta_data_s*))kfree;
  metadata->presentationTime = ((TIME64)packet.timestamp.tv_sec * USEC_PER_SEC) +
                                (TIME64)packet.timestamp.tv_usec;

  switch(packet.type)
  {
    case HDMI_ACP_PACKET_TYPE:
    {
      /*
       * Don't allow the configuration of ACP packets unless the
       * connected TV has the supports AI flag set in its EDID.
       */
      if((dev->edid_info.display_type != STM_DISPLAY_HDMI) ||
         (dev->edid_info.hdmi_vsdb_flags & STM_HDMI_VSDB_SUPPORTS_AI) == 0)
      {
        DPRINTK("Not Sending ACP Datapacket, sink does not support AI\n");
        kfree(metadata);
        return -EPERM;
      }

      DPRINTK("Sending ACP Datapacket\n");

      metadata->type = STM_METADATA_TYPE_ACP_DATA;
      break;
    }
    case HDMI_VENDOR_INFOFRAME_TYPE:
    {
      DPRINTK("Sending vendor IFrame\n");
      metadata->type = STM_METADATA_TYPE_VENDOR_IFRAME;
      break;
    }
    case HDMI_NTSC_INFOFRAME_TYPE:
    {
      DPRINTK("Sending NTSC IFrame\n");
      metadata->type = STM_METADATA_TYPE_NTSC_IFRAME;
      break;
    }
    case HDMI_GAMUT_DATA_PACKET_TYPE:
    {
      DPRINTK("Sending Color Gamut Datapacket\n");
      metadata->type = STM_METADATA_TYPE_COLOR_GAMUT_DATA;
      break;
    }
    default:
    {
      DPRINTK("Unsupported Datapacket\n");
      kfree(metadata);
      return -EINVAL;
    }
  }

  iframe = (stm_hdmi_info_frame_t*)&metadata->data[0];
  iframe->type    = packet.type;
  iframe->version = packet.version;
  iframe->length  = packet.length;
  /*
   * Note: we cannot use packet.length to size the memcpy as this is only
   * valid for real InfoFrames not arbitrary HDMI data island packets.
   */
  memcpy(&iframe->data[0],&packet.data[0],28);

  if(stm_display_output_queue_metadata(dev->hdmi_output, metadata, &res)<0)
  {
    kfree(metadata);
    if(signal_pending(current))
      return -ERESTARTSYS;
    else
      return -EIO;
  }

  return stmhdmi_convert_metadata_result_to_errno(res);
}