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