Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
|
|
Функция ioctls в структуре tty_driver вызывается ядром tty- устройств, когда происходит вызов ioctls(2) для node устройства. Если драйвер не знает какие выполнить действия для переданного значения параметра он должен вернуть значение -ENOIOCTLCMD, чтобы ядро само попыталось реализовать работу этого вызова. В ядре 2.6 определены около 70 значений, передаваемых в функцию ioctls tty-драйвера. Большинство tty-драйверов не обрабатывают их все, а только небольшое количество общепринятых. Здесь приведен список наиболее популярных, затем рассказано, как их обрабатывать:
hardorsoft
26.10.10 в 06:44
|
|
|
|
|
Получить значение регистра состояния линии (LSR - line status register)
hardorsoft
26.10.10 в 06:44
|
|
|
|
|
Получение информации о последовательной линии. Вызвавший потенциально может получить большое количество информации от tty-устройства за один вызов. Некоторые программы (такие как setserial и dip) вызывают эту функцию чтобы убедится, что скорость передачи установлена и для получения основной информации об устройстве. При вызове передается указатель на большую структуру типа serial_struct, которую tty-драйвер заполняет соответствующими значениями. Вот пример реализации этого:
hardorsoft
26.10.10 в 06:45
|
|
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
|
|
|
|
|
Установка информации о последовательной линии. Операция противоположна TIOCGSERIAL, и позволяет пользователю сразу установить статус последовательной линии tty-устройства. В функцию передается указатель на структуру struct serial_struct, содержащую устанавливаемые параметры. Большинство программ нормально работают, если данную возможность не реализовать.
hardorsoft
26.10.10 в 06:46
|
|
|
|
|
Ожидает изменения MSR. Пользователь редко дает этот запрос в ioctls, функция ожидает, пока значение регистра MSR не изменится. Параметр arg содержит тип ожидаемого события. Обычно используется при ожидании изменения статуса линии, говорящего, что устройство готово принимать данные.
hardorsoft
26.10.10 в 06:46
|
|
Аккуратно реализуйте эту функцию, и не используйте interruptible_sleep_on, это не безопасно в этом случае могут возникнуть гонки. Вместо этого используйте wait_queue. Приведем пример:
hardorsoft
26.10.10 в 06:47
|
|
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
|
|
Чтобы этот код работал должным образом, tty-драйверу необходимо в каком-либо месте, при изменении регистра MSR, выполнить функцию:
hardorsoft
26.10.10 в 06:47
|
|
|
|
|
Получить счетчик прерываний. Этот вызов происходит, когда пользователю требуется узнать, сколько произошло прерываний от последовательной линии. Если у драйвера есть обработчик прерывания, драйвер должен определить структуру, для ведения этой статистики, и увеличивать соответствующий счетчик при каждом вызове обработчика.
hardorsoft
26.10.10 в 06:48
|
|
В функцию ioctls передается указатель на структуру serial_icounter_struct, которая заполняется tty-драйвером. Этот вызов часто делается совместно с предыдущим вызовом TIOCMIWAIT. Если при работе tty-драйвера отслеживаются все прерывания, то реализующий этот вызов код может быть очень простым:
hardorsoft
26.10.10 в 06:48
|
|
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
|
|