Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 18.4. ioctls

Оглавление
Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

18.4. ioctls

hardorsoft 26.10.10 в 06:43

0

Функция ioctls в структуре tty_driver вызывается ядром tty-
устройств, когда происходит вызов ioctls(2) для node устройства. Если
драйвер не знает какие выполнить действия для переданного значения
параметра он должен вернуть значение -ENOIOCTLCMD, чтобы ядро само
попыталось реализовать работу этого вызова.
В ядре 2.6 определены около 70 значений, передаваемых в функцию
ioctls tty-драйвера. Большинство tty-драйверов не обрабатывают их все, а
только небольшое количество общепринятых. Здесь приведен список
наиболее популярных, затем рассказано, как их обрабатывать:

hardorsoft 26.10.10 в 06:44

0

TIOCSERGETLSR

hardorsoft 26.10.10 в 06:44

0

Получить значение регистра состояния линии (LSR - line status
register)

hardorsoft 26.10.10 в 06:44

0

TIOCGSERIAL

hardorsoft 26.10.10 в 06:44

0

Получение информации о последовательной линии. Вызвавший
потенциально может получить большое количество информации от
tty-устройства за один вызов. Некоторые программы (такие как
setserial и dip) вызывают эту функцию чтобы убедится, что
скорость передачи установлена и для получения основной
информации об устройстве. При вызове передается указатель на
большую структуру типа serial_struct, которую tty-драйвер
заполняет соответствующими значениями. Вот пример реализации
этого:

hardorsoft 26.10.10 в 06:45

0

static int tiny_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct tiny_serial *tiny = tty->driver_data;
if (cmd = = TIOCGSERIAL) {
struct serial_struct tmp;
if (!arg)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = tiny->serial.type;
tmp.line = tiny->serial.line;
tmp.port = tiny->serial.port;
tmp.irq = tiny->serial.irq;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = tiny->serial.xmit_fifo_size;
tmp.baud_base = tiny->serial.baud_base;
tmp.close_delay = 5*HZ;
tmp.closing_wait = 30*HZ;
tmp.custom_divisor = tiny->serial.custom_divisor;
tmp.hub6 = tiny->serial.hub6;
tmp.io_type = tiny->serial.io_type;
if (copy_to_user((void __user *)arg, &tmp, sizeof(tmp)))
return -EFAULT;
return 0;
}
return -ENOIOCTLCMD;
}

hardorsoft 26.10.10 в 06:45

0

TIOCSSERIAL

hardorsoft 26.10.10 в 06:45

0

Установка информации о последовательной линии. Операция
противоположна TIOCGSERIAL, и позволяет пользователю сразу
установить статус последовательной линии tty-устройства. В
функцию передается указатель на структуру struct serial_struct,
содержащую устанавливаемые параметры. Большинство программ
нормально работают, если данную возможность не реализовать.

hardorsoft 26.10.10 в 06:46

0

TIOCMIWAIT

hardorsoft 26.10.10 в 06:46

0

Ожидает изменения MSR. Пользователь редко дает этот запрос в
ioctls, функция ожидает, пока значение регистра MSR не
изменится. Параметр arg содержит тип ожидаемого события.
Обычно используется при ожидании изменения статуса линии,
говорящего, что устройство готово принимать данные.

hardorsoft 26.10.10 в 06:46

0

Аккуратно реализуйте эту функцию, и не используйте
interruptible_sleep_on, это не безопасно в этом случае могут
возникнуть гонки. Вместо этого используйте wait_queue. Приведем
пример:

hardorsoft 26.10.10 в 06:47

0

static int tiny_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct tiny_serial *tiny = tty->driver_data;
if (cmd = = TIOCMIWAIT) {
DECLARE_WAITQUEUE(wait, current);
struct async_icount cnow;
struct async_icount cprev;
cprev = tiny->icount;
while (1) {
add_wait_queue(&tiny->wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule( );
remove_wait_queue(&tiny->wait, &wait);
/* see if a signal woke us up */
if (signal_pending(current))
return -ERESTARTSYS;
cnow = tiny->icount;
if (cnow.rng = = cprev.rng && cnow.dsr = = cprev.dsr &&
cnow.dcd = = cprev.dcd && cnow.cts = = cprev.cts)
return -EIO; /* no change => error */
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
return 0;
}
cprev = cnow;
}
}
return -ENOIOCTLCMD;
}

hardorsoft 26.10.10 в 06:47

0

Чтобы этот код работал должным образом, tty-драйверу необходимо
в каком-либо месте, при изменении регистра MSR, выполнить
функцию:

hardorsoft 26.10.10 в 06:47

0

TIOCGICOUNT

hardorsoft 26.10.10 в 06:47

0

Получить счетчик прерываний. Этот вызов происходит, когда
пользователю требуется узнать, сколько произошло прерываний от
последовательной линии. Если у драйвера есть обработчик
прерывания, драйвер должен определить структуру, для ведения
этой статистики, и увеличивать соответствующий счетчик при
каждом вызове обработчика.

hardorsoft 26.10.10 в 06:48

0

В функцию ioctls передается указатель на структуру
serial_icounter_struct, которая заполняется tty-драйвером. Этот
вызов часто делается совместно с предыдущим вызовом TIOCMIWAIT.
Если при работе tty-драйвера отслеживаются все прерывания, то
реализующий этот вызов код может быть очень простым:

hardorsoft 26.10.10 в 06:48

0

static int tiny_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct tiny_serial *tiny = tty->driver_data;
if (cmd = = TIOCGICOUNT) {
struct async_icount cnow = tiny->icount;
struct serial_icounter_struct icount;
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
icount.dcd = cnow.dcd;
icount.rx = cnow.rx;
icount.tx = cnow.tx;
icount.frame = cnow.frame;
icount.overrun = cnow.overrun;
icount.parity = cnow.parity;
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
return -EFAULT;
return 0;
}
return -ENOIOCTLCMD;
}

hardorsoft 26.10.10 в 06:48

0
Минутку...