00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "opcmciasystem.h"
00031 using namespace Opie::Core;
00032
00033
00034 #include <opie2/odebug.h>
00035
00036
00037 #include <qfile.h>
00038 #include <qtextstream.h>
00039
00040
00041 #include <errno.h>
00042 #include <fcntl.h>
00043 #include <string.h>
00044 #include <stdlib.h>
00045 #include <sys/ioctl.h>
00046 #include <sys/types.h>
00047 #include <sys/stat.h>
00048 #include <unistd.h>
00049
00050 #define PROC_DEVICES "/proc/devices"
00051
00052
00053
00054
00055
00056 OPcmciaSystem* OPcmciaSystem::_instance = 0;
00057
00058 OPcmciaSystem::OPcmciaSystem()
00059 :_major( 0 )
00060 {
00061 qDebug( "OPcmciaSystem::OPcmciaSystem()" );
00062
00063
00064 QFile procfile( PROC_DEVICES );
00065 if ( procfile.exists() && procfile.open( IO_ReadOnly ) )
00066 {
00067 QTextStream devstream( &procfile );
00068 devstream.readLine();
00069 while ( !devstream.atEnd() && !_major )
00070 {
00071 int nodenumber;
00072 QString driver;
00073 devstream >> nodenumber >> driver;
00074 if ( driver == "pcmcia" )
00075 {
00076 qDebug( "OPcmciaSystem::OPcmciaSystem(): gotcha! pcmcia node number = %d", nodenumber );
00077 _major = nodenumber;
00078 break;
00079 }
00080 }
00081 }
00082 else
00083 {
00084 qWarning( "OPcmciaSystem::OPcmciaSystem() - can't open /proc/devices - continuing with limited functionality." );
00085 }
00086
00087 synchronize();
00088 }
00089
00090 void OPcmciaSystem::synchronize()
00091 {
00092 qDebug( "OPcmciaSystem::synchronize()" );
00093 _interfaces.clear();
00094
00095
00096
00097
00098
00099
00100 QString fileName;
00101 if ( QFile::exists( "/var/run/stab" ) ) { fileName = "/var/run/stab"; }
00102 else if ( QFile::exists( "/var/state/pcmcia/stab" ) ) { fileName = "/var/state/pcmcia/stab"; }
00103 else { fileName = "/var/lib/pcmcia/stab"; }
00104 QFile cardinfofile( fileName );
00105 if ( !cardinfofile.exists() || !cardinfofile.open( IO_ReadOnly ) )
00106 {
00107 qWarning( "pcmcia info file not found or unaccessible" );
00108 return;
00109 }
00110 QTextStream cardinfo( &cardinfofile );
00111 while ( !cardinfo.atEnd() )
00112 {
00113 QString strSocket;
00114 int numSocket;
00115 char colon;
00116 QString cardName;
00117 cardinfo >> strSocket >> numSocket >> colon;
00118 cardName = cardinfo.readLine().stripWhiteSpace();
00119 qDebug( "strSocket = '%s', numSocket = '%d', colon = '%c', cardName = '%s'", (const char*) strSocket, numSocket, colon, ( const char*) cardName );
00120 if ( strSocket == "Socket" && colon == ':' )
00121 {
00122 _interfaces.append( new OPcmciaSocket( _major, numSocket, this, (const char*) cardName ) );
00123 }
00124 else
00125 {
00126 continue;
00127 }
00128 }
00129 }
00130
00131
00132 int OPcmciaSystem::count() const
00133 {
00134 return _interfaces.count();
00135 }
00136
00137
00138 int OPcmciaSystem::cardCount() const
00139 {
00140 int nonEmpty = 0;
00141 OPcmciaSystem::CardIterator it = iterator();
00142 while ( it.current() )
00143 {
00144 if ( !it.current()->isEmpty() ) nonEmpty++;
00145 ++it;
00146 }
00147 return nonEmpty;
00148 }
00149
00150
00151 OPcmciaSocket* OPcmciaSystem::socket( unsigned int number )
00152 {
00153 return _interfaces.at( number );
00154 }
00155
00156
00157 void OPcmciaSystem::restart()
00158 {
00159
00160 ::system( "/etc/init.d/pcmcia restart" );
00161 }
00162
00163
00164 OPcmciaSystem* OPcmciaSystem::instance()
00165 {
00166 if ( !_instance ) _instance = new OPcmciaSystem();
00167 return _instance;
00168 }
00169
00170
00171 OPcmciaSystem::CardIterator OPcmciaSystem::iterator() const
00172 {
00173 return OPcmciaSystem::CardIterator( _interfaces );
00174 }
00175
00176
00177
00178
00179
00180
00181 OPcmciaSocket::OPcmciaSocket( int major, int socket, QObject* parent, const char* name )
00182 :QObject( parent, name ), _major( major ), _socket( socket )
00183 {
00184 qDebug( "OPcmciaSocket::OPcmciaSocket()" );
00185 init();
00186 }
00187
00188
00189 OPcmciaSocket::~OPcmciaSocket()
00190 {
00191 qDebug( "OPcmciaSocket::~OPcmciaSocket()" );
00192 cleanup();
00193 }
00194
00195
00196 void OPcmciaSocket::init()
00197 {
00198
00199 if ( _major )
00200 {
00201 dev_t dev = makedev( _major, _socket );
00202
00203 #ifdef OPCMCIA_DEBUG
00204 QString filename = "/tmp/opcmciasystem-debug";
00205 if ( QFile::exists( filename ) )
00206 #else
00207 QString filename = QString().sprintf( "/tmp/opcmciasystem-%d", ::getpid() );
00208 if ( ::mknod( (const char*) filename, ( S_IFCHR|S_IREAD|S_IWRITE ), dev ) == 0 )
00209 #endif
00210 {
00211 _fd = ::open( (const char*) filename, O_RDONLY);
00212 if ( !_fd )
00213 {
00214 qWarning( "OPcmciaSocket::init() - can't open control socket (%s)", strerror( errno ) );
00215 }
00216 #ifndef OPCMCIA_DEBUG
00217 else
00218 {
00219 ::unlink( (const char*) filename );
00220 }
00221 #endif
00222 }
00223 else
00224 {
00225 qWarning( "OPcmciaSocket::init() - can't create device node '%s' (%s)", (const char*) filename, strerror( errno ) );
00226 }
00227 }
00228 }
00229
00230 void OPcmciaSocket::cleanup()
00231 {
00232
00233 }
00234
00235 bool OPcmciaSocket::getTuple( cisdata_t tuple ) const
00236 {
00237 _ioctlarg.tuple.DesiredTuple = tuple;
00238 _ioctlarg.tuple.Attributes = TUPLE_RETURN_COMMON;
00239 _ioctlarg.tuple.TupleOffset = 0;
00240
00241 int result;
00242 result = ::ioctl(_fd, DS_GET_FIRST_TUPLE, &_ioctlarg);
00243 if ( result != 0 )
00244 {
00245 qWarning( "OPcmciaSocket::getTuple() - DS_GET_FIRST_TUPLE failed (%s)", strerror( errno ) );
00246 return false;
00247 }
00248
00249 result = ::ioctl(_fd, DS_GET_TUPLE_DATA, &_ioctlarg);
00250 if ( result != 0 )
00251 {
00252 qWarning( "OPcmciaSocket::getTuple() - DS_GET_TUPLE_DATA failed (%s)", strerror( errno ) );
00253 return false;
00254 }
00255
00256 result = ::ioctl( _fd, DS_PARSE_TUPLE, &_ioctlarg );
00257 if ( result != 0 )
00258 {
00259 qWarning( "OPcmciaSocket::getTuple() - DS_PARSE_TUPLE failed (%s)", strerror( errno ) );
00260 return false;
00261 }
00262
00263 return true;
00264 }
00265
00266
00267 int OPcmciaSocket::number() const
00268 {
00269 return _socket;
00270 }
00271
00272
00273 QString OPcmciaSocket::identity() const
00274 {
00275 return ( strcmp( name(), "empty" ) == 0 ) ? "<Empty Socket>" : name();
00276 }
00277
00278
00279 const OPcmciaSocket::OPcmciaSocketCardStatus OPcmciaSocket::status() const
00280 {
00281 cs_status_t cs_status;
00282 cs_status.Function = 0;
00283 int result = ::ioctl( _fd, DS_GET_STATUS, &cs_status );
00284 if ( result != 0 )
00285 {
00286 qWarning( "OPcmciaSocket::status() - DS_GET_STATUS failed (%s)", strerror( errno ) );
00287
00288 return Unknown;
00289 }
00290 else
00291 {
00292 qDebug( " card status = 0x%08x", cs_status.CardState );
00293 qDebug( " socket status = 0x%08x", cs_status.SocketState );
00294 return (OPcmciaSocket::OPcmciaSocketCardStatus) (cs_status.CardState + cs_status.SocketState);
00295 }
00296 }
00297
00298
00299 bool OPcmciaSocket::isUnsupported() const
00300 {
00301 return ( strcmp( name(), "unsupported card" ) == 0 );
00302 }
00303
00304
00305 bool OPcmciaSocket::isEmpty() const
00306 {
00307 return !(status() & ( Occupied | OccupiedCardBus ));
00308 }
00309
00310
00311 bool OPcmciaSocket::isSuspended() const
00312 {
00313 return status() & Suspended;
00314 }
00315
00316
00317 bool OPcmciaSocket::eject()
00318 {
00319 return ::ioctl( _fd, DS_EJECT_CARD ) != -1;
00320 }
00321
00322
00323 bool OPcmciaSocket::insert()
00324 {
00325 return ::ioctl( _fd, DS_INSERT_CARD ) != -1;
00326 }
00327
00328
00329 bool OPcmciaSocket::suspend()
00330 {
00331 return ::ioctl( _fd, DS_SUSPEND_CARD ) != -1;
00332 }
00333
00334
00335 bool OPcmciaSocket::resume()
00336 {
00337 return ::ioctl( _fd, DS_RESUME_CARD ) != -1;
00338 }
00339
00340
00341 bool OPcmciaSocket::reset()
00342 {
00343 return ::ioctl( _fd, DS_RESET_CARD ) != -1;
00344 }
00345
00346
00347 QStringList OPcmciaSocket::productIdentityVector() const
00348 {
00349 QStringList list;
00350 cistpl_vers_1_t *vers = &_ioctlarg.tuple_parse.parse.version_1;
00351 vers->ns = 0;
00352 if ( getTuple( CISTPL_VERS_1 ) )
00353 {
00354 qDebug( " NUMBER_OF_PRODIDs = %d", vers->ns );
00355 for ( int i = 0; i < QMIN( CISTPL_VERS_1_MAX_PROD_STRINGS, vers->ns ); ++i )
00356 {
00357 qDebug( " PRODID = '%s'", vers->str+vers->ofs[i] );
00358 list += vers->str+vers->ofs[i];
00359 }
00360 }
00361 else
00362 {
00363 list += "<unknown>";
00364 }
00365 return list;
00366 }
00367
00368
00369 QString OPcmciaSocket::productIdentity() const
00370 {
00371 return productIdentityVector().join( " " ).stripWhiteSpace();
00372 }
00373
00374
00375 QString OPcmciaSocket::manufacturerIdentity() const
00376 {
00377 cistpl_manfid_t *manfid = &_ioctlarg.tuple_parse.parse.manfid;
00378 if ( getTuple( CISTPL_MANFID ) )
00379 {
00380 return QString().sprintf( "0x%04x, 0x%04x", manfid->manf, manfid->card );
00381 }
00382 else
00383 return "<unknown>";
00384 }
00385
00386
00387 QString OPcmciaSocket::function() const
00388 {
00389 cistpl_funcid_t *funcid = &_ioctlarg.tuple_parse.parse.funcid;
00390 if ( getTuple( CISTPL_FUNCID ) )
00391 {
00392 switch ( funcid->func )
00393 {
00394 case 0: return "Multifunction"; break;
00395 case 1: return "Memory"; break;
00396 case 2: return "Serial"; break;
00397 case 3: return "Parallel"; break;
00398 case 4: return "Fixed Disk"; break;
00399 case 5: return "Video"; break;
00400 case 6: return "Network"; break;
00401 case 7: return "AIMS"; break;
00402 case 8: return "SCSI"; break;
00403 default: return "<unknown>"; break;
00404 }
00405 }
00406 else
00407 {
00408 return "<unknown>";
00409 }
00410 }