/* podscreen.c: Library providing unified access to Apple iPod displays Copyright (C) 2005 Matthew Westcott This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Author contact information: E-mail: matthew@west.co.tt Postal address: 14 Daisy Hill Drive, Adlington, Chorley, Lancs, PR6 9NE, United Kingdom */ #include "podscreen.h" #include #include #include #include #define outl(a,b) (*(volatile unsigned int *)(b) = (a)) #define inl(a) (*(volatile unsigned int *)(a)) #define lcd_wait_write(scr) {while( (inl((scr)->ipod_lcd_base) & 0x8000) ) ;} #define IPOD_STD_LCD_BUSY_MASK 0x8000 #define IPOD_COLOR_LCD_BUSY_MASK 0x8000 #define IPOD_STD_LCD_WIDTH 160 #define IPOD_STD_LCD_HEIGHT 128 #define IPOD_MINI_LCD_WIDTH 138 #define IPOD_MINI_LCD_HEIGHT 110 #define IPOD_COLOR_LCD_WIDTH 220 #define IPOD_COLOR_LCD_HEIGHT 176 #define IPOD_PP5002_RTC 0xcf001110 #define IPOD_PP5002_LCD_BASE 0xc0001000 #define IPOD_PP5020_RTC 0x60005010 #define IPOD_PP5020_LCD_BASE 0x70003000 #define IPOD_COLOR_LCD_BASE 0x70008a0c #define LCD_CMD 0x8 #define LCD_DATA 0x10 /* static method prototypes */ static long ipod_get_hw_version(void); static void lcd_send_data(short data); static void lcd_prepare_cmd(byte cmd); static void lcd_cmd_and_data(byte cmd, short data); static psPixel *mono_find_color(unsigned char r, unsigned char g, unsigned char b); static long ipod_get_hw_version(void) { int i; char cpuinfo[512]; char * ptr; FILE * file; if ((file = fopen("/proc/cpuinfo", "r")) != NULL) { while (fgets(cpuinfo, sizeof(cpuinfo), file) != NULL) if (strncmp(cpuinfo, "Revision", 8) == 0) break; fclose(file); } else { return 0; } for (i = 0; !isspace(cpuinfo[i]); i++); for (; isspace(cpuinfo[i]); i++); ptr = cpuinfo + i + 2; return strtol(ptr, NULL, 16); } /* send LCD data */ static void lcd_send_data(psScreen *scr, short data) { lcd_wait_write(scr); outl(data>>8, scr->ipod_lcd_base + LCD_DATA); lcd_wait_write(scr); outl(data, scr->ipod_lcd_base + LCD_DATA); } /* send LCD command */ static void lcd_prepare_cmd(psScreen *scr, byte cmd) { lcd_wait_write(scr); outl(0x0, scr->ipod_lcd_base + LCD_CMD); lcd_wait_write(scr); outl(cmd, scr->ipod_lcd_base + LCD_CMD); } /* send LCD command and data */ static void lcd_cmd_and_data(psScreen *scr, byte cmd, short data) { lcd_prepare_cmd(scr, cmd); lcd_send_data(scr, data); } psPixel mono_palette[10] = { 3, /* PS_COLOR_BLACK */ 2, /* PS_COLOR_DARKGREY */ 1, /* PS_COLOR_LIGHTGREY */ 0, /* PS_COLOR_WHITE */ 2, /* PS_COLOR_RED */ 2, /* PS_COLOR_GREEN */ 2, /* PS_COLOR_BLUE */ 1, /* PS_COLOR_YELLOW */ 1, /* PS_COLOR_MAGENTA */ 1, /* PS_COLOR_CYAN */ } static psPixel *mono_find_color(unsigned char r, unsigned char g, unsigned char b) { int v = r + g + b; if (v < 192) { return 0; } else if (v < 384) { return 1; } else if (v < 576) { return 2; } else { return 3; } } psScreen *psGetScreen(psIpodFamily desired) { psScreen *scr; int hw_version; scr = malloc(sizeof(psScreen)); hw_version = ipod_get_hw_version(); switch (hw_version) { case 6: scr->lcd_base = IPOD_COLOR_LCD_BASE; scr->lcd_busy_mask = IPOD_COLOR_LCD_BUSY_MASK; scr->lcd_width = IPOD_COLOR_LCD_WIDTH; scr->lcd_height = IPOD_COLOR_LCD_HEIGHT; scr->ipod_rtc = IPOD_PP5020_RTC; scr->is_color = 1; break; case 5: scr->lcd_base = IPOD_PP5020_LCD_BASE; scr->lcd_busy_mask = IPOD_STD_LCD_BUSY_MASK; scr->lcd_width = IPOD_STD_LCD_WIDTH; scr->lcd_height = IPOD_STD_LCD_HEIGHT; scr->ipod_rtc = IPOD_PP5020_RTC; scr->is_color = 0; break; case 7: case 4: scr->lcd_width = IPOD_MINI_LCD_WIDTH; scr->lcd_height = IPOD_MINI_LCD_HEIGHT; scr->lcd_base = IPOD_PP5020_LCD_BASE; scr->lcd_busy_mask = IPOD_STD_LCD_BUSY_MASK; scr->ipod_rtc = IPOD_PP5020_RTC; scr->is_color = 0; break; case 3: case 2: case 1: scr->width = IPOD_STD_LCD_WIDTH; scr->height = IPOD_STD_LCD_HEIGHT; scr->lcd_base = IPOD_PP5002_LCD_BASE; scr->ipod_rtc = IPOD_PP5002_RTC; scr->lcd_busy_mask = IPOD_STD_LCD_BUSY_MASK; scr->is_color = 0; break; } if (scr->is_color) { } else { scr->find_color = &mono_find_color; scr->palette = mono_palette; } } void *psReleaseScreen(psScreen *scr) { free(scr); }