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