src/video/ipod/SDL_ipodvideo.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 28 May 2006 13:04:16 +0000
branchSDL-1.3
changeset 1662 782fd950bd46
parent 1545 8d9bb0cf2c2a
child 1668 4da1ee79c9af
permissions -rw-r--r--
Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API.

WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid.

The code is now run through a consistent indent format:
indent -i4 -nut -nsc -br -ce

The headers are being converted to automatically generate doxygen documentation.
     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     }
   530     while (posted);
   531 }
   532 
   533 // enough space for 160x128x2
   534 static char ipod_scr[160 * (128 / 4)];
   535 
   536 #define outl(datum,addr) (*(volatile unsigned long *)(addr) = (datum))
   537 #define inl(addr) (*(volatile unsigned long *)(addr))
   538 
   539 /*** The following LCD code is taken from Linux kernel uclinux-2.4.24-uc0-ipod2,
   540      file arch/armnommu/mach-ipod/fb.c. A few modifications have been made. ***/
   541 
   542 /* get current usec counter */
   543 static int
   544 M_timer_get_current (void)
   545 {
   546     return inl (lcd_rtc);
   547 }
   548 
   549 /* check if number of useconds has past */
   550 static int
   551 M_timer_check (int clock_start, int usecs)
   552 {
   553     unsigned long clock;
   554     clock = inl (lcd_rtc);
   555 
   556     if ((clock - clock_start) >= usecs) {
   557         return 1;
   558     } else {
   559         return 0;
   560     }
   561 }
   562 
   563 /* wait for LCD with timeout */
   564 static void
   565 M_lcd_wait_write (void)
   566 {
   567     if ((inl (lcd_base) & 0x8000) != 0) {
   568         int start = M_timer_get_current ();
   569 
   570         do {
   571             if ((inl (lcd_base) & (unsigned int) 0x8000) == 0)
   572                 break;
   573         }
   574         while (M_timer_check (start, 1000) == 0);
   575     }
   576 }
   577 
   578 
   579 /* send LCD data */
   580 static void
   581 M_lcd_send_data (int data_lo, int data_hi)
   582 {
   583     M_lcd_wait_write ();
   584 
   585     outl (data_lo, lcd_base + LCD_DATA);
   586 
   587     M_lcd_wait_write ();
   588 
   589     outl (data_hi, lcd_base + LCD_DATA);
   590 
   591 }
   592 
   593 /* send LCD command */
   594 static void
   595 M_lcd_prepare_cmd (int cmd)
   596 {
   597     M_lcd_wait_write ();
   598 
   599     outl (0x0, lcd_base + LCD_CMD);
   600 
   601     M_lcd_wait_write ();
   602 
   603     outl (cmd, lcd_base + LCD_CMD);
   604 
   605 }
   606 
   607 /* send LCD command and data */
   608 static void
   609 M_lcd_cmd_and_data (int cmd, int data_lo, int data_hi)
   610 {
   611     M_lcd_prepare_cmd (cmd);
   612 
   613     M_lcd_send_data (data_lo, data_hi);
   614 }
   615 
   616 // Copied from uW
   617 static void
   618 M_update_display (int sx, int sy, int mx, int my)
   619 {
   620     int y;
   621     unsigned short cursor_pos;
   622 
   623     sx >>= 3;
   624     mx >>= 3;
   625 
   626     cursor_pos = sx + (sy << 5);
   627 
   628     for (y = sy; y <= my; y++) {
   629         unsigned char *img_data;
   630         int x;
   631 
   632         /* move the cursor */
   633         M_lcd_cmd_and_data (0x11, cursor_pos >> 8, cursor_pos & 0xff);
   634 
   635         /* setup for printing */
   636         M_lcd_prepare_cmd (0x12);
   637 
   638         img_data = ipod_scr + (sx << 1) + (y * (lcd_width / 4));
   639 
   640         /* loops up to 160 times */
   641         for (x = sx; x <= mx; x++) {
   642             /* display eight pixels */
   643             M_lcd_send_data (*(img_data + 1), *img_data);
   644 
   645             img_data += 2;
   646         }
   647 
   648         /* update cursor pos counter */
   649         cursor_pos += 0x20;
   650     }
   651 }
   652 
   653 /* get current usec counter */
   654 static int
   655 C_timer_get_current (void)
   656 {
   657     return inl (0x60005010);
   658 }
   659 
   660 /* check if number of useconds has past */
   661 static int
   662 C_timer_check (int clock_start, int usecs)
   663 {
   664     unsigned long clock;
   665     clock = inl (0x60005010);
   666 
   667     if ((clock - clock_start) >= usecs) {
   668         return 1;
   669     } else {
   670         return 0;
   671     }
   672 }
   673 
   674 /* wait for LCD with timeout */
   675 static void
   676 C_lcd_wait_write (void)
   677 {
   678     if ((inl (0x70008A0C) & 0x80000000) != 0) {
   679         int start = C_timer_get_current ();
   680 
   681         do {
   682             if ((inl (0x70008A0C) & 0x80000000) == 0)
   683                 break;
   684         }
   685         while (C_timer_check (start, 1000) == 0);
   686     }
   687 }
   688 static void
   689 C_lcd_cmd_data (int cmd, int data)
   690 {
   691     C_lcd_wait_write ();
   692     outl (cmd | 0x80000000, 0x70008A0C);
   693 
   694     C_lcd_wait_write ();
   695     outl (data | 0x80000000, 0x70008A0C);
   696 }
   697 
   698 static void
   699 C_update_display (int sx, int sy, int mx, int my)
   700 {
   701     int height = (my - sy) + 1;
   702     int width = (mx - sx) + 1;
   703 
   704     char *addr = SDL_VideoSurface->pixels;
   705 
   706     if (width & 1)
   707         width++;
   708 
   709     /* start X and Y */
   710     C_lcd_cmd_data (0x12, (sy & 0xff));
   711     C_lcd_cmd_data (0x13, (((SDL_VideoSurface->w - 1) - sx) & 0xff));
   712 
   713     /* max X and Y */
   714     C_lcd_cmd_data (0x15, (((sy + height) - 1) & 0xff));
   715     C_lcd_cmd_data (0x16,
   716                     (((((SDL_VideoSurface->w - 1) - sx) - width) +
   717                       1) & 0xff));
   718 
   719     addr += sx + sy * SDL_VideoSurface->pitch;
   720 
   721     while (height > 0) {
   722         int h, x, y, pixels_to_write;
   723 
   724         pixels_to_write = (width * height) * 2;
   725 
   726         /* calculate how much we can do in one go */
   727         h = height;
   728         if (pixels_to_write > 64000) {
   729             h = (64000 / 2) / width;
   730             pixels_to_write = (width * h) * 2;
   731         }
   732 
   733         outl (0x10000080, 0x70008A20);
   734         outl ((pixels_to_write - 1) | 0xC0010000, 0x70008A24);
   735         outl (0x34000000, 0x70008A20);
   736 
   737         /* for each row */
   738         for (x = 0; x < h; x++) {
   739             /* for each column */
   740             for (y = 0; y < width; y += 2) {
   741                 unsigned two_pixels;
   742 
   743                 two_pixels = addr[0] | (addr[1] << 16);
   744                 addr += 2;
   745 
   746                 while ((inl (0x70008A20) & 0x1000000) == 0);
   747 
   748                 /* output 2 pixels */
   749                 outl (two_pixels, 0x70008B00);
   750             }
   751 
   752             addr += SDL_VideoSurface->w - width;
   753         }
   754 
   755         while ((inl (0x70008A20) & 0x4000000) == 0);
   756 
   757         outl (0x0, 0x70008A24);
   758 
   759         height = height - h;
   760     }
   761 }
   762 
   763 // Should work with photo. However, I don't have one, so I'm not sure.
   764 static void
   765 iPod_UpdateRects (_THIS, int nrects, SDL_Rect * rects)
   766 {
   767     if (SDL_VideoSurface->format->BitsPerPixel == 16) {
   768         C_update_display (0, 0, lcd_width, lcd_height);
   769     } else {
   770         int i, y, x;
   771         for (i = 0; i < nrects; i++) {
   772             SDL_Rect *r = rects + i;
   773             if (!r) {
   774                 continue;
   775             }
   776 
   777             for (y = r->y; (y < r->y + r->h) && y < lcd_height; y++) {
   778                 for (x = r->x; (x < r->x + r->w) && x < lcd_width; x++) {
   779                     ipod_scr[y * (lcd_width / 4) + x / 4] &=
   780                         ~(3 << (2 * (x % 4)));
   781                     ipod_scr[y * (lcd_width / 4) + x / 4] |=
   782                         (((Uint8 *) (SDL_VideoSurface->pixels))[y *
   783                                                                 SDL_VideoSurface->
   784                                                                 pitch
   785                                                                 +
   786                                                                 x] &
   787                          3) << (2 * (x % 4));
   788                 }
   789             }
   790         }
   791 
   792         M_update_display (0, 0, lcd_width, lcd_height);
   793     }
   794 }
   795 
   796 /* vi: set ts=4 sw=4 expandtab: */