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"); }
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; }
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; }
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); }
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(); } }
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; } }
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; }
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--; } } }
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; }
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(); }
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; }