1 /** 2 * 3 * TODO: description 4 * 5 * This file is a part of USB SCSI CAM for Haiku. 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