author | llornkcor <llornkcor> | 2006-04-23 21:07:19 (UTC) |
---|---|---|
committer | llornkcor <llornkcor> | 2006-04-23 21:07:19 (UTC) |
commit | 2457dde10b8108a74f160b5d1c6bdbb877e0099a (patch) (unidiff) | |
tree | 7453c0ac4fdafb55702a05fa09117fe3da31721d /libopie2 | |
parent | 226ccbb7d87a54411d640432f0ac19cbd942aa01 (diff) | |
download | opie-2457dde10b8108a74f160b5d1c6bdbb877e0099a.zip opie-2457dde10b8108a74f160b5d1c6bdbb877e0099a.tar.gz opie-2457dde10b8108a74f160b5d1c6bdbb877e0099a.tar.bz2 |
add support for HTC Universal device
-rw-r--r-- | libopie2/opiecore/device/odevice_htc.cpp | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/libopie2/opiecore/device/odevice_htc.cpp b/libopie2/opiecore/device/odevice_htc.cpp new file mode 100644 index 0000000..a40308d --- a/dev/null +++ b/libopie2/opiecore/device/odevice_htc.cpp | |||
@@ -0,0 +1,721 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) 2002-2005 The Opie Team <opie-devel@handhelds.org> | ||
4 | =. Copyright (C) 2002-2005 Michael 'Mickey' Lauer <mickey@Vanille.de> | ||
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; version 2 of the License. | ||
12 | ._= =} : | ||
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_htc.h" | ||
31 | |||
32 | /* OPIE */ | ||
33 | #include <opie2/oinputsystem.h> | ||
34 | #include <opie2/oresource.h> | ||
35 | |||
36 | #include <qpe/config.h> | ||
37 | #include <qpe/sound.h> | ||
38 | |||
39 | /* QT */ | ||
40 | #include <qapplication.h> | ||
41 | #include <qfile.h> | ||
42 | #include <qtextstream.h> | ||
43 | #include <qwindowsystem_qws.h> | ||
44 | #include <qcopchannel_qws.h> | ||
45 | |||
46 | /* STD */ | ||
47 | #include <string.h> | ||
48 | #include <errno.h> | ||
49 | #include <fcntl.h> | ||
50 | #include <math.h> | ||
51 | #include <stdlib.h> | ||
52 | #include <signal.h> | ||
53 | #include <sys/ioctl.h> | ||
54 | #include <sys/time.h> | ||
55 | #include <unistd.h> | ||
56 | #ifndef QT_NO_SOUND | ||
57 | #include <linux/soundcard.h> | ||
58 | #endif | ||
59 | |||
60 | using namespace Opie::Core; | ||
61 | using namespace Opie::Core::Internal; | ||
62 | |||
63 | struct htc_button htc_buttons [] = { | ||
64 | { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), | ||
65 | "devicebuttons/z_calendar", | ||
66 | "datebook", "nextView()", | ||
67 | "today", "raise()" }, | ||
68 | { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), | ||
69 | "devicebuttons/z_contact", | ||
70 | "addressbook", "raise()", | ||
71 | "addressbook", "beamBusinessCard()" }, | ||
72 | { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), | ||
73 | "devicebuttons/z_home", | ||
74 | "QPE/Launcher", "home()", | ||
75 | "buttonsettings", "raise()" }, | ||
76 | { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), | ||
77 | "devicebuttons/z_menu", | ||
78 | "QPE/TaskBar", "toggleMenu()", | ||
79 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
80 | { Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), | ||
81 | "devicebuttons/z_mail", | ||
82 | "opiemail", "raise()", | ||
83 | "opiemail", "newMail()" }, | ||
84 | }; | ||
85 | |||
86 | struct htc_button htc_buttons_universal [] = { | ||
87 | { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), | ||
88 | "devicebuttons/z_calendar", | ||
89 | "datebook", "nextView()", | ||
90 | "today", "raise()" }, | ||
91 | { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), | ||
92 | "devicebuttons/z_contact", | ||
93 | "addressbook", "raise()", | ||
94 | "addressbook", "beamBusinessCard()" }, | ||
95 | { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), | ||
96 | "devicebuttons/z_home", | ||
97 | "QPE/Launcher", "home()", | ||
98 | "buttonsettings", "raise()" }, | ||
99 | { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), | ||
100 | "devicebuttons/z_menu", | ||
101 | "QPE/TaskBar", "toggleMenu()", | ||
102 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
103 | { Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), | ||
104 | "devicebuttons/z_mail", | ||
105 | "opiemail", "raise()", | ||
106 | "opiemail", "newMail()" }, | ||
107 | |||
108 | { Qt::Key_F15, QT_TRANSLATE_NOOP("Button", "Hinge1"), | ||
109 | "devicebuttons/z_hinge1", | ||
110 | "QPE/Rotation", "rotateDefault()",0}, | ||
111 | { Qt::Key_F16, QT_TRANSLATE_NOOP("Button", "Hinge2"), | ||
112 | "devicebuttons/z_hinge2", | ||
113 | "QPE/Rotation", "rotateDefault()",0}, | ||
114 | { Qt::Key_F17, QT_TRANSLATE_NOOP("Button", "Hinge3"), | ||
115 | "devicebuttons/z_hinge3", | ||
116 | "QPE/Rotation", "rotateDefault()",0}, | ||
117 | }; | ||
118 | |||
119 | struct htc_button htc_buttons_6000 [] = { | ||
120 | { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), | ||
121 | "devicebuttons/z_calendar", | ||
122 | "datebook", "nextView()", | ||
123 | "today", "raise()" }, | ||
124 | { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), | ||
125 | "devicebuttons/z_contact", | ||
126 | "addressbook", "raise()", | ||
127 | "addressbook", "beamBusinessCard()" }, | ||
128 | { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), | ||
129 | "devicebuttons/z_home", | ||
130 | "QPE/Launcher", "home()", | ||
131 | "buttonsettings", "raise()" }, | ||
132 | { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), | ||
133 | "devicebuttons/z_menu", | ||
134 | "QPE/TaskBar", "toggleMenu()", | ||
135 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
136 | { Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), | ||
137 | "devicebuttons/z_mail", | ||
138 | "opiemail", "raise()", | ||
139 | "opiemail", "newMail()" }, | ||
140 | { Qt::Key_F15, QT_TRANSLATE_NOOP("Button", "Rotate Button"), | ||
141 | "devicebuttons/z_rotate", | ||
142 | 0, | ||
143 | "QPE/Rotation", "rotateDefault()" }, | ||
144 | { Qt::Key_F24, QT_TRANSLATE_NOOP("Button", "Record Button"), | ||
145 | "devicebuttons/z_hinge3", | ||
146 | "QPE/VMemo", "toggleRecord()", | ||
147 | "sound", "raise()" }, | ||
148 | }; | ||
149 | |||
150 | // FIXME This gets unnecessary complicated. We should think about splitting the HTC | ||
151 | // class up into individual classes. We would need three classes | ||
152 | // | ||
153 | // HTC-Universal (PXA-model w/ 640x480 lcd, for Universal) | ||
154 | |||
155 | void HTC::init(const QString& cpu_info) | ||
156 | { | ||
157 | qDebug( "HTC::init()" ); | ||
158 | // Set the time to wait until the system is really suspended | ||
159 | // the delta between apm --suspend and sleeping | ||
160 | setAPMTimeOut( 15000 ); | ||
161 | |||
162 | // generic distribution code already scanned /etc/issue at that point - | ||
163 | // embedix releases contain "Embedix <version> | Linux for Embedded Devices" | ||
164 | if ( d->m_sysverstr.contains( "embedix", false ) ) | ||
165 | { | ||
166 | d->m_vendorstr = "HTC"; | ||
167 | d->m_vendor = Vendor_HTC; | ||
168 | d->m_systemstr = "OpenEmbedded"; | ||
169 | d->m_system = System_OpenEmbedded; | ||
170 | m_embedix = true; | ||
171 | } | ||
172 | else | ||
173 | { | ||
174 | d->m_vendorstr = "Xanadux Team"; | ||
175 | d->m_systemstr = "Familiar"; | ||
176 | d->m_system = System_Familiar; | ||
177 | // sysver already gathered | ||
178 | |||
179 | // OpenHTC sometimes uses the 2.4 (embedix) kernel, check if this is one | ||
180 | FILE *uname = popen("uname -r", "r"); | ||
181 | QFile f; | ||
182 | QString line; | ||
183 | if ( f.open(IO_ReadOnly, uname) ) { | ||
184 | QTextStream ts ( &f ); | ||
185 | line = ts.readLine(); | ||
186 | m_embedix = line.startsWith( "2.4." ); | ||
187 | f.close(); | ||
188 | } | ||
189 | pclose(uname); | ||
190 | } | ||
191 | |||
192 | // check the HTC model | ||
193 | QString model; | ||
194 | int loc = cpu_info.find( ":" ); | ||
195 | if ( loc != -1 ) | ||
196 | model = cpu_info.mid( loc+2 ).simplifyWhiteSpace(); | ||
197 | else | ||
198 | model = cpu_info; | ||
199 | |||
200 | if ( model == "HTC Universal" ) { | ||
201 | d->m_model = Model_HTC_Universal; | ||
202 | d->m_modelstr = "HTC Universal"; | ||
203 | } else { | ||
204 | d->m_model = Model_HTC_Universal; | ||
205 | d->m_modelstr = "Unknown HTC"; | ||
206 | } | ||
207 | |||
208 | // set path to backlight device in kernel 2.6 | ||
209 | switch ( d->m_model ) | ||
210 | { | ||
211 | case Model_HTC_Universal: | ||
212 | default: | ||
213 | // m_backlightdev = "/sys/class/backlight/corgi-bl/"; | ||
214 | m_backlightdev = "/sys/class/backlight/pxafb/"; | ||
215 | } | ||
216 | |||
217 | // set initial rotation | ||
218 | switch( d->m_model ) | ||
219 | { | ||
220 | case Model_HTC_Universal: | ||
221 | initHingeSensor(); | ||
222 | d->m_rotation = rotation(); | ||
223 | d->m_direction = direction(); | ||
224 | break; | ||
225 | default: | ||
226 | d->m_rotation = Rot270; | ||
227 | } | ||
228 | |||
229 | // set default qte driver | ||
230 | switch( d->m_model ) | ||
231 | { | ||
232 | default: | ||
233 | d->m_qteDriver = "Transformed"; | ||
234 | } | ||
235 | |||
236 | m_leds[0] = Led_Off; | ||
237 | |||
238 | if ( m_embedix ) | ||
239 | qDebug( "HTC::init() - Using the 2.4 Embedix HAL on a %s", (const char*) d->m_modelstr ); | ||
240 | else | ||
241 | qDebug( "HTC::init() - Using the 2.6 Xanadux HAL on a %s", (const char*) d->m_modelstr ); | ||
242 | } | ||
243 | |||
244 | void HTC::initButtons() | ||
245 | { | ||
246 | qDebug( "HTC::initButtons()" ); | ||
247 | if ( d->m_buttons ) | ||
248 | return; | ||
249 | |||
250 | d->m_buttons = new QValueList <ODeviceButton>; | ||
251 | |||
252 | struct htc_button * phtc_buttons; | ||
253 | int buttoncount; | ||
254 | switch ( d->m_model ) | ||
255 | { | ||
256 | case Model_HTC_Universal: | ||
257 | if ( isQWS( ) ) | ||
258 | { | ||
259 | addPreHandler(this); | ||
260 | } | ||
261 | phtc_buttons = htc_buttons_universal; | ||
262 | buttoncount = ARRAY_SIZE(htc_buttons_universal); | ||
263 | break; | ||
264 | default: | ||
265 | phtc_buttons = htc_buttons; | ||
266 | buttoncount = ARRAY_SIZE(htc_buttons); | ||
267 | break; | ||
268 | } | ||
269 | |||
270 | for ( int i = 0; i < buttoncount; i++ ) { | ||
271 | struct htc_button *zb = phtc_buttons + i; | ||
272 | ODeviceButton b; | ||
273 | |||
274 | b.setKeycode( zb->code ); | ||
275 | b.setUserText( QObject::tr( "Button", zb->utext )); | ||
276 | b.setPixmap( OResource::loadPixmap( zb->pix )); | ||
277 | b.setFactoryPresetPressedAction( OQCopMessage( makeChannel ( zb->fpressedservice ), zb->fpressedaction )); | ||
278 | b.setFactoryPresetHeldAction( OQCopMessage( makeChannel ( zb->fheldservice ), zb->fheldaction )); | ||
279 | d->m_buttons->append( b ); | ||
280 | } | ||
281 | |||
282 | reloadButtonMapping(); | ||
283 | } | ||
284 | |||
285 | |||
286 | |||
287 | typedef struct sharp_led_status { | ||
288 | int which; /* select which LED status is wanted. */ | ||
289 | int status; /* set new led status if you call SHARP_LED_SETSTATUS */ | ||
290 | } sharp_led_status; | ||
291 | |||
292 | void HTC::buzzer( int sound ) | ||
293 | { | ||
294 | #ifndef QT_NO_SOUND | ||
295 | Sound *snd = 0; | ||
296 | |||
297 | // All devices except SL5500 have a DSP device | ||
298 | if ( d->m_model == Model_HTC_Universal ) { | ||
299 | |||
300 | switch ( sound ){ | ||
301 | case SHARP_BUZ_TOUCHSOUND: { | ||
302 | static Sound touch_sound("touchsound"); | ||
303 | snd = &touch_sound; | ||
304 | } | ||
305 | break; | ||
306 | case SHARP_BUZ_KEYSOUND: { | ||
307 | static Sound key_sound( "keysound" ); | ||
308 | snd = &key_sound; | ||
309 | } | ||
310 | break; | ||
311 | case SHARP_BUZ_SCHEDULE_ALARM: | ||
312 | default: { | ||
313 | static Sound alarm_sound("alarm"); | ||
314 | snd = &alarm_sound; | ||
315 | } | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | // If a soundname is defined, we expect that this device has | ||
321 | // sound capabilities.. Otherwise we expect to have the buzzer | ||
322 | // device.. | ||
323 | if ( snd && snd->isFinished() ){ | ||
324 | changeMixerForAlarm( 0, "/dev/sound/mixer", snd ); | ||
325 | snd->play(); | ||
326 | } else if( !snd ) { | ||
327 | int fd = ::open ( "/dev/sharp_buz", O_WRONLY|O_NONBLOCK ); | ||
328 | |||
329 | if ( fd >= 0 ) { | ||
330 | ::ioctl ( fd, SHARP_BUZZER_MAKESOUND, sound ); | ||
331 | ::close ( fd ); | ||
332 | } | ||
333 | |||
334 | } | ||
335 | #endif | ||
336 | } | ||
337 | |||
338 | |||
339 | void HTC::playAlarmSound() | ||
340 | { | ||
341 | buzzer( SHARP_BUZ_SCHEDULE_ALARM ); | ||
342 | } | ||
343 | |||
344 | void HTC::playTouchSound() | ||
345 | { | ||
346 | buzzer( SHARP_BUZ_TOUCHSOUND ); | ||
347 | } | ||
348 | |||
349 | void HTC::playKeySound() | ||
350 | { | ||
351 | buzzer( SHARP_BUZ_KEYSOUND ); | ||
352 | } | ||
353 | |||
354 | |||
355 | QValueList <OLed> HTC::ledList() const | ||
356 | { | ||
357 | QValueList <OLed> vl; | ||
358 | vl << Led_Mail; | ||
359 | return vl; | ||
360 | } | ||
361 | |||
362 | QValueList <OLedState> HTC::ledStateList( OLed l ) const | ||
363 | { | ||
364 | QValueList <OLedState> vl; | ||
365 | |||
366 | if ( l == Led_Mail ) | ||
367 | vl << Led_Off << Led_On << Led_BlinkSlow; | ||
368 | return vl; | ||
369 | } | ||
370 | |||
371 | OLedState HTC::ledState( OLed which ) const | ||
372 | { | ||
373 | if ( which == Led_Mail ) | ||
374 | return m_leds [0]; | ||
375 | else | ||
376 | return Led_Off; | ||
377 | } | ||
378 | |||
379 | bool HTC::setLedState( OLed which, OLedState st ) | ||
380 | { | ||
381 | // Currently not supported on non_embedix kernels | ||
382 | if (!m_embedix) | ||
383 | { | ||
384 | qDebug( "HTC::setLedState: ODevice handling for non-embedix kernels not yet implemented" ); | ||
385 | return false; | ||
386 | } | ||
387 | |||
388 | static int fd = ::open ( "/dev/sharp_led", O_RDWR|O_NONBLOCK ); | ||
389 | |||
390 | if ( which == Led_Mail ) { | ||
391 | if ( fd >= 0 ) { | ||
392 | struct sharp_led_status leds; | ||
393 | ::memset ( &leds, 0, sizeof( leds )); | ||
394 | leds. which = SHARP_LED_MAIL_EXISTS; | ||
395 | bool ok = true; | ||
396 | |||
397 | switch ( st ) { | ||
398 | case Led_Off : leds. status = LED_MAIL_NO_UNREAD_MAIL; break; | ||
399 | case Led_On : leds. status = LED_MAIL_NEWMAIL_EXISTS; break; | ||
400 | case Led_BlinkSlow: leds. status = LED_MAIL_UNREAD_MAIL_EX; break; | ||
401 | default : ok = false; | ||
402 | } | ||
403 | |||
404 | if ( ok && ( ::ioctl ( fd, SHARP_LED_SETSTATUS, &leds ) >= 0 )) { | ||
405 | m_leds [0] = st; | ||
406 | return true; | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | return false; | ||
411 | } | ||
412 | |||
413 | int HTC::displayBrightnessResolution() const | ||
414 | { | ||
415 | /* MV */ | ||
416 | return 16; | ||
417 | |||
418 | int res = 1; | ||
419 | if (m_embedix) | ||
420 | { | ||
421 | int fd = ::open( SHARP_FL_IOCTL_DEVICE, O_RDWR|O_NONBLOCK ); | ||
422 | if ( fd ) | ||
423 | { | ||
424 | int value = ::ioctl( fd, SHARP_FL_IOCTL_GET_STEP, 0 ); | ||
425 | ::close( fd ); | ||
426 | return value ? value : res; | ||
427 | } | ||
428 | } | ||
429 | else | ||
430 | { | ||
431 | int fd = ::open( m_backlightdev + "max_brightness", O_RDONLY|O_NONBLOCK ); | ||
432 | if ( fd ) | ||
433 | { | ||
434 | char buf[100]; | ||
435 | if ( ::read( fd, &buf[0], sizeof buf ) ) ::sscanf( &buf[0], "%d", &res ); | ||
436 | ::close( fd ); | ||
437 | } | ||
438 | } | ||
439 | return res; | ||
440 | } | ||
441 | |||
442 | bool HTC::setDisplayBrightness( int bright ) | ||
443 | { | ||
444 | /* MV */ | ||
445 | return false; | ||
446 | |||
447 | //qDebug( "HTC::setDisplayBrightness( %d )", bright ); | ||
448 | bool res = false; | ||
449 | |||
450 | if ( bright > 255 ) bright = 255; | ||
451 | if ( bright < 0 ) bright = 0; | ||
452 | |||
453 | int numberOfSteps = displayBrightnessResolution(); | ||
454 | int val = ( bright == 1 ) ? 1 : ( bright * numberOfSteps ) / 255; | ||
455 | |||
456 | if ( m_embedix ) | ||
457 | { | ||
458 | int fd = ::open( SHARP_FL_IOCTL_DEVICE, O_WRONLY|O_NONBLOCK ); | ||
459 | if ( fd ) | ||
460 | { | ||
461 | res = ( ::ioctl( fd, SHARP_FL_IOCTL_STEP_CONTRAST, val ) == 0 ); | ||
462 | ::close( fd ); | ||
463 | } | ||
464 | } | ||
465 | else | ||
466 | { | ||
467 | int fd = ::open( m_backlightdev + "brightness", O_WRONLY|O_NONBLOCK ); | ||
468 | if ( fd ) | ||
469 | { | ||
470 | char buf[100]; | ||
471 | int len = ::snprintf( &buf[0], sizeof buf, "%d", val ); | ||
472 | res = ( ::write( fd, &buf[0], len ) == 0 ); | ||
473 | ::close( fd ); | ||
474 | } | ||
475 | } | ||
476 | return res; | ||
477 | } | ||
478 | |||
479 | bool HTC::setDisplayStatus( bool on ) | ||
480 | { | ||
481 | /* MV */ | ||
482 | return false; | ||
483 | |||
484 | bool res = false; | ||
485 | if ( m_embedix ) | ||
486 | { | ||
487 | int fd = ::open( SHARP_FL_IOCTL_DEVICE, O_WRONLY|O_NONBLOCK ); | ||
488 | if ( fd ) | ||
489 | { | ||
490 | int ioctlnum = on ? SHARP_FL_IOCTL_ON : SHARP_FL_IOCTL_OFF; | ||
491 | res = ( ::ioctl ( fd, ioctlnum, 0 ) == 0 ); | ||
492 | ::close ( fd ); | ||
493 | } | ||
494 | } | ||
495 | else | ||
496 | { | ||
497 | int fd = ::open( m_backlightdev + "power", O_WRONLY|O_NONBLOCK ); | ||
498 | if ( fd ) | ||
499 | { | ||
500 | char buf[10]; | ||
501 | buf[0] = on ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | ||
502 | buf[1] = '\0'; | ||
503 | res = ( ::write( fd, &buf[0], 2 ) == 0 ); | ||
504 | ::close( fd ); | ||
505 | } | ||
506 | } | ||
507 | return res; | ||
508 | } | ||
509 | |||
510 | Transformation HTC::rotation() const | ||
511 | { | ||
512 | qDebug( "HTC::rotation()" ); | ||
513 | Transformation rot; | ||
514 | |||
515 | switch ( d->m_model ) { | ||
516 | case Model_HTC_Universal: | ||
517 | { | ||
518 | OHingeStatus hs = readHingeSensor(); | ||
519 | qDebug( "HTC::rotation() - hinge sensor = %d", (int) hs ); | ||
520 | if ( hs == CASE_PORTRAIT ) rot = Rot0; | ||
521 | else if ( hs == CASE_UNKNOWN ) rot = Rot270; | ||
522 | else rot = Rot270; | ||
523 | } | ||
524 | break; | ||
525 | } | ||
526 | |||
527 | qDebug( "HTC::rotation() - returning '%d'", rot ); | ||
528 | return rot; | ||
529 | } | ||
530 | ODirection HTC::direction() const | ||
531 | { | ||
532 | ODirection dir; | ||
533 | |||
534 | switch ( d->m_model ) { | ||
535 | case Model_HTC_Universal: { | ||
536 | OHingeStatus hs = readHingeSensor(); | ||
537 | if ( hs == CASE_PORTRAIT ) dir = CCW; | ||
538 | else if ( hs == CASE_UNKNOWN ) dir = CCW; | ||
539 | else dir = CW; | ||
540 | } | ||
541 | break; | ||
542 | default: dir = d->m_direction; | ||
543 | break; | ||
544 | } | ||
545 | return dir; | ||
546 | |||
547 | } | ||
548 | |||
549 | bool HTC::hasHingeSensor() const | ||
550 | { | ||
551 | return d->m_model == Model_HTC_Universal; | ||
552 | } | ||
553 | |||
554 | OHingeStatus HTC::readHingeSensor() const | ||
555 | { | ||
556 | if (m_embedix) | ||
557 | { | ||
558 | int handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); | ||
559 | if (handle == -1) | ||
560 | { | ||
561 | qWarning("HTC::readHingeSensor() - failed (%s)", "unknown reason" ); //FIXME: use strerror | ||
562 | return CASE_UNKNOWN; | ||
563 | } | ||
564 | else | ||
565 | { | ||
566 | int retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); | ||
567 | ::close (handle); | ||
568 | if ( retval == CASE_CLOSED || retval == CASE_PORTRAIT || retval == CASE_LANDSCAPE ) | ||
569 | { | ||
570 | qDebug( "HTC::readHingeSensor() - result = %d", retval ); | ||
571 | return static_cast<OHingeStatus>( retval ); | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | qWarning("HTC::readHingeSensor() - couldn't compute hinge status!" ); | ||
576 | return CASE_UNKNOWN; | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | /* | ||
583 | * The HTC Universal keyboard is event source 1 in kernel 2.6. | ||
584 | * Hinge status is reported via Input System Switchs 0 and 1 like that: | ||
585 | * | ||
586 | * ------------------------- | ||
587 | * | SW0 | SW1 | CASE | | ||
588 | * |-----|-----|-----------| | ||
589 | * | 0 0 Unknown | | ||
590 | * | 1 0 Portrait | | ||
591 | * | 0 1 Closed | | ||
592 | * | 1 1 Landscape | | ||
593 | * ------------------------- | ||
594 | */ | ||
595 | OInputDevice* keyboard = OInputSystem::instance()->device( "event1" ); | ||
596 | bool switch0 = true; | ||
597 | bool switch1 = false; | ||
598 | if ( keyboard ) | ||
599 | { | ||
600 | switch0 = keyboard->isHeld( OInputDevice::Switch0 ); | ||
601 | switch1 = keyboard->isHeld( OInputDevice::Switch1 ); | ||
602 | } | ||
603 | if ( switch0 ) | ||
604 | { | ||
605 | return switch1 ? CASE_LANDSCAPE : CASE_PORTRAIT; | ||
606 | } | ||
607 | else | ||
608 | { | ||
609 | return switch1 ? CASE_CLOSED : CASE_UNKNOWN; | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | |||
614 | void HTC::initHingeSensor() | ||
615 | { | ||
616 | if ( m_embedix ) return; | ||
617 | |||
618 | m_hinge.setName( "/dev/input/event1" ); | ||
619 | if ( !m_hinge.open( IO_ReadOnly ) ) | ||
620 | { | ||
621 | qWarning( "HTC::init() - Couldn't open /dev/input/event1 for read (%s)", strerror( errno ) ); | ||
622 | return; | ||
623 | } | ||
624 | |||
625 | QSocketNotifier* sn = new QSocketNotifier( m_hinge.handle(), QSocketNotifier::Read, this ); | ||
626 | QObject::connect( sn, SIGNAL(activated(int)), this, SLOT(hingeSensorTriggered()) ); | ||
627 | |||
628 | qDebug( "HTC::init() - Hinge Sensor Initialization successfully completed" ); | ||
629 | } | ||
630 | |||
631 | void HTC::hingeSensorTriggered() | ||
632 | { | ||
633 | qDebug( "HTC::hingeSensorTriggered() - got event" ); | ||
634 | struct input_event e; | ||
635 | if ( ::read( m_hinge.handle(), &e, sizeof e ) > 0 ) | ||
636 | { | ||
637 | qDebug( "HTC::hingeSensorTriggered() - event has type %d, code %d, value %d", e.type, e.code, e.value ); | ||
638 | if ( e.type != EV_SW ) return; | ||
639 | if ( readHingeSensor() != CASE_UNKNOWN ) | ||
640 | { | ||
641 | qDebug( "HTC::hingeSensorTriggered() - got valid switch event, calling rotateDefault()" ); | ||
642 | QCopChannel::send( "QPE/Rotation", "rotateDefault()" ); | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | |||
647 | void HTC::systemMessage( const QCString &msg, const QByteArray & ) | ||
648 | { | ||
649 | if ( msg == "deviceButtonMappingChanged()" ) { | ||
650 | reloadButtonMapping(); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * Take code from iPAQ device. | ||
656 | * That way we switch the cursor directions depending on status of hinge sensor, eg. hardware direction. | ||
657 | * I hope that is ok - Alwin | ||
658 | */ | ||
659 | bool HTC::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat ) | ||
660 | { | ||
661 | int newkeycode = keycode; | ||
662 | |||
663 | if ( !hasHingeSensor() ) return false; | ||
664 | |||
665 | /* map cursor keys depending on the hinge status */ | ||
666 | switch ( keycode ) { | ||
667 | // Rotate cursor keys | ||
668 | case Key_Left : | ||
669 | case Key_Right: | ||
670 | case Key_Up : | ||
671 | case Key_Down : | ||
672 | { | ||
673 | if (rotation()==Rot90) { | ||
674 | newkeycode = Key_Left + ( keycode - Key_Left + 3 ) % 4; | ||
675 | } | ||
676 | } | ||
677 | break; | ||
678 | |||
679 | } | ||
680 | if (newkeycode!=keycode) { | ||
681 | if ( newkeycode != Key_unknown ) { | ||
682 | QWSServer::sendKeyEvent ( -1, newkeycode, modifiers, isPress, autoRepeat ); | ||
683 | } | ||
684 | return true; | ||
685 | } | ||
686 | return false; | ||
687 | } | ||
688 | |||
689 | bool HTC::suspend() { | ||
690 | |||
691 | /* MV */ | ||
692 | return false; | ||
693 | |||
694 | if ( !isQWS( ) ) // only qwsserver is allowed to suspend | ||
695 | return false; | ||
696 | |||
697 | bool res = false; | ||
698 | QCopChannel::send( "QPE/System", "aboutToSuspend()" ); | ||
699 | |||
700 | struct timeval tvs, tvn; | ||
701 | ::gettimeofday ( &tvs, 0 ); | ||
702 | |||
703 | ::sync(); // flush fs caches | ||
704 | res = ( ::system ( "apm --suspend" ) == 0 ); | ||
705 | |||
706 | // This is needed because some apm implementations are asynchronous and we | ||
707 | // can not be sure when exactly the device is really suspended | ||
708 | // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists. | ||
709 | // on non embedix eg. 2.6 kernel line apm is synchronous so we don't need it here. | ||
710 | |||
711 | if ( res && m_embedix) { | ||
712 | do { // wait at most 1.5 sec: either suspend didn't work or the device resumed | ||
713 | ::usleep ( 200 * 1000 ); | ||
714 | ::gettimeofday ( &tvn, 0 ); | ||
715 | } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < m_timeOut ); | ||
716 | } | ||
717 | |||
718 | QCopChannel::send( "QPE/System", "returnFromSuspend()" ); | ||
719 | |||
720 | return res; | ||
721 | } | ||