Exemplo n.º 1
0
zx_status_t QemuStream::DisableConverterLocked(bool force_all) {
    const CodecVerb DISABLE_CONVERTER_VERBS[] = {
        SET_AMPLIFIER_GAIN_MUTE(true, 0, is_input(), !is_input()),
        SET_CONVERTER_STREAM_CHAN(IHDA_INVALID_STREAM_TAG, 0),
    };

    return RunCmdListLocked(DISABLE_CONVERTER_VERBS, countof(DISABLE_CONVERTER_VERBS), force_all);
}
Exemplo n.º 2
0
zx_status_t QemuStream::FinishChangeStreamFormatLocked(uint16_t encoded_fmt) {
    const CodecVerb ENABLE_CONVERTER_VERBS[] = {
        SET_CONVERTER_FORMAT(encoded_fmt),
        SET_CONVERTER_STREAM_CHAN(dma_stream_tag(), 0),
        SET_AMPLIFIER_GAIN_MUTE(false, UNITY_GAIN, is_input(), !is_input()),
    };

    return RunCmdListLocked(ENABLE_CONVERTER_VERBS, countof(ENABLE_CONVERTER_VERBS));
}
Exemplo n.º 3
0
void QemuStream::OnGetStringLocked(const audio_proto::GetStringReq& req,
                                   audio_proto::GetStringResp* out_resp) {
    ZX_DEBUG_ASSERT(out_resp);
    const char* str = nullptr;

    switch (req.id) {
        case AUDIO_STREAM_STR_ID_MANUFACTURER:
            str = "QEMU";
            break;

        case AUDIO_STREAM_STR_ID_PRODUCT:
            str = is_input() ? "Builtin Microphone" : "Builtin Speakers";
            break;

        default:
            IntelHDAStreamBase::OnGetStringLocked(req, out_resp);
            return;
    }

    int res = snprintf(reinterpret_cast<char*>(out_resp->str), sizeof(out_resp->str), "%s",
                       str ? str : "<unassigned>");
    ZX_DEBUG_ASSERT(res >= 0);
    out_resp->result = ZX_OK;
    out_resp->strlen = fbl::min<uint32_t>(res, sizeof(out_resp->str) - 1);
    out_resp->id = req.id;
}
Exemplo n.º 4
0
bool TCPBuffer::_pending(void)
{
    if(input_pending())
        return true;

    if(is_input() && iowait && iowait != Timer::inf)
        return Socket::wait(so, iowait);

    return Socket::wait(so, 0);
}
Exemplo n.º 5
0
coeff_t multi_adag_node::compute_coeff() {
    if(is_input()) return c;
    ASSERT(scales.size() == src.size());
    ASSERT(src.size() >= 2);
    coeff_t res = compute_scale(src[0]->c, scales[0]);
    for(size_t i = 1; i < src.size(); ++i) {
	res = res + compute_scale(src[i]->c, scales[i]);
    }
    return res >> rsh;
}
Exemplo n.º 6
0
void multi_adag_node::output(ostream &os) {
    if(is_input()) os << "t" << reg << " = " << c << "\n";
    else {
	os << (is_target?"T":"t") << reg << " = multi_add(";
	for(size_t i=0; i<src.size(); ++i) {
	    os << "t" << src[i]->reg << "/" << scales[i];
	    if(i!=src.size()-1) os << ", ";
	}
	os << ") >>" << rsh << "\n";
    }
}
Exemplo n.º 7
0
/** \brief Convert this object to a std::string
 */
std::string	fdwatch_cond_t::to_string()	const throw()
{
	std::ostringstream      oss;
	oss << "[";
	if( is_input() )	oss << "(input)";
	if( is_output() )	oss << "(output)";
	if( is_error() )	oss << "(error)";
	oss << "]";
	// return the built string
	return oss.str();	
}
Exemplo n.º 8
0
void adag_node::output_dot(ostream &os) {
    if(is_input()) os << c << " [peripheries=2]\n";
    else {
	os << c << "[style=filled fillcolor=\"#" 
	   << (char)('a'+rand()%6) << (char)('a'+rand()%6) << (char)('a'+rand()%6) 
	   << (char)('a'+rand()%6) << (char)('a'+rand()%6) << (char)('a'+rand()%6) 
	   << "\"" << (is_target ? " peripheries=2]" : " peripheries=1]") << endl;
	for(size_t i=0; i<src.size(); ++i) {
          os << src[i]->c << "->" << c << " [weight=1 label=\"";
          if(scales[i] < 0) { os << "-"; if(scales[i]!=-1) os << " <<" << -scales[i]-1; }
          else              { os << "+"; if(scales[i]!=1)  os << " <<" << scales[i]-1; }
          os << "\"]" << endl;
	}
    }
}
Exemplo n.º 9
0
   nir_foreach_instr_safe(instr, block) {
      if (instr->type != nir_instr_type_intrinsic)
         continue;

      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);

      if ((mode == nir_var_shader_in && is_input(intrin)) ||
          (mode == nir_var_shader_out && is_output(intrin))) {
         nir_src *offset = nir_get_io_offset_src(intrin);
         nir_const_value *const_offset = nir_src_as_const_value(*offset);

         if (const_offset) {
            intrin->const_index[0] += const_offset->u32[0];
            b->cursor = nir_before_instr(&intrin->instr);
            nir_instr_rewrite_src(&intrin->instr, offset,
                                  nir_src_for_ssa(nir_imm_int(b, 0)));
         }
      }
   }
Exemplo n.º 10
0
static void
schedule(struct ir3_sched_ctx *ctx, struct ir3_instruction *instr)
{
	debug_assert(ctx->block == instr->block);

	/* maybe there is a better way to handle this than just stuffing
	 * a nop.. ideally we'd know about this constraint in the
	 * scheduling and depth calculation..
	 */
	if (ctx->scheduled && is_sfu_or_mem(ctx->scheduled) && is_sfu_or_mem(instr))
		ir3_NOP(ctx->block);

	/* remove from depth list:
	 */
	list_delinit(&instr->node);

	if (writes_addr(instr)) {
		debug_assert(ctx->addr == NULL);
		ctx->addr = instr;
	}

	if (writes_pred(instr)) {
		debug_assert(ctx->pred == NULL);
		ctx->pred = instr;
	}

	instr->flags |= IR3_INSTR_MARK;

	list_addtail(&instr->node, &instr->block->instr_list);
	ctx->scheduled = instr;

	if (writes_addr(instr) || writes_pred(instr) || is_input(instr)) {
		clear_cache(ctx, NULL);
	} else {
		/* invalidate only the necessary entries.. */
		clear_cache(ctx, instr);
	}
}
Exemplo n.º 11
0
zx_status_t IntelHDAStreamBase::PublishDeviceLocked() {
    if (!is_active() || (parent_device_ != nullptr)) return ZX_ERR_BAD_STATE;
    ZX_DEBUG_ASSERT(parent_codec_ != nullptr);

    // Initialize our device and fill out the protocol hooks
    device_add_args_t args = {};
    args.version = DEVICE_ADD_ARGS_VERSION;
    args.name = dev_name_;
    args.ctx = this;
    args.ops = &STREAM_DEVICE_THUNKS;
    args.proto_id = (is_input() ? ZX_PROTOCOL_AUDIO_INPUT : ZX_PROTOCOL_AUDIO_OUTPUT);

    // Publish the device.
    zx_status_t res = device_add(parent_codec_->codec_device(), &args, &stream_device_);
    if (res != ZX_OK) {
        LOG("Failed to add stream device for \"%s\" (res %d)\n", dev_name_, res);
        return res;
    }

    // Record our parent.
    parent_device_ = parent_codec_->codec_device();

    return ZX_OK;
}
Exemplo n.º 12
0
void pump()
{
	SDL_PumpEvents();

	pump_info info;

	//used to keep track of double click events
	static int last_mouse_down = -1;
	static int last_click_x = -1, last_click_y = -1;

	SDL_Event temp_event;
	int poll_count = 0;
	int begin_ignoring = 0;
	std::vector< SDL_Event > events;
	while(SDL_PollEvent(&temp_event)) {
		++poll_count;
		if(!begin_ignoring && temp_event.type == SDL_ACTIVEEVENT) {
			begin_ignoring = poll_count;
		} else if(begin_ignoring > 0 && is_input(temp_event)) {
			//ignore user input events that occurred after the window was activated
			continue;
		}
		events.push_back(temp_event);
	}
	std::vector<SDL_Event>::iterator ev_it = events.begin();
	for(int i=1; i < begin_ignoring; ++i){
		if(is_input(*ev_it)) {
			//ignore user input events that occurred before the window was activated
			ev_it = events.erase(ev_it);
		} else {
			++ev_it;
		}
	}
	std::vector<SDL_Event>::iterator ev_end = events.end();
	for(ev_it = events.begin(); ev_it != ev_end; ++ev_it){
		SDL_Event &event = *ev_it;
		switch(event.type) {

			case SDL_ACTIVEEVENT: {
				SDL_ActiveEvent& ae = reinterpret_cast<SDL_ActiveEvent&>(event);
				if((ae.state & SDL_APPMOUSEFOCUS) != 0 || (ae.state & SDL_APPINPUTFOCUS) != 0) {
					cursor::set_focus(ae.gain != 0);
				}
				break;
			}

			//if the window must be redrawn, update the entire screen
			case SDL_VIDEOEXPOSE: {
				update_whole_screen();
				break;
			}

			case SDL_VIDEORESIZE: {
				const SDL_ResizeEvent* const resize = reinterpret_cast<SDL_ResizeEvent*>(&event);
				info.resize_dimensions.first = resize->w;
				info.resize_dimensions.second = resize->h;
				break;
			}

			case SDL_MOUSEMOTION: {
				//always make sure a cursor is displayed if the
				//mouse moves or if the user clicks
				cursor::set_focus(true);
				raise_help_string_event(event.motion.x,event.motion.y);
				break;
			}

			case SDL_MOUSEBUTTONDOWN: {
				//always make sure a cursor is displayed if the
				//mouse moves or if the user clicks
				cursor::set_focus(true);
				if(event.button.button == SDL_BUTTON_LEFT) {
					static const int DoubleClickTime = 500;
					static const int DoubleClickMaxMove = 3;
					if(last_mouse_down >= 0 && info.ticks() - last_mouse_down < DoubleClickTime &&
					   abs(event.button.x - last_click_x) < DoubleClickMaxMove &&
					   abs(event.button.y - last_click_y) < DoubleClickMaxMove) {
						SDL_UserEvent user_event;
						user_event.type = DOUBLE_CLICK_EVENT;
						user_event.code = 0;
						user_event.data1 = reinterpret_cast<void*>(event.button.x);
						user_event.data2 = reinterpret_cast<void*>(event.button.y);
						::SDL_PushEvent(reinterpret_cast<SDL_Event*>(&user_event));
					}
					last_mouse_down = info.ticks();
					last_click_x = event.button.x;
					last_click_y = event.button.y;
				}
				break;
			}

#if defined(_X11) && !defined(__APPLE__)
			case SDL_SYSWMEVENT: {
				//clipboard support for X11
				handle_system_event(event);
				break;
			}
#endif

			case SDL_QUIT: {
				throw CVideo::quit();
			}
		}

		if(event_contexts.empty() == false) {

			const std::vector<handler*>& event_handlers = event_contexts.back().handlers;

			//events may cause more event handlers to be added and/or removed,
			//so we must use indexes instead of iterators here.
			for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
				event_handlers[i1]->handle_event(event);
			}
		}
	}

	//inform the pump monitors that an events::pump() has occurred
	for(size_t i1 = 0, i2 = pump_monitors.size(); i1 != i2 && i1 < pump_monitors.size(); ++i1) {
		pump_monitors[i1]->process(info);
	}
}
Exemplo n.º 13
0
void pump()
{
	if(boost::this_thread::get_id() != main_thread) {
		// Can only call this on the main thread!
		return;
	}
	SDL_PumpEvents();
	peek_for_resize();
	pump_info info;

	//used to keep track of double click events
	static int last_mouse_down = -1;
	static int last_click_x = -1, last_click_y = -1;

	SDL_Event temp_event;
	int poll_count = 0;
	int begin_ignoring = 0;
	std::vector< SDL_Event > events;
	while(SDL_PollEvent(&temp_event)) {
		++poll_count;
		peek_for_resize();

		if(!begin_ignoring && temp_event.type == SDL_WINDOWEVENT
				&& (temp_event.window.event == SDL_WINDOWEVENT_ENTER
						|| temp_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED))
		{
			begin_ignoring = poll_count;
		} else if(begin_ignoring > 0 && is_input(temp_event)) {
			//ignore user input events that occurred after the window was activated
			continue;
		}
		events.push_back(temp_event);
	}

	std::vector<SDL_Event>::iterator ev_it = events.begin();
	for(int i=1; i < begin_ignoring; ++i){
		if(is_input(*ev_it)) {
			//ignore user input events that occurred before the window was activated
			ev_it = events.erase(ev_it);
		} else {
			++ev_it;
		}
	}

	std::vector<SDL_Event>::iterator ev_end = events.end();
	bool resize_found = false;
	for(ev_it = events.begin(); ev_it != ev_end; ++ev_it){
		SDL_Event &event = *ev_it;
		if (event.type == SDL_WINDOWEVENT &&
				event.window.event == SDL_WINDOWEVENT_RESIZED) {
			resize_found = true;
			last_resize_event = event;
			last_resize_event_used = false;

		}
	}
	// remove all inputs, draw events and only keep the last of the resize events
	// This will turn horrible after ~38 days when the Uint32 wraps.
	if (resize_found || SDL_GetTicks() <= last_resize_event.window.timestamp + resize_timeout) {
		events.erase(std::remove_if(events.begin(), events.end(), remove_on_resize), events.end());
	} else if(SDL_GetTicks() > last_resize_event.window.timestamp + resize_timeout && !last_resize_event_used) {
		events.insert(events.begin(), last_resize_event);
		last_resize_event_used = true;
	}

	ev_end = events.end();

	for(ev_it = events.begin(); ev_it != ev_end; ++ev_it){
		for (context& c : event_contexts)
		{
			c.add_staging_handlers();
		}

		SDL_Event &event = *ev_it;
		switch(event.type) {

			case SDL_WINDOWEVENT:
				switch(event.window.event) {
					case SDL_WINDOWEVENT_ENTER:
					case SDL_WINDOWEVENT_FOCUS_GAINED:
						cursor::set_focus(1);
						break;

					case SDL_WINDOWEVENT_LEAVE:
					case SDL_WINDOWEVENT_FOCUS_LOST:
						cursor::set_focus(1);
						break;

					case SDL_WINDOWEVENT_RESIZED:
						info.resize_dimensions.first = event.window.data1;
						info.resize_dimensions.second = event.window.data2;
						break;
				}
				//make sure this runs in it's own scope.
				{
					flip_locker flip_lock(CVideo::get_singleton());
					for( std::deque<context>::iterator i = event_contexts.begin() ; i != event_contexts.end(); ++i) {
						const handler_list& event_handlers = (*i).handlers;
						for(auto handler : event_handlers) {
							handler->handle_window_event(event);
						}
					}
					const handler_list& event_handlers = event_contexts.front().handlers;
					for(auto handler : event_handlers) {
						handler->handle_window_event(event);
					}
				}

				//This event was just distributed, don't re-distribute.
				continue;

			case SDL_MOUSEMOTION: {
				//always make sure a cursor is displayed if the
				//mouse moves or if the user clicks
				cursor::set_focus(true);
				raise_help_string_event(event.motion.x,event.motion.y);
				break;
			}

			case SDL_MOUSEBUTTONDOWN: {
				//always make sure a cursor is displayed if the
				//mouse moves or if the user clicks
				cursor::set_focus(true);
				if(event.button.button == SDL_BUTTON_LEFT) {
					static const int DoubleClickTime = 500;
					static const int DoubleClickMaxMove = 3;
					if(last_mouse_down >= 0 && info.ticks() - last_mouse_down < DoubleClickTime &&
					   abs(event.button.x - last_click_x) < DoubleClickMaxMove &&
					   abs(event.button.y - last_click_y) < DoubleClickMaxMove) {
						SDL_UserEvent user_event;
						user_event.type = DOUBLE_CLICK_EVENT;
						user_event.code = 0;
						user_event.data1 = reinterpret_cast<void*>(event.button.x);
						user_event.data2 = reinterpret_cast<void*>(event.button.y);
						::SDL_PushEvent(reinterpret_cast<SDL_Event*>(&user_event));
					}
					last_mouse_down = info.ticks();
					last_click_x = event.button.x;
					last_click_y = event.button.y;
				}
				break;
			}
			case DRAW_ALL_EVENT:
			{
				flip_locker flip_lock(CVideo::get_singleton());
				/* iterate backwards as the most recent things will be at the top */
				for( std::deque<context>::iterator i = event_contexts.begin() ; i != event_contexts.end(); ++i) {
					handler_list& event_handlers = (*i).handlers;
					for( handler_list::iterator i1 = event_handlers.begin(); i1 != event_handlers.end(); ++i1) {
						(*i1)->handle_event(event);
					}
				}
				continue; //do not do further handling here
			}

#ifndef __APPLE__
			case SDL_KEYDOWN: {
				if(event.key.keysym.sym == SDLK_F4 && (event.key.keysym.mod == KMOD_RALT || event.key.keysym.mod == KMOD_LALT)) {
					quit_confirmation::quit_to_desktop();
					continue; // this event is already handled
				}
				break;
			}
#endif

#if defined(_X11) && !defined(__APPLE__)
			case SDL_SYSWMEVENT: {
				//clipboard support for X11
				desktop::clipboard::handle_system_event(event);
				break;
			}
#endif

#if defined _WIN32
			case SDL_SYSWMEVENT: {
				windows_tray_notification::handle_system_event(event);
				break;
			}
#endif

			case SDL_QUIT: {
				quit_confirmation::quit_to_desktop();
				continue; //this event is already handled.
			}
		}

		const handler_list& global_handlers = event_contexts.front().handlers;
		for(auto handler : global_handlers) {
			handler->handle_event(event);
		}

		if(event_contexts.empty() == false) {

			const handler_list& event_handlers = event_contexts.back().handlers;

			for(auto handler : event_handlers) {
				handler->handle_event(event);
			}
		}

	}

	//inform the pump monitors that an events::pump() has occurred
	for(size_t i1 = 0, i2 = pump_monitors.size(); i1 != i2 && i1 < pump_monitors.size(); ++i1) {
		pump_monitors[i1]->process(info);
	}
}
Exemplo n.º 14
0
  DatabaseIO::DatabaseIO(Region *region, std::string filename, DatabaseUsage db_usage,
                         MPI_Comm communicator, const PropertyManager &props)
      : properties(props), commonSideTopology(nullptr), DBFilename(std::move(filename)),
        dbState(STATE_INVALID), isParallel(false), myProcessor(0),
        cycleCount(0), overlayCount(0), timeScaleFactor(1.0), splitType(SPLIT_BY_TOPOLOGIES),
        dbUsage(db_usage), dbIntSizeAPI(USE_INT32_API), lowerCaseVariableNames(true),
        util_(communicator), region_(region), isInput(is_input_event(db_usage)),
        isParallelConsistent(true),
        singleProcOnly(db_usage == WRITE_HISTORY || db_usage == WRITE_HEARTBEAT ||
                       SerializeIO::isEnabled()),
        doLogging(false), useGenericCanonicalName(false)
  {
    isParallel  = util_.parallel_size() > 1;
    myProcessor = util_.parallel_rank();

    // Check environment variable IOSS_PROPERTIES. If it exists, parse
    // the contents and add to the 'properties' map.

    std::string env_props;
    if (util_.get_environment("IOSS_PROPERTIES", env_props, isParallel)) {
      // env_props string should be of the form
      // "PROP1=VALUE1:PROP2=VALUE2:..."
      std::vector<std::string> prop_val = tokenize(env_props, ":");

      for (auto &elem : prop_val) {
        std::vector<std::string> property = tokenize(elem, "=");
        if (property.size() != 2) {
          std::ostringstream errmsg;
          errmsg << "ERROR: Invalid property specification found in "
                    "IOSS_PROPERTIES environment variable\n"
                 << "       Found '" << elem << "' which is not of the correct PROPERTY=VALUE form";
          IOSS_ERROR(errmsg);
        }
        std::string prop      = Utils::uppercase(property[0]);
        std::string value     = property[1];
        std::string up_value  = Utils::uppercase(value);
        bool        all_digit = value.find_first_not_of("0123456789") == std::string::npos;

        if (myProcessor == 0) {
          std::cerr << "IOSS: Adding property '" << prop << "' with value '" << value << "'\n";
        }
        if (all_digit) {
          int int_value = std::strtol(value.c_str(), nullptr, 10);
          properties.add(Property(prop, int_value));
        }
        else if (up_value == "TRUE" || up_value == "YES") {
          properties.add(Property(prop, 1));
        }
        else if (up_value == "FALSE" || up_value == "NO") {
          properties.add(Property(prop, 0));
        }
        else {
          properties.add(Property(prop, value));
        }
      }
    }

    if (properties.exists("INTEGER_SIZE_API")) {
      int isize = properties.get("INTEGER_SIZE_API").get_int();
      if (isize == 8) {
        set_int_byte_size_api(Ioss::USE_INT64_API);
      }
    }

    {
      bool logging;
      if (Utils::check_set_bool_property(properties, "LOGGING", logging)) {
        set_logging(logging);
      }
    }

    Utils::check_set_bool_property(properties, "LOWER_CASE_VARIABLE_NAMES", lowerCaseVariableNames);
    Utils::check_set_bool_property(properties, "USE_GENERIC_CANONICAL_NAMES",
                                   useGenericCanonicalName);

    {
      bool consistent;
      if (Utils::check_set_bool_property(properties, "PARALLEL_CONSISTENCY", consistent)) {
        set_parallel_consistency(consistent);
      }
    }

    if (!is_input()) {
      // Create full path to the output file at this point if it doesn't
      // exist...
      create_path(DBFilename);
    }
  }
Exemplo n.º 15
0
 inline bool is_output(Port *port) {return !is_input(port);}
Exemplo n.º 16
0
coeff_t binary_adag_node::compute_coeff() { 
    if(is_input()) return c;
    else return 
     (compute_scale(src[0]->c, scales[0]) + compute_scale(src[1]->c, scales[1]))
	 >> rsh;
}
Exemplo n.º 17
0
void list_subdevice_info(snd_ctl_t *ctl, int card, int device) {
    snd_rawmidi_info_t *info;
    const char *name;
    const char *sub_name;
    int subs, subs_in, subs_out;
    int sub, in, out;
    int status;

    snd_rawmidi_info_alloca(&info);
    snd_rawmidi_info_set_device(info, device);

    snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
    snd_ctl_rawmidi_info(ctl, info);
    subs_in = snd_rawmidi_info_get_subdevices_count(info);
    snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
    snd_ctl_rawmidi_info(ctl, info);
    subs_out = snd_rawmidi_info_get_subdevices_count(info);
    subs = subs_in > subs_out ? subs_in : subs_out;

    sub = 0;
    in = out = 0;
    if ((status = is_output(ctl, card, device, sub)) < 0) {
        error("cannot get rawmidi information %d:%d: %s",
              card, device, snd_strerror(status));
        return;
    } else if (status)
        out = 1;

    if (status == 0) {
        if ((status = is_input(ctl, card, device, sub)) < 0) {
            error("cannot get rawmidi information %d:%d: %s",
                  card, device, snd_strerror(status));
            return;
        }
    } else if (status)
        in = 1;

    if (status == 0)
        return;

    name = snd_rawmidi_info_get_name(info);
    sub_name = snd_rawmidi_info_get_subdevice_name(info);
    if (sub_name[0] == '\0') {
        if (subs == 1) {
            printf("%c%c  hw:%d,%d    %s\n",
                   in  ? 'I' : ' ',
                   out ? 'O' : ' ',
                   card, device, name);
        } else
            printf("%c%c  hw:%d,%d    %s (%d subdevices)\n",
                   in  ? 'I' : ' ',
                   out ? 'O' : ' ',
                   card, device, name, subs);
    } else {
        sub = 0;
        for (;;) {
            printf("%c%c  hw:%d,%d,%d  %s\n",
                   in ? 'I' : ' ', out ? 'O' : ' ',
                   card, device, sub, sub_name);
            if (++sub >= subs)
                break;

            in = is_input(ctl, card, device, sub);
            out = is_output(ctl, card, device, sub);
            snd_rawmidi_info_set_subdevice(info, sub);
            if (out) {
                snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
                if ((status = snd_ctl_rawmidi_info(ctl, info)) < 0) {
                    error("cannot get rawmidi information %d:%d:%d: %s",
                          card, device, sub, snd_strerror(status));
                    break;
                }
            } else {
                snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
                if ((status = snd_ctl_rawmidi_info(ctl, info)) < 0) {
                    error("cannot get rawmidi information %d:%d:%d: %s",
                          card, device, sub, snd_strerror(status));
                    break;
                }
            }
            sub_name = snd_rawmidi_info_get_subdevice_name(info);
        }
    }
}