diff options
Diffstat (limited to 'backend/drm')
-rw-r--r-- | backend/drm/atomic.c | 24 | ||||
-rw-r--r-- | backend/drm/backend.c | 21 | ||||
-rw-r--r-- | backend/drm/drm.c | 162 | ||||
-rw-r--r-- | backend/drm/legacy.c | 10 | ||||
-rw-r--r-- | backend/drm/properties.c | 13 | ||||
-rw-r--r-- | backend/drm/util.c | 19 |
6 files changed, 198 insertions, 51 deletions
diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 90acac25..ad80f2fd 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -104,7 +104,8 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } - if (drmModeCreatePropertyBlob(drm->fd, mode, sizeof(*mode), &crtc->mode_id)) { + if (drmModeCreatePropertyBlob(drm->fd, mode, sizeof(*mode), + &crtc->mode_id)) { wlr_log_errno(WLR_ERROR, "Unable to create property blob"); return false; } @@ -120,6 +121,10 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, struct atomic atom; atomic_begin(crtc, &atom); atomic_add(&atom, conn->id, conn->props.crtc_id, crtc->id); + if (mode != NULL && conn->props.link_status != 0) { + atomic_add(&atom, conn->id, conn->props.link_status, + DRM_MODE_LINK_STATUS_GOOD); + } atomic_add(&atom, crtc->id, crtc->props.mode_id, crtc->mode_id); atomic_add(&atom, crtc->id, crtc->props.active, 1); set_plane_props(&atom, crtc->primary, crtc->id, fb_id, true); @@ -200,14 +205,14 @@ static bool atomic_crtc_move_cursor(struct wlr_drm_backend *drm, } static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, - struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, - uint32_t size) { + struct wlr_drm_crtc *crtc, size_t size, + uint16_t *r, uint16_t *g, uint16_t *b) { // Fallback to legacy gamma interface when gamma properties are not available // (can happen on older intel gpu's that support gamma but not degamma) // TEMP: This is broken on AMDGPU. Always fallback to legacy until they get // it fixed. Ref https://bugs.freedesktop.org/show_bug.cgi?id=107459 if (crtc->props.gamma_lut == 0 || true) { - return legacy_iface.crtc_set_gamma(drm, crtc, r, g, b, size); + return legacy_iface.crtc_set_gamma(drm, crtc, size, r, g, b); } struct drm_color_lut *gamma = malloc(size * sizeof(struct drm_color_lut)); @@ -216,7 +221,7 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, return false; } - for (uint32_t i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { gamma[i].red = r[i]; gamma[i].green = g[i]; gamma[i].blue = b[i]; @@ -240,21 +245,20 @@ static bool atomic_crtc_set_gamma(struct wlr_drm_backend *drm, return atomic_end(drm->fd, &atom); } -static uint32_t atomic_crtc_get_gamma_size(struct wlr_drm_backend *drm, +static size_t atomic_crtc_get_gamma_size(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc) { - uint64_t gamma_lut_size; - if (crtc->props.gamma_lut_size == 0) { return legacy_iface.crtc_get_gamma_size(drm, crtc); } + uint64_t gamma_lut_size; if (!get_drm_prop(drm->fd, crtc->id, crtc->props.gamma_lut_size, - &gamma_lut_size)) { + &gamma_lut_size)) { wlr_log(WLR_ERROR, "Unable to get gamma lut size"); return 0; } - return (uint32_t)gamma_lut_size; + return (size_t)gamma_lut_size; } const struct wlr_drm_interface atomic_iface = { diff --git a/backend/drm/backend.c b/backend/drm/backend.c index bba79bda..a9082077 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -65,10 +65,16 @@ static struct wlr_renderer *backend_get_renderer( } } +static clockid_t backend_get_presentation_clock(struct wlr_backend *backend) { + struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend); + return drm->clock; +} + static struct wlr_backend_impl backend_impl = { .start = backend_start, .destroy = backend_destroy, .get_renderer = backend_get_renderer, + .get_presentation_clock = backend_get_presentation_clock, }; bool wlr_backend_is_drm(struct wlr_backend *b) { @@ -101,6 +107,16 @@ static void session_signal(struct wl_listener *listener, void *data) { (plane && plane->cursor_enabled) ? plane->cursor_bo : NULL); drm->iface->crtc_move_cursor(drm, conn->crtc, conn->cursor_x, conn->cursor_y); + + if (conn->crtc->gamma_table != NULL) { + size_t size = conn->crtc->gamma_table_size; + uint16_t *r = conn->crtc->gamma_table; + uint16_t *g = conn->crtc->gamma_table + size; + uint16_t *b = conn->crtc->gamma_table + 2 * size; + drm->iface->crtc_set_gamma(drm, conn->crtc, size, r, g, b); + } else { + set_drm_connector_gamma(&conn->output, 0, NULL, NULL, NULL); + } } } else { wlr_log(WLR_INFO, "DRM fd paused"); @@ -193,8 +209,3 @@ error_fd: free(drm); return NULL; } - -struct wlr_session *wlr_drm_backend_get_session(struct wlr_backend *backend) { - struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend); - return drm->session; -} diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 110c2229..1313e7fe 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 199309L #include <assert.h> #include <drm_mode.h> #include <EGL/egl.h> @@ -27,8 +28,8 @@ #include "util/signal.h" bool check_drm_features(struct wlr_drm_backend *drm) { + uint64_t cap; if (drm->parent) { - uint64_t cap; if (drmGetCap(drm->fd, DRM_CAP_PRIME, &cap) || !(cap & DRM_PRIME_CAP_IMPORT)) { wlr_log(WLR_ERROR, @@ -51,16 +52,21 @@ bool check_drm_features(struct wlr_drm_backend *drm) { const char *no_atomic = getenv("WLR_DRM_NO_ATOMIC"); if (no_atomic && strcmp(no_atomic, "1") == 0) { - wlr_log(WLR_DEBUG, "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); + wlr_log(WLR_DEBUG, + "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); drm->iface = &legacy_iface; } else if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_ATOMIC, 1)) { - wlr_log(WLR_DEBUG, "Atomic modesetting unsupported, using legacy DRM interface"); + wlr_log(WLR_DEBUG, + "Atomic modesetting unsupported, using legacy DRM interface"); drm->iface = &legacy_iface; } else { wlr_log(WLR_DEBUG, "Using atomic DRM interface"); drm->iface = &atomic_iface; } + int ret = drmGetCap(drm->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap); + drm->clock = (ret == 0 && cap == 1) ? CLOCK_MONOTONIC : CLOCK_REALTIME; + return true; } @@ -150,6 +156,11 @@ bool init_drm_resources(struct wlr_drm_backend *drm) { wlr_log(WLR_INFO, "Found %d DRM CRTCs", res->count_crtcs); drm->num_crtcs = res->count_crtcs; + if (drm->num_crtcs == 0) { + drmModeFreeResources(res); + return true; + } + drm->crtcs = calloc(drm->num_crtcs, sizeof(drm->crtcs[0])); if (!drm->crtcs) { wlr_log_errno(WLR_ERROR, "Allocation failed"); @@ -193,6 +204,7 @@ void finish_drm_resources(struct wlr_drm_backend *drm) { if (crtc->gamma_lut) { drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut); } + free(crtc->gamma_table); } for (size_t i = 0; i < drm->num_planes; ++i) { struct wlr_drm_plane *plane = &drm->planes[i]; @@ -251,7 +263,7 @@ static bool drm_connector_swap_buffers(struct wlr_output *output, return true; } -static void fill_empty_gamma_table(uint32_t size, +static void fill_empty_gamma_table(size_t size, uint16_t *r, uint16_t *g, uint16_t *b) { for (uint32_t i = 0; i < size; ++i) { uint16_t val = (uint32_t)0xffff * i / (size - 1); @@ -259,7 +271,7 @@ static void fill_empty_gamma_table(uint32_t size, } } -static uint32_t drm_connector_get_gamma_size(struct wlr_output *output) { +static size_t drm_connector_get_gamma_size(struct wlr_output *output) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); @@ -270,8 +282,8 @@ static uint32_t drm_connector_get_gamma_size(struct wlr_output *output) { return 0; } -static bool drm_connector_set_gamma(struct wlr_output *output, - uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { +bool set_drm_connector_gamma(struct wlr_output *output, size_t size, + const uint16_t *r, const uint16_t *g, const uint16_t *b) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); @@ -279,25 +291,42 @@ static bool drm_connector_set_gamma(struct wlr_output *output, return false; } - uint16_t *reset_table = NULL; + bool reset = false; if (size == 0) { + reset = true; size = drm_connector_get_gamma_size(output); - reset_table = malloc(3 * size * sizeof(uint16_t)); - if (reset_table == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate gamma table"); + if (size == 0) { return false; } - r = reset_table; - g = reset_table + size; - b = reset_table + 2 * size; - fill_empty_gamma_table(size, r, g, b); } - bool ok = drm->iface->crtc_set_gamma(drm, conn->crtc, r, g, b, size); + uint16_t *gamma_table = malloc(3 * size * sizeof(uint16_t)); + if (gamma_table == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate gamma table"); + return false; + } + uint16_t *_r = gamma_table; + uint16_t *_g = gamma_table + size; + uint16_t *_b = gamma_table + 2 * size; + + if (reset) { + fill_empty_gamma_table(size, _r, _g, _b); + } else { + memcpy(_r, r, size * sizeof(uint16_t)); + memcpy(_g, g, size * sizeof(uint16_t)); + memcpy(_b, b, size * sizeof(uint16_t)); + } + + bool ok = drm->iface->crtc_set_gamma(drm, conn->crtc, size, _r, _g, _b); if (ok) { wlr_output_update_needs_swap(output); + + free(conn->crtc->gamma_table); + conn->crtc->gamma_table = gamma_table; + conn->crtc->gamma_table_size = size; + } else { + free(gamma_table); } - free(reset_table); return ok; } @@ -409,9 +438,9 @@ static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, continue; } - uint32_t possible[drm->num_type_planes[type]]; - uint32_t crtc[drm->num_crtcs]; - uint32_t crtc_res[drm->num_crtcs]; + uint32_t possible[drm->num_type_planes[type] + 1]; + uint32_t crtc[drm->num_crtcs + 1]; + uint32_t crtc_res[drm->num_crtcs + 1]; for (size_t i = 0; i < drm->num_type_planes[type]; ++i) { possible[i] = drm->type_planes[type][i].possible_crtcs; @@ -706,6 +735,43 @@ static bool drm_connector_move_cursor(struct wlr_output *output, return ok; } +static void drm_connector_schedule_frame(struct wlr_output *output) { + struct wlr_drm_connector *conn = get_drm_connector_from_output(output); + struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); + if (!drm->session->active) { + return; + } + + // We need to figure out where we are in the vblank cycle + // TODO: try using drmWaitVBlank and fallback to pageflipping + + struct wlr_drm_crtc *crtc = conn->crtc; + if (!crtc) { + return; + } + struct wlr_drm_plane *plane = crtc->primary; + struct gbm_bo *bo = plane->surf.back; + if (!bo) { + // We haven't swapped buffers yet -- can't do a pageflip + wlr_output_send_frame(output); + return; + } + uint32_t fb_id = get_fb_for_bo(bo); + + if (conn->pageflip_pending) { + wlr_log(WLR_ERROR, "Skipping pageflip on output '%s'", + conn->output.name); + return; + } + + if (!drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { + return; + } + + conn->pageflip_pending = true; + wlr_output_update_enabled(output, true); +} + static void drm_connector_destroy(struct wlr_output *output) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); drm_connector_cleanup(conn); @@ -724,9 +790,10 @@ static const struct wlr_output_impl output_impl = { .destroy = drm_connector_destroy, .make_current = drm_connector_make_current, .swap_buffers = drm_connector_swap_buffers, - .set_gamma = drm_connector_set_gamma, + .set_gamma = set_drm_connector_gamma, .get_gamma_size = drm_connector_get_gamma_size, .export_dmabuf = drm_connector_export_dmabuf, + .schedule_frame = drm_connector_schedule_frame, }; bool wlr_output_is_drm(struct wlr_output *output) { @@ -759,6 +826,8 @@ static void dealloc_crtc(struct wlr_drm_connector *conn) { wlr_log(WLR_DEBUG, "De-allocating CRTC %zu for output '%s'", conn->crtc - drm->crtcs, conn->output.name); + set_drm_connector_gamma(&conn->output, 0, NULL, NULL, NULL); + for (size_t type = 0; type < 3; ++type) { struct wlr_drm_plane *plane = conn->crtc->planes[type]; if (plane == NULL) { @@ -1014,6 +1083,24 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->crtc = NULL; } + // This can only happen *after* hotplug, since we haven't read the + // connector properties yet + if (wlr_conn->props.link_status != 0) { + uint64_t link_status; + if (!get_drm_prop(drm->fd, wlr_conn->id, + wlr_conn->props.link_status, &link_status)) { + wlr_log(WLR_ERROR, "Failed to get link status for '%s'", + wlr_conn->output.name); + continue; + } + + if (link_status == DRM_MODE_LINK_STATUS_BAD) { + // We need to reload our list of modes and force a modeset + wlr_log(WLR_INFO, "Bad link for '%s'", wlr_conn->output.name); + drm_connector_cleanup(wlr_conn); + } + } + if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED && drm_conn->connection == DRM_MODE_CONNECTED) { wlr_log(WLR_INFO, "'%s' connected", wlr_conn->output.name); @@ -1096,7 +1183,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { } } - bool changed_outputs[wl_list_length(&drm->outputs)]; + bool changed_outputs[wl_list_length(&drm->outputs) + 1]; memset(changed_outputs, false, sizeof(changed_outputs)); for (size_t i = 0; i < new_outputs_len; ++i) { struct wlr_drm_connector *conn = new_outputs[i]; @@ -1128,9 +1215,13 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { attempt_enable_needs_modeset(drm); } +static int mhz_to_nsec(int mhz) { + return 1000000000000LL / mhz; +} + static void page_flip_handler(int fd, unsigned seq, - unsigned tv_sec, unsigned tv_usec, void *user) { - struct wlr_drm_connector *conn = user; + unsigned tv_sec, unsigned tv_usec, void *data) { + struct wlr_drm_connector *conn = data; struct wlr_drm_backend *drm = get_drm_backend_from_backend(conn->output.backend); @@ -1150,6 +1241,19 @@ static void page_flip_handler(int fd, unsigned seq, post_drm_surface(&conn->crtc->primary->mgpu_surf); } + struct timespec present_time = { + .tv_sec = tv_sec, + .tv_nsec = tv_usec * 1000, + }; + struct wlr_output_event_present present_event = { + .when = &present_time, + .seq = seq, + .refresh = mhz_to_nsec(conn->output.refresh), + .flags = WLR_OUTPUT_PRESENT_VSYNC | WLR_OUTPUT_PRESENT_HW_CLOCK | + WLR_OUTPUT_PRESENT_HW_COMPLETION, + }; + wlr_output_send_present(&conn->output, &present_event); + if (drm->session->active) { wlr_output_send_frame(&conn->output); } @@ -1157,7 +1261,7 @@ static void page_flip_handler(int fd, unsigned seq, int handle_drm_event(int fd, uint32_t mask, void *data) { drmEventContext event = { - .version = DRM_EVENT_CONTEXT_VERSION, + .version = 2, .page_flip_handler = page_flip_handler, }; @@ -1243,7 +1347,13 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { memset(&conn->output.model, 0, sizeof(conn->output.model)); memset(&conn->output.serial, 0, sizeof(conn->output.serial)); - conn->pageflip_pending = false; + if (conn->output.idle_frame != NULL) { + wl_event_source_remove(conn->output.idle_frame); + conn->output.idle_frame = NULL; + } + conn->output.needs_swap = false; + conn->output.frame_pending = false; + /* Fallthrough */ case WLR_DRM_CONN_NEEDS_MODESET: wlr_log(WLR_INFO, "Emitting destruction signal for '%s'", diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index c205e167..182c7a95 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -63,14 +63,14 @@ bool legacy_crtc_move_cursor(struct wlr_drm_backend *drm, } bool legacy_crtc_set_gamma(struct wlr_drm_backend *drm, - struct wlr_drm_crtc *crtc, uint16_t *r, uint16_t *g, uint16_t *b, - uint32_t size) { - return !drmModeCrtcSetGamma(drm->fd, crtc->id, size, r, g, b); + struct wlr_drm_crtc *crtc, size_t size, + uint16_t *r, uint16_t *g, uint16_t *b) { + return !drmModeCrtcSetGamma(drm->fd, crtc->id, (uint32_t)size, r, g, b); } -uint32_t legacy_crtc_get_gamma_size(struct wlr_drm_backend *drm, +size_t legacy_crtc_get_gamma_size(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc) { - return crtc->legacy_crtc->gamma_size; + return (size_t)crtc->legacy_crtc->gamma_size; } const struct wlr_drm_interface legacy_iface = { diff --git a/backend/drm/properties.c b/backend/drm/properties.c index 372de232..5ca4c8ac 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -19,9 +19,10 @@ struct prop_info { static const struct prop_info connector_info[] = { #define INDEX(name) (offsetof(union wlr_drm_connector_props, name) / sizeof(uint32_t)) - { "CRTC_ID", INDEX(crtc_id) }, - { "DPMS", INDEX(dpms) }, - { "EDID", INDEX(edid) }, + { "CRTC_ID", INDEX(crtc_id) }, + { "DPMS", INDEX(dpms) }, + { "EDID", INDEX(edid) }, + { "link-status", INDEX(link_status) }, #undef INDEX }; @@ -87,7 +88,8 @@ static bool scan_properties(int fd, uint32_t id, uint32_t type, uint32_t *result return true; } -bool get_drm_connector_props(int fd, uint32_t id, union wlr_drm_connector_props *out) { +bool get_drm_connector_props(int fd, uint32_t id, + union wlr_drm_connector_props *out) { return scan_properties(fd, id, DRM_MODE_OBJECT_CONNECTOR, out->props, connector_info, sizeof(connector_info) / sizeof(connector_info[0])); } @@ -103,7 +105,8 @@ bool get_drm_plane_props(int fd, uint32_t id, union wlr_drm_plane_props *out) { } bool get_drm_prop(int fd, uint32_t obj, uint32_t prop, uint64_t *ret) { - drmModeObjectProperties *props = drmModeObjectGetProperties(fd, obj, DRM_MODE_OBJECT_ANY); + drmModeObjectProperties *props = + drmModeObjectGetProperties(fd, obj, DRM_MODE_OBJECT_ANY); if (!props) { return false; } diff --git a/backend/drm/util.c b/backend/drm/util.c index f9637c33..6b2c0981 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -32,21 +32,30 @@ static const char *get_manufacturer(uint16_t id) { case ID('A', 'A', 'A'): return "Avolites Ltd"; case ID('A', 'C', 'I'): return "Ancor Communications Inc"; case ID('A', 'C', 'R'): return "Acer Technologies"; + case ID('A', 'D', 'A'): return "Addi-Data GmbH"; case ID('A', 'P', 'P'): return "Apple Computer Inc"; + case ID('A', 'S', 'K'): return "Ask A/S"; + case ID('A', 'V', 'T'): return "Avtek (Electronics) Pty Ltd"; case ID('B', 'N', 'O'): return "Bang & Olufsen"; case ID('C', 'M', 'N'): return "Chimei Innolux Corporation"; case ID('C', 'M', 'O'): return "Chi Mei Optoelectronics corp."; case ID('C', 'R', 'O'): return "Extraordinary Technologies PTY Limited"; case ID('D', 'E', 'L'): return "Dell Inc."; + case ID('D', 'G', 'C'): return "Data General Corporation"; case ID('D', 'O', 'N'): return "DENON, Ltd."; case ID('E', 'N', 'C'): return "Eizo Nanao Corporation"; case ID('E', 'P', 'H'): return "Epiphan Systems Inc."; + case ID('E', 'X', 'P'): return "Data Export Corporation"; + case ID('F', 'N', 'I'): return "Funai Electric Co., Ltd."; case ID('F', 'U', 'S'): return "Fujitsu Siemens Computers GmbH"; case ID('G', 'S', 'M'): return "Goldstar Company Ltd"; case ID('H', 'I', 'Q'): return "Kaohsiung Opto Electronics Americas, Inc."; case ID('H', 'S', 'D'): return "HannStar Display Corp"; + case ID('H', 'T', 'C'): return "Hitachi Ltd"; case ID('H', 'W', 'P'): return "Hewlett Packard"; case ID('I', 'N', 'T'): return "Interphase Corporation"; + case ID('I', 'N', 'X'): return "Communications Supply Corporation (A division of WESCO)"; + case ID('I', 'T', 'E'): return "Integrated Tech Express Inc"; case ID('I', 'V', 'M'): return "Iiyama North America"; case ID('L', 'E', 'N'): return "Lenovo Group Limited"; case ID('M', 'A', 'X'): return "Rogen Tech Distribution Inc"; @@ -55,6 +64,7 @@ static const char *get_manufacturer(uint16_t id) { case ID('M', 'T', 'C'): return "Mars-Tech Corporation"; case ID('M', 'T', 'X'): return "Matrox"; case ID('N', 'E', 'C'): return "NEC Corporation"; + case ID('N', 'E', 'X'): return "Nexgen Mediatech Inc."; case ID('O', 'N', 'K'): return "ONKYO Corporation"; case ID('O', 'R', 'N'): return "ORION ELECTRIC CO., LTD."; case ID('O', 'T', 'M'): return "Optoma Corporation"; @@ -63,15 +73,24 @@ static const char *get_manufacturer(uint16_t id) { case ID('P', 'I', 'O'): return "Pioneer Electronic Corporation"; case ID('P', 'N', 'R'): return "Planar Systems, Inc."; case ID('Q', 'D', 'S'): return "Quanta Display Inc."; + case ID('R', 'A', 'T'): return "Rent-A-Tech"; + case ID('R', 'E', 'N'): return "Renesas Technology Corp."; case ID('S', 'A', 'M'): return "Samsung Electric Company"; + case ID('S', 'A', 'N'): return "Sanyo Electric Co., Ltd."; case ID('S', 'E', 'C'): return "Seiko Epson Corporation"; case ID('S', 'H', 'P'): return "Sharp Corporation"; case ID('S', 'I', 'I'): return "Silicon Image, Inc."; case ID('S', 'N', 'Y'): return "Sony"; + case ID('S', 'T', 'D'): return "STD Computer Inc"; + case ID('S', 'V', 'S'): return "SVSI"; + case ID('S', 'Y', 'N'): return "Synaptics Inc"; + case ID('T', 'C', 'L'): return "Technical Concepts Ltd"; case ID('T', 'O', 'P'): return "Orion Communications Co., Ltd."; case ID('T', 'S', 'B'): return "Toshiba America Info Systems Inc"; case ID('T', 'S', 'T'): return "Transtream Inc"; case ID('U', 'N', 'K'): return "Unknown"; + case ID('V', 'E', 'S'): return "Vestel Elektronik Sanayi ve Ticaret A. S."; + case ID('V', 'I', 'T'): return "Visitech AS"; case ID('V', 'I', 'Z'): return "VIZIO, Inc"; case ID('V', 'S', 'C'): return "ViewSonic Corporation"; case ID('Y', 'M', 'H'): return "Yamaha Corporation"; |