summaryrefslogtreecommitdiff
path: root/libopie2/opiecore
authormickeyl <mickeyl>2004-01-13 15:21:40 (UTC)
committer mickeyl <mickeyl>2004-01-13 15:21:40 (UTC)
commitaf79bda4c7e51f46abe67124f9c06126eaebb59d (patch) (unidiff)
tree4e9ad77ec4b2bb3d66ac6553d0a225b0b18f2140 /libopie2/opiecore
parent24eb97ec5cda3d72c3541fd120568b8d937025f8 (diff)
downloadopie-af79bda4c7e51f46abe67124f9c06126eaebb59d.zip
opie-af79bda4c7e51f46abe67124f9c06126eaebb59d.tar.gz
opie-af79bda4c7e51f46abe67124f9c06126eaebb59d.tar.bz2
- split odevice into dedicated files and classes, it has getting much too large
- merge odevice into libopie2 - merge oprocctrl and oprocess into libopie2
Diffstat (limited to 'libopie2/opiecore') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiecore/device/odevice.cpp623
-rw-r--r--libopie2/opiecore/device/odevice.h329
-rw-r--r--libopie2/opiecore/device/odevice_ipaq.cpp524
-rw-r--r--libopie2/opiecore/device/odevice_jornada.cpp214
-rw-r--r--libopie2/opiecore/device/odevice_ramses.cpp317
-rw-r--r--libopie2/opiecore/device/odevice_simpad.cpp443
-rw-r--r--libopie2/opiecore/device/odevice_yopy.cpp212
-rw-r--r--libopie2/opiecore/device/odevice_zaurus.cpp790
-rw-r--r--libopie2/opiecore/device/odevicebutton.cpp246
-rw-r--r--libopie2/opiecore/device/odevicebutton.h108
-rw-r--r--libopie2/opiecore/libopiecore2.control2
-rw-r--r--libopie2/opiecore/opiecore.pro16
-rw-r--r--libopie2/opiecore/oprocctrl.cpp284
-rw-r--r--libopie2/opiecore/oprocctrl.h121
-rw-r--r--libopie2/opiecore/oprocess.cpp970
-rw-r--r--libopie2/opiecore/oprocess.h747
16 files changed, 5944 insertions, 2 deletions
diff --git a/libopie2/opiecore/device/odevice.cpp b/libopie2/opiecore/device/odevice.cpp
new file mode 100644
index 0000000..0f88c3c
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice.cpp
@@ -0,0 +1,623 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include "odevice.h"
31
32/* QT */
33#include <qapplication.h>
34#include <qfile.h>
35#include <qtextstream.h>
36#include <qwindowsystem_qws.h>
37
38/* OPIE */
39#include <qpe/config.h>
40#include <qpe/resource.h>
41#include <qpe/sound.h>
42#include <qpe/qcopenvelope_qws.h>
43
44/* STD */
45#include <fcntl.h>
46#include <math.h>
47#include <stdlib.h>
48#include <signal.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <unistd.h>
52#ifndef QT_NO_SOUND
53#include <linux/soundcard.h>
54#endif
55
56#ifndef ARRAY_SIZE
57#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
58#endif
59
60// _IO and friends are only defined in kernel headers ...
61
62#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 ))
63
64#define OD_IO(type,number) OD_IOC(0,type,number,0)
65#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size))
66#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size))
67#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size))
68
69using namespace Opie;
70
71class iPAQ;
72class Zaurus;
73class SIMpad;
74class Ramses;
75class Jornada;
76
77ODevice *ODevice::inst()
78{
79 static ODevice *dev = 0;
80
81 // rewrite this to only use /proc/devinfo or so
82
83 /*
84 if ( !dev ) {
85 if ( QFile::exists ( "/proc/hal/model" ))
86 dev = new iPAQ();
87 else if ( Zaurus::isZaurus() )
88 dev = new Zaurus();
89 else if ( QFile::exists ( "/proc/ucb1x00" ) && QFile::exists ( "/proc/cs3" ))
90 dev = new SIMpad();
91 else if ( QFile::exists ( "/proc/sys/board/name" ))
92 dev = new Ramses();
93 else if ( Yopy::isYopy() )
94 dev = new Yopy();
95 else if ( Jornada::isJornada() )
96 dev = new Jornada();
97 else
98 dev = new ODevice();
99 dev->init();
100 }
101 */
102 return dev;
103}
104
105ODevice::ODevice()
106{
107 d = new ODeviceData;
108
109 d->m_modelstr = "Unknown";
110 d->m_model = Model_Unknown;
111 d->m_vendorstr = "Unknown";
112 d->m_vendor = Vendor_Unknown;
113 d->m_systemstr = "Unknown";
114 d->m_system = System_Unknown;
115 d->m_sysverstr = "0.0";
116 d->m_rotation = Rot0;
117 d->m_direction = CW;
118
119 d->m_holdtime = 1000; // 1000ms
120 d->m_buttons = 0;
121 d->m_cpu_frequencies = new QStrList;
122}
123
124void ODevice::systemMessage ( const QCString &msg, const QByteArray & )
125{
126 if ( msg == "deviceButtonMappingChanged()" ) {
127 reloadButtonMapping();
128 }
129}
130
131void ODevice::init()
132{
133}
134
135/**
136* This method initialises the button mapping
137*/
138void ODevice::initButtons()
139{
140 if ( d->m_buttons )
141 return;
142
143 qDebug ( "init Buttons" );
144 d->m_buttons = new QValueList <ODeviceButton>;
145
146 reloadButtonMapping();
147
148 QCopChannel *sysch = new QCopChannel ( "QPE/System", this );
149 connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & )));
150}
151
152ODevice::~ODevice()
153{
154// we leak m_devicebuttons and m_cpu_frequency
155// but it's a singleton and it is not so importantant
156// -zecke
157 delete d;
158}
159
160bool ODevice::setSoftSuspend ( bool /*soft*/ )
161{
162 return false;
163}
164
165//#include <linux/apm_bios.h>
166
167#define APM_IOC_SUSPEND OD_IO( 'A', 2 )
168
169/**
170* This method will try to suspend the device
171* It only works if the user is the QWS Server and the apm application
172* is installed.
173* It tries to suspend and then waits some time cause some distributions
174* do have asynchronus apm implementations.
175* This method will either fail and return false or it'll suspend the
176* device and return once the device got woken up
177*
178* @return if the device got suspended
179*/
180bool ODevice::suspend()
181{
182 qDebug("ODevice::suspend");
183 if ( !isQWS( ) ) // only qwsserver is allowed to suspend
184 return false;
185
186 if ( d->m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices
187 return false;
188
189 bool res = false;
190
191 struct timeval tvs, tvn;
192 ::gettimeofday ( &tvs, 0 );
193
194 ::sync(); // flush fs caches
195 res = ( ::system ( "apm --suspend" ) == 0 );
196
197 // This is needed because the iPAQ apm implementation is asynchronous and we
198 // can not be sure when exactly the device is really suspended
199 // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists.
200
201 if ( res ) {
202 do { // wait at most 1.5 sec: either suspend didn't work or the device resumed
203 ::usleep ( 200 * 1000 );
204 ::gettimeofday ( &tvn, 0 );
205 } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 1500 );
206 }
207
208 return res;
209}
210
211//#include <linux/fb.h> better not rely on kernel headers in userspace ...
212
213#define FBIOBLANK OD_IO( 'F', 0x11 ) // 0x4611
214
215/* VESA Blanking Levels */
216#define VESA_NO_BLANKING 0
217#define VESA_VSYNC_SUSPEND 1
218#define VESA_HSYNC_SUSPEND 2
219#define VESA_POWERDOWN 3
220
221/**
222* This sets the display on or off
223*/
224bool ODevice::setDisplayStatus ( bool on )
225{
226 qDebug("ODevice::setDisplayStatus(%d)", on);
227
228 if ( d->m_model == Model_Unknown )
229 return false;
230
231 bool res = false;
232 int fd;
233
234 if (( fd = ::open ( "/dev/fb0", O_RDWR )) >= 0 ) {
235 res = ( ::ioctl ( fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN ) == 0 );
236 ::close ( fd );
237 }
238 return res;
239}
240
241/**
242* This sets the display brightness
243*
244* @param p The brightness to be set on a scale from 0 to 255
245* @return success or failure
246*/
247bool ODevice::setDisplayBrightness ( int p)
248{
249 Q_UNUSED( p )
250 return false;
251}
252
253/**
254* @return returns the number of steppings on the brightness slider
255* in the Light-'n-Power settings.
256*/
257int ODevice::displayBrightnessResolution() const
258{
259 return 16;
260}
261
262/**
263* This sets the display contrast
264* @param p The contrast to be set on a scale from 0 to 255
265* @return success or failure
266*/
267bool ODevice::setDisplayContrast ( int p)
268{
269 Q_UNUSED( p )
270 return false;
271}
272
273/**
274* @return return the max value for the brightness settings slider
275* or 0 if the device doesn't support setting of a contrast
276*/
277int ODevice::displayContrastResolution() const
278{
279 return 0;
280}
281
282/**
283* This returns the vendor as string
284* @return Vendor as QString
285*/
286QString ODevice::vendorString() const
287{
288 return d->m_vendorstr;
289}
290
291/**
292* This returns the vendor as one of the values of OVendor
293* @return OVendor
294*/
295OVendor ODevice::vendor() const
296{
297 return d->m_vendor;
298}
299
300/**
301* This returns the model as a string
302* @return A string representing the model
303*/
304QString ODevice::modelString() const
305{
306 return d->m_modelstr;
307}
308
309/**
310* This does return the OModel used
311*/
312OModel ODevice::model() const
313{
314 return d->m_model;
315}
316
317/**
318* This does return the systen name
319*/
320QString ODevice::systemString() const
321{
322 return d->m_systemstr;
323}
324
325/**
326* Return System as OSystem value
327*/
328OSystem ODevice::system() const
329{
330 return d->m_system;
331}
332
333/**
334* @return the version string of the base system
335*/
336QString ODevice::systemVersionString() const
337{
338 return d->m_sysverstr;
339}
340
341/**
342* @return the current Transformation
343*/
344Transformation ODevice::rotation() const
345{
346 return d->m_rotation;
347}
348
349/**
350* @return the current rotation direction
351*/
352ODirection ODevice::direction() const
353{
354 return d->m_direction;
355}
356
357/**
358* This plays an alarmSound
359*/
360void ODevice::alarmSound()
361{
362#ifndef QT_NO_SOUND
363 static Sound snd ( "alarm" );
364
365 if ( snd. isFinished())
366 snd. play();
367#endif
368}
369
370/**
371* This plays a key sound
372*/
373void ODevice::keySound()
374{
375#ifndef QT_NO_SOUND
376 static Sound snd ( "keysound" );
377
378 if ( snd. isFinished())
379 snd. play();
380#endif
381}
382
383/**
384* This plays a touch sound
385*/
386void ODevice::touchSound()
387{
388#ifndef QT_NO_SOUND
389 static Sound snd ( "touchsound" );
390
391 if ( snd. isFinished())
392 snd. play();
393#endif
394}
395
396/**
397* This method will return a list of leds
398* available on this device
399* @return a list of LEDs.
400*/
401QValueList <OLed> ODevice::ledList() const
402{
403 return QValueList <OLed>();
404}
405
406/**
407* This does return the state of the LEDs
408*/
409QValueList <OLedState> ODevice::ledStateList ( OLed /*which*/ ) const
410{
411 return QValueList <OLedState>();
412}
413
414/**
415* @return the state for a given OLed
416*/
417OLedState ODevice::ledState ( OLed /*which*/ ) const
418{
419 return Led_Off;
420}
421
422/**
423* Set the state for a LED
424* @param which Which OLed to use
425* @param st The state to set
426* @return success or failure
427*/
428bool ODevice::setLedState ( OLed which, OLedState st )
429{
430 Q_UNUSED( which )
431 Q_UNUSED( st )
432 return false;
433}
434
435/**
436* @return if the device has a light sensor
437*/
438bool ODevice::hasLightSensor() const
439{
440 return false;
441}
442
443/**
444* @return a value from the light sensor
445*/
446int ODevice::readLightSensor()
447{
448 return -1;
449}
450
451/**
452* @return the light sensor resolution
453*/
454int ODevice::lightSensorResolution() const
455{
456 return 0;
457}
458
459/**
460* @return if the device has a hinge sensor
461*/
462bool ODevice::hasHingeSensor() const
463{
464 return false;
465}
466
467/**
468* @return a value from the hinge sensor
469*/
470OHingeStatus ODevice::readHingeSensor()
471{
472 return CASE_UNKNOWN;
473}
474
475/**
476* @return a list with CPU frequencies supported by the hardware
477*/
478const QStrList &ODevice::allowedCpuFrequencies() const
479{
480 return *d->m_cpu_frequencies;
481}
482
483
484/**
485* Set desired CPU frequency
486*
487* @param index index into d->m_cpu_frequencies of the frequency to be set
488*/
489bool ODevice::setCurrentCpuFrequency(uint index)
490{
491 if (index >= d->m_cpu_frequencies->count())
492 return false;
493
494 char *freq = d->m_cpu_frequencies->at(index);
495 qWarning("set freq to %s", freq);
496
497 int fd;
498
499 if ((fd = ::open("/proc/sys/cpu/0/speed", O_WRONLY)) >= 0) {
500 char writeCommand[50];
501 const int count = sprintf(writeCommand, "%s\n", freq);
502 int res = (::write(fd, writeCommand, count) != -1);
503 ::close(fd);
504 return res;
505 }
506
507 return false;
508}
509
510
511/**
512* @return a list of hardware buttons
513*/
514const QValueList <ODeviceButton> &ODevice::buttons()
515{
516 initButtons();
517
518 return *d->m_buttons;
519}
520
521/**
522* @return The amount of time that would count as a hold
523*/
524uint ODevice::buttonHoldTime() const
525{
526 return d->m_holdtime;
527}
528
529/**
530* This method return a ODeviceButton for a key code
531* or 0 if no special hardware button is available for the device
532*
533* @return The devicebutton or 0l
534* @see ODeviceButton
535*/
536const ODeviceButton *ODevice::buttonForKeycode ( ushort code )
537{
538 initButtons();
539
540 for ( QValueListConstIterator<ODeviceButton> it = d->m_buttons->begin(); it != d->m_buttons->end(); ++it ) {
541 if ( (*it). keycode() == code )
542 return &(*it);
543 }
544 return 0;
545}
546
547void ODevice::reloadButtonMapping()
548{
549 initButtons();
550
551 Config cfg ( "ButtonSettings" );
552
553 for ( uint i = 0; i < d->m_buttons->count(); i++ ) {
554 ODeviceButton &b = ( *d->m_buttons ) [i];
555 QString group = "Button" + QString::number ( i );
556
557 QCString pch, hch;
558 QCString pm, hm;
559 QByteArray pdata, hdata;
560
561 if ( cfg. hasGroup ( group )) {
562 cfg. setGroup ( group );
563 pch = cfg. readEntry ( "PressedActionChannel" ). latin1();
564 pm = cfg. readEntry ( "PressedActionMessage" ). latin1();
565 // pdata = decodeBase64 ( buttonFile. readEntry ( "PressedActionArgs" ));
566
567 hch = cfg. readEntry ( "HeldActionChannel" ). latin1();
568 hm = cfg. readEntry ( "HeldActionMessage" ). latin1();
569 // hdata = decodeBase64 ( buttonFile. readEntry ( "HeldActionArgs" ));
570 }
571
572 b. setPressedAction ( OQCopMessage ( pch, pm, pdata ));
573
574 b. setHeldAction ( OQCopMessage ( hch, hm, hdata ));
575 }
576}
577
578void ODevice::remapPressedAction ( int button, const OQCopMessage &action )
579{
580 initButtons();
581
582 QString mb_chan;
583
584 if ( button >= (int) d->m_buttons->count())
585 return;
586
587 ODeviceButton &b = ( *d->m_buttons ) [button];
588 b. setPressedAction ( action );
589
590 mb_chan=b. pressedAction(). channel();
591
592 Config buttonFile ( "ButtonSettings" );
593 buttonFile. setGroup ( "Button" + QString::number ( button ));
594 buttonFile. writeEntry ( "PressedActionChannel", (const char*) mb_chan);
595 buttonFile. writeEntry ( "PressedActionMessage", (const char*) b. pressedAction(). message());
596
597 //buttonFile. writeEntry ( "PressedActionArgs", encodeBase64 ( b. pressedAction(). data()));
598
599 QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" );
600}
601
602void ODevice::remapHeldAction ( int button, const OQCopMessage &action )
603{
604 initButtons();
605
606 if ( button >= (int) d->m_buttons->count())
607 return;
608
609 ODeviceButton &b = ( *d->m_buttons ) [button];
610 b. setHeldAction ( action );
611
612 Config buttonFile ( "ButtonSettings" );
613 buttonFile. setGroup ( "Button" + QString::number ( button ));
614 buttonFile. writeEntry ( "HeldActionChannel", (const char *) b. heldAction(). channel());
615 buttonFile. writeEntry ( "HeldActionMessage", (const char *) b. heldAction(). message());
616
617 //buttonFile. writeEntry ( "HeldActionArgs", decodeBase64 ( b. heldAction(). data()));
618
619 QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" );
620}
621void ODevice::virtual_hook(int, void* ){
622
623}
diff --git a/libopie2/opiecore/device/odevice.h b/libopie2/opiecore/device/odevice.h
new file mode 100644
index 0000000..bde6411
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice.h
@@ -0,0 +1,329 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#ifndef ODEVICE_H_
31#define ODEVICE_H_
32
33#include <opie2/odevicebutton.h>
34
35/* QT */
36#include <qnamespace.h>
37#include <qobject.h>
38#include <qstring.h>
39#include <qstrlist.h>
40
41#include <qpe/qpeapplication.h> /* for Transformation enum.. */
42
43namespace Opie
44{
45 class ODeviceData;
46/**
47 * The available devices
48 */
49enum OModel {
50 Model_Unknown, // = 0
51
52 Model_Series_Mask = 0xff000000,
53
54 Model_iPAQ = ( 1 << 24 ),
55
56 Model_iPAQ_All = ( Model_iPAQ | 0xffffff ),
57 Model_iPAQ_H31xx = ( Model_iPAQ | 0x000001 ),
58 Model_iPAQ_H36xx = ( Model_iPAQ | 0x000002 ),
59 Model_iPAQ_H37xx = ( Model_iPAQ | 0x000004 ),
60 Model_iPAQ_H38xx = ( Model_iPAQ | 0x000008 ),
61 Model_iPAQ_H39xx = ( Model_iPAQ | 0x000010 ),
62 Model_iPAQ_H5xxx = ( Model_iPAQ | 0x000011 ),
63
64 Model_Jornada = ( 6 << 24 ),
65 Model_Jornada_56x = ( Model_Jornada | 0x000001 ),
66
67 Model_Zaurus = ( 2 << 24 ),
68
69 Model_Zaurus_SL5000 = ( Model_Zaurus | 0x000001 ),
70 Model_Zaurus_SL5500 = ( Model_Zaurus | 0x000002 ),
71 Model_Zaurus_SLA300 = ( Model_Zaurus | 0x000003 ),
72 Model_Zaurus_SLB600 = ( Model_Zaurus | 0x000004 ),
73 Model_Zaurus_SLC7x0 = ( Model_Zaurus | 0x000005 ),
74
75 Model_SIMpad = ( 3 << 24 ),
76
77 Model_SIMpad_All = ( Model_SIMpad | 0xffffff ),
78 Model_SIMpad_CL4 = ( Model_SIMpad | 0x000001 ),
79 Model_SIMpad_SL4 = ( Model_SIMpad | 0x000002 ),
80 Model_SIMpad_SLC = ( Model_SIMpad | 0x000004 ),
81 Model_SIMpad_TSinus = ( Model_SIMpad | 0x000008 ),
82
83 Model_Ramses = ( 4 << 24 ),
84
85 Model_Ramses_All = ( Model_Ramses | 0xffffff ),
86 Model_Ramses_MNCI = ( Model_Ramses | 0x000001 ),
87
88 Model_Yopy = ( 5 << 24 ),
89
90 Model_Yopy_All = ( Model_Yopy | 0xffffff ),
91 Model_Yopy_3000 = ( Model_Yopy | 0x000001 ),
92 Model_Yopy_3500 = ( Model_Yopy | 0x000002 ),
93 Model_Yopy_3700 = ( Model_Yopy | 0x000003 ),
94
95};
96
97/**
98 * The vendor of the device
99 */
100enum OVendor {
101 Vendor_Unknown,
102
103 Vendor_HP,
104 Vendor_Sharp,
105 Vendor_SIEMENS,
106 Vendor_MundN,
107 Vendor_GMate,
108};
109
110/**
111 * The System used
112 */
113enum OSystem {
114 System_Unknown,
115
116 System_Familiar,
117 System_Zaurus,
118 System_OpenZaurus,
119 System_Linupy,
120};
121
122enum OLedState {
123 Led_Off,
124 Led_On,
125 Led_BlinkSlow,
126 Led_BlinkFast
127};
128
129enum OLed {
130 Led_Mail,
131 Led_Power,
132 Led_BlueTooth
133};
134
135enum OHardKey {
136 HardKey_Datebook = Qt::Key_F9,
137 HardKey_Contacts = Qt::Key_F10,
138 HardKey_Menu = Qt::Key_F11,
139 HardKey_Home = Qt::Key_F12,
140 HardKey_Mail = Qt::Key_F13,
141 HardKey_Record = Qt::Key_F24,
142 HardKey_Suspend = Qt::Key_F34,
143 HardKey_Backlight = Qt::Key_F35,
144 HardKey_Action = Qt::Key_F10,
145 HardKey_OK = Qt::Key_F11,
146 HardKey_End = Qt::Key_F12,
147};
148
149enum ODirection {
150 CW = 0,
151 CCW = 1,
152 Flip = 2,
153};
154
155enum OHingeStatus {
156 CASE_CLOSED = 3,
157 CASE_PORTRAIT = 2,
158 CASE_LANDSCAPE = 0,
159 CASE_UNKNOWN = 1,
160};
161
162/**
163 * A singleton which gives informations about device specefic option
164 * like the Hardware used, LEDs, the Base Distribution and
165 * hardware key mappings.
166 *
167 * @short A small class for device specefic options
168 * @see QObject
169 * @author Robert Griebl
170 * @version 1.0
171 */
172class ODevice : public QObject
173{
174 Q_OBJECT
175
176private:
177 /* disable copy */
178 ODevice ( const ODevice & );
179
180protected:
181 ODevice();
182 virtual void init();
183 virtual void initButtons();
184
185 ODeviceData *d;
186
187public:
188 // sandman do we want to allow destructions? -zecke?
189 virtual ~ODevice();
190
191 static ODevice *inst();
192
193 // information
194
195 QString modelString() const;
196 OModel model() const;
197 inline OModel series() const { return (OModel) ( model() & Model_Series_Mask ); }
198
199 QString vendorString() const;
200 OVendor vendor() const;
201
202 QString systemString() const;
203 OSystem system() const;
204
205 QString systemVersionString() const;
206
207 virtual Transformation rotation() const;
208 virtual ODirection direction() const;
209
210 // system
211
212 virtual bool setSoftSuspend ( bool on );
213 virtual bool suspend();
214
215 virtual bool setDisplayStatus ( bool on );
216 virtual bool setDisplayBrightness ( int brightness );
217 virtual int displayBrightnessResolution() const;
218 virtual bool setDisplayContrast ( int contrast );
219 virtual int displayContrastResolution() const;
220
221 // don't add new virtual methods, use this:
222 ///*virtual */ void boo(int i ) { return virtual_hook(1,&i); };
223 // and in your subclass do do overwrite
224 //protected virtual int virtual_hook(int, void *)
225 // which is defined below
226
227 // input / output
228 //FIXME playAlarmSound and al might be better -zecke
229 virtual void alarmSound();
230 virtual void keySound();
231 virtual void touchSound();
232
233 virtual QValueList <OLed> ledList() const;
234 virtual QValueList <OLedState> ledStateList ( OLed led ) const;
235 virtual OLedState ledState ( OLed led ) const;
236 virtual bool setLedState ( OLed led, OLedState st );
237
238 virtual bool hasLightSensor() const;
239 virtual int readLightSensor();
240 virtual int lightSensorResolution() const;
241
242 virtual bool hasHingeSensor() const;
243 virtual OHingeStatus readHingeSensor();
244
245 const QStrList &allowedCpuFrequencies() const;
246 bool setCurrentCpuFrequency(uint index);
247
248 /**
249 * Returns the available buttons on this device. The number and location
250 * of buttons will vary depending on the device. Button numbers will be assigned
251 * by the device manufacturer and will be from most preferred button to least preffered
252 * button. Note that this list only contains "user mappable" buttons.
253 */
254 const QValueList<ODeviceButton> &buttons() /* ### make const */;
255
256 /**
257 * Returns the DeviceButton for the \a keyCode. If \a keyCode is not found, it
258 * returns 0L
259 */
260 const ODeviceButton *buttonForKeycode ( ushort keyCode );
261
262 /**
263 * Reassigns the pressed action for \a button. To return to the factory
264 * default pass an empty string as \a qcopMessage.
265 */
266 void remapPressedAction ( int button, const OQCopMessage &qcopMessage );
267
268 /**
269 * Reassigns the held action for \a button. To return to the factory
270 * default pass an empty string as \a qcopMessage.
271 */
272 void remapHeldAction ( int button, const OQCopMessage &qcopMessage );
273
274 /**
275 * How long (in ms) you have to press a button for a "hold" action
276 */
277 uint buttonHoldTime() const;
278
279signals:
280 void buttonMappingChanged();
281
282private slots:
283 void systemMessage ( const QCString &, const QByteArray & );
284
285protected:
286 void reloadButtonMapping();
287 /* ugly virtual hook */
288 virtual void virtual_hook( int id, void* data );
289};
290
291class ODeviceData {
292
293 public:
294 QString m_vendorstr;
295 OVendor m_vendor;
296
297 QString m_modelstr;
298 OModel m_model;
299
300 QString m_systemstr;
301 OSystem m_system;
302
303 QString m_sysverstr;
304
305 Transformation m_rotation;
306 ODirection m_direction;
307
308 QValueList <ODeviceButton> *m_buttons;
309 uint m_holdtime;
310 QStrList *m_cpu_frequencies;
311};
312
313}
314
315static inline bool isQWS()
316{
317 return qApp ? ( qApp->type() == QApplication::GuiServer ) : false;
318}
319
320static QCString makeChannel ( const char *str )
321{
322 if ( str && !::strchr ( str, '/' ))
323 return QCString ( "QPE/Application/" ) + str;
324 else
325 return str;
326}
327
328#endif
329
diff --git a/libopie2/opiecore/device/odevice_ipaq.cpp b/libopie2/opiecore/device/odevice_ipaq.cpp
new file mode 100644
index 0000000..d928806
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice_ipaq.cpp
@@ -0,0 +1,524 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include "odevice.h"
31
32/* QT */
33#include <qapplication.h>
34#include <qfile.h>
35#include <qtextstream.h>
36#include <qwindowsystem_qws.h>
37
38/* OPIE */
39#include <qpe/config.h>
40#include <qpe/resource.h>
41#include <qpe/sound.h>
42#include <qpe/qcopenvelope_qws.h>
43
44/* STD */
45#include <fcntl.h>
46#include <math.h>
47#include <stdlib.h>
48#include <signal.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <unistd.h>
52#ifndef QT_NO_SOUND
53#include <linux/soundcard.h>
54#endif
55
56#ifndef ARRAY_SIZE
57#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
58#endif
59
60// _IO and friends are only defined in kernel headers ...
61
62#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 ))
63
64#define OD_IO(type,number) OD_IOC(0,type,number,0)
65#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size))
66#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size))
67#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size))
68
69typedef struct {
70 unsigned char OffOnBlink; /* 0=off 1=on 2=Blink */
71 unsigned char TotalTime; /* Units of 5 seconds */
72 unsigned char OnTime; /* units of 100m/s */
73 unsigned char OffTime; /* units of 100m/s */
74} LED_IN;
75
76typedef struct {
77 unsigned char mode;
78 unsigned char pwr;
79 unsigned char brightness;
80} FLITE_IN;
81
82#define LED_ON OD_IOW( 'f', 5, LED_IN )
83#define FLITE_ON OD_IOW( 'f', 7, FLITE_IN )
84
85using namespace Opie;
86
87class iPAQ : public ODevice, public QWSServer::KeyboardFilter
88{
89
90 protected:
91 virtual void init();
92 virtual void initButtons();
93
94 public:
95 virtual bool setSoftSuspend( bool soft );
96
97 virtual bool setDisplayBrightness( int b );
98 virtual int displayBrightnessResolution() const;
99
100 virtual void alarmSound();
101
102 virtual QValueList <OLed> ledList() const;
103 virtual QValueList <OLedState> ledStateList( OLed led ) const;
104 virtual OLedState ledState( OLed led ) const;
105 virtual bool setLedState( OLed led, OLedState st );
106
107 virtual bool hasLightSensor() const;
108 virtual int readLightSensor();
109 virtual int lightSensorResolution() const;
110
111 protected:
112 virtual bool filter( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat );
113 virtual void timerEvent( QTimerEvent *te );
114
115 int m_power_timer;
116
117 OLedState m_leds [2];
118};
119
120struct i_button {
121 uint model;
122 Qt::Key code;
123 char *utext;
124 char *pix;
125 char *fpressedservice;
126 char *fpressedaction;
127 char *fheldservice;
128 char *fheldaction;
129} ipaq_buttons [] = {
130 { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx,
131 Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"),
132 "devicebuttons/ipaq_calendar",
133 "datebook", "nextView()",
134 "today", "raise()" },
135 { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx,
136 Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"),
137 "devicebuttons/ipaq_contact",
138 "addressbook", "raise()",
139 "addressbook", "beamBusinessCard()" },
140 { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx,
141 Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"),
142 "devicebuttons/ipaq_menu",
143 "QPE/TaskBar", "toggleMenu()",
144 "QPE/TaskBar", "toggleStartMenu()" },
145 { Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx,
146 Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"),
147 "devicebuttons/ipaq_mail",
148 "mail", "raise()",
149 "mail", "newMail()" },
150 { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx,
151 Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"),
152 "devicebuttons/ipaq_home",
153 "QPE/Launcher", "home()",
154 "buttonsettings", "raise()" },
155 { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx,
156 Qt::Key_F24, QT_TRANSLATE_NOOP("Button", "Record Button"),
157 "devicebuttons/ipaq_record",
158 "QPE/VMemo", "toggleRecord()",
159 "sound", "raise()" },
160};
161
162void iPAQ::init()
163{
164 d->m_vendorstr = "HP";
165 d->m_vendor = Vendor_HP;
166
167 QFile f ( "/proc/hal/model" );
168
169 if ( f. open ( IO_ReadOnly )) {
170 QTextStream ts ( &f );
171
172 d->m_modelstr = "H" + ts. readLine();
173
174 if ( d->m_modelstr == "H3100" )
175 d->m_model = Model_iPAQ_H31xx;
176 else if ( d->m_modelstr == "H3600" )
177 d->m_model = Model_iPAQ_H36xx;
178 else if ( d->m_modelstr == "H3700" )
179 d->m_model = Model_iPAQ_H37xx;
180 else if ( d->m_modelstr == "H3800" )
181 d->m_model = Model_iPAQ_H38xx;
182 else if ( d->m_modelstr == "H3900" )
183 d->m_model = Model_iPAQ_H39xx;
184 else if ( d->m_modelstr == "H5400" )
185 d->m_model = Model_iPAQ_H5xxx;
186 else
187 d->m_model = Model_Unknown;
188
189 f. close();
190 }
191
192 switch ( d->m_model ) {
193 case Model_iPAQ_H31xx:
194 case Model_iPAQ_H38xx:
195 d->m_rotation = Rot90;
196 break;
197 case Model_iPAQ_H36xx:
198 case Model_iPAQ_H37xx:
199 case Model_iPAQ_H39xx:
200
201 default:
202 d->m_rotation = Rot270;
203 break;
204 case Model_iPAQ_H5xxx:
205 d->m_rotation = Rot0;
206 }
207
208 f. setName ( "/etc/familiar-version" );
209 if ( f. open ( IO_ReadOnly )) {
210 d->m_systemstr = "Familiar";
211 d->m_system = System_Familiar;
212
213 QTextStream ts ( &f );
214 d->m_sysverstr = ts. readLine(). mid ( 10 );
215
216 f. close();
217 } else {
218 f. setName ( "/etc/oz_version" );
219
220 if ( f. open ( IO_ReadOnly )) {
221 d->m_systemstr = "OpenEmbedded/iPaq";
222 d->m_system = System_Familiar;
223
224 QTextStream ts ( &f );
225 ts.setDevice ( &f );
226 d->m_sysverstr = ts. readLine();
227 f. close();
228 }
229 }
230
231 m_leds [0] = m_leds [1] = Led_Off;
232
233 m_power_timer = 0;
234
235}
236
237void iPAQ::initButtons()
238{
239 if ( d->m_buttons )
240 return;
241
242 if ( isQWS( ) )
243 QWSServer::setKeyboardFilter ( this );
244
245 d->m_buttons = new QValueList <ODeviceButton>;
246
247 for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) {
248 i_button *ib = ipaq_buttons + i;
249 ODeviceButton b;
250
251 if (( ib->model & d->m_model ) == d->m_model ) {
252 b. setKeycode ( ib->code );
253 b. setUserText ( QObject::tr ( "Button", ib->utext ));
254 b. setPixmap ( Resource::loadPixmap ( ib->pix ));
255 b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib->fpressedservice ), ib->fpressedaction ));
256 b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib->fheldservice ), ib->fheldaction ));
257
258 d->m_buttons->append ( b );
259 }
260 }
261 reloadButtonMapping();
262
263 QCopChannel *sysch = new QCopChannel ( "QPE/System", this );
264 connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & )));
265}
266
267QValueList <OLed> iPAQ::ledList() const
268{
269 QValueList <OLed> vl;
270 vl << Led_Power;
271
272 if ( d->m_model == Model_iPAQ_H38xx )
273 vl << Led_BlueTooth;
274 return vl;
275}
276
277QValueList <OLedState> iPAQ::ledStateList ( OLed l ) const
278{
279 QValueList <OLedState> vl;
280
281 if ( l == Led_Power )
282 vl << Led_Off << Led_On << Led_BlinkSlow << Led_BlinkFast;
283 else if ( l == Led_BlueTooth && d->m_model == Model_iPAQ_H38xx )
284 vl << Led_Off; // << Led_On << ???
285
286 return vl;
287}
288
289OLedState iPAQ::ledState ( OLed l ) const
290{
291 switch ( l ) {
292 case Led_Power:
293 return m_leds [0];
294 case Led_BlueTooth:
295 return m_leds [1];
296 default:
297 return Led_Off;
298 }
299}
300
301bool iPAQ::setLedState ( OLed l, OLedState st )
302{
303 static int fd = ::open ( "/dev/touchscreen/0", O_RDWR | O_NONBLOCK );
304
305 if ( l == Led_Power ) {
306 if ( fd >= 0 ) {
307 LED_IN leds;
308 ::memset ( &leds, 0, sizeof( leds ));
309 leds. TotalTime = 0;
310 leds. OnTime = 0;
311 leds. OffTime = 1;
312 leds. OffOnBlink = 2;
313
314 switch ( st ) {
315 case Led_Off : leds. OffOnBlink = 0; break;
316 case Led_On : leds. OffOnBlink = 1; break;
317 case Led_BlinkSlow: leds. OnTime = 10; leds. OffTime = 10; break;
318 case Led_BlinkFast: leds. OnTime = 5; leds. OffTime = 5; break;
319 }
320
321 if ( ::ioctl ( fd, LED_ON, &leds ) >= 0 ) {
322 m_leds [0] = st;
323 return true;
324 }
325 }
326 }
327 return false;
328}
329
330
331bool iPAQ::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat )
332{
333 int newkeycode = keycode;
334
335 switch ( keycode ) {
336 // H38xx/H39xx have no "Q" key anymore - this is now the Mail key
337 case HardKey_Menu: {
338 if (( d->m_model == Model_iPAQ_H38xx ) ||
339 ( d->m_model == Model_iPAQ_H39xx ) ||
340 ( d->m_model == Model_iPAQ_H5xxx)) {
341 newkeycode = HardKey_Mail;
342 }
343 break;
344 }
345
346 // Rotate cursor keys 180°
347 case Key_Left :
348 case Key_Right:
349 case Key_Up :
350 case Key_Down : {
351 if (( d->m_model == Model_iPAQ_H31xx ) ||
352 ( d->m_model == Model_iPAQ_H38xx )) {
353 newkeycode = Key_Left + ( keycode - Key_Left + 2 ) % 4;
354 }
355 break;
356 }
357
358 // map Power Button short/long press to F34/F35
359 case Key_SysReq: {
360 if ( isPress ) {
361 if ( m_power_timer )
362 killTimer ( m_power_timer );
363 m_power_timer = startTimer ( 500 );
364 }
365 else if ( m_power_timer ) {
366 killTimer ( m_power_timer );
367 m_power_timer = 0;
368 QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, true, false );
369 QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, false, false );
370 }
371 newkeycode = Key_unknown;
372 break;
373 }
374 }
375
376 if ( newkeycode != keycode ) {
377 if ( newkeycode != Key_unknown )
378 QWSServer::sendKeyEvent ( -1, newkeycode, modifiers, isPress, autoRepeat );
379 return true;
380 }
381 else
382 return false;
383}
384
385void iPAQ::timerEvent ( QTimerEvent * )
386{
387 killTimer ( m_power_timer );
388 m_power_timer = 0;
389 QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false );
390 QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false );
391}
392
393
394void iPAQ::alarmSound()
395{
396#ifndef QT_NO_SOUND
397 static Sound snd ( "alarm" );
398 int fd;
399 int vol;
400 bool vol_reset = false;
401
402 if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) {
403 if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) {
404 Config cfg ( "qpe" );
405 cfg. setGroup ( "Volume" );
406
407 int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 );
408 if ( volalarm < 0 )
409 volalarm = 0;
410 else if ( volalarm > 100 )
411 volalarm = 100;
412 volalarm |= ( volalarm << 8 );
413
414 if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 )
415 vol_reset = true;
416 }
417 }
418
419 snd. play();
420 while ( !snd. isFinished())
421 qApp->processEvents();
422
423 if ( fd >= 0 ) {
424 if ( vol_reset )
425 ::ioctl ( fd, MIXER_WRITE( 0 ), &vol );
426 ::close ( fd );
427 }
428#endif
429}
430
431
432bool iPAQ::setSoftSuspend ( bool soft )
433{
434 bool res = false;
435 int fd;
436
437 if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) {
438 if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 )
439 res = true;
440 else
441 ::perror ( "write to /proc/sys/ts/suspend_button_mode" );
442
443 ::close ( fd );
444 }
445 else
446 ::perror ( "/proc/sys/ts/suspend_button_mode" );
447
448 return res;
449}
450
451
452bool iPAQ::setDisplayBrightness ( int bright )
453{
454 bool res = false;
455 int fd;
456
457 if ( bright > 255 )
458 bright = 255;
459 if ( bright < 0 )
460 bright = 0;
461
462 if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) {
463 FLITE_IN bl;
464 bl. mode = 1;
465 bl. pwr = bright ? 1 : 0;
466 bl. brightness = ( bright * ( displayBrightnessResolution() - 1 ) + 127 ) / 255;
467 res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 );
468 ::close ( fd );
469 }
470 return res;
471}
472
473int iPAQ::displayBrightnessResolution() const
474{
475 switch ( model()) {
476 case Model_iPAQ_H31xx:
477 case Model_iPAQ_H36xx:
478 case Model_iPAQ_H37xx:
479 return 128; // really 256, but >128 could damage the LCD
480
481 case Model_iPAQ_H38xx:
482 case Model_iPAQ_H39xx:
483 return 64;
484 case Model_iPAQ_H5xxx:
485 return 255;
486
487 default:
488 return 2;
489 }
490}
491
492
493bool iPAQ::hasLightSensor() const
494{
495 return true;
496}
497
498int iPAQ::readLightSensor()
499{
500 int fd;
501 int val = -1;
502
503 if (( fd = ::open ( "/proc/hal/light_sensor", O_RDONLY )) >= 0 ) {
504 char buffer [8];
505
506 if ( ::read ( fd, buffer, 5 ) == 5 ) {
507 char *endptr;
508
509 buffer [4] = 0;
510 val = ::strtol ( buffer + 2, &endptr, 16 );
511
512 if ( *endptr != 0 )
513 val = -1;
514 }
515 ::close ( fd );
516 }
517
518 return val;
519}
520
521int iPAQ::lightSensorResolution() const
522{
523 return 256;
524}
diff --git a/libopie2/opiecore/device/odevice_jornada.cpp b/libopie2/opiecore/device/odevice_jornada.cpp
new file mode 100644
index 0000000..bcd03ed
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice_jornada.cpp
@@ -0,0 +1,214 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include "odevice.h"
31
32/* QT */
33#include <qapplication.h>
34#include <qfile.h>
35#include <qtextstream.h>
36#include <qwindowsystem_qws.h>
37
38/* OPIE */
39#include <qpe/config.h>
40#include <qpe/resource.h>
41#include <qpe/sound.h>
42#include <qpe/qcopenvelope_qws.h>
43
44/* STD */
45#include <fcntl.h>
46#include <math.h>
47#include <stdlib.h>
48#include <signal.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <unistd.h>
52#ifndef QT_NO_SOUND
53#include <linux/soundcard.h>
54#endif
55
56#ifndef ARRAY_SIZE
57#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
58#endif
59
60// _IO and friends are only defined in kernel headers ...
61
62#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 ))
63
64#define OD_IO(type,number) OD_IOC(0,type,number,0)
65#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size))
66#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size))
67#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size))
68
69typedef struct {
70 unsigned char OffOnBlink; /* 0=off 1=on 2=Blink */
71 unsigned char TotalTime; /* Units of 5 seconds */
72 unsigned char OnTime; /* units of 100m/s */
73 unsigned char OffTime; /* units of 100m/s */
74} LED_IN;
75
76typedef struct {
77 unsigned char mode;
78 unsigned char pwr;
79 unsigned char brightness;
80} FLITE_IN;
81
82#define LED_ON OD_IOW( 'f', 5, LED_IN )
83#define FLITE_ON OD_IOW( 'f', 7, FLITE_IN )
84
85using namespace Opie;
86
87class Jornada : public ODevice
88{
89
90 protected:
91 virtual void init();
92
93 public:
94 virtual bool setSoftSuspend ( bool soft );
95 virtual bool setDisplayBrightness ( int b );
96 virtual int displayBrightnessResolution() const;
97 static bool isJornada();
98};
99
100
101bool Jornada::isJornada()
102{
103 QFile f( "/proc/cpuinfo" );
104 if ( f. open ( IO_ReadOnly ) ) {
105 QTextStream ts ( &f );
106 QString line;
107 while( line = ts. readLine() ) {
108 if ( line. left ( 8 ) == "Hardware" ) {
109 int loc = line. find ( ":" );
110 if ( loc != -1 ) {
111 QString model = line.mid( loc + 2 ).simplifyWhiteSpace( );
112 return ( model == "HP Jornada 56x" );
113 }
114 }
115 }
116 }
117 return false;
118}
119
120void Jornada::init()
121{
122 d->m_vendorstr = "HP";
123 d->m_vendor = Vendor_HP;
124 d->m_modelstr = "Jornada 56x";
125 d->m_model = Model_Jornada_56x;
126 d->m_systemstr = "Familiar";
127 d->m_system = System_Familiar;
128 d->m_rotation = Rot0;
129
130 QFile f ( "/etc/familiar-version" );
131 f. setName ( "/etc/familiar-version" );
132 if ( f. open ( IO_ReadOnly )) {
133
134 QTextStream ts ( &f );
135 d->m_sysverstr = ts. readLine(). mid ( 10 );
136
137 f. close();
138 }
139}
140
141#if 0
142void Jornada::initButtons()
143{
144 if ( d->m_buttons )
145 return;
146
147 // Simulation uses iPAQ 3660 device buttons
148
149 qDebug ( "init Buttons" );
150 d->m_buttons = new QValueList <ODeviceButton>;
151
152 for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) {
153 i_button *ib = ipaq_buttons + i;
154 ODeviceButton b;
155
156 if (( ib->model & Model_iPAQ_H36xx ) == Model_iPAQ_H36xx ) {
157 b. setKeycode ( ib->code );
158 b. setUserText ( QObject::tr ( "Button", ib->utext ));
159 b. setPixmap ( Resource::loadPixmap ( ib->pix ));
160 b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib->fpressedservice ), ib->fpressedaction ));
161 b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib->fheldservice ), ib->fheldaction ));
162 d->m_buttons->append ( b );
163 }
164 }
165 reloadButtonMapping();
166
167 QCopChannel *sysch = new QCopChannel ( "QPE/System", this );
168 connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & )));
169}
170#endif
171
172int Jornada::displayBrightnessResolution() const
173{
174}
175
176bool Jornada::setDisplayBrightness( int bright )
177{
178 bool res = false;
179 int fd;
180
181 if ( bright > 255 )
182 bright = 255;
183 if ( bright < 0 )
184 bright = 0;
185
186 if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) {
187 FLITE_IN bl;
188 bl. mode = 1;
189 bl. pwr = bright ? 1 : 0;
190 bl. brightness = ( bright * ( displayBrightnessResolution() - 1 ) + 127 ) / 255;
191 res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 );
192 ::close ( fd );
193 }
194 return res;
195}
196
197bool Jornada::setSoftSuspend( bool soft )
198{
199 bool res = false;
200 int fd;
201
202 if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) {
203 if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 )
204 res = true;
205 else
206 ::perror ( "write to /proc/sys/ts/suspend_button_mode" );
207
208 ::close ( fd );
209 }
210 else
211 ::perror ( "/proc/sys/ts/suspend_button_mode" );
212
213 return res;
214}
diff --git a/libopie2/opiecore/device/odevice_ramses.cpp b/libopie2/opiecore/device/odevice_ramses.cpp
new file mode 100644
index 0000000..a90c3a0
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice_ramses.cpp
@@ -0,0 +1,317 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include "odevice.h"
31
32/* QT */
33#include <qapplication.h>
34#include <qfile.h>
35#include <qtextstream.h>
36#include <qwindowsystem_qws.h>
37
38/* OPIE */
39#include <qpe/config.h>
40#include <qpe/resource.h>
41#include <qpe/sound.h>
42#include <qpe/qcopenvelope_qws.h>
43
44/* STD */
45#include <fcntl.h>
46#include <math.h>
47#include <stdlib.h>
48#include <signal.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <unistd.h>
52#ifndef QT_NO_SOUND
53#include <linux/soundcard.h>
54#endif
55
56#ifndef ARRAY_SIZE
57#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
58#endif
59
60// _IO and friends are only defined in kernel headers ...
61
62#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 ))
63
64#define OD_IO(type,number) OD_IOC(0,type,number,0)
65#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size))
66#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size))
67#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size))
68
69using namespace Opie;
70
71class Ramses : public ODevice, public QWSServer::KeyboardFilter
72{
73 protected:
74 virtual void init();
75
76 public:
77 virtual bool setSoftSuspend( bool soft );
78 virtual bool suspend();
79
80 virtual bool setDisplayStatus( bool on );
81 virtual bool setDisplayBrightness( int b );
82 virtual int displayBrightnessResolution() const;
83 virtual bool setDisplayContrast( int b );
84 virtual int displayContrastResolution() const;
85
86 protected:
87 virtual bool filter ( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat );
88 virtual void timerEvent ( QTimerEvent *te );
89
90 int m_power_timer;
91};
92
93struct r_button {
94 uint model;
95 Qt::Key code;
96 char *utext;
97 char *pix;
98 char *fpressedservice;
99 char *fpressedaction;
100 char *fheldservice;
101 char *fheldaction;
102} ramses_buttons [] = {
103 { Model_Ramses_MNCI,
104 Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"),
105 "devicebuttons/z_menu",
106 "QPE/TaskBar", "toggleMenu()",
107 "QPE/TaskBar", "toggleStartMenu()" },
108 { Model_Ramses_MNCI,
109 Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"),
110 "devicebuttons/ipaq_home",
111 "QPE/Launcher", "home()",
112 "buttonsettings", "raise()" },
113};
114
115void Ramses::init()
116{
117 d->m_vendorstr = "M und N";
118 d->m_vendor = Vendor_MundN;
119
120 QFile f("/proc/sys/board/ramses");
121
122 d->m_modelstr = "Ramses";
123 d->m_model = Model_Ramses_MNCI;
124
125 d->m_rotation = Rot0;
126 d->m_holdtime = 1000;
127
128 f.setName("/etc/oz_version");
129
130 if (f.open(IO_ReadOnly)) {
131 d->m_systemstr = "OpenEmbedded/Ramses";
132 d->m_system = System_OpenZaurus;
133
134 QTextStream ts(&f);
135 ts.setDevice(&f);
136 d->m_sysverstr = ts.readLine();
137 f.close();
138 }
139
140 m_power_timer = 0;
141
142#ifdef QT_QWS_ALLOW_OVERCLOCK
143#warning *** Overclocking enabled - this may fry your hardware - you have been warned ***
144#define OC(x...) x
145#else
146#define OC(x...)
147#endif
148
149 // This table is true for a Intel XScale PXA 255
150
151 d->m_cpu_frequencies->append("99000"); // mem= 99, run= 99, turbo= 99, PXbus= 50
152OC(d->m_cpu_frequencies->append("118000"); ) // mem=118, run=118, turbo=118, PXbus= 59 OC'd mem
153 d->m_cpu_frequencies->append("199100"); // mem= 99, run=199, turbo=199, PXbus= 99
154OC(d->m_cpu_frequencies->append("236000"); ) // mem=118, run=236, turbo=236, PXbus=118 OC'd mem
155 d->m_cpu_frequencies->append("298600"); // mem= 99, run=199, turbo=298, PXbus= 99
156OC(d->m_cpu_frequencies->append("354000"); ) // mem=118, run=236, turbo=354, PXbus=118 OC'd mem
157 d->m_cpu_frequencies->append("398099"); // mem= 99, run=199, turbo=398, PXbus= 99
158 d->m_cpu_frequencies->append("398100"); // mem= 99, run=398, turbo=398, PXbus=196
159OC(d->m_cpu_frequencies->append("471000"); ) // mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus
160
161}
162
163bool Ramses::filter(int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat)
164{
165 Q_UNUSED( keycode );
166 Q_UNUSED( modifiers );
167 Q_UNUSED( isPress );
168 Q_UNUSED( autoRepeat );
169 return false;
170}
171
172void Ramses::timerEvent(QTimerEvent *)
173{
174 killTimer(m_power_timer);
175 m_power_timer = 0;
176 QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, true, false);
177 QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, false, false);
178}
179
180
181bool Ramses::setSoftSuspend(bool soft)
182{
183 qDebug("Ramses::setSoftSuspend(%d)", soft);
184#if 0
185 bool res = false;
186 int fd;
187
188 if (((fd = ::open("/dev/apm_bios", O_RDWR)) >= 0) ||
189 ((fd = ::open("/dev/misc/apm_bios",O_RDWR)) >= 0)) {
190
191 int sources = ::ioctl(fd, APM_IOCGEVTSRC, 0); // get current event sources
192
193 if (sources >= 0) {
194 if (soft)
195 sources &= ~APM_EVT_POWER_BUTTON;
196 else
197 sources |= APM_EVT_POWER_BUTTON;
198
199 if (::ioctl(fd, APM_IOCSEVTSRC, sources) >= 0) // set new event sources
200 res = true;
201 else
202 perror("APM_IOCGEVTSRC");
203 }
204 else
205 perror("APM_IOCGEVTSRC");
206
207 ::close(fd);
208 }
209 else
210 perror("/dev/apm_bios or /dev/misc/apm_bios");
211
212 return res;
213#else
214 return true;
215#endif
216}
217
218bool Ramses::suspend()
219{
220 qDebug("Ramses::suspend");
221 return false;
222}
223
224/**
225* This sets the display on or off
226*/
227bool Ramses::setDisplayStatus(bool on)
228{
229 qDebug("Ramses::setDisplayStatus(%d)", on);
230#if 0
231 bool res = false;
232 int fd;
233
234 if ((fd = ::open ("/dev/fb/0", O_RDWR)) >= 0) {
235 res = (::ioctl(fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN) == 0);
236 ::close(fd);
237 }
238 return res;
239#else
240 return true;
241#endif
242}
243
244
245/*
246* We get something between 0..255 into us
247*/
248bool Ramses::setDisplayBrightness(int bright)
249{
250 qDebug("Ramses::setDisplayBrightness(%d)", bright);
251 bool res = false;
252 int fd;
253
254 // pwm1 brighness: 20 steps 500..0 (dunkel->hell)
255
256 if (bright > 255 )
257 bright = 255;
258 if (bright < 0)
259 bright = 0;
260
261 // Turn backlight completely off
262 if ((fd = ::open("/proc/sys/board/lcd_backlight", O_WRONLY)) >= 0) {
263 char writeCommand[10];
264 const int count = sprintf(writeCommand, "%d\n", bright ? 1 : 0);
265 res = (::write(fd, writeCommand, count) != -1);
266 ::close(fd);
267 }
268
269 // scale backlight brightness to hardware
270 bright = 500-(bright * 500 / 255);
271 if ((fd = ::open("/proc/sys/board/pwm1", O_WRONLY)) >= 0) {
272 qDebug(" %d ->pwm1", bright);
273 char writeCommand[100];
274 const int count = sprintf(writeCommand, "%d\n", bright);
275 res = (::write(fd, writeCommand, count) != -1);
276 ::close(fd);
277 }
278 return res;
279}
280
281
282int Ramses::displayBrightnessResolution() const
283{
284 return 32;
285}
286
287bool Ramses::setDisplayContrast(int contr)
288{
289 qDebug("Ramses::setDisplayContrast(%d)", contr);
290 bool res = false;
291 int fd;
292
293 // pwm0 contrast: 20 steps 79..90 (dunkel->hell)
294
295 if (contr > 255 )
296 contr = 255;
297 if (contr < 0)
298 contr = 0;
299 contr = 90 - (contr * 20 / 255);
300
301 if ((fd = ::open("/proc/sys/board/pwm0", O_WRONLY)) >= 0) {
302 qDebug(" %d ->pwm0", contr);
303 char writeCommand[100];
304 const int count = sprintf(writeCommand, "%d\n", contr);
305 res = (::write(fd, writeCommand, count) != -1);
306 res = true;
307 ::close(fd);
308 }
309 return res;
310}
311
312
313int Ramses::displayContrastResolution() const
314{
315 return 20;
316}
317
diff --git a/libopie2/opiecore/device/odevice_simpad.cpp b/libopie2/opiecore/device/odevice_simpad.cpp
new file mode 100644
index 0000000..82dce10
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice_simpad.cpp
@@ -0,0 +1,443 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include "odevice.h"
31
32/* QT */
33#include <qapplication.h>
34#include <qfile.h>
35#include <qtextstream.h>
36#include <qwindowsystem_qws.h>
37
38/* OPIE */
39#include <qpe/config.h>
40#include <qpe/resource.h>
41#include <qpe/sound.h>
42#include <qpe/qcopenvelope_qws.h>
43
44/* STD */
45#include <fcntl.h>
46#include <math.h>
47#include <stdlib.h>
48#include <signal.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <unistd.h>
52#ifndef QT_NO_SOUND
53#include <linux/soundcard.h>
54#endif
55
56#ifndef ARRAY_SIZE
57#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
58#endif
59
60// _IO and friends are only defined in kernel headers ...
61
62#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 ))
63
64#define OD_IO(type,number) OD_IOC(0,type,number,0)
65#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size))
66#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size))
67#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size))
68
69using namespace Opie;
70
71class SIMpad : public ODevice, public QWSServer::KeyboardFilter
72{
73 protected:
74 virtual void init();
75 virtual void initButtons();
76
77 public:
78 virtual bool setSoftSuspend( bool soft );
79 virtual bool suspend();
80
81 virtual bool setDisplayStatus( bool on );
82 virtual bool setDisplayBrightness( int b );
83 virtual int displayBrightnessResolution() const;
84
85 virtual void alarmSound();
86
87 virtual QValueList <OLed> ledList() const;
88 virtual QValueList <OLedState> ledStateList( OLed led ) const;
89 virtual OLedState ledState( OLed led ) const;
90 virtual bool setLedState( OLed led, OLedState st );
91
92 protected:
93 virtual bool filter( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat );
94 virtual void timerEvent( QTimerEvent *te );
95
96 int m_power_timer;
97
98 OLedState m_leds [1];
99};
100
101struct s_button {
102 uint model;
103 Qt::Key code;
104 char *utext;
105 char *pix;
106 char *fpressedservice;
107 char *fpressedaction;
108 char *fheldservice;
109 char *fheldaction;
110} simpad_buttons [] = {
111 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
112 Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Lower+Up"),
113 "devicebuttons/simpad_lower_up",
114 "datebook", "nextView()",
115 "today", "raise()" },
116 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
117 Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Lower+Down"),
118 "devicebuttons/simpad_lower_down",
119 "addressbook", "raise()",
120 "addressbook", "beamBusinessCard()" },
121 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
122 Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Lower+Right"),
123 "devicebuttons/simpad_lower_right",
124 "QPE/TaskBar", "toggleMenu()",
125 "QPE/TaskBar", "toggleStartMenu()" },
126 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
127 Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Lower+Left"),
128 "devicebuttons/simpad_lower_left",
129 "mail", "raise()",
130 "mail", "newMail()" },
131
132 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
133 Qt::Key_F5, QT_TRANSLATE_NOOP("Button", "Upper+Up"),
134 "devicebuttons/simpad_upper_up",
135 "QPE/Launcher", "home()",
136 "buttonsettings", "raise()" },
137 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
138 Qt::Key_F6, QT_TRANSLATE_NOOP("Button", "Upper+Down"),
139 "devicebuttons/simpad_upper_down",
140 "addressbook", "raise()",
141 "addressbook", "beamBusinessCard()" },
142 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
143 Qt::Key_F7, QT_TRANSLATE_NOOP("Button", "Upper+Right"),
144 "devicebuttons/simpad_upper_right",
145 "QPE/TaskBar", "toggleMenu()",
146 "QPE/TaskBar", "toggleStartMenu()" },
147 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
148 Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Upper+Left"),
149 "devicebuttons/simpad_upper_left",
150 "QPE/Rotation", "flip()",
151 "QPE/Rotation", "flip()" },
152 /*
153 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
154 Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"),
155 "devicebuttons/simpad_lower_upper",
156 "QPE/Launcher", "home()",
157 "buttonsettings", "raise()" },
158 { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus,
159 Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"),
160 "devicebuttons/simpad_upper_lower",
161 "QPE/Launcher", "home()",
162 "buttonsettings", "raise()" },
163 */
164};
165
166void SIMpad::init()
167{
168 d->m_vendorstr = "SIEMENS";
169 d->m_vendor = Vendor_SIEMENS;
170
171 QFile f ( "/proc/hal/model" );
172
173 //TODO Implement model checking
174 //FIXME For now we assume an SL4
175
176 d->m_modelstr = "SL4";
177 d->m_model = Model_SIMpad_SL4;
178
179 switch ( d->m_model ) {
180 default:
181 d->m_rotation = Rot0;
182 d->m_direction = CCW;
183 d->m_holdtime = 1000; // 1000ms
184
185 break;
186 }
187
188 f. setName ( "/etc/familiar-version" );
189 if ( f. open ( IO_ReadOnly )) {
190 d->m_systemstr = "Familiar";
191 d->m_system = System_Familiar;
192
193 QTextStream ts ( &f );
194 d->m_sysverstr = ts. readLine(). mid ( 10 );
195
196 f. close();
197 } else {
198 f. setName ( "/etc/oz_version" );
199
200 if ( f. open ( IO_ReadOnly )) {
201 d->m_systemstr = "OpenEmbedded/SIMpad";
202 d->m_system = System_OpenZaurus;
203
204 QTextStream ts ( &f );
205 ts.setDevice ( &f );
206 d->m_sysverstr = ts. readLine();
207 f. close();
208 }
209 }
210
211 m_leds [0] = m_leds [1] = Led_Off;
212
213 m_power_timer = 0;
214
215}
216
217void SIMpad::initButtons()
218{
219 if ( d->m_buttons )
220 return;
221
222 if ( isQWS( ) )
223 QWSServer::setKeyboardFilter ( this );
224
225 d->m_buttons = new QValueList <ODeviceButton>;
226
227 for ( uint i = 0; i < ( sizeof( simpad_buttons ) / sizeof( s_button )); i++ ) {
228 s_button *sb = simpad_buttons + i;
229 ODeviceButton b;
230
231 if (( sb->model & d->m_model ) == d->m_model ) {
232 b. setKeycode ( sb->code );
233 b. setUserText ( QObject::tr ( "Button", sb->utext ));
234 b. setPixmap ( Resource::loadPixmap ( sb->pix ));
235 b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( sb->fpressedservice ), sb->fpressedaction ));
236 b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( sb->fheldservice ), sb->fheldaction ));
237
238 d->m_buttons->append ( b );
239 }
240 }
241 reloadButtonMapping();
242
243 QCopChannel *sysch = new QCopChannel ( "QPE/System", this );
244 connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & )));
245}
246
247// SIMpad boardcontrol register CS3
248#define SIMPAD_BOARDCONTROL "/proc/cs3"
249#define SIMPAD_VCC_5V_EN 0x0001 // For 5V PCMCIA
250#define SIMPAD_VCC_3V_EN 0x0002 // FOR 3.3V PCMCIA
251#define SIMPAD_EN1 0x0004 // This is only for EPROM's
252#define SIMPAD_EN0 0x0008 // Both should be enable for 3.3V or 5V
253#define SIMPAD_DISPLAY_ON 0x0010
254#define SIMPAD_PCMCIA_BUFF_DIS 0x0020
255#define SIMPAD_MQ_RESET 0x0040
256#define SIMPAD_PCMCIA_RESET 0x0080
257#define SIMPAD_DECT_POWER_ON 0x0100
258#define SIMPAD_IRDA_SD 0x0200 // Shutdown for powersave
259#define SIMPAD_RS232_ON 0x0400
260#define SIMPAD_SD_MEDIAQ 0x0800 // Shutdown for powersave
261#define SIMPAD_LED2_ON 0x1000
262#define SIMPAD_IRDA_MODE 0x2000 // Fast/Slow IrDA mode
263#define SIMPAD_ENABLE_5V 0x4000 // Enable 5V circuit
264#define SIMPAD_RESET_SIMCARD 0x8000
265
266//SIMpad touchscreen backlight strength control
267#define SIMPAD_BACKLIGHT_CONTROL "/proc/driver/mq200/registers/PWM_CONTROL"
268#define SIMPAD_BACKLIGHT_MASK 0x00a10044
269
270QValueList <OLed> SIMpad::ledList() const
271{
272 QValueList <OLed> vl;
273 vl << Led_Power; //FIXME which LED is LED2 ? The green one or the amber one?
274 //vl << Led_Mail; //TODO find out if LED1 is accessible anyway
275 return vl;
276}
277
278QValueList <OLedState> SIMpad::ledStateList ( OLed l ) const
279{
280 QValueList <OLedState> vl;
281
282 if ( l == Led_Power ) //FIXME which LED is LED2 ? The green one or the amber one?
283 vl << Led_Off << Led_On;
284 //else if ( l == Led_Mail ) //TODO find out if LED1 is accessible anyway
285 //vl << Led_Off;
286 return vl;
287}
288
289OLedState SIMpad::ledState ( OLed l ) const
290{
291 switch ( l ) {
292 case Led_Power:
293 return m_leds [0];
294 //case Led_Mail:
295 //return m_leds [1];
296 default:
297 return Led_Off;
298 }
299}
300
301bool SIMpad::setLedState ( OLed l, OLedState st )
302{
303#if 0
304 static int fd = ::open ( SIMPAD_BOARDCONTROL, O_RDWR | O_NONBLOCK );
305
306 /*TODO Implement this like that:
307 read from cs3
308 && with SIMPAD_LED2_ON
309 write to cs3 */
310 m_leds [0] = st;
311 return true;
312 }
313 }
314 }
315
316#endif
317 return false;
318}
319
320
321bool SIMpad::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat )
322{
323 //TODO
324 return false;
325}
326
327void SIMpad::timerEvent ( QTimerEvent * )
328{
329 killTimer ( m_power_timer );
330 m_power_timer = 0;
331 QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false );
332 QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false );
333}
334
335
336void SIMpad::alarmSound()
337{
338#ifndef QT_NO_SOUND
339 static Sound snd ( "alarm" );
340 int fd;
341 int vol;
342 bool vol_reset = false;
343
344 if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) {
345 if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) {
346 Config cfg ( "qpe" );
347 cfg. setGroup ( "Volume" );
348
349 int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 );
350 if ( volalarm < 0 )
351 volalarm = 0;
352 else if ( volalarm > 100 )
353 volalarm = 100;
354 volalarm |= ( volalarm << 8 );
355
356 if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 )
357 vol_reset = true;
358 }
359 }
360
361 snd. play();
362 while ( !snd. isFinished())
363 qApp->processEvents();
364
365 if ( fd >= 0 ) {
366 if ( vol_reset )
367 ::ioctl ( fd, MIXER_WRITE( 0 ), &vol );
368 ::close ( fd );
369 }
370#endif
371}
372
373
374bool SIMpad::suspend() // Must override because SIMpad does NOT have apm
375{
376 qDebug( "ODevice for SIMpad: suspend()" );
377 if ( !isQWS( ) ) // only qwsserver is allowed to suspend
378 return false;
379
380 bool res = false;
381
382 struct timeval tvs, tvn;
383 ::gettimeofday ( &tvs, 0 );
384
385 ::sync(); // flush fs caches
386 res = ( ::system ( "cat /dev/fb/0 >/tmp/.buffer; echo > /proc/sys/pm/suspend; cat /tmp/.buffer >/dev/fb/0" ) == 0 ); //TODO make better :)
387
388 return res;
389}
390
391
392bool SIMpad::setSoftSuspend ( bool soft )
393{
394 qDebug( "ODevice for SIMpad: UNHANDLED setSoftSuspend(%s)", soft? "on" : "off" );
395 return false;
396}
397
398
399bool SIMpad::setDisplayStatus ( bool on )
400{
401 qDebug( "ODevice for SIMpad: setDisplayStatus(%s)", on? "on" : "off" );
402
403 bool res = false;
404 int fd;
405
406 QString cmdline = QString().sprintf( "echo %s > /proc/cs3", on ? "0xd41a" : "0xd40a" ); //TODO make better :)
407
408 res = ( ::system( (const char*) cmdline ) == 0 );
409
410 return res;
411}
412
413
414bool SIMpad::setDisplayBrightness ( int bright )
415{
416 qDebug( "ODevice for SIMpad: setDisplayBrightness( %d )", bright );
417 bool res = false;
418 int fd;
419
420 if ( bright > 255 )
421 bright = 255;
422 if ( bright < 1 )
423 bright = 0;
424
425 if (( fd = ::open ( SIMPAD_BACKLIGHT_CONTROL, O_WRONLY )) >= 0 ) {
426 int value = 255 - bright;
427 const int mask = SIMPAD_BACKLIGHT_MASK;
428 value = value << 8;
429 value += mask;
430 char writeCommand[100];
431 const int count = sprintf( writeCommand, "0x%x\n", value );
432 res = ( ::write ( fd, writeCommand, count ) != -1 );
433 ::close ( fd );
434 }
435 return res;
436}
437
438
439int SIMpad::displayBrightnessResolution() const
440{
441 return 255; // All SIMpad models share the same display
442}
443
diff --git a/libopie2/opiecore/device/odevice_yopy.cpp b/libopie2/opiecore/device/odevice_yopy.cpp
new file mode 100644
index 0000000..9d0cdeb
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice_yopy.cpp
@@ -0,0 +1,212 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include "odevice.h"
31
32/* QT */
33#include <qapplication.h>
34#include <qfile.h>
35#include <qtextstream.h>
36#include <qwindowsystem_qws.h>
37
38/* OPIE */
39#include <qpe/config.h>
40#include <qpe/resource.h>
41#include <qpe/sound.h>
42#include <qpe/qcopenvelope_qws.h>
43
44/* STD */
45#include <fcntl.h>
46#include <math.h>
47#include <stdlib.h>
48#include <signal.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <unistd.h>
52#ifndef QT_NO_SOUND
53#include <linux/soundcard.h>
54#endif
55
56#ifndef ARRAY_SIZE
57#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
58#endif
59
60// _IO and friends are only defined in kernel headers ...
61
62#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 ))
63
64#define OD_IO(type,number) OD_IOC(0,type,number,0)
65#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size))
66#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size))
67#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size))
68
69using namespace Opie;
70
71class Yopy : public ODevice
72{
73 protected:
74
75 virtual void init();
76 virtual void initButtons();
77
78 public:
79 virtual bool suspend();
80
81 virtual bool setDisplayBrightness ( int b );
82 virtual int displayBrightnessResolution() const;
83
84 static bool isYopy();
85};
86
87struct yopy_button {
88 Qt::Key code;
89 char *utext;
90 char *pix;
91 char *fpressedservice;
92 char *fpressedaction;
93 char *fheldservice;
94 char *fheldaction;
95} yopy_buttons [] = {
96{ Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Action Button"),
97 "devicebuttons/yopy_action",
98 "datebook", "nextView()",
99 "today", "raise()" },
100{ Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "OK Button"),
101 "devicebuttons/yopy_ok",
102 "addressbook", "raise()",
103 "addressbook", "beamBusinessCard()" },
104{ Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "End Button"),
105 "devicebuttons/yopy_end",
106 "QPE/Launcher", "home()",
107 "buttonsettings", "raise()" },
108};
109
110bool Yopy::isYopy()
111{
112QFile f( "/proc/cpuinfo" );
113if ( f. open ( IO_ReadOnly ) ) {
114 QTextStream ts ( &f );
115 QString line;
116 while( line = ts. readLine() ) {
117 if ( line. left ( 8 ) == "Hardware" ) {
118 int loc = line. find ( ":" );
119 if ( loc != -1 ) {
120 QString model =
121 line. mid ( loc + 2 ). simplifyWhiteSpace( );
122 return ( model == "Yopy" );
123 }
124 }
125 }
126}
127return false;
128}
129
130void Yopy::init()
131{
132d->m_vendorstr = "G.Mate";
133d->m_vendor = Vendor_GMate;
134d->m_modelstr = "Yopy3700";
135d->m_model = Model_Yopy_3700;
136d->m_rotation = Rot0;
137
138d->m_systemstr = "Linupy";
139d->m_system = System_Linupy;
140
141QFile f ( "/etc/issue" );
142if ( f. open ( IO_ReadOnly )) {
143 QTextStream ts ( &f );
144 ts.readLine();
145 d->m_sysverstr = ts. readLine();
146 f. close();
147}
148}
149
150void Yopy::initButtons()
151{
152if ( d->m_buttons )
153 return;
154
155d->m_buttons = new QValueList <ODeviceButton>;
156
157for (uint i = 0; i < ( sizeof( yopy_buttons ) / sizeof(yopy_button)); i++) {
158
159 yopy_button *ib = yopy_buttons + i;
160
161 ODeviceButton b;
162
163 b. setKeycode ( ib->code );
164 b. setUserText ( QObject::tr ( "Button", ib->utext ));
165 b. setPixmap ( Resource::loadPixmap ( ib->pix ));
166 b. setFactoryPresetPressedAction
167 (OQCopMessage(makeChannel(ib->fpressedservice), ib->fpressedaction));
168 b. setFactoryPresetHeldAction
169 (OQCopMessage(makeChannel(ib->fheldservice), ib->fheldaction));
170
171 d->m_buttons->append ( b );
172}
173reloadButtonMapping();
174
175QCopChannel *sysch = new QCopChannel("QPE/System", this);
176connect(sysch, SIGNAL(received(const QCString &, const QByteArray & )),
177 this, SLOT(systemMessage(const QCString &, const QByteArray & )));
178}
179
180bool Yopy::suspend()
181{
182/* Opie for Yopy does not implement its own power management at the
183 moment. The public version runs parallel to X, and relies on the
184 existing power management features. */
185return false;
186}
187
188bool Yopy::setDisplayBrightness(int bright)
189{
190/* The code here works, but is disabled as the current version runs
191 parallel to X, and relies on the existing backlight demon. */
192#if 0
193if ( QFile::exists("/proc/sys/pm/light") ) {
194 int fd = ::open("/proc/sys/pm/light", O_WRONLY);
195 if (fd >= 0 ) {
196 if (bright)
197 ::write(fd, "1\n", 2);
198 else
199 ::write(fd, "0\n", 2);
200 ::close(fd);
201 return true;
202 }
203}
204#endif
205return false;
206}
207
208int Yopy::displayBrightnessResolution() const
209{
210 return 2;
211}
212
diff --git a/libopie2/opiecore/device/odevice_zaurus.cpp b/libopie2/opiecore/device/odevice_zaurus.cpp
new file mode 100644
index 0000000..a6e8b82
--- a/dev/null
+++ b/libopie2/opiecore/device/odevice_zaurus.cpp
@@ -0,0 +1,790 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include "odevice.h"
31
32/* QT */
33#include <qapplication.h>
34#include <qfile.h>
35#include <qtextstream.h>
36#include <qwindowsystem_qws.h>
37
38/* OPIE */
39#include <qpe/config.h>
40#include <qpe/resource.h>
41#include <qpe/sound.h>
42#include <qpe/qcopenvelope_qws.h>
43
44/* STD */
45#include <fcntl.h>
46#include <math.h>
47#include <stdlib.h>
48#include <signal.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <unistd.h>
52#ifndef QT_NO_SOUND
53#include <linux/soundcard.h>
54#endif
55
56#ifndef ARRAY_SIZE
57#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
58#endif
59
60// _IO and friends are only defined in kernel headers ...
61
62#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 ))
63
64#define OD_IO(type,number) OD_IOC(0,type,number,0)
65#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size))
66#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size))
67#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size))
68
69using namespace Opie;
70
71class Zaurus : public ODevice
72{
73
74 protected:
75 virtual void init();
76 virtual void initButtons();
77
78 public:
79 virtual bool setSoftSuspend ( bool soft );
80
81 virtual bool setDisplayBrightness ( int b );
82 virtual int displayBrightnessResolution() const;
83
84 virtual void alarmSound();
85 virtual void keySound();
86 virtual void touchSound();
87
88 virtual QValueList <OLed> ledList() const;
89 virtual QValueList <OLedState> ledStateList ( OLed led ) const;
90 virtual OLedState ledState( OLed led ) const;
91 virtual bool setLedState( OLed led, OLedState st );
92
93 virtual bool hasHingeSensor() const;
94 virtual OHingeStatus readHingeSensor();
95
96 static bool isZaurus();
97
98 virtual bool suspend();
99 virtual Transformation rotation() const;
100 virtual ODirection direction() const;
101
102 protected:
103 virtual void buzzer ( int snd );
104
105 OLedState m_leds [1];
106 bool m_embedix;
107};
108
109struct z_button {
110 Qt::Key code;
111 char *utext;
112 char *pix;
113 char *fpressedservice;
114 char *fpressedaction;
115 char *fheldservice;
116 char *fheldaction;
117} z_buttons [] = {
118 { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"),
119 "devicebuttons/z_calendar",
120 "datebook", "nextView()",
121 "today", "raise()" },
122 { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"),
123 "devicebuttons/z_contact",
124 "addressbook", "raise()",
125 "addressbook", "beamBusinessCard()" },
126 { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"),
127 "devicebuttons/z_home",
128 "QPE/Launcher", "home()",
129 "buttonsettings", "raise()" },
130 { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"),
131 "devicebuttons/z_menu",
132 "QPE/TaskBar", "toggleMenu()",
133 "QPE/TaskBar", "toggleStartMenu()" },
134 { Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"),
135 "devicebuttons/z_mail",
136 "mail", "raise()",
137 "mail", "newMail()" },
138};
139
140struct z_button z_buttons_c700 [] = {
141 { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"),
142 "devicebuttons/z_calendar",
143 "datebook", "nextView()",
144 "today", "raise()" },
145 { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"),
146 "devicebuttons/z_contact",
147 "addressbook", "raise()",
148 "addressbook", "beamBusinessCard()" },
149 { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"),
150 "devicebuttons/z_home",
151 "QPE/Launcher", "home()",
152 "buttonsettings", "raise()" },
153 { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"),
154 "devicebuttons/z_menu",
155 "QPE/TaskBar", "toggleMenu()",
156 "QPE/TaskBar", "toggleStartMenu()" },
157 { Qt::Key_F14, QT_TRANSLATE_NOOP("Button", "Display Rotate"),
158 "devicebuttons/z_hinge",
159 "QPE/Rotation", "rotateDefault()",
160 "QPE/Dummy", "doNothing()" },
161};
162
163// Check whether this device is the sharp zaurus..
164// FIXME This gets unnecessary complicated. We should think about splitting the Zaurus
165// class up into individual classes. We need three classes
166//
167// Zaurus-Collie (SA-model w/ 320x240 lcd, for SL5500 and SL5000)
168// Zaurus-Poodle (PXA-model w/ 320x240 lcd, for SL5600)
169// Zaurus-Corgi (PXA-model w/ 640x480 lcd, for C700, C750, C760, and C860)
170//
171// Only question right now is: Do we really need to do it? Because as soon
172// as the OpenZaurus kernel is ready, there will be a unified interface for all
173// Zaurus models (concerning apm, backlight, buttons, etc.)
174//
175// Comments? - mickeyl.
176
177bool Zaurus::isZaurus()
178{
179
180 // If the special devices by embedix exist, it is quite simple: it is a Zaurus !
181 if ( QFile::exists ( "/dev/sharp_buz" ) || QFile::exists ( "/dev/sharp_led" ) ){
182 return true;
183 }
184
185 // On non-embedix kernels, we have to look closer.
186 bool is_zaurus = false;
187 QFile f ( "/proc/cpuinfo" );
188 if ( f. open ( IO_ReadOnly ) ) {
189 QString model;
190 QFile f ( "/proc/cpuinfo" );
191
192 QTextStream ts ( &f );
193 QString line;
194 while( line = ts. readLine() ) {
195 if ( line. left ( 8 ) == "Hardware" )
196 break;
197 }
198 int loc = line. find ( ":" );
199 if ( loc != -1 )
200 model = line. mid ( loc + 2 ). simplifyWhiteSpace( );
201
202 if ( model == "Sharp-Collie"
203 || model == "Collie"
204 || model == "SHARP Corgi"
205 || model == "SHARP Shepherd"
206 || model == "SHARP Poodle"
207 || model == "SHARP Husky"
208 )
209 is_zaurus = true;
210
211 }
212 return is_zaurus;
213}
214
215
216void Zaurus::init()
217{
218 d->m_vendorstr = "Sharp";
219 d->m_vendor = Vendor_Sharp;
220 m_embedix = true; // Not openzaurus means: It has an embedix kernel !
221
222 // QFile f ( "/proc/filesystems" );
223 QString model;
224
225 // It isn't a good idea to check the system configuration to
226 // detect the distribution !
227 // Otherwise it may happen that any other distribution is detected as openzaurus, just
228 // because it uses a jffs2 filesystem..
229 // (eilers)
230 // if ( f. open ( IO_ReadOnly ) && ( QTextStream ( &f ). read(). find ( "\tjffs2\n" ) >= 0 )) {
231 QFile f ("/etc/oz_version");
232 if ( f.exists() ){
233 d->m_vendorstr = "OpenZaurus Team";
234 d->m_systemstr = "OpenZaurus";
235 d->m_system = System_OpenZaurus;
236
237 if ( f. open ( IO_ReadOnly )) {
238 QTextStream ts ( &f );
239 d->m_sysverstr = ts. readLine();//. mid ( 10 );
240 f. close();
241 }
242
243 // Openzaurus sometimes uses the embedix kernel!
244 // => Check whether this is an embedix kernel
245 FILE *uname = popen("uname -r", "r");
246 QString line;
247 if ( f.open(IO_ReadOnly, uname) ) {
248 QTextStream ts ( &f );
249 line = ts. readLine();
250 int loc = line. find ( "embedix" );
251 if ( loc != -1 )
252 m_embedix = true;
253 else
254 m_embedix = false;
255 f. close();
256 }
257 pclose(uname);
258 }
259 else {
260 d->m_systemstr = "Zaurus";
261 d->m_system = System_Zaurus;
262 }
263
264 f. setName ( "/proc/cpuinfo" );
265 if ( f. open ( IO_ReadOnly ) ) {
266 QTextStream ts ( &f );
267 QString line;
268 while( line = ts. readLine() ) {
269 if ( line. left ( 8 ) == "Hardware" )
270 break;
271 }
272 int loc = line. find ( ":" );
273 if ( loc != -1 )
274 model = line. mid ( loc + 2 ). simplifyWhiteSpace( );
275 }
276
277 if ( model == "SHARP Corgi" ) {
278 d->m_model = Model_Zaurus_SLC7x0;
279 d->m_modelstr = "Zaurus SL-C700";
280 } else if ( model == "SHARP Shepherd" ) {
281 d->m_model = Model_Zaurus_SLC7x0;
282 d->m_modelstr = "Zaurus SL-C750";
283 } else if ( model == "SHARP Husky" ) {
284 d->m_model = Model_Zaurus_SLC7x0;
285 d->m_modelstr = "Zaurus SL-C760";
286 } else if ( model == "SHARP Poodle" ) {
287 d->m_model = Model_Zaurus_SLB600;
288 d->m_modelstr = "Zaurus SL-B500 or SL-5600";
289 } else if ( model == "Sharp-Collie" || model == "Collie" ) {
290 d->m_model = Model_Zaurus_SL5500;
291 d->m_modelstr = "Zaurus SL-5500 or SL-5000d";
292 } else {
293 d->m_model = Model_Zaurus_SL5500;
294 d->m_modelstr = "Zaurus (Model unknown)";
295 }
296
297 bool flipstate = false;
298 switch ( d->m_model ) {
299 case Model_Zaurus_SLA300:
300 d->m_rotation = Rot0;
301 break;
302 case Model_Zaurus_SLC7x0:
303 d->m_rotation = rotation();
304 d->m_direction = direction();
305 break;
306 case Model_Zaurus_SLB600:
307 case Model_Zaurus_SL5500:
308 case Model_Zaurus_SL5000:
309 default:
310 d->m_rotation = Rot270;
311 break;
312 }
313 m_leds [0] = Led_Off;
314}
315
316void Zaurus::initButtons()
317{
318 if ( d->m_buttons )
319 return;
320
321 d->m_buttons = new QValueList <ODeviceButton>;
322
323 struct z_button * pz_buttons;
324 int buttoncount;
325 switch ( d->m_model ) {
326 case Model_Zaurus_SLC7x0:
327 pz_buttons = z_buttons_c700;
328 buttoncount = ARRAY_SIZE(z_buttons_c700);
329 break;
330 default:
331 pz_buttons = z_buttons;
332 buttoncount = ARRAY_SIZE(z_buttons);
333 break;
334 }
335
336 for ( int i = 0; i < buttoncount; i++ ) {
337 struct z_button *zb = pz_buttons + i;
338 ODeviceButton b;
339
340 b. setKeycode ( zb->code );
341 b. setUserText ( QObject::tr ( "Button", zb->utext ));
342 b. setPixmap ( Resource::loadPixmap ( zb->pix ));
343 b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( zb->fpressedservice ),
344 zb->fpressedaction ));
345 b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( zb->fheldservice ),
346 zb->fheldaction ));
347
348 d->m_buttons->append ( b );
349 }
350
351 reloadButtonMapping();
352
353 QCopChannel *sysch = new QCopChannel ( "QPE/System", this );
354 connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )),
355 this, SLOT( systemMessage ( const QCString &, const QByteArray & )));
356}
357
358#include <unistd.h>
359#include <fcntl.h>
360#include <sys/ioctl.h>
361
362//#include <asm/sharp_char.h> // including kernel headers is evil ...
363
364#define SHARP_DEV_IOCTL_COMMAND_START 0x5680
365
366 #defineSHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START)
367#define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START)
368
369#define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */
370#define SHARP_BUZ_KEYSOUND 2 /* key sound */
371#define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */
372
373/* --- for SHARP_BUZZER device --- */
374
375 //#defineSHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START)
376//#define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START)
377
378#define SHARP_BUZZER_SETVOLUME (SHARP_BUZZER_IOCTL_START+1)
379#define SHARP_BUZZER_GETVOLUME (SHARP_BUZZER_IOCTL_START+2)
380#define SHARP_BUZZER_ISSUPPORTED (SHARP_BUZZER_IOCTL_START+3)
381#define SHARP_BUZZER_SETMUTE (SHARP_BUZZER_IOCTL_START+4)
382#define SHARP_BUZZER_STOPSOUND (SHARP_BUZZER_IOCTL_START+5)
383
384//#define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */
385//#define SHARP_BUZ_KEYSOUND 2 /* key sound */
386
387//#define SHARP_PDA_ILLCLICKSOUND 3 /* illegal click */
388//#define SHARP_PDA_WARNSOUND 4 /* warning occurred */
389//#define SHARP_PDA_ERRORSOUND 5 /* error occurred */
390//#define SHARP_PDA_CRITICALSOUND 6 /* critical error occurred */
391//#define SHARP_PDA_SYSSTARTSOUND 7 /* system start */
392//#define SHARP_PDA_SYSTEMENDSOUND 8 /* system shutdown */
393//#define SHARP_PDA_APPSTART 9 /* application start */
394//#define SHARP_PDA_APPQUIT 10 /* application ends */
395
396//#define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */
397//#define SHARP_BUZ_DAILY_ALARM 12 /* daily alarm */
398//#define SHARP_BUZ_GOT_PHONE_CALL 13 /* phone call sound */
399//#define SHARP_BUZ_GOT_MAIL 14 /* mail sound */
400//
401
402 #defineSHARP_LED_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START)
403#define SHARP_LED_SETSTATUS (SHARP_LED_IOCTL_START+1)
404
405#define SHARP_IOCTL_GET_ROTATION 0x413c
406
407typedef struct sharp_led_status {
408int which; /* select which LED status is wanted. */
409int status; /* set new led status if you call SHARP_LED_SETSTATUS */
410} sharp_led_status;
411
412#define SHARP_LED_MAIL_EXISTS 9 /* mail status (exists or not) */
413
414#define LED_MAIL_NO_UNREAD_MAIL 0 /* for SHARP_LED_MAIL_EXISTS */
415#define LED_MAIL_NEWMAIL_EXISTS 1 /* for SHARP_LED_MAIL_EXISTS */
416#define LED_MAIL_UNREAD_MAIL_EX 2 /* for SHARP_LED_MAIL_EXISTS */
417
418// #include <asm/sharp_apm.h> // including kernel headers is evil ...
419
420#define APM_IOCGEVTSRC OD_IOR( 'A', 203, int )
421#define APM_IOCSEVTSRC OD_IORW( 'A', 204, int )
422#define APM_EVT_POWER_BUTTON (1 << 0)
423
424#define FL_IOCTL_STEP_CONTRAST 100
425
426
427void Zaurus::buzzer ( int sound )
428{
429#ifndef QT_NO_SOUND
430 QString soundname;
431
432 // Not all devices have real sound
433 if ( d->m_model == Model_Zaurus_SLC7x0
434 || d->m_model == Model_Zaurus_SLB600 ){
435
436 switch ( sound ){
437 case SHARP_BUZ_SCHEDULE_ALARM:
438 soundname = "alarm";
439 break;
440 case SHARP_BUZ_TOUCHSOUND:
441 soundname = "touchsound";
442 break;
443 case SHARP_BUZ_KEYSOUND:
444 soundname = "keysound";
445 break;
446 default:
447 soundname = "alarm";
448
449 }
450 }
451
452 // If a soundname is defined, we expect that this device has
453 // sound capabilities.. Otherwise we expect to have the buzzer
454 // device..
455 if ( !soundname.isEmpty() ){
456 int fd;
457 int vol;
458 bool vol_reset = false;
459
460 Sound snd ( soundname );
461
462 if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) {
463 if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) {
464 Config cfg ( "qpe" );
465 cfg. setGroup ( "Volume" );
466
467 int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 );
468 if ( volalarm < 0 )
469 volalarm = 0;
470 else if ( volalarm > 100 )
471 volalarm = 100;
472 volalarm |= ( volalarm << 8 );
473
474 if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 )
475 vol_reset = true;
476 }
477 }
478
479 snd. play();
480 while ( !snd. isFinished())
481 qApp->processEvents();
482
483 if ( fd >= 0 ) {
484 if ( vol_reset )
485 ::ioctl ( fd, MIXER_WRITE( 0 ), &vol );
486 ::close ( fd );
487 }
488 } else {
489 int fd = ::open ( "/dev/sharp_buz", O_WRONLY|O_NONBLOCK );
490
491 if ( fd >= 0 ) {
492 ::ioctl ( fd, SHARP_BUZZER_MAKESOUND, sound );
493 ::close ( fd );
494 }
495
496 }
497#endif
498}
499
500
501void Zaurus::alarmSound()
502{
503 buzzer ( SHARP_BUZ_SCHEDULE_ALARM );
504}
505
506void Zaurus::touchSound()
507{
508 buzzer ( SHARP_BUZ_TOUCHSOUND );
509}
510
511void Zaurus::keySound()
512{
513 buzzer ( SHARP_BUZ_KEYSOUND );
514}
515
516
517QValueList <OLed> Zaurus::ledList() const
518{
519 QValueList <OLed> vl;
520 vl << Led_Mail;
521 return vl;
522}
523
524QValueList <OLedState> Zaurus::ledStateList ( OLed l ) const
525{
526 QValueList <OLedState> vl;
527
528 if ( l == Led_Mail )
529 vl << Led_Off << Led_On << Led_BlinkSlow;
530 return vl;
531}
532
533OLedState Zaurus::ledState ( OLed which ) const
534{
535 if ( which == Led_Mail )
536 return m_leds [0];
537 else
538 return Led_Off;
539}
540
541bool Zaurus::setLedState ( OLed which, OLedState st )
542{
543 if (!m_embedix) // Currently not supported on non_embedix kernels
544 return false;
545
546 static int fd = ::open ( "/dev/sharp_led", O_RDWR|O_NONBLOCK );
547
548 if ( which == Led_Mail ) {
549 if ( fd >= 0 ) {
550 struct sharp_led_status leds;
551 ::memset ( &leds, 0, sizeof( leds ));
552 leds. which = SHARP_LED_MAIL_EXISTS;
553 bool ok = true;
554
555 switch ( st ) {
556 case Led_Off : leds. status = LED_MAIL_NO_UNREAD_MAIL; break;
557 case Led_On : leds. status = LED_MAIL_NEWMAIL_EXISTS; break;
558 case Led_BlinkSlow: leds. status = LED_MAIL_UNREAD_MAIL_EX; break;
559 default : ok = false;
560 }
561
562 if ( ok && ( ::ioctl ( fd, SHARP_LED_SETSTATUS, &leds ) >= 0 )) {
563 m_leds [0] = st;
564 return true;
565 }
566 }
567 }
568 return false;
569}
570
571bool Zaurus::setSoftSuspend ( bool soft )
572{
573 if (!m_embedix) {
574 /* non-Embedix kernels dont have kernel autosuspend */
575 return ODevice::setSoftSuspend( soft );
576 }
577
578 bool res = false;
579 int fd;
580
581 if ((( fd = ::open ( "/dev/apm_bios", O_RDWR )) >= 0 ) ||
582 (( fd = ::open ( "/dev/misc/apm_bios",O_RDWR )) >= 0 )) {
583
584 int sources = ::ioctl ( fd, APM_IOCGEVTSRC, 0 ); // get current event sources
585
586 if ( sources >= 0 ) {
587 if ( soft )
588 sources &= ~APM_EVT_POWER_BUTTON;
589 else
590 sources |= APM_EVT_POWER_BUTTON;
591
592 if ( ::ioctl ( fd, APM_IOCSEVTSRC, sources ) >= 0 ) // set new event sources
593 res = true;
594 else
595 perror ( "APM_IOCGEVTSRC" );
596 }
597 else
598 perror ( "APM_IOCGEVTSRC" );
599
600 ::close ( fd );
601 }
602 else
603 perror ( "/dev/apm_bios or /dev/misc/apm_bios" );
604
605 return res;
606}
607
608
609bool Zaurus::setDisplayBrightness ( int bright )
610{
611 //qDebug( "Zaurus::setDisplayBrightness( %d )", bright );
612 bool res = false;
613 int fd;
614
615 if ( bright > 255 ) bright = 255;
616 if ( bright < 0 ) bright = 0;
617
618 if ( m_embedix )
619 {
620 if ( d->m_model == Model_Zaurus_SLC7x0 )
621 {
622 //qDebug( "using special treatment for devices with the corgi backlight interface" );
623 // special treatment for devices with the corgi backlight interface
624 if (( fd = ::open ( "/proc/driver/fl/corgi-bl", O_WRONLY )) >= 0 )
625 {
626 int value = ( bright == 1 ) ? 1 : bright * ( 17.0 / 255.0 );
627 char writeCommand[100];
628 const int count = sprintf( writeCommand, "0x%x\n", value );
629 res = ( ::write ( fd, writeCommand, count ) != -1 );
630 ::close ( fd );
631 }
632 return res;
633 }
634 else
635 {
636 // standard treatment for devices with the dumb embedix frontlight interface
637 if (( fd = ::open ( "/dev/fl", O_WRONLY )) >= 0 ) {
638 int bl = ( bright * 4 + 127 ) / 255; // only 4 steps on zaurus
639 if ( bright && !bl )
640 bl = 1;
641 res = ( ::ioctl ( fd, FL_IOCTL_STEP_CONTRAST, bl ) == 0 );
642 ::close ( fd );
643 }
644 }
645 }
646 else
647 {
648 // special treatment for the OpenZaurus unified interface
649 #define FB_BACKLIGHT_SET_BRIGHTNESS _IOW('F', 1, u_int) /* set brightness */
650 if (( fd = ::open ( "/dev/fb0", O_WRONLY )) >= 0 ) {
651 res = ( ::ioctl ( fd , FB_BACKLIGHT_SET_BRIGHTNESS, bright ) == 0 );
652 ::close ( fd );
653 }
654 }
655 return res;
656}
657
658bool Zaurus::suspend()
659{
660 qDebug("ODevice::suspend");
661 if ( !isQWS( ) ) // only qwsserver is allowed to suspend
662 return false;
663
664 if ( d->m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices
665 return false;
666
667 bool res = false;
668
669 struct timeval tvs, tvn;
670 ::gettimeofday ( &tvs, 0 );
671
672 ::sync(); // flush fs caches
673 res = ( ::system ( "apm --suspend" ) == 0 );
674
675 // This is needed because the iPAQ apm implementation is asynchronous and we
676 // can not be sure when exactly the device is really suspended
677 // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists.
678
679 if ( res ) {
680 do { // Yes, wait 15 seconds. This APM bug sucks big time.
681 ::usleep ( 200 * 1000 );
682 ::gettimeofday ( &tvn, 0 );
683 } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 15000 );
684 }
685
686 QCopEnvelope ( "QPE/Rotation", "rotateDefault()" );
687 return res;
688}
689
690
691Transformation Zaurus::rotation() const
692{
693 Transformation rot;
694 int handle = 0;
695 int retval = 0;
696
697 switch ( d->m_model ) {
698 case Model_Zaurus_SLC7x0:
699 handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK);
700 if (handle == -1) {
701 return Rot270;
702 } else {
703 retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION);
704 ::close (handle);
705
706 if (retval == 2 )
707 rot = Rot0;
708 else
709 rot = Rot270;
710 }
711 break;
712 case Model_Zaurus_SLA300:
713 case Model_Zaurus_SLB600:
714 case Model_Zaurus_SL5500:
715 case Model_Zaurus_SL5000:
716 default:
717 rot = d->m_rotation;
718 break;
719 }
720
721 return rot;
722}
723ODirection Zaurus::direction() const
724{
725 ODirection dir;
726 int handle = 0;
727 int retval = 0;
728 switch ( d->m_model ) {
729 case Model_Zaurus_SLC7x0:
730 handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK);
731 if (handle == -1) {
732 dir = CW;
733 } else {
734 retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION);
735 ::close (handle);
736 if (retval == 2 )
737 dir = CCW;
738 else
739 dir = CW;
740 }
741 break;
742 case Model_Zaurus_SLA300:
743 case Model_Zaurus_SLB600:
744 case Model_Zaurus_SL5500:
745 case Model_Zaurus_SL5000:
746 default:
747 dir = d->m_direction;
748 break;
749 }
750 return dir;
751
752}
753
754int Zaurus::displayBrightnessResolution() const
755{
756 if (m_embedix)
757 return d->m_model == Model_Zaurus_SLC7x0 ? 18 : 5;
758 else
759 return 256;
760}
761
762bool Zaurus::hasHingeSensor() const
763{
764 return d->m_model == Model_Zaurus_SLC7x0;
765}
766
767OHingeStatus Zaurus::readHingeSensor()
768{
769 int handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK);
770 if (handle == -1)
771 {
772 qWarning("Zaurus::readHingeSensor() - failed (%s)", "unknown reason" ); //FIXME: use strerror
773 return CASE_UNKNOWN;
774 }
775 else
776 {
777 int retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION);
778 ::close (handle);
779 if ( retval == CASE_CLOSED || retval == CASE_PORTRAIT || retval == CASE_LANDSCAPE )
780 {
781 qDebug( "Zaurus::readHingeSensor() - result = %d", retval );
782 return static_cast<OHingeStatus>( retval );
783 }
784 else
785 {
786 qWarning("Zaurus::readHingeSensor() - couldn't compute hinge status!" );
787 return CASE_UNKNOWN;
788 }
789 }
790}
diff --git a/libopie2/opiecore/device/odevicebutton.cpp b/libopie2/opiecore/device/odevicebutton.cpp
new file mode 100644
index 0000000..0b593d5
--- a/dev/null
+++ b/libopie2/opiecore/device/odevicebutton.cpp
@@ -0,0 +1,246 @@
1/*
2                 This file is part of the Opie Project
3              Copyright (C) The Opie Team <opie-devel@handhelds.org>
4 =.
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28*/
29
30#include <qpixmap.h>
31#include <qstring.h>
32
33#include <qpe/qcopenvelope_qws.h>
34#include <opie2/odevicebutton.h>
35
36using namespace Opie;
37
38class OQCopMessageData
39{
40 public:
41 QCString m_channel;
42 QCString m_message;
43 QByteArray m_data;
44};
45
46
47OQCopMessage::OQCopMessage()
48 : d ( 0 )
49{
50 init ( QCString(), QCString(), QByteArray());
51}
52
53OQCopMessage::OQCopMessage ( const OQCopMessage &copy )
54 : d ( 0 )
55{
56 init ( copy. channel(), copy. message(), copy. data());
57}
58
59OQCopMessage &OQCopMessage::operator = ( const OQCopMessage &assign )
60{
61 init ( assign. channel(), assign. message(), assign. data());
62 return *this;
63}
64
65OQCopMessage::OQCopMessage ( const QCString &ch, const QCString &m, const QByteArray &arg )
66 : d ( 0 )
67{
68 init ( ch, m, arg );
69}
70
71void OQCopMessage::init ( const QCString &ch, const QCString &m, const QByteArray &arg )
72{
73 if ( !d )
74 d = new OQCopMessageData();
75 d->m_channel = ch;
76 d->m_message = m;
77 d->m_data = arg;
78}
79
80bool OQCopMessage::send()
81{
82 if ( d->m_channel. isEmpty() || d->m_message. isEmpty() )
83 return false;
84
85 QCopEnvelope e ( d->m_channel, d->m_message );
86
87 if ( d->m_data. size())
88 e. writeRawBytes ( d->m_data. data(), d->m_data. size());
89
90 return true;
91}
92
93QCString OQCopMessage::channel() const
94{
95 return d->m_channel;
96}
97
98QCString OQCopMessage::message() const
99{
100 return d->m_message;
101}
102
103QByteArray OQCopMessage::data() const
104{
105 return d->m_data;
106}
107
108bool OQCopMessage::isNull() const
109{
110 return d->m_message.isNull() || d->m_channel.isNull();
111}
112void OQCopMessage::setChannel ( const QCString &ch )
113{
114 d->m_channel = ch;
115}
116
117void OQCopMessage::setMessage ( const QCString &m )
118{
119 d->m_message = m;
120}
121
122void OQCopMessage::setData ( const QByteArray &data )
123{
124 d->m_data = data;
125}
126
127/*! \class Opie::ODeviceButton
128 \brief The Opie::ODeviceButton class represents a physical user mappable button on a Qtopia device.
129
130 This class represents a physical button on a Qtopia device. A
131 device may have "user programmable" buttons.
132 The location and number of buttons will vary from device to
133 device. userText() and pixmap() may be used to describe this button
134 to the user in help documentation.
135
136 \ingroup qtopiaemb
137 \internal
138*/
139
140ODeviceButton::ODeviceButton()
141{}
142
143ODeviceButton::~ODeviceButton()
144{}
145
146/*!
147Returns the button's keycode.
148*/
149ushort ODeviceButton::keycode() const
150{
151 return m_Keycode;
152}
153
154
155/*!
156This function returns a human readable, translated description of the button.
157*/
158QString ODeviceButton::userText() const
159{
160 return m_UserText;
161}
162
163/*!
164This function returns the pixmap for this button. If there isn't one
165it will return an empty (null) pixmap.
166*/
167QPixmap ODeviceButton::pixmap() const
168{
169 return m_Pixmap;
170}
171
172/*!
173This function returns the factory preset (default) action for when this button
174is pressed. The return value is a legal QCop message.
175*/
176OQCopMessage ODeviceButton::factoryPresetPressedAction() const
177{
178 return m_FactoryPresetPressedAction;
179}
180
181/*!
182This function returns the user assigned action for when this button is pressed.
183If no action is assigned, factoryPresetAction() is returned.
184*/
185OQCopMessage ODeviceButton::pressedAction() const
186{
187 if (m_PressedAction.channel().isEmpty())
188 return factoryPresetPressedAction();
189 return m_PressedAction;
190}
191
192/*!
193This function returns the factory preset (default) action for when this button
194is pressed and held. The return value is a legal QCop message.
195*/
196OQCopMessage ODeviceButton::factoryPresetHeldAction() const
197{
198 return m_FactoryPresetHeldAction;
199}
200
201/*!
202This function returns the user assigned action for when this button is pressed
203and held. If no action is assigned, factoryPresetAction() is returned.
204*/
205OQCopMessage ODeviceButton::heldAction() const
206{
207 if (m_HeldAction.channel().isEmpty())
208 return factoryPresetHeldAction();
209 return m_HeldAction;
210}
211
212void ODeviceButton::setKeycode(ushort keycode)
213{
214 m_Keycode = keycode;
215}
216
217void ODeviceButton::setUserText(const QString& text)
218{
219 m_UserText = text;
220}
221
222void ODeviceButton::setPixmap(const QPixmap& picture)
223{
224 m_Pixmap = picture;
225}
226
227void ODeviceButton::setFactoryPresetPressedAction(const OQCopMessage& action)
228{
229 m_FactoryPresetPressedAction = action;
230}
231
232
233void ODeviceButton::setPressedAction(const OQCopMessage& action)
234{
235 m_PressedAction = action;
236}
237
238void ODeviceButton::setFactoryPresetHeldAction(const OQCopMessage& action)
239{
240 m_FactoryPresetHeldAction = action;
241}
242
243void ODeviceButton::setHeldAction(const OQCopMessage& action)
244{
245 m_HeldAction = action;
246}
diff --git a/libopie2/opiecore/device/odevicebutton.h b/libopie2/opiecore/device/odevicebutton.h
new file mode 100644
index 0000000..a66b88f
--- a/dev/null
+++ b/libopie2/opiecore/device/odevicebutton.h
@@ -0,0 +1,108 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#ifndef DEVICE_BUTTON_H
21#define DEVICE_BUTTON_H
22
23#include <qpixmap.h>
24#include <qstring.h>
25
26class OQCopMessageData;
27
28namespace Opie
29{
30
31class OQCopMessage
32{
33public:
34 OQCopMessage ( );
35 OQCopMessage ( const OQCopMessage &copy );
36 OQCopMessage ( const QCString &m_channel, const QCString &message, const QByteArray &args = QByteArray ( ));
37
38 OQCopMessage &operator = ( const OQCopMessage &assign );
39
40 void setChannel ( const QCString &channel );
41 void setMessage ( const QCString &message );
42 void setData ( const QByteArray &ba );
43
44 QCString channel ( ) const;
45 QCString message ( ) const;
46 QByteArray data ( ) const;
47
48 bool isNull()const;
49
50 bool send ( );
51
52private:
53 void init ( const QCString &m_channel, const QCString &message, const QByteArray &args );
54
55 OQCopMessageData *d;
56 class Private;
57 Private* m_data;
58};
59
60
61/**
62 * This class represents a physical button on a Qtopia device. A device may
63 * have n "user programmable" buttons, which are number 1..n. The location
64 * and number of buttons will vary from device to device. userText() and pixmap()
65 * may be used to describe this button to the user in help documentation.
66 *
67 * @version 1.0
68 * @author Trolltech
69 * @short A representation of buttons
70 */
71
72class ODeviceButton
73{
74 public:
75 ODeviceButton();
76 virtual ~ODeviceButton();
77
78 ushort keycode ( ) const;
79 QString userText ( ) const;
80 QPixmap pixmap ( ) const;
81 OQCopMessage factoryPresetPressedAction ( ) const;
82 OQCopMessage pressedAction ( ) const;
83 OQCopMessage factoryPresetHeldAction ( ) const;
84 OQCopMessage heldAction ( ) const;
85
86 void setKeycode ( ushort keycode );
87 void setUserText ( const QString& text );
88 void setPixmap ( const QPixmap& picture );
89 void setFactoryPresetPressedAction ( const OQCopMessage& qcopMessage );
90 void setPressedAction ( const OQCopMessage& qcopMessage );
91 void setFactoryPresetHeldAction ( const OQCopMessage& qcopMessage );
92 void setHeldAction ( const OQCopMessage& qcopMessage );
93
94 private:
95 ushort m_Keycode;
96 QString m_UserText;
97 QPixmap m_Pixmap;
98 OQCopMessage m_FactoryPresetPressedAction;
99 OQCopMessage m_PressedAction;
100 OQCopMessage m_FactoryPresetHeldAction;
101 OQCopMessage m_HeldAction;
102 class Private;
103 Private *d;
104};
105
106}
107
108#endif
diff --git a/libopie2/opiecore/libopiecore2.control b/libopie2/opiecore/libopiecore2.control
index 956d24f..f0a3afc 100644
--- a/libopie2/opiecore/libopiecore2.control
+++ b/libopie2/opiecore/libopiecore2.control
@@ -4,7 +4,7 @@ Priority: optional
4Section: opie/system 4Section: opie/system
5Maintainer: Opie Team <opie@handhelds.org> 5Maintainer: Opie Team <opie@handhelds.org>
6Architecture: arm 6Architecture: arm
7Version: 1.8.2-$SUB_VERSION.2 7Version: 1.8.3-$SUB_VERSION.2
8Depends: libqpe1 8Depends: libqpe1
9Provides: libopiecore2 9Provides: libopiecore2
10Description: Opie library 2.0 CORE 10Description: Opie library 2.0 CORE
diff --git a/libopie2/opiecore/opiecore.pro b/libopie2/opiecore/opiecore.pro
index 237a5ed..97e8146 100644
--- a/libopie2/opiecore/opiecore.pro
+++ b/libopie2/opiecore/opiecore.pro
@@ -4,20 +4,34 @@ DESTDIR = $(OPIEDIR)/lib
4HEADERS = oapplication.h \ 4HEADERS = oapplication.h \
5 oconfig.h \ 5 oconfig.h \
6 odebug.h \ 6 odebug.h \
7 odevice.h \
8 odevicebutton.h \
7 oglobal.h \ 9 oglobal.h \
8 oglobalsettings.h \ 10 oglobalsettings.h \
11 oprocess.h \
12 oprocctrl.h \
9 ostorageinfo.h 13 ostorageinfo.h
10 14
11SOURCES = oapplication.cpp \ 15SOURCES = oapplication.cpp \
12 oconfig.cpp \ 16 oconfig.cpp \
13 odebug.cpp \ 17 odebug.cpp \
18 odevice.cpp \
19 odevicebutton.cpp \
20 odevice_ipaq.cpp \
21 odevice_jornada.cpp \
22 odevice_ramses.cpp \
23 odevice_simpad.cpp \
24 odevice_zaurus.cpp \
25 odevice_yopy.cpp \
14 oglobal.cpp \ 26 oglobal.cpp \
15 oglobalsettings.cpp \ 27 oglobalsettings.cpp \
28 oprocess.cpp \
29 oprocctrl.cpp \
16 ostorageinfo.cpp 30 ostorageinfo.cpp
17 31
18INTERFACES = 32INTERFACES =
19TARGET = opiecore2 33TARGET = opiecore2
20VERSION = 1.8.2 34VERSION = 1.8.3
21INCLUDEPATH += $(OPIEDIR)/include 35INCLUDEPATH += $(OPIEDIR)/include
22DEPENDPATH += $(OPIEDIR)/include 36DEPENDPATH += $(OPIEDIR)/include
23MOC_DIR = moc 37MOC_DIR = moc
diff --git a/libopie2/opiecore/oprocctrl.cpp b/libopie2/opiecore/oprocctrl.cpp
new file mode 100644
index 0000000..b3d57c8
--- a/dev/null
+++ b/libopie2/opiecore/oprocctrl.cpp
@@ -0,0 +1,284 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//
20// KPROCESSCONTROLLER -- A helper class for KProcess
21//
22// version 0.3.1, Jan, 8th 1997
23//
24// (C) Christian Czezatke
25// e9025461@student.tuwien.ac.at
26// Ported by Holger Freyther
27//
28
29//#include <config.h>
30
31#include <sys/types.h>
32#include <sys/socket.h>
33
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <assert.h>
40
41#include <qsocketnotifier.h>
42#include "oprocess.h"
43#include "oprocctrl.h"
44
45OProcessController *OProcessController::theOProcessController = 0;
46
47struct sigaction OProcessController::oldChildHandlerData;
48bool OProcessController::handlerSet = false;
49
50OProcessController::OProcessController()
51{
52 assert( theOProcessController == 0 );
53
54 if (0 > pipe(fd))
55 printf(strerror(errno));
56
57 notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read);
58 notifier->setEnabled(true);
59 QObject::connect(notifier, SIGNAL(activated(int)),
60 this, SLOT(slotDoHousekeeping(int)));
61 connect( &delayedChildrenCleanupTimer, SIGNAL( timeout()),
62 SLOT( delayedChildrenCleanup()));
63
64 theOProcessController = this;
65
66 setupHandlers();
67}
68
69
70void OProcessController::setupHandlers()
71{
72 if( handlerSet )
73 return;
74 struct sigaction act;
75 act.sa_handler=theSigCHLDHandler;
76 sigemptyset(&(act.sa_mask));
77 sigaddset(&(act.sa_mask), SIGCHLD);
78 // Make sure we don't block this signal. gdb tends to do that :-(
79 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0);
80
81 act.sa_flags = SA_NOCLDSTOP;
82
83 // CC: take care of SunOS which automatically restarts interrupted system
84 // calls (and thus does not have SA_RESTART)
85
86#ifdef SA_RESTART
87 act.sa_flags |= SA_RESTART;
88#endif
89
90 sigaction( SIGCHLD, &act, &oldChildHandlerData );
91
92 act.sa_handler=SIG_IGN;
93 sigemptyset(&(act.sa_mask));
94 sigaddset(&(act.sa_mask), SIGPIPE);
95 act.sa_flags = 0;
96 sigaction( SIGPIPE, &act, 0L);
97 handlerSet = true;
98}
99
100void OProcessController::resetHandlers()
101{
102 if( !handlerSet )
103 return;
104 sigaction( SIGCHLD, &oldChildHandlerData, 0 );
105 // there should be no problem with SIGPIPE staying SIG_IGN
106 handlerSet = false;
107}
108
109// block SIGCHLD handler, because it accesses processList
110void OProcessController::addOProcess( OProcess* p )
111{
112 sigset_t newset, oldset;
113 sigemptyset( &newset );
114 sigaddset( &newset, SIGCHLD );
115 sigprocmask( SIG_BLOCK, &newset, &oldset );
116 processList.append( p );
117 sigprocmask( SIG_SETMASK, &oldset, 0 );
118}
119
120void OProcessController::removeOProcess( OProcess* p )
121{
122 sigset_t newset, oldset;
123 sigemptyset( &newset );
124 sigaddset( &newset, SIGCHLD );
125 sigprocmask( SIG_BLOCK, &newset, &oldset );
126 processList.remove( p );
127 sigprocmask( SIG_SETMASK, &oldset, 0 );
128}
129
130//using a struct which contains both the pid and the status makes it easier to write
131//and read the data into the pipe
132//especially this solves a problem which appeared on my box where slotDoHouseKeeping() received
133//only 4 bytes (with some debug output around the write()'s it received all 8 bytes)
134//don't know why this happened, but when writing all 8 bytes at once it works here, aleXXX
135struct waitdata
136{
137 pid_t pid;
138 int status;
139};
140
141void OProcessController::theSigCHLDHandler(int arg)
142{
143 struct waitdata wd;
144 // int status;
145 // pid_t this_pid;
146 int saved_errno;
147
148 saved_errno = errno;
149 // since waitpid and write change errno, we have to save it and restore it
150 // (Richard Stevens, Advanced programming in the Unix Environment)
151
152 bool found = false;
153 if( theOProcessController != 0 )
154 {
155 // iterating the list doesn't perform any system call
156 for( QValueList<OProcess*>::ConstIterator it = theOProcessController->processList.begin();
157 it != theOProcessController->processList.end();
158 ++it )
159 {
160 if( !(*it)->isRunning())
161 continue;
162 wd.pid = waitpid( (*it)->pid(), &wd.status, WNOHANG );
163 if ( wd.pid > 0 )
164 {
165 ::write(theOProcessController->fd[1], &wd, sizeof(wd));
166 found = true;
167 }
168 }
169 }
170 if( !found && oldChildHandlerData.sa_handler != SIG_IGN
171 && oldChildHandlerData.sa_handler != SIG_DFL )
172 oldChildHandlerData.sa_handler( arg ); // call the old handler
173 // handle the rest
174 if( theOProcessController != 0 )
175 {
176 static const struct waitdata dwd = { 0, 0 }
177 ; // delayed waitpid()
178 ::write(theOProcessController->fd[1], &dwd, sizeof(dwd));
179 }
180 else
181 {
182 int dummy;
183 while( waitpid( -1, &dummy, WNOHANG ) > 0 )
184 ;
185 }
186
187 errno = saved_errno;
188}
189
190
191
192void OProcessController::slotDoHousekeeping(int )
193{
194 unsigned int bytes_read = 0;
195 unsigned int errcnt=0;
196 // read pid and status from the pipe.
197 struct waitdata wd;
198 while ((bytes_read < sizeof(wd)) && (errcnt < 50))
199 {
200 int r = ::read(fd[0], ((char *)&wd) + bytes_read, sizeof(wd) - bytes_read);
201 if (r > 0) bytes_read += r;
202 else if (r < 0) errcnt++;
203 }
204 if (errcnt >= 50)
205 {
206 fprintf(stderr,
207 "Error: Max. error count for pipe read "
208 "exceeded in OProcessController::slotDoHousekeeping\n");
209 return; // it makes no sense to continue here!
210 }
211 if (bytes_read != sizeof(wd))
212 {
213 fprintf(stderr,
214 "Error: Could not read info from signal handler %d <> %d!\n",
215 bytes_read, sizeof(wd));
216 return; // it makes no sense to continue here!
217 }
218 if (wd.pid==0)
219 { // special case, see delayedChildrenCleanup()
220 delayedChildrenCleanupTimer.start( 1000, true );
221 return;
222 }
223
224 for( QValueList<OProcess*>::ConstIterator it = processList.begin();
225 it != processList.end();
226 ++it )
227 {
228 OProcess* proc = *it;
229 if (proc->pid() == wd.pid)
230 {
231 // process has exited, so do emit the respective events
232 if (proc->run_mode == OProcess::Block)
233 {
234 // If the reads are done blocking then set the status in proc
235 // but do nothing else because OProcess will perform the other
236 // actions of processHasExited.
237 proc->status = wd.status;
238 proc->runs = false;
239 }
240 else
241 {
242 proc->processHasExited(wd.status);
243 }
244 return;
245 }
246 }
247}
248
249// this is needed e.g. for popen(), which calls waitpid() checking
250// for its forked child, if we did waitpid() directly in the SIGCHLD
251// handler, popen()'s waitpid() call would fail
252void OProcessController::delayedChildrenCleanup()
253{
254 struct waitdata wd;
255 while(( wd.pid = waitpid( -1, &wd.status, WNOHANG ) ) > 0 )
256 {
257 for( QValueList<OProcess*>::ConstIterator it = processList.begin();
258 it != processList.end();
259 ++it )
260 {
261 if( !(*it)->isRunning() || (*it)->pid() != wd.pid )
262 continue;
263 // it's OProcess, handle it
264 ::write(fd[1], &wd, sizeof(wd));
265 break;
266 }
267 }
268}
269
270OProcessController::~OProcessController()
271{
272 assert( theOProcessController == this );
273 resetHandlers();
274
275 notifier->setEnabled(false);
276
277 close(fd[0]);
278 close(fd[1]);
279
280 delete notifier;
281 theOProcessController = 0;
282}
283
284//#include "kprocctrl.moc"
diff --git a/libopie2/opiecore/oprocctrl.h b/libopie2/opiecore/oprocctrl.h
new file mode 100644
index 0000000..44b8a48
--- a/dev/null
+++ b/libopie2/opiecore/oprocctrl.h
@@ -0,0 +1,121 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//
20// KPROCESSCONTROLLER -- A helper class for KProcess
21//
22// version 0.3.1, Jan 8th 1997
23//
24// (C) Christian Czezatke
25// e9025461@student.tuwien.ac.at
26// Ported by Holger Freyther
27//
28
29#ifndef __KPROCCTRL_H__
30#define __KPROCCTRL_H__
31
32#include <qvaluelist.h>
33#include <qtimer.h>
34
35#include "oprocess.h"
36
37class OProcessControllerPrivate;
38class QSocketNotifier;
39
40/**
41 * @short Used internally by @ref OProcess
42 * @internal
43 * @author Christian Czezakte <e9025461@student.tuwien.ac.at>
44 *
45 * A class for internal use by OProcess only. -- Exactly one instance
46 * of this class is generated by the first instance of OProcess that is
47 * created (a pointer to it gets stored in @ref theOProcessController ).
48 *
49 * This class takes care of the actual (UN*X) signal handling.
50*/
51class OProcessController : public QObject
52{
53 Q_OBJECT
54
55public:
56 OProcessController();
57 ~OProcessController();
58 //CC: WARNING! Destructor Not virtual (but you don't derive classes from this anyhow...)
59
60public:
61
62 /**
63 * Only a single instance of this class is allowed at a time,
64 * and this static variable is used to track the one instance.
65 */
66 static OProcessController *theOProcessController;
67
68 /**
69 * Automatically called upon SIGCHLD.
70 *
71 * Normally you do not need to do anything with this function but
72 * if your application needs to disable SIGCHLD for some time for
73 * reasons beyond your control, you should call this function afterwards
74 * to make sure that no SIGCHLDs where missed.
75 */
76 static void theSigCHLDHandler(int signal);
77 // handler for sigchld
78
79 /**
80 * @internal
81 */
82 static void setupHandlers();
83 /**
84 * @internal
85 */
86 static void resetHandlers();
87 /**
88 * @internal
89 */
90 void addOProcess( OProcess* );
91 /**
92 * @internal
93 */
94 void removeOProcess( OProcess* );
95public slots:
96 /**
97 * @internal
98 */
99 void slotDoHousekeeping(int socket);
100
101private slots:
102 void delayedChildrenCleanup();
103private:
104 int fd[2];
105 QSocketNotifier *notifier;
106 static struct sigaction oldChildHandlerData;
107 static bool handlerSet;
108 QValueList<OProcess*> processList;
109 QTimer delayedChildrenCleanupTimer;
110
111 // Disallow assignment and copy-construction
112 OProcessController( const OProcessController& );
113 OProcessController& operator= ( const OProcessController& );
114
115 OProcessControllerPrivate *d;
116};
117
118
119
120#endif
121
diff --git a/libopie2/opiecore/oprocess.cpp b/libopie2/opiecore/oprocess.cpp
new file mode 100644
index 0000000..fb51bf9
--- a/dev/null
+++ b/libopie2/opiecore/oprocess.cpp
@@ -0,0 +1,970 @@
1/*
2
3 $Id$
4
5 This file is part of the KDE libraries
6 Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
22
23*/
24
25
26//
27// KPROCESS -- A class for handling child processes in KDE without
28// having to take care of Un*x specific implementation details
29//
30// version 0.3.1, Jan 8th 1998
31//
32// (C) Christian Czezatke
33// e9025461@student.tuwien.ac.at
34//
35// Changes:
36//
37// March 2nd, 1998: Changed parameter list for KShellProcess:
38// Arguments are now placed in a single string so that
39// <shell> -c <commandstring> is passed to the shell
40// to make the use of "operator<<" consistent with KProcess
41//
42//
43// Ported by Holger Freyther
44// <zekce> Harlekin: oprocess and say it was ported to Qt by the Opie developers an Qt 2
45
46
47
48#include "oprocess.h"
49#define _MAY_INCLUDE_KPROCESSCONTROLLER_
50#include "oprocctrl.h"
51
52//#include <config.h>
53
54#include <qfile.h>
55#include <qsocketnotifier.h>
56#include <qregexp.h>
57
58#include <sys/time.h>
59#include <sys/types.h>
60#include <sys/stat.h>
61#include <sys/socket.h>
62
63#include <errno.h>
64#include <fcntl.h>
65#include <stdlib.h>
66#include <signal.h>
67#include <stdio.h>
68#include <string.h>
69#include <unistd.h>
70#ifdef HAVE_SYS_SELECT_H
71#include <sys/select.h>
72#endif
73#ifdef HAVE_INITGROUPS
74#include <grp.h>
75#endif
76#include <pwd.h>
77
78#include <qapplication.h>
79#include <qmap.h>
80//#include <kdebug.h>
81
82/////////////////////////////
83// public member functions //
84/////////////////////////////
85
86class OProcessPrivate
87{
88public:
89 OProcessPrivate() : useShell(false) { }
90
91 bool useShell;
92 QMap<QString,QString> env;
93 QString wd;
94 QCString shell;
95};
96
97
98OProcess::OProcess(QObject *parent, const char *name)
99 : QObject(parent, name)
100{
101 init ( );
102}
103
104OProcess::OProcess(const QString &arg0, QObject *parent, const char *name)
105 : QObject(parent, name)
106{
107 init ( );
108 *this << arg0;
109}
110
111OProcess::OProcess(const QStringList &args, QObject *parent, const char *name)
112 : QObject(parent, name)
113{
114 init ( );
115 *this << args;
116}
117
118void OProcess::init ( )
119{
120 run_mode = NotifyOnExit;
121 runs = false;
122 pid_ = 0;
123 status = 0;
124 keepPrivs = false;
125 innot = 0;
126 outnot = 0;
127 errnot = 0;
128 communication = NoCommunication;
129 input_data = 0;
130 input_sent = 0;
131 input_total = 0;
132 d = 0;
133
134 if (0 == OProcessController::theOProcessController)
135 {
136 (void) new OProcessController();
137 CHECK_PTR(OProcessController::theOProcessController);
138 }
139
140 OProcessController::theOProcessController->addOProcess(this);
141 out[0] = out[1] = -1;
142 in[0] = in[1] = -1;
143 err[0] = err[1] = -1;
144}
145
146void
147OProcess::setEnvironment(const QString &name, const QString &value)
148{
149 if (!d)
150 d = new OProcessPrivate;
151 d->env.insert(name, value);
152}
153
154void
155OProcess::setWorkingDirectory(const QString &dir)
156{
157 if (!d)
158 d = new OProcessPrivate;
159 d->wd = dir;
160}
161
162void
163OProcess::setupEnvironment()
164{
165 if (d)
166 {
167 QMap<QString,QString>::Iterator it;
168 for(it = d->env.begin(); it != d->env.end(); ++it)
169 setenv(QFile::encodeName(it.key()).data(),
170 QFile::encodeName(it.data()).data(), 1);
171 if (!d->wd.isEmpty())
172 chdir(QFile::encodeName(d->wd).data());
173 }
174}
175
176void
177OProcess::setRunPrivileged(bool keepPrivileges)
178{
179 keepPrivs = keepPrivileges;
180}
181
182bool
183OProcess::runPrivileged() const
184{
185 return keepPrivs;
186}
187
188
189OProcess::~OProcess()
190{
191 // destroying the OProcess instance sends a SIGKILL to the
192 // child process (if it is running) after removing it from the
193 // list of valid processes (if the process is not started as
194 // "DontCare")
195
196 OProcessController::theOProcessController->removeOProcess(this);
197 // this must happen before we kill the child
198 // TODO: block the signal while removing the current process from the process list
199
200 if (runs && (run_mode != DontCare))
201 kill(SIGKILL);
202
203 // Clean up open fd's and socket notifiers.
204 closeStdin();
205 closeStdout();
206 closeStderr();
207
208 // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess
209 delete d;
210}
211
212void OProcess::detach()
213{
214 OProcessController::theOProcessController->removeOProcess(this);
215
216 runs = false;
217 pid_ = 0;
218
219 // Clean up open fd's and socket notifiers.
220 closeStdin();
221 closeStdout();
222 closeStderr();
223}
224
225bool OProcess::setExecutable(const QString& proc)
226{
227 if (runs) return false;
228
229 if (proc.isEmpty()) return false;
230
231 if (!arguments.isEmpty())
232 arguments.remove(arguments.begin());
233 arguments.prepend(QFile::encodeName(proc));
234
235 return true;
236}
237
238OProcess &OProcess::operator<<(const QStringList& args)
239{
240 QStringList::ConstIterator it = args.begin();
241 for ( ; it != args.end() ; ++it )
242 arguments.append(QFile::encodeName(*it));
243 return *this;
244}
245
246OProcess &OProcess::operator<<(const QCString& arg)
247{
248 return operator<< (arg.data());
249}
250
251OProcess &OProcess::operator<<(const char* arg)
252{
253 arguments.append(arg);
254 return *this;
255}
256
257OProcess &OProcess::operator<<(const QString& arg)
258{
259 arguments.append(QFile::encodeName(arg));
260 return *this;
261}
262
263void OProcess::clearArguments()
264{
265 arguments.clear();
266}
267
268bool OProcess::start(RunMode runmode, Communication comm)
269{
270 uint i;
271 uint n = arguments.count();
272 char **arglist;
273
274 if (runs || (0 == n))
275 {
276 return false; // cannot start a process that is already running
277 // or if no executable has been assigned
278 }
279 run_mode = runmode;
280 status = 0;
281
282 QCString shellCmd;
283 if (d && d->useShell)
284 {
285 if (d->shell.isEmpty())
286 {
287 qWarning( "Could not find a valid shell" );
288 return false;
289 }
290
291 arglist = static_cast<char **>(malloc( (4)*sizeof(char *)));
292 for (i=0; i < n; i++)
293 {
294 shellCmd += arguments[i];
295 shellCmd += " "; // CC: to separate the arguments
296 }
297
298 arglist[0] = d->shell.data();
299 arglist[1] = (char *) "-c";
300 arglist[2] = shellCmd.data();
301 arglist[3] = 0;
302 }
303 else
304 {
305 arglist = static_cast<char **>(malloc( (n+1)*sizeof(char *)));
306 for (i=0; i < n; i++)
307 arglist[i] = arguments[i].data();
308 arglist[n]= 0;
309 }
310
311 if (!setupCommunication(comm))
312 qWarning( "Could not setup Communication!");
313
314 // We do this in the parent because if we do it in the child process
315 // gdb gets confused when the application runs from gdb.
316 uid_t uid = getuid();
317 gid_t gid = getgid();
318#ifdef HAVE_INITGROUPS
319 struct passwd *pw = getpwuid(uid);
320#endif
321
322 int fd[2];
323 if (0 > pipe(fd))
324 {
325 fd[0] = fd[1] = 0; // Pipe failed.. continue
326 }
327
328 runs = true;
329
330 QApplication::flushX();
331
332 // WABA: Note that we use fork() and not vfork() because
333 // vfork() has unclear semantics and is not standardized.
334 pid_ = fork();
335
336 if (0 == pid_)
337 {
338 if (fd[0])
339 close(fd[0]);
340 if (!runPrivileged())
341 {
342 setgid(gid);
343#if defined( HAVE_INITGROUPS)
344 if(pw)
345 initgroups(pw->pw_name, pw->pw_gid);
346#endif
347 setuid(uid);
348 }
349 // The child process
350 if(!commSetupDoneC())
351 qWarning( "Could not finish comm setup in child!" );
352
353 setupEnvironment();
354
355 // Matthias
356 if (run_mode == DontCare)
357 setpgid(0,0);
358 // restore default SIGPIPE handler (Harri)
359 struct sigaction act;
360 sigemptyset(&(act.sa_mask));
361 sigaddset(&(act.sa_mask), SIGPIPE);
362 act.sa_handler = SIG_DFL;
363 act.sa_flags = 0;
364 sigaction(SIGPIPE, &act, 0L);
365
366 // We set the close on exec flag.
367 // Closing of fd[1] indicates that the execvp succeeded!
368 if (fd[1])
369 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
370 execvp(arglist[0], arglist);
371 char resultByte = 1;
372 if (fd[1])
373 write(fd[1], &resultByte, 1);
374 _exit(-1);
375 }
376 else if (-1 == pid_)
377 {
378 // forking failed
379
380 runs = false;
381 free(arglist);
382 return false;
383 }
384 else
385 {
386 if (fd[1])
387 close(fd[1]);
388 // the parent continues here
389
390 // Discard any data for stdin that might still be there
391 input_data = 0;
392
393 // Check whether client could be started.
394 if (fd[0]) for(;;)
395 {
396 char resultByte;
397 int n = ::read(fd[0], &resultByte, 1);
398 if (n == 1)
399 {
400 // Error
401 runs = false;
402 close(fd[0]);
403 free(arglist);
404 pid_ = 0;
405 return false;
406 }
407 if (n == -1)
408 {
409 if ((errno == ECHILD) || (errno == EINTR))
410 continue; // Ignore
411 }
412 break; // success
413 }
414 if (fd[0])
415 close(fd[0]);
416
417 if (!commSetupDoneP()) // finish communication socket setup for the parent
418 qWarning( "Could not finish comm setup in parent!" );
419
420 if (run_mode == Block)
421 {
422 commClose();
423
424 // The SIGCHLD handler of the process controller will catch
425 // the exit and set the status
426 while(runs)
427 {
428 OProcessController::theOProcessController->
429 slotDoHousekeeping(0);
430 }
431 runs = FALSE;
432 emit processExited(this);
433 }
434 }
435 free(arglist);
436 return true;
437}
438
439
440
441bool OProcess::kill(int signo)
442{
443 bool rv=false;
444
445 if (0 != pid_)
446 rv= (-1 != ::kill(pid_, signo));
447 // probably store errno somewhere...
448 return rv;
449}
450
451
452
453bool OProcess::isRunning() const
454{
455 return runs;
456}
457
458
459
460pid_t OProcess::pid() const
461{
462 return pid_;
463}
464
465
466
467bool OProcess::normalExit() const
468{
469 int _status = status;
470 return (pid_ != 0) && (!runs) && (WIFEXITED((_status)));
471}
472
473
474
475int OProcess::exitStatus() const
476{
477 int _status = status;
478 return WEXITSTATUS((_status));
479}
480
481
482
483bool OProcess::writeStdin(const char *buffer, int buflen)
484{
485 bool rv;
486
487 // if there is still data pending, writing new data
488 // to stdout is not allowed (since it could also confuse
489 // kprocess...
490 if (0 != input_data)
491 return false;
492
493 if (runs && (communication & Stdin))
494 {
495 input_data = buffer;
496 input_sent = 0;
497 input_total = buflen;
498 slotSendData(0);
499 innot->setEnabled(true);
500 rv = true;
501 }
502 else
503 rv = false;
504 return rv;
505}
506
507void OProcess::flushStdin ( )
508{
509 if ( !input_data || ( input_sent == input_total ))
510 return;
511
512 int d1, d2;
513
514 do
515 {
516 d1 = input_total - input_sent;
517 slotSendData ( 0 );
518 d2 = input_total - input_sent;
519 }
520 while ( d2 <= d1 );
521}
522
523void OProcess::suspend()
524{
525 if ((communication & Stdout) && outnot)
526 outnot->setEnabled(false);
527}
528
529void OProcess::resume()
530{
531 if ((communication & Stdout) && outnot)
532 outnot->setEnabled(true);
533}
534
535bool OProcess::closeStdin()
536{
537 bool rv;
538
539 if (communication & Stdin)
540 {
541 communication = (Communication) (communication & ~Stdin);
542 delete innot;
543 innot = 0;
544 close(in[1]);
545 rv = true;
546 }
547 else
548 rv = false;
549 return rv;
550}
551
552bool OProcess::closeStdout()
553{
554 bool rv;
555
556 if (communication & Stdout)
557 {
558 communication = (Communication) (communication & ~Stdout);
559 delete outnot;
560 outnot = 0;
561 close(out[0]);
562 rv = true;
563 }
564 else
565 rv = false;
566 return rv;
567}
568
569bool OProcess::closeStderr()
570{
571 bool rv;
572
573 if (communication & Stderr)
574 {
575 communication = static_cast<Communication>(communication & ~Stderr);
576 delete errnot;
577 errnot = 0;
578 close(err[0]);
579 rv = true;
580 }
581 else
582 rv = false;
583 return rv;
584}
585
586
587/////////////////////////////
588// protected slots //
589/////////////////////////////
590
591
592
593void OProcess::slotChildOutput(int fdno)
594{
595 if (!childOutput(fdno))
596 closeStdout();
597}
598
599
600void OProcess::slotChildError(int fdno)
601{
602 if (!childError(fdno))
603 closeStderr();
604}
605
606
607void OProcess::slotSendData(int)
608{
609 if (input_sent == input_total)
610 {
611 innot->setEnabled(false);
612 input_data = 0;
613 emit wroteStdin(this);
614 }
615 else
616 input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent);
617}
618
619
620
621//////////////////////////////
622// private member functions //
623//////////////////////////////
624
625
626
627void OProcess::processHasExited(int state)
628{
629 if (runs)
630 {
631 runs = false;
632 status = state;
633
634 commClose(); // cleanup communication sockets
635
636 // also emit a signal if the process was run Blocking
637 if (DontCare != run_mode)
638 {
639 emit processExited(this);
640 }
641 }
642}
643
644
645
646int OProcess::childOutput(int fdno)
647{
648 if (communication & NoRead)
649 {
650 int len = -1;
651 emit receivedStdout(fdno, len);
652 errno = 0; // Make sure errno doesn't read "EAGAIN"
653 return len;
654 }
655 else
656 {
657 char buffer[1024];
658 int len;
659
660 len = ::read(fdno, buffer, 1024);
661
662 if ( 0 < len)
663 {
664 emit receivedStdout(this, buffer, len);
665 }
666 return len;
667 }
668}
669
670
671
672int OProcess::childError(int fdno)
673{
674 char buffer[1024];
675 int len;
676
677 len = ::read(fdno, buffer, 1024);
678
679 if ( 0 < len)
680 emit receivedStderr(this, buffer, len);
681 return len;
682}
683
684
685
686int OProcess::setupCommunication(Communication comm)
687{
688 int ok;
689
690 communication = comm;
691
692 ok = 1;
693 if (comm & Stdin)
694 ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, in) >= 0;
695
696 if (comm & Stdout)
697 ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, out) >= 0;
698
699 if (comm & Stderr)
700 ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, err) >= 0;
701
702 return ok;
703}
704
705
706
707int OProcess::commSetupDoneP()
708{
709 int ok = 1;
710
711 if (communication != NoCommunication)
712 {
713 if (communication & Stdin)
714 close(in[0]);
715 if (communication & Stdout)
716 close(out[1]);
717 if (communication & Stderr)
718 close(err[1]);
719
720 // Don't create socket notifiers and set the sockets non-blocking if
721 // blocking is requested.
722 if (run_mode == Block) return ok;
723
724 if (communication & Stdin)
725 {
726 // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK));
727 innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this);
728 CHECK_PTR(innot);
729 innot->setEnabled(false); // will be enabled when data has to be sent
730 QObject::connect(innot, SIGNAL(activated(int)),
731 this, SLOT(slotSendData(int)));
732 }
733
734 if (communication & Stdout)
735 {
736 // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK));
737 outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
738 CHECK_PTR(outnot);
739 QObject::connect(outnot, SIGNAL(activated(int)),
740 this, SLOT(slotChildOutput(int)));
741 if (communication & NoRead)
742 suspend();
743 }
744
745 if (communication & Stderr)
746 {
747 // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK));
748 errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
749 CHECK_PTR(errnot);
750 QObject::connect(errnot, SIGNAL(activated(int)),
751 this, SLOT(slotChildError(int)));
752 }
753 }
754 return ok;
755}
756
757
758
759int OProcess::commSetupDoneC()
760{
761 int ok = 1;
762 struct linger so;
763 memset(&so, 0, sizeof(so));
764
765 if (communication & Stdin)
766 close(in[1]);
767 if (communication & Stdout)
768 close(out[0]);
769 if (communication & Stderr)
770 close(err[0]);
771
772 if (communication & Stdin)
773 ok &= dup2(in[0], STDIN_FILENO) != -1;
774 else
775 {
776 int null_fd = open( "/dev/null", O_RDONLY );
777 ok &= dup2( null_fd, STDIN_FILENO ) != -1;
778 close( null_fd );
779 }
780 if (communication & Stdout)
781 {
782 ok &= dup2(out[1], STDOUT_FILENO) != -1;
783 ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so));
784 }
785 else
786 {
787 int null_fd = open( "/dev/null", O_WRONLY );
788 ok &= dup2( null_fd, STDOUT_FILENO ) != -1;
789 close( null_fd );
790 }
791 if (communication & Stderr)
792 {
793 ok &= dup2(err[1], STDERR_FILENO) != -1;
794 ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&so), sizeof(so));
795 }
796 else
797 {
798 int null_fd = open( "/dev/null", O_WRONLY );
799 ok &= dup2( null_fd, STDERR_FILENO ) != -1;
800 close( null_fd );
801 }
802 return ok;
803}
804
805
806
807void OProcess::commClose()
808{
809 if (NoCommunication != communication)
810 {
811 bool b_in = (communication & Stdin);
812 bool b_out = (communication & Stdout);
813 bool b_err = (communication & Stderr);
814 if (b_in)
815 delete innot;
816
817 if (b_out || b_err)
818 {
819 // If both channels are being read we need to make sure that one socket buffer
820 // doesn't fill up whilst we are waiting for data on the other (causing a deadlock).
821 // Hence we need to use select.
822
823 // Once one or other of the channels has reached EOF (or given an error) go back
824 // to the usual mechanism.
825
826 int fds_ready = 1;
827 fd_set rfds;
828
829 int max_fd = 0;
830 if (b_out)
831 {
832 fcntl(out[0], F_SETFL, O_NONBLOCK);
833 if (out[0] > max_fd)
834 max_fd = out[0];
835 delete outnot;
836 outnot = 0;
837 }
838 if (b_err)
839 {
840 fcntl(err[0], F_SETFL, O_NONBLOCK);
841 if (err[0] > max_fd)
842 max_fd = err[0];
843 delete errnot;
844 errnot = 0;
845 }
846
847
848 while (b_out || b_err)
849 {
850 // * If the process is still running we block until we
851 // receive data. (p_timeout = 0, no timeout)
852 // * If the process has already exited, we only check
853 // the available data, we don't wait for more.
854 // (p_timeout = &timeout, timeout immediately)
855 struct timeval timeout;
856 timeout.tv_sec = 0;
857 timeout.tv_usec = 0;
858 struct timeval *p_timeout = runs ? 0 : &timeout;
859
860 FD_ZERO(&rfds);
861 if (b_out)
862 FD_SET(out[0], &rfds);
863
864 if (b_err)
865 FD_SET(err[0], &rfds);
866
867 fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
868 if (fds_ready <= 0) break;
869
870 if (b_out && FD_ISSET(out[0], &rfds))
871 {
872 int ret = 1;
873 while (ret > 0) ret = childOutput(out[0]);
874 if ((ret == -1 && errno != EAGAIN) || ret == 0)
875 b_out = false;
876 }
877
878 if (b_err && FD_ISSET(err[0], &rfds))
879 {
880 int ret = 1;
881 while (ret > 0) ret = childError(err[0]);
882 if ((ret == -1 && errno != EAGAIN) || ret == 0)
883 b_err = false;
884 }
885 }
886 }
887
888 if (b_in)
889 {
890 communication = (Communication) (communication & ~Stdin);
891 close(in[1]);
892 }
893 if (b_out)
894 {
895 communication = (Communication) (communication & ~Stdout);
896 close(out[0]);
897 }
898 if (b_err)
899 {
900 communication = (Communication) (communication & ~Stderr);
901 close(err[0]);
902 }
903 }
904}
905
906void OProcess::setUseShell(bool useShell, const char *shell)
907{
908 if (!d)
909 d = new OProcessPrivate;
910 d->useShell = useShell;
911 d->shell = shell;
912 if (d->shell.isEmpty())
913 d->shell = searchShell();
914}
915
916QString OProcess::quote(const QString &arg)
917{
918 QString res = arg;
919 res.replace(QRegExp(QString::fromLatin1("\'")),
920 QString::fromLatin1("'\"'\"'"));
921 res.prepend('\'');
922 res.append('\'');
923 return res;
924}
925
926QCString OProcess::searchShell()
927{
928 QCString tmpShell = QCString(getenv("SHELL")).stripWhiteSpace();
929 if (!isExecutable(tmpShell))
930 {
931 tmpShell = "/bin/sh";
932 }
933
934 return tmpShell;
935}
936
937bool OProcess::isExecutable(const QCString &filename)
938{
939 struct stat fileinfo;
940
941 if (filename.isEmpty()) return false;
942
943 // CC: we've got a valid filename, now let's see whether we can execute that file
944
945 if (-1 == stat(filename.data(), &fileinfo)) return false;
946 // CC: return false if the file does not exist
947
948 // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets
949 if ( (S_ISDIR(fileinfo.st_mode)) ||
950 (S_ISCHR(fileinfo.st_mode)) ||
951 (S_ISBLK(fileinfo.st_mode)) ||
952#ifdef S_ISSOCK
953 // CC: SYSVR4 systems don't have that macro
954 (S_ISSOCK(fileinfo.st_mode)) ||
955#endif
956 (S_ISFIFO(fileinfo.st_mode)) ||
957 (S_ISDIR(fileinfo.st_mode)) )
958 {
959 return false;
960 }
961
962 // CC: now check for permission to execute the file
963 if (access(filename.data(), X_OK) != 0) return false;
964
965 // CC: we've passed all the tests...
966 return true;
967}
968
969
970
diff --git a/libopie2/opiecore/oprocess.h b/libopie2/opiecore/oprocess.h
new file mode 100644
index 0000000..8dd19b5
--- a/dev/null
+++ b/libopie2/opiecore/oprocess.h
@@ -0,0 +1,747 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//
20// KPROCESS -- A class for handling child processes in KDE without
21// having to take care of Un*x specific implementation details
22//
23// version 0.3.1, Jan 8th 1998
24//
25// (C) Christian Czezatke
26// e9025461@student.tuwien.ac.at
27// Ported by Holger Freyther to the Open Palmtop Integrated Environment
28//
29
30#ifndef __kprocess_h__
31#define __kprocess_h__
32
33#include <sys/types.h> // for pid_t
34#include <sys/wait.h>
35#include <signal.h>
36#include <unistd.h>
37#include <qvaluelist.h>
38#include <qcstring.h>
39#include <qobject.h>
40
41class QSocketNotifier;
42class OProcessPrivate;
43
44/**
45 * Child process invocation, monitoring and control.
46 *
47 * @sect General usage and features
48 *
49 *This class allows a KDE and OPIE application to start child processes without having
50 *to worry about UN*X signal handling issues and zombie process reaping.
51 *
52 *@see KProcIO
53 *
54 *Basically, this class distinguishes three different ways of running
55 *child processes:
56 *
57 *@li OProcess::DontCare -- The child process is invoked and both the child
58 *process and the parent process continue concurrently.
59 *
60 *Starting a DontCare child process means that the application is
61 *not interested in any notification to determine whether the
62 *child process has already exited or not.
63 *
64 *@li OProcess::NotifyOnExit -- The child process is invoked and both the
65 *child and the parent process run concurrently.
66 *
67 *When the child process exits, the OProcess instance
68 *corresponding to it emits the Qt signal @ref processExited().
69 *
70 *Since this signal is @em not emitted from within a UN*X
71 *signal handler, arbitrary function calls can be made.
72 *
73 *Be aware: When the OProcess objects gets destructed, the child
74 *process will be killed if it is still running!
75 *This means in particular, that you cannot use a OProcess on the stack
76 *with OProcess::NotifyOnExit.
77 *
78 *@li OProcess::Block -- The child process starts and the parent process
79 *is suspended until the child process exits. (@em Really not recommended
80 *for programs with a GUI.)
81 *
82 *OProcess also provides several functions for determining the exit status
83 *and the pid of the child process it represents.
84 *
85 *Furthermore it is possible to supply command-line arguments to the process
86 *in a clean fashion (no null -- terminated stringlists and such...)
87 *
88 *A small usage example:
89 *<pre>
90 *OProcess *proc = new OProcess;
91 *
92 **proc << "my_executable";
93 **proc << "These" << "are" << "the" << "command" << "line" << "args";
94 *QApplication::connect(proc, SIGNAL(processExited(OProcess *)),
95 * pointer_to_my_object, SLOT(my_objects_slot(OProcess *)));
96 *proc->start();
97 *</pre>
98 *
99 *This will start "my_executable" with the commandline arguments "These"...
100 *
101 *When the child process exits, the respective Qt signal will be emitted.
102 *
103 *@sect Communication with the child process
104 *
105 *OProcess supports communication with the child process through
106 *stdin/stdout/stderr.
107 *
108 *The following functions are provided for getting data from the child
109 *process or sending data to the child's stdin (For more information,
110 *have a look at the documentation of each function):
111 *
112 *@li bool @ref writeStdin(char *buffer, int buflen);
113 *@li -- Transmit data to the child process's stdin.
114 *
115 *@li bool @ref closeStdin();
116 *@li -- Closes the child process's stdin (which causes it to see an feof(stdin)).
117 *Returns false if you try to close stdin for a process that has been started
118 *without a communication channel to stdin.
119 *
120 *@li bool @ref closeStdout();
121 *@li -- Closes the child process's stdout.
122 *Returns false if you try to close stdout for a process that has been started
123 *without a communication channel to stdout.
124 *
125 *@li bool @ref closeStderr();
126 *@li -- Closes the child process's stderr.
127 *Returns false if you try to close stderr for a process that has been started
128 *without a communication channel to stderr.
129 *
130 *
131 *@sect QT signals:
132 *
133 *@li void @ref receivedStdout(OProcess *proc, char *buffer, int buflen);
134 *@li void @ref receivedStderr(OProcess *proc, char *buffer, int buflen);
135 *@li -- Indicates that new data has arrived from either the
136 *child process's stdout or stderr.
137 *
138 *@li void @ref wroteStdin(OProcess *proc);
139 *@li -- Indicates that all data that has been sent to the child process
140 *by a prior call to @ref writeStdin() has actually been transmitted to the
141 *client .
142 *
143 *@author Christian Czezakte e9025461@student.tuwien.ac.at
144 *
145 *
146 **/
147class OProcess : public QObject
148{
149 Q_OBJECT
150
151public:
152
153 /**
154 * Modes in which the communication channel can be opened.
155 *
156 * If communication for more than one channel is required,
157 * the values have to be or'ed together, for example to get
158 * communication with stdout as well as with stdin, you would
159 * specify @p Stdin @p | @p Stdout
160 *
161 * If @p NoRead is specified in conjunction with @p Stdout,
162 * no data is actually read from @p Stdout but only
163 * the signal @ref childOutput(int fd) is emitted.
164 */
165 enum Communication { NoCommunication = 0, Stdin = 1, Stdout = 2, Stderr = 4,
166 AllOutput = 6, All = 7,
167 NoRead };
168
169 /**
170 * Run-modes for a child process.
171 */
172 enum RunMode {
173 /**
174 * The application does not receive notifications from the subprocess when
175 * it is finished or aborted.
176 */
177 DontCare,
178 /**
179 * The application is notified when the subprocess dies.
180 */
181 NotifyOnExit,
182 /**
183 * The application is suspended until the started process is finished.
184 */
185 Block };
186
187 /**
188 * Constructor
189 */
190 OProcess(QObject *parent = 0, const char *name = 0);
191 /**
192 * Constructor
193 */
194 OProcess(const QString &arg0, QObject *parent = 0, const char *name = 0);
195 /**
196 * Constructor
197 */
198 OProcess(const QStringList &args, QObject *parent = 0, const char *name = 0);
199
200 /**
201 *Destructor:
202 *
203 * If the process is running when the destructor for this class
204 * is called, the child process is killed with a SIGKILL, but
205 * only if the run mode is not of type @p DontCare.
206 * Processes started as @p DontCare keep running anyway.
207 */
208 virtual ~OProcess();
209
210 /**
211 @deprecated
212
213 The use of this function is now deprecated. -- Please use the
214 "operator<<" instead of "setExecutable".
215
216 Sets the executable to be started with this OProcess object.
217 Returns false if the process is currently running (in that
218 case the executable remains unchanged.)
219
220 @see operator<<
221
222 */
223 bool setExecutable(const QString& proc);
224
225
226 /**
227 * Sets the executable and the command line argument list for this process.
228 *
229 * For example, doing an "ls -l /usr/local/bin" can be achieved by:
230 * <pre>
231 * OProcess p;
232 * ...
233 * p << "ls" << "-l" << "/usr/local/bin"
234 * </pre>
235 *
236 **/
237 OProcess &operator<<(const QString& arg);
238 /**
239 * Similar to previous method, takes a char *, supposed to be in locale 8 bit already.
240 */
241 OProcess &operator<<(const char * arg);
242 /**
243 * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already.
244 */
245 OProcess &operator<<(const QCString & arg);
246
247 /**
248 * Sets the executable and the command line argument list for this process,
249 * in a single method call, or add a list of arguments.
250 **/
251 OProcess &operator<<(const QStringList& args);
252
253 /**
254 * Clear a command line argument list that has been set by using
255 * the "operator<<".
256 */
257 void clearArguments();
258
259 /**
260 * Starts the process.
261 * For a detailed description of the
262 * various run modes and communication semantics, have a look at the
263 * general description of the OProcess class.
264 *
265 * The following problems could cause this function to
266 * return false:
267 *
268 * @li The process is already running.
269 * @li The command line argument list is empty.
270 * @li The starting of the process failed (could not fork).
271 * @li The executable was not found.
272 *
273 * @param comm Specifies which communication links should be
274 * established to the child process (stdin/stdout/stderr). By default,
275 * no communication takes place and the respective communication
276 * signals will never get emitted.
277 *
278 * @return true on success, false on error
279 * (see above for error conditions)
280 **/
281 virtual bool start(RunMode runmode = NotifyOnExit,
282 Communication comm = NoCommunication);
283
284 /**
285 * Stop the process (by sending it a signal).
286 *
287 * @param signoThe signal to send. The default is SIGTERM.
288 * @return @p true if the signal was delivered successfully.
289 */
290 virtual bool kill(int signo = SIGTERM);
291
292 /**
293 @return @p true if the process is (still) considered to be running
294 */
295 bool isRunning() const;
296
297 /** Returns the process id of the process.
298 *
299 * If it is called after
300 * the process has exited, it returns the process id of the last
301 * child process that was created by this instance of OProcess.
302 *
303 * Calling it before any child process has been started by this
304 * OProcess instance causes pid() to return 0.
305 **/
306 pid_t pid() const;
307
308 /**
309 * Suspend processing of data from stdout of the child process.
310 */
311 void suspend();
312
313 /**
314 * Resume processing of data from stdout of the child process.
315 */
316 void resume();
317
318 /**
319 * @return @p true if the process has already finished and has exited
320 * "voluntarily", ie: it has not been killed by a signal.
321 *
322 * Note that you should check @ref OProcess::exitStatus() to determine
323 * whether the process completed its task successful or not.
324 */
325 bool normalExit() const;
326
327 /**
328 * Returns the exit status of the process.
329 *
330 * Please use
331 * @ref OProcess::normalExit() to check whether the process has exited
332 * cleanly (i.e., @ref OProcess::normalExit() returns @p true) before calling
333 * this function because if the process did not exit normally,
334 * it does not have a valid exit status.
335 */
336 int exitStatus() const;
337
338
339 /**
340 * Transmit data to the child process's stdin.
341 *
342 * OProcess::writeStdin may return false in the following cases:
343 *
344 * @li The process is not currently running.
345 *
346 * @li Communication to stdin has not been requested in the @ref start() call.
347 *
348 * @li Transmission of data to the child process by a previous call to
349 * @ref writeStdin() is still in progress.
350 *
351 * Please note that the data is sent to the client asynchronously,
352 * so when this function returns, the data might not have been
353 * processed by the child process.
354 *
355 * If all the data has been sent to the client, the signal
356 * @ref wroteStdin() will be emitted.
357 *
358 * Please note that you must not free "buffer" or call @ref writeStdin()
359 * again until either a @ref wroteStdin() signal indicates that the
360 * data has been sent or a @ref processHasExited() signal shows that
361 * the child process is no longer alive...
362 **/
363 bool writeStdin(const char *buffer, int buflen);
364
365 void flushStdin();
366
367 /**
368 * This causes the stdin file descriptor of the child process to be
369 * closed indicating an "EOF" to the child.
370 *
371 * @return @p false if no communication to the process's stdin
372 * had been specified in the call to @ref start().
373 */
374 bool closeStdin();
375
376 /**
377 * This causes the stdout file descriptor of the child process to be
378 * closed.
379 *
380 * @return @p false if no communication to the process's stdout
381 * had been specified in the call to @ref start().
382 */
383 bool closeStdout();
384
385 /**
386 * This causes the stderr file descriptor of the child process to be
387 * closed.
388 *
389 * @return @p false if no communication to the process's stderr
390 * had been specified in the call to @ref start().
391 */
392 bool closeStderr();
393
394 /**
395 * Lets you see what your arguments are for debugging.
396 */
397
398 const QValueList<QCString> &args() { return arguments; }
399
400 /**
401 * Controls whether the started process should drop any
402 * setuid/segid privileges or whether it should keep them
403 *
404 * The default is @p false : drop privileges
405 */
406 void setRunPrivileged(bool keepPrivileges);
407
408 /**
409 * Returns whether the started process will drop any
410 * setuid/segid privileges or whether it will keep them
411 */
412 bool runPrivileged() const;
413
414 /**
415 * Modifies the environment of the process to be started.
416 * This function must be called before starting the process.
417 */
418 void setEnvironment(const QString &name, const QString &value);
419
420 /**
421 * Changes the current working directory (CWD) of the process
422 * to be started.
423 * This function must be called before starting the process.
424 */
425 void setWorkingDirectory(const QString &dir);
426
427 /**
428 * Specify whether to start the command via a shell or directly.
429 * The default is to start the command directly.
430 * If @p useShell is true @p shell will be used as shell, or
431 * if shell is empty, the standard shell is used.
432 * @p quote A flag indicating whether to quote the arguments.
433 *
434 * When using a shell, the caller should make sure that all filenames etc.
435 * are properly quoted when passed as argument.
436 * @see quote()
437 */
438 void setUseShell(bool useShell, const char *shell = 0);
439
440 /**
441 * This function can be used to quote an argument string such that
442 * the shell processes it properly. This is e. g. necessary for
443 * user-provided file names which may contain spaces or quotes.
444 * It also prevents expansion of wild cards and environment variables.
445 */
446 static QString quote(const QString &arg);
447
448 /**
449 * Detaches OProcess from child process. All communication is closed.
450 * No exit notification is emitted any more for the child process.
451 * Deleting the OProcess will no longer kill the child process.
452 * Note that the current process remains the parent process of the
453 * child process.
454 */
455 void detach();
456
457
458
459signals:
460
461 /**
462 * Emitted after the process has terminated when
463 * the process was run in the @p NotifyOnExit (==default option to
464 * @ref start()) or the @ref Block mode.
465 **/
466 void processExited(OProcess *proc);
467
468
469 /**
470 * Emitted, when output from the child process has
471 * been received on stdout.
472 *
473 * To actually get
474 * these signals, the respective communication link (stdout/stderr)
475 * has to be turned on in @ref start().
476 *
477 * @param buffer The data received.
478 * @param buflen The number of bytes that are available.
479 *
480 * You should copy the information contained in @p buffer to your private
481 * data structures before returning from this slot.
482 **/
483 void receivedStdout(OProcess *proc, char *buffer, int buflen);
484
485 /**
486 * Emitted when output from the child process has
487 * been received on stdout.
488 *
489 * To actually get these signals, the respective communications link
490 * (stdout/stderr) has to be turned on in @ref start() and the
491 * @p NoRead flag should have been passed.
492 *
493 * You will need to explicitly call resume() after your call to start()
494 * to begin processing data from the child process's stdout. This is
495 * to ensure that this signal is not emitted when no one is connected
496 * to it, otherwise this signal will not be emitted.
497 *
498 * The data still has to be read from file descriptor @p fd.
499 **/
500 void receivedStdout(int fd, int &len);
501
502
503 /**
504 * Emitted, when output from the child process has
505 * been received on stderr.
506 * To actually get
507 * these signals, the respective communication link (stdout/stderr)
508 * has to be turned on in @ref start().
509 *
510 * @param buffer The data received.
511 * @param buflen The number of bytes that are available.
512 *
513 * You should copy the information contained in @p buffer to your private
514 * data structures before returning from this slot.
515 */
516 void receivedStderr(OProcess *proc, char *buffer, int buflen);
517
518 /**
519 * Emitted after all the data that has been
520 * specified by a prior call to @ref writeStdin() has actually been
521 * written to the child process.
522 **/
523 void wroteStdin(OProcess *proc);
524
525
526protected slots:
527
528 /**
529 * This slot gets activated when data from the child's stdout arrives.
530 * It usually calls "childOutput"
531 */
532 void slotChildOutput(int fdno);
533
534 /**
535 * This slot gets activated when data from the child's stderr arrives.
536 * It usually calls "childError"
537 */
538 void slotChildError(int fdno);
539 /*
540 Slot functions for capturing stdout and stderr of the child
541 */
542
543 /**
544 * Called when another bulk of data can be sent to the child's
545 * stdin. If there is no more data to be sent to stdin currently
546 * available, this function must disable the QSocketNotifier "innot".
547 */
548 void slotSendData(int dummy);
549
550protected:
551
552 /**
553 * Sets up the environment according to the data passed via
554 * setEnvironment(...)
555 */
556 void setupEnvironment();
557
558 /**
559 * The list of the process' command line arguments. The first entry
560 * in this list is the executable itself.
561 */
562 QValueList<QCString> arguments;
563 /**
564 * How to run the process (Block, NotifyOnExit, DontCare). You should
565 * not modify this data member directly from derived classes.
566 */
567 RunMode run_mode;
568 /**
569 * true if the process is currently running. You should not
570 * modify this data member directly from derived classes. For
571 * reading the value of this data member, please use "isRunning()"
572 * since "runs" will probably be made private in later versions
573 * of OProcess.
574 */
575 bool runs;
576
577 /**
578 * The PID of the currently running process (see "getPid()").
579 * You should not modify this data member in derived classes.
580 * Please use "getPid()" instead of directly accessing this
581 * member function since it will probably be made private in
582 * later versions of OProcess.
583 */
584 pid_t pid_;
585
586 /**
587 * The process' exit status as returned by "waitpid". You should not
588 * modify the value of this data member from derived classes. You should
589 * rather use @ref exitStatus than accessing this data member directly
590 * since it will probably be made private in further versions of
591 * OProcess.
592 */
593 int status;
594
595
596 /**
597 * See setRunPrivileged()
598 */
599 bool keepPrivs;
600
601 /*
602 Functions for setting up the sockets for communication.
603 setupCommunication
604 -- is called from "start" before "fork"ing.
605 commSetupDoneP
606 -- completes communication socket setup in the parent
607 commSetupDoneC
608 -- completes communication setup in the child process
609 commClose
610 -- frees all allocated communication resources in the parent
611 after the process has exited
612 */
613
614 /**
615 * This function is called from "OProcess::start" right before a "fork" takes
616 * place. According to
617 * the "comm" parameter this function has to initialize the "in", "out" and
618 * "err" data member of OProcess.
619 *
620 * This function should return 0 if setting the needed communication channels
621 * was successful.
622 *
623 * The default implementation is to create UNIX STREAM sockets for the communication,
624 * but you could overload this function and establish a TCP/IP communication for
625 * network communication, for example.
626 */
627 virtual int setupCommunication(Communication comm);
628
629 /**
630 * Called right after a (successful) fork on the parent side. This function
631 * will usually do some communications cleanup, like closing the reading end
632 * of the "stdin" communication channel.
633 *
634 * Furthermore, it must also create the QSocketNotifiers "innot", "outnot" and
635 * "errnot" and connect their Qt slots to the respective OProcess member functions.
636 *
637 * For a more detailed explanation, it is best to have a look at the default
638 * implementation of "setupCommunication" in kprocess.cpp.
639 */
640 virtual int commSetupDoneP();
641
642 /**
643 * Called right after a (successful) fork, but before an "exec" on the child
644 * process' side. It usually just closes the unused communication ends of
645 * "in", "out" and "err" (like the writing end of the "in" communication
646 * channel.
647 */
648 virtual int commSetupDoneC();
649
650
651 /**
652 * Immediately called after a process has exited. This function normally
653 * calls commClose to close all open communication channels to this
654 * process and emits the "processExited" signal (if the process was
655 * not running in the "DontCare" mode).
656 */
657 virtual void processHasExited(int state);
658
659 /**
660 * Should clean up the communication links to the child after it has
661 * exited. Should be called from "processHasExited".
662 */
663 virtual void commClose();
664
665
666 /**
667 * the socket descriptors for stdin/stdout/stderr.
668 */
669 int out[2];
670 int in[2];
671 int err[2];
672
673 /**
674 * The socket notifiers for the above socket descriptors.
675 */
676 QSocketNotifier *innot;
677 QSocketNotifier *outnot;
678 QSocketNotifier *errnot;
679
680 /**
681 * Lists the communication links that are activated for the child
682 * process. Should not be modified from derived classes.
683 */
684 Communication communication;
685
686 /**
687 * Called by "slotChildOutput" this function copies data arriving from the
688 * child process's stdout to the respective buffer and emits the signal
689 * "@ref receivedStderr".
690 */
691 int childOutput(int fdno);
692
693 /**
694 * Called by "slotChildOutput" this function copies data arriving from the
695 * child process's stdout to the respective buffer and emits the signal
696 * "@ref receivedStderr"
697 */
698 int childError(int fdno);
699
700 // information about the data that has to be sent to the child:
701
702 const char *input_data; // the buffer holding the data
703 int input_sent; // # of bytes already transmitted
704 int input_total; // total length of input_data
705
706 /**
707 * @ref OProcessController is a friend of OProcess because it has to have
708 * access to various data members.
709 */
710 friend class OProcessController;
711
712
713private:
714 /**
715 * Searches for a valid shell.
716 * Here is the algorithm used for finding an executable shell:
717 *
718 * @li Try the executable pointed to by the "SHELL" environment
719 * variable with white spaces stripped off
720 *
721 * @li If your process runs with uid != euid or gid != egid, a shell
722 * not listed in /etc/shells will not used.
723 *
724 * @li If no valid shell could be found, "/bin/sh" is used as a last resort.
725 */
726 QCString searchShell();
727
728 /**
729 * Used by @ref searchShell in order to find out whether the shell found
730 * is actually executable at all.
731 */
732 bool isExecutable(const QCString &filename);
733
734 // Disallow assignment and copy-construction
735 OProcess( const OProcess& );
736 OProcess& operator= ( const OProcess& );
737
738private:
739 void init ( );
740
741 OProcessPrivate *d;
742};
743
744
745
746#endif
747