Esempio n. 1
0
void IntelHDAStreamBase::Deactivate() {
    {
        fbl::AutoLock obj_lock(&obj_lock_);
        DEBUG_LOG("Deactivating stream\n");

        // Let go of any unsolicited stream tags we may be holding.
        if (unsol_tag_count_) {
            ZX_DEBUG_ASSERT(parent_codec_ != nullptr);
            parent_codec_->ReleaseAllUnsolTags(*this);
            unsol_tag_count_ = 0;
        }

        // Clear out our parent_codec_ pointer.  This will mark us as being
        // inactive and prevent any new connections from being made.
        parent_codec_.reset();

        // We should already have been removed from our codec's active stream list
        // at this point.
        ZX_DEBUG_ASSERT(!this->InContainer());
    }

    default_domain_->Deactivate();

    {
        fbl::AutoLock obj_lock(&obj_lock_);
        ZX_DEBUG_ASSERT(stream_channel_ == nullptr);

        // Allow our implementation to send the commands needed to tear down the
        // widgets which make up this stream.
        OnDeactivateLocked();

        // If we have been given a DMA stream by the IHDA controller, attempt to
        // return it now.
        if ((dma_stream_id_ != IHDA_INVALID_STREAM_ID) && (codec_channel_ != nullptr)) {
            ihda_proto::ReleaseStreamReq req;

            req.hdr.transaction_id = id();
            req.hdr.cmd = IHDA_CODEC_RELEASE_STREAM_NOACK,
            req.stream_id = dma_stream_id_;

            codec_channel_->Write(&req, sizeof(req));

            dma_stream_id_  = IHDA_INVALID_STREAM_ID;
            dma_stream_tag_ = IHDA_INVALID_STREAM_TAG;
        }

        // Let go of our reference to the codec device channel.
        codec_channel_ = nullptr;

        // If we had published a device node, remove it now.
        if (parent_device_ != nullptr) {
            device_remove(stream_device_);
            parent_device_ = nullptr;
        }
    }

    DEBUG_LOG("Deactivate complete\n");
}
Esempio n. 2
0
static void *threadFunc2(void *arg)
{
	int ret;
	ret = obj_lock(&obj);
	sleep(1);
	printf("obj.a = %d\n", obj.a);
	printf("obj.b = %d\n", obj.b);
	ret = obj_unlock(&obj);
	return NULL;
}
Esempio n. 3
0
static void *threadFunc1(void *arg)
{
	int ret;
	ret = obj_lock(&obj);
	obj.a = 10;
	sleep(2);
	obj.b = 20;
	ret = obj_unlock(&obj);
	return NULL;
}
Esempio n. 4
0
zx_status_t IntelHDAStreamBase::ProcessResponse(const CodecResponse& resp) {
    fbl::AutoLock obj_lock(&obj_lock_);

    if (!is_active()) {
        DEBUG_LOG("Ignoring codec response (0x%08x, 0x%08x) for inactive stream id %u\n",
                resp.data, resp.data_ex, id());
        return ZX_OK;
    }

    return resp.unsolicited()
        ? OnUnsolicitedResponseLocked(resp)
        : OnSolicitedResponseLocked(resp);
}
Esempio n. 5
0
void IntelHDAStreamBase::ProcessClientDeactivate(const dispatcher::Channel* channel,
                                                 bool privileged) {
    ZX_DEBUG_ASSERT(channel != nullptr);
    fbl::AutoLock obj_lock(&obj_lock_);

    // Let our subclass know that this channel is going away.
    OnChannelDeactivateLocked(*channel);

    // Is this the privileged stream channel?
    if (privileged) {
        ZX_DEBUG_ASSERT(channel == stream_channel_.get());
        stream_channel_.reset();
    }
}
Esempio n. 6
0
zx_status_t IntelHDAStreamBase::ProcessClientRequest(dispatcher::Channel* channel,
                                                     bool privileged) {
    ZX_DEBUG_ASSERT(channel != nullptr);
    fbl::AutoLock obj_lock(&obj_lock_);

    // If we have lost our connection to the codec device, or are in the process
    // of shutting down, there is nothing further we can do.  Fail the request
    // and close the connection to the caller.
    if (!is_active() || (codec_channel_ == nullptr))
        return ZX_ERR_BAD_STATE;

    union {
        audio_proto::CmdHdr           hdr;
        audio_proto::StreamGetFmtsReq get_formats;
        audio_proto::StreamSetFmtReq  set_format;
        audio_proto::GetGainReq       get_gain;
        audio_proto::SetGainReq       set_gain;
        audio_proto::PlugDetectReq    plug_detect;
        audio_proto::GetUniqueIdReq   get_unique_id;
        audio_proto::GetStringReq     get_string;
        // TODO(johngro) : add more commands here
    } req;

    static_assert(sizeof(req) <= 256,
                  "Request buffer is getting to be too large to hold on the stack!");

    uint32_t req_size;
    zx_status_t res = channel->Read(&req, sizeof(req), &req_size);
    if (res != ZX_OK)
        return res;

    if ((req_size < sizeof(req.hdr) ||
        (req.hdr.transaction_id == AUDIO_INVALID_TRANSACTION_ID)))
        return ZX_ERR_INVALID_ARGS;

    // Strip the NO_ACK flag from the request before selecting the dispatch target.
    auto cmd = static_cast<audio_proto::Cmd>(req.hdr.cmd & ~AUDIO_FLAG_NO_ACK);
    switch (cmd) {
        HANDLE_REQ(AUDIO_STREAM_CMD_GET_FORMATS,   get_formats,   DoGetStreamFormatsLocked, false);
        HANDLE_REQ(AUDIO_STREAM_CMD_SET_FORMAT,    set_format,    DoSetStreamFormatLocked,  false);
        HANDLE_REQ(AUDIO_STREAM_CMD_GET_GAIN,      get_gain,      DoGetGainLocked,          false);
        HANDLE_REQ(AUDIO_STREAM_CMD_SET_GAIN,      set_gain,      DoSetGainLocked,          true);
        HANDLE_REQ(AUDIO_STREAM_CMD_PLUG_DETECT,   plug_detect,   DoPlugDetectLocked,       true);
        HANDLE_REQ(AUDIO_STREAM_CMD_GET_UNIQUE_ID, get_unique_id, DoGetUniqueIdLocked,      false);
        HANDLE_REQ(AUDIO_STREAM_CMD_GET_STRING,    get_string,    DoGetStringLocked,        false);
        default:
            DEBUG_LOG("Unrecognized stream command 0x%04x\n", req.hdr.cmd);
            return ZX_ERR_NOT_SUPPORTED;
    }
}
Esempio n. 7
0
zx_status_t IntelHDAStreamBase::ProcessSetStreamFmt(const ihda_proto::SetStreamFmtResp& codec_resp,
                                                    zx::channel&& ring_buffer_channel) {
    ZX_DEBUG_ASSERT(ring_buffer_channel.is_valid());

    fbl::AutoLock obj_lock(&obj_lock_);
    audio_proto::StreamSetFmtResp resp = { };
    zx_status_t res = ZX_OK;

    // Are we shutting down?
    if (!is_active()) return ZX_ERR_BAD_STATE;

    // If we don't have a set format operation in flight, or the stream channel
    // has been closed, this set format operation has been canceled.  Do not
    // return an error up the stack; we don't want to close the connection to
    // our codec device.
    if ((set_format_tid_ == AUDIO_INVALID_TRANSACTION_ID) ||
        (stream_channel_ == nullptr))
        goto finished;

    // Let the implementation send the commands required to finish changing the
    // stream format.
    res = FinishChangeStreamFormatLocked(encoded_fmt_);
    if (res != ZX_OK) {
        DEBUG_LOG("Failed to finish set format (enc fmt 0x%04hx res %d)\n", encoded_fmt_, res);
        goto finished;
    }

    // Respond to the caller, transferring the DMA handle back in the process.
    resp.hdr.cmd = AUDIO_STREAM_CMD_SET_FORMAT;
    resp.hdr.transaction_id = set_format_tid_;
    resp.result = ZX_OK;
    resp.external_delay_nsec = 0;   // report his properly based on the codec path delay.
    res = stream_channel_->Write(&resp, sizeof(resp), std::move(ring_buffer_channel));

finished:
    // Something went fatally wrong when trying to send the result back to the
    // caller.  Close the stream channel.
    if ((res != ZX_OK) && (stream_channel_ != nullptr)) {
        OnChannelDeactivateLocked(*stream_channel_);
        stream_channel_->Deactivate();
        stream_channel_ = nullptr;
    }

    // One way or the other, this set format operation is finished.  Clear out
    // the in-flight transaction ID
    set_format_tid_ = AUDIO_INVALID_TRANSACTION_ID;

    return ZX_OK;
}
Esempio n. 8
0
void objdict_clean(objdict_t *dict)
{
  int i;
  void *obj;
  for (i=0;i<dict->len;i++)
    {
      obj = obj_lock(dict->def[i].value,NULL);
      if (obj)
	obj_unlock(obj);
      else
	dict->def[i].value = 0;
      if (!dict->def[i].value)
	{
	  free(dict->def[i].name);
	  if (dict->len > i + 1)
	    dict->def[i] = dict->def[dict->len - 1];
	  dict->len--;
	  i--;
	}
    }
}
Esempio n. 9
0
static int tags_shell_fun(int argc, const char *argv[])
{
    if (argc > 0)
    {
        shell_print("Usage: tags\n");
        shell_print("List currently defined tags and sprite types\n");
    }
    else
    {
        int i;
        shell_print("Currently defined sprite tags:\n");
        for (i=0; i<sprite_tags->len; i++)
        {
            sprite_t *s = obj_lock(sprite_tags->def[i].value,&sprite_type);
            if (s)
            {
                shell_print("%s\t (%s)\n",sprite_tags->def[i].name,obj_type(s)->name);
                obj_unlock(s);
            }
        }
    }
    return 0;
}
Esempio n. 10
0
zx_status_t IntelHDAStreamBase::ProcessRequestStream(const ihda_proto::RequestStreamResp& resp) {
    fbl::AutoLock obj_lock(&obj_lock_);
    zx_status_t res;

    if (!is_active()) return ZX_ERR_BAD_STATE;

    res = SetDMAStreamLocked(resp.stream_id, resp.stream_tag);
    if (res != ZX_OK) {
        // TODO(johngro) : If we failed to set the DMA info because this stream
        // is in the process of shutting down, we really should return the
        // stream to the controller.
        //
        // Right now, we are going to return an error which will cause the lower
        // level infrastructure to close the codec device channel.  This will
        // prevent a leak (the core controller driver will re-claim the stream),
        // but it will also ruin all of the other streams in this codec are
        // going to end up being destroyed.  For simple codec driver who never
        // change stream topology, this is probably fine, but for more
        // complicated ones it probably is not.
        return res;
    }

    return OnDMAAssignedLocked();
}
Esempio n. 11
0
zx_status_t IntelHDAStreamBase::DeviceIoctl(uint32_t op,
                                            const void* in_buf,
                                            size_t in_len,
                                            void* out_buf,
                                            size_t out_len,
                                            size_t* out_actual) {
    // The only IOCTL we support is get channel.
    if (op != AUDIO_IOCTL_GET_CHANNEL) {
        return ZX_ERR_NOT_SUPPORTED;
    }
    if ((out_buf == nullptr) ||
        (out_actual == nullptr) ||
        (out_len != sizeof(zx_handle_t))) {
        return ZX_ERR_INVALID_ARGS;
    }

    fbl::AutoLock obj_lock(&obj_lock_);

    // Do not allow any new connections if we are in the process of shutting down
    if (!is_active())
        return ZX_ERR_BAD_STATE;

    // For now, block new connections if we currently have no privileged
    // connection, but there is a SetFormat request in flight to the codec
    // driver.  We are trying to avoid the following sequence...
    //
    // 1) A privileged connection starts a set format.
    // 2) After we ask the controller to set the format, our privileged channel
    //    is closed.
    // 3) A new user connects.
    // 4) The response to the first client's request arrives and gets sent
    //    to the second client.
    // 5) Confusion ensues.
    //
    // Denying new connections while the old request is in flight avoids this,
    // but is generally a terrible solution.  What we should really do is tag
    // the requests to the codec driver with a unique ID which we can use to
    // filter responses.  One option might be to split the transaction ID so
    // that a portion of the TID is used for stream routing, while another
    // portion is used for requests like this.
    bool privileged = (stream_channel_ == nullptr);
    if (privileged && (set_format_tid_ != AUDIO_INVALID_TRANSACTION_ID))
        return ZX_ERR_SHOULD_WAIT;

    // Attempt to allocate a new driver channel and bind it to us.  If we don't
    // already have a stream_channel_, flag this channel is the privileged
    // connection (The connection which is allowed to do things like change
    // formats).
    auto channel = dispatcher::Channel::Create();
    if (channel == nullptr)
        return ZX_ERR_NO_MEMORY;

    dispatcher::Channel::ProcessHandler phandler(
    [stream = fbl::WrapRefPtr(this), privileged](dispatcher::Channel* channel) -> zx_status_t {
        OBTAIN_EXECUTION_DOMAIN_TOKEN(t, stream->default_domain_);
        return stream->ProcessClientRequest(channel, privileged);
    });

    dispatcher::Channel::ChannelClosedHandler chandler(
    [stream = fbl::WrapRefPtr(this), privileged](const dispatcher::Channel* channel) -> void {
        OBTAIN_EXECUTION_DOMAIN_TOKEN(t, stream->default_domain_);
        stream->ProcessClientDeactivate(channel, privileged);
    });

    zx::channel client_endpoint;
    zx_status_t res = channel->Activate(&client_endpoint,
                                        default_domain_,
                                        std::move(phandler),
                                        std::move(chandler));
    if (res == ZX_OK) {
        if (privileged) {
            ZX_DEBUG_ASSERT(stream_channel_ == nullptr);
            stream_channel_ = channel;
        }

        *(reinterpret_cast<zx_handle_t*>(out_buf)) = client_endpoint.release();
        *out_actual = sizeof(zx_handle_t);
    }

    return res;
}