├── README.md ├── android └── system │ └── etc │ └── excluded-input-devices.xml ├── gtk-ui ├── Makefile └── gtk-ui.c ├── host └── etc │ └── X11 │ └── xorg.conf.d │ ├── 10-evdev.conf │ └── 60-android.conf └── kernel └── drivers ├── input ├── Kconfig.addition ├── Makefile.addition └── androidinput.c ├── rtc ├── alarm-dev.c └── alarm.c └── video ├── vfb.c └── vfb.original.c /README.md: -------------------------------------------------------------------------------- 1 | ParallelDroid 2 | ============= 3 | 4 | What is this? 5 | -------------- 6 | Some code and utilities I've been using to run Android natively in a window on 7 | my normal desktop system. 8 | 9 | Don't expect anything to work. 10 | 11 | But...? 12 | -------- 13 | 14 | Check out the video at http://www.youtube.com/watch?v=_URfbYOpx-s 15 | 16 | There are a lot of glitches, but at least it's faster than the emulator... 17 | 18 | I'll fix up the code and write a blog post explaining it 19 | when I get the time. 20 | -------------------------------------------------------------------------------- /android/system/etc/excluded-input-devices.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gtk-ui/Makefile: -------------------------------------------------------------------------------- 1 | GTKFLAGS = $(shell pkg-config --libs --cflags gtk+-2.0 gthread-2.0) 2 | 3 | all: gtk-ui 4 | 5 | gtk-ui: gtk-ui.c 6 | gcc gtk-ui.c -o gtk-ui $(GTKFLAGS) 7 | 8 | clean: 9 | rm -rf gtk-ui 10 | 11 | .PHONY: clean 12 | .SILENT: clean 13 | -------------------------------------------------------------------------------- /gtk-ui/gtk-ui.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Philip Åkesson 3 | * 4 | * Other credits: 5 | * - Some GTK related code from the GTK documentation at http://www.gtk.org 6 | * - Some FB related code from the fbvncserver project 7 | * Original at http://fbvncserver.sourceforge.net/ 8 | * Modified by Danke Xie at 9 | * http://code.google.com/p/fastdroid-vnc/ 10 | * 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License as published by the 13 | * Free Software Foundation; either version 2, or (at your option) any 14 | * later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * General Public License for more details. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | #define IMAGE_WIDTH 640 42 | #define IMAGE_HEIGHT 480 43 | 44 | #define EV_PRESSED 1 45 | #define EV_RELEASED 0 46 | 47 | static GdkPixmap *pixmap = NULL; 48 | guchar rgbbuf[IMAGE_WIDTH * IMAGE_HEIGHT * 3]; 49 | static int currently_drawing = 0; 50 | 51 | /* Framebuffer */ 52 | guchar* bits; 53 | int bpp; /* byte per pixel */ 54 | int stride; /* size of stride in pixel */ 55 | struct fb_var_screeninfo vi; 56 | struct fb_fix_screeninfo fi; 57 | 58 | /* Input events */ 59 | static char INPUT_DEVICE[PATH_MAX] = "/dev/input/event2"; /* TODO: This is hardcoded for now... */ 60 | static int inputfd = -1; 61 | static int xmin, xmax; 62 | static int ymin, ymax; 63 | 64 | static gboolean configure_event(GtkWidget *widget, GdkEventConfigure *event) 65 | { 66 | return TRUE; 67 | } 68 | 69 | void *do_draw(void *ptr) 70 | { 71 | siginfo_t info; 72 | sigset_t sigset; 73 | 74 | sigemptyset(&sigset); 75 | sigaddset(&sigset, SIGALRM); 76 | 77 | while (1) { 78 | while (sigwaitinfo(&sigset, &info) > 0) { 79 | currently_drawing = 1; 80 | 81 | int width, height; 82 | gdk_threads_enter(); 83 | gdk_drawable_get_size(pixmap, &width, &height); 84 | gdk_threads_leave(); 85 | 86 | memcpy(rgbbuf, 87 | bits + (vi.xoffset + vi.yoffset*vi.xres_virtual)*bpp, 88 | vi.yres*stride*bpp); 89 | 90 | cairo_surface_t *cst = 91 | cairo_image_surface_create_for_data(rgbbuf, 92 | CAIRO_FORMAT_RGB16_565, IMAGE_WIDTH, IMAGE_HEIGHT, 93 | stride*bpp); 94 | 95 | /* When dealing with gdkPixmap's, we need to make sure not to 96 | access them from outside gtk_main(). */ 97 | gdk_threads_enter(); 98 | 99 | cairo_t *cr_pixmap = gdk_cairo_create(pixmap); 100 | cairo_set_source_surface(cr_pixmap, cst, 0, 0); 101 | cairo_paint(cr_pixmap); 102 | cairo_destroy(cr_pixmap); 103 | 104 | gdk_threads_leave(); 105 | 106 | cairo_surface_destroy(cst); 107 | 108 | currently_drawing = 0; 109 | } 110 | } 111 | } 112 | 113 | gboolean timer_exe(GtkWidget *widget) 114 | { 115 | static int first_time = 1; 116 | static pthread_t thread_info; 117 | int width, height; 118 | 119 | int drawing_status = g_atomic_int_get(¤tly_drawing); 120 | 121 | if (first_time == 1) { 122 | int iret; 123 | iret = pthread_create(&thread_info, NULL, do_draw, NULL); 124 | } 125 | 126 | if (drawing_status == 0) { 127 | pthread_kill(thread_info, SIGALRM); 128 | } 129 | 130 | gdk_drawable_get_size(pixmap, &width, &height); 131 | gtk_widget_queue_draw_area(widget, 0, 0, width, height); 132 | 133 | first_time = 0; 134 | return TRUE; 135 | } 136 | 137 | static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event) 138 | { 139 | cairo_t *cr = gdk_cairo_create(widget->window); 140 | gdk_cairo_set_source_pixmap(cr, pixmap, 0, 0); 141 | cairo_paint(cr); 142 | cairo_destroy(cr); 143 | 144 | return FALSE; 145 | } 146 | 147 | static void init_input_device() 148 | { 149 | struct input_absinfo info; 150 | 151 | if ((inputfd = open(INPUT_DEVICE, O_RDWR)) == -1) { 152 | printf("Cannot open input device %s\n", INPUT_DEVICE); 153 | exit(EXIT_FAILURE); 154 | } 155 | 156 | if (ioctl(inputfd, EVIOCGABS(ABS_X), &info)) { 157 | printf("Cannot get ABS_X info, %s\n", strerror(errno)); 158 | exit(EXIT_FAILURE); 159 | } 160 | 161 | xmin = info.minimum; 162 | xmax = info.maximum; 163 | if (xmax) { 164 | printf("Touch device xmin=%d xmax=%d\n", xmin, xmax); 165 | } else { 166 | printf("Touch device has no xmax: using emulator mode\n"); 167 | } 168 | 169 | if (ioctl(inputfd, EVIOCGABS(ABS_Y), &info)) { 170 | printf("Cannot get ABS_Y, %s\n", strerror(errno)); 171 | exit(EXIT_FAILURE); 172 | } 173 | ymin = info.minimum; 174 | ymax = info.maximum; 175 | if (ymax) { 176 | printf("Touch device ymin=%d ymax=%d\n", ymin, ymax); 177 | } else { 178 | printf("Touch device has no ymax: using emulator mode\n"); 179 | } 180 | } 181 | 182 | static void cleanup_input() 183 | { 184 | if (inputfd != -1) { 185 | close(inputfd); 186 | } 187 | } 188 | 189 | void injectKeyEvent(unsigned int code, unsigned int value) 190 | { 191 | struct input_event ev; 192 | 193 | memset(&ev, 0, sizeof(ev)); 194 | gettimeofday(&ev.time, 0); 195 | ev.type = EV_KEY; 196 | ev.code = code; 197 | ev.value = value; 198 | if (write(inputfd, &ev, sizeof(ev)) < 0) { 199 | printf("Event failed, %s\n", strerror(errno)); 200 | } 201 | 202 | /*gettimeofday(&ev.time,0); 203 | ev.type = EV_SYN; 204 | ev.code = 0; 205 | ev.value = 0; 206 | if(write(inputfd, &ev, sizeof(ev)) < 0) { 207 | printf("Event failed, %s\n", strerror(errno)); 208 | }*/ 209 | } 210 | 211 | void injectTouchEvent(int down, int x, int y) 212 | { 213 | struct input_event ev; 214 | 215 | /* Re-calculate the final x and y if xmax/ymax are specified */ 216 | if (xmax) x = xmin + (x * (xmax - xmin)) / (vi.xres); 217 | if (ymax) y = ymin + (y * (ymax - ymin)) / (vi.yres); 218 | 219 | memset(&ev, 0, sizeof(ev)); 220 | 221 | gettimeofday(&ev.time,0); 222 | ev.type = EV_KEY; 223 | ev.code = BTN_TOUCH; 224 | ev.value = down; 225 | if (write(inputfd, &ev, sizeof(ev)) < 0) { 226 | printf("Write event failed, %s\n", strerror(errno)); 227 | } 228 | 229 | gettimeofday(&ev.time,0); 230 | ev.type = EV_ABS; 231 | ev.code = ABS_X; 232 | ev.value = x; 233 | if (write(inputfd, &ev, sizeof(ev)) < 0) { 234 | printf("Write event failed, %s\n", strerror(errno)); 235 | } 236 | 237 | gettimeofday(&ev.time,0); 238 | ev.type = EV_ABS; 239 | ev.code = ABS_Y; 240 | ev.value = y; 241 | if (write(inputfd, &ev, sizeof(ev)) < 0) { 242 | printf("Write event failed, %s\n", strerror(errno)); 243 | } 244 | 245 | gettimeofday(&ev.time,0); 246 | ev.type = EV_SYN; 247 | ev.code = 0; 248 | ev.value = 0; 249 | if (write(inputfd, &ev, sizeof(ev)) < 0) { 250 | printf("Write event failed, %s\n", strerror(errno)); 251 | } 252 | } 253 | 254 | static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event) 255 | { 256 | if (event->button == 1) { 257 | injectTouchEvent(1, event->x, event->y); 258 | } 259 | 260 | return TRUE; 261 | } 262 | 263 | static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) 264 | { 265 | if (event->button == 1) { 266 | injectTouchEvent(0, event->x, event->y); 267 | } 268 | 269 | return TRUE; 270 | } 271 | 272 | static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) 273 | { 274 | int x, y; 275 | GdkModifierType state; 276 | 277 | if (event->is_hint) { 278 | gdk_window_get_pointer(event->window, &x, &y, &state); 279 | } else { 280 | x = event->x; 281 | y = event->y; 282 | state = event->state; 283 | } 284 | 285 | if (state & GDK_BUTTON1_MASK) { 286 | injectTouchEvent(1, x, y); 287 | } else { 288 | injectTouchEvent(0, x, y); 289 | } 290 | 291 | return TRUE; 292 | } 293 | 294 | static void destroy(GtkWidget *widget, gpointer data) 295 | { 296 | cleanup_input(); 297 | gtk_main_quit(); 298 | } 299 | 300 | static void back_button_clicked() 301 | { 302 | printf("Back button pressed\n"); 303 | injectKeyEvent(KEY_BACKSPACE, EV_PRESSED); 304 | injectKeyEvent(KEY_BACKSPACE, EV_RELEASED); 305 | } 306 | 307 | static void home_button_clicked() 308 | { 309 | printf("Home button pressed\n"); 310 | injectKeyEvent(KEY_HOME, EV_PRESSED); 311 | injectKeyEvent(KEY_HOME, EV_RELEASED); 312 | } 313 | 314 | static void menu_button_clicked() 315 | { 316 | printf("Menu button pressed\n"); 317 | injectKeyEvent(KEY_LEFTMETA, EV_PRESSED); 318 | injectKeyEvent(KEY_LEFTMETA, EV_RELEASED); //0x52 319 | } 320 | 321 | int main(int argc, char *argv[]) 322 | { 323 | int fd; 324 | 325 | GtkWidget *window; 326 | GtkWidget *drawing_area; 327 | GtkWidget *vbox; 328 | GtkWidget *hbox; 329 | GtkWidget *button; 330 | 331 | /* Block SIGALRM in the main thread */ 332 | sigset_t sigset; 333 | sigemptyset(&sigset); 334 | sigaddset(&sigset, SIGALRM); 335 | pthread_sigmask(SIG_BLOCK, &sigset, NULL); 336 | 337 | if (!g_thread_supported()) { 338 | g_thread_init(NULL); 339 | } 340 | 341 | gdk_threads_init(); 342 | gdk_threads_enter(); 343 | 344 | gtk_init(&argc, &argv); 345 | 346 | /* Framebuffer */ 347 | 348 | /* Open framebuffer */ 349 | if (0 > (fd = open("/dev/fb0", O_RDWR))) { 350 | printf("Failed to open fb\n"); 351 | return -1; 352 | } 353 | 354 | /* Get fixed information */ 355 | if(0 > ioctl(fd, FBIOGET_FSCREENINFO, &fi)) { 356 | printf("Failed to get fixed info\n"); 357 | return -1; 358 | } 359 | 360 | /* Get variable information */ 361 | if(0 > ioctl(fd, FBIOGET_VSCREENINFO, &vi)) { 362 | printf("Failed to get variable info\n"); 363 | return -1; 364 | } 365 | 366 | /* Get raw bits buffer */ 367 | if(MAP_FAILED == (bits = mmap(0, fi.smem_len, 368 | PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))) { 369 | printf("Failed to mmap fb\n"); 370 | return -1; 371 | } 372 | 373 | printf("Framebuffer resolution: %d x %d\n", vi.xres, vi.yres); 374 | 375 | /* Calculate useful information */ 376 | bpp = vi.bits_per_pixel >> 3; 377 | stride = fi.line_length / bpp; 378 | 379 | /* Do GTK stuff */ 380 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 381 | gtk_window_set_title((GtkWindow*)window, "ParallelDroid"); 382 | g_signal_connect(window, "destroy", G_CALLBACK(destroy), NULL); 383 | 384 | vbox = gtk_vbox_new(FALSE, 0); 385 | gtk_container_add(GTK_CONTAINER(window), vbox); 386 | gtk_widget_show(vbox); 387 | 388 | drawing_area = gtk_drawing_area_new(); 389 | gtk_widget_set_size_request(GTK_WIDGET(drawing_area), vi.xres, vi.yres); 390 | gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE, TRUE, 0); 391 | gtk_widget_show(drawing_area); 392 | 393 | init_input_device(); 394 | 395 | /* Events */ 396 | gtk_widget_set_events(drawing_area, GDK_EXPOSURE_MASK 397 | | GDK_LEAVE_NOTIFY_MASK 398 | | GDK_BUTTON_PRESS_MASK 399 | | GDK_BUTTON_RELEASE_MASK 400 | | GDK_POINTER_MOTION_MASK 401 | | GDK_POINTER_MOTION_HINT_MASK); 402 | 403 | g_signal_connect(drawing_area, "motion-notify-event", 404 | G_CALLBACK (motion_notify_event), NULL); 405 | g_signal_connect(drawing_area, "button-press-event", 406 | G_CALLBACK(button_press_event), NULL); 407 | g_signal_connect(drawing_area, "button-release-event", 408 | G_CALLBACK(button_release_event), NULL); 409 | g_signal_connect(drawing_area, "expose-event", 410 | G_CALLBACK(expose_event), NULL); 411 | g_signal_connect(drawing_area, "configure-event", 412 | G_CALLBACK(configure_event), NULL); 413 | 414 | /* Create and add buttons */ 415 | hbox = gtk_hbox_new(FALSE, 0); 416 | gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); 417 | gtk_widget_show(hbox); 418 | 419 | button = gtk_button_new_with_label("Back"); 420 | gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); 421 | g_signal_connect(button, "clicked", 422 | G_CALLBACK(back_button_clicked), NULL); 423 | gtk_widget_show(button); 424 | 425 | button = gtk_button_new_with_label("Home"); 426 | gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); 427 | g_signal_connect_swapped(button, "clicked", 428 | G_CALLBACK(home_button_clicked), NULL); 429 | gtk_widget_show(button); 430 | 431 | button = gtk_button_new_with_label("Menu"); 432 | gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); 433 | g_signal_connect_swapped(button, "clicked", 434 | G_CALLBACK(menu_button_clicked), NULL); 435 | gtk_widget_show(button); 436 | 437 | gtk_widget_show_all(window); 438 | 439 | pixmap = gdk_pixmap_new(drawing_area->window, IMAGE_WIDTH, 440 | IMAGE_HEIGHT, -1); 441 | 442 | (void)g_timeout_add(33, (GSourceFunc)timer_exe, drawing_area); 443 | 444 | gtk_main(); 445 | gdk_threads_leave(); 446 | 447 | return 0; 448 | } 449 | -------------------------------------------------------------------------------- /host/etc/X11/xorg.conf.d/10-evdev.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Catch-all evdev loader for udev-based systems 3 | # We don't simply match on any device since that also adds accelerometers 4 | # and other devices that we don't really want to use. The list below 5 | # matches everything but joysticks. 6 | 7 | Section "InputClass" 8 | Identifier "evdev pointer catchall" 9 | MatchIsPointer "on" 10 | MatchDevicePath "/dev/input/event*" 11 | Driver "evdev" 12 | EndSection 13 | 14 | Section "InputClass" 15 | Identifier "evdev keyboard catchall" 16 | MatchIsKeyboard "on" 17 | MatchDevicePath "/dev/input/event*" 18 | Driver "evdev" 19 | EndSection 20 | 21 | Section "InputClass" 22 | Identifier "evdev touchpad catchall" 23 | MatchIsTouchpad "on" 24 | MatchDevicePath "/dev/input/event*" 25 | Driver "evdev" 26 | EndSection 27 | 28 | Section "InputClass" 29 | Identifier "evdev tablet catchall" 30 | MatchIsTablet "on" 31 | MatchDevicePath "/dev/input/event*" 32 | Driver "evdev" 33 | EndSection 34 | 35 | #Section "InputClass" 36 | # Identifier "evdev touchscreen catchall" 37 | # MatchIsTouchscreen "on" 38 | # MatchDevicePath "/dev/input/event*" 39 | # Driver "evdev" 40 | #EndSection 41 | -------------------------------------------------------------------------------- /host/etc/X11/xorg.conf.d/60-android.conf: -------------------------------------------------------------------------------- 1 | Section "InputClass" 2 | Identifier "Ignore virtual input device" 3 | MatchProduct "Android virtual input" 4 | Option "Ignore" "on" 5 | EndSection 6 | -------------------------------------------------------------------------------- /kernel/drivers/input/Kconfig.addition: -------------------------------------------------------------------------------- 1 | config INPUT_ANDROID 2 | tristate "Android input driver" 3 | default y 4 | help 5 | Say Y here to enable the Android virtual input driver 6 | -------------------------------------------------------------------------------- /kernel/drivers/input/Makefile.addition: -------------------------------------------------------------------------------- 1 | obj-$(CONFIG_INPUT_ANDROID) += androidinput.o 2 | -------------------------------------------------------------------------------- /kernel/drivers/input/androidinput.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Android virtual input device 3 | * 4 | * Copyright (c) 2011 Philip Åkesson 5 | * 6 | * Based on vnckbd.c, Copyright (c) 2010 Danke Xie 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define __UNUSED __attribute__((unused)) 23 | 24 | #define X_AXIS_MAX 640 25 | #define Y_AXIS_MAX 480 26 | 27 | static unsigned int keycode_list[KEY_MAX]; /* allow all keycodes */ 28 | 29 | struct android_input { 30 | unsigned int keycode[ARRAY_SIZE(keycode_list)]; 31 | struct input_dev *input; 32 | int suspended; /*. need? */ 33 | spinlock_t lock; 34 | }; 35 | 36 | #ifdef CONFIG_INPUT_ANDROID 37 | struct platform_device android_input_device = { 38 | .name = "android-input", 39 | .id = -1, 40 | }; 41 | #endif /* CONFIG_INPUT_ANDROID */ 42 | 43 | static int __devinit android_input_probe(struct platform_device *pdev) 44 | { 45 | int i; 46 | struct android_input *android_input; 47 | struct input_dev *input_dev; 48 | int error; 49 | 50 | printk(KERN_INFO "android-input: Probing\n"); 51 | 52 | android_input = kzalloc(sizeof(struct android_input), GFP_KERNEL); 53 | if (!android_input) { 54 | return -ENOMEM; 55 | } 56 | 57 | input_dev = input_allocate_device(); 58 | if (!input_dev) { 59 | kfree(android_input); 60 | return -ENOMEM; 61 | } 62 | 63 | platform_set_drvdata(pdev, android_input); 64 | 65 | spin_lock_init(&android_input->lock); 66 | 67 | android_input->input = input_dev; 68 | 69 | input_set_drvdata(input_dev, android_input); 70 | input_dev->name = "Android virtual input"; 71 | input_dev->phys = "android/input0"; 72 | input_dev->dev.parent = &pdev->dev; 73 | 74 | input_dev->id.bustype = BUS_HOST; 75 | input_dev->id.vendor = 0x0001; 76 | input_dev->id.product = 0x0001; 77 | input_dev->id.version = 0x0100; 78 | 79 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 80 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 81 | input_set_capability(input_dev, EV_ABS, ABS_X); 82 | input_set_capability(input_dev, EV_ABS, ABS_Y); 83 | input_set_abs_params(input_dev, ABS_X, 0, X_AXIS_MAX, 0, 0); 84 | input_set_abs_params(input_dev, ABS_Y, 0, Y_AXIS_MAX, 0, 0); 85 | 86 | input_dev->keycode = android_input->keycode; 87 | input_dev->keycodesize = sizeof(unsigned int); 88 | input_dev->keycodemax = ARRAY_SIZE(keycode_list); 89 | 90 | /* one-to-one mapping from scancode to keycode */ 91 | for (i = 0; i < ARRAY_SIZE(keycode_list); i++) { 92 | keycode_list[i] = i; 93 | } 94 | 95 | memcpy(android_input->keycode, keycode_list, sizeof(keycode_list)); 96 | 97 | for (i = 0; i < ARRAY_SIZE(keycode_list); i++) 98 | __set_bit(android_input->keycode[i], input_dev->keybit); 99 | clear_bit(0, input_dev->keybit); 100 | 101 | error = input_register_device(input_dev); 102 | if (error) { 103 | printk(KERN_ERR "android-input: Unable to register input device, " 104 | "error: %d\n", error); 105 | goto fail; 106 | } 107 | 108 | printk(KERN_INFO "android-input: Registered\n"); 109 | 110 | return 0; 111 | 112 | fail: 113 | platform_set_drvdata(pdev, NULL); 114 | input_free_device(input_dev); 115 | kfree(android_input); 116 | 117 | return error; 118 | } 119 | 120 | static int __devexit android_input_remove(struct platform_device *dev) 121 | { 122 | struct android_input *android_input = platform_get_drvdata(dev); 123 | 124 | input_unregister_device(android_input->input); 125 | 126 | kfree(android_input); 127 | 128 | return 0; 129 | } 130 | 131 | static struct platform_driver android_input_driver = { 132 | .probe = android_input_probe, 133 | .remove = __devexit_p(android_input_remove), 134 | .driver = { 135 | .name = "android-input", 136 | .owner = THIS_MODULE, 137 | }, 138 | }; 139 | 140 | static int __devinit android_input_init(void) 141 | { 142 | int rc; 143 | 144 | rc = platform_driver_register(&android_input_driver); 145 | if (rc) return rc; 146 | 147 | #ifdef CONFIG_INPUT_ANDROID 148 | rc = platform_device_register(&vnc_keyboard_device); 149 | #endif 150 | 151 | return rc; 152 | } 153 | 154 | static void __exit android_input_exit(void) 155 | { 156 | platform_driver_unregister(&android_input_driver); 157 | } 158 | 159 | module_init(android_input_init); 160 | module_exit(android_input_exit); 161 | 162 | MODULE_AUTHOR("Philip Åkesson "); 163 | MODULE_AUTHOR("Danke Xie "); 164 | MODULE_DESCRIPTION("Android Input Driver"); 165 | MODULE_LICENSE("GPL v2"); 166 | MODULE_ALIAS("platform:android-input"); 167 | -------------------------------------------------------------------------------- /kernel/drivers/rtc/alarm-dev.c: -------------------------------------------------------------------------------- 1 | /* drivers/rtc/alarm-dev.c 2 | * 3 | * Copyright (C) 2007-2009 Google, Inc. 4 | * 5 | * This software is licensed under the terms of the GNU General Public 6 | * License version 2, as published by the Free Software Foundation, and 7 | * may be copied, distributed, and modified under those terms. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | */ 15 | 16 | #if !defined(__i386__) && !defined(__x86_64__) 17 | #include 18 | #endif 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define ANDROID_ALARM_PRINT_INFO (1U << 0) 31 | #define ANDROID_ALARM_PRINT_IO (1U << 1) 32 | #define ANDROID_ALARM_PRINT_INT (1U << 2) 33 | 34 | static int debug_mask = ANDROID_ALARM_PRINT_INFO; 35 | module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); 36 | 37 | #define pr_alarm(debug_level_mask, args...) \ 38 | do { \ 39 | if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \ 40 | pr_info(args); \ 41 | } \ 42 | } while (0) 43 | 44 | #define ANDROID_ALARM_WAKEUP_MASK ( \ 45 | ANDROID_ALARM_RTC_WAKEUP_MASK | \ 46 | ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) 47 | 48 | /* support old usespace code */ 49 | #define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */ 50 | #define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t) 51 | 52 | static int alarm_opened; 53 | static DEFINE_SPINLOCK(alarm_slock); 54 | static struct wake_lock alarm_wake_lock; 55 | static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue); 56 | static uint32_t alarm_pending; 57 | static uint32_t alarm_enabled; 58 | static uint32_t wait_pending; 59 | 60 | static struct alarm alarms[ANDROID_ALARM_TYPE_COUNT]; 61 | 62 | static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 63 | { 64 | int rv = 0; 65 | unsigned long flags; 66 | struct timespec new_alarm_time; 67 | struct timespec new_rtc_time; 68 | struct timespec tmp_time; 69 | enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd); 70 | uint32_t alarm_type_mask = 1U << alarm_type; 71 | 72 | if (alarm_type >= ANDROID_ALARM_TYPE_COUNT) 73 | return -EINVAL; 74 | 75 | if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) { 76 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) 77 | return -EPERM; 78 | if (file->private_data == NULL && 79 | cmd != ANDROID_ALARM_SET_RTC) { 80 | spin_lock_irqsave(&alarm_slock, flags); 81 | if (alarm_opened) { 82 | spin_unlock_irqrestore(&alarm_slock, flags); 83 | return -EBUSY; 84 | } 85 | alarm_opened = 1; 86 | file->private_data = (void *)1; 87 | spin_unlock_irqrestore(&alarm_slock, flags); 88 | } 89 | } 90 | 91 | switch (ANDROID_ALARM_BASE_CMD(cmd)) { 92 | case ANDROID_ALARM_CLEAR(0): 93 | spin_lock_irqsave(&alarm_slock, flags); 94 | pr_alarm(IO, "alarm %d clear\n", alarm_type); 95 | alarm_try_to_cancel(&alarms[alarm_type]); 96 | if (alarm_pending) { 97 | alarm_pending &= ~alarm_type_mask; 98 | if (!alarm_pending && !wait_pending) 99 | wake_unlock(&alarm_wake_lock); 100 | } 101 | alarm_enabled &= ~alarm_type_mask; 102 | spin_unlock_irqrestore(&alarm_slock, flags); 103 | break; 104 | 105 | case ANDROID_ALARM_SET_OLD: 106 | case ANDROID_ALARM_SET_AND_WAIT_OLD: 107 | if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) { 108 | rv = -EFAULT; 109 | goto err1; 110 | } 111 | new_alarm_time.tv_nsec = 0; 112 | goto from_old_alarm_set; 113 | 114 | case ANDROID_ALARM_SET_AND_WAIT(0): 115 | case ANDROID_ALARM_SET(0): 116 | if (copy_from_user(&new_alarm_time, (void __user *)arg, 117 | sizeof(new_alarm_time))) { 118 | rv = -EFAULT; 119 | goto err1; 120 | } 121 | from_old_alarm_set: 122 | spin_lock_irqsave(&alarm_slock, flags); 123 | pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type, 124 | new_alarm_time.tv_sec, new_alarm_time.tv_nsec); 125 | alarm_enabled |= alarm_type_mask; 126 | alarm_start_range(&alarms[alarm_type], 127 | timespec_to_ktime(new_alarm_time), 128 | timespec_to_ktime(new_alarm_time)); 129 | spin_unlock_irqrestore(&alarm_slock, flags); 130 | if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0) 131 | && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD) 132 | break; 133 | /* fall though */ 134 | case ANDROID_ALARM_WAIT: 135 | spin_lock_irqsave(&alarm_slock, flags); 136 | pr_alarm(IO, "alarm wait\n"); 137 | if (!alarm_pending && wait_pending) { 138 | wake_unlock(&alarm_wake_lock); 139 | wait_pending = 0; 140 | } 141 | spin_unlock_irqrestore(&alarm_slock, flags); 142 | rv = wait_event_interruptible(alarm_wait_queue, alarm_pending); 143 | if (rv) 144 | goto err1; 145 | spin_lock_irqsave(&alarm_slock, flags); 146 | rv = alarm_pending; 147 | wait_pending = 1; 148 | alarm_pending = 0; 149 | spin_unlock_irqrestore(&alarm_slock, flags); 150 | break; 151 | case ANDROID_ALARM_SET_RTC: 152 | if (copy_from_user(&new_rtc_time, (void __user *)arg, 153 | sizeof(new_rtc_time))) { 154 | rv = -EFAULT; 155 | goto err1; 156 | } 157 | rv = alarm_set_rtc(new_rtc_time); 158 | spin_lock_irqsave(&alarm_slock, flags); 159 | alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK; 160 | wake_up(&alarm_wait_queue); 161 | spin_unlock_irqrestore(&alarm_slock, flags); 162 | if (rv < 0) 163 | goto err1; 164 | break; 165 | case ANDROID_ALARM_GET_TIME(0): 166 | switch (alarm_type) { 167 | case ANDROID_ALARM_RTC_WAKEUP: 168 | case ANDROID_ALARM_RTC: 169 | getnstimeofday(&tmp_time); 170 | break; 171 | case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP: 172 | case ANDROID_ALARM_ELAPSED_REALTIME: 173 | tmp_time = 174 | ktime_to_timespec(alarm_get_elapsed_realtime()); 175 | break; 176 | case ANDROID_ALARM_TYPE_COUNT: 177 | case ANDROID_ALARM_SYSTEMTIME: 178 | ktime_get_ts(&tmp_time); 179 | break; 180 | } 181 | if (copy_to_user((void __user *)arg, &tmp_time, 182 | sizeof(tmp_time))) { 183 | rv = -EFAULT; 184 | goto err1; 185 | } 186 | break; 187 | 188 | default: 189 | rv = -EINVAL; 190 | goto err1; 191 | } 192 | err1: 193 | return rv; 194 | } 195 | 196 | static int alarm_open(struct inode *inode, struct file *file) 197 | { 198 | file->private_data = NULL; 199 | return 0; 200 | } 201 | 202 | static int alarm_release(struct inode *inode, struct file *file) 203 | { 204 | int i; 205 | unsigned long flags; 206 | 207 | spin_lock_irqsave(&alarm_slock, flags); 208 | if (file->private_data != 0) { 209 | for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) { 210 | uint32_t alarm_type_mask = 1U << i; 211 | if (alarm_enabled & alarm_type_mask) { 212 | pr_alarm(INFO, "alarm_release: clear alarm, " 213 | "pending %d\n", 214 | !!(alarm_pending & alarm_type_mask)); 215 | alarm_enabled &= ~alarm_type_mask; 216 | } 217 | spin_unlock_irqrestore(&alarm_slock, flags); 218 | alarm_cancel(&alarms[i]); 219 | spin_lock_irqsave(&alarm_slock, flags); 220 | } 221 | if (alarm_pending | wait_pending) { 222 | if (alarm_pending) 223 | pr_alarm(INFO, "alarm_release: clear " 224 | "pending alarms %x\n", alarm_pending); 225 | wake_unlock(&alarm_wake_lock); 226 | wait_pending = 0; 227 | alarm_pending = 0; 228 | } 229 | alarm_opened = 0; 230 | } 231 | spin_unlock_irqrestore(&alarm_slock, flags); 232 | return 0; 233 | } 234 | 235 | static void alarm_triggered(struct alarm *alarm) 236 | { 237 | unsigned long flags; 238 | uint32_t alarm_type_mask = 1U << alarm->type; 239 | 240 | pr_alarm(INT, "alarm_triggered type %d\n", alarm->type); 241 | spin_lock_irqsave(&alarm_slock, flags); 242 | if (alarm_enabled & alarm_type_mask) { 243 | wake_lock_timeout(&alarm_wake_lock, 5 * HZ); 244 | alarm_enabled &= ~alarm_type_mask; 245 | alarm_pending |= alarm_type_mask; 246 | wake_up(&alarm_wait_queue); 247 | } 248 | spin_unlock_irqrestore(&alarm_slock, flags); 249 | } 250 | 251 | static const struct file_operations alarm_fops = { 252 | .owner = THIS_MODULE, 253 | .unlocked_ioctl = alarm_ioctl, 254 | .open = alarm_open, 255 | .release = alarm_release, 256 | }; 257 | 258 | static struct miscdevice alarm_device = { 259 | .minor = MISC_DYNAMIC_MINOR, 260 | .name = "alarm", 261 | .fops = &alarm_fops, 262 | }; 263 | 264 | static int __init alarm_dev_init(void) 265 | { 266 | int err; 267 | int i; 268 | 269 | err = misc_register(&alarm_device); 270 | if (err) 271 | return err; 272 | 273 | for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) 274 | alarm_init(&alarms[i], i, alarm_triggered); 275 | wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm"); 276 | 277 | return 0; 278 | } 279 | 280 | static void __exit alarm_dev_exit(void) 281 | { 282 | misc_deregister(&alarm_device); 283 | wake_lock_destroy(&alarm_wake_lock); 284 | } 285 | 286 | module_init(alarm_dev_init); 287 | module_exit(alarm_dev_exit); 288 | 289 | -------------------------------------------------------------------------------- /kernel/drivers/rtc/alarm.c: -------------------------------------------------------------------------------- 1 | /* drivers/rtc/alarm.c 2 | * 3 | * Copyright (C) 2007-2009 Google, Inc. 4 | * 5 | * This software is licensed under the terms of the GNU General Public 6 | * License version 2, as published by the Free Software Foundation, and 7 | * may be copied, distributed, and modified under those terms. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | */ 15 | 16 | #if !defined(__i386__) && !defined(__x86_64__) 17 | #include 18 | #endif 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define ANDROID_ALARM_PRINT_ERROR (1U << 0) 30 | #define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1) 31 | #define ANDROID_ALARM_PRINT_TSET (1U << 2) 32 | #define ANDROID_ALARM_PRINT_CALL (1U << 3) 33 | #define ANDROID_ALARM_PRINT_SUSPEND (1U << 4) 34 | #define ANDROID_ALARM_PRINT_INT (1U << 5) 35 | #define ANDROID_ALARM_PRINT_FLOW (1U << 6) 36 | 37 | static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \ 38 | ANDROID_ALARM_PRINT_INIT_STATUS; 39 | module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); 40 | 41 | #define pr_alarm(debug_level_mask, args...) \ 42 | do { \ 43 | if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \ 44 | pr_info(args); \ 45 | } \ 46 | } while (0) 47 | 48 | #define ANDROID_ALARM_WAKEUP_MASK ( \ 49 | ANDROID_ALARM_RTC_WAKEUP_MASK | \ 50 | ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) 51 | 52 | /* support old usespace code */ 53 | #define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */ 54 | #define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t) 55 | 56 | struct alarm_queue { 57 | struct rb_root alarms; 58 | struct rb_node *first; 59 | struct hrtimer timer; 60 | ktime_t delta; 61 | bool stopped; 62 | ktime_t stopped_time; 63 | }; 64 | 65 | static struct rtc_device *alarm_rtc_dev; 66 | static DEFINE_SPINLOCK(alarm_slock); 67 | static DEFINE_MUTEX(alarm_setrtc_mutex); 68 | static struct wake_lock alarm_rtc_wake_lock; 69 | static struct platform_device *alarm_platform_dev; 70 | struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT]; 71 | static bool suspended; 72 | 73 | static void update_timer_locked(struct alarm_queue *base, bool head_removed) 74 | { 75 | struct alarm *alarm; 76 | bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] || 77 | base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; 78 | 79 | if (base->stopped) { 80 | pr_alarm(FLOW, "changed alarm while setting the wall time\n"); 81 | return; 82 | } 83 | 84 | if (is_wakeup && !suspended && head_removed) 85 | wake_unlock(&alarm_rtc_wake_lock); 86 | 87 | if (!base->first) 88 | return; 89 | 90 | alarm = container_of(base->first, struct alarm, node); 91 | 92 | pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n", 93 | alarm->type, alarm->function, ktime_to_ns(alarm->expires)); 94 | 95 | if (is_wakeup && suspended) { 96 | pr_alarm(FLOW, "changed alarm while suspened\n"); 97 | wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); 98 | return; 99 | } 100 | 101 | hrtimer_try_to_cancel(&base->timer); 102 | base->timer._expires = ktime_add(base->delta, alarm->expires); 103 | base->timer._softexpires = ktime_add(base->delta, alarm->softexpires); 104 | hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS); 105 | } 106 | 107 | static void alarm_enqueue_locked(struct alarm *alarm) 108 | { 109 | struct alarm_queue *base = &alarms[alarm->type]; 110 | struct rb_node **link = &base->alarms.rb_node; 111 | struct rb_node *parent = NULL; 112 | struct alarm *entry; 113 | int leftmost = 1; 114 | bool was_first = false; 115 | 116 | pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n", 117 | alarm->type, alarm->function, ktime_to_ns(alarm->expires)); 118 | 119 | if (base->first == &alarm->node) { 120 | base->first = rb_next(&alarm->node); 121 | was_first = true; 122 | } 123 | if (!RB_EMPTY_NODE(&alarm->node)) { 124 | rb_erase(&alarm->node, &base->alarms); 125 | RB_CLEAR_NODE(&alarm->node); 126 | } 127 | 128 | while (*link) { 129 | parent = *link; 130 | entry = rb_entry(parent, struct alarm, node); 131 | /* 132 | * We dont care about collisions. Nodes with 133 | * the same expiry time stay together. 134 | */ 135 | if (alarm->expires.tv64 < entry->expires.tv64) { 136 | link = &(*link)->rb_left; 137 | } else { 138 | link = &(*link)->rb_right; 139 | leftmost = 0; 140 | } 141 | } 142 | if (leftmost) 143 | base->first = &alarm->node; 144 | if (leftmost || was_first) 145 | update_timer_locked(base, was_first); 146 | 147 | rb_link_node(&alarm->node, parent, link); 148 | rb_insert_color(&alarm->node, &base->alarms); 149 | } 150 | 151 | /** 152 | * alarm_init - initialize an alarm 153 | * @alarm: the alarm to be initialized 154 | * @type: the alarm type to be used 155 | * @function: alarm callback function 156 | */ 157 | void alarm_init(struct alarm *alarm, 158 | enum android_alarm_type type, void (*function)(struct alarm *)) 159 | { 160 | RB_CLEAR_NODE(&alarm->node); 161 | alarm->type = type; 162 | alarm->function = function; 163 | 164 | pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function); 165 | } 166 | 167 | 168 | /** 169 | * alarm_start_range - (re)start an alarm 170 | * @alarm: the alarm to be added 171 | * @start: earliest expiry time 172 | * @end: expiry time 173 | */ 174 | void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end) 175 | { 176 | unsigned long flags; 177 | 178 | spin_lock_irqsave(&alarm_slock, flags); 179 | alarm->softexpires = start; 180 | alarm->expires = end; 181 | alarm_enqueue_locked(alarm); 182 | spin_unlock_irqrestore(&alarm_slock, flags); 183 | } 184 | 185 | /** 186 | * alarm_try_to_cancel - try to deactivate an alarm 187 | * @alarm: alarm to stop 188 | * 189 | * Returns: 190 | * 0 when the alarm was not active 191 | * 1 when the alarm was active 192 | * -1 when the alarm may currently be excuting the callback function and 193 | * cannot be stopped (it may also be inactive) 194 | */ 195 | int alarm_try_to_cancel(struct alarm *alarm) 196 | { 197 | struct alarm_queue *base = &alarms[alarm->type]; 198 | unsigned long flags; 199 | bool first = false; 200 | int ret = 0; 201 | 202 | spin_lock_irqsave(&alarm_slock, flags); 203 | if (!RB_EMPTY_NODE(&alarm->node)) { 204 | pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n", 205 | alarm->type, alarm->function, 206 | ktime_to_ns(alarm->expires)); 207 | ret = 1; 208 | if (base->first == &alarm->node) { 209 | base->first = rb_next(&alarm->node); 210 | first = true; 211 | } 212 | rb_erase(&alarm->node, &base->alarms); 213 | RB_CLEAR_NODE(&alarm->node); 214 | if (first) 215 | update_timer_locked(base, true); 216 | } else 217 | pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n", 218 | alarm->type, alarm->function); 219 | spin_unlock_irqrestore(&alarm_slock, flags); 220 | if (!ret && hrtimer_callback_running(&base->timer)) 221 | ret = -1; 222 | return ret; 223 | } 224 | 225 | /** 226 | * alarm_cancel - cancel an alarm and wait for the handler to finish. 227 | * @alarm: the alarm to be cancelled 228 | * 229 | * Returns: 230 | * 0 when the alarm was not active 231 | * 1 when the alarm was active 232 | */ 233 | int alarm_cancel(struct alarm *alarm) 234 | { 235 | for (;;) { 236 | int ret = alarm_try_to_cancel(alarm); 237 | if (ret >= 0) 238 | return ret; 239 | cpu_relax(); 240 | } 241 | } 242 | 243 | /** 244 | * alarm_set_rtc - set the kernel and rtc walltime 245 | * @new_time: timespec value containing the new time 246 | */ 247 | int alarm_set_rtc(struct timespec new_time) 248 | { 249 | int i; 250 | int ret; 251 | unsigned long flags; 252 | struct rtc_time rtc_new_rtc_time; 253 | struct timespec tmp_time; 254 | 255 | rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time); 256 | 257 | pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n", 258 | new_time.tv_sec, new_time.tv_nsec, 259 | rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min, 260 | rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1, 261 | rtc_new_rtc_time.tm_mday, 262 | rtc_new_rtc_time.tm_year + 1900); 263 | 264 | mutex_lock(&alarm_setrtc_mutex); 265 | spin_lock_irqsave(&alarm_slock, flags); 266 | wake_lock(&alarm_rtc_wake_lock); 267 | getnstimeofday(&tmp_time); 268 | for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { 269 | hrtimer_try_to_cancel(&alarms[i].timer); 270 | alarms[i].stopped = true; 271 | alarms[i].stopped_time = timespec_to_ktime(tmp_time); 272 | } 273 | alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = 274 | alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = 275 | ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta, 276 | timespec_to_ktime(timespec_sub(tmp_time, new_time))); 277 | spin_unlock_irqrestore(&alarm_slock, flags); 278 | ret = do_settimeofday(&new_time); 279 | spin_lock_irqsave(&alarm_slock, flags); 280 | for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { 281 | alarms[i].stopped = false; 282 | update_timer_locked(&alarms[i], false); 283 | } 284 | spin_unlock_irqrestore(&alarm_slock, flags); 285 | if (ret < 0) { 286 | pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n"); 287 | goto err; 288 | } 289 | if (!alarm_rtc_dev) { 290 | pr_alarm(ERROR, 291 | "alarm_set_rtc: no RTC, time will be lost on reboot\n"); 292 | goto err; 293 | } 294 | ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time); 295 | if (ret < 0) 296 | pr_alarm(ERROR, "alarm_set_rtc: " 297 | "Failed to set RTC, time will be lost on reboot\n"); 298 | err: 299 | wake_unlock(&alarm_rtc_wake_lock); 300 | mutex_unlock(&alarm_setrtc_mutex); 301 | return ret; 302 | } 303 | 304 | /** 305 | * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format 306 | * 307 | * returns the time in ktime_t format 308 | */ 309 | ktime_t alarm_get_elapsed_realtime(void) 310 | { 311 | ktime_t now; 312 | unsigned long flags; 313 | struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME]; 314 | 315 | spin_lock_irqsave(&alarm_slock, flags); 316 | now = base->stopped ? base->stopped_time : ktime_get_real(); 317 | now = ktime_sub(now, base->delta); 318 | spin_unlock_irqrestore(&alarm_slock, flags); 319 | return now; 320 | } 321 | 322 | static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer) 323 | { 324 | struct alarm_queue *base; 325 | struct alarm *alarm; 326 | unsigned long flags; 327 | ktime_t now; 328 | 329 | spin_lock_irqsave(&alarm_slock, flags); 330 | 331 | base = container_of(timer, struct alarm_queue, timer); 332 | now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer); 333 | now = ktime_sub(now, base->delta); 334 | 335 | pr_alarm(INT, "alarm_timer_triggered type %d at %lld\n", 336 | base - alarms, ktime_to_ns(now)); 337 | 338 | while (base->first) { 339 | alarm = container_of(base->first, struct alarm, node); 340 | if (alarm->softexpires.tv64 > now.tv64) { 341 | pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n", 342 | alarm->function, ktime_to_ns(alarm->expires), 343 | ktime_to_ns(alarm->softexpires)); 344 | break; 345 | } 346 | base->first = rb_next(&alarm->node); 347 | rb_erase(&alarm->node, &base->alarms); 348 | RB_CLEAR_NODE(&alarm->node); 349 | pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n", 350 | alarm->type, alarm->function, 351 | ktime_to_ns(alarm->expires), 352 | ktime_to_ns(alarm->softexpires)); 353 | spin_unlock_irqrestore(&alarm_slock, flags); 354 | alarm->function(alarm); 355 | spin_lock_irqsave(&alarm_slock, flags); 356 | } 357 | if (!base->first) 358 | pr_alarm(FLOW, "no more alarms of type %d\n", base - alarms); 359 | update_timer_locked(base, true); 360 | spin_unlock_irqrestore(&alarm_slock, flags); 361 | return HRTIMER_NORESTART; 362 | } 363 | 364 | static void alarm_triggered_func(void *p) 365 | { 366 | struct rtc_device *rtc = alarm_rtc_dev; 367 | if (!(rtc->irq_data & RTC_AF)) 368 | return; 369 | pr_alarm(INT, "rtc alarm triggered\n"); 370 | wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); 371 | } 372 | 373 | static int alarm_suspend(struct platform_device *pdev, pm_message_t state) 374 | { 375 | int err = 0; 376 | unsigned long flags; 377 | struct rtc_wkalrm rtc_alarm; 378 | struct rtc_time rtc_current_rtc_time; 379 | unsigned long rtc_current_time; 380 | unsigned long rtc_alarm_time; 381 | struct timespec rtc_delta; 382 | struct timespec wall_time; 383 | struct alarm_queue *wakeup_queue = NULL; 384 | struct alarm_queue *tmp_queue = NULL; 385 | 386 | pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event); 387 | 388 | spin_lock_irqsave(&alarm_slock, flags); 389 | suspended = true; 390 | spin_unlock_irqrestore(&alarm_slock, flags); 391 | 392 | hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer); 393 | hrtimer_cancel(&alarms[ 394 | ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK].timer); 395 | 396 | tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP]; 397 | if (tmp_queue->first) 398 | wakeup_queue = tmp_queue; 399 | tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; 400 | if (tmp_queue->first && (!wakeup_queue || 401 | hrtimer_get_expires(&tmp_queue->timer).tv64 < 402 | hrtimer_get_expires(&wakeup_queue->timer).tv64)) 403 | wakeup_queue = tmp_queue; 404 | if (wakeup_queue) { 405 | rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); 406 | getnstimeofday(&wall_time); 407 | rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); 408 | set_normalized_timespec(&rtc_delta, 409 | wall_time.tv_sec - rtc_current_time, 410 | wall_time.tv_nsec); 411 | 412 | rtc_alarm_time = timespec_sub(ktime_to_timespec( 413 | hrtimer_get_expires(&wakeup_queue->timer)), 414 | rtc_delta).tv_sec; 415 | 416 | rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time); 417 | rtc_alarm.enabled = 1; 418 | rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); 419 | rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); 420 | rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); 421 | pr_alarm(SUSPEND, 422 | "rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n", 423 | rtc_alarm_time, rtc_current_time, 424 | rtc_delta.tv_sec, rtc_delta.tv_nsec); 425 | if (rtc_current_time + 1 >= rtc_alarm_time) { 426 | pr_alarm(SUSPEND, "alarm about to go off\n"); 427 | memset(&rtc_alarm, 0, sizeof(rtc_alarm)); 428 | rtc_alarm.enabled = 0; 429 | rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); 430 | 431 | spin_lock_irqsave(&alarm_slock, flags); 432 | suspended = false; 433 | wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ); 434 | update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], 435 | false); 436 | update_timer_locked(&alarms[ 437 | ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false); 438 | err = -EBUSY; 439 | spin_unlock_irqrestore(&alarm_slock, flags); 440 | } 441 | } 442 | return err; 443 | } 444 | 445 | static int alarm_resume(struct platform_device *pdev) 446 | { 447 | struct rtc_wkalrm alarm; 448 | unsigned long flags; 449 | 450 | pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev); 451 | 452 | memset(&alarm, 0, sizeof(alarm)); 453 | alarm.enabled = 0; 454 | rtc_set_alarm(alarm_rtc_dev, &alarm); 455 | 456 | spin_lock_irqsave(&alarm_slock, flags); 457 | suspended = false; 458 | update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false); 459 | update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], 460 | false); 461 | spin_unlock_irqrestore(&alarm_slock, flags); 462 | 463 | return 0; 464 | } 465 | 466 | static struct rtc_task alarm_rtc_task = { 467 | .func = alarm_triggered_func 468 | }; 469 | 470 | static int rtc_alarm_add_device(struct device *dev, 471 | struct class_interface *class_intf) 472 | { 473 | int err; 474 | struct rtc_device *rtc = to_rtc_device(dev); 475 | 476 | mutex_lock(&alarm_setrtc_mutex); 477 | 478 | if (alarm_rtc_dev) { 479 | err = -EBUSY; 480 | goto err1; 481 | } 482 | 483 | alarm_platform_dev = 484 | platform_device_register_simple("alarm", -1, NULL, 0); 485 | if (IS_ERR(alarm_platform_dev)) { 486 | err = PTR_ERR(alarm_platform_dev); 487 | goto err2; 488 | } 489 | err = rtc_irq_register(rtc, &alarm_rtc_task); 490 | if (err) 491 | goto err3; 492 | alarm_rtc_dev = rtc; 493 | pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name); 494 | mutex_unlock(&alarm_setrtc_mutex); 495 | 496 | return 0; 497 | 498 | err3: 499 | platform_device_unregister(alarm_platform_dev); 500 | err2: 501 | err1: 502 | mutex_unlock(&alarm_setrtc_mutex); 503 | return err; 504 | } 505 | 506 | static void rtc_alarm_remove_device(struct device *dev, 507 | struct class_interface *class_intf) 508 | { 509 | if (dev == &alarm_rtc_dev->dev) { 510 | pr_alarm(INIT_STATUS, "lost rtc device for alarms"); 511 | rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task); 512 | platform_device_unregister(alarm_platform_dev); 513 | alarm_rtc_dev = NULL; 514 | } 515 | } 516 | 517 | static struct class_interface rtc_alarm_interface = { 518 | .add_dev = &rtc_alarm_add_device, 519 | .remove_dev = &rtc_alarm_remove_device, 520 | }; 521 | 522 | static struct platform_driver alarm_driver = { 523 | .suspend = alarm_suspend, 524 | .resume = alarm_resume, 525 | .driver = { 526 | .name = "alarm" 527 | } 528 | }; 529 | 530 | static int __init alarm_late_init(void) 531 | { 532 | unsigned long flags; 533 | struct timespec tmp_time, system_time; 534 | 535 | /* this needs to run after the rtc is read at boot */ 536 | spin_lock_irqsave(&alarm_slock, flags); 537 | /* We read the current rtc and system time so we can later calulate 538 | * elasped realtime to be (boot_systemtime + rtc - boot_rtc) == 539 | * (rtc - (boot_rtc - boot_systemtime)) 540 | */ 541 | getnstimeofday(&tmp_time); 542 | ktime_get_ts(&system_time); 543 | alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = 544 | alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = 545 | timespec_to_ktime(timespec_sub(tmp_time, system_time)); 546 | 547 | spin_unlock_irqrestore(&alarm_slock, flags); 548 | return 0; 549 | } 550 | 551 | static int __init alarm_driver_init(void) 552 | { 553 | int err; 554 | int i; 555 | 556 | for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { 557 | hrtimer_init(&alarms[i].timer, 558 | CLOCK_REALTIME, HRTIMER_MODE_ABS); 559 | alarms[i].timer.function = alarm_timer_triggered; 560 | } 561 | hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer, 562 | CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 563 | alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered; 564 | err = platform_driver_register(&alarm_driver); 565 | if (err < 0) 566 | goto err1; 567 | wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc"); 568 | rtc_alarm_interface.class = rtc_class; 569 | err = class_interface_register(&rtc_alarm_interface); 570 | if (err < 0) 571 | goto err2; 572 | 573 | return 0; 574 | 575 | err2: 576 | wake_lock_destroy(&alarm_rtc_wake_lock); 577 | platform_driver_unregister(&alarm_driver); 578 | err1: 579 | return err; 580 | } 581 | 582 | static void __exit alarm_exit(void) 583 | { 584 | class_interface_unregister(&rtc_alarm_interface); 585 | wake_lock_destroy(&alarm_rtc_wake_lock); 586 | platform_driver_unregister(&alarm_driver); 587 | } 588 | 589 | late_initcall(alarm_late_init); 590 | module_init(alarm_driver_init); 591 | module_exit(alarm_exit); 592 | 593 | -------------------------------------------------------------------------------- /kernel/drivers/video/vfb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/drivers/video/vfb.c -- Virtual frame buffer device 3 | * 4 | * Copyright (C) 2002 James Simmons 5 | * 6 | * Copyright (C) 1997 Geert Uytterhoeven 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of this archive for 10 | * more details. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | /* 27 | * RAM we reserve for the frame buffer. This defines the maximum screen 28 | * size 29 | * 30 | * The default can be overridden if the driver is compiled as a module 31 | */ 32 | 33 | #define VIDEOMEMSIZE (4*1024*1024) /* 4 MB */ 34 | 35 | static void *videomemory; 36 | static u_long videomemorysize = VIDEOMEMSIZE; 37 | module_param(videomemorysize, ulong, 0); 38 | 39 | /********************************************************************** 40 | * 41 | * Memory management 42 | * 43 | **********************************************************************/ 44 | static void *rvmalloc(unsigned long size) 45 | { 46 | void *mem; 47 | unsigned long adr; 48 | 49 | size = PAGE_ALIGN(size); 50 | mem = vmalloc_32(size); 51 | if (!mem) 52 | return NULL; 53 | 54 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ 55 | adr = (unsigned long) mem; 56 | while (size > 0) { 57 | SetPageReserved(vmalloc_to_page((void *)adr)); 58 | adr += PAGE_SIZE; 59 | size -= PAGE_SIZE; 60 | } 61 | 62 | return mem; 63 | } 64 | 65 | static void rvfree(void *mem, unsigned long size) 66 | { 67 | unsigned long adr; 68 | 69 | if (!mem) 70 | return; 71 | 72 | adr = (unsigned long) mem; 73 | while ((long) size > 0) { 74 | ClearPageReserved(vmalloc_to_page((void *)adr)); 75 | adr += PAGE_SIZE; 76 | size -= PAGE_SIZE; 77 | } 78 | vfree(mem); 79 | } 80 | 81 | static struct fb_var_screeninfo vfb_default __devinitdata = { 82 | .xres = 640, 83 | .yres = 480, 84 | .xres_virtual = 640, 85 | .yres_virtual = 960, 86 | .bits_per_pixel = 16, 87 | .red = { 0, 5, 0 }, 88 | .green = { 5, 6, 0 }, 89 | .blue = { 11, 5, 0 }, 90 | .activate = FB_ACTIVATE_TEST, 91 | .height = -1, 92 | .width = -1, 93 | .pixclock = 20000, 94 | .left_margin = 64, 95 | .right_margin = 64, 96 | .upper_margin = 32, 97 | .lower_margin = 32, 98 | .hsync_len = 64, 99 | .vsync_len = 2, 100 | .vmode = FB_VMODE_NONINTERLACED, 101 | }; 102 | 103 | static struct fb_fix_screeninfo vfb_fix __devinitdata = { 104 | .id = "Virtual FB", 105 | .type = FB_TYPE_PACKED_PIXELS, 106 | .visual = FB_VISUAL_PSEUDOCOLOR, 107 | .xpanstep = 0, 108 | .ypanstep = 1, 109 | .ywrapstep = 0, 110 | .accel = FB_ACCEL_NONE, 111 | }; 112 | 113 | static int vfb_enable __initdata = 0; /* disabled by default */ 114 | module_param(vfb_enable, bool, 0); 115 | 116 | static int vfb_check_var(struct fb_var_screeninfo *var, 117 | struct fb_info *info); 118 | static int vfb_set_par(struct fb_info *info); 119 | static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 120 | u_int transp, struct fb_info *info); 121 | static int vfb_pan_display(struct fb_var_screeninfo *var, 122 | struct fb_info *info); 123 | static int vfb_mmap(struct fb_info *info, 124 | struct vm_area_struct *vma); 125 | 126 | static struct fb_ops vfb_ops = { 127 | .fb_read = fb_sys_read, 128 | .fb_write = fb_sys_write, 129 | .fb_check_var = vfb_check_var, 130 | .fb_set_par = vfb_set_par, 131 | .fb_setcolreg = vfb_setcolreg, 132 | .fb_pan_display = vfb_pan_display, 133 | .fb_fillrect = sys_fillrect, 134 | .fb_copyarea = sys_copyarea, 135 | .fb_imageblit = sys_imageblit, 136 | .fb_mmap = vfb_mmap, 137 | }; 138 | 139 | /* 140 | * Internal routines 141 | */ 142 | 143 | static u_long get_line_length(int xres_virtual, int bpp) 144 | { 145 | u_long length; 146 | 147 | length = xres_virtual * bpp; 148 | length = (length + 31) & ~31; 149 | length >>= 3; 150 | return (length); 151 | } 152 | 153 | /* 154 | * Setting the video mode has been split into two parts. 155 | * First part, xxxfb_check_var, must not write anything 156 | * to hardware, it should only verify and adjust var. 157 | * This means it doesn't alter par but it does use hardware 158 | * data from it to check this var. 159 | */ 160 | 161 | static int vfb_check_var(struct fb_var_screeninfo *var, 162 | struct fb_info *info) 163 | { 164 | u_long line_length; 165 | 166 | /* 167 | * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! 168 | * as FB_VMODE_SMOOTH_XPAN is only used internally 169 | */ 170 | 171 | if (var->vmode & FB_VMODE_CONUPDATE) { 172 | var->vmode |= FB_VMODE_YWRAP; 173 | var->xoffset = info->var.xoffset; 174 | var->yoffset = info->var.yoffset; 175 | } 176 | 177 | /* 178 | * Some very basic checks 179 | */ 180 | if (!var->xres) 181 | var->xres = 1; 182 | if (!var->yres) 183 | var->yres = 1; 184 | if (var->xres > var->xres_virtual) 185 | var->xres_virtual = var->xres; 186 | if (var->yres > var->yres_virtual) 187 | var->yres_virtual = var->yres; 188 | if (var->bits_per_pixel <= 1) 189 | var->bits_per_pixel = 1; 190 | else if (var->bits_per_pixel <= 8) 191 | var->bits_per_pixel = 8; 192 | else if (var->bits_per_pixel <= 16) 193 | var->bits_per_pixel = 16; 194 | else if (var->bits_per_pixel <= 24) 195 | var->bits_per_pixel = 24; 196 | else if (var->bits_per_pixel <= 32) 197 | var->bits_per_pixel = 32; 198 | else 199 | return -EINVAL; 200 | 201 | if (var->xres_virtual < var->xoffset + var->xres) 202 | var->xres_virtual = var->xoffset + var->xres; 203 | if (var->yres_virtual < var->yoffset + var->yres) 204 | var->yres_virtual = var->yoffset + var->yres; 205 | 206 | /* 207 | * Memory limit 208 | */ 209 | line_length = 210 | get_line_length(var->xres_virtual, var->bits_per_pixel); 211 | if (line_length * var->yres_virtual > videomemorysize) 212 | return -ENOMEM; 213 | 214 | /* 215 | * Now that we checked it we alter var. The reason being is that the video 216 | * mode passed in might not work but slight changes to it might make it 217 | * work. This way we let the user know what is acceptable. 218 | */ 219 | switch (var->bits_per_pixel) { 220 | case 1: 221 | case 8: 222 | var->red.offset = 0; 223 | var->red.length = 8; 224 | var->green.offset = 0; 225 | var->green.length = 8; 226 | var->blue.offset = 0; 227 | var->blue.length = 8; 228 | var->transp.offset = 0; 229 | var->transp.length = 0; 230 | break; 231 | case 16: /* RGBA 5551 */ 232 | if (var->transp.length) { 233 | var->red.offset = 0; 234 | var->red.length = 5; 235 | var->green.offset = 5; 236 | var->green.length = 5; 237 | var->blue.offset = 10; 238 | var->blue.length = 5; 239 | var->transp.offset = 15; 240 | var->transp.length = 1; 241 | } else { /* RGB 565 */ 242 | var->red.offset = 0; 243 | var->red.length = 5; 244 | var->green.offset = 5; 245 | var->green.length = 6; 246 | var->blue.offset = 11; 247 | var->blue.length = 5; 248 | var->transp.offset = 0; 249 | var->transp.length = 0; 250 | } 251 | break; 252 | case 24: /* RGB 888 */ 253 | var->red.offset = 0; 254 | var->red.length = 8; 255 | var->green.offset = 8; 256 | var->green.length = 8; 257 | var->blue.offset = 16; 258 | var->blue.length = 8; 259 | var->transp.offset = 0; 260 | var->transp.length = 0; 261 | break; 262 | case 32: /* RGBA 8888 */ 263 | var->red.offset = 0; 264 | var->red.length = 8; 265 | var->green.offset = 8; 266 | var->green.length = 8; 267 | var->blue.offset = 16; 268 | var->blue.length = 8; 269 | var->transp.offset = 24; 270 | var->transp.length = 8; 271 | break; 272 | } 273 | var->red.msb_right = 0; 274 | var->green.msb_right = 0; 275 | var->blue.msb_right = 0; 276 | var->transp.msb_right = 0; 277 | 278 | return 0; 279 | } 280 | 281 | /* This routine actually sets the video mode. It's in here where we 282 | * the hardware state info->par and fix which can be affected by the 283 | * change in par. For this driver it doesn't do much. 284 | */ 285 | static int vfb_set_par(struct fb_info *info) 286 | { 287 | info->fix.line_length = get_line_length(info->var.xres_virtual, 288 | info->var.bits_per_pixel); 289 | return 0; 290 | } 291 | 292 | /* 293 | * Set a single color register. The values supplied are already 294 | * rounded down to the hardware's capabilities (according to the 295 | * entries in the var structure). Return != 0 for invalid regno. 296 | */ 297 | 298 | static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 299 | u_int transp, struct fb_info *info) 300 | { 301 | if (regno >= 256) /* no. of hw registers */ 302 | return 1; 303 | /* 304 | * Program hardware... do anything you want with transp 305 | */ 306 | 307 | /* grayscale works only partially under directcolor */ 308 | if (info->var.grayscale) { 309 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 310 | red = green = blue = 311 | (red * 77 + green * 151 + blue * 28) >> 8; 312 | } 313 | 314 | /* Directcolor: 315 | * var->{color}.offset contains start of bitfield 316 | * var->{color}.length contains length of bitfield 317 | * {hardwarespecific} contains width of RAMDAC 318 | * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) 319 | * RAMDAC[X] is programmed to (red, green, blue) 320 | * 321 | * Pseudocolor: 322 | * var->{color}.offset is 0 unless the palette index takes less than 323 | * bits_per_pixel bits and is stored in the upper 324 | * bits of the pixel value 325 | * var->{color}.length is set so that 1 << length is the number of available 326 | * palette entries 327 | * cmap is not used 328 | * RAMDAC[X] is programmed to (red, green, blue) 329 | * 330 | * Truecolor: 331 | * does not use DAC. Usually 3 are present. 332 | * var->{color}.offset contains start of bitfield 333 | * var->{color}.length contains length of bitfield 334 | * cmap is programmed to (red << red.offset) | (green << green.offset) | 335 | * (blue << blue.offset) | (transp << transp.offset) 336 | * RAMDAC does not exist 337 | */ 338 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) 339 | switch (info->fix.visual) { 340 | case FB_VISUAL_TRUECOLOR: 341 | case FB_VISUAL_PSEUDOCOLOR: 342 | red = CNVT_TOHW(red, info->var.red.length); 343 | green = CNVT_TOHW(green, info->var.green.length); 344 | blue = CNVT_TOHW(blue, info->var.blue.length); 345 | transp = CNVT_TOHW(transp, info->var.transp.length); 346 | break; 347 | case FB_VISUAL_DIRECTCOLOR: 348 | red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ 349 | green = CNVT_TOHW(green, 8); 350 | blue = CNVT_TOHW(blue, 8); 351 | /* hey, there is bug in transp handling... */ 352 | transp = CNVT_TOHW(transp, 8); 353 | break; 354 | } 355 | #undef CNVT_TOHW 356 | /* Truecolor has hardware independent palette */ 357 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 358 | u32 v; 359 | 360 | if (regno >= 16) 361 | return 1; 362 | 363 | v = (red << info->var.red.offset) | 364 | (green << info->var.green.offset) | 365 | (blue << info->var.blue.offset) | 366 | (transp << info->var.transp.offset); 367 | switch (info->var.bits_per_pixel) { 368 | case 8: 369 | break; 370 | case 16: 371 | ((u32 *) (info->pseudo_palette))[regno] = v; 372 | break; 373 | case 24: 374 | case 32: 375 | ((u32 *) (info->pseudo_palette))[regno] = v; 376 | break; 377 | } 378 | return 0; 379 | } 380 | return 0; 381 | } 382 | 383 | /* 384 | * Pan or Wrap the Display 385 | * 386 | * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 387 | */ 388 | 389 | static int vfb_pan_display(struct fb_var_screeninfo *var, 390 | struct fb_info *info) 391 | { 392 | if (var->vmode & FB_VMODE_YWRAP) { 393 | if (var->yoffset < 0 394 | || var->yoffset >= info->var.yres_virtual 395 | || var->xoffset) 396 | return -EINVAL; 397 | } else { 398 | if (var->xoffset + var->xres > info->var.xres_virtual || 399 | var->yoffset + var->yres > info->var.yres_virtual) 400 | return -EINVAL; 401 | } 402 | info->var.xoffset = var->xoffset; 403 | info->var.yoffset = var->yoffset; 404 | if (var->vmode & FB_VMODE_YWRAP) 405 | info->var.vmode |= FB_VMODE_YWRAP; 406 | else 407 | info->var.vmode &= ~FB_VMODE_YWRAP; 408 | return 0; 409 | } 410 | 411 | /* 412 | * Most drivers don't need their own mmap function 413 | */ 414 | 415 | static int vfb_mmap(struct fb_info *info, 416 | struct vm_area_struct *vma) 417 | { 418 | unsigned long start = vma->vm_start; 419 | unsigned long size = vma->vm_end - vma->vm_start; 420 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 421 | unsigned long page, pos; 422 | 423 | if (offset + size > info->fix.smem_len) { 424 | return -EINVAL; 425 | } 426 | 427 | pos = (unsigned long)info->fix.smem_start + offset; 428 | 429 | while (size > 0) { 430 | page = vmalloc_to_pfn((void *)pos); 431 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { 432 | return -EAGAIN; 433 | } 434 | start += PAGE_SIZE; 435 | pos += PAGE_SIZE; 436 | if (size > PAGE_SIZE) 437 | size -= PAGE_SIZE; 438 | else 439 | size = 0; 440 | } 441 | 442 | vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ 443 | return 0; 444 | 445 | } 446 | 447 | #ifndef MODULE 448 | /* 449 | * The virtual framebuffer driver is only enabled if explicitly 450 | * requested by passing 'video=vfb:' (or any actual options). 451 | */ 452 | static int __init vfb_setup(char *options) 453 | { 454 | char *this_opt; 455 | 456 | vfb_enable = 0; 457 | 458 | if (!options) 459 | return 1; 460 | 461 | vfb_enable = 1; 462 | 463 | if (!*options) 464 | return 1; 465 | 466 | while ((this_opt = strsep(&options, ",")) != NULL) { 467 | if (!*this_opt) 468 | continue; 469 | /* Test disable for backwards compatibility */ 470 | if (!strcmp(this_opt, "disable")) 471 | vfb_enable = 0; 472 | } 473 | return 1; 474 | } 475 | #endif /* MODULE */ 476 | 477 | /* 478 | * Initialisation 479 | */ 480 | 481 | static int __devinit vfb_probe(struct platform_device *dev) 482 | { 483 | struct fb_info *info; 484 | int retval = -ENOMEM; 485 | 486 | /* 487 | * For real video cards we use ioremap. 488 | */ 489 | if (!(videomemory = rvmalloc(videomemorysize))) 490 | return retval; 491 | 492 | /* 493 | * VFB must clear memory to prevent kernel info 494 | * leakage into userspace 495 | * VGA-based drivers MUST NOT clear memory if 496 | * they want to be able to take over vgacon 497 | */ 498 | memset(videomemory, 0, videomemorysize); 499 | 500 | info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); 501 | if (!info) 502 | goto err; 503 | 504 | info->screen_base = (char __iomem *)videomemory; 505 | info->fbops = &vfb_ops; 506 | 507 | //retval = fb_find_mode(&info->var, info, NULL, 508 | // NULL, 0, NULL, 8); 509 | 510 | //if (!retval || (retval == 4)) 511 | // info->var = vfb_default; 512 | 513 | info->var = vfb_default; 514 | 515 | vfb_fix.smem_start = (unsigned long) videomemory; 516 | vfb_fix.smem_len = videomemorysize; 517 | info->fix = vfb_fix; 518 | info->pseudo_palette = info->par; 519 | info->par = NULL; 520 | info->flags = FBINFO_FLAG_DEFAULT; 521 | 522 | retval = fb_alloc_cmap(&info->cmap, 256, 0); 523 | if (retval < 0) 524 | goto err1; 525 | 526 | retval = register_framebuffer(info); 527 | if (retval < 0) 528 | goto err2; 529 | platform_set_drvdata(dev, info); 530 | 531 | printk(KERN_INFO 532 | "fb%d: Virtual frame buffer device, using %ldK of video memory\n", 533 | info->node, videomemorysize >> 10); 534 | return 0; 535 | err2: 536 | fb_dealloc_cmap(&info->cmap); 537 | err1: 538 | framebuffer_release(info); 539 | err: 540 | rvfree(videomemory, videomemorysize); 541 | return retval; 542 | } 543 | 544 | static int vfb_remove(struct platform_device *dev) 545 | { 546 | struct fb_info *info = platform_get_drvdata(dev); 547 | 548 | if (info) { 549 | unregister_framebuffer(info); 550 | rvfree(videomemory, videomemorysize); 551 | fb_dealloc_cmap(&info->cmap); 552 | framebuffer_release(info); 553 | } 554 | return 0; 555 | } 556 | 557 | static struct platform_driver vfb_driver = { 558 | .probe = vfb_probe, 559 | .remove = vfb_remove, 560 | .driver = { 561 | .name = "vfb", 562 | }, 563 | }; 564 | 565 | static struct platform_device *vfb_device; 566 | 567 | static int __init vfb_init(void) 568 | { 569 | int ret = 0; 570 | 571 | #ifndef MODULE 572 | char *option = NULL; 573 | 574 | if (fb_get_options("vfb", &option)) 575 | return -ENODEV; 576 | vfb_setup(option); 577 | #endif 578 | 579 | if (!vfb_enable) 580 | return -ENXIO; 581 | 582 | ret = platform_driver_register(&vfb_driver); 583 | 584 | if (!ret) { 585 | vfb_device = platform_device_alloc("vfb", 0); 586 | 587 | if (vfb_device) 588 | ret = platform_device_add(vfb_device); 589 | else 590 | ret = -ENOMEM; 591 | 592 | if (ret) { 593 | platform_device_put(vfb_device); 594 | platform_driver_unregister(&vfb_driver); 595 | } 596 | } 597 | 598 | return ret; 599 | } 600 | 601 | module_init(vfb_init); 602 | 603 | #ifdef MODULE 604 | static void __exit vfb_exit(void) 605 | { 606 | platform_device_unregister(vfb_device); 607 | platform_driver_unregister(&vfb_driver); 608 | } 609 | 610 | module_exit(vfb_exit); 611 | 612 | MODULE_LICENSE("GPL"); 613 | #endif /* MODULE */ 614 | -------------------------------------------------------------------------------- /kernel/drivers/video/vfb.original.c: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/drivers/video/vfb.c -- Virtual frame buffer device 3 | * 4 | * Copyright (C) 2002 James Simmons 5 | * 6 | * Copyright (C) 1997 Geert Uytterhoeven 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of this archive for 10 | * more details. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | /* 27 | * RAM we reserve for the frame buffer. This defines the maximum screen 28 | * size 29 | * 30 | * The default can be overridden if the driver is compiled as a module 31 | */ 32 | 33 | #define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */ 34 | 35 | static void *videomemory; 36 | static u_long videomemorysize = VIDEOMEMSIZE; 37 | module_param(videomemorysize, ulong, 0); 38 | 39 | /********************************************************************** 40 | * 41 | * Memory management 42 | * 43 | **********************************************************************/ 44 | static void *rvmalloc(unsigned long size) 45 | { 46 | void *mem; 47 | unsigned long adr; 48 | 49 | size = PAGE_ALIGN(size); 50 | mem = vmalloc_32(size); 51 | if (!mem) 52 | return NULL; 53 | 54 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ 55 | adr = (unsigned long) mem; 56 | while (size > 0) { 57 | SetPageReserved(vmalloc_to_page((void *)adr)); 58 | adr += PAGE_SIZE; 59 | size -= PAGE_SIZE; 60 | } 61 | 62 | return mem; 63 | } 64 | 65 | static void rvfree(void *mem, unsigned long size) 66 | { 67 | unsigned long adr; 68 | 69 | if (!mem) 70 | return; 71 | 72 | adr = (unsigned long) mem; 73 | while ((long) size > 0) { 74 | ClearPageReserved(vmalloc_to_page((void *)adr)); 75 | adr += PAGE_SIZE; 76 | size -= PAGE_SIZE; 77 | } 78 | vfree(mem); 79 | } 80 | 81 | static struct fb_var_screeninfo vfb_default __devinitdata = { 82 | .xres = 640, 83 | .yres = 480, 84 | .xres_virtual = 640, 85 | .yres_virtual = 480, 86 | .bits_per_pixel = 8, 87 | .red = { 0, 8, 0 }, 88 | .green = { 0, 8, 0 }, 89 | .blue = { 0, 8, 0 }, 90 | .activate = FB_ACTIVATE_TEST, 91 | .height = -1, 92 | .width = -1, 93 | .pixclock = 20000, 94 | .left_margin = 64, 95 | .right_margin = 64, 96 | .upper_margin = 32, 97 | .lower_margin = 32, 98 | .hsync_len = 64, 99 | .vsync_len = 2, 100 | .vmode = FB_VMODE_NONINTERLACED, 101 | }; 102 | 103 | static struct fb_fix_screeninfo vfb_fix __devinitdata = { 104 | .id = "Virtual FB", 105 | .type = FB_TYPE_PACKED_PIXELS, 106 | .visual = FB_VISUAL_PSEUDOCOLOR, 107 | .xpanstep = 1, 108 | .ypanstep = 1, 109 | .ywrapstep = 1, 110 | .accel = FB_ACCEL_NONE, 111 | }; 112 | 113 | static int vfb_enable __initdata = 0; /* disabled by default */ 114 | module_param(vfb_enable, bool, 0); 115 | 116 | static int vfb_check_var(struct fb_var_screeninfo *var, 117 | struct fb_info *info); 118 | static int vfb_set_par(struct fb_info *info); 119 | static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 120 | u_int transp, struct fb_info *info); 121 | static int vfb_pan_display(struct fb_var_screeninfo *var, 122 | struct fb_info *info); 123 | static int vfb_mmap(struct fb_info *info, 124 | struct vm_area_struct *vma); 125 | 126 | static struct fb_ops vfb_ops = { 127 | .fb_read = fb_sys_read, 128 | .fb_write = fb_sys_write, 129 | .fb_check_var = vfb_check_var, 130 | .fb_set_par = vfb_set_par, 131 | .fb_setcolreg = vfb_setcolreg, 132 | .fb_pan_display = vfb_pan_display, 133 | .fb_fillrect = sys_fillrect, 134 | .fb_copyarea = sys_copyarea, 135 | .fb_imageblit = sys_imageblit, 136 | .fb_mmap = vfb_mmap, 137 | }; 138 | 139 | /* 140 | * Internal routines 141 | */ 142 | 143 | static u_long get_line_length(int xres_virtual, int bpp) 144 | { 145 | u_long length; 146 | 147 | length = xres_virtual * bpp; 148 | length = (length + 31) & ~31; 149 | length >>= 3; 150 | return (length); 151 | } 152 | 153 | /* 154 | * Setting the video mode has been split into two parts. 155 | * First part, xxxfb_check_var, must not write anything 156 | * to hardware, it should only verify and adjust var. 157 | * This means it doesn't alter par but it does use hardware 158 | * data from it to check this var. 159 | */ 160 | 161 | static int vfb_check_var(struct fb_var_screeninfo *var, 162 | struct fb_info *info) 163 | { 164 | u_long line_length; 165 | 166 | /* 167 | * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! 168 | * as FB_VMODE_SMOOTH_XPAN is only used internally 169 | */ 170 | 171 | if (var->vmode & FB_VMODE_CONUPDATE) { 172 | var->vmode |= FB_VMODE_YWRAP; 173 | var->xoffset = info->var.xoffset; 174 | var->yoffset = info->var.yoffset; 175 | } 176 | 177 | /* 178 | * Some very basic checks 179 | */ 180 | if (!var->xres) 181 | var->xres = 1; 182 | if (!var->yres) 183 | var->yres = 1; 184 | if (var->xres > var->xres_virtual) 185 | var->xres_virtual = var->xres; 186 | if (var->yres > var->yres_virtual) 187 | var->yres_virtual = var->yres; 188 | if (var->bits_per_pixel <= 1) 189 | var->bits_per_pixel = 1; 190 | else if (var->bits_per_pixel <= 8) 191 | var->bits_per_pixel = 8; 192 | else if (var->bits_per_pixel <= 16) 193 | var->bits_per_pixel = 16; 194 | else if (var->bits_per_pixel <= 24) 195 | var->bits_per_pixel = 24; 196 | else if (var->bits_per_pixel <= 32) 197 | var->bits_per_pixel = 32; 198 | else 199 | return -EINVAL; 200 | 201 | if (var->xres_virtual < var->xoffset + var->xres) 202 | var->xres_virtual = var->xoffset + var->xres; 203 | if (var->yres_virtual < var->yoffset + var->yres) 204 | var->yres_virtual = var->yoffset + var->yres; 205 | 206 | /* 207 | * Memory limit 208 | */ 209 | line_length = 210 | get_line_length(var->xres_virtual, var->bits_per_pixel); 211 | if (line_length * var->yres_virtual > videomemorysize) 212 | return -ENOMEM; 213 | 214 | /* 215 | * Now that we checked it we alter var. The reason being is that the video 216 | * mode passed in might not work but slight changes to it might make it 217 | * work. This way we let the user know what is acceptable. 218 | */ 219 | switch (var->bits_per_pixel) { 220 | case 1: 221 | case 8: 222 | var->red.offset = 0; 223 | var->red.length = 8; 224 | var->green.offset = 0; 225 | var->green.length = 8; 226 | var->blue.offset = 0; 227 | var->blue.length = 8; 228 | var->transp.offset = 0; 229 | var->transp.length = 0; 230 | break; 231 | case 16: /* RGBA 5551 */ 232 | if (var->transp.length) { 233 | var->red.offset = 0; 234 | var->red.length = 5; 235 | var->green.offset = 5; 236 | var->green.length = 5; 237 | var->blue.offset = 10; 238 | var->blue.length = 5; 239 | var->transp.offset = 15; 240 | var->transp.length = 1; 241 | } else { /* RGB 565 */ 242 | var->red.offset = 0; 243 | var->red.length = 5; 244 | var->green.offset = 5; 245 | var->green.length = 6; 246 | var->blue.offset = 11; 247 | var->blue.length = 5; 248 | var->transp.offset = 0; 249 | var->transp.length = 0; 250 | } 251 | break; 252 | case 24: /* RGB 888 */ 253 | var->red.offset = 0; 254 | var->red.length = 8; 255 | var->green.offset = 8; 256 | var->green.length = 8; 257 | var->blue.offset = 16; 258 | var->blue.length = 8; 259 | var->transp.offset = 0; 260 | var->transp.length = 0; 261 | break; 262 | case 32: /* RGBA 8888 */ 263 | var->red.offset = 0; 264 | var->red.length = 8; 265 | var->green.offset = 8; 266 | var->green.length = 8; 267 | var->blue.offset = 16; 268 | var->blue.length = 8; 269 | var->transp.offset = 24; 270 | var->transp.length = 8; 271 | break; 272 | } 273 | var->red.msb_right = 0; 274 | var->green.msb_right = 0; 275 | var->blue.msb_right = 0; 276 | var->transp.msb_right = 0; 277 | 278 | return 0; 279 | } 280 | 281 | /* This routine actually sets the video mode. It's in here where we 282 | * the hardware state info->par and fix which can be affected by the 283 | * change in par. For this driver it doesn't do much. 284 | */ 285 | static int vfb_set_par(struct fb_info *info) 286 | { 287 | info->fix.line_length = get_line_length(info->var.xres_virtual, 288 | info->var.bits_per_pixel); 289 | return 0; 290 | } 291 | 292 | /* 293 | * Set a single color register. The values supplied are already 294 | * rounded down to the hardware's capabilities (according to the 295 | * entries in the var structure). Return != 0 for invalid regno. 296 | */ 297 | 298 | static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 299 | u_int transp, struct fb_info *info) 300 | { 301 | if (regno >= 256) /* no. of hw registers */ 302 | return 1; 303 | /* 304 | * Program hardware... do anything you want with transp 305 | */ 306 | 307 | /* grayscale works only partially under directcolor */ 308 | if (info->var.grayscale) { 309 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 310 | red = green = blue = 311 | (red * 77 + green * 151 + blue * 28) >> 8; 312 | } 313 | 314 | /* Directcolor: 315 | * var->{color}.offset contains start of bitfield 316 | * var->{color}.length contains length of bitfield 317 | * {hardwarespecific} contains width of RAMDAC 318 | * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) 319 | * RAMDAC[X] is programmed to (red, green, blue) 320 | * 321 | * Pseudocolor: 322 | * var->{color}.offset is 0 unless the palette index takes less than 323 | * bits_per_pixel bits and is stored in the upper 324 | * bits of the pixel value 325 | * var->{color}.length is set so that 1 << length is the number of available 326 | * palette entries 327 | * cmap is not used 328 | * RAMDAC[X] is programmed to (red, green, blue) 329 | * 330 | * Truecolor: 331 | * does not use DAC. Usually 3 are present. 332 | * var->{color}.offset contains start of bitfield 333 | * var->{color}.length contains length of bitfield 334 | * cmap is programmed to (red << red.offset) | (green << green.offset) | 335 | * (blue << blue.offset) | (transp << transp.offset) 336 | * RAMDAC does not exist 337 | */ 338 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) 339 | switch (info->fix.visual) { 340 | case FB_VISUAL_TRUECOLOR: 341 | case FB_VISUAL_PSEUDOCOLOR: 342 | red = CNVT_TOHW(red, info->var.red.length); 343 | green = CNVT_TOHW(green, info->var.green.length); 344 | blue = CNVT_TOHW(blue, info->var.blue.length); 345 | transp = CNVT_TOHW(transp, info->var.transp.length); 346 | break; 347 | case FB_VISUAL_DIRECTCOLOR: 348 | red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ 349 | green = CNVT_TOHW(green, 8); 350 | blue = CNVT_TOHW(blue, 8); 351 | /* hey, there is bug in transp handling... */ 352 | transp = CNVT_TOHW(transp, 8); 353 | break; 354 | } 355 | #undef CNVT_TOHW 356 | /* Truecolor has hardware independent palette */ 357 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 358 | u32 v; 359 | 360 | if (regno >= 16) 361 | return 1; 362 | 363 | v = (red << info->var.red.offset) | 364 | (green << info->var.green.offset) | 365 | (blue << info->var.blue.offset) | 366 | (transp << info->var.transp.offset); 367 | switch (info->var.bits_per_pixel) { 368 | case 8: 369 | break; 370 | case 16: 371 | ((u32 *) (info->pseudo_palette))[regno] = v; 372 | break; 373 | case 24: 374 | case 32: 375 | ((u32 *) (info->pseudo_palette))[regno] = v; 376 | break; 377 | } 378 | return 0; 379 | } 380 | return 0; 381 | } 382 | 383 | /* 384 | * Pan or Wrap the Display 385 | * 386 | * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 387 | */ 388 | 389 | static int vfb_pan_display(struct fb_var_screeninfo *var, 390 | struct fb_info *info) 391 | { 392 | if (var->vmode & FB_VMODE_YWRAP) { 393 | if (var->yoffset < 0 394 | || var->yoffset >= info->var.yres_virtual 395 | || var->xoffset) 396 | return -EINVAL; 397 | } else { 398 | if (var->xoffset + var->xres > info->var.xres_virtual || 399 | var->yoffset + var->yres > info->var.yres_virtual) 400 | return -EINVAL; 401 | } 402 | info->var.xoffset = var->xoffset; 403 | info->var.yoffset = var->yoffset; 404 | if (var->vmode & FB_VMODE_YWRAP) 405 | info->var.vmode |= FB_VMODE_YWRAP; 406 | else 407 | info->var.vmode &= ~FB_VMODE_YWRAP; 408 | return 0; 409 | } 410 | 411 | /* 412 | * Most drivers don't need their own mmap function 413 | */ 414 | 415 | static int vfb_mmap(struct fb_info *info, 416 | struct vm_area_struct *vma) 417 | { 418 | unsigned long start = vma->vm_start; 419 | unsigned long size = vma->vm_end - vma->vm_start; 420 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 421 | unsigned long page, pos; 422 | 423 | if (offset + size > info->fix.smem_len) { 424 | return -EINVAL; 425 | } 426 | 427 | pos = (unsigned long)info->fix.smem_start + offset; 428 | 429 | while (size > 0) { 430 | page = vmalloc_to_pfn((void *)pos); 431 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { 432 | return -EAGAIN; 433 | } 434 | start += PAGE_SIZE; 435 | pos += PAGE_SIZE; 436 | if (size > PAGE_SIZE) 437 | size -= PAGE_SIZE; 438 | else 439 | size = 0; 440 | } 441 | 442 | vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ 443 | return 0; 444 | 445 | } 446 | 447 | #ifndef MODULE 448 | /* 449 | * The virtual framebuffer driver is only enabled if explicitly 450 | * requested by passing 'video=vfb:' (or any actual options). 451 | */ 452 | static int __init vfb_setup(char *options) 453 | { 454 | char *this_opt; 455 | 456 | vfb_enable = 0; 457 | 458 | if (!options) 459 | return 1; 460 | 461 | vfb_enable = 1; 462 | 463 | if (!*options) 464 | return 1; 465 | 466 | while ((this_opt = strsep(&options, ",")) != NULL) { 467 | if (!*this_opt) 468 | continue; 469 | /* Test disable for backwards compatibility */ 470 | if (!strcmp(this_opt, "disable")) 471 | vfb_enable = 0; 472 | } 473 | return 1; 474 | } 475 | #endif /* MODULE */ 476 | 477 | /* 478 | * Initialisation 479 | */ 480 | 481 | static int __devinit vfb_probe(struct platform_device *dev) 482 | { 483 | struct fb_info *info; 484 | int retval = -ENOMEM; 485 | 486 | /* 487 | * For real video cards we use ioremap. 488 | */ 489 | if (!(videomemory = rvmalloc(videomemorysize))) 490 | return retval; 491 | 492 | /* 493 | * VFB must clear memory to prevent kernel info 494 | * leakage into userspace 495 | * VGA-based drivers MUST NOT clear memory if 496 | * they want to be able to take over vgacon 497 | */ 498 | memset(videomemory, 0, videomemorysize); 499 | 500 | info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); 501 | if (!info) 502 | goto err; 503 | 504 | info->screen_base = (char __iomem *)videomemory; 505 | info->fbops = &vfb_ops; 506 | 507 | retval = fb_find_mode(&info->var, info, NULL, 508 | NULL, 0, NULL, 8); 509 | 510 | if (!retval || (retval == 4)) 511 | info->var = vfb_default; 512 | vfb_fix.smem_start = (unsigned long) videomemory; 513 | vfb_fix.smem_len = videomemorysize; 514 | info->fix = vfb_fix; 515 | info->pseudo_palette = info->par; 516 | info->par = NULL; 517 | info->flags = FBINFO_FLAG_DEFAULT; 518 | 519 | retval = fb_alloc_cmap(&info->cmap, 256, 0); 520 | if (retval < 0) 521 | goto err1; 522 | 523 | retval = register_framebuffer(info); 524 | if (retval < 0) 525 | goto err2; 526 | platform_set_drvdata(dev, info); 527 | 528 | printk(KERN_INFO 529 | "fb%d: Virtual frame buffer device, using %ldK of video memory\n", 530 | info->node, videomemorysize >> 10); 531 | return 0; 532 | err2: 533 | fb_dealloc_cmap(&info->cmap); 534 | err1: 535 | framebuffer_release(info); 536 | err: 537 | rvfree(videomemory, videomemorysize); 538 | return retval; 539 | } 540 | 541 | static int vfb_remove(struct platform_device *dev) 542 | { 543 | struct fb_info *info = platform_get_drvdata(dev); 544 | 545 | if (info) { 546 | unregister_framebuffer(info); 547 | rvfree(videomemory, videomemorysize); 548 | fb_dealloc_cmap(&info->cmap); 549 | framebuffer_release(info); 550 | } 551 | return 0; 552 | } 553 | 554 | static struct platform_driver vfb_driver = { 555 | .probe = vfb_probe, 556 | .remove = vfb_remove, 557 | .driver = { 558 | .name = "vfb", 559 | }, 560 | }; 561 | 562 | static struct platform_device *vfb_device; 563 | 564 | static int __init vfb_init(void) 565 | { 566 | int ret = 0; 567 | 568 | #ifndef MODULE 569 | char *option = NULL; 570 | 571 | if (fb_get_options("vfb", &option)) 572 | return -ENODEV; 573 | vfb_setup(option); 574 | #endif 575 | 576 | if (!vfb_enable) 577 | return -ENXIO; 578 | 579 | ret = platform_driver_register(&vfb_driver); 580 | 581 | if (!ret) { 582 | vfb_device = platform_device_alloc("vfb", 0); 583 | 584 | if (vfb_device) 585 | ret = platform_device_add(vfb_device); 586 | else 587 | ret = -ENOMEM; 588 | 589 | if (ret) { 590 | platform_device_put(vfb_device); 591 | platform_driver_unregister(&vfb_driver); 592 | } 593 | } 594 | 595 | return ret; 596 | } 597 | 598 | module_init(vfb_init); 599 | 600 | #ifdef MODULE 601 | static void __exit vfb_exit(void) 602 | { 603 | platform_device_unregister(vfb_device); 604 | platform_driver_unregister(&vfb_driver); 605 | } 606 | 607 | module_exit(vfb_exit); 608 | 609 | MODULE_LICENSE("GPL"); 610 | #endif /* MODULE */ 611 | --------------------------------------------------------------------------------