a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* -*- c-basic-offset: 8 -*-
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop: A Remote Desktop Protocol client.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Support for the Matrox "lspci" channel
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright (C) 2005 Matrox Graphics Inc.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is free software: you can redistribute it and/or modify
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it under the terms of the GNU General Public License as published by
a180a41bba1d50822df23fff0099e90b86638b89vboxsync the Free Software Foundation, either version 3 of the License, or
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (at your option) any later version.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is distributed in the hope that it will be useful,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync but WITHOUT ANY WARRANTY; without even the implied warranty of
a180a41bba1d50822df23fff0099e90b86638b89vboxsync MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a180a41bba1d50822df23fff0099e90b86638b89vboxsync GNU General Public License for more details.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync You should have received a copy of the GNU General Public License
a180a41bba1d50822df23fff0099e90b86638b89vboxsync along with this program. If not, see <http://www.gnu.org/licenses/>.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync*/
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/*
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * the General Public License version 2 (GPLv2) at this time for any software where
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * a choice of GPL license versions is made available with the language indicating
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * that GPLv2 or any later version may be used, or where a choice of which version
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * of the GPL is applied is otherwise unspecified.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include "rdesktop.h"
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <sys/types.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <unistd.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic VCHANNEL *lspci_channel;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsynctypedef struct _pci_device
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 klass;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 vendor;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 device;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 subvendor;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 subdevice;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 revision;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 progif;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync} pci_device;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic pci_device current_device;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void lspci_send(const char *output);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Handle one line of output from the lspci subprocess */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL
a180a41bba1d50822df23fff0099e90b86638b89vboxsynchandle_child_line(const char *line, void *data)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync const char *val;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char buf[1024];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (str_startswith(line, "Class:"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val = line + sizeof("Class:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Skip whitespace and second Class: occurance */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val += strspn(val, " \t") + sizeof("Class");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.klass = strtol(val, NULL, 16);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (str_startswith(line, "Vendor:"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val = line + sizeof("Vendor:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.vendor = strtol(val, NULL, 16);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (str_startswith(line, "Device:"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val = line + sizeof("Device:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Sigh, there are *two* lines tagged as Device:. We
a180a41bba1d50822df23fff0099e90b86638b89vboxsync are not interested in the domain/bus/slot/func */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!strchr(val, ':'))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.device = strtol(val, NULL, 16);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (str_startswith(line, "SVendor:"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val = line + sizeof("SVendor:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.subvendor = strtol(val, NULL, 16);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (str_startswith(line, "SDevice:"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val = line + sizeof("SDevice:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.subdevice = strtol(val, NULL, 16);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (str_startswith(line, "Rev:"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val = line + sizeof("Rev:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.revision = strtol(val, NULL, 16);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (str_startswith(line, "ProgIf:"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync val = line + sizeof("ProgIf:");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.progif = strtol(val, NULL, 16);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (strspn(line, " \t") == strlen(line))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Blank line. Send collected information over channel */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync snprintf(buf, sizeof(buf), "%04x,%04x,%04x,%04x,%04x,%02x,%02x\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.klass, current_device.vendor,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.device, current_device.subvendor,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync current_device.subdevice, current_device.revision, current_device.progif);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync lspci_send(buf);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(&current_device, 0, sizeof(current_device));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync warning("lspci: Unrecoqnized line '%s'\n", line);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Process one line of input from virtual channel */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL
a180a41bba1d50822df23fff0099e90b86638b89vboxsynclspci_process_line(const char *line, void *data)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *lspci_command[5] = { "lspci", "-m", "-n", "-v", NULL };
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!strcmp(line, "LSPCI"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memset(&current_device, 0, sizeof(current_device));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync subprocess(lspci_command, handle_child_line, NULL);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Send single dot to indicate end of enumeration */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync lspci_send(".\n");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync error("lspci protocol error: Invalid line '%s'\n", line);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Process new data from the virtual channel */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsynclspci_process(STREAM s)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned int pkglen;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync static char *rest = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *buf;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync pkglen = s->end - s->p;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* str_handle_lines requires null terminated strings */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync buf = xmalloc(pkglen + 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync STRNCPY(buf, (char *) s->p, pkglen + 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#if 0
a180a41bba1d50822df23fff0099e90b86638b89vboxsync printf("lspci recv:\n");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync hexdump(s->p, pkglen);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync str_handle_lines(buf, &rest, lspci_process_line, NULL);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(buf);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Initialize this module: Register the lspci channel */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncRD_BOOL
a180a41bba1d50822df23fff0099e90b86638b89vboxsynclspci_init(void)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync lspci_channel =
a180a41bba1d50822df23fff0099e90b86638b89vboxsync channel_register("lspci", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync lspci_process);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return (lspci_channel != NULL);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Send data to channel */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsynclspci_send(const char *output)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync STREAM s;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync size_t len;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync len = strlen(output);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync s = channel_init(lspci_channel, len);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync out_uint8p(s, output, len) s_mark_end(s);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#if 0
a180a41bba1d50822df23fff0099e90b86638b89vboxsync printf("lspci send:\n");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync channel_send(s, lspci_channel);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}