xref: /haiku/src/add-ons/kernel/busses/scsi/usb/settings.c (revision cd552c7a15cc10c36dae8d7439ba1d6c0bb168c5)
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