diff options
Diffstat (limited to 'klaptopdaemon/kpcmcia.cpp')
-rw-r--r-- | klaptopdaemon/kpcmcia.cpp | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/klaptopdaemon/kpcmcia.cpp b/klaptopdaemon/kpcmcia.cpp new file mode 100644 index 0000000..9dec605 --- /dev/null +++ b/klaptopdaemon/kpcmcia.cpp @@ -0,0 +1,547 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2001 George Staikos <staikos@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* + * Much of the linux code was migrated from: + * kardinfo Copyright 1999, Mirko Sucker <mirko.sucker@unibw-hamburg.de> + */ + +#include <qtimer.h> +#include <qfile.h> +#include <qregexp.h> + +#include <klocale.h> +#include <kinstance.h> +#include <kstandarddirs.h> + + +#include "kpcmcia.h" + + +#ifdef __linux__ + extern "C" { + #include <sys/types.h> + #include <unistd.h> + #include <fcntl.h> + #include <sys/stat.h> + #include <sys/ioctl.h> + #include <sys/file.h> + #include <sys/time.h> + #include "linux/version.h" + #include "linux/cs_types.h" + #include "linux/cs.h" + #include "linux/cistpl.h" + #include "linux/ds.h" + } + +// Taken from cardinfo.c +typedef struct event_tag_t { + event_t event; + const char *name; +} event_tag_t; + + +static event_tag_t event_tag[] = { + { CS_EVENT_CARD_INSERTION, "card insertion" }, + { CS_EVENT_CARD_REMOVAL, "card removal" }, + { CS_EVENT_RESET_PHYSICAL, "prepare for reset" }, + { CS_EVENT_CARD_RESET, "card reset successful" }, + { CS_EVENT_RESET_COMPLETE, "reset request complete" }, + { CS_EVENT_EJECTION_REQUEST, "user eject request" }, + { CS_EVENT_INSERTION_REQUEST, "user insert request" }, + { CS_EVENT_PM_SUSPEND, "suspend card" }, + { CS_EVENT_PM_RESUME, "resume card" }, + { CS_EVENT_REQUEST_ATTENTION, "request attention" } +}; + +#define NTAGS (sizeof(event_tag)/sizeof(event_tag_t)) + +static int lookupDevice(const char *x); +static int openDevice(dev_t dev); + +#else +#include <unistd.h> +#endif + + + +KPCMCIACard::KPCMCIACard() { + _fd = -1; + _num = 9999999; + _status = 0; + _last = 0; + _interrupt = -1; + _ports = ""; + _device = ""; + _module = ""; + _type = ""; + _iotype = 0; + _cardname = i18n("Empty slot."); + _vcc = _vpp = _vpp2 = 0; + _inttype = 0; + _cfgbase = 0; +} + + +KPCMCIACard::~KPCMCIACard() { + if (_fd != -1) close(_fd); +} + + + +// RETURN: <0 => error +// =0 => no error, no update +// >0 => no error, update happened +// +int KPCMCIACard::refresh() { +////////////////////////////////////////////// +///////////// LINUX ONLY +/////////////////////////////////////////////// +#ifdef __linux__ +struct timeval tv; +cs_status_t status; +fd_set rfds; +int rc; +event_t event; +struct stat sb; +config_info_t cfg; +KPCMCIACard oldValues(*this); +int updated = 0; +oldValues._fd = -1; + +#define CHECK_CHANGED(x, y) do { if (x.y != y) updated = 1; } while(0) + + /** + * Get any events on the pcmcia device + */ +tv.tv_sec = 0; tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(_fd, &rfds); + rc = select(_fd+1, &rfds, NULL, NULL, &tv); + if (rc > 0) { + rc = read(_fd, (void *)&event, 4); + if (rc == 4) { + int thisEvent = -1; // thisEvent is the index of event in event_tag + for (unsigned int j = 0; j < NTAGS; j++) { + if (event_tag[j].event == event) { + thisEvent = j; + break; + } + if (thisEvent < 0) return -1; + } + } else { + return -1; + } + } else return updated; + + if (event == CS_EVENT_EJECTION_REQUEST) { + _interrupt = -1; + _ports = ""; + _device = ""; + _module = ""; + _type = ""; + _iotype = 0; + _inttype = 0; + _cfgbase = 0; + _cardname = i18n("Empty slot."); + _vcc = _vpp = _vpp2 = 0; + return updated; + } + + /** + * Read in the stab file. + */ + if (!stat(_stabPath.latin1(), &sb) && sb.st_mtime >= _last) { + QFile f(_stabPath.latin1()); + + if (f.open(IO_ReadOnly)) { + QTextStream ts(&f); + bool foundit = false; + QString _thisreg = "^Socket %1: "; + QRegExp thisreg ( _thisreg.arg(_num) ); + + if (flock(f.handle(), LOCK_SH)) return updated; + + _last = sb.st_mtime; + + // find the card + while(!foundit) { + QString s; + if (ts.eof()) break; + s = ts.readLine(); + if (s.contains(thisreg)) { + _cardname = s.right(s.length() - s.find(':') - 1); + _cardname = _cardname.stripWhiteSpace(); + foundit = true; + CHECK_CHANGED(oldValues, _cardname); + } + } + + // read it in + if (foundit && !ts.eof()) { // FIXME: ts.eof() is a bad error!! + QString s = ts.readLine(); + int end; + s.simplifyWhiteSpace(); + + end = s.find(QRegExp("[ \r\t\n]")); + s = s.remove(0, end+1); + + end = s.find(QRegExp("[ \r\t\n]")); + _type = s; + _type.truncate(end); + s = s.remove(0, end+1); + + end = s.find(QRegExp("[ \r\t\n]")); + _module = s; + _module.truncate(end); + s = s.remove(0, end+1); + + end = s.find(QRegExp("[ \r\t\n]")); + s = s.remove(0, end+1); + + end = s.find(QRegExp("[ \r\t\n]")); + _device = s; + _device.truncate(end); + s = s.remove(0, end+1); + CHECK_CHANGED(oldValues, _type); + CHECK_CHANGED(oldValues, _module); + CHECK_CHANGED(oldValues, _device); + } + + flock(f.handle(), LOCK_UN); + f.close(); + } else return -1; + } else return updated; + + + /** + * Get the card's status and configuration information + */ + status.Function = 0; + ioctl(_fd, DS_GET_STATUS, &status); + memset(&cfg, 0, sizeof(cfg)); + ioctl(_fd, DS_GET_CONFIGURATION_INFO, &cfg); + // status is looked up in the table at the top + if (cfg.Attributes & CONF_VALID_CLIENT) { + if (cfg.AssignedIRQ == 0) + _interrupt = -1; + else _interrupt = cfg.AssignedIRQ; + + if (cfg.NumPorts1 > 0) { + int stop = cfg.BasePort1 + cfg.NumPorts1; + if (cfg.NumPorts2 > 0) { + if (stop == cfg.BasePort2) { + _ports.sprintf("%#x-%#x", cfg.BasePort1, stop+cfg.NumPorts2-1); + } else { + _ports.sprintf("%#x-%#x, %#x-%#x", cfg.BasePort1, stop-1, + cfg.BasePort2, cfg.BasePort2+cfg.NumPorts2-1); + } + } else { + _ports.sprintf("%#x-%#x", cfg.BasePort1, stop-1); + } + } + CHECK_CHANGED(oldValues, _ports); + CHECK_CHANGED(oldValues, _interrupt); + } + + _vcc = cfg.Vcc; + _vpp = cfg.Vpp1; + _vpp2 = cfg.Vpp2; + CHECK_CHANGED(oldValues, _vcc); + CHECK_CHANGED(oldValues, _vpp); + CHECK_CHANGED(oldValues, _vpp2); + _inttype = cfg.IntType; + CHECK_CHANGED(oldValues, _inttype); + _iotype = cfg.IOAddrLines; + CHECK_CHANGED(oldValues, _iotype); + _cfgbase = cfg.ConfigBase; + CHECK_CHANGED(oldValues, _cfgbase); + + if (status.CardState & CS_EVENT_CARD_DETECT) + _status |= CARD_STATUS_PRESENT; + if (status.CardState & CS_EVENT_CARD_REMOVAL) + _status &= ~CARD_STATUS_PRESENT; + if (event & CS_EVENT_CARD_REMOVAL) + _status &= ~CARD_STATUS_PRESENT; + + if (!(status.CardState & CS_EVENT_PM_SUSPEND)) { + if (status.CardState & CS_EVENT_READY_CHANGE) { + _status |= CARD_STATUS_READY; + _status &= ~(CARD_STATUS_BUSY|CARD_STATUS_SUSPEND); + } else { + _status |= CARD_STATUS_BUSY; + _status &= ~(CARD_STATUS_READY|CARD_STATUS_SUSPEND); + } + } else if (status.CardState & CS_EVENT_PM_SUSPEND) { + _status |= CARD_STATUS_SUSPEND; + _status &= ~(CARD_STATUS_READY|CARD_STATUS_BUSY); + } + + CHECK_CHANGED(oldValues, _status); + +return updated; +#else +return 0; +#endif +} + + +int KPCMCIACard::insert() { +#ifdef __linux__ + ioctl(_fd, DS_INSERT_CARD); + return 0; +#else + return -1; +#endif +} + + + +int KPCMCIACard::eject() { +#ifdef __linux__ + ioctl(_fd, DS_EJECT_CARD); + return 0; +#else + return -1; +#endif +} + + + +int KPCMCIACard::reset() { +#ifdef __linux__ + ioctl(_fd, DS_RESET_CARD); + return 0; +#else + return -1; +#endif +} + + + +int KPCMCIACard::suspend() { +#ifdef __linux__ + ioctl(_fd, DS_SUSPEND_CARD); + return 0; +#else + return -1; +#endif +} + + + +int KPCMCIACard::resume() { +#ifdef __linux__ + ioctl(_fd, DS_RESUME_CARD); + return 0; +#else + return -1; +#endif +} + + + + + +KPCMCIA::KPCMCIA(int maxSlots, const char *stabpath) : _maxSlots(maxSlots), + _stabPath(stabpath) { + +_refreshSpeed = 750; + +_haveCardServices = false; +_timer = new QTimer(this); +connect(_timer, SIGNAL(timeout()), this, SLOT(updateCardInfo())); +_cards = new QMemArray<KPCMCIACard *>(_maxSlots+1); +_cardCnt = 0; + + +/////////////////////////////////////////////////// +// LINUX code +/////////////////////////////////////////////////// +#ifdef __linux__ +servinfo_t serv; + + int device = lookupDevice("pcmcia"); + + if (device >= 0) { + for (int z = 0; z < _maxSlots; z++) { + int fd = openDevice((device << 8) + z); + if (fd < 0) break; + (*_cards)[_cardCnt] = new KPCMCIACard; + (*_cards)[_cardCnt]->_stabPath = _stabPath; + (*_cards)[_cardCnt]->_fd = fd; + (*_cards)[_cardCnt]->_num = _cardCnt; + //(*_cards)[_cardCnt]->refresh(); + _cardCnt++; + //kdDebug() << "Found a pcmcia slot" << endl; + } + + if (_cardCnt > 0) { + if (ioctl((*_cards)[0]->_fd, DS_GET_CARD_SERVICES_INFO, &serv) == 0) { + // FIXME: what to do here? + } + _haveCardServices = true; + } + } + + + +_timer->start(_refreshSpeed, true); + +/////////////////////////////////////////////////// +// No supported platform. +/////////////////////////////////////////////////// +#else + +#endif +} + + + + + + + + +KPCMCIA::~KPCMCIA() { +/////////////////////////////////////////////////// +// LINUX code +/////////////////////////////////////////////////// +#ifdef __linux__ + + +/////////////////////////////////////////////////// +// No supported platform. +/////////////////////////////////////////////////// +#else + +#endif + + +delete _timer; +delete _cards; +} + + + + + + + +KPCMCIACard* KPCMCIA::getCard(int num) { + if (num >= _cardCnt || num < 0) return NULL; + return (*_cards)[num]; +} + + + + +void KPCMCIA::updateCardInfo() { + for (int i = 0; i < _cardCnt; i++) { + int rc = (*_cards)[i]->refresh(); + /* + kdDebug() << "CARD UPDATED: " << i << endl + << " Name: " << (*_cards)[i]->_cardname << endl + << " Device: " << (*_cards)[i]->_device << endl + << " VCC: " << (*_cards)[i]->_vcc << endl + << " VPP: " << (*_cards)[i]->_vpp << endl + << " IRQ: " << (*_cards)[i]->_interrupt << endl + << " Ports: " << (*_cards)[i]->_ports << endl + << " Type: " << (*_cards)[i]->_type << endl + << " Module: " << (*_cards)[i]->_module << endl + << endl; + */ + if (rc > 0) emit cardUpdated(i); + } +_timer->start(_refreshSpeed, true); +} + + + +void KPCMCIA::setRefreshSpeed(int msec) { + _refreshSpeed = msec; +} + + +int KPCMCIA::getCardCount() { + return _cardCnt; +} + + +bool KPCMCIA::haveCardServices() { + return _haveCardServices; +} + + +#include "kpcmcia.moc" + + + +#ifdef __linux__ +static int lookupDevice(const char *x) { +QFile df("/proc/devices"); +QString thisreg; + + thisreg = "^[0-9]+ %1$"; + thisreg = thisreg.arg(x); + + if (df.open(IO_ReadOnly)) { + QTextStream t(&df); + QString s; + while (!t.eof()) { + s = t.readLine(); + + if (s.contains(QRegExp(thisreg))) { + int n = (s.left(3).stripWhiteSpace()).toInt(); + df.close(); + return n; + } + } + df.close(); + } +return -1; +} + +static int openDevice(dev_t dev) { +QString tmp_path = locateLocal("tmp", KGlobal::instance()->instanceName()); +QString ext = "_socket%1"; + + tmp_path += ext.arg((int)dev); + + int rc = mknod(tmp_path.latin1(), (S_IFCHR | S_IREAD), dev); + if (rc < 0) return -1; + + int fd = open(tmp_path.latin1(), O_RDONLY); + if (fd < 0) { + unlink(tmp_path.latin1()); + return -1; + } + + if (unlink(tmp_path.latin1()) < 0) { + close(fd); + return -1; + } + + return fd; +} + +#endif + + |