SMBIOS Library
Smi.cpp
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
3  *
4  * Copyright (C) 2005 Dell Inc.
5  * by Michael Brown <Michael_E_Brown@dell.com>
6  * Licensed under the Open Software License version 2.1
7  *
8  * Alternatively, you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License,
11  * or (at your option) any later version.
12 
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  */
18 
19 // compat header should always be first header if including system headers
20 #define LIBSMBIOS_SOURCE
21 #include "smbios/compat.h"
22 
23 //#include <iostream>
24 #include <string.h>
25 
26 #include "SmiImpl.h"
27 #include "smbios/ISmbios.h"
28 #include "smbios/IToken.h"
29 #include "TokenLowLevel.h"
30 
31 using namespace std;
32 
33 #if defined(DEBUG_SMI)
34 # define DCOUT(line) do { cout << line; } while(0)
35 # define DCERR(line) do { cerr << line; } while(0)
36 #else
37 # define DCOUT(line) do {} while(0)
38 # define DCERR(line) do {} while(0)
39 #endif
40 
41 /* work around broken VC6 compiler */
42 #define SIZEOF_KERNELBUF (sizeof(kernel_buf) - sizeof(kernel_buf.command_buffer_start))
43 
44 namespace smi
45 {
46 
47 
48  //
49  // ISmi functions
50  //
51  IDellCallingInterfaceSmi::IDellCallingInterfaceSmi()
52  {}
53 
54  IDellCallingInterfaceSmi::~IDellCallingInterfaceSmi()
55  {}
56 
57  DellCallingInterfaceSmiImpl::DellCallingInterfaceSmiImpl(SmiStrategy *initStrategy, u16 address, u8 code )
58  : buffer(0), bufferSize(0), smiStrategy(initStrategy)
59  {
60  // this is the only place where we use 'real' sizeof(kernel_buf),
61  // everywhere else should use SIZEOF_KERNELBUF
62  memset( &kernel_buf, 0, sizeof(kernel_buf) );
63 
64  memset( &smi_buf, 0, sizeof(smi_buf) );
65  memset( &argIsAddress, 0, sizeof(argIsAddress) );
66  memset( &argAddressOffset, 0, sizeof(argAddressOffset) );
67 
69  kernel_buf.ebx = 0;
71  kernel_buf.command_address = address;
72  kernel_buf.command_code = code;
73 
74  /* default to "not handled" */
75  smi_buf.cbRES1 = -3;
76  }
77 
79  {
80  if(buffer)
81  {
82  delete [] buffer;
83  buffer = 0;
84  bufferSize = 0;
85  }
86  }
87 
89  {
90  return buffer;
91  }
92 
94  {
95  if ( bufferSize != newSize )
96  {
97  delete [] buffer;
98  buffer = new u8[newSize];
99  memset(buffer, 0, newSize);
100 
101  bufferSize=newSize;
102  }
103  }
104 
106  {
107  if(!bufferSize)
108  throw SmiExceptionImpl("Output buffer not large enough.");
109 
110  memcpy(buffer, src, bufferSize<size?bufferSize:size);
111  }
112 
114  {
115  smiStrategy->lock() ;
116  smiStrategy->setSize( SIZEOF_KERNELBUF + sizeof(smi_buf) + bufferSize );
117 
118  size_t baseAddr = smiStrategy->getPhysicalBufferBaseAddress();
119  for( int i=0; i<4; i++)
120  if( argIsAddress[i] )
121  smi_buf.inputArgs[i] = static_cast<u32>(baseAddr + SIZEOF_KERNELBUF + sizeof(smi_buf) + argAddressOffset[i]);
122 
123  smiStrategy->addInputBuffer(reinterpret_cast<u8 *>(&kernel_buf), SIZEOF_KERNELBUF);
124  smiStrategy->addInputBuffer(reinterpret_cast<u8 *>(&smi_buf), sizeof(smi_buf));
125  if(buffer)
126  smiStrategy->addInputBuffer(buffer, bufferSize);
127 
128  smiStrategy->execute();
129 
130  smiStrategy->getResultBuffer(reinterpret_cast<u8 *>(&kernel_buf), SIZEOF_KERNELBUF);
131  smiStrategy->getResultBuffer(reinterpret_cast<u8 *>(&smi_buf), sizeof(smi_buf));
132  if(buffer)
133  smiStrategy->getResultBuffer(reinterpret_cast<u8 *>(buffer), bufferSize);
134 
135  smiStrategy->finish();
136 
137  if( -6 == smi_buf.cbRES1 )
138  throw SmiExceptionImpl("Output buffer not large enough.");
139 
140  if( -5 == smi_buf.cbRES1 )
141  throw SmiExceptionImpl("Output buffer format error.");
142 
143  if( -3 == smi_buf.cbRES1 )
144  throw UnhandledSmiImpl("Unhandled SMI call.");
145 
146  if( -2 == smi_buf.cbRES1 )
147  throw UnsupportedSmiImpl("Unsupported SMI call.");
148 
149  if( -1 == smi_buf.cbRES1 )
150  throw SmiExecutedWithErrorImpl("BIOS returned error for SMI call.");
151  }
152 
154  {
155  if( argNumber >= 4 )
156  throw ParameterErrorImpl("Internal programming error. Argument must be in range 0..3");
157 
158  argIsAddress[argNumber] = true;
159  argAddressOffset[argNumber] = bufferOffset;
160  }
161 
162 
164  {
165  smi_buf.smiClass = newClass;
166  }
167 
169  {
170  smi_buf.smiSelect = newSelect;
171  }
172 
173  void DellCallingInterfaceSmiImpl::setArg( u8 argNumber, u32 argValue )
174  {
175  if( argNumber >= 4 )
176  throw ParameterErrorImpl("Internal programming error. Argument must be in range 0..3");
177 
178  smi_buf.inputArgs[ argNumber ] = argValue;
179  }
180 
182  {
183  if( resNumber >= 4 )
184  throw ParameterErrorImpl("Internal programming error. Result request must be in range 0..3");
185 
186  return smi_buf.outputRes[resNumber];
187  }
188 
189 
190  /**************************************************************************
191  HELPER FUNCTIONS (Non-member functions)
192  *************************************************************************/
193 
194  std::auto_ptr<smi::IDellCallingInterfaceSmi> setupCallingInterfaceSmi(u16 smiClass, u16 select, const u32 args[4])
195  {
196  const smbios::ISmbiosTable *table = 0;
198 
199  std::auto_ptr<smi::IDellCallingInterfaceSmi> smi = smi::SmiFactory::getFactory()->makeNew(smi::SmiFactory::DELL_CALLING_INTERFACE_SMI);
200 
201  smi->setClass( smiClass );
202  smi->setSelect( select );
203  smi->setArg(0, args[0]);
204  smi->setArg(1, args[1]);
205  smi->setArg(2, args[2]);
206  smi->setArg(3, args[3]);
207 
208  return smi;
209  }
210 
211  void doSimpleCallingInterfaceSmi(u16 smiClass, u16 select, const u32 args[4], u32 res[4])
212  {
213 
214  std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(
215  setupCallingInterfaceSmi(smiClass, select, args));
216 
217  smi->execute();
218 
219  res[0] = smi->getRes(0);
220  res[1] = smi->getRes(1);
221  res[2] = smi->getRes(2);
222  res[3] = smi->getRes(3);
223  }
224 
225  /*
226  An application that will attempt to set information via any Security-Key-protected Calling Interface function must first acquire a proper Security Key. It does this by performing the following steps:
227 
228  1.Check to see if an Administrator Password is set (Class 10, Selector 0 or 3). If yes, go to 2; otherwise, go to 3.
229 
230  2.Verify the Administrator Password (Class 10 Selector 1 or 4). If the password is verified (cbRES1 == 0), read the Security Key from cbRES2, and use it on subsequent set functions where it is required. If the password does not verify (cbRES1 == -1), repeat step 2 until it does verify; otherwise, subsequent set functions protected by the Administrator Password will be rejected by the BIOS if it supports the Security Key feature.
231 
232  3.Check to see if a User Password is set (Class 9, Selector 0 or 3). If yes, go to 4; otherwise, no Security Key will be needed to change data through the Calling Interface, and the caller can use any value at all for the Security Key when using any Security-Key-protected Calling Interface function.
233 
234  4.Verify the User Password (Class 9 Selector 1 or 4). If the password is verified (cbRES1 == 0), read the Security Key from cbRES2, and use it on subsequent set functions where it is required. If the password does not verify (cbRES1 == -1), repeat step 4 until it does verify; otherwise, subsequent set functions protected by the User Password will be rejected by the BIOS if it supports the Security Key feature.
235 
236  */
237  static bool getPasswordPropertiesII(u16 which, u8 &maxLen, u8 &minLen, u8 &props)
238  {
239  if( which != 9 && which != 10 )
240  throw ParameterErrorImpl("Internal programming error. Argument must be either 9 or 10.");
241 
242  bool hasPw = false;
243 
244  u32 args[4] = {0,}, res[4] = {0,};
245 
246  // select 3 == get properties
247  doSimpleCallingInterfaceSmi(which, 3, args, res);
248 
249  // byte 0 of res[1] shows password status
250  // 2 = password not installed
251  // 3 = password disabled by jumper
252  if ( (res[1] & 0xFF)==2 || (res[1] & 0xFF)==3 )
253  goto out;
254 
255  DCERR( "getPasswordPropertiesII()" << hex << endl );
256  DCERR( "res[0]: " << res[0] << endl);
257  DCERR( "res[1]: " << res[1] << endl);
258  DCERR( "res[2]: " << res[2] << endl);
259  DCERR( "res[3]: " << res[3] << endl);
260 
261  hasPw = true;
262  maxLen = static_cast<u8>((res[1] & 0x0000FF00) >> 8);
263  minLen = static_cast<u8>((res[1] & 0x00FF0000) >> 16);
264  props = static_cast<u8>((res[1] & 0xFF000000) >> 24);
265 
266 out:
267  return hasPw;
268  }
269 
270  bool getPasswordStatus(u16 which)
271  {
272  if( which != 9 && which != 10 )
273  throw ParameterErrorImpl("Internal programming error. Argument must be either 9 or 10.");
274  try
275  {
276  u32 args[4] = {0,}, res[4] = {0,};
277  doSimpleCallingInterfaceSmi(which, 0, args, res);
278  //1 = pass not installed, 3 = pass not installed, and only setable by an admin
279  if( (res[0] & 0xFF) == 1 || ( res[0] & 0xFF ) == 3)
280  return false;
281  return true;
282  }
283  catch(const exception &)
284  {
285  //if we caught any exceptions, try the next method
286  }
287  u8 max,min,props;
288  return getPasswordPropertiesII(which,max,min,props);
289  }
290 
291  static u32 getAuthenticationKeyII(const string &password)
292  {
293  u32 authKey = 0;
294 
295  DCERR( "getAuthenticationKeyII()" << endl );
296 
297  u16 toCheck[2] = { class_admin_password, class_user_password };
298  DCERR( " trying auth keys" << endl);
299 
300  // try admin password first, then user password
301  for( int i=0; i<2; i++ )
302  {
303  DCERR( " trying class code: " << toCheck[i] << endl);
304 
305  u8 maxLen=0, minLen=0, props=0;
306  // try next password type if no password set
307  try
308  {
309  if( ! getPasswordPropertiesII(toCheck[i], maxLen, minLen, props) )
310  continue;
311  }
312  catch( const exception & )
313  {
314  // usually get here for unsupported SMI exception.
315  // in which case, it makes no sense to continue
316  //DCERR( " Caught something." << e.what() << endl);
317  continue;
318  }
319 
320  DCERR("has a password." << hex << endl);
321  DCERR( " max len: " << (int)maxLen << endl);
322  DCERR( " min len: " << (int)minLen << endl);
323  DCERR( " props : " << hex << props << endl);
324 
325  u32 args[4] = {0,};
326  // select 4 == verify password
327  std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(setupCallingInterfaceSmi(toCheck[i], 4, args));
328  smi->setBufferContents(reinterpret_cast<const u8*>(password.c_str()), strnlen(password.c_str(), maxLen));
329  smi->setArgAsPhysicalAddress( 0, 0 );
330  smi->execute();
331 
332  DCERR("after verify:"<< endl);
333  DCERR("res[0]: " << smi->getRes(0) << endl; );
334  DCERR("res[1]: " << smi->getRes(1) << endl; );
335  DCERR("res[2]: " << smi->getRes(2) << endl; );
336  DCERR("res[3]: " << smi->getRes(3) << endl; );
337 
338  if(! smi->getRes(0))
339  authKey = smi->getRes(1);
340  else
341  throw PasswordVerificationFailedImpl("BIOS setup password enabled, but given password does not match.");
342 
343  // if this password is installed, no sense in checking the other, as it will not work.
344  // highest priority password always takes precedence
345  break;
346  }
347 
348  return authKey;
349  }
350 
351  u32 getAuthenticationKey(const string &password)
352  {
353  u32 authKey = 0;
354 
355  DCERR("getAuthenticationKey(" << password << ")" << endl);
356 
357  // try admin password first, then user password
358  u16 toCheck[2] = { class_admin_password, class_user_password };
359  DCERR(" trying auth keys" << endl);
360 
361  for( int i=0; i<2; i++ )
362  {
363  DCERR(" trying class code: " << toCheck[i] << endl);
364  try
365  {
366  u32 args[4] = {0,}, res[4] = {0,};
367  doSimpleCallingInterfaceSmi(toCheck[i], 0, args, res);
368 
369  // no password of this type installed if res[0] == 0
370  if( res[0] != 0 )
371  continue;
372  }
373  catch(const SmiException &)
374  {
375  // We should only get here under the following circumstances:
376  // - unsupported SMI call
377  // - unhandled SMI call
378  // - could not talk to dcdbas driver
379  continue;
380  }
381 
382  // If we get here, that means a password of type toCheck[i]
383  // is installed.
384  //
385  DCERR(" password installed" << endl);
386 
387  u32 args[4] = {0}, res[4] = {0,};
388  strncpy(reinterpret_cast<char *>(args), password.c_str(), 2 * sizeof(u32));
389 
390  DCERR(" args are : 0x" << args[0] << " 0x" << args[1] << " 0x" << args[2] << " 0x" << args[3] << endl);
391 
392  // if SMI above succeeded, this should too, no exception handling
393  doSimpleCallingInterfaceSmi(toCheck[i], 1, args, res);
394 
395  DCERR(" res was : 0x" << res[0] << " 0x" << res[1] << " 0x" << res[2] << " 0x" << res[3] << endl);
396  if( res[0] == 0 )
397  authKey = res[1];
398  else
399  throw PasswordVerificationFailedImpl("BIOS setup password enabled, but given password does not match.");
400 
401  // if this password is installed, no sense in checking the other, as it will not work.
402  // highest priority password always takes precedence
403  break;
404  }
405 
406  // if this didn't work, try other method.
407  if( ! authKey )
408  authKey = getAuthenticationKeyII( password );
409 
410  return authKey;
411  }
412 
414  {
416 
417  try
418  {
419  u32 args[4] = {0,}, res[4] = {0,};
421  format = PW_FORMAT_SCAN_CODE;
422  goto out;
423  }
424  catch(const exception &)
425  { }
426 
427  try
428  {
429  u32 args[4] = {0,}, res[4] = {0,};
431  format = PW_FORMAT_SCAN_CODE;
432  goto out;
433  }
434  catch(const exception &)
435  { }
436 
437  try
438  {
439  u8 maxLen=0, minLen=0, props=0;
440  getPasswordPropertiesII(class_admin_password, maxLen, minLen, props);
441  format = PW_FORMAT_SCAN_CODE;
442  if (props & 0x01)
443  format = PW_FORMAT_ASCII;
444  goto out;
445  }
446  catch(const exception &)
447  { }
448 
449  try
450  {
451  u8 maxLen=0, minLen=0, props=0;
452  getPasswordPropertiesII(class_user_password, maxLen, minLen, props);
453  format = PW_FORMAT_SCAN_CODE;
454  if (props & 0x01)
455  format = PW_FORMAT_ASCII;
456  goto out;
457  }
458  catch(const exception &)
459  { }
460 
461 out:
462  return format;
463  }
464 
465  static u32 readSetting(u16 select, u32 location, u32 *minValue, u32 *maxValue)
466  {
467  u32 args[4] = {location, 0,}, res[4] = {0,};
468  doSimpleCallingInterfaceSmi(0, select, args, res); // 0 == class code for setting/batter/ac/systemstatus
469  if(minValue)
470  *minValue = res[2];
471  if(maxValue)
472  *maxValue = res[3];
473  return res[1]; // current value
474  }
475 
476  u32 readNVStorage(u32 location, u32 *minValue, u32 *maxValue)
477  {
478  return readSetting(0, location, minValue, maxValue); // 0 = select code for nv storage
479  }
480 
481  u32 readBatteryModeSetting(u32 location, u32 *minValue, u32 *maxValue)
482  {
483  return readSetting(1, location, minValue, maxValue); // 1 = select code for battery mode
484  }
485 
486  u32 readACModeSetting(u32 location, u32 *minValue, u32 *maxValue)
487  {
488  return readSetting(2, location, minValue, maxValue); // 2 = select code for ac mode
489  }
490 
491  u32 readSystemStatus(u32 *failingSensorHandle)
492  {
493  // 3 = select code for system status
494  // 1st 0 == dummy location value
495  // 2nd 0 == dummy max value pointer
496  return readSetting(3, 0, failingSensorHandle, 0);
497  }
498 
499 
500  static u32 writeSetting(const std::string &password, u16 select, u32 location, u32 newValue, u32 *minValue, u32 *maxValue)
501  {
502  u32 args[4] = {location, newValue,}, res[4] = {0,};
503 
504  // go twice. Once without security key, once by trying password given.
505  for(int i=0; i<2; i++)
506  {
507  try
508  {
509  // 0 == class code for writing to setting/battery/ac/systemstatus
510  DCERR("Try #" << i << " for writeSetting()" << endl);
511  DCERR(" args are : 0x" << args[0] << " 0x" << args[1] << " 0x" << args[2] << " 0x" << args[3] << endl);
512  doSimpleCallingInterfaceSmi(1, select, args, res);
513  DCERR(" res was : 0x" << res[0] << " 0x" << res[1] << " 0x" << res[2] << " 0x" << res[3] << endl);
514  break;
515  }
516  catch(const SmiExecutedWithError &)
517  {
518  // on second time through, just pass exception upwards.
519  if(i==1)
520  throw;
521 
522  DCERR("Executed with error, try password..." << endl);
523  args[2] = getAuthenticationKey(password);
524  }
525  }
526 
527  if(minValue)
528  *minValue = res[2];
529  if(maxValue)
530  *maxValue = res[3];
531  return res[1]; // current value
532  }
533 
534  u32 writeNVStorage(const std::string &password, u32 location, u32 value, u32 *minValue, u32 *maxValue)
535  {
536  return writeSetting(password, 0, location, value, minValue, maxValue);
537  }
538 
539  u32 writeBatteryModeSetting(const std::string &password, u32 location, u32 value, u32 *minValue, u32 *maxValue)
540  {
541  return writeSetting(password, 1, location, value, minValue, maxValue);
542  }
543 
544  u32 writeACModeSetting(const std::string &password, u32 location, u32 value, u32 *minValue, u32 *maxValue)
545  {
546  return writeSetting(password, 2, location, value, minValue, maxValue);
547  }
548 
549  void getDisplayType(u32 &type, u32 &resolution, u32 &memSizeX256kb)
550  {
551  u32 args[4] = {0,}, res[4] = {0,};
552  doSimpleCallingInterfaceSmi(4, 0, args, res);
553 
554  type = (res[1] & 0x00FF);
555  resolution = (res[1] & 0xFF00) >> 8;
556  memSizeX256kb = res[2];
557  }
558 
559  void getPanelResolution(u32 &horiz, u32 &vert)
560  {
561  u32 args[4] = {0,}, res[4] = {0,};
562  doSimpleCallingInterfaceSmi(4, 1, args, res);
563 
564  horiz = (res[1] & 0x0000FFFF);
565  vert = (res[1] & 0xFFFF0000) >> 16;
566  }
567 
568  void getActiveDisplays(u32 &bits)
569  {
570  u32 args[4] = {0,}, res[4] = {0,};
571  doSimpleCallingInterfaceSmi(4, 2, args, res);
572 
573  bits = res[1];
574  }
575 
576  void setActiveDisplays(u32 &bits)
577  {
578  u32 args[4] = {bits, 0,}, res[4] = {0,};
579  doSimpleCallingInterfaceSmi(4, 3, args, res);
580  }
581 
582  void getPropertyOwnershipTag(char *tagBuf, size_t size)
583  {
584  u32 args[4] = {0,};
585  // class 20 == property tag
586  std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(setupCallingInterfaceSmi(20, 0, args));
587  smi->setBufferSize(80); // 80 is max len, making sure it doesn't overflow now. :-)
588  smi->setArgAsPhysicalAddress( 0, 0 );
589  smi->execute();
590  strncpy( tagBuf, reinterpret_cast<const char*>(smi->getBufferPtr()), size < 80? size:80);
591  tagBuf[size-1] = '\0';
592  }
593 
594  void setPropertyOwnershipTag(const string password, const char *newTag, size_t size)
595  {
596  u32 args[4] = {0,};
597 
598  for(int i=0; i<2; i++)
599  {
600  try
601  {
602  // class 20 == property tag
603  std::auto_ptr<smi::IDellCallingInterfaceSmi> smi(setupCallingInterfaceSmi(20, 1, args));
604  smi->setBufferSize(120); // 80 is max len, making sure it doesn't overflow now. :-)
605  smi->setBufferContents(reinterpret_cast<const u8*>(newTag), strnlen(newTag, 80));
606  smi->setArgAsPhysicalAddress( 0, 0 );
607  smi->execute();
608  break;
609  }
610  catch(const SmiExecutedWithError &)
611  {
612  // on second time through, just pass exception upwards.
613  if(i==1)
614  throw;
615 
616  //cout << "Caught error. Might be bad password. Trying password: " << password << endl;
617  args[1] = getAuthenticationKey(password);
618  }
619  }
620  }
621 
622 
623  // token list for wireless tokens. Probably not the best place for this,
624  // but until something better comes along...
625  const int Bluetooth_Devices_Disable = 0x0153; // docs appear to be wrong. They say 0x0152, but this looks backwards from reality
626  const int Bluetooth_Devices_Enable = 0x0152; // docs appear to be wrong. They say 0x0153, but this looks backwards from reality
627  const int Cellular_Radio_Disable = 0x017B;
628  const int Cellular_Radio_Enable = 0x017C;
629  const int WiFi_Locator_Disable = 0x017D;
630  const int WiFi_Locator_Enable = 0x017E;
631  const int Wireless_LAN_Disable = 0x017F;
632  const int Wireless_LAN_Enable = 0x0180;
639  const int Radio_Transmission_Enable = 0x010c;
640  const int Radio_Transmission_Disable = 0x010d;
641  const int Wireless_Device_Disable = 0x0114;
642  const int Wireless_Device_App_Control = 0x0115;
644 
645  // cbClass 17
646  // cbSelect 11
647  // WiFi Control
648  // Entry/return values grouped by the value of cbARG1, byte0 which indicates the function to perform:
649  // 0x1 = Set QuickSet Radio Disable Flag
650  // cbARG1, byte1 Radio ID value:
651  // 0 Radio Status
652  // 1 WLAN ID
653  // 2 BT ID
654  // 3 WWAN ID
655  // cbARG1, byte2 Flag bits:
656  // 0 QuickSet disables radio (1)
657  // 1-7 Reserved (0)
658  // cbRES1 Standard return codes (0, -1, -2)
659  // cbRES2 QuickSet (QS) radio disable bit map:
660  // 0 QS disables WLAN
661  // 1 QS disables BT
662  // 2 QS disables WWAN
663  // 3-31 Reserved (0)
664  void wirelessRadioControl(bool enable, bool boot, bool runtime, int enable_token, int disable_token, int radioNum, std::string password)
665  {
666  if (boot)
667  smbios::activateToken( (enable ?
668  enable_token :
669  disable_token),
670  password
671  );
672  if (runtime)
673  {
674  if (enable && !smbios::isTokenActive(enable_token))
675  throw ConfigErrorImpl("boot time config disabled, runtime setting has no effect.");
676 
677  u32 disable = enable ? 0:1;
678  u32 args[4] = {(1 | (static_cast<u32>(radioNum)<<8) | ((disable)<<16)), 0, 0, 0};
679  u32 res[4] = {0,};
680  doSimpleCallingInterfaceSmi(17, 11, args, res);
681  }
682  }
683 
684 
685  static void switchControl(u32 whichConfig, u32 whichSwitch, bool enable)
686  {
687  std::auto_ptr<smi::IDellCallingInterfaceSmi> smi = smi::SmiFactory::getFactory()->makeNew(smi::SmiFactory::DELL_CALLING_INTERFACE_SMI);
688  smi->setClass( 17 ); /* ? */
689  smi->setSelect( 11 ); /* WiFi Control */
690 
691  // 0x2 = Wireless Switch Configuration
692  // cbARG1, byte1 Subcommand:
693  // 0 Get config
694  // 1 Set config
695  // 2 Set WiFi locator enable/disable
696  // cbARG1,byte2 Switch settings (if byte 1==1):
697  // 0 WLAN switch control (1)
698  // 1 BT switch control (1)
699  // 2 WWAN switch control (1)
700  // 3-7 Reserved (0)
701  // cbARG1, byte2 Enable bits (if byte 1==2):
702  // 0 Enable WiFi locator (1)
703  // cbRES1 Standard return codes (0, -1, -2)
704  // cbRES2 QuickSet radio disable bit map:
705  // 0 WLAN controlled by switch (1)
706  // 1 BT controlled by switch (1)
707  // 2 WWAN controlled by switch (1)
708  // 3-6 Reserved (0)
709  // 7 Wireless switch config locked (1)
710  // 8 WiFi locator enabled (1)
711  // 9-14 Reserved (0)
712  // 15 WiFi locator setting locked (1)
713  // 16-31 Reserved (0)
714  smi->setArg(smi::cbARG1, 0x2);
715  smi->execute();
716 
717  u32 oldConfig = smi->getRes(smi::cbRES2);
718  if (whichConfig == 1)
719  oldConfig &= 0xFF;
720  else if (whichConfig == 2)
721  oldConfig = ((oldConfig>>8) & 0xFF);
722 
723  u32 newConfig = (oldConfig & ~whichSwitch) | ((enable?1:0) * whichSwitch);
724  smi->setArg(smi::cbARG1, (0x2 | (whichConfig << 8) | (newConfig << 16)));
725  smi->execute();
726  }
727 
728  void wirelessSwitchControl(bool enable, bool boot, bool runtime, int enable_token, int disable_token, int switchNum, std::string password)
729  {
730  int intSwitchConfig = 0, intSwitchNum = 0;
731  switch(switchNum)
732  {
733  case WLAN_SWITCH_CTL:
734  intSwitchConfig = 1;
735  intSwitchNum = 1;
736  break;
738  intSwitchConfig = 1;
739  intSwitchNum = 2;
740  break;
741  case WWAN_SWITCH_CTL:
742  intSwitchConfig = 1;
743  intSwitchNum = 4;
744  break;
745  case LOCATOR_SWITCH_CTL:
746  intSwitchConfig = 2;
747  intSwitchNum = 1;
748  break;
749  default:
750  throw ParameterErrorImpl("Invalid switch number passed to wirelessSwitchControl()");
751  }
752 
753  if (boot)
754  smbios::activateToken( (enable ?
755  enable_token :
756  disable_token),
757  password
758  );
759  if (runtime)
760  switchControl(intSwitchConfig, intSwitchNum, enable);
761  }
762 
763  radioStatusCode wirelessRadioStatus(radioNum which, std::ostream &cout, u32 defRes2)
764  {
766  try
767  {
768  u32 args[4] = {0,}, res[4] ={0,};
769  if (!defRes2)
770  smi::doSimpleCallingInterfaceSmi(17, 11, args, res);
771  else
772  res[smi::cbRES2] = defRes2;
773 
774  int supported_bit=0, installed_bit=0, disabled_bit=0;
775  string name;
776  switch(which)
777  {
778  case smi::WLAN_RADIO_NUM:
779  supported_bit = 2;
780  installed_bit = 8;
781  disabled_bit = 17;
782  name = "WLAN";
783  break;
785  supported_bit = 3;
786  installed_bit = 9;
787  disabled_bit = 18;
788  name = "Bluetooth";
789  break;
790  case smi::WWAN_RADIO_NUM:
791  supported_bit = 4;
792  installed_bit = 10;
793  disabled_bit = 19;
794  name = "WWAN";
795  break;
796  }
797 
798  cout << "Radio Status for " << name << ":" << endl;
799  if (res[smi::cbRES2] & (1 << supported_bit))
800  {
801  cout << "\t" << name << " supported" << endl;
802  cout << "\t" << name << " " << ((res[smi::cbRES2] & (1 << installed_bit)) ? "installed":"not installed") << endl;
803  cout << "\t" << name << " " << ((res[smi::cbRES2] & (1 << disabled_bit)) ? "disabled" : "enabled") << endl;
804 
805  ret = STATUS_DISABLED;
806  if (!(res[smi::cbRES2] & (1 << installed_bit)))
807  ret = STATUS_NOT_PRESENT;
808  else if (!(res[smi::cbRES2] & (1 << disabled_bit)))
809  ret = STATUS_ENABLED;
810  } else {
811  cout << "\t" << name << " not supported" << endl;
812  ret = STATUS_UNSUPPORTED;
813  }
814  cout << "\tStatus Code: " << ret << endl;
815  } catch (smi::UnsupportedSmi &) {
816  // this interface not available...
817  }
818  return ret;
819  }
820 
821 }