1 // license:BSD-3-Clause
2 // copyright-holders:Miodrag Milanovic
3 #pragma once
4 
5 #ifndef __EMU_H__
6 #error Dont include this file directly; include emu.h instead.
7 #endif
8 
9 #ifndef MAME_EMU_DISLOT_H
10 #define MAME_EMU_DISLOT_H
11 
12 //**************************************************************************
13 //  TYPE DEFINITIONS
14 //**************************************************************************
15 
16 class get_default_card_software_hook
17 {
18 	// goofy "hook" to pass to device_slot_interface::get_default_card_software
19 public:
20 	get_default_card_software_hook(const std::string &path, std::function<bool(util::core_file &, std::string&)> &&get_hashfile_extrainfo);
21 
22 	// accesses the image file to be scrutinized by get_default_card_software(); is
23 	// nullptr in the case of images loaded by software list
image_file()24 	util::core_file::ptr &image_file() { return m_image_file;  }
25 
26 	// checks to see if image is of the specified "file type" (in practice, file extension)
is_filetype(const char * candidate_filetype)27 	bool is_filetype(const char *candidate_filetype) const { return !core_stricmp(m_file_type.c_str(), candidate_filetype); }
28 
29 	// extra info from hashfile
30 	bool hashfile_extrainfo(std::string &extrainfo);
31 
32 private:
33 	util::core_file::ptr                                    m_image_file;
34 	std::string                                             m_file_type;
35 	std::function<bool(util::core_file &, std::string&)>    m_get_hashfile_extrainfo;
36 	bool                                                    m_called_get_hashfile_extrainfo;
37 	bool                                                    m_has_hash_extrainfo;
38 	std::string                                             m_hash_extrainfo;
39 };
40 
41 
42 /// \brief Base class for configurable slot devices
43 class device_slot_interface : public device_interface
44 {
45 public:
46 	class slot_option
47 	{
48 	public:
49 		slot_option(char const *name, device_type const &devtype, bool selectable);
50 
name()51 		char const *name() const { return m_name; }
devtype()52 		device_type const &devtype() const { return m_devtype; }
selectable()53 		bool selectable() const { return m_selectable; }
default_bios()54 		char const *default_bios() const { return m_default_bios; }
machine_config()55 		std::function<void (device_t *)> const &machine_config() const { return m_machine_config; }
input_device_defaults()56 		input_device_default const *input_device_defaults() const { return m_input_device_defaults; }
clock()57 		u32 clock() const { return m_clock; }
58 
default_bios(char const * default_bios)59 		slot_option &default_bios(char const *default_bios) { m_default_bios = default_bios; return *this; }
machine_config(Object && cb)60 		template <typename Object> slot_option &machine_config(Object &&cb) { m_machine_config = std::forward<Object>(cb); return *this; }
input_device_defaults(input_device_default const * dev_inp_def)61 		slot_option &input_device_defaults(input_device_default const *dev_inp_def) { m_input_device_defaults = dev_inp_def; return *this; }
clock(u32 clock)62 		slot_option &clock(u32 clock) { m_clock = clock; return *this; }
clock(XTAL clock)63 		slot_option &clock(XTAL clock) { clock.validate(std::string("Configuring slot option ") + m_name); m_clock = clock.value(); return *this; }
64 
65 	private:
66 		// internal state
67 		char const *const m_name;
68 		device_type const m_devtype;
69 		bool const m_selectable;
70 		char const *m_default_bios;
71 		std::function<void (device_t *)> m_machine_config;
72 		input_device_default const *m_input_device_defaults;
73 		u32 m_clock;
74 	};
75 
76 	virtual ~device_slot_interface();
77 
78 	/// \brief Set whether slot is fixed
79 	///
80 	/// Allows a slot to be configured as fixed.  Fixed slots can only
81 	/// be configured programmatically.  Options for fixed slots are not
82 	/// user-selectable.  By default, slots are not fixed.
83 	/// \param [in] fixed True to mark the slot as fixed, or false to
84 	///   mark it user-configurable.
85 	/// \sa fixed
set_fixed(bool fixed)86 	void set_fixed(bool fixed) { m_fixed = fixed; }
87 
88 	/// \brief Set the default option
89 	///
90 	/// Set the default option the slot.  The corresponding card device
91 	/// will be loaded if no other option is selected by the user or
92 	/// programmatically.
93 	/// \param [in] option The name of the default option.  This must be
94 	///   correspond to an option added using #option_add or
95 	///   #option_add_internal, or be nullptr to not load any card
96 	///   device by default.  The string is not copied and must remain
97 	///   valid for the lifetime of the device (or until another default
98 	///   option is configured).
99 	/// \sa default_option
set_default_option(const char * option)100 	void set_default_option(const char *option) { m_default_option = option; }
101 
102 	/// \brief Clear options
103 	///
104 	/// This removes all previously added options.
option_reset()105 	void option_reset() { m_options.clear(); }
106 
107 	/// \brief Add a user-selectable option
108 	///
109 	/// Adds an option that may be selected by the user via the command
110 	/// line or other configureation methods.
111 	/// \param [in] option The name used to select the option.  This
112 	///   will also be used as the tag when instantiating the card.  It
113 	///   must be a valid device tag, and should be terse but
114 	///   descriptive.  The string is copied when the option is added.
115 	/// \param [in] devtype Device type of the option.  The device type
116 	///   description is used in the user interface.
117 	/// \return A reference to the added option for additional
118 	///   configuration.
119 	slot_option &option_add(char const *option, const device_type &devtype);
120 
121 	/// \brief Add an internal option
122 	///
123 	/// Adds an option that may only be selected programmatically.  This
124 	/// is most often used for options used for loading software.
125 	/// \param [in] option The name used to select the option.  This
126 	///   will also be used as the tag when instantiating the card.  It
127 	///   must be a valid device tag.  The string is copied when the
128 	///   option is added.
129 	/// \param [in] devtype Device type of the option.  The device type
130 	///   description is used in the user interface.
131 	/// \return A reference to the added option for additional
132 	///   configuration.
133 	slot_option &option_add_internal(const char *option, const device_type &devtype);
134 
set_option_default_bios(const char * option,const char * default_bios)135 	void set_option_default_bios(const char *option, const char *default_bios) { config_option(option)->default_bios(default_bios); }
set_option_machine_config(const char * option,T && machine_config)136 	template <typename T> void set_option_machine_config(const char *option, T &&machine_config) { config_option(option)->machine_config(std::forward<T>(machine_config)); }
set_option_device_input_defaults(const char * option,const input_device_default * default_input)137 	void set_option_device_input_defaults(const char *option, const input_device_default *default_input) { config_option(option)->input_device_defaults(default_input); }
138 
139 	/// \brief Returns whether the slot is fixed
140 	///
141 	/// Fixed slots can only be configured programmatically.  Slots are
142 	/// not fixed by default.
143 	/// \return True if the slot is fixed, or false if it is
144 	///   user-configurable.
145 	/// \sa set_fixed
fixed()146 	bool fixed() const { return m_fixed; }
147 
148 	/// \brief Returns true if the slot has user-selectable options
149 	///
150 	/// Returns true if the slot is not marked as fixed and has at least
151 	/// one user-selectable option (added using #option_add rather than
152 	/// #option_add_internal).  Returns false if the slot is marked as
153 	/// fixed, all options are internal, or there are no options.
154 	/// \return True if the slot has user-selectable options, or false
155 	///   otherwise.
156 	bool has_selectable_options() const;
157 
default_option()158 	const char *default_option() const { return m_default_option; }
option_list()159 	const std::unordered_map<std::string, std::unique_ptr<slot_option>> &option_list() const { return m_options; }
160 	const slot_option *option(const char *name) const;
get_default_card_software(get_default_card_software_hook & hook)161 	virtual std::string get_default_card_software(get_default_card_software_hook &hook) const { return std::string(); }
get_card_device()162 	device_t *get_card_device() const { return m_card_device; }
set_card_device(device_t * dev)163 	void set_card_device(device_t *dev) { m_card_device = dev; }
slot_name()164 	const char *slot_name() const { return device().tag() + 1; }
option_set(const char * tag,const device_type & devtype)165 	slot_option &option_set(const char *tag, const device_type &devtype) { m_default_option = tag; m_fixed = true; return option_add_internal(tag, devtype); }
166 
167 protected:
168 	device_slot_interface(machine_config const &mconfig, device_t &device);
169 	virtual void interface_validity_check(validity_checker &valid) const override ATTR_COLD;
set_default_clock(u32 clock)170 	void set_default_clock(u32 clock) { m_default_clock = clock; }
171 
172 private:
173 	// internal state
174 	std::unordered_map<std::string, std::unique_ptr<slot_option>> m_options;
175 	u32 m_default_clock;
176 	char const *m_default_option;
177 	bool m_fixed;
178 	device_t *m_card_device;
179 
180 	slot_option *config_option(char const *option);
181 };
182 
183 
184 /// \brief Base class for slots that accept a single card interface
185 ///
186 /// Performs basic validity checks to ensure the configured card (if
187 /// any) implements the required interface.
188 template <typename Card>
189 class device_single_card_slot_interface : public device_slot_interface
190 {
191 public:
get_card_device()192 	Card *get_card_device() const { return dynamic_cast<Card *>(device_slot_interface::get_card_device()); }
193 
194 protected:
device_single_card_slot_interface(machine_config const & mconfig,device_t & device)195 	device_single_card_slot_interface(machine_config const &mconfig, device_t &device) :
196 		device_slot_interface(mconfig, device)
197 	{
198 	}
199 
interface_validity_check(validity_checker & valid)200 	virtual void interface_validity_check(validity_checker &valid) const override ATTR_COLD
201 	{
202 		device_slot_interface::interface_validity_check(valid);
203 		device_t *const card(device_slot_interface::get_card_device());
204 		if (card && !dynamic_cast<Card *>(card))
205 		{
206 			osd_printf_error(
207 					"Card device %s (%s) does not implement %s\n",
208 					card->tag(),
209 					card->name(),
210 					typeid(Card).name());
211 		}
212 	}
213 
interface_pre_start()214 	virtual void interface_pre_start() override ATTR_COLD
215 	{
216 		device_slot_interface::interface_pre_start();
217 		device_t *const card(device_slot_interface::get_card_device());
218 		if (card && !dynamic_cast<Card *>(card))
219 		{
220 			throw emu_fatalerror(
221 					"slot '%s' card device %s (%s) does not implement %s\n",
222 					device().tag(),
223 					card->tag(),
224 					card->name(),
225 					typeid(Card).name());
226 		}
227 	}
228 };
229 
230 typedef device_interface_iterator<device_slot_interface> slot_interface_iterator;
231 
232 #endif // MAME_EMU_DISLOT_H
233