diff options
-rw-r--r-- | linux-core/drmP.h | 4 | ||||
-rw-r--r-- | linux-core/drm_crtc.c | 1 | ||||
-rw-r--r-- | linux-core/drm_crtc.h | 9 | ||||
-rw-r--r-- | linux-core/drm_crtc_helper.c | 123 | ||||
-rw-r--r-- | linux-core/drm_crtc_helper.h | 3 | ||||
-rw-r--r-- | linux-core/i915_drv.c | 8 | ||||
-rw-r--r-- | linux-core/intel_display.c | 21 | ||||
-rw-r--r-- | linux-core/intel_drv.h | 8 | ||||
-rw-r--r-- | linux-core/intel_fb.c | 692 | ||||
-rw-r--r-- | shared-core/i915_drv.h | 2 | ||||
-rw-r--r-- | shared-core/i915_irq.c | 135 |
11 files changed, 527 insertions, 479 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6e627cd9..5b2d7829 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -742,10 +742,6 @@ struct drm_driver { void (*set_version) (struct drm_device *dev, struct drm_set_version *sv); - /* FB routines, if present */ - int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); - int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); - /* Master routines */ int (*master_create)(struct drm_device *dev, struct drm_master *master); void (*master_destroy)(struct drm_device *dev, struct drm_master *master); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 7a049da8..d49834b9 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -562,6 +562,7 @@ void drm_mode_config_init(struct drm_device *dev) { mutex_init(&dev->mode_config.mutex); INIT_LIST_HEAD(&dev->mode_config.fb_list); + INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.connector_list); INIT_LIST_HEAD(&dev->mode_config.encoder_list); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index f3953692..043b4a57 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -498,8 +498,9 @@ struct drm_connector { * * This is used to set modes. */ -struct drm_mode_set -{ +struct drm_mode_set { + struct list_head head; + struct drm_framebuffer *fb; struct drm_crtc *crtc; struct drm_display_mode *mode; @@ -523,6 +524,7 @@ struct drm_mode_set struct drm_mode_config_funcs { bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); + void (*fb_changed)(struct drm_device *dev); }; struct drm_mode_group { @@ -554,6 +556,9 @@ struct drm_mode_config { struct list_head property_list; + /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */ + struct list_head fb_kernel_list; + /* currently in use generation id */ int current_generation; diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 4083d6b7..777820d7 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -67,6 +67,7 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ui struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; int ret; + DRM_DEBUG("%s\n", drm_get_connector_name(connector)); /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &connector->modes, head) mode->status = MODE_UNVERIFIED; @@ -186,8 +187,11 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - if (!crtc->enabled) + crtc->enabled = drm_helper_crtc_in_use(crtc); + if (!crtc->enabled) { crtc_funcs->dpms(crtc, DPMSModeOff); + crtc->fb = NULL; + } } } EXPORT_SYMBOL(drm_helper_disable_unused_functions); @@ -209,6 +213,7 @@ static void drm_pick_crtcs (struct drm_device *dev) struct drm_connector_helper_funcs *connector_funcs; int found; + DRM_DEBUG("\n"); /* clean out all the encoder/crtc combos */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { encoder->crtc = NULL; @@ -496,6 +501,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, set->x, set->y); + dev = set->crtc->dev; /* save previous config */ @@ -514,8 +520,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) - flip_or_move = true; + if (set->crtc->fb != set->fb) { + /* if we have no fb then its a change not a flip */ + if (set->crtc->fb == NULL) + changed = true; + else + flip_or_move = true; + } if (set->x != set->crtc->x || set->y != set->crtc->y) flip_or_move = true; @@ -532,7 +543,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; save_encoders[count++] = connector->encoder; - new_encoder = NULL; + new_encoder = connector->encoder; for (ro = 0; ro < set->num_connectors; ro++) { if (set->connectors[ro] == connector) { new_encoder = connector_funcs->best_encoder(connector); @@ -626,6 +637,22 @@ fail_no_encoder: } EXPORT_SYMBOL(drm_crtc_helper_set_config); +bool drm_helper_plugged_event(struct drm_device *dev) +{ + DRM_DEBUG("\n"); + + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); + + drm_pick_crtcs(dev); + + /* alert the driver fb layer */ + dev->mode_config.funcs->fb_changed(dev); + + drm_helper_disable_unused_functions(dev); + + drm_sysfs_hotplug_event(dev); + return true; +} /** * drm_initial_config - setup a sane initial connector configuration * @dev: DRM device @@ -643,45 +670,9 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config); */ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) { - struct drm_connector *connector; int ret = false; - mutex_lock(&dev->mode_config.mutex); - - drm_helper_probe_connector_modes(dev, 2048, 2048); - - drm_pick_crtcs(dev); - - /* This is a little screwy, as we've already walked the connectors - * above, but it's a little bit of magic too. There's the potential - * for things not to get setup above if an existing device gets - * re-assigned thus confusing the hardware. By walking the connectors - * this fixes up their crtc's. - */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - - struct drm_encoder *encoder = connector->encoder; - struct drm_crtc *crtc; - - if (!encoder) - continue; - - crtc = connector->encoder->crtc; - - /* can't setup the connector if there's no assigned mode */ - if (!crtc || !crtc->desired_mode) - continue; - - dev->driver->fb_probe(dev, crtc, connector); - - /* and needs an attached fb */ - if (crtc->fb) - drm_crtc_helper_set_mode(crtc, crtc->desired_mode, 0, 0); - } - - drm_helper_disable_unused_functions(dev); - - mutex_unlock(&dev->mode_config.mutex); + drm_helper_plugged_event(dev); return ret; } EXPORT_SYMBOL(drm_helper_initial_config); @@ -699,62 +690,16 @@ EXPORT_SYMBOL(drm_helper_initial_config); * RETURNS: * Zero on success, errno on failure. */ -int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, - bool connected) +int drm_helper_hotplug_stage_two(struct drm_device *dev) { - int has_config = 0; - dev->mode_config.hotplug_counter++; - /* We might want to do something more here */ - if (!connected) { - DRM_DEBUG("not connected\n"); - return 0; - } - - if (connector->encoder) { - if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the connector already has a config\n"); - has_config = 1; - } - } - - drm_helper_probe_connector_modes(dev, 2048, 2048); - - if (!has_config) - drm_pick_crtcs(dev); - - if (!connector->encoder) { - DRM_DEBUG("could not find a desired mode or crtc for connector\n"); - return 1; - } - - if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) { - DRM_DEBUG("could not find a desired mode or crtc for connector\n"); - return 1; - } - - /* We should really check if there is a fb using this crtc */ - if (!has_config) - dev->driver->fb_probe(dev, connector->encoder->crtc, connector); - else { - dev->driver->fb_resize(dev, connector->encoder->crtc); - -#if 0 - if (!drm_crtc_set_mode(connector->encoder->crtc, connector->encoder->crtc->desired_mode, 0, 0)) - DRM_ERROR("failed to set mode after hotplug\n"); -#endif - } - - drm_sysfs_hotplug_event(dev); - - drm_helper_disable_unused_functions(dev); + drm_helper_plugged_event(dev); return 0; } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); - int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd) { diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 7b7f23dc..45a67f98 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -65,8 +65,7 @@ struct drm_connector_helper_funcs { extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern void drm_helper_disable_unused_functions(struct drm_device *dev); -extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, - bool connected); +extern int drm_helper_hotplug_stage_two(struct drm_device *dev); extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 2aac4926..f755dcd4 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -42,6 +42,12 @@ static struct pci_device_id pciidlist[] = { unsigned int i915_modeset = 0; module_param_named(modeset, i915_modeset, int, 0400); +unsigned int i915_fbpercrtc = 0; +module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); + +unsigned int i915_rightof = 1; +module_param_named(i915_rightof, i915_rightof, int, 0400); + #ifdef I915_HAVE_FENCE extern struct drm_fence_driver i915_fence_driver; #endif @@ -588,8 +594,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .fb_probe = intelfb_probe, - .fb_resize = intelfb_resize, .master_create = i915_master_create, .master_destroy = i915_master_destroy, .ioctls = i915_ioctls, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 6493af16..0081b5be 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1167,13 +1167,10 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, } /* - * If we didn't find an unused CRTC, use the first available one - * that can drive this connector. + * If we didn't find an unused CRTC, don't use any. */ if (!crtc) { - crtc = supported_crtc; - if (!crtc) - return NULL; + return NULL; } encoder->crtc = crtc; @@ -1366,7 +1363,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) struct intel_crtc *intel_crtc; int i; - intel_crtc = kzalloc(sizeof(struct intel_crtc), GFP_KERNEL); + intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); if (intel_crtc == NULL) return; @@ -1383,6 +1380,16 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = DPMSModeOff; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); + + intel_crtc->mode_set.crtc = &intel_crtc->base; + intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1); + intel_crtc->mode_set.num_connectors = 0; + + if (i915_fbpercrtc) { + + + + } } struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) @@ -1513,6 +1520,7 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, static const struct drm_mode_config_funcs intel_mode_funcs = { .resize_fb = NULL, .fb_create = intel_user_framebuffer_create, + .fb_changed = intelfb_probe, }; void intel_modeset_init(struct drm_device *dev) @@ -1554,6 +1562,7 @@ void intel_modeset_init(struct drm_device *dev) intel_setup_outputs(dev); + /* setup fbs */ //drm_initial_config(dev, false); } diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 46f0fbec..1008e271 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -20,6 +20,8 @@ /* The i830->i865 use multiple DVOs with multiple i2cs */ /* the i915, i945 have a single sDVO i2c bus - which is different */ #define MAX_OUTPUTS 6 +/* maximum connectors per crtcs in the mode set */ +#define INTELFB_CONN_LIMIT 4 #define INTEL_I2C_BUS_DVO 1 #define INTEL_I2C_BUS_SDVO 2 @@ -52,6 +54,7 @@ struct intel_framebuffer { struct drm_bo_kmap_obj kmap; }; + struct intel_output { struct drm_connector base; @@ -70,6 +73,9 @@ struct intel_crtc { uint32_t cursor_addr; u8 lut_r[256], lut_g[256], lut_b[256]; int dpms_mode; + struct intel_framebuffer *fbdev_fb; + /* a mode_set for fbdev users on this crtc */ + struct drm_mode_set mode_set; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) @@ -108,7 +114,7 @@ extern void intel_release_load_detect_pipe(struct intel_output *intel_output, extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); -extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); +extern int intelfb_probe(struct drm_device *dev); extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 1107cbfb..85a173e1 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -47,14 +47,11 @@ struct intelfb_par { struct drm_device *dev; -/* - struct drm_crtc *crtc; - struct drm_display_mode *fb_mode; - struct drm_framebuffer *fb; -*/ struct drm_display_mode *our_mode; - struct drm_mode_set set; - struct drm_connector *hack; + struct intel_framebuffer *intel_fb; + int crtc_count; + /* crtc currently bound to this */ + uint32_t crtc_ids[2]; }; /* static int @@ -73,38 +70,52 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->set.fb; - struct drm_crtc *crtc = par->set.crtc; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + int i; - if (regno > 255) - return 1; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_mode_set *modeset = &intel_crtc->mode_set; + struct drm_framebuffer *fb = modeset->fb; - if (fb->depth == 8) { - intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); - return 0; - } + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; - if (regno < 16) { - switch (fb->depth) { - case 15: - fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 16: - fb->pseudo_palette[regno] = (red & 0xf800) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - case 24: - case 32: - fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | - (green & 0xff00) | - ((blue & 0xff00) >> 8); - break; + if (i == par->crtc_count) + continue; + + + if (regno > 255) + return 1; + + if (fb->depth == 8) { + intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); + return 0; } - } + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + } return 0; } @@ -112,12 +123,11 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - /*struct drm_device *dev = par->dev;*/ - struct drm_framebuffer *fb = par->set.fb; - /*struct drm_connector *connector;*/ - int depth/*, found = 0*/; + struct intel_framebuffer *intel_fb = par->intel_fb; + struct drm_framebuffer *fb = &intel_fb->base; + int depth; - if (!var->pixclock) + if (var->pixclock == -1 || !var->pixclock) return -EINVAL; /* Need to resize the fb object !!! */ @@ -194,31 +204,6 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } -#if 0 - /* Here we walk the connector mode list and look for modes. If we haven't - * got it, then bail. Not very nice, so this is disabled. - * In the set_par code, we create our mode based on the incoming - * parameters. Nicer, but may not be desired by some. - */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->crtc == par->crtc) - break; - } - - list_for_each_entry(drm_mode, &connector->modes, head) { - if (drm_mode->hdisplay == var->xres && - drm_mode->vdisplay == var->yres && - (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && - (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { - found = 1; - break; - } - } - - if (!found) - return -EINVAL; -#endif - return 0; } @@ -227,123 +212,132 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->set.fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode, *search_mode; - struct drm_connector *connector = NULL; struct fb_var_screeninfo *var = &info->var; - int found = 0; + int i; - DRM_DEBUG("\n"); + DRM_DEBUG("%d %d\n", var->xres, var->pixclock); - switch (var->bits_per_pixel) { - case 16: - fb->depth = (var->green.length == 6) ? 16 : 15; - break; - case 32: - fb->depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - fb->depth = var->bits_per_pixel; - break; - } - fb->bits_per_pixel = var->bits_per_pixel; + if (var->pixclock != -1) { - info->fix.line_length = fb->pitch; - info->fix.smem_len = info->fix.line_length * fb->height; - info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - - info->screen_size = info->fix.smem_len; /* ??? */ - - /* create a drm mode */ - drm_mode = drm_mode_create(dev); - drm_mode->hdisplay = var->xres; - drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; - drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; - drm_mode->htotal = drm_mode->hsync_end + var->left_margin; - drm_mode->vdisplay = var->yres; - drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; - drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; - drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; - drm_mode->clock = PICOS2KHZ(var->pixclock); - drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); - drm_mode->flags = 0; - drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; - drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; - - drm_mode_set_name(drm_mode); - drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); - - found = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder && - connector->encoder->crtc == par->set.crtc){ - found = 1; - break; - } - } + DRM_ERROR("PIXEL CLCOK SET\n"); +#if 0 + struct intel_framebuffer *intel_fb = par->intel_fb; + struct drm_framebuffer *fb = &intel_fb->base; + struct drm_display_mode *drm_mode, *search_mode; + struct drm_connector *connector = NULL; + struct drm_device *dev = par->dev; - /* no connector bound, bail */ - if (!found) - return -EINVAL; + int found = 0; - found = 0; - drm_mode_debug_printmodeline(drm_mode); - list_for_each_entry(search_mode, &connector->modes, head) { - drm_mode_debug_printmodeline(search_mode); - if (drm_mode_equal(drm_mode, search_mode)) { - drm_mode_destroy(dev, drm_mode); - drm_mode = search_mode; - found = 1; + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; break; } - } - - /* If we didn't find a matching mode that exists on our connector, - * create a new attachment for the incoming user specified mode - */ - if (!found) { - if (par->our_mode) { - /* this also destroys the mode */ - drm_mode_detachmode_crtc(dev, par->our_mode); + + fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = fb->pitch; + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + /* reuse desired mode if possible */ + /* create a drm mode */ + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode->flags = 0; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + + drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + + found = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder && + connector->encoder->crtc == par->set.crtc){ + found = 1; + break; + } } - - par->set.mode = drm_mode; - par->our_mode = drm_mode; + + /* no connector bound, bail */ + if (!found) + return -EINVAL; + + found = 0; drm_mode_debug_printmodeline(drm_mode); - /* attach mode */ - drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + list_for_each_entry(search_mode, &connector->modes, head) { + drm_mode_debug_printmodeline(search_mode); + if (drm_mode_equal(drm_mode, search_mode)) { + drm_mode_destroy(dev, drm_mode); + drm_mode = search_mode; + found = 1; + break; + } + } + + /* If we didn't find a matching mode that exists on our connector, + * create a new attachment for the incoming user specified mode + */ + if (!found) { + if (par->our_mode) { + /* this also destroys the mode */ + drm_mode_detachmode_crtc(dev, par->our_mode); + } + + par->set.mode = drm_mode; + par->our_mode = drm_mode; + drm_mode_debug_printmodeline(drm_mode); + /* attach mode */ + drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + } else { + par->set.mode = drm_mode; + if (par->our_mode) + drm_mode_detachmode_crtc(dev, par->our_mode); + par->our_mode = NULL; + } + return par->set.crtc->funcs->set_config(&par->set); +#endif + return -EINVAL; } else { - par->set.mode = drm_mode; - if (par->our_mode) - drm_mode_detachmode_crtc(dev, par->our_mode); - par->our_mode = NULL; - } + struct drm_crtc *crtc; + int ret; -#if 0 - /* re-attach fb */ - if (!par->crtc->fb) { - par->crtc->fb = par->fb; - changed = 1; - } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) - changed = 1; - - drm_mode_debug_printmodeline(drm_mode); - drm_mode_debug_printmodeline(&par->crtc->mode); - if (!drm_mode_equal(drm_mode, &par->crtc->mode)) - changed = 1; - - if (changed) - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; - return 0; -#else - return par->set.crtc->funcs->set_config(&par->set); -#endif + if (i == par->crtc_count) + continue; + + ret = crtc->funcs->set_config(&intel_crtc->mode_set); + if (ret) + return ret; + } + return 0; + } } #if 0 @@ -495,17 +489,36 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - int ret; - DRM_DEBUG("\n"); - - par->set.x = var->xoffset; - par->set.y = var->yoffset; + struct drm_device *dev = par->dev; + struct drm_mode_set *modeset; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + int ret = 0; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; - ret = par->set.crtc->funcs->set_config(&par->set); + if (i == par->crtc_count) + continue; - if (!ret) { - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; + intel_crtc = to_intel_crtc(crtc); + modeset = &intel_crtc->mode_set; + + modeset->x = var->xoffset; + modeset->y = var->yoffset; + + if (modeset->num_connectors) { + ret = crtc->funcs->set_config(modeset); + + if (!ret) { + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + } + } } return ret; @@ -567,29 +580,21 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector) +int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, + uint32_t surface_width, uint32_t surface_height, + struct intel_framebuffer **intel_fb_p) { struct fb_info *info; struct intelfb_par *par; - struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; - struct drm_display_mode *mode = crtc->desired_mode; struct drm_mode_fb_cmd mode_cmd; - struct drm_buffer_object *fbo = NULL; + struct device *device = &dev->pdev->dev; int ret; - info = framebuffer_alloc(sizeof(struct intelfb_par), device); - if (!info){ - return -EINVAL; - } - - if (!connector) - return -EINVAL; - - mode_cmd.width = 2048;/* crtc->desired_mode->hdisplay; */ - mode_cmd.height = 2048;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */ mode_cmd.bpp = 32; mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); @@ -606,43 +611,31 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - framebuffer_release(info); return -EINVAL; } fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); if (!fb) { - framebuffer_release(info); drm_bo_usage_deref_unlocked(&fbo); DRM_ERROR("failed to allocate fb.\n"); return -EINVAL; } + list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); + intel_fb = to_intel_framebuffer(fb); + *intel_fb_p = intel_fb; intel_fb->bo = fbo; - crtc->fb = fb; - - /* To allow resizeing without swapping buffers */ - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, - intel_fb->base.height, intel_fb->bo->offset, fbo); + info = framebuffer_alloc(sizeof(struct intelfb_par), device); + if (!info) + return -EINVAL; - fb->fbdev = info; - par = info->par; - par->dev = dev; - par->set.crtc = crtc; - par->set.fb = fb; - par->hack = connector; - par->set.connectors = &par->hack; - par->set.num_connectors = 1; - - info->fbops = &intelfb_ops; - - strcpy(info->fix.id, "intelfb"); + strcpy(info->fix.id, "inteldrmfb"); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.type_aux = 0; @@ -651,14 +644,10 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_I830; info->fix.type_aux = 0; - - if (IS_I9XX(dev)) { - info->fix.mmio_start = pci_resource_start(dev->pdev, 0); - info->fix.mmio_len = pci_resource_len(dev->pdev, 0); - } else { - info->fix.mmio_start = pci_resource_start(dev->pdev, 1); - info->fix.mmio_len = pci_resource_len(dev->pdev, 1); - } + + info->flags = FBINFO_DEFAULT; + + info->fbops = &intelfb_ops; info->fix.line_length = fb->pitch; info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; @@ -672,6 +661,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ + + memset(intel_fb->kmap.virtual, 0, info->screen_size); + info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; @@ -682,28 +674,16 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn info->var.height = -1; info->var.width = -1; - info->var.xres = mode->hdisplay; - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.yres = mode->vdisplay; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; - info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = KHZ2PICOS(mode->clock); + info->var.xres = fb_width; + info->var.yres = fb_height; - if (mode->flags & V_PHSYNC) - info->var.sync |= FB_SYNC_HOR_HIGH_ACT; - - if (mode->flags & V_PVSYNC) - info->var.sync |= FB_SYNC_VERT_HIGH_ACT; - - if (mode->flags & V_INTERLACE) - info->var.vmode = FB_VMODE_INTERLACED; - else if (mode->flags & V_DBLSCAN) - info->var.vmode = FB_VMODE_DOUBLE; - else - info->var.vmode = FB_VMODE_NONINTERLACED; + if (IS_I9XX(dev)) { + info->fix.mmio_start = pci_resource_start(dev->pdev, 0); + info->fix.mmio_len = pci_resource_len(dev->pdev, 0); + } else { + info->fix.mmio_start = pci_resource_start(dev->pdev, 1); + info->fix.mmio_len = pci_resource_len(dev->pdev, 1); + } info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; @@ -767,13 +747,247 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn break; } - if (register_framebuffer(info) < 0) - return -EINVAL; + fb->fbdev = info; + + par->intel_fb = intel_fb; + par->dev = dev; + + /* To allow resizeing without swapping buffers */ + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, + intel_fb->base.height, intel_fb->bo->offset, fbo); + + return 0; +} + +static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_framebuffer *fb; + struct drm_connector *connector; + struct fb_info *info; + struct intelfb_par *par; + struct drm_mode_set *modeset; + unsigned int width, height; + int new_fb = 0; + int ret, i, conn_count; + + if (!drm_helper_crtc_in_use(crtc)) + return 0; + + if (!crtc->desired_mode) + return 0; + + width = crtc->desired_mode->hdisplay; + height = crtc->desired_mode->vdisplay; + + /* is there an fb bound to this crtc already */ + if (!intel_crtc->mode_set.fb) { + ret = intelfb_create(dev, width, height, width, height, &intel_fb); + if (ret) + return -EINVAL; + new_fb = 1; + } else { + fb = intel_crtc->mode_set.fb; + intel_fb = to_intel_framebuffer(fb); + if ((intel_fb->base.width < width) || (intel_fb->base.height < height)) + return -EINVAL; + } + + info = intel_fb->base.fbdev; + par = info->par; + + modeset = &intel_crtc->mode_set; + modeset->fb = &intel_fb->base; + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; + conn_count++; + if (conn_count > INTELFB_CONN_LIMIT) + BUG(); + } + } + + for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; + + par->crtc_ids[0] = crtc->base.id; + + modeset->num_connectors = conn_count; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; + + par->crtc_count = 1; + + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } else + intelfb_set_par(info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} + +static int intelfb_multi_fb_probe(struct drm_device *dev) +{ + + struct drm_crtc *crtc; + int ret = 0; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + ret = intelfb_multi_fb_probe_crtc(dev, crtc); + if (ret) + return ret; + } + return ret; +} + +static int intelfb_single_fb_probe(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_connector *connector; + unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + unsigned int surface_width = 0, surface_height = 0; + int new_fb = 0; + int crtc_count = 0; + int ret, i, conn_count = 0; + struct intel_framebuffer *intel_fb; + struct fb_info *info; + struct intelfb_par *par; + struct drm_mode_set *modeset; + + DRM_DEBUG("\n"); + /* first up get a count of crtcs now in use and new min/maxes width/heights */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (drm_helper_crtc_in_use(crtc)) { + if (crtc->desired_mode) { + if (crtc->desired_mode->hdisplay < fb_width) + fb_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay < fb_height) + fb_height = crtc->desired_mode->vdisplay; + + if (crtc->desired_mode->hdisplay > surface_width) + surface_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay > surface_height) + surface_height = crtc->desired_mode->vdisplay; + + } + crtc_count++; + } + } + + if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { + /* hmm everyone went away - assume VGA cable just fell out + and will come back later. */ + return 0; + } + + /* do we have an fb already? */ + if (list_empty(&dev->mode_config.fb_kernel_list)) { + /* create an fb if we don't have one */ + ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); + if (ret) + return -EINVAL; + new_fb = 1; + } else { + struct drm_framebuffer *fb; + fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); + intel_fb = to_intel_framebuffer(fb); + + /* if someone hotplugs something bigger than we have already allocated, we are pwned. + As really we can't resize an fbdev that is in the wild currently due to fbdev + not really being designed for the lower layers moving stuff around under it. + - so in the grand style of things - punt. */ + if ((fb->width < surface_width) || (fb->height < surface_height)) { + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); + return -EINVAL; + } + } + + info = intel_fb->base.fbdev; + par = info->par; + + crtc_count = 0; + /* okay we need to setup new connector sets in the crtcs */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + modeset = &intel_crtc->mode_set; + modeset->fb = &intel_fb->base; + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if(connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; + conn_count++; + if (conn_count > INTELFB_CONN_LIMIT) + BUG(); + } + } + + for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; + + par->crtc_ids[crtc_count++] = crtc->base.id; + + modeset->num_connectors = conn_count; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; + } + par->crtc_count = crtc_count; + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } else + intelfb_set_par(info); + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, - info->fix.id); + info->fix.id); return 0; } + +int intelfb_probe(struct drm_device *dev) +{ + int ret; + + DRM_DEBUG("\n"); + + /* something has changed in the lower levels of hell - deal with it + here */ + + /* two modes : a) 1 fb to rule all crtcs. + b) one fb per crtc. + two actions 1) new connected device + 2) device removed. + case a/1 : if the fb surface isn't big enough - resize the surface fb. + if the fb size isn't big enough - resize fb into surface. + if everything big enough configure the new crtc/etc. + case a/2 : undo the configuration + possibly resize down the fb to fit the new configuration. + case b/1 : see if it is on a new crtc - setup a new fb and add it. + case b/2 : teardown the new fb. + */ + + /* mode a first */ + /* search for an fb */ + if (i915_fbpercrtc == 1) { + ret = intelfb_multi_fb_probe(dev); + } else { + ret = intelfb_single_fb_probe(dev); + } + +fail: + /* TODO */ + return ret; +} EXPORT_SYMBOL(intelfb_probe); int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a54f5af9..34e81ad5 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -372,6 +372,8 @@ int i915_execbuffer(struct drm_device *dev, void *data, #endif +extern unsigned int i915_fbpercrtc; + #ifdef __linux__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) extern void intel_init_chipset_flush_compat(struct drm_device *dev); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4c147a08..2d355688 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -441,93 +441,8 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) return count; } -#define HOTPLUG_CMD_CRT 1 -#define HOTPLUG_CMD_CRT_DIS 2 -#define HOTPLUG_CMD_SDVOB 4 -#define HOTPLUG_CMD_SDVOC 8 -#define HOTPLUG_CMD_TV 16 - static struct drm_device *hotplug_dev; -static int hotplug_cmd = 0; -static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; - -static void i915_hotplug_tv(struct drm_device *dev) -{ - struct drm_connector *connector; - struct intel_output *iout; - enum drm_connector_status status; - - mutex_lock(&dev->mode_config.mutex); - - /* find the crt output */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_intel_output(connector); - if (iout->type == INTEL_OUTPUT_TVOUT) - break; - else - iout = 0; - } - - if (iout == 0) - goto unlock; - - status = connector->funcs->detect(connector); - drm_helper_hotplug_stage_two(dev, connector, - status == connector_status_connected ? 1 : 0); - -unlock: - mutex_unlock(&dev->mode_config.mutex); -} - -static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) -{ - struct drm_connector *connector; - struct intel_output *iout; - - mutex_lock(&dev->mode_config.mutex); - - /* find the crt output */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_intel_output(connector); - if (iout->type == INTEL_OUTPUT_ANALOG) - break; - else - iout = 0; - } - - if (iout == 0) - goto unlock; - - drm_helper_hotplug_stage_two(dev, connector, isconnected); -unlock: - mutex_unlock(&dev->mode_config.mutex); -} - -static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) -{ - struct drm_connector *connector = 0; - enum drm_connector_status status; - - mutex_lock(&dev->mode_config.mutex); - - connector = intel_sdvo_find(dev, sdvoB); - - if (!connector) - goto unlock; - - status = connector->funcs->detect(connector); - - if (status != connector_status_connected) - drm_helper_hotplug_stage_two(dev, connector, false); - else - drm_helper_hotplug_stage_two(dev, connector, true); - - intel_sdvo_set_hotplug(connector, 1); - -unlock: - mutex_unlock(&dev->mode_config.mutex); -} /* * This code is called in a more safe envirmoent to handle the hotplugs. * Add code here for hotplug love to userspace. @@ -539,34 +454,8 @@ static void i915_hotplug_work_func(struct work_struct *work) #endif { struct drm_device *dev = hotplug_dev; - int crt; - int crtDis; - int sdvoB; - int sdvoC; - int tv; - - spin_lock(&hotplug_lock); - tv = hotplug_cmd & HOTPLUG_CMD_TV; - crt = hotplug_cmd & HOTPLUG_CMD_CRT; - crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS; - sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; - sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC; - hotplug_cmd = 0; - spin_unlock(&hotplug_lock); - - if (tv) - i915_hotplug_tv(dev); - if (crt) - i915_hotplug_crt(dev, true); - if (crtDis) - i915_hotplug_crt(dev, false); - - if (sdvoB) - i915_hotplug_sdvo(dev, 1); - - if (sdvoC) - i915_hotplug_sdvo(dev, 0); + drm_helper_hotplug_stage_two(dev); drm_handle_hotplug(dev); } @@ -583,40 +472,18 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) if (stat & TV_HOTPLUG_INT_STATUS) { DRM_DEBUG("TV event\n"); - - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_TV; - spin_unlock(&hotplug_lock); } if (stat & CRT_HOTPLUG_INT_STATUS) { DRM_DEBUG("CRT event\n"); - - if (stat & CRT_HOTPLUG_MONITOR_MASK) { - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_CRT; - spin_unlock(&hotplug_lock); - } else { - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_CRT_DIS; - spin_unlock(&hotplug_lock); - } } if (stat & SDVOB_HOTPLUG_INT_STATUS) { DRM_DEBUG("sDVOB event\n"); - - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_SDVOB; - spin_unlock(&hotplug_lock); } if (stat & SDVOC_HOTPLUG_INT_STATUS) { DRM_DEBUG("sDVOC event\n"); - - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_SDVOC; - spin_unlock(&hotplug_lock); } queue_work(dev_priv->wq, &hotplug); |