diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-02-26 14:53:33 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-02-26 14:53:33 +1100 |
commit | 80e3e14e8c6643132713955e5f11fac88ad24c72 (patch) | |
tree | 06cdb65a75139cee5b8f163efa7dfafba7fac407 /drivers | |
parent | 4a622980745b96ce4f94bfd603ca0f4aad35cc28 (diff) | |
parent | 336f872c6f01e6967794442903d5a0cda05d8428 (diff) |
Merge remote branch 'kgdb/kgdb-next'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/kdb_keyboard.c | 204 | ||||
-rw-r--r-- | drivers/char/kdb_keyboard.h | 143 | ||||
-rw-r--r-- | drivers/char/keyboard.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 79 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 97 | ||||
-rw-r--r-- | drivers/input/input.c | 15 | ||||
-rw-r--r-- | drivers/misc/kgdbts.c | 6 | ||||
-rw-r--r-- | drivers/serial/8250.c | 4 | ||||
-rw-r--r-- | drivers/serial/amba-pl011.c | 6 | ||||
-rw-r--r-- | drivers/serial/kgdboc.c | 134 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 6 | ||||
-rw-r--r-- | drivers/serial/sunzilog.c | 50 | ||||
-rw-r--r-- | drivers/usb/early/ehci-dbgp.c | 184 | ||||
-rw-r--r-- | drivers/video/console/fbcon.c | 7 |
15 files changed, 900 insertions, 65 deletions
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index f957edf7e45d..dbc579e13b2b 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o obj-y += misc.o obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o +obj-$(CONFIG_KDB_KEYBOARD) += kdb_keyboard.o obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o diff --git a/drivers/char/kdb_keyboard.c b/drivers/char/kdb_keyboard.c new file mode 100644 index 000000000000..95aa10286e40 --- /dev/null +++ b/drivers/char/kdb_keyboard.c @@ -0,0 +1,204 @@ +/* + * Kernel Debugger Architecture Dependent Console I/O handler + * + * This file is subject to the terms and conditions of the GNU General Public + * License. + * + * Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved. + */ + +#include <linux/kdb.h> +#include <linux/keyboard.h> +#include <linux/ctype.h> +#include <linux/module.h> +#include <linux/io.h> +#include "kdb_keyboard.h" + + +static int kbd_exists; + +/* + * Check if the keyboard controller has a keypress for us. + * Some parts (Enter Release, LED change) are still blocking polled here, + * but hopefully they are all short. + */ +int kdb_get_kbd_char(void) +{ + int scancode, scanstatus; + static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ + static int shift_key; /* Shift next keypress */ + static int ctrl_key; + u_short keychar; + + if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) || + (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) { + kbd_exists = 0; + return -1; + } + kbd_exists = 1; + + if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + return -1; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + /* + * Ignore mouse events. + */ + if (scanstatus & KBD_STAT_MOUSE_OBF) + return -1; + + /* + * Ignore release, trigger on make + * (except for shift keys, where we want to + * keep the shift state so long as the key is + * held down). + */ + + if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { + /* + * Next key may use shift table + */ + if ((scancode & 0x80) == 0) + shift_key = 1; + else + shift_key = 0; + return -1; + } + + if ((scancode&0x7f) == 0x1d) { + /* + * Left ctrl key + */ + if ((scancode & 0x80) == 0) + ctrl_key = 1; + else + ctrl_key = 0; + return -1; + } + + if ((scancode & 0x80) != 0) + return -1; + + scancode &= 0x7f; + + /* + * Translate scancode + */ + + if (scancode == 0x3a) { + /* + * Toggle caps lock + */ + shift_lock ^= 1; + +#ifdef KDB_BLINK_LED + kdb_toggleled(0x4); +#endif + return -1; + } + + if (scancode == 0x0e) { + /* + * Backspace + */ + return 8; + } + + /* Special Key */ + switch (scancode) { + case 0xF: /* Tab */ + return 9; + case 0x53: /* Del */ + return 4; + case 0x47: /* Home */ + return 1; + case 0x4F: /* End */ + return 5; + case 0x4B: /* Left */ + return 2; + case 0x48: /* Up */ + return 16; + case 0x50: /* Down */ + return 14; + case 0x4D: /* Right */ + return 6; + } + + if (scancode == 0xe0) + return -1; + + /* + * For Japanese 86/106 keyboards + * See comment in drivers/char/pc_keyb.c. + * - Masahiro Adegawa + */ + if (scancode == 0x73) + scancode = 0x59; + else if (scancode == 0x7d) + scancode = 0x7c; + + if (!shift_lock && !shift_key && !ctrl_key) { + keychar = plain_map[scancode]; + } else if ((shift_lock || shift_key) && key_maps[1]) { + keychar = key_maps[1][scancode]; + } else if (ctrl_key && key_maps[4]) { + keychar = key_maps[4][scancode]; + } else { + keychar = 0x0020; + kdb_printf("Unknown state/scancode (%d)\n", scancode); + } + keychar &= 0x0fff; + if (keychar == '\t') + keychar = ' '; + switch (KTYP(keychar)) { + case KT_LETTER: + case KT_LATIN: + if (isprint(keychar)) + break; /* printable characters */ + /* drop through */ + case KT_SPEC: + if (keychar == K_ENTER) + break; + /* drop through */ + default: + return -1; /* ignore unprintables */ + } + + if ((scancode & 0x7f) == 0x1c) { + /* + * enter key. All done. Absorb the release scancode. + */ + while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + ; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + while (scanstatus & KBD_STAT_MOUSE_OBF) { + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + } + + if (scancode != 0x9c) { + /* + * Wasn't an enter-release, why not? + */ + kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", + scancode, scanstatus); + } + + return 13; + } + + return keychar & 0xff; +} +EXPORT_SYMBOL_GPL(kdb_get_kbd_char); diff --git a/drivers/char/kdb_keyboard.h b/drivers/char/kdb_keyboard.h new file mode 100644 index 000000000000..5541668cce0a --- /dev/null +++ b/drivers/char/kdb_keyboard.h @@ -0,0 +1,143 @@ +/* + * include/linux/pc_keyb.h + * + * PC Keyboard And Keyboard Controller + * + * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> + */ + +/* + * Configuration Switches + */ + +#undef KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged + * FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse + * needs initialization. */ + +#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the + * keyboard */ +#define KBC_TIMEOUT 250 /* Timeout in ms for sending + * to keyboard controller */ +#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard + * command acknowledge */ + +/* + * Internal variables of the driver + */ + +extern unsigned char pckbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers on normal PCs. + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to + * the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command + * write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect + * the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define AUX_BUF_SIZE 2048 /* This might be better divisible by + three to make overruns stay in sync + but then the read function would need + a lock etc - ick */ + +struct aux_queue { + unsigned long head; + unsigned long tail; + wait_queue_head_t proc_list; + struct fasync_struct *fasync; + unsigned char buf[AUX_BUF_SIZE]; +}; + + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index ada25bb8941e..11491a3107cd 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1190,6 +1190,11 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if (keycode < BTN_MISC && printk_ratelimit()) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); + if (down) + set_bit(keycode, key_down); + else + clear_bit(keycode, key_down); + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { if (!sysrq_down) { @@ -1232,11 +1237,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) raw_mode = 1; } - if (down) - set_bit(keycode, key_down); - else - clear_bit(keycode, key_down); - if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { @@ -1412,6 +1412,22 @@ static const struct input_device_id kbd_ids[] = { MODULE_DEVICE_TABLE(input, kbd_ids); +#ifdef CONFIG_KDB_KEYBOARD +void kbd_clear_keys(void) +{ + int i, j, k; + + for (i = 0; i < ARRAY_SIZE(key_down); i++) { + k = i * BITS_PER_LONG; + for (j = 0; j < BITS_PER_LONG; j++, k++) { + if (test_bit(k, key_down)) { + kbd_keycode(k, 0, 0); + } + } + } +} +#endif + static struct input_handler kbd_handler = { .event = kbd_event, .match = kbd_match, @@ -1420,6 +1436,9 @@ static struct input_handler kbd_handler = { .start = kbd_start, .name = "kbd", .id_table = kbd_ids, +#ifdef CONFIG_KDB_KEYBOARD + .dbg_clear_keys = kbd_clear_keys, +#endif }; int __init kbd_init(void) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0f9e90552dc4..ea06bf31b7b4 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -29,6 +29,7 @@ */ #include <linux/sysrq.h> #include <linux/fb.h> +#include <linux/kgdb.h> #include "drmP.h" #include "drm_crtc.h" #include "drm_fb_helper.h" @@ -233,6 +234,80 @@ int drm_fb_helper_parse_command_line(struct drm_device *dev) return 0; } +#define to_fb_helper(ops) (container_of((ops), struct drm_fb_helper, kdb_ops)) + +static int drm_fb_kdb_enter(struct dbg_kms_ops *ops) +{ + struct drm_fb_helper *helper = to_fb_helper(ops); + struct drm_crtc_helper_funcs *funcs; + int i; + + if (list_empty(&kernel_fb_helper_list)) + return false; + + list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { + for (i = 0; i < helper->crtc_count; i++) { + struct drm_mode_set *mode_set = + &helper->crtc_info[i].mode_set; + + if (!mode_set->crtc->enabled) + continue; + + funcs = mode_set->crtc->helper_private; + funcs->mode_set_base_atomic(mode_set->crtc, + mode_set->fb, + mode_set->x, + mode_set->y); + + } + } + + return 0; +} + +/* Find the real fb for a given fb helper CRTC */ +static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_crtc *c; + + list_for_each_entry(c, &dev->mode_config.crtc_list, head) { + if (crtc->base.id == c->base.id) + return c->fb; + } + + return NULL; +} + +static int drm_fb_kdb_exit(struct dbg_kms_ops *ops) +{ + struct drm_fb_helper *helper = to_fb_helper(ops); + struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *funcs; + struct drm_framebuffer *fb; + int i; + + for (i = 0; i < helper->crtc_count; i++) { + struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; + crtc = mode_set->crtc; + funcs = crtc->helper_private; + fb = drm_mode_config_fb(crtc); + + if (!crtc->enabled) + continue; + + if (!fb) { + DRM_ERROR("no fb to restore??\n"); + continue; + } + + funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, + crtc->y); + } + + return 0; +} + bool drm_fb_helper_force_kernel_mode(void) { int i = 0; @@ -923,6 +998,9 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, /* Switch back to kernel console on panic */ /* multi card linked list maybe */ if (list_empty(&kernel_fb_helper_list)) { + fb_helper->kdb_ops.activate_console = drm_fb_kdb_enter; + fb_helper->kdb_ops.restore_console = drm_fb_kdb_exit; + dbg_kms_ops_register(&fb_helper->kdb_ops); printk(KERN_INFO "registered panic notifier\n"); atomic_notifier_chain_register(&panic_notifier_list, &paniced); @@ -937,6 +1015,7 @@ void drm_fb_helper_free(struct drm_fb_helper *helper) { list_del(&helper->kernel_fb_list); if (list_empty(&kernel_fb_helper_list)) { + dbg_kms_ops_unregister(&helper->kdb_ops); printk(KERN_INFO "unregistered panic notifier\n"); atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b27202d23ebc..21e9597488ba 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1210,6 +1210,10 @@ static void intel_update_fbc(struct drm_crtc *crtc, goto out_disable; } + /* If the kernel debugger is active, always disable compression */ + if (in_dbg_master()) + goto out_disable; + if (dev_priv->display.fbc_enabled(crtc)) { /* We can re-enable it in this case, but need to update pitch */ if (fb->pitch > dev_priv->cfb_pitch) @@ -1278,6 +1282,98 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) return 0; } +/* Assume fb object is pinned & idle & fenced and just update base pointers */ +static int +intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *obj; + int plane = intel_crtc->plane; + unsigned long Start, Offset; + int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR); + int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF); + int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; + int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + u32 dspcntr; + + switch (plane) { + case 0: + case 1: + break; + default: + DRM_ERROR("Can't update plane %d in SAREA\n", plane); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + obj_priv = obj->driver_private; + + dspcntr = I915_READ(dspcntr_reg); + /* Mask out pixel format bits in case we change it */ + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + switch (fb->bits_per_pixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (fb->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 24: + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + DRM_ERROR("Unknown color depth\n"); + return -EINVAL; + } + if (IS_I965G(dev)) { + if (obj_priv->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else + dspcntr &= ~DISPPLANE_TILED; + } + + if (IS_IRONLAKE(dev)) + /* must disable */ + dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + + I915_WRITE(dspcntr_reg, dspcntr); + + Start = obj_priv->gtt_offset; + Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); + + DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); + I915_WRITE(dspstride, fb->pitch); + if (IS_I965G(dev)) { + I915_WRITE(dspbase, Offset); + I915_READ(dspbase); + I915_WRITE(dspsurf, Start); + I915_READ(dspsurf); + I915_WRITE(dsptileoff, (y << 16) | x); + } else { + I915_WRITE(dspbase, Start + Offset); + I915_READ(dspbase); + } + + if ((IS_I965G(dev) || plane == 0)) + intel_update_fbc(crtc, &crtc->mode); + + intel_wait_for_vblank(dev); + intel_increase_pllclock(crtc, true); + + return 0; +} + static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) @@ -4257,6 +4353,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, + .mode_set_base_atomic = intel_pipe_set_base_atomic, .prepare = intel_crtc_prepare, .commit = intel_crtc_commit, .load_lut = intel_crtc_load_lut, diff --git a/drivers/input/input.c b/drivers/input/input.c index 41168d5f8c17..a031c5918771 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1737,6 +1737,21 @@ int input_register_handler(struct input_handler *handler) } EXPORT_SYMBOL(input_register_handler); +#ifdef CONFIG_KDB_KEYBOARD +/* input_db_clear_keys - Clear any keyboards if they have a call back, + * after returning from the kernel debugger + */ +void input_dbg_clear_keys(void) +{ + struct input_handler *handler; + + list_for_each_entry(handler, &input_handler_list, node) + if (handler->dbg_clear_keys) + handler->dbg_clear_keys(); +} +EXPORT_SYMBOL_GPL(input_dbg_clear_keys); +#endif + /** * input_unregister_handler - unregisters an input handler * @handler: handler to be unregistered diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index fcb6ec1af173..72450237a0f4 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -295,6 +295,10 @@ static int check_and_rewind_pc(char *put_str, char *arg) /* On x86 a breakpoint stop requires it to be decremented */ if (addr + 1 == kgdbts_regs.ip) offset = -1; +#elif defined(CONFIG_SUPERH) + /* On SUPERH a breakpoint stop requires it to be decremented */ + if (addr + 2 == kgdbts_regs.pc) + offset = -2; #endif if (strcmp(arg, "silent") && instruction_pointer(&kgdbts_regs) + offset != addr) { @@ -305,6 +309,8 @@ static int check_and_rewind_pc(char *put_str, char *arg) #ifdef CONFIG_X86 /* On x86 adjust the instruction pointer if needed */ kgdbts_regs.ip += offset; +#elif defined(CONFIG_SUPERH) + kgdbts_regs.pc += offset; #endif return 0; } diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a81ff7bc5fa1..bfcde1aaacec 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1890,8 +1890,8 @@ static int serial8250_get_poll_char(struct uart_port *port) struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned char lsr = serial_inp(up, UART_LSR); - while (!(lsr & UART_LSR_DR)) - lsr = serial_inp(up, UART_LSR); + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; return serial_inp(up, UART_RX); } diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index ce6c35333ff7..aad86ecdd1c4 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -341,9 +341,9 @@ static int pl010_get_poll_char(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status; - do { - status = readw(uap->port.membase + UART01x_FR); - } while (status & UART01x_FR_RXFE); + status = readw(uap->port.membase + UART01x_FR); + if (status & UART01x_FR_RXFE) + return NO_POLL_CHAR; return readw(uap->port.membase + UART01x_DR); } diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index eadc1ab6bbce..91ca95af2e74 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -14,7 +14,10 @@ #include <linux/kernel.h> #include <linux/ctype.h> #include <linux/kgdb.h> +#include <linux/kdb.h> #include <linux/tty.h> +#include <linux/console.h> +#include <linux/input.h> #define MAX_CONFIG_LEN 40 @@ -29,9 +32,55 @@ static struct kparam_string kps = { .maxlen = MAX_CONFIG_LEN, }; +static int kgdboc_use_kms; /* 1 if we use kernel mode switching */ static struct tty_driver *kgdb_tty_driver; static int kgdb_tty_line; +#ifdef CONFIG_KDB_KEYBOARD +static int kgdboc_use_kbd; /* 1 if we use a keyboard */ + +static int kgdboc_register_kbd(char **cptr) +{ + kgdboc_use_kbd = 0; + if (strncmp(*cptr, "kbd", 3) == 0) { + if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { + kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; + kdb_poll_idx++; + kgdboc_use_kbd = 1; + if (cptr[0][3] == ',') + *cptr += 4; + else + return 1; + } + } + return 0; +} + +static void kgdboc_unregister_kbd(void) +{ + int i; + + for (i = 0; i < kdb_poll_idx; i++) { + if (kdb_poll_funcs[i] == kdb_get_kbd_char) { + kdb_poll_idx--; + kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx]; + kdb_poll_funcs[kdb_poll_idx] = NULL; + i--; + } + } +} + +static inline void kgdboc_clear_kbd(void) +{ + if (kgdboc_use_kbd) + input_dbg_clear_keys(); /* Release all pressed keys */ +} +#else /* ! CONFIG_KDB_KEYBOARD */ +#define kgdboc_register_kbd(x) 0 +#define kgdboc_unregister_kbd() +#define kgdboc_clear_kbd() +#endif /* ! CONFIG_KDB_KEYBOARD */ + static int kgdboc_option_setup(char *opt) { if (strlen(opt) > MAX_CONFIG_LEN) { @@ -45,25 +94,57 @@ static int kgdboc_option_setup(char *opt) __setup("kgdboc=", kgdboc_option_setup); +static void cleanup_kgdboc(void) +{ + kgdboc_unregister_kbd(); + if (configured == 1) + kgdb_unregister_io_module(&kgdboc_io_ops); +} + static int configure_kgdboc(void) { struct tty_driver *p; int tty_line = 0; int err; + char *cptr = config; + struct console *cons; err = kgdboc_option_setup(config); if (err || !strlen(config) || isspace(config[0])) goto noconfig; err = -ENODEV; + kgdboc_io_ops.is_console = 0; + kgdb_tty_driver = NULL; - p = tty_find_polling_driver(config, &tty_line); + kgdboc_use_kms = 0; + if (strncmp(cptr, "kms,", 4) == 0) { + cptr += 4; + kgdboc_use_kms = 1; + } + + if (kgdboc_register_kbd(&cptr)) + goto do_register; + + p = tty_find_polling_driver(cptr, &tty_line); if (!p) goto noconfig; + cons = console_drivers; + while (cons) { + int idx; + if (cons->device && cons->device(cons, &idx) == p && + idx == tty_line) { + kgdboc_io_ops.is_console = 1; + break; + } + cons = cons->next; + } + kgdb_tty_driver = p; kgdb_tty_line = tty_line; +do_register: err = kgdb_register_io_module(&kgdboc_io_ops); if (err) goto noconfig; @@ -75,6 +156,7 @@ static int configure_kgdboc(void) noconfig: config[0] = 0; configured = 0; + cleanup_kgdboc(); return err; } @@ -88,20 +170,18 @@ static int __init init_kgdboc(void) return configure_kgdboc(); } -static void cleanup_kgdboc(void) -{ - if (configured == 1) - kgdb_unregister_io_module(&kgdboc_io_ops); -} - static int kgdboc_get_char(void) { + if (!kgdb_tty_driver) + return -1; return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, kgdb_tty_line); } static void kgdboc_put_char(u8 chr) { + if (!kgdb_tty_driver) + return; kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); } @@ -140,8 +220,19 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) return configure_kgdboc(); } +static int dbg_restore_graphics; + static void kgdboc_pre_exp_handler(void) { + if (!dbg_restore_graphics && kgdboc_use_kms && dbg_kms_ops && + dbg_kms_ops->activate_console) { + if (dbg_kms_ops->activate_console(dbg_kms_ops)) { + printk(KERN_ERR "kgdboc: kernel mode switch error\n"); + } else { + dbg_restore_graphics = 1; + dbg_pre_vt_hook(); + } + } /* Increment the module count when the debugger is active */ if (!kgdb_connected) try_module_get(THIS_MODULE); @@ -152,6 +243,16 @@ static void kgdboc_post_exp_handler(void) /* decrement the module count when the debugger detaches */ if (!kgdb_connected) module_put(THIS_MODULE); + if (kgdboc_use_kms && dbg_kms_ops && + dbg_kms_ops->restore_console) { + if (dbg_restore_graphics) { + if (dbg_kms_ops->restore_console(dbg_kms_ops)) + printk(KERN_ERR "kgdboc: graphics restore failed\n"); + dbg_restore_graphics = 0; + dbg_post_vt_hook(); + } + } + kgdboc_clear_kbd(); } static struct kgdb_io kgdboc_io_ops = { @@ -162,6 +263,25 @@ static struct kgdb_io kgdboc_io_ops = { .post_exception = kgdboc_post_exp_handler, }; +#ifdef CONFIG_KGDB_SERIAL_CONSOLE +/* This is only available if kgdboc is a built in for early debugging */ +int __init kgdboc_early_init(char *opt) +{ + /* save the first character of the config string because the + * init routine can destroy it. + */ + char save_ch; + + kgdboc_option_setup(opt); + save_ch = config[0]; + init_kgdboc(); + config[0] = save_ch; + return 0; +} + +early_param("ekgdboc", kgdboc_early_init); +#endif /* CONFIG_KGDB_SERIAL_CONSOLE */ + module_init(init_kgdboc); module_exit(cleanup_kgdboc); module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 42f3333c4ad0..2cf3b6df4471 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -126,7 +126,11 @@ static int sci_poll_get_char(struct uart_port *port) handle_error(port); continue; } - } while (!(status & SCxSR_RDxF(port))); + break; + } while (1); + + if (!(status & SCxSR_RDxF(port))) + return NO_POLL_CHAR; c = sci_in(port, SCxRDR); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 2c7a66af4f52..978b3cee02d7 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -102,6 +102,8 @@ struct uart_sunzilog_port { #endif }; +static void sunzilog_putchar(struct uart_port *port, int ch); + #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) #define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) @@ -996,6 +998,50 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se return -EINVAL; } +#ifdef CONFIG_CONSOLE_POLL +static int sunzilog_get_poll_char(struct uart_port *port) +{ + unsigned char ch, r1; + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel + = ZILOG_CHANNEL_FROM_PORT(&up->port); + + + r1 = read_zsreg(channel, R1); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + + ch = readb(&channel->control); + ZSDELAY(); + + /* This funny hack depends upon BRK_ABRT not interfering + * with the other bits we care about in R1. + */ + if (ch & BRK_ABRT) + r1 |= BRK_ABRT; + + if (!(ch & Rx_CH_AV)) + return NO_POLL_CHAR; + + ch = readb(&channel->data); + ZSDELAY(); + + ch &= up->parity_mask; + return ch; +} + +static void sunzilog_put_poll_char(struct uart_port *port, + unsigned char ch) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port; + + sunzilog_putchar(&up->port, ch); +} +#endif /* CONFIG_CONSOLE_POLL */ + static struct uart_ops sunzilog_pops = { .tx_empty = sunzilog_tx_empty, .set_mctrl = sunzilog_set_mctrl, @@ -1013,6 +1059,10 @@ static struct uart_ops sunzilog_pops = { .request_port = sunzilog_request_port, .config_port = sunzilog_config_port, .verify_port = sunzilog_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sunzilog_get_poll_char, + .poll_put_char = sunzilog_put_poll_char, +#endif }; static int uart_chip_count; diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 2958a1271b20..94ecdbc758ce 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -19,6 +19,9 @@ #include <linux/usb/ch9.h> #include <linux/usb/ehci_def.h> #include <linux/delay.h> +#include <linux/serial_core.h> +#include <linux/kgdb.h> +#include <linux/kthread.h> #include <asm/io.h> #include <asm/pci-direct.h> #include <asm/fixmap.h> @@ -55,6 +58,7 @@ static struct ehci_regs __iomem *ehci_regs; static struct ehci_dbg_port __iomem *ehci_debug; static int dbgp_not_safe; /* Cannot use debug device during ehci reset */ static unsigned int dbgp_endpoint_out; +static unsigned int dbgp_endpoint_in; struct ehci_dev { u32 bus; @@ -66,8 +70,6 @@ static struct ehci_dev ehci_dev; #define USB_DEBUG_DEVNUM 127 -#define DBGP_DATA_TOGGLE 0x8800 - #ifdef DBGP_DEBUG #define dbgp_printk printk static void dbgp_ehci_status(char *str) @@ -88,16 +90,18 @@ static inline void dbgp_ehci_status(char *str) { } static inline void dbgp_printk(const char *fmt, ...) { } #endif -static inline u32 dbgp_pid_update(u32 x, u32 tok) -{ - return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff); -} - static inline u32 dbgp_len_update(u32 x, u32 len) { return (x & ~0x0f) | (len & 0x0f); } +#ifdef CONFIG_KGDB +static struct kgdb_io kgdbdbgp_io_ops; +#define dbgp_kgdb_mode (dbg_io_ops == &kgdbdbgp_io_ops) +#else +#define dbgp_kgdb_mode (0) +#endif + /* * USB Packet IDs (PIDs) */ @@ -136,6 +140,19 @@ static inline u32 dbgp_len_update(u32 x, u32 len) #define DBGP_MAX_PACKET 8 #define DBGP_TIMEOUT (250 * 1000) +#define DBGP_LOOPS 1000 + +static inline u32 dbgp_pid_write_update(u32 x, u32 tok) +{ + static int data0 = USB_PID_DATA1; + data0 ^= USB_PID_DATA_TOGGLE; + return (x & 0xffff0000) | (data0 << 8) | (tok & 0xff); +} + +static inline u32 dbgp_pid_read_update(u32 x, u32 tok) +{ + return (x & 0xffff0000) | (USB_PID_DATA0 << 8) | (tok & 0xff); +} static int dbgp_wait_until_complete(void) { @@ -176,11 +193,10 @@ static void dbgp_breath(void) /* Sleep to give the debug port a chance to breathe */ } -static int dbgp_wait_until_done(unsigned ctrl) +static int dbgp_wait_until_done(unsigned ctrl, int loop) { u32 pids, lpid; int ret; - int loop = 3; retry: writel(ctrl | DBGP_GO, &ehci_debug->control); @@ -197,6 +213,8 @@ retry: */ if (ret == -DBGP_TIMEOUT && !dbgp_not_safe) dbgp_not_safe = 1; + if (ret == -DBGP_ERR_BAD && --loop > 0) + goto retry; return ret; } @@ -245,12 +263,20 @@ static inline void dbgp_get_data(void *buf, int size) bytes[i] = (hi >> (8*(i - 4))) & 0xff; } -static int dbgp_out(u32 addr, const char *bytes, int size) +static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, + const char *bytes, int size) { + int ret; + u32 addr; u32 pids, ctrl; + if (size > DBGP_MAX_PACKET) + return -1; + + addr = DBGP_EPADDR(devnum, endpoint); + pids = readl(&ehci_debug->pids); - pids = dbgp_pid_update(pids, USB_PID_OUT); + pids = dbgp_pid_write_update(pids, USB_PID_OUT); ctrl = readl(&ehci_debug->control); ctrl = dbgp_len_update(ctrl, size); @@ -260,40 +286,13 @@ static int dbgp_out(u32 addr, const char *bytes, int size) dbgp_set_data(bytes, size); writel(addr, &ehci_debug->address); writel(pids, &ehci_debug->pids); - return dbgp_wait_until_done(ctrl); -} - -static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, - const char *bytes, int size) -{ - int ret; - int loops = 5; - u32 addr; - if (size > DBGP_MAX_PACKET) - return -1; - - addr = DBGP_EPADDR(devnum, endpoint); -try_again: - if (loops--) { - ret = dbgp_out(addr, bytes, size); - if (ret == -DBGP_ERR_BAD) { - int try_loops = 3; - do { - /* Emit a dummy packet to re-sync communication - * with the debug device */ - if (dbgp_out(addr, "12345678", 8) >= 0) { - udelay(2); - goto try_again; - } - } while (try_loops--); - } - } + ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS); return ret; } static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, - int size) + int size, int loops) { u32 pids, addr, ctrl; int ret; @@ -304,7 +303,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, addr = DBGP_EPADDR(devnum, endpoint); pids = readl(&ehci_debug->pids); - pids = dbgp_pid_update(pids, USB_PID_IN); + pids = dbgp_pid_read_update(pids, USB_PID_IN); ctrl = readl(&ehci_debug->control); ctrl = dbgp_len_update(ctrl, size); @@ -313,7 +312,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, writel(addr, &ehci_debug->address); writel(pids, &ehci_debug->pids); - ret = dbgp_wait_until_done(ctrl); + ret = dbgp_wait_until_done(ctrl, loops); if (ret < 0) return ret; @@ -354,15 +353,14 @@ static int dbgp_control_msg(unsigned devnum, int requesttype, dbgp_set_data(&req, sizeof(req)); writel(addr, &ehci_debug->address); writel(pids, &ehci_debug->pids); - ret = dbgp_wait_until_done(ctrl); + ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS); if (ret < 0) return ret; /* Read the result */ - return dbgp_bulk_read(devnum, 0, data, size); + return dbgp_bulk_read(devnum, 0, data, size, DBGP_LOOPS); } - /* Find a PCI capability */ static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap) { @@ -571,6 +569,7 @@ try_again: goto err; } dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; + dbgp_endpoint_in = dbgp_desc.bDebugInEndpoint; /* Move the device to 127 if it isn't already there */ if (devnum != USB_DEBUG_DEVNUM) { @@ -980,8 +979,9 @@ int dbgp_reset_prep(void) if (!ehci_debug) return 0; - if (early_dbgp_console.index != -1 && - !(early_dbgp_console.flags & CON_BOOT)) + if ((early_dbgp_console.index != -1 && + !(early_dbgp_console.flags & CON_BOOT)) || + dbgp_kgdb_mode) return 1; /* This means the console is not initialized, or should get * shutdown so as to allow for reuse of the usb device, which @@ -994,3 +994,93 @@ int dbgp_reset_prep(void) return 0; } EXPORT_SYMBOL_GPL(dbgp_reset_prep); + +#ifdef CONFIG_KGDB + +static char kgdbdbgp_buf[DBGP_MAX_PACKET]; +static int kgdbdbgp_buf_sz; +static int kgdbdbgp_buf_idx; +static int kgdbdbgp_loop_cnt = DBGP_LOOPS; + +static int kgdbdbgp_read_char(void) +{ + int ret; + + if (kgdbdbgp_buf_idx < kgdbdbgp_buf_sz) { + char ch = kgdbdbgp_buf[kgdbdbgp_buf_idx++]; + return ch; + } + + ret = dbgp_bulk_read(USB_DEBUG_DEVNUM, dbgp_endpoint_in, + &kgdbdbgp_buf, DBGP_MAX_PACKET, + kgdbdbgp_loop_cnt); + if (ret <= 0) + return NO_POLL_CHAR; + kgdbdbgp_buf_sz = ret; + kgdbdbgp_buf_idx = 1; + return kgdbdbgp_buf[0]; +} + +static void kgdbdbgp_write_char(u8 chr) +{ + early_dbgp_write(NULL, &chr, 1); +} + +static struct kgdb_io kgdbdbgp_io_ops = { + .name = "kgdbdbgp", + .read_char = kgdbdbgp_read_char, + .write_char = kgdbdbgp_write_char, +}; + +static int kgdbdbgp_wait_time; + +static int __init kgdbdbgp_parse_config(char *str) +{ + char *ptr; + + if (!ehci_debug) { + if (early_dbgp_init(str)) + return -1; + } + ptr = strchr(str, ','); + if (ptr) { + ptr++; + kgdbdbgp_wait_time = simple_strtoul(ptr, &ptr, 10); + } + kgdb_register_io_module(&kgdbdbgp_io_ops); + kgdbdbgp_io_ops.is_console = early_dbgp_console.index != -1; + + return 0; +} +early_param("kgdbdbgp", kgdbdbgp_parse_config); + +static int kgdbdbgp_reader_thread(void *ptr) +{ + int ret; + + while (readl(&ehci_debug->control) & DBGP_ENABLED) { + kgdbdbgp_loop_cnt = 1; + ret = kgdbdbgp_read_char(); + kgdbdbgp_loop_cnt = DBGP_LOOPS; + if (ret != NO_POLL_CHAR) { + if (ret == 0x3 || ret == '$') { + if (ret == '$') + kgdbdbgp_buf_idx--; + kgdb_breakpoint(); + } + continue; + } + schedule_timeout_interruptible(kgdbdbgp_wait_time * HZ); + } + return 0; +} + +static int __init kgdbdbgp_start_thread(void) +{ + if (dbgp_kgdb_mode && kgdbdbgp_wait_time) + kthread_run(kgdbdbgp_reader_thread, NULL, "%s", "dbgp"); + + return 0; +} +module_init(kgdbdbgp_start_thread); +#endif /* CONFIG_KGDB */ diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 3681c6a88212..6f2ed5a15e0c 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -75,6 +75,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/crc32.h> /* For counting font checksums */ +#include <linux/kgdb.h> #include <asm/fb.h> #include <asm/irq.h> #include <asm/system.h> @@ -2318,6 +2319,12 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) } } + if (in_dbg_master()) { + if (info->fbops->fb_blank) + info->fbops->fb_blank(blank, info); + return 0; + } + if (!fbcon_is_inactive(vc, info)) { if (ops->blank_state != blank) { ops->blank_state = blank; |