12db0303fSimker/**
22db0303fSimker *
32db0303fSimker * TODO: description
406437987SMatt Madia *
506437987SMatt Madia * This file is a part of USB SCSI CAM for Haiku.
62db0303fSimker * May be used under terms of the MIT License
72db0303fSimker *
82db0303fSimker * Author(s):
92db0303fSimker * 	Siarzhuk Zharski <imker@gmx.li>
1006437987SMatt Madia *
1106437987SMatt Madia *
12b3d94504SStephan Aßmus */
13b3d94504SStephan Aßmus/** driver settings support implementation */
14b3d94504SStephan Aßmus
15b3d94504SStephan Aßmus#include "usb_scsi.h"
16b3d94504SStephan Aßmus#include "settings.h"
1706437987SMatt Madia//#include "proto_common.h"
18b3d94504SStephan Aßmus
192db0303fSimker#include <stdlib.h>	/* strtoul */
20b3d94504SStephan Aßmus#include <strings.h> /* strncpy */
21b3d94504SStephan Aßmus#include <driver_settings.h>
22b3d94504SStephan Aßmus#include "tracing.h"
23b3d94504SStephan Aßmus
242db0303fSimker#define DEF_DEVS	2	/**< default amount of reserved devices */
252db0303fSimker#define S_DEF_DEVS	"2" /**< default amount of reserved devices */
262db0303fSimker#define DEF_LUNS	4	/**< default amount of reserved LUNs */
272db0303fSimker#define S_DEF_LUNS	"4" /**< default amount of reserved LUNs */
28b3d94504SStephan Aßmus/** count of device entries, to be reserved for fake devices */
292db0303fSimkerint reserved_devices	= DEF_DEVS;
30b3d94504SStephan Aßmus/** count of Logical Unit Numbers, to be reserved for fake devices */
312db0303fSimkerint reserved_luns		= DEF_LUNS;
32b3d94504SStephan Aßmus
332db0303fSimkerbool b_reservation_on  = true;
34b3d94504SStephan Aßmusbool b_ignore_sysinit2 = false;
35b3d94504SStephan Aßmus/**
362db0303fSimker	support of some kind rudimentary "quick" search. Indexes in
372db0303fSimker	settings_keys array.
38b3d94504SStephan Aßmus*/
39b3d94504SStephan Aßmusenum SKKeys{
4006437987SMatt Madia skkVendor = 0,
4106437987SMatt Madia skkDevice,
4206437987SMatt Madia// skkName,
4306437987SMatt Madia// skkTransport,
4406437987SMatt Madia skkProtocol,
4506437987SMatt Madia skkCommandSet,
4606437987SMatt Madia skkFakeInq,
4706437987SMatt Madia skk6ByteCmd,
48b3d94504SStephan Aßmus skkTransTU,
49b3d94504SStephan Aßmus skkNoTU,
5006437987SMatt Madia skkNoGetMaxLUN,
5106437987SMatt Madia skkNoPreventMedia,
5206437987SMatt Madia skkUseModeSense10,
5306437987SMatt Madia skkForceReadOnly,
5406437987SMatt Madia skkProtoBulk,
5506437987SMatt Madia skkProtoCB,
56b3d94504SStephan Aßmus skkProtoCBI,
57b3d94504SStephan Aßmus// skkProtoFreecom,
5806437987SMatt Madia skkCmdSetSCSI,
5906437987SMatt Madia skkCmdSetUFI,
6006437987SMatt Madia skkCmdSetATAPI,
6106437987SMatt Madia skkCmdSetRBC,
6206437987SMatt Madia skkCmdSetQIC157,
6306437987SMatt Madia
64b3d94504SStephan Aßmus skkKeysCount,
6506437987SMatt Madia// skkTransportBase = skkSubClassSCSI,
6606437987SMatt Madia skkProtoBegin = skkProtoBulk,
6706437987SMatt Madia skkProtoEnd	 = skkProtoCBI,
6806437987SMatt Madia skkCmdSetBegin = skkCmdSetSCSI,
6906437987SMatt Madia skkCmdSetEnd	 = skkCmdSetQIC157,
70b3d94504SStephan Aßmus};
71b3d94504SStephan Aßmus/**
7206437987SMatt Madia	helper struct, used in our "quick" search algorithm
73b3d94504SStephan Aßmus*/
74b3d94504SStephan Aßmusstruct _settings_key{
752db0303fSimker	union _hash{
762db0303fSimker		char name[32];
772db0303fSimker		uint16 key;
782db0303fSimker	}hash;
7906437987SMatt Madia	uint32 property;
802db0303fSimker}settings_keys[] = {	/**< array of keys, used in our settings files */
812db0303fSimker	{{"vendor"	 }, 0}, /* MUST BE SYNCHRONISED WITH skk*** indexes!!! */
822db0303fSimker	{{"device"	 }, 0},
832db0303fSimker//	{{"name"		 }, 0},
842db0303fSimker//	{{"transport"}, 0},
852db0303fSimker	{{"protocol"}, 0},
862db0303fSimker	{{"commandset"}, 0},
872db0303fSimker	{{"fake_inquiry"	}, 0},
882db0303fSimker	{{"use_rw6_byte_cmd" }, 0},
892db0303fSimker	{{"trans_test_unit"	}, 0},
902db0303fSimker	{{"no_test_unit"	}, 0},
912db0303fSimker	{{"no_get_max_lun"}, 0},
922db0303fSimker	{{"no_prevent_media"}, 0},
932db0303fSimker	{{"use_mode_sense_10"}, 0},
942db0303fSimker	{{"force_read_only"}, 0},
952db0303fSimker	{{"BULK"	 }, PROTO_BULK_ONLY},
962db0303fSimker	{{"CB"		 }, PROTO_CB},
972db0303fSimker	{{"CBI"		}, PROTO_CBI},
982db0303fSimker//	{{"Freecom"}, PROTO_FREECOM},
992db0303fSimker	{{"SCSI"	 }, CMDSET_SCSI},
1002db0303fSimker	{{"UFI"		}, CMDSET_UFI},
1012db0303fSimker	{{"ATAPI"	}, CMDSET_ATAPI},
1022db0303fSimker	{{"RBC"		}, CMDSET_RBC},
1032db0303fSimker	{{"QIC157" }, CMDSET_QIC157},
104b3d94504SStephan Aßmus};
105b3d94504SStephan Aßmus/**
1062db0303fSimker	\define:SK_EQUAL
1072db0303fSimker	checks is the __name parameter correspond to value, pointed by __id index
10806437987SMatt Madia	in settings_keys array. The magic of our "quick" search algorithm =-))
109b3d94504SStephan Aßmus*/
110b3d94504SStephan Aßmus#define CAST_SK(__name) (*(uint16 *)(__name))
111b3d94504SStephan Aßmus#define SK_EQUAL(__name, __id) ((CAST_SK(__name) == (settings_keys[__id].hash.key)) && \
1122db0303fSimker																 (0 == strcmp(__name, settings_keys[__id].hash.name)))
113b3d94504SStephan Aßmus/**
1142db0303fSimker	\fn:load_module_settings
1152db0303fSimker	loads driver settings from extarnal settings file through BeOS driver
1162db0303fSimker	settings API. Called on initialization of the module
11706437987SMatt Madia*/
1182db0303fSimkervoid load_module_settings(void)
119b3d94504SStephan Aßmus{
1202db0303fSimker	void *sh = load_driver_settings(MODULE_NAME);
1212db0303fSimker	if(sh){
1222db0303fSimker		load_log_settings(sh);
1232db0303fSimker		/* devices "reservation". Workaround for plug-n-play device attaching*/
1242db0303fSimker		reserved_devices = strtoul(get_driver_parameter(sh, "reserve_devices",
1252db0303fSimker								S_DEF_DEVS, S_DEF_DEVS), NULL, 0);
1262db0303fSimker		reserved_luns	 = strtoul(get_driver_parameter(sh, "reserve_luns",
1272db0303fSimker								S_DEF_LUNS, S_DEF_LUNS), NULL, 0);
1282db0303fSimker		b_ignore_sysinit2 = get_driver_boolean_parameter(sh, "ignore_sysinit2",
1292db0303fSimker								b_ignore_sysinit2, false);
1302db0303fSimker		if(reserved_devices > MAX_DEVICES_COUNT)
13106437987SMatt Madia			reserved_devices = MAX_DEVICES_COUNT;
1322db0303fSimker		if(reserved_luns > MAX_LUNS_COUNT)
1332db0303fSimker			reserved_luns = MAX_LUNS_COUNT;
1342db0303fSimker		b_reservation_on = (reserved_devices != 0);
13506437987SMatt Madia
1362db0303fSimker		unload_driver_settings(sh);
1372db0303fSimker	} else {
1382db0303fSimker		TRACE("settings:load:file '%s' was not found. Using default setting...\n",
1392db0303fSimker												 MODULE_NAME);
14006437987SMatt Madia	}
141b3d94504SStephan Aßmus}
142b3d94504SStephan Aßmus/**
1432db0303fSimker	\fn:strncpy_value
1442db0303fSimker	\param to: buffer for copied string
1452db0303fSimker	\param dp: driver_parameter, from wich copied string come
14606437987SMatt Madia	\param size: maximal size of copied string
1472db0303fSimker	copies a string, containing value[0] of this parameter, from driver_parameter,
1482db0303fSimker	pointed by dp, to buffer pointed by to. Semantic of this function is similar
14906437987SMatt Madia	to standard strncpy() one.
150b3d94504SStephan Aßmus*/
151b3d94504SStephan Aßmus/*static void
152b3d94504SStephan Aßmusstrncpy_value(char *to, driver_parameter *dp, size_t size)
153b3d94504SStephan Aßmus{
1542db0303fSimker	to[0] = 0;
1552db0303fSimker	if(dp->value_count > 0){
1562db0303fSimker		strncpy(to, dp->values[0], size);
1572db0303fSimker	}
158b3d94504SStephan Aßmus}*/
159b3d94504SStephan Aßmus/**
1602db0303fSimker	\fn:parse_transport
1612db0303fSimker	\param dp: driver_parameter, containing device transport information
1622db0303fSimker	\return: a bitmasked value from PROP_-defined flags for USB subclass and \
1632db0303fSimker					 protocol
1642db0303fSimker	parse the transport driver_parameter for known USB subclasses, protocols and
16506437987SMatt Madia	compose a bitmasked value from those settings
166b3d94504SStephan Aßmus*/
167b3d94504SStephan Aßmusstatic uint32
1682db0303fSimkerparse_transport(driver_parameter *dp, int skkBase, int skkEnd,
1692db0303fSimker				uint32 vendor_prop, char *vendor_prop_name)
170b3d94504SStephan Aßmus{
1712db0303fSimker	uint32 ret = 0;
1722db0303fSimker	if(dp->value_count > 0){
1732db0303fSimker		char *value = dp->values[0];
1742db0303fSimker		int skkIdx = skkBase;
1752db0303fSimker		for(; skkIdx <= skkEnd; skkIdx++){
1762db0303fSimker			if(SK_EQUAL(value, skkIdx)){
1772db0303fSimker				ret |= settings_keys[skkIdx].property;
1782db0303fSimker				break;
1792db0303fSimker			}
1802db0303fSimker		} /* for(...) enumerate protocol and commandset keys */
1812db0303fSimker		if(skkIdx > skkEnd){ /* not found - assume vendor prop */
1822db0303fSimker			ret |= vendor_prop;
1832db0303fSimker			strncpy(vendor_prop_name, value, VENDOR_PROP_NAME_LEN);
1842db0303fSimker		}
1852db0303fSimker		if(dp->value_count > 1){
1862db0303fSimker			TRACE("settings:parse_transport:accept '%s', ignore extra...\n", value);
1872db0303fSimker		}
18806437987SMatt Madia	}
1892db0303fSimker	return ret;
190b3d94504SStephan Aßmus}
191b3d94504SStephan Aßmus/**
1922db0303fSimker	\fn:lookup_device_info
1932db0303fSimker	\param product_id: product id of device to be checked for private settings
1942db0303fSimker	\param dp: driver_parameter, containing device information
19506437987SMatt Madia	\param udd: on return contains name,protocol etc. information about device
1962db0303fSimker	\return: "true" if private settings for device found - "false" otherwise
1972db0303fSimker	looks through device parameter, pointed by dp, obtains the name and other
1982db0303fSimker	parameters of private device settings if available
199b3d94504SStephan Aßmus*/
200b3d94504SStephan Aßmusstatic bool
2012db0303fSimkerlookup_device_info(uint16 product_id, driver_parameter *dp,
2022db0303fSimker									 usb_device_settings *uds)
203b3d94504SStephan Aßmus{
2042db0303fSimker	bool b_found = false;
2052db0303fSimker	if(dp){
2062db0303fSimker		int i = 0;
2072db0303fSimker		for(; i < dp->value_count; i++){
2082db0303fSimker			uint16 id = strtoul(dp->values[0], NULL, 0) & 0xffff;
2092db0303fSimker			if(product_id == id){
2102db0303fSimker				int prm = 0;
2112db0303fSimker				uds->product_id = product_id;
2122db0303fSimker				for(; prm < dp->parameter_count; prm++){
2132db0303fSimker/*					if(SK_EQUAL(dp->parameters[prm].name, skkName)){
2142db0303fSimker						strncpy_value(udd->product_name, &dp->parameters[prm], INQ_PRODUCT_LEN);
2152db0303fSimker					} else*/
2162db0303fSimker/*					if(SK_EQUAL(dp->parameters[prm].name, skkTransport)){
2172db0303fSimker						udd->properties |= parse_transport(&dp->parameters[prm]);
2182db0303fSimker					} else*/
2192db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkProtocol)){
2202db0303fSimker						uds->properties |= parse_transport(&dp->parameters[prm],
22106437987SMatt Madia							 skkProtoBegin, skkProtoEnd,
2222db0303fSimker							 PROTO_VENDOR, uds->vendor_protocol);
2232db0303fSimker					} else
2242db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkCommandSet)){
2252db0303fSimker						uds->properties |= parse_transport(&dp->parameters[prm],
22606437987SMatt Madia							 skkCmdSetBegin, skkCmdSetEnd,
2272db0303fSimker							 CMDSET_VENDOR, uds->vendor_commandset);
2282db0303fSimker					} else
2292db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkFakeInq)){
2302db0303fSimker						uds->properties |= FIX_NO_INQUIRY;
2312db0303fSimker					} else
2322db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skk6ByteCmd)){
2332db0303fSimker						uds->properties |= FIX_FORCE_RW_TO_6;
2342db0303fSimker					} else
2352db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkTransTU)){
2362db0303fSimker						uds->properties |= FIX_TRANS_TEST_UNIT;
23706437987SMatt Madia					} else
2382db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkNoTU)){
2392db0303fSimker						uds->properties |= FIX_NO_TEST_UNIT;
24006437987SMatt Madia					} else
2412db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkNoPreventMedia)){
2422db0303fSimker						uds->properties |= FIX_NO_PREVENT_MEDIA;
2432db0303fSimker					} else
2442db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkUseModeSense10)){
2452db0303fSimker						uds->properties |= FIX_FORCE_MS_TO_10;
2462db0303fSimker					} else
2472db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkForceReadOnly)){
2482db0303fSimker						uds->properties |= FIX_FORCE_READ_ONLY;
2492db0303fSimker					} else
2502db0303fSimker					if(SK_EQUAL(dp->parameters[prm].name, skkNoGetMaxLUN)){
2512db0303fSimker						uds->properties |= FIX_NO_GETMAXLUN;
2522db0303fSimker					} else {
2532db0303fSimker						TRACE("settings:device:ignore unknown parameter:%s\n",
2542db0303fSimker																												dp->parameters[prm].name);
2552db0303fSimker					}
2562db0303fSimker				} /* for(...) enumerate device parameters */
2572db0303fSimker				b_found = true;
2582db0303fSimker				break;
2592db0303fSimker			} /* if(product_id == id){ */
2602db0303fSimker		} /*enumerate parameter values (product ids) */
2612db0303fSimker	} /* if(dp) */
2622db0303fSimker	return b_found;
263b3d94504SStephan Aßmus}
264b3d94504SStephan Aßmus/**
2652db0303fSimker	\fn:lookup_vendor_info
2662db0303fSimker	\param vendor_id: vendor id of device to be checked for private settings
2672db0303fSimker	\param product_id: product id of device to be checked for private settings
2682db0303fSimker	\param dp: driver_parameter, containing vendor information
2692db0303fSimker	\param udd: on return contains name, protocol etc. information about device
2702db0303fSimker	\return: "true" if private settings for device found - "false" otherwise
2712db0303fSimker	looks through vendor parameter, pointed by dp, obtains the name of vendor and
2722db0303fSimker	device information if available
273b3d94504SStephan Aßmus*/
274b3d94504SStephan Aßmusstatic bool
2752db0303fSimkerlookup_vendor_info(uint16 vendor_id, uint16 product_id,
2762db0303fSimker				 driver_parameter *dp, usb_device_settings *uds)
277b3d94504SStephan Aßmus{
2782db0303fSimker	bool b_found = false;
27906437987SMatt Madia	if(dp && dp->value_count > 0 && dp->values[0]){
2802db0303fSimker		uint16 id = strtoul(dp->values[0], NULL, 0) & 0xffff;
2812db0303fSimker		if(vendor_id == id){
2822db0303fSimker			int i = 0;
2832db0303fSimker			for( i = 0; i < dp->parameter_count; i++){
2842db0303fSimker				if(!b_found && SK_EQUAL(dp->parameters[i].name, skkDevice)){
2852db0303fSimker					b_found = lookup_device_info(product_id, &dp->parameters[i], uds);
2862db0303fSimker				} /*else
2872db0303fSimker				if(SK_EQUAL(dp->parameters[i].name, skkName)){
2882db0303fSimker					strncpy_value(udd->vendor_name, &dp->parameters[i], INQ_VENDOR_LEN);
2892db0303fSimker				} */else {
2902db0303fSimker					TRACE("settings:vendor:ignore unknown parameter:%s\n",
2912db0303fSimker																											 dp->parameters[i].name);
2922db0303fSimker				}
2932db0303fSimker			} /*for(...) enumerate "vendor" parameters*/
2942db0303fSimker		} /*if(vendor_id == id){*/
2952db0303fSimker	} /* if(dp && ... etc */
2962db0303fSimker	return b_found;
297b3d94504SStephan Aßmus}
298b3d94504SStephan Aßmus/**
2992db0303fSimker	\fn:lookup_device_settings
3002db0303fSimker	\param vendor_id: vendor id of device to be checked for private settings
3012db0303fSimker	\param product_id: product id of device to be checked for private settings
3022db0303fSimker	\param udd: on return contains name,protocol etc. information about device
3032db0303fSimker	\return: "true" if private settings for device found - "false" otherwise
3042db0303fSimker	looks through driver settings file for private device description and load it
30506437987SMatt Madia	if available into struct pointed by udd
306b3d94504SStephan Aßmus*/
307b3d94504SStephan Aßmusbool lookup_device_settings(const usb_device_descriptor *udd,
3082db0303fSimker								usb_device_settings *uds)
309b3d94504SStephan Aßmus{
3102db0303fSimker	bool b_found = false;
3112db0303fSimker	if(uds){
3122db0303fSimker		void *sh = load_driver_settings(MODULE_NAME);
3132db0303fSimker		if(sh){
3142db0303fSimker			const driver_settings *ds = get_driver_settings(sh);
3152db0303fSimker			if(ds){
3162db0303fSimker				int i = 0;
3172db0303fSimker				for(i = 0; i < ds->parameter_count; i++){
3182db0303fSimker					if(SK_EQUAL(ds->parameters[i].name, skkVendor)){
3192db0303fSimker						b_found = lookup_vendor_info(udd->vendor_id,
3202db0303fSimker													 udd->product_id,
3212db0303fSimker											 &ds->parameters[i], uds);
3222db0303fSimker						if(b_found){
3232db0303fSimker							uds->vendor_id = udd->vendor_id;
3242db0303fSimker							break; //we've got it - stop enumeration.
32506437987SMatt Madia						}
3262db0303fSimker					}
3272db0303fSimker				} /*for(...) - enumerate "root" parameters*/
32806437987SMatt Madia			} /* if(ds) */
3292db0303fSimker			unload_driver_settings(sh);
3302db0303fSimker		} /* if(sh) */
3312db0303fSimker		if(b_found){
3322db0303fSimker			//TRACE("settings:loaded settings:'%s(%04x)/%s(%04x)/%08x'\n",
3332db0303fSimker			TRACE("settings:loaded settings:'%04x/%04x/%08x'\n",
3342db0303fSimker				/*descr->vendor_name,*/ uds->vendor_id,
3352db0303fSimker				/*descr->product_name,*/
3362db0303fSimker				uds->product_id, uds->properties);
3372db0303fSimker		}
3382db0303fSimker	} /* if(descr)*/
3392db0303fSimker	return b_found;
340b3d94504SStephan Aßmus}
3412db0303fSimker
342