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 */
load_module_settings(void)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
parse_transport(driver_parameter * dp,int skkBase,int skkEnd,uint32 vendor_prop,char * vendor_prop_name)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
lookup_device_info(uint16 product_id,driver_parameter * dp,usb_device_settings * uds)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
lookup_vendor_info(uint16 vendor_id,uint16 product_id,driver_parameter * dp,usb_device_settings * uds)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 */
lookup_device_settings(const usb_device_descriptor * udd,usb_device_settings * uds)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