xref: /haiku/src/add-ons/kernel/busses/scsi/usb/settings.c (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /**
2  *
3  * TODO: description
4  *
5  * This file is a part of USB SCSI CAM for Haiku OS.
6  * May be used under terms of the MIT License
7  *
8  * Author(s):
9  * 	Siarzhuk Zharski <imker@gmx.li>
10  *
11  *
12  */
13 /** driver settings support implementation */
14 
15 #include "usb_scsi.h"
16 #include "settings.h"
17 //#include "proto_common.h"
18 
19 #include <stdlib.h>	/* strtoul */
20 #include <strings.h> /* strncpy */
21 #include <driver_settings.h>
22 #include "tracing.h"
23 
24 #define DEF_DEVS	2	/**< default amount of reserved devices */
25 #define S_DEF_DEVS	"2" /**< default amount of reserved devices */
26 #define DEF_LUNS	4	/**< default amount of reserved LUNs */
27 #define S_DEF_LUNS	"4" /**< default amount of reserved LUNs */
28 /** count of device entries, to be reserved for fake devices */
29 int reserved_devices	= DEF_DEVS;
30 /** count of Logical Unit Numbers, to be reserved for fake devices */
31 int reserved_luns		= DEF_LUNS;
32 
33 bool b_reservation_on  = true;
34 bool b_ignore_sysinit2 = false;
35 /**
36 	support of some kind rudimentary "quick" search. Indexes in
37 	settings_keys array.
38 */
39 enum SKKeys{
40  skkVendor = 0,
41  skkDevice,
42 // skkName,
43 // skkTransport,
44  skkProtocol,
45  skkCommandSet,
46  skkFakeInq,
47  skk6ByteCmd,
48  skkTransTU,
49  skkNoTU,
50  skkNoGetMaxLUN,
51  skkNoPreventMedia,
52  skkUseModeSense10,
53  skkForceReadOnly,
54  skkProtoBulk,
55  skkProtoCB,
56  skkProtoCBI,
57 // skkProtoFreecom,
58  skkCmdSetSCSI,
59  skkCmdSetUFI,
60  skkCmdSetATAPI,
61  skkCmdSetRBC,
62  skkCmdSetQIC157,
63 
64  skkKeysCount,
65 // skkTransportBase = skkSubClassSCSI,
66  skkProtoBegin = skkProtoBulk,
67  skkProtoEnd	 = skkProtoCBI,
68  skkCmdSetBegin = skkCmdSetSCSI,
69  skkCmdSetEnd	 = skkCmdSetQIC157,
70 };
71 /**
72 	helper struct, used in our "quick" search algorithm
73 */
74 struct _settings_key{
75 	union _hash{
76 		char name[32];
77 		uint16 key;
78 	}hash;
79 	uint32 property;
80 }settings_keys[] = {	/**< array of keys, used in our settings files */
81 	{{"vendor"	 }, 0}, /* MUST BE SYNCHRONISED WITH skk*** indexes!!! */
82 	{{"device"	 }, 0},
83 //	{{"name"		 }, 0},
84 //	{{"transport"}, 0},
85 	{{"protocol"}, 0},
86 	{{"commandset"}, 0},
87 	{{"fake_inquiry"	}, 0},
88 	{{"use_rw6_byte_cmd" }, 0},
89 	{{"trans_test_unit"	}, 0},
90 	{{"no_test_unit"	}, 0},
91 	{{"no_get_max_lun"}, 0},
92 	{{"no_prevent_media"}, 0},
93 	{{"use_mode_sense_10"}, 0},
94 	{{"force_read_only"}, 0},
95 	{{"BULK"	 }, PROTO_BULK_ONLY},
96 	{{"CB"		 }, PROTO_CB},
97 	{{"CBI"		}, PROTO_CBI},
98 //	{{"Freecom"}, PROTO_FREECOM},
99 	{{"SCSI"	 }, CMDSET_SCSI},
100 	{{"UFI"		}, CMDSET_UFI},
101 	{{"ATAPI"	}, CMDSET_ATAPI},
102 	{{"RBC"		}, CMDSET_RBC},
103 	{{"QIC157" }, CMDSET_QIC157},
104 };
105 /**
106 	\define:SK_EQUAL
107 	checks is the __name parameter correspond to value, pointed by __id index
108 	in settings_keys array. The magic of our "quick" search algorithm =-))
109 */
110 #define CAST_SK(__name) (*(uint16 *)(__name))
111 #define SK_EQUAL(__name, __id) ((CAST_SK(__name) == (settings_keys[__id].hash.key)) && \
112 																 (0 == strcmp(__name, settings_keys[__id].hash.name)))
113 /**
114 	\fn:load_module_settings
115 	loads driver settings from extarnal settings file through BeOS driver
116 	settings API. Called on initialization of the module
117 */
118 void load_module_settings(void)
119 {
120 	void *sh = load_driver_settings(MODULE_NAME);
121 	if(sh){
122 		load_log_settings(sh);
123 		/* devices "reservation". Workaround for plug-n-play device attaching*/
124 		reserved_devices = strtoul(get_driver_parameter(sh, "reserve_devices",
125 								S_DEF_DEVS, S_DEF_DEVS), NULL, 0);
126 		reserved_luns	 = strtoul(get_driver_parameter(sh, "reserve_luns",
127 								S_DEF_LUNS, S_DEF_LUNS), NULL, 0);
128 		b_ignore_sysinit2 = get_driver_boolean_parameter(sh, "ignore_sysinit2",
129 								b_ignore_sysinit2, false);
130 		if(reserved_devices > MAX_DEVICES_COUNT)
131 			reserved_devices = MAX_DEVICES_COUNT;
132 		if(reserved_luns > MAX_LUNS_COUNT)
133 			reserved_luns = MAX_LUNS_COUNT;
134 		b_reservation_on = (reserved_devices != 0);
135 
136 		unload_driver_settings(sh);
137 	} else {
138 		TRACE("settings:load:file '%s' was not found. Using default setting...\n",
139 												 MODULE_NAME);
140 	}
141 }
142 /**
143 	\fn:strncpy_value
144 	\param to: buffer for copied string
145 	\param dp: driver_parameter, from wich copied string come
146 	\param size: maximal size of copied string
147 	copies a string, containing value[0] of this parameter, from driver_parameter,
148 	pointed by dp, to buffer pointed by to. Semantic of this function is similar
149 	to standard strncpy() one.
150 */
151 /*static void
152 strncpy_value(char *to, driver_parameter *dp, size_t size)
153 {
154 	to[0] = 0;
155 	if(dp->value_count > 0){
156 		strncpy(to, dp->values[0], size);
157 	}
158 }*/
159 /**
160 	\fn:parse_transport
161 	\param dp: driver_parameter, containing device transport information
162 	\return: a bitmasked value from PROP_-defined flags for USB subclass and \
163 					 protocol
164 	parse the transport driver_parameter for known USB subclasses, protocols and
165 	compose a bitmasked value from those settings
166 */
167 static uint32
168 parse_transport(driver_parameter *dp, int skkBase, int skkEnd,
169 				uint32 vendor_prop, char *vendor_prop_name)
170 {
171 	uint32 ret = 0;
172 	if(dp->value_count > 0){
173 		char *value = dp->values[0];
174 		int skkIdx = skkBase;
175 		for(; skkIdx <= skkEnd; skkIdx++){
176 			if(SK_EQUAL(value, skkIdx)){
177 				ret |= settings_keys[skkIdx].property;
178 				break;
179 			}
180 		} /* for(...) enumerate protocol and commandset keys */
181 		if(skkIdx > skkEnd){ /* not found - assume vendor prop */
182 			ret |= vendor_prop;
183 			strncpy(vendor_prop_name, value, VENDOR_PROP_NAME_LEN);
184 		}
185 		if(dp->value_count > 1){
186 			TRACE("settings:parse_transport:accept '%s', ignore extra...\n", value);
187 		}
188 	}
189 	return ret;
190 }
191 /**
192 	\fn:lookup_device_info
193 	\param product_id: product id of device to be checked for private settings
194 	\param dp: driver_parameter, containing device information
195 	\param udd: on return contains name,protocol etc. information about device
196 	\return: "true" if private settings for device found - "false" otherwise
197 	looks through device parameter, pointed by dp, obtains the name and other
198 	parameters of private device settings if available
199 */
200 static bool
201 lookup_device_info(uint16 product_id, driver_parameter *dp,
202 									 usb_device_settings *uds)
203 {
204 	bool b_found = false;
205 	if(dp){
206 		int i = 0;
207 		for(; i < dp->value_count; i++){
208 			uint16 id = strtoul(dp->values[0], NULL, 0) & 0xffff;
209 			if(product_id == id){
210 				int prm = 0;
211 				uds->product_id = product_id;
212 				for(; prm < dp->parameter_count; prm++){
213 /*					if(SK_EQUAL(dp->parameters[prm].name, skkName)){
214 						strncpy_value(udd->product_name, &dp->parameters[prm], INQ_PRODUCT_LEN);
215 					} else*/
216 /*					if(SK_EQUAL(dp->parameters[prm].name, skkTransport)){
217 						udd->properties |= parse_transport(&dp->parameters[prm]);
218 					} else*/
219 					if(SK_EQUAL(dp->parameters[prm].name, skkProtocol)){
220 						uds->properties |= parse_transport(&dp->parameters[prm],
221 							 skkProtoBegin, skkProtoEnd,
222 							 PROTO_VENDOR, uds->vendor_protocol);
223 					} else
224 					if(SK_EQUAL(dp->parameters[prm].name, skkCommandSet)){
225 						uds->properties |= parse_transport(&dp->parameters[prm],
226 							 skkCmdSetBegin, skkCmdSetEnd,
227 							 CMDSET_VENDOR, uds->vendor_commandset);
228 					} else
229 					if(SK_EQUAL(dp->parameters[prm].name, skkFakeInq)){
230 						uds->properties |= FIX_NO_INQUIRY;
231 					} else
232 					if(SK_EQUAL(dp->parameters[prm].name, skk6ByteCmd)){
233 						uds->properties |= FIX_FORCE_RW_TO_6;
234 					} else
235 					if(SK_EQUAL(dp->parameters[prm].name, skkTransTU)){
236 						uds->properties |= FIX_TRANS_TEST_UNIT;
237 					} else
238 					if(SK_EQUAL(dp->parameters[prm].name, skkNoTU)){
239 						uds->properties |= FIX_NO_TEST_UNIT;
240 					} else
241 					if(SK_EQUAL(dp->parameters[prm].name, skkNoPreventMedia)){
242 						uds->properties |= FIX_NO_PREVENT_MEDIA;
243 					} else
244 					if(SK_EQUAL(dp->parameters[prm].name, skkUseModeSense10)){
245 						uds->properties |= FIX_FORCE_MS_TO_10;
246 					} else
247 					if(SK_EQUAL(dp->parameters[prm].name, skkForceReadOnly)){
248 						uds->properties |= FIX_FORCE_READ_ONLY;
249 					} else
250 					if(SK_EQUAL(dp->parameters[prm].name, skkNoGetMaxLUN)){
251 						uds->properties |= FIX_NO_GETMAXLUN;
252 					} else {
253 						TRACE("settings:device:ignore unknown parameter:%s\n",
254 																												dp->parameters[prm].name);
255 					}
256 				} /* for(...) enumerate device parameters */
257 				b_found = true;
258 				break;
259 			} /* if(product_id == id){ */
260 		} /*enumerate parameter values (product ids) */
261 	} /* if(dp) */
262 	return b_found;
263 }
264 /**
265 	\fn:lookup_vendor_info
266 	\param vendor_id: vendor id of device to be checked for private settings
267 	\param product_id: product id of device to be checked for private settings
268 	\param dp: driver_parameter, containing vendor information
269 	\param udd: on return contains name, protocol etc. information about device
270 	\return: "true" if private settings for device found - "false" otherwise
271 	looks through vendor parameter, pointed by dp, obtains the name of vendor and
272 	device information if available
273 */
274 static bool
275 lookup_vendor_info(uint16 vendor_id, uint16 product_id,
276 				 driver_parameter *dp, usb_device_settings *uds)
277 {
278 	bool b_found = false;
279 	if(dp && dp->value_count > 0 && dp->values[0]){
280 		uint16 id = strtoul(dp->values[0], NULL, 0) & 0xffff;
281 		if(vendor_id == id){
282 			int i = 0;
283 			for( i = 0; i < dp->parameter_count; i++){
284 				if(!b_found && SK_EQUAL(dp->parameters[i].name, skkDevice)){
285 					b_found = lookup_device_info(product_id, &dp->parameters[i], uds);
286 				} /*else
287 				if(SK_EQUAL(dp->parameters[i].name, skkName)){
288 					strncpy_value(udd->vendor_name, &dp->parameters[i], INQ_VENDOR_LEN);
289 				} */else {
290 					TRACE("settings:vendor:ignore unknown parameter:%s\n",
291 																											 dp->parameters[i].name);
292 				}
293 			} /*for(...) enumerate "vendor" parameters*/
294 		} /*if(vendor_id == id){*/
295 	} /* if(dp && ... etc */
296 	return b_found;
297 }
298 /**
299 	\fn:lookup_device_settings
300 	\param vendor_id: vendor id of device to be checked for private settings
301 	\param product_id: product id of device to be checked for private settings
302 	\param udd: on return contains name,protocol etc. information about device
303 	\return: "true" if private settings for device found - "false" otherwise
304 	looks through driver settings file for private device description and load it
305 	if available into struct pointed by udd
306 */
307 bool lookup_device_settings(const usb_device_descriptor *udd,
308 								usb_device_settings *uds)
309 {
310 	bool b_found = false;
311 	if(uds){
312 		void *sh = load_driver_settings(MODULE_NAME);
313 		if(sh){
314 			const driver_settings *ds = get_driver_settings(sh);
315 			if(ds){
316 				int i = 0;
317 				for(i = 0; i < ds->parameter_count; i++){
318 					if(SK_EQUAL(ds->parameters[i].name, skkVendor)){
319 						b_found = lookup_vendor_info(udd->vendor_id,
320 													 udd->product_id,
321 											 &ds->parameters[i], uds);
322 						if(b_found){
323 							uds->vendor_id = udd->vendor_id;
324 							break; //we've got it - stop enumeration.
325 						}
326 					}
327 				} /*for(...) - enumerate "root" parameters*/
328 			} /* if(ds) */
329 			unload_driver_settings(sh);
330 		} /* if(sh) */
331 		if(b_found){
332 			//TRACE("settings:loaded settings:'%s(%04x)/%s(%04x)/%08x'\n",
333 			TRACE("settings:loaded settings:'%04x/%04x/%08x'\n",
334 				/*descr->vendor_name,*/ uds->vendor_id,
335 				/*descr->product_name,*/
336 				uds->product_id, uds->properties);
337 		}
338 	} /* if(descr)*/
339 	return b_found;
340 }
341 
342