src/video/ipod/SDL_ipodvideo.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 10 Jul 2006 21:04:37 +0000
changeset 1895 c121d94672cb
parent 1545 8d9bb0cf2c2a
child 2669 e27bdcc80744
child 2735 204be4fc2726
permissions -rw-r--r--
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
slouken@1402
     1
/*
slouken@1402
     2
    SDL - Simple DirectMedia Layer
slouken@1402
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@1402
     4
slouken@1402
     5
    This library is free software; you can redistribute it and/or
slouken@1402
     6
    modify it under the terms of the GNU Lesser General Public
slouken@1402
     7
    License as published by the Free Software Foundation; either
slouken@1402
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@1402
     9
slouken@1402
    10
    This library is distributed in the hope that it will be useful,
slouken@1402
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@1402
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1402
    13
    Lesser General Public License for more details.
slouken@1402
    14
slouken@1402
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1402
    16
    License along with this library; if not, write to the Free Software
slouken@1402
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@1402
    18
slouken@1402
    19
    Sam Lantinga
slouken@1402
    20
    slouken@libsdl.org
slouken@1402
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@1402
    23
icculus@1140
    24
#include <sys/types.h>
icculus@1140
    25
#include <sys/ioctl.h>
icculus@1140
    26
icculus@1140
    27
#include <unistd.h>
icculus@1140
    28
#include <fcntl.h>
icculus@1140
    29
#include <string.h>
icculus@1140
    30
#include <termios.h>
icculus@1140
    31
#include <ctype.h>
icculus@1140
    32
icculus@1140
    33
#include <linux/vt.h>
icculus@1140
    34
#include <linux/kd.h>
icculus@1140
    35
#include <linux/keyboard.h>
icculus@1140
    36
#include <linux/fb.h>
icculus@1140
    37
icculus@1140
    38
#include "SDL_video.h"
icculus@1140
    39
#include "SDL_mouse.h"
slouken@1361
    40
#include "../SDL_sysvideo.h"
slouken@1361
    41
#include "../SDL_pixels_c.h"
slouken@1361
    42
#include "../../events/SDL_events_c.h"
icculus@1140
    43
#include "SDL_sysevents.h"
icculus@1140
    44
#include "SDL_ipodvideo.h"
icculus@1140
    45
icculus@1140
    46
#define _THIS SDL_VideoDevice *this
icculus@1140
    47
slouken@1895
    48
static int iPod_VideoInit(_THIS, SDL_PixelFormat * vformat);
slouken@1895
    49
static SDL_Rect **iPod_ListModes(_THIS, SDL_PixelFormat * format,
slouken@1895
    50
                                 Uint32 flags);
slouken@1895
    51
static SDL_Surface *iPod_SetVideoMode(_THIS, SDL_Surface * current,
slouken@1895
    52
                                      int width, int height, int bpp,
slouken@1895
    53
                                      Uint32 flags);
slouken@1895
    54
static int iPod_SetColors(_THIS, int firstcolor, int ncolors,
slouken@1895
    55
                          SDL_Color * colors);
slouken@1895
    56
static void iPod_UpdateRects(_THIS, int nrects, SDL_Rect * rects);
slouken@1895
    57
static void iPod_VideoQuit(_THIS);
slouken@1895
    58
static void iPod_PumpEvents(_THIS);
icculus@1140
    59
icculus@1140
    60
static long iPod_GetGeneration();
icculus@1140
    61
icculus@1140
    62
static int initd = 0;
icculus@1140
    63
static int kbfd = -1;
icculus@1140
    64
static int fbfd = -1;
icculus@1140
    65
static int oldvt = -1;
icculus@1140
    66
static int curvt = -1;
icculus@1140
    67
static int old_kbmode = -1;
icculus@1140
    68
static long generation = 0;
icculus@1140
    69
static struct termios old_termios, cur_termios;
icculus@1140
    70
icculus@1140
    71
FILE *dbgout;
icculus@1140
    72
icculus@1140
    73
#define LCD_DATA          0x10
icculus@1140
    74
#define LCD_CMD           0x08
icculus@1140
    75
#define IPOD_OLD_LCD_BASE 0xc0001000
icculus@1140
    76
#define IPOD_OLD_LCD_RTC  0xcf001110
icculus@1140
    77
#define IPOD_NEW_LCD_BASE 0x70003000
icculus@1140
    78
#define IPOD_NEW_LCD_RTC  0x60005010
icculus@1140
    79
icculus@1140
    80
static unsigned long lcd_base, lcd_rtc, lcd_width, lcd_height;
icculus@1140
    81
slouken@1895
    82
static long
slouken@1895
    83
iPod_GetGeneration()
icculus@1140
    84
{
icculus@1140
    85
    int i;
icculus@1140
    86
    char cpuinfo[256];
icculus@1140
    87
    char *ptr;
icculus@1140
    88
    FILE *file;
slouken@1895
    89
icculus@1140
    90
    if ((file = fopen("/proc/cpuinfo", "r")) != NULL) {
slouken@1895
    91
        while (fgets(cpuinfo, sizeof(cpuinfo), file) != NULL)
slouken@1895
    92
            if (SDL_strncmp(cpuinfo, "Revision", 8) == 0)
slouken@1895
    93
                break;
slouken@1895
    94
        fclose(file);
icculus@1140
    95
    }
icculus@1140
    96
    for (i = 0; !isspace(cpuinfo[i]); i++);
icculus@1140
    97
    for (; isspace(cpuinfo[i]); i++);
icculus@1140
    98
    ptr = cpuinfo + i + 2;
slouken@1895
    99
slouken@1336
   100
    return SDL_strtol(ptr, NULL, 10);
icculus@1140
   101
}
icculus@1140
   102
slouken@1895
   103
static int
slouken@1895
   104
iPod_Available()
icculus@1140
   105
{
icculus@1140
   106
    return 1;
icculus@1140
   107
}
icculus@1140
   108
slouken@1895
   109
static void
slouken@1895
   110
iPod_DeleteDevice(SDL_VideoDevice * device)
icculus@1140
   111
{
slouken@1895
   112
    free(device->hidden);
slouken@1895
   113
    free(device);
icculus@1140
   114
}
icculus@1140
   115
slouken@1895
   116
void
slouken@1895
   117
iPod_InitOSKeymap(_THIS)
slouken@1895
   118
{
slouken@1895
   119
}
icculus@1140
   120
slouken@1895
   121
static SDL_VideoDevice *
slouken@1895
   122
iPod_CreateDevice(int devindex)
icculus@1140
   123
{
icculus@1140
   124
    SDL_VideoDevice *this;
slouken@1895
   125
slouken@1895
   126
    this = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
icculus@1140
   127
    if (this) {
slouken@1895
   128
        memset(this, 0, sizeof *this);
slouken@1895
   129
        this->hidden = (struct SDL_PrivateVideoData *)
slouken@1895
   130
            SDL_malloc(sizeof(struct SDL_PrivateVideoData));
icculus@1140
   131
    }
icculus@1140
   132
    if (!this || !this->hidden) {
slouken@1895
   133
        SDL_OutOfMemory();
slouken@1895
   134
        if (this)
slouken@1895
   135
            SDL_free(this);
slouken@1895
   136
        return 0;
icculus@1140
   137
    }
slouken@1895
   138
    memset(this->hidden, 0, sizeof(struct SDL_PrivateVideoData));
slouken@1895
   139
icculus@1140
   140
    generation = iPod_GetGeneration();
icculus@1140
   141
icculus@1140
   142
    this->VideoInit = iPod_VideoInit;
icculus@1140
   143
    this->ListModes = iPod_ListModes;
icculus@1140
   144
    this->SetVideoMode = iPod_SetVideoMode;
icculus@1140
   145
    this->SetColors = iPod_SetColors;
icculus@1140
   146
    this->UpdateRects = iPod_UpdateRects;
icculus@1140
   147
    this->VideoQuit = iPod_VideoQuit;
icculus@1140
   148
    this->AllocHWSurface = 0;
icculus@1140
   149
    this->CheckHWBlit = 0;
icculus@1140
   150
    this->FillHWRect = 0;
icculus@1140
   151
    this->SetHWColorKey = 0;
icculus@1140
   152
    this->SetHWAlpha = 0;
icculus@1140
   153
    this->LockHWSurface = 0;
icculus@1140
   154
    this->UnlockHWSurface = 0;
icculus@1140
   155
    this->FlipHWSurface = 0;
icculus@1140
   156
    this->FreeHWSurface = 0;
icculus@1140
   157
    this->SetCaption = 0;
icculus@1140
   158
    this->SetIcon = 0;
icculus@1140
   159
    this->IconifyWindow = 0;
icculus@1140
   160
    this->GrabInput = 0;
icculus@1140
   161
    this->GetWMInfo = 0;
icculus@1140
   162
    this->InitOSKeymap = iPod_InitOSKeymap;
icculus@1140
   163
    this->PumpEvents = iPod_PumpEvents;
icculus@1140
   164
    this->free = iPod_DeleteDevice;
icculus@1140
   165
icculus@1140
   166
    return this;
icculus@1140
   167
}
icculus@1140
   168
icculus@1140
   169
VideoBootStrap iPod_bootstrap = {
icculus@1140
   170
    "ipod", "iPod Framebuffer Driver",
icculus@1140
   171
    iPod_Available, iPod_CreateDevice
icculus@1140
   172
};
icculus@1140
   173
icculus@1140
   174
//--//
icculus@1140
   175
slouken@1895
   176
static int
slouken@1895
   177
iPod_VideoInit(_THIS, SDL_PixelFormat * vformat)
icculus@1140
   178
{
icculus@1140
   179
    if (!initd) {
slouken@1895
   180
        /*** Code adapted/copied from SDL fbcon driver. ***/
icculus@1140
   181
slouken@1895
   182
        static const char *const tty0[] = { "/dev/tty0", "/dev/vc/0", 0 };
slouken@1895
   183
        static const char *const vcs[] = { "/dev/vc/%d", "/dev/tty%d", 0 };
slouken@1895
   184
        int i, tty0_fd;
icculus@1140
   185
slouken@1895
   186
        dbgout =
slouken@1895
   187
            fdopen(open("/etc/sdlpod.log", O_WRONLY | O_SYNC | O_APPEND),
slouken@1895
   188
                   "a");
slouken@1895
   189
        if (dbgout) {
slouken@1895
   190
            setbuf(dbgout, 0);
slouken@1895
   191
            fprintf(dbgout, "--> Started SDL <--\n");
slouken@1895
   192
        }
slouken@1895
   193
        // Try to query for a free VT
slouken@1895
   194
        tty0_fd = -1;
slouken@1895
   195
        for (i = 0; tty0[i] && (tty0_fd < 0); ++i) {
slouken@1895
   196
            tty0_fd = open(tty0[i], O_WRONLY, 0);
slouken@1895
   197
        }
slouken@1895
   198
        if (tty0_fd < 0) {
slouken@1895
   199
            tty0_fd = dup(0);   /* Maybe stdin is a VT? */
slouken@1895
   200
        }
slouken@1895
   201
        ioctl(tty0_fd, VT_OPENQRY, &curvt);
slouken@1895
   202
        close(tty0_fd);
icculus@1140
   203
slouken@1895
   204
        tty0_fd = open("/dev/tty", O_RDWR, 0);
slouken@1895
   205
        if (tty0_fd >= 0) {
slouken@1895
   206
            ioctl(tty0_fd, TIOCNOTTY, 0);
slouken@1895
   207
            close(tty0_fd);
slouken@1895
   208
        }
icculus@1140
   209
slouken@1895
   210
        if ((geteuid() == 0) && (curvt > 0)) {
slouken@1895
   211
            for (i = 0; vcs[i] && (kbfd < 0); ++i) {
slouken@1895
   212
                char vtpath[12];
icculus@1140
   213
slouken@1895
   214
                SDL_snprintf(vtpath, SDL_arraysize(vtpath), vcs[i], curvt);
slouken@1895
   215
                kbfd = open(vtpath, O_RDWR);
slouken@1895
   216
            }
slouken@1895
   217
        }
slouken@1895
   218
        if (kbfd < 0) {
slouken@1895
   219
            if (dbgout)
slouken@1895
   220
                fprintf(dbgout, "Couldn't open any VC\n");
slouken@1895
   221
            return -1;
slouken@1895
   222
        }
slouken@1895
   223
        if (dbgout)
slouken@1895
   224
            fprintf(stderr, "Current VT: %d\n", curvt);
icculus@1140
   225
slouken@1895
   226
        if (kbfd >= 0) {
slouken@1895
   227
            /* Switch to the correct virtual terminal */
slouken@1895
   228
            if (curvt > 0) {
slouken@1895
   229
                struct vt_stat vtstate;
icculus@1140
   230
slouken@1895
   231
                if (ioctl(kbfd, VT_GETSTATE, &vtstate) == 0) {
slouken@1895
   232
                    oldvt = vtstate.v_active;
slouken@1895
   233
                }
slouken@1895
   234
                if (ioctl(kbfd, VT_ACTIVATE, curvt) == 0) {
slouken@1895
   235
                    if (dbgout)
slouken@1895
   236
                        fprintf(dbgout, "Waiting for switch to this VT... ");
slouken@1895
   237
                    ioctl(kbfd, VT_WAITACTIVE, curvt);
slouken@1895
   238
                    if (dbgout)
slouken@1895
   239
                        fprintf(dbgout, "done!\n");
slouken@1895
   240
                }
slouken@1895
   241
            }
slouken@1895
   242
            // Set terminal input mode
slouken@1895
   243
            if (tcgetattr(kbfd, &old_termios) < 0) {
slouken@1895
   244
                if (dbgout)
slouken@1895
   245
                    fprintf(dbgout, "Can't get termios\n");
slouken@1895
   246
                return -1;
slouken@1895
   247
            }
slouken@1895
   248
            cur_termios = old_termios;
slouken@1895
   249
            //      cur_termios.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON);
slouken@1895
   250
            //      cur_termios.c_iflag |= (BRKINT);
slouken@1895
   251
            //      cur_termios.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN);
slouken@1895
   252
            //      cur_termios.c_oflag &= ~(OPOST);
slouken@1895
   253
            //      cur_termios.c_oflag |= (ONOCR | ONLRET);
slouken@1895
   254
            cur_termios.c_lflag &= ~(ICANON | ECHO | ISIG);
slouken@1895
   255
            cur_termios.c_iflag &=
slouken@1895
   256
                ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
slouken@1895
   257
            cur_termios.c_cc[VMIN] = 0;
slouken@1895
   258
            cur_termios.c_cc[VTIME] = 0;
icculus@1140
   259
slouken@1895
   260
            if (tcsetattr(kbfd, TCSAFLUSH, &cur_termios) < 0) {
slouken@1895
   261
                if (dbgout)
slouken@1895
   262
                    fprintf(dbgout, "Can't set termios\n");
slouken@1895
   263
                return -1;
slouken@1895
   264
            }
slouken@1895
   265
            if (ioctl(kbfd, KDSKBMODE, K_MEDIUMRAW) < 0) {
slouken@1895
   266
                if (dbgout)
slouken@1895
   267
                    fprintf(dbgout, "Can't set medium-raw mode\n");
slouken@1895
   268
                return -1;
slouken@1895
   269
            }
slouken@1895
   270
            if (ioctl(kbfd, KDSETMODE, KD_GRAPHICS) < 0) {
slouken@1895
   271
                if (dbgout)
slouken@1895
   272
                    fprintf(dbgout, "Can't set graphics\n");
slouken@1895
   273
                return -1;
slouken@1895
   274
            }
slouken@1895
   275
        }
slouken@1895
   276
        // Open the framebuffer
slouken@1895
   277
        if ((fbfd = open("/dev/fb0", O_RDWR)) < 0) {
slouken@1895
   278
            if (dbgout)
slouken@1895
   279
                fprintf(dbgout, "Can't open framebuffer\n");
slouken@1895
   280
            return -1;
slouken@1895
   281
        } else {
slouken@1895
   282
            struct fb_var_screeninfo vinfo;
icculus@1140
   283
slouken@1895
   284
            if (dbgout)
slouken@1895
   285
                fprintf(dbgout, "Generation: %ld\n", generation);
icculus@1140
   286
slouken@1895
   287
            if (generation >= 40000) {
slouken@1895
   288
                lcd_base = IPOD_NEW_LCD_BASE;
slouken@1895
   289
            } else {
slouken@1895
   290
                lcd_base = IPOD_OLD_LCD_BASE;
slouken@1895
   291
            }
icculus@1140
   292
slouken@1895
   293
            ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
slouken@1895
   294
            close(fbfd);
icculus@1140
   295
slouken@1895
   296
            if (lcd_base == IPOD_OLD_LCD_BASE)
slouken@1895
   297
                lcd_rtc = IPOD_OLD_LCD_RTC;
slouken@1895
   298
            else if (lcd_base == IPOD_NEW_LCD_BASE)
slouken@1895
   299
                lcd_rtc = IPOD_NEW_LCD_RTC;
slouken@1895
   300
            else {
slouken@1895
   301
                SDL_SetError("Unknown iPod version");
slouken@1895
   302
                return -1;
slouken@1895
   303
            }
icculus@1140
   304
slouken@1895
   305
            lcd_width = vinfo.xres;
slouken@1895
   306
            lcd_height = vinfo.yres;
icculus@1140
   307
slouken@1895
   308
            if (dbgout)
slouken@1895
   309
                fprintf(dbgout, "LCD is %dx%d\n", lcd_width, lcd_height);
slouken@1895
   310
        }
icculus@1140
   311
slouken@1895
   312
        fcntl(kbfd, F_SETFL, O_RDWR | O_NONBLOCK);
slouken@1545
   313
slouken@1895
   314
        /* Determine the current screen size */
slouken@1895
   315
        this->info.current_w = lcd_width;
slouken@1895
   316
        this->info.current_h = lcd_height;
icculus@1140
   317
slouken@1895
   318
        if ((generation >= 60000) && (generation < 70000)) {
slouken@1895
   319
            vformat->BitsPerPixel = 16;
slouken@1895
   320
            vformat->Rmask = 0xF800;
slouken@1895
   321
            vformat->Gmask = 0x07E0;
slouken@1895
   322
            vformat->Bmask = 0x001F;
slouken@1895
   323
        } else {
slouken@1895
   324
            vformat->BitsPerPixel = 8;
slouken@1895
   325
            vformat->Rmask = vformat->Gmask = vformat->Bmask = 0;
slouken@1895
   326
        }
slouken@1895
   327
slouken@1895
   328
        initd = 1;
slouken@1895
   329
        if (dbgout)
slouken@1895
   330
            fprintf(dbgout, "Initialized.\n\n");
icculus@1140
   331
    }
icculus@1140
   332
    return 0;
icculus@1140
   333
}
icculus@1140
   334
slouken@1895
   335
static SDL_Rect **
slouken@1895
   336
iPod_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags)
icculus@1140
   337
{
icculus@1140
   338
    int width, height, fd;
icculus@1140
   339
    static SDL_Rect r;
icculus@1140
   340
    static SDL_Rect *rs[2] = { &r, 0 };
icculus@1140
   341
slouken@1895
   342
    if ((fd = open("/dev/fb0", O_RDWR)) < 0) {
slouken@1895
   343
        return 0;
icculus@1140
   344
    } else {
slouken@1895
   345
        struct fb_var_screeninfo vinfo;
slouken@1895
   346
slouken@1895
   347
        ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
slouken@1895
   348
        close(fbfd);
slouken@1895
   349
slouken@1895
   350
        width = vinfo.xres;
slouken@1895
   351
        height = vinfo.yres;
icculus@1140
   352
    }
icculus@1140
   353
    r.x = r.y = 0;
icculus@1140
   354
    r.w = width;
icculus@1140
   355
    r.h = height;
icculus@1140
   356
    return rs;
icculus@1140
   357
}
icculus@1140
   358
icculus@1140
   359
slouken@1895
   360
static SDL_Surface *
slouken@1895
   361
iPod_SetVideoMode(_THIS, SDL_Surface * current, int width, int height,
slouken@1895
   362
                  int bpp, Uint32 flags)
icculus@1140
   363
{
icculus@1140
   364
    Uint32 Rmask, Gmask, Bmask;
icculus@1140
   365
    if (bpp > 8) {
slouken@1895
   366
        Rmask = 0xF800;
slouken@1895
   367
        Gmask = 0x07E0;
slouken@1895
   368
        Bmask = 0x001F;
icculus@1140
   369
    } else {
slouken@1895
   370
        Rmask = Gmask = Bmask = 0;
icculus@1140
   371
    }
icculus@1140
   372
slouken@1895
   373
    if (this->hidden->buffer)
slouken@1895
   374
        SDL_free(this->hidden->buffer);
slouken@1895
   375
    this->hidden->buffer = SDL_malloc(width * height * (bpp / 8));
icculus@1140
   376
    if (!this->hidden->buffer) {
slouken@1895
   377
        SDL_SetError("Couldn't allocate buffer for requested mode");
slouken@1895
   378
        return 0;
icculus@1140
   379
    }
icculus@1140
   380
slouken@1895
   381
    memset(this->hidden->buffer, 0, width * height * (bpp / 8));
icculus@1140
   382
slouken@1895
   383
    if (!SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, 0)) {
slouken@1895
   384
        SDL_SetError("Couldn't allocate new pixel format");
slouken@1895
   385
        SDL_free(this->hidden->buffer);
slouken@1895
   386
        this->hidden->buffer = 0;
slouken@1895
   387
        return 0;
icculus@1140
   388
    }
icculus@1140
   389
icculus@1140
   390
    if (bpp <= 8) {
slouken@1895
   391
        int i, j;
slouken@1895
   392
        for (i = 0; i < 256; i += 4) {
slouken@1895
   393
            for (j = 0; j < 4; j++) {
slouken@1895
   394
                current->format->palette->colors[i + j].r = 85 * j;
slouken@1895
   395
                current->format->palette->colors[i + j].g = 85 * j;
slouken@1895
   396
                current->format->palette->colors[i + j].b = 85 * j;
slouken@1895
   397
            }
slouken@1895
   398
        }
icculus@1140
   399
    }
icculus@1140
   400
icculus@1140
   401
    current->flags = flags & SDL_FULLSCREEN;
icculus@1140
   402
    this->hidden->w = current->w = width;
icculus@1140
   403
    this->hidden->h = current->h = height;
icculus@1140
   404
    current->pitch = current->w * (bpp / 8);
icculus@1140
   405
    current->pixels = this->hidden->buffer;
icculus@1140
   406
icculus@1140
   407
    return current;
icculus@1140
   408
}
icculus@1140
   409
slouken@1895
   410
static int
slouken@1895
   411
iPod_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
icculus@1140
   412
{
slouken@1895
   413
    if (SDL_VideoSurface && SDL_VideoSurface->format
slouken@1895
   414
        && SDL_VideoSurface->format->palette) {
slouken@1895
   415
        int i, j;
slouken@1895
   416
        for (i = 0; i < 256; i += 4) {
slouken@1895
   417
            for (j = 0; j < 4; j++) {
slouken@1895
   418
                SDL_VideoSurface->format->palette->colors[i + j].r = 85 * j;
slouken@1895
   419
                SDL_VideoSurface->format->palette->colors[i + j].g = 85 * j;
slouken@1895
   420
                SDL_VideoSurface->format->palette->colors[i + j].b = 85 * j;
slouken@1895
   421
            }
slouken@1895
   422
        }
icculus@1140
   423
    }
icculus@1140
   424
    return 0;
icculus@1140
   425
}
icculus@1140
   426
slouken@1895
   427
static void
slouken@1895
   428
iPod_VideoQuit(_THIS)
icculus@1140
   429
{
slouken@1895
   430
    ioctl(kbfd, KDSETMODE, KD_TEXT);
slouken@1895
   431
    tcsetattr(kbfd, TCSAFLUSH, &old_termios);
icculus@1140
   432
    old_kbmode = -1;
icculus@1140
   433
icculus@1140
   434
    if (oldvt > 0)
slouken@1895
   435
        ioctl(kbfd, VT_ACTIVATE, oldvt);
slouken@1895
   436
icculus@1140
   437
    if (kbfd > 0)
slouken@1895
   438
        close(kbfd);
icculus@1140
   439
icculus@1140
   440
    if (dbgout) {
slouken@1895
   441
        fprintf(dbgout, "<-- Ended SDL -->\n");
slouken@1895
   442
        fclose(dbgout);
icculus@1140
   443
    }
slouken@1895
   444
icculus@1140
   445
    kbfd = -1;
icculus@1140
   446
}
icculus@1140
   447
icculus@1140
   448
static char iPod_SC_keymap[] = {
slouken@1895
   449
    0,                          /* 0 - no key */
slouken@1895
   450
    '[' - 0x40,                 /* ESC (Ctrl+[) */
icculus@1140
   451
    '1', '2', '3', '4', '5', '6', '7', '8', '9',
icculus@1140
   452
    '-', '=',
slouken@1895
   453
    '\b', '\t',                 /* Backspace, Tab (Ctrl+H,Ctrl+I) */
icculus@1140
   454
    'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
slouken@1895
   455
    '\n', 0,                    /* Enter, Left CTRL */
icculus@1140
   456
    'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
slouken@1895
   457
    0, '\\',                    /* left shift, backslash */
icculus@1140
   458
    'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
slouken@1895
   459
    0, '*', 0, ' ', 0,          /* right shift, KP mul, left alt, space, capslock */
slouken@1895
   460
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* F1-10 */
slouken@1895
   461
    0, 0,                       /* numlock, scrollock */
slouken@1895
   462
    '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.',    /* numeric keypad */
slouken@1895
   463
    0, 0,                       /* padding */
slouken@1895
   464
    0, 0, 0,                    /* "less" (?), F11, F12 */
slouken@1895
   465
    0, 0, 0, 0, 0, 0, 0,        /* padding */
slouken@1895
   466
    '\n', 0, '/', 0, 0,         /* KP enter, Rctrl, Ctrl, KP div, PrtSc, RAlt */
slouken@1895
   467
    0, 0, 0, 0, 0, 0, 0, 0, 0,  /* Break, Home, Up, PgUp, Left, Right, End, Down, PgDn */
slouken@1895
   468
    0, 0,                       /* Ins, Del */
slouken@1895
   469
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      /* padding */
slouken@1895
   470
    0, 0,                       /* RWin, LWin */
slouken@1895
   471
    0                           /* no key */
icculus@1140
   472
};
icculus@1140
   473
slouken@1895
   474
slouken@1895
   475
static void
slouken@1895
   476
iPod_keyboard()
icculus@1140
   477
{
icculus@1140
   478
    unsigned char keybuf[128];
icculus@1140
   479
    int i, nread;
icculus@1140
   480
    SDL_keysym keysym;
icculus@1140
   481
    SDL_Event ev;
icculus@1140
   482
icculus@1140
   483
    keysym.mod = 0;
icculus@1140
   484
    keysym.scancode = 0xff;
slouken@1895
   485
    memset(&ev, 0, sizeof(SDL_Event));
icculus@1140
   486
slouken@1895
   487
    nread = read(kbfd, keybuf, 128);
icculus@1140
   488
    for (i = 0; i < nread; i++) {
slouken@1895
   489
        char ascii = iPod_SC_keymap[keybuf[i] & 0x7f];
icculus@1140
   490
slouken@1895
   491
        if (dbgout)
slouken@1895
   492
            fprintf(dbgout, "Key! %02x is %c %s", keybuf[i], ascii,
slouken@1895
   493
                    (keybuf[i] & 0x80) ? "up" : "down");
icculus@1140
   494
slouken@1895
   495
        keysym.sym = keysym.unicode = ascii;
slouken@1895
   496
        ev.type = (keybuf[i] & 0x80) ? SDL_KEYUP : SDL_KEYDOWN;
slouken@1895
   497
        ev.key.state = 0;
slouken@1895
   498
        ev.key.keysym = keysym;
slouken@1895
   499
        SDL_PushEvent(&ev);
icculus@1140
   500
    }
icculus@1140
   501
}
icculus@1140
   502
slouken@1895
   503
static void
slouken@1895
   504
iPod_PumpEvents(_THIS)
icculus@1140
   505
{
icculus@1140
   506
    fd_set fdset;
icculus@1140
   507
    int max_fd = 0;
icculus@1140
   508
    static struct timeval zero;
icculus@1140
   509
    int posted;
icculus@1140
   510
icculus@1140
   511
    do {
slouken@1895
   512
        posted = 0;
icculus@1140
   513
slouken@1895
   514
        FD_ZERO(&fdset);
slouken@1895
   515
        if (kbfd >= 0) {
slouken@1895
   516
            FD_SET(kbfd, &fdset);
slouken@1895
   517
            max_fd = kbfd;
slouken@1895
   518
        }
slouken@1895
   519
        if (dbgout)
slouken@1895
   520
            fprintf(dbgout, "Selecting");
slouken@1895
   521
        if (select(max_fd + 1, &fdset, 0, 0, &zero) > 0) {
slouken@1895
   522
            if (dbgout)
slouken@1895
   523
                fprintf(dbgout, " -> match!\n");
slouken@1895
   524
            iPod_keyboard();
slouken@1895
   525
            posted++;
slouken@1895
   526
        }
slouken@1895
   527
        if (dbgout)
slouken@1895
   528
            fprintf(dbgout, "\n");
slouken@1895
   529
    }
slouken@1895
   530
    while (posted);
icculus@1140
   531
}
icculus@1140
   532
icculus@1140
   533
// enough space for 160x128x2
slouken@1895
   534
static char ipod_scr[160 * (128 / 4)];
icculus@1140
   535
icculus@1140
   536
#define outl(datum,addr) (*(volatile unsigned long *)(addr) = (datum))
icculus@1140
   537
#define inl(addr) (*(volatile unsigned long *)(addr))
icculus@1140
   538
icculus@1140
   539
/*** The following LCD code is taken from Linux kernel uclinux-2.4.24-uc0-ipod2,
icculus@1140
   540
     file arch/armnommu/mach-ipod/fb.c. A few modifications have been made. ***/
icculus@1140
   541
icculus@1140
   542
/* get current usec counter */
slouken@1895
   543
static int
slouken@1895
   544
M_timer_get_current(void)
icculus@1140
   545
{
slouken@1895
   546
    return inl(lcd_rtc);
icculus@1140
   547
}
icculus@1140
   548
icculus@1140
   549
/* check if number of useconds has past */
slouken@1895
   550
static int
slouken@1895
   551
M_timer_check(int clock_start, int usecs)
icculus@1140
   552
{
slouken@1895
   553
    unsigned long clock;
slouken@1895
   554
    clock = inl(lcd_rtc);
slouken@1895
   555
slouken@1895
   556
    if ((clock - clock_start) >= usecs) {
slouken@1895
   557
        return 1;
slouken@1895
   558
    } else {
slouken@1895
   559
        return 0;
slouken@1895
   560
    }
icculus@1140
   561
}
icculus@1140
   562
icculus@1140
   563
/* wait for LCD with timeout */
slouken@1895
   564
static void
slouken@1895
   565
M_lcd_wait_write(void)
icculus@1140
   566
{
slouken@1895
   567
    if ((inl(lcd_base) & 0x8000) != 0) {
slouken@1895
   568
        int start = M_timer_get_current();
slouken@1895
   569
slouken@1895
   570
        do {
slouken@1895
   571
            if ((inl(lcd_base) & (unsigned int) 0x8000) == 0)
slouken@1895
   572
                break;
slouken@1895
   573
        }
slouken@1895
   574
        while (M_timer_check(start, 1000) == 0);
slouken@1895
   575
    }
icculus@1140
   576
}
icculus@1140
   577
icculus@1140
   578
icculus@1140
   579
/* send LCD data */
slouken@1895
   580
static void
slouken@1895
   581
M_lcd_send_data(int data_lo, int data_hi)
icculus@1140
   582
{
slouken@1895
   583
    M_lcd_wait_write();
slouken@1895
   584
slouken@1895
   585
    outl(data_lo, lcd_base + LCD_DATA);
slouken@1895
   586
slouken@1895
   587
    M_lcd_wait_write();
slouken@1895
   588
slouken@1895
   589
    outl(data_hi, lcd_base + LCD_DATA);
icculus@1140
   590
icculus@1140
   591
}
icculus@1140
   592
icculus@1140
   593
/* send LCD command */
icculus@1140
   594
static void
icculus@1140
   595
M_lcd_prepare_cmd(int cmd)
icculus@1140
   596
{
slouken@1895
   597
    M_lcd_wait_write();
icculus@1140
   598
slouken@1895
   599
    outl(0x0, lcd_base + LCD_CMD);
icculus@1140
   600
slouken@1895
   601
    M_lcd_wait_write();
slouken@1895
   602
slouken@1895
   603
    outl(cmd, lcd_base + LCD_CMD);
slouken@1895
   604
icculus@1140
   605
}
icculus@1140
   606
icculus@1140
   607
/* send LCD command and data */
slouken@1895
   608
static void
slouken@1895
   609
M_lcd_cmd_and_data(int cmd, int data_lo, int data_hi)
icculus@1140
   610
{
slouken@1895
   611
    M_lcd_prepare_cmd(cmd);
icculus@1140
   612
slouken@1895
   613
    M_lcd_send_data(data_lo, data_hi);
icculus@1140
   614
}
icculus@1140
   615
icculus@1140
   616
// Copied from uW
slouken@1895
   617
static void
slouken@1895
   618
M_update_display(int sx, int sy, int mx, int my)
icculus@1140
   619
{
slouken@1895
   620
    int y;
slouken@1895
   621
    unsigned short cursor_pos;
icculus@1140
   622
slouken@1895
   623
    sx >>= 3;
slouken@1895
   624
    mx >>= 3;
icculus@1140
   625
slouken@1895
   626
    cursor_pos = sx + (sy << 5);
icculus@1140
   627
slouken@1895
   628
    for (y = sy; y <= my; y++) {
slouken@1895
   629
        unsigned char *img_data;
slouken@1895
   630
        int x;
icculus@1140
   631
slouken@1895
   632
        /* move the cursor */
slouken@1895
   633
        M_lcd_cmd_and_data(0x11, cursor_pos >> 8, cursor_pos & 0xff);
icculus@1140
   634
slouken@1895
   635
        /* setup for printing */
slouken@1895
   636
        M_lcd_prepare_cmd(0x12);
icculus@1140
   637
slouken@1895
   638
        img_data = ipod_scr + (sx << 1) + (y * (lcd_width / 4));
icculus@1140
   639
slouken@1895
   640
        /* loops up to 160 times */
slouken@1895
   641
        for (x = sx; x <= mx; x++) {
slouken@1895
   642
            /* display eight pixels */
slouken@1895
   643
            M_lcd_send_data(*(img_data + 1), *img_data);
icculus@1140
   644
slouken@1895
   645
            img_data += 2;
slouken@1895
   646
        }
icculus@1140
   647
slouken@1895
   648
        /* update cursor pos counter */
slouken@1895
   649
        cursor_pos += 0x20;
slouken@1895
   650
    }
icculus@1140
   651
}
icculus@1140
   652
icculus@1140
   653
/* get current usec counter */
slouken@1895
   654
static int
slouken@1895
   655
C_timer_get_current(void)
icculus@1140
   656
{
slouken@1895
   657
    return inl(0x60005010);
icculus@1140
   658
}
icculus@1140
   659
icculus@1140
   660
/* check if number of useconds has past */
slouken@1895
   661
static int
slouken@1895
   662
C_timer_check(int clock_start, int usecs)
icculus@1140
   663
{
slouken@1895
   664
    unsigned long clock;
slouken@1895
   665
    clock = inl(0x60005010);
slouken@1895
   666
slouken@1895
   667
    if ((clock - clock_start) >= usecs) {
slouken@1895
   668
        return 1;
slouken@1895
   669
    } else {
slouken@1895
   670
        return 0;
slouken@1895
   671
    }
icculus@1140
   672
}
icculus@1140
   673
icculus@1140
   674
/* wait for LCD with timeout */
slouken@1895
   675
static void
slouken@1895
   676
C_lcd_wait_write(void)
icculus@1140
   677
{
slouken@1895
   678
    if ((inl(0x70008A0C) & 0x80000000) != 0) {
slouken@1895
   679
        int start = C_timer_get_current();
slouken@1895
   680
slouken@1895
   681
        do {
slouken@1895
   682
            if ((inl(0x70008A0C) & 0x80000000) == 0)
slouken@1895
   683
                break;
slouken@1895
   684
        }
slouken@1895
   685
        while (C_timer_check(start, 1000) == 0);
slouken@1895
   686
    }
icculus@1140
   687
}
slouken@1895
   688
static void
slouken@1895
   689
C_lcd_cmd_data(int cmd, int data)
icculus@1140
   690
{
slouken@1895
   691
    C_lcd_wait_write();
slouken@1895
   692
    outl(cmd | 0x80000000, 0x70008A0C);
icculus@1140
   693
slouken@1895
   694
    C_lcd_wait_write();
slouken@1895
   695
    outl(data | 0x80000000, 0x70008A0C);
icculus@1140
   696
}
icculus@1140
   697
slouken@1895
   698
static void
slouken@1895
   699
C_update_display(int sx, int sy, int mx, int my)
icculus@1140
   700
{
slouken@1895
   701
    int height = (my - sy) + 1;
slouken@1895
   702
    int width = (mx - sx) + 1;
icculus@1140
   703
slouken@1895
   704
    char *addr = SDL_VideoSurface->pixels;
icculus@1140
   705
slouken@1895
   706
    if (width & 1)
slouken@1895
   707
        width++;
icculus@1140
   708
slouken@1895
   709
    /* start X and Y */
slouken@1895
   710
    C_lcd_cmd_data(0x12, (sy & 0xff));
slouken@1895
   711
    C_lcd_cmd_data(0x13, (((SDL_VideoSurface->w - 1) - sx) & 0xff));
icculus@1140
   712
slouken@1895
   713
    /* max X and Y */
slouken@1895
   714
    C_lcd_cmd_data(0x15, (((sy + height) - 1) & 0xff));
slouken@1895
   715
    C_lcd_cmd_data(0x16,
slouken@1895
   716
                   (((((SDL_VideoSurface->w - 1) - sx) - width) + 1) & 0xff));
icculus@1140
   717
slouken@1895
   718
    addr += sx + sy * SDL_VideoSurface->pitch;
icculus@1140
   719
slouken@1895
   720
    while (height > 0) {
slouken@1895
   721
        int h, x, y, pixels_to_write;
icculus@1140
   722
slouken@1895
   723
        pixels_to_write = (width * height) * 2;
icculus@1140
   724
slouken@1895
   725
        /* calculate how much we can do in one go */
slouken@1895
   726
        h = height;
slouken@1895
   727
        if (pixels_to_write > 64000) {
slouken@1895
   728
            h = (64000 / 2) / width;
slouken@1895
   729
            pixels_to_write = (width * h) * 2;
slouken@1895
   730
        }
icculus@1140
   731
slouken@1895
   732
        outl(0x10000080, 0x70008A20);
slouken@1895
   733
        outl((pixels_to_write - 1) | 0xC0010000, 0x70008A24);
slouken@1895
   734
        outl(0x34000000, 0x70008A20);
icculus@1140
   735
slouken@1895
   736
        /* for each row */
slouken@1895
   737
        for (x = 0; x < h; x++) {
slouken@1895
   738
            /* for each column */
slouken@1895
   739
            for (y = 0; y < width; y += 2) {
slouken@1895
   740
                unsigned two_pixels;
icculus@1140
   741
slouken@1895
   742
                two_pixels = addr[0] | (addr[1] << 16);
slouken@1895
   743
                addr += 2;
icculus@1140
   744
slouken@1895
   745
                while ((inl(0x70008A20) & 0x1000000) == 0);
icculus@1140
   746
slouken@1895
   747
                /* output 2 pixels */
slouken@1895
   748
                outl(two_pixels, 0x70008B00);
slouken@1895
   749
            }
icculus@1140
   750
slouken@1895
   751
            addr += SDL_VideoSurface->w - width;
slouken@1895
   752
        }
icculus@1140
   753
slouken@1895
   754
        while ((inl(0x70008A20) & 0x4000000) == 0);
icculus@1140
   755
slouken@1895
   756
        outl(0x0, 0x70008A24);
icculus@1140
   757
slouken@1895
   758
        height = height - h;
slouken@1895
   759
    }
icculus@1140
   760
}
icculus@1140
   761
icculus@1140
   762
// Should work with photo. However, I don't have one, so I'm not sure.
slouken@1895
   763
static void
slouken@1895
   764
iPod_UpdateRects(_THIS, int nrects, SDL_Rect * rects)
icculus@1140
   765
{
icculus@1140
   766
    if (SDL_VideoSurface->format->BitsPerPixel == 16) {
slouken@1895
   767
        C_update_display(0, 0, lcd_width, lcd_height);
icculus@1140
   768
    } else {
slouken@1895
   769
        int i, y, x;
slouken@1895
   770
        for (i = 0; i < nrects; i++) {
slouken@1895
   771
            SDL_Rect *r = rects + i;
slouken@1895
   772
            if (!r) {
slouken@1895
   773
                continue;
slouken@1895
   774
            }
slouken@1895
   775
slouken@1895
   776
            for (y = r->y; (y < r->y + r->h) && y < lcd_height; y++) {
slouken@1895
   777
                for (x = r->x; (x < r->x + r->w) && x < lcd_width; x++) {
slouken@1895
   778
                    ipod_scr[y * (lcd_width / 4) + x / 4] &=
slouken@1895
   779
                        ~(3 << (2 * (x % 4)));
slouken@1895
   780
                    ipod_scr[y * (lcd_width / 4) + x / 4] |=
slouken@1895
   781
                        (((Uint8 *) (SDL_VideoSurface->pixels))[y *
slouken@1895
   782
                                                                SDL_VideoSurface->
slouken@1895
   783
                                                                pitch
slouken@1895
   784
                                                                +
slouken@1895
   785
                                                                x] &
slouken@1895
   786
                         3) << (2 * (x % 4));
slouken@1895
   787
                }
slouken@1895
   788
            }
slouken@1895
   789
        }
slouken@1895
   790
slouken@1895
   791
        M_update_display(0, 0, lcd_width, lcd_height);
icculus@1140
   792
    }
icculus@1140
   793
}
slouken@1895
   794
slouken@1895
   795
/* vi: set ts=4 sw=4 expandtab: */