static int set_termios(struct tty_struct * tty, unsigned long arg, int opt) { struct termios tmp_termios; int retval = tty_check_change(tty); if (retval) return retval; if (opt & TERMIOS_TERMIO) { memcpy(&tmp_termios, tty->termios, sizeof(struct termios)); if (user_termio_to_kernel_termios(&tmp_termios, (struct termio *) arg)) return -EFAULT; } else { if (user_termios_to_kernel_termios(&tmp_termios, (struct termios *) arg)) return -EFAULT; } if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) return -EINTR; } change_termios(tty, &tmp_termios); return 0; }
static int set_termios(struct tty_struct * tty, void __user *arg, int opt) { struct termios tmp_termios; struct tty_ldisc *ld; int retval = tty_check_change(tty); if (retval) return retval; if (opt & TERMIOS_TERMIO) { memcpy(&tmp_termios, tty->termios, sizeof(struct termios)); if (user_termio_to_kernel_termios(&tmp_termios, (struct termio __user *)arg)) return -EFAULT; } else { if (user_termios_to_kernel_termios(&tmp_termios, (struct termios __user *)arg)) return -EFAULT; } ld = tty_ldisc_ref(tty); if (ld != NULL) { if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) ld->flush_buffer(tty); tty_ldisc_deref(ld); } if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) return -EINTR; } change_termios(tty, &tmp_termios); return 0; }
int n_tty_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) { struct tty_struct * real_tty; int retval; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) real_tty = tty->link; else real_tty = tty; switch (cmd) { #ifdef TIOCGETP case TIOCGETP: return get_sgttyb(real_tty, (struct sgttyb *) arg); case TIOCSETP: case TIOCSETN: return set_sgttyb(real_tty, (struct sgttyb *) arg); #endif #ifdef TIOCGETC case TIOCGETC: return get_tchars(real_tty, (struct tchars *) arg); case TIOCSETC: return set_tchars(real_tty, (struct tchars *) arg); #endif #ifdef TIOCGLTC case TIOCGLTC: return get_ltchars(real_tty, (struct ltchars *) arg); case TIOCSLTC: return set_ltchars(real_tty, (struct ltchars *) arg); #endif case TCGETS: if (kernel_termios_to_user_termios((struct termios *)arg, real_tty->termios)) return -EFAULT; return 0; case TCSETSF: return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_WAIT); case TCSETSW: return set_termios(real_tty, arg, TERMIOS_WAIT); case TCSETS: return set_termios(real_tty, arg, 0); case TCGETA: return get_termio(real_tty,(struct termio *) arg); case TCSETAF: return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO); case TCSETAW: return set_termios(real_tty, arg, TERMIOS_WAIT | TERMIOS_TERMIO); case TCSETA: return set_termios(real_tty, arg, TERMIOS_TERMIO); case TCXONC: retval = tty_check_change(tty); if (retval) return retval; switch (arg) { case TCOOFF: if (!tty->flow_stopped) { tty->flow_stopped = 1; stop_tty(tty); } break; case TCOON: if (tty->flow_stopped) { tty->flow_stopped = 0; start_tty(tty); } break; case TCIOFF: if (STOP_CHAR(tty) != __DISABLED_CHAR) send_prio_char(tty, STOP_CHAR(tty)); break; case TCION: if (START_CHAR(tty) != __DISABLED_CHAR) send_prio_char(tty, START_CHAR(tty)); break; default: return -EINVAL; } return 0; case TCFLSH: retval = tty_check_change(tty); if (retval) return retval; switch (arg) { case TCIFLUSH: if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); break; case TCIOFLUSH: if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); /* fall through */ case TCOFLUSH: if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); break; default: return -EINVAL; } return 0; case TIOCOUTQ: return put_user(tty->driver->chars_in_buffer ? tty->driver->chars_in_buffer(tty) : 0, (int *) arg); case TIOCINQ: retval = tty->read_cnt; if (L_ICANON(tty)) retval = inq_canon(tty); return put_user(retval, (unsigned int *) arg); case TIOCGLCKTRMIOS: if (kernel_termios_to_user_termios((struct termios *)arg, real_tty->termios_locked)) return -EFAULT; return 0; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios *) arg)) return -EFAULT; return 0; case TIOCPKT: { int pktmode; if (tty->driver->type != TTY_DRIVER_TYPE_PTY || tty->driver->subtype != PTY_TYPE_MASTER) return -ENOTTY; if (get_user(pktmode, (int *) arg)) return -EFAULT; if (pktmode) { if (!tty->packet) { tty->packet = 1; tty->link->ctrl_status = 0; } } else tty->packet = 0; return 0; } case TIOCGSOFTCAR: return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); case TIOCSSOFTCAR: if (get_user(arg, (unsigned int *) arg)) return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; default: return -ENOIOCTLCMD; } }
static int kobil_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) { struct kobil_private * priv; int result; unsigned short urb_val = 0; unsigned char *transfer_buffer; int transfer_buffer_length = 8; char *settings; void __user *user_arg = (void __user *)arg; priv = usb_get_serial_port_data(port); if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { // This device doesn't support ioctl calls return 0; } switch (cmd) { case TCGETS: // 0x5401 if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } if (kernel_termios_to_user_termios((struct termios __user *)arg, &priv->internal_termios)) return -EFAULT; return 0; case TCSETS: // 0x5402 if (!(port->tty->termios)) { dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); return -ENOTTY; } if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } if (user_termios_to_kernel_termios(&priv->internal_termios, (struct termios __user *)arg)) return -EFAULT; settings = (unsigned char *) kmalloc(50, GFP_KERNEL); if (! settings) { return -ENOBUFS; } memset(settings, 0, 50); switch (priv->internal_termios.c_cflag & CBAUD) { case B1200: urb_val = SUSBCR_SBR_1200; strcat(settings, "1200 "); break; case B9600: default: urb_val = SUSBCR_SBR_9600; strcat(settings, "9600 "); break; } urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit "); if (priv->internal_termios.c_cflag & PARENB) { if (priv->internal_termios.c_cflag & PARODD) { urb_val |= SUSBCR_SPASB_OddParity; strcat(settings, "Odd Parity"); } else { urb_val |= SUSBCR_SPASB_EvenParity; strcat(settings, "Even Parity"); } } else { urb_val |= SUSBCR_SPASB_NoParity; strcat(settings, "No Parity"); } dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings ); result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), SUSBCRequest_SetBaudRateParityAndStopBits, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, urb_val, 0, settings, 0, KOBIL_TIMEOUT ); dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result); kfree(settings); return 0; case TCFLSH: // 0x540B transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { return -ENOBUFS; } result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), SUSBCRequest_Misc, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, SUSBCR_MSC_ResetAllQueues, 0, NULL,//transfer_buffer, 0, KOBIL_TIMEOUT ); dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result); kfree(transfer_buffer); return ((result < 0) ? -EFAULT : 0); } return -ENOIOCTLCMD; }
/* the real citty_ioctl function. * The above is done to get the small functions*/ static int citty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct file *file = NULL; F_ENTER(); switch (cmd) { case TIOCGSERIAL: return citty_ioctl_tiocgserial(tty, file, cmd, arg); case TIOCMIWAIT: return citty_ioctl_tiocmiwait(tty, file, cmd, arg); case TIOCGICOUNT: return citty_ioctl_tiocgicount(tty, file, cmd, arg); #ifndef TCGETS2 case TCSETS: if (user_termios_to_kernel_termios(&tty->termios, (struct termios __user *) arg)) return -EFAULT; else return 0; case TCGETS: if (kernel_termios_to_user_termios( (struct termios __user *)arg, &tty->termios)) return -EFAULT; else return 0; #else case TCSETS: if (user_termios_to_kernel_termios_1(&tty->termios, (struct termios __user *) arg)) return -EFAULT; else return 0; case TCSETS2: if (user_termios_to_kernel_termios(&tty->termios, (struct termios2 __user *) arg)) return -EFAULT; else return 0; case TCGETS: if (kernel_termios_to_user_termios_1( (struct termios __user *)arg, &tty->termios)) return -EFAULT; else return 0; case TCGETS2: if (kernel_termios_to_user_termios( (struct termios2 __user *)arg, &tty->termios)) return -EFAULT; else return 0; #endif case TCSETSF: /* 0x5404 */ case TCSETAF: /* 0x5408 */ return 0; /* has to return zero for qtopia to work */ default: PDEBUG("citty_ioctl cmd: %d.\n", cmd); return -ENOIOCTLCMD; /* for PPPD to work? */ break; } F_LEAVE(); }