├── 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 |
--------------------------------------------------------------------------------