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 #include <QTimer>
00027 #include <QFile>
00028 #include <QRegExp>
00029
00030 #include <QTextStream>
00031 #include <Q3MemArray>
00032
00033 #include <klocale.h>
00034 #include <kcomponentdata.h>
00035 #include <kstandarddirs.h>
00036
00037
00038 #include "kpcmcia.h"
00039
00040
00041 #ifdef __linux__
00042 extern "C" {
00043 #include <sys/types.h>
00044 #include <unistd.h>
00045 #include <fcntl.h>
00046 #include <sys/stat.h>
00047 #include <sys/ioctl.h>
00048 #include <sys/file.h>
00049 #include <sys/time.h>
00050 #include "linux/version.h"
00051 #include "linux/cs_types.h"
00052 #include "linux/cs.h"
00053 #include "linux/cistpl.h"
00054 #include "linux/ds.h"
00055 }
00056
00057
00058 typedef struct event_tag_t {
00059 event_t event;
00060 const char *name;
00061 } event_tag_t;
00062
00063
00064 static event_tag_t event_tag[] = {
00065 { CS_EVENT_CARD_INSERTION, "card insertion" },
00066 { CS_EVENT_CARD_REMOVAL, "card removal" },
00067 { CS_EVENT_RESET_PHYSICAL, "prepare for reset" },
00068 { CS_EVENT_CARD_RESET, "card reset successful" },
00069 { CS_EVENT_RESET_COMPLETE, "reset request complete" },
00070 { CS_EVENT_EJECTION_REQUEST, "user eject request" },
00071 { CS_EVENT_INSERTION_REQUEST, "user insert request" },
00072 { CS_EVENT_PM_SUSPEND, "suspend card" },
00073 { CS_EVENT_PM_RESUME, "resume card" },
00074 { CS_EVENT_REQUEST_ATTENTION, "request attention" }
00075 };
00076
00077 #define NTAGS (sizeof(event_tag)/sizeof(event_tag_t))
00078
00079 static int lookupDevice(const char *x);
00080 static int openDevice(dev_t dev);
00081
00082 #else
00083 #include <unistd.h>
00084 #endif
00085
00086
00087
00088 KPCMCIACard::KPCMCIACard() {
00089 _fd = -1;
00090 _num = 9999999;
00091 _status = 0;
00092 _last = 0;
00093 _interrupt = -1;
00094 _ports = "";
00095 _device = "";
00096 _module = "";
00097 _type = "";
00098 _iotype = 0;
00099 _cardname = i18n("Empty slot.");
00100 _vcc = _vpp = _vpp2 = 0;
00101 _inttype = 0;
00102 _cfgbase = 0;
00103 }
00104
00105
00106 KPCMCIACard::~KPCMCIACard() {
00107 if (_fd != -1) close(_fd);
00108 }
00109
00110
00111
00112
00113
00114
00115
00116 int KPCMCIACard::refresh() {
00120 #ifdef __linux__
00121 struct timeval tv;
00122 cs_status_t status;
00123 fd_set rfds;
00124 int rc;
00125 event_t event;
00126 struct stat sb;
00127 config_info_t cfg;
00128 KPCMCIACard oldValues(*this);
00129 int updated = 0;
00130 oldValues._fd = -1;
00131
00132 #define CHECK_CHANGED(x, y) do { if (x.y != y) updated = 1; } while(0)
00133
00137 tv.tv_sec = 0; tv.tv_usec = 0;
00138 FD_ZERO(&rfds);
00139 FD_SET(_fd, &rfds);
00140 rc = select(_fd+1, &rfds, NULL, NULL, &tv);
00141 if (rc > 0) {
00142 rc = read(_fd, (void *)&event, 4);
00143 if (rc == 4) {
00144 int thisEvent = -1;
00145 for (unsigned int j = 0; j < NTAGS; j++) {
00146 if (event_tag[j].event == event) {
00147 thisEvent = j;
00148 break;
00149 }
00150 if (thisEvent < 0) return -1;
00151 }
00152 } else {
00153 return -1;
00154 }
00155 } else return updated;
00156
00157 if (event == CS_EVENT_EJECTION_REQUEST) {
00158 _interrupt = -1;
00159 _ports = "";
00160 _device = "";
00161 _module = "";
00162 _type = "";
00163 _iotype = 0;
00164 _inttype = 0;
00165 _cfgbase = 0;
00166 _cardname = i18n("Empty slot.");
00167 _vcc = _vpp = _vpp2 = 0;
00168 return updated;
00169 }
00170
00174 if (!stat(_stabPath.latin1(), &sb) && sb.st_mtime >= _last) {
00175 QFile f(_stabPath.latin1());
00176
00177 if (f.open(QIODevice::ReadOnly)) {
00178 QTextStream ts(&f);
00179 bool foundit = false;
00180 QString _thisreg = "^Socket %1: ";
00181 QRegExp thisreg ( _thisreg.arg(_num) );
00182
00183 if (flock(f.handle(), LOCK_SH)) return updated;
00184
00185 _last = sb.st_mtime;
00186
00187
00188 while(!foundit) {
00189 QString s;
00190 if (ts.eof()) break;
00191 s = ts.readLine();
00192 if (s.contains(thisreg)) {
00193 _cardname = s.right(s.length() - s.find(':') - 1);
00194 _cardname = _cardname.trimmed();
00195 foundit = true;
00196 CHECK_CHANGED(oldValues, _cardname);
00197 }
00198 }
00199
00200
00201 if (foundit && !ts.eof()) {
00202 QString s = ts.readLine();
00203 int end;
00204 s.simplified();
00205
00206 end = s.find(QRegExp("[ \r\t\n]"));
00207 s = s.remove(0, end+1);
00208
00209 end = s.find(QRegExp("[ \r\t\n]"));
00210 _type = s;
00211 _type.truncate(end);
00212 s = s.remove(0, end+1);
00213
00214 end = s.find(QRegExp("[ \r\t\n]"));
00215 _module = s;
00216 _module.truncate(end);
00217 s = s.remove(0, end+1);
00218
00219 end = s.find(QRegExp("[ \r\t\n]"));
00220 s = s.remove(0, end+1);
00221
00222 end = s.find(QRegExp("[ \r\t\n]"));
00223 _device = s;
00224 _device.truncate(end);
00225 s = s.remove(0, end+1);
00226 CHECK_CHANGED(oldValues, _type);
00227 CHECK_CHANGED(oldValues, _module);
00228 CHECK_CHANGED(oldValues, _device);
00229 }
00230
00231 flock(f.handle(), LOCK_UN);
00232 f.close();
00233 } else return -1;
00234 } else return updated;
00235
00236
00240 status.Function = 0;
00241 ioctl(_fd, DS_GET_STATUS, &status);
00242 memset(&cfg, 0, sizeof(cfg));
00243 ioctl(_fd, DS_GET_CONFIGURATION_INFO, &cfg);
00244
00245 if (cfg.Attributes & CONF_VALID_CLIENT) {
00246 if (cfg.AssignedIRQ == 0)
00247 _interrupt = -1;
00248 else _interrupt = cfg.AssignedIRQ;
00249
00250 if (cfg.NumPorts1 > 0) {
00251 int stop = cfg.BasePort1 + cfg.NumPorts1;
00252 if (cfg.NumPorts2 > 0) {
00253 if (stop == cfg.BasePort2) {
00254 _ports.sprintf("%#x-%#x", cfg.BasePort1, stop+cfg.NumPorts2-1);
00255 } else {
00256 _ports.sprintf("%#x-%#x, %#x-%#x", cfg.BasePort1, stop-1,
00257 cfg.BasePort2, cfg.BasePort2+cfg.NumPorts2-1);
00258 }
00259 } else {
00260 _ports.sprintf("%#x-%#x", cfg.BasePort1, stop-1);
00261 }
00262 }
00263 CHECK_CHANGED(oldValues, _ports);
00264 CHECK_CHANGED(oldValues, _interrupt);
00265 }
00266
00267 _vcc = cfg.Vcc;
00268 _vpp = cfg.Vpp1;
00269 _vpp2 = cfg.Vpp2;
00270 CHECK_CHANGED(oldValues, _vcc);
00271 CHECK_CHANGED(oldValues, _vpp);
00272 CHECK_CHANGED(oldValues, _vpp2);
00273 _inttype = cfg.IntType;
00274 CHECK_CHANGED(oldValues, _inttype);
00275 _iotype = cfg.IOAddrLines;
00276 CHECK_CHANGED(oldValues, _iotype);
00277 _cfgbase = cfg.ConfigBase;
00278 CHECK_CHANGED(oldValues, _cfgbase);
00279
00280 if (status.CardState & CS_EVENT_CARD_DETECT)
00281 _status |= CARD_STATUS_PRESENT;
00282 if (status.CardState & CS_EVENT_CARD_REMOVAL)
00283 _status &= ~CARD_STATUS_PRESENT;
00284 if (event & CS_EVENT_CARD_REMOVAL)
00285 _status &= ~CARD_STATUS_PRESENT;
00286
00287 if (!(status.CardState & CS_EVENT_PM_SUSPEND)) {
00288 if (status.CardState & CS_EVENT_READY_CHANGE) {
00289 _status |= CARD_STATUS_READY;
00290 _status &= ~(CARD_STATUS_BUSY|CARD_STATUS_SUSPEND);
00291 } else {
00292 _status |= CARD_STATUS_BUSY;
00293 _status &= ~(CARD_STATUS_READY|CARD_STATUS_SUSPEND);
00294 }
00295 } else if (status.CardState & CS_EVENT_PM_SUSPEND) {
00296 _status |= CARD_STATUS_SUSPEND;
00297 _status &= ~(CARD_STATUS_READY|CARD_STATUS_BUSY);
00298 }
00299
00300 CHECK_CHANGED(oldValues, _status);
00301
00302 return updated;
00303 #else
00304 return 0;
00305 #endif
00306 }
00307
00308
00309 int KPCMCIACard::insert() {
00310 #ifdef __linux__
00311 ioctl(_fd, DS_INSERT_CARD);
00312 return 0;
00313 #else
00314 return -1;
00315 #endif
00316 }
00317
00318
00319
00320 int KPCMCIACard::eject() {
00321 #ifdef __linux__
00322 ioctl(_fd, DS_EJECT_CARD);
00323 return 0;
00324 #else
00325 return -1;
00326 #endif
00327 }
00328
00329
00330
00331 int KPCMCIACard::reset() {
00332 #ifdef __linux__
00333 ioctl(_fd, DS_RESET_CARD);
00334 return 0;
00335 #else
00336 return -1;
00337 #endif
00338 }
00339
00340
00341
00342 int KPCMCIACard::suspend() {
00343 #ifdef __linux__
00344 ioctl(_fd, DS_SUSPEND_CARD);
00345 return 0;
00346 #else
00347 return -1;
00348 #endif
00349 }
00350
00351
00352
00353 int KPCMCIACard::resume() {
00354 #ifdef __linux__
00355 ioctl(_fd, DS_RESUME_CARD);
00356 return 0;
00357 #else
00358 return -1;
00359 #endif
00360 }
00361
00362
00363
00364
00365
00366 KPCMCIA::KPCMCIA(int maxSlots, const char *stabpath) : _maxSlots(maxSlots),
00367 _stabPath(stabpath) {
00368
00369 _refreshSpeed = 750;
00370
00371 _haveCardServices = false;
00372 _timer = new QTimer(this);
00373 connect(_timer, SIGNAL(timeout()), this, SLOT(updateCardInfo()));
00374 _cards = new Q3MemArray<KPCMCIACard *>(_maxSlots+1);
00375 _cardCnt = 0;
00376
00377
00379
00381 #ifdef __linux__
00382 servinfo_t serv;
00383
00384 int device = lookupDevice("pcmcia");
00385
00386 if (device >= 0) {
00387 for (int z = 0; z < _maxSlots; z++) {
00388 int fd = openDevice((device << 8) + z);
00389 if (fd < 0) break;
00390 (*_cards)[_cardCnt] = new KPCMCIACard;
00391 (*_cards)[_cardCnt]->_stabPath = _stabPath;
00392 (*_cards)[_cardCnt]->_fd = fd;
00393 (*_cards)[_cardCnt]->_num = _cardCnt;
00394
00395 _cardCnt++;
00396
00397 }
00398
00399 if (_cardCnt > 0) {
00400 if (ioctl((*_cards)[0]->_fd, DS_GET_CARD_SERVICES_INFO, &serv) == 0) {
00401
00402 }
00403 _haveCardServices = true;
00404 }
00405 }
00406
00407
00408
00409 _timer->start(_refreshSpeed, true);
00410
00412
00414 #else
00415
00416 #endif
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426 KPCMCIA::~KPCMCIA() {
00428
00430 #ifdef __linux__
00431
00432
00434
00436 #else
00437
00438 #endif
00439
00440
00441 delete _timer;
00442 delete _cards;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 KPCMCIACard* KPCMCIA::getCard(int num) {
00452 if (num >= _cardCnt || num < 0) return NULL;
00453 return (*_cards)[num];
00454 }
00455
00456
00457
00458
00459 void KPCMCIA::updateCardInfo() {
00460 for (int i = 0; i < _cardCnt; i++) {
00461 int rc = (*_cards)[i]->refresh();
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 if (rc > 0) emit cardUpdated(i);
00475 }
00476 _timer->start(_refreshSpeed, true);
00477 }
00478
00479
00480
00481 void KPCMCIA::setRefreshSpeed(int msec) {
00482 _refreshSpeed = msec;
00483 }
00484
00485
00486 int KPCMCIA::getCardCount() {
00487 return _cardCnt;
00488 }
00489
00490
00491 bool KPCMCIA::haveCardServices() {
00492 return _haveCardServices;
00493 }
00494
00495
00496 #include "kpcmcia.moc"
00497
00498
00499
00500 #ifdef __linux__
00501 static int lookupDevice(const char *x) {
00502 QFile df("/proc/devices");
00503 QString thisreg;
00504
00505 thisreg = "^[0-9]+ %1$";
00506 thisreg = thisreg.arg(x);
00507
00508 if (df.open(QIODevice::ReadOnly)) {
00509 QTextStream t(&df);
00510 QString s;
00511 while (!t.eof()) {
00512 s = t.readLine();
00513
00514 if (s.contains(QRegExp(thisreg))) {
00515 int n = (s.left(3).trimmed()).toInt();
00516 df.close();
00517 return n;
00518 }
00519 }
00520 df.close();
00521 }
00522 return -1;
00523 }
00524
00525 static int openDevice(dev_t dev) {
00526 QString tmp_path = locateLocal("tmp", KGlobal::mainComponent().componentName());
00527 QString ext = "_socket%1";
00528
00529 tmp_path += ext.arg((int)dev);
00530
00531 int rc = mknod(tmp_path.latin1(), (S_IFCHR | S_IREAD), dev);
00532 if (rc < 0) return -1;
00533
00534 int fd = open(tmp_path.latin1(), O_RDONLY);
00535 if (fd < 0) {
00536 unlink(tmp_path.latin1());
00537 return -1;
00538 }
00539
00540 if (unlink(tmp_path.latin1()) < 0) {
00541 close(fd);
00542 return -1;
00543 }
00544
00545 return fd;
00546 }
00547
00548 #endif
00549
00550