[Comm] Dosemu: LPT port access HOWTO

Grigory Batalov bga-no-spam на kovgok.ru
Пн Фев 23 23:13:57 MSK 2004


  Здравствуйте!

  Не прошло и двух лет с тех пор, как я обещал описать доступ
к LPT-порту в dosemu =). Предлагаю почтеннейшей публике следующее
HOWTO.

  Указанные настройки действительны для dosemu-1.1.99-alt1
и последующей dosemu-1.2.0-alt1, которую я сейчас тестирую.

---
1. Перечислить в dosemu.conf требуемые порты. Например, для LPT:

$ sudo vim /etc/dosemu.conf

$_ports = "device /dev/lp0 range 0x378 0x37a"

Низкоуровневый доступ к портам - привелегированная операция,
так что
 а) придётся установить dosemu.bin как SUID root
 б) соответствующие настройки нужно вносить в /etc/dosemu.conf,
    т.к. в ~/.dosemurc они будут просто проигнорированы

---
2. При использовании SUID root dosemu проверяет /etc/dosemu.users.
Если запускающий пользователь не описан в этом файле, или имеет
недостаточные привелегии, dosemu переходит в обычный, непривилеги-
рованный режим.

$ sudo vim /etc/dosemu.users

bga c_port

В данном примере пользователь bga получает полномочия для
работы с портами. Пользователи из класса restricted таких
полномочий не имеют.

---
3. Устройство, указанное в переменной $_ports, должно иметь
достаточные права на чтение и/или запись для запускающего
пользователя.

$ ls -l /dev/lp0
crw-rw----    1 root     lp         6,   0 Сен 25 18:22 /dev/lp0

Поскольку такими правами обладает группа lp, добавим
пользователя bga к этой группе.

$ sudo vim /etc/group

lp:x:7:daemon,lp,bga

---
4. Установим бит SUID у dosemu:

$ sudo chmod u+s /usr/bin/dosemu.bin

Можно держать одновременно SUID и не-SUID версии dosemu.bin
и выбирать нужную непосредственно перед запуском.

---
5. Протестируем настройки:

$ dosemu -D9+iT
Running privileged (sudo/suid) in full feature mode

$ less ~/.dosemu/boot.log
...
CONF: range of I/O ports 0x0378-0x037a
PORT: allow_io for port 0x0378:3 perm=3 or=0 and=ff
PORT: range 0x0378-0x037a already registered as parport0
PORT: Device /dev/lp0 opened successfully = 6
PORT: registered "std port io" handle 0x01 [0x0378-0x037a] fd=138776120
...

Если запустить тестовую программу (см. ниже), то в boot.log
также будут записаны обращения к порту:
...
378 < 0
37a < 1
37a < 0
379 > 87
378 < 1
37a < 1
37a < 0
379 > 8f
...

---
6. Бывает нужен более быстрый доступ к портам, что соответствует
опции fast переменной $_ports:

$_ports = "device /dev/lp0 fast range 0x378 0x37a"

Тогда в ~/.dosemu/boot.log заносится:
...
CONF: range of I/O ports 0x0378-0x037a
PORT: allow_io for port 0x0378:3 perm=3 or=0 and=ff
PORT: range 0x0378-0x037a already registered as parport0
PORT: Device /dev/lp0 opened successfully = 6
PORT: registered "std port io" handle 0x01 [0x0378-0x037a] fd=138776320
PORT: giving fast access to ports [0x0378-0x037a]
nPORT: set_ioperm [378:3:1] returns 0
...
А обращения к портам уже не фиксируются.

---
7. Тест LPT-порта при помощи заглушки. 
Используется заглушка типа NDIAGS (см. также фото):

 *  2 <-> 15    (Data0 -> Error)
 *  3 <-> 13    (Data1 -> Offline)
 *  4 <-> 12    (Data2 -> No Paper)
 *  5 <-> 10    (Data3 -> Acknowledge)
 *  6 <-> 11    (Data4 -> Busy)

Прилагаю программу на C, комилировать для DOS при помощи
Turbo C 2.0:

tcc -Ic:\tc20 -Lc:\tc20 -DDOS port.c

для Линукса при помощи GCC:

gcc -g -Wall -O2 -DLINUX -o port port.c

Линукс-версия пригодится для проверки заглушки из Линукса:

$ sudo ./port 0x378
Using port 0x378
Testing for 'Error' (0x01)
Testing for 'Offline' (0x02)
Testing for 'No Paper' (0x04)
Testing for 'Acknowledge' (0x08)
Testing for 'Busy' (0x10)
All tests passed

В DOS:

C:\TMP>port 0x378
Using port 0x378
Testing for 'Error' (0x01)
Testing for 'Offline' (0x02)
Testing for 'No Paper' (0x04)
Testing for 'Acknowledge' (0x08)
Testing for 'Busy' (0x10)
All tests passed

Можно включить подробные сообщения программы ключом '-d'.

---
8. Если что-то не получилось, советую запустить dosemu с ключами
-D9+iT и подробнейшим образом изучить ~/.dosemu/boot.log.
После чего можно с чистой совестью просить о помощи в рассылке
community@ =).

---
9. Исправления и пожелания приветствуются.

-------------- next part --------------
/*
 *  (c) 2004 Grigory Batalov <bga at altlinux.ru>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  Test program for NDiags-type LPT plug.
 *
 *  Plug's pinout:
 *  2 <-> 15	(Data0 -> Error)
 *  3 <-> 13	(Data1 -> Offline)
 *  4 <-> 12	(Data2 -> No Paper)
 *  5 <-> 10	(Data3 -> Acknowledge)
 *  6 <-> 11	(Data4 -> Busy)
 *  (5 low bits of Data go to 5 high bits of Status)
 *
 *  Compile under DOS with Turbo C 2.0:
 *   tcc -Ic:\tc20 -Lc:\tc20 -DDOS port.c
 *
 *  Compile under Linux with GCC:
 *   gcc -g -Wall -O2 -DLINUX -o port port.c
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifdef LINUX
#	include <unistd.h>
#	include <sys/io.h>
#	define OUTB(a,b) outb(a,b)
#	define INB(a) inb(a)
#else
#	ifdef DOS
#		include <dos.h>
#		define OUTB(a,b) outportb(b,a)
#		define INB(a) inportb(a)
#	else
#		error "Define or -DLINUX either -DDOS"
#	endif
#endif

int test_byte(int base, int byte) {
	int before,after;
	/* send zero */
	OUTB(0, base);
	OUTB(1, base + 2);
	OUTB(0, base + 2);
	/* check status */
	before = INB(base + 1);

	/* send byte */
	OUTB(byte, base);
	OUTB(1, base+2);
	OUTB(0, base+2);
	/* get new status */
	after = INB(base + 1);

	/* calculate difference in status
	   as lower byte of (a XOR b) */
	return (after^before) & 0xff;
}

int main(int argc, char* argv[]) {
    int i,j, base, diff1,diff2, do_debug = 0;

    /* names for status bits */
    char *status[] = {	"Error",	/* bit 3 */
			"Offline",	/* bit 4 */
			"No Paper",	/* bit 5 */
			"Acknowledge",	/* bit 6 */
			"Busy" };	/* bit 7 */

    if (argc < 2 || (base = (int) strtol(argv[1], NULL, 0)) == 0) {
	printf ("Usage:\n %s <port> [-d]\n"
		" <port>\t\t - port number, example: 0x378\n"
		" -d\t\t - show debug messages\n",
		argv[0]);
	exit(1);
    }

    printf("Using port 0x%03x\n",base);

    if (argc > 2 && !strncmp(argv[2], "-d", 2))
	do_debug = 1;

#ifdef LINUX
    if (ioperm(base, 3, 1)) {
	perror("ioperm");
	exit(1);
    }
#endif

    for (i = 0; i < 5; i++) {
	printf ("Testing for '%s' (0x%02x)\n", status[i], 1<<i);

	for (j = 0; j < 1<<5; j++) {
	    /* test enabled bit */
	    diff1 = test_byte(base, j | (1<<i));

	    /* test disabled bit */
	    diff2 = test_byte(base, j & ~(1<<i));

	    if (do_debug)
		printf ("%02d) Sent 0x%02x, got 0x%02x; sent 0x%02x, got 0x%02x; difference: 0x%02x\n",
			j, j | (1<<i), diff1, j & ~(1<<i), diff2, diff1^diff2);

	    /* should differ in only status bit */
	    if ((diff1^diff2) != 1<<(i+3)) {
		printf ("Signal '%s' failed (sent 0x%02x, got 0x%02x, expected 0x%02x)\n",
			status[i], j | (1<<i), diff1, 1<<(i+3));
		exit(1);
	    }
	}
    }
    printf ("All tests passed\n");
    exit(0);
}




-------------- next part --------------
A non-text attachment was scrubbed...
Name: ndiags-plug.jpg
Type: image/jpeg
Size: 22744 bytes
Desc: not available
Url : /pipermail/community/attachments/20040223/4f0a5338/ndiags-plug-0001.jpg


Подробная информация о списке рассылки Community