static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, char* ptr) { /* FIXME: not perfect as it should bypass the in-queue */ WARN("(%p,'%c') not perfect!\n", hDevice, *ptr); if (write(fd, ptr, 1) != 1) return FILE_GetNtStatus(); return STATUS_SUCCESS; }
static NTSTATUS set_XOn(int fd) { struct termios port; if (tcgetattr(fd,&port) == -1) { FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno)); return FILE_GetNtStatus(); } port.c_iflag |= IXON; if (tcsetattr(fd, TCSADRAIN, &port) == -1) { FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno)); return FILE_GetNtStatus(); } return STATUS_SUCCESS; }
/* * does not change IXON but simulates that IXON has been received: */ static NTSTATUS set_XOn(int fd) { if (tcflow(fd, TCOON)) { return FILE_GetNtStatus(); } return STATUS_SUCCESS; }
static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st) { NTSTATUS status; struct termios port; unsigned int ux_timeout; SERVER_START_REQ( set_serial_info ) { req->handle = handle; req->flags = SERIALINFO_SET_TIMEOUTS; req->readinterval = st->ReadIntervalTimeout ; req->readmult = st->ReadTotalTimeoutMultiplier ; req->readconst = st->ReadTotalTimeoutConstant ; req->writemult = st->WriteTotalTimeoutMultiplier ; req->writeconst = st->WriteTotalTimeoutConstant ; status = wine_server_call( req ); } SERVER_END_REQ; if (status) return status; if (tcgetattr(fd, &port) == -1) { FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno)); return FILE_GetNtStatus(); } /* VTIME is in 1/10 seconds */ if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */ ux_timeout = 0; else { ux_timeout = (st->ReadIntervalTimeout + 99) / 100; if (ux_timeout == 0) ux_timeout = 1; /* must be at least some timeout */ } port.c_cc[VTIME] = ux_timeout; if (tcsetattr(fd, 0, &port) == -1) { FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno)); return FILE_GetNtStatus(); } return STATUS_SUCCESS; }
static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr) { struct termios port; int speed; if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } #ifndef __EMX__ #ifdef CBAUD speed = port.c_cflag & CBAUD; #else speed = cfgetospeed(&port); #endif switch (speed) { case B0: sbr->BaudRate = 0; break; case B50: sbr->BaudRate = 50; break; case B75: sbr->BaudRate = 75; break; case B110: sbr->BaudRate = 110; break; case B134: sbr->BaudRate = 134; break; case B150: sbr->BaudRate = 150; break; case B200: sbr->BaudRate = 200; break; case B300: sbr->BaudRate = 300; break; case B600: sbr->BaudRate = 600; break; case B1200: sbr->BaudRate = 1200; break; case B1800: sbr->BaudRate = 1800; break; case B2400: sbr->BaudRate = 2400; break; case B4800: sbr->BaudRate = 4800; break; case B9600: sbr->BaudRate = 9600; break; case B19200: sbr->BaudRate = 19200; break; case B38400: sbr->BaudRate = 38400; break; #ifdef B57600 case B57600: sbr->BaudRate = 57600; break; #endif #ifdef B115200 case B115200: sbr->BaudRate = 115200; break; #endif #ifdef B230400 case B230400: sbr->BaudRate = 230400; break; #endif #ifdef B460800 case B460800: sbr->BaudRate = 460800; break; #endif default: ERR("unknown speed %x\n", speed); return STATUS_INVALID_PARAMETER; } #else return STATUS_INVALID_PARAMETER; #endif return STATUS_SUCCESS; }
/*********************************************************************** * wine_server_handle_to_fd (NTDLL.@) * * Retrieve the file descriptor corresponding to a file handle. * * PARAMS * handle [I] Wine file handle. * access [I] Win32 file access rights requested. * unix_fd [O] Address where Unix file descriptor will be stored. * options [O] Address where the file open options will be stored. Optional. * * RETURNS * NTSTATUS code */ int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd, unsigned int *options ) { int needs_close, ret = server_get_unix_fd( handle, access, unix_fd, &needs_close, NULL, options ); if (!ret && !needs_close) { if ((*unix_fd = dup(*unix_fd)) == -1) ret = FILE_GetNtStatus(); } return ret; }
static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf) { int stat = 0; struct termios port; if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } /* termios does not support DTR/DSR flow control */ shf->ControlHandShake = 0; shf->FlowReplace = 0; #ifdef TIOCMGET if (ioctl(fd, TIOCMGET, &stat) == -1) { WARN("ioctl error '%s'\n", strerror(errno)); shf->ControlHandShake |= SERIAL_DTR_CONTROL; shf->FlowReplace |= SERIAL_RTS_CONTROL; } #else WARN("Setting DTR/RTS to enabled by default\n"); shf->ControlHandShake |= SERIAL_DTR_CONTROL; shf->FlowReplace |= SERIAL_RTS_CONTROL; #endif #ifdef TIOCM_DTR if (stat & TIOCM_DTR) #endif shf->ControlHandShake |= SERIAL_DTR_CONTROL; #ifdef CRTSCTS if (port.c_cflag & CRTSCTS) { shf->FlowReplace |= SERIAL_RTS_CONTROL; shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE; } else #endif { #ifdef TIOCM_RTS if (stat & TIOCM_RTS) #endif shf->FlowReplace |= SERIAL_RTS_CONTROL; } if (port.c_iflag & IXOFF) shf->FlowReplace |= SERIAL_AUTO_RECEIVE; if (port.c_iflag & IXON) shf->FlowReplace |= SERIAL_AUTO_TRANSMIT; shf->XonLimit = 10; shf->XoffLimit = 10; return STATUS_SUCCESS; }
static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc) { struct termios port; if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } port.c_cc[VEOF ] = sc->EofChar; /* FIXME: sc->ErrorChar is not supported */ /* FIXME: sc->BreakChar is not supported */ /* FIXME: sc->EventChar is not supported */ port.c_cc[VSTART] = sc->XonChar; port.c_cc[VSTOP ] = sc->XoffChar; if (tcsetattr(fd, TCSANOW, &port) == -1) { ERR("tcsetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } return STATUS_SUCCESS; }
/*********************************************************************** * Get extended interrupt count info, needed for wait_on */ static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info) { int out; #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCGICOUNT) struct serial_icounter_struct einfo; if (!ioctl(fd, TIOCGICOUNT, &einfo)) { irq_info->rx = einfo.rx; irq_info->tx = einfo.tx; irq_info->frame = einfo.frame; irq_info->overrun = einfo.overrun; irq_info->parity = einfo.parity; irq_info->brk = einfo.brk; irq_info->buf_overrun = einfo.buf_overrun; } else { TRACE("TIOCGICOUNT err %s\n", strerror(errno)); memset(irq_info,0, sizeof(serial_irq_info)); } #else memset(irq_info,0, sizeof(serial_irq_info)); #endif irq_info->temt = 0; /* Generate a single TX_TXEMPTY event when the TX Buffer turns empty*/ #ifdef TIOCSERGETLSR /* prefer to log the state TIOCSERGETLSR */ if (!ioctl(fd, TIOCSERGETLSR, &out)) { irq_info->temt = (out & TIOCSER_TEMT) != 0; return STATUS_SUCCESS; } TRACE("TIOCSERGETLSR err %s\n", strerror(errno)); #endif #ifdef TIOCOUTQ /* otherwise we log when the out queue gets empty */ if (!ioctl(fd, TIOCOUTQ, &out)) { irq_info->temt = out == 0; return STATUS_SUCCESS; } TRACE("TIOCOUTQ err %s\n", strerror(errno)); return FILE_GetNtStatus(); #endif return STATUS_SUCCESS; }
static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc) { struct termios port; if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } #ifdef CMSPAR switch (port.c_cflag & (PARENB | PARODD | CMSPAR)) #else switch (port.c_cflag & (PARENB | PARODD)) #endif { case 0: slc->Parity = NOPARITY; break; case PARENB: slc->Parity = EVENPARITY; break; case PARENB|PARODD: slc->Parity = ODDPARITY; break; #ifdef CMSPAR case PARENB|CMSPAR: slc->Parity = MARKPARITY; break; case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break; break; #endif } switch (port.c_cflag & CSIZE) { case CS5: slc->WordLength = 5; break; case CS6: slc->WordLength = 6; break; case CS7: slc->WordLength = 7; break; case CS8: slc->WordLength = 8; break; default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE)); } if (port.c_cflag & CSTOPB) { if (slc->WordLength == 5) slc->StopBits = ONE5STOPBITS; else slc->StopBits = TWOSTOPBITS; } else slc->StopBits = ONESTOPBIT; return STATUS_SUCCESS; }
static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc) { struct termios port; if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } sc->EofChar = port.c_cc[VEOF]; sc->ErrorChar = 0xFF; sc->BreakChar = 0; /* FIXME */ sc->EventChar = 0; /* FIXME */ sc->XonChar = port.c_cc[VSTART]; sc->XoffChar = port.c_cc[VSTOP]; return STATUS_SUCCESS; }
/*********************************************************************** * Get extended interrupt count info, needed for wait_on */ static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info) { NTSTATUS status = STATUS_NOT_IMPLEMENTED; #ifdef TIOCGICOUNT struct serial_icounter_struct einfo; if (!ioctl(fd, TIOCGICOUNT, &einfo)) { irq_info->rx = einfo.rx; irq_info->tx = einfo.tx; irq_info->frame = einfo.frame; irq_info->overrun = einfo.overrun; irq_info->parity = einfo.parity; irq_info->brk = einfo.brk; irq_info->buf_overrun = einfo.buf_overrun; return STATUS_SUCCESS; } TRACE("TIOCGICOUNT err %s\n", strerror(errno)); status = FILE_GetNtStatus(); #endif memset(irq_info,0, sizeof(serial_irq_info)); return status; }
static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat) { NTSTATUS status = STATUS_SUCCESS; int mstat; #ifdef TIOCMGET if (ioctl(fd, TIOCMGET, &mstat) == -1) { WARN("ioctl failed\n"); status = FILE_GetNtStatus(); } else { *lpModemStat = 0; #ifdef TIOCM_CTS if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON; #endif #ifdef TIOCM_DSR if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON; #endif #ifdef TIOCM_RNG if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON; #endif #ifdef TIOCM_CAR /* FIXME: Not really sure about RLSD UB 990810 */ if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON; #endif TRACE("%04x -> %s%s%s%s\n", mstat, (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "", (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "", (*lpModemStat & MS_DSR_ON) ? "MS_DSR_ON " : "", (*lpModemStat & MS_CTS_ON) ? "MS_CTS_ON " : ""); } #else status = STATUS_NOT_SUPPORTED; #endif return status; }
static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc) { struct termios port; unsigned bytesize, stopbits; if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } #ifdef IMAXBEL port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL); #else port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK); #endif port.c_iflag |= IGNBRK | INPCK; port.c_oflag &= ~(OPOST); port.c_cflag &= ~(HUPCL); port.c_cflag |= CLOCAL | CREAD; /* * on FreeBSD, turning off ICANON does not disable IEXTEN, * so we must turn it off explicitly. No harm done on Linux. */ port.c_lflag &= ~(ICANON|ECHO|ISIG|IEXTEN); port.c_lflag |= NOFLSH; bytesize = slc->WordLength; stopbits = slc->StopBits; #ifdef CMSPAR port.c_cflag &= ~(PARENB | PARODD | CMSPAR); #else port.c_cflag &= ~(PARENB | PARODD); #endif /* make sure that reads don't block */ port.c_cc[VMIN] = 0; port.c_cc[VTIME] = 0; switch (slc->Parity) { case NOPARITY: port.c_iflag &= ~INPCK; break; case ODDPARITY: port.c_cflag |= PARENB | PARODD; break; case EVENPARITY: port.c_cflag |= PARENB; break; #ifdef CMSPAR /* Linux defines mark/space (stick) parity */ case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break; case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break; #else /* try the POSIX way */ case MARKPARITY: if (slc->StopBits == ONESTOPBIT) { stopbits = TWOSTOPBITS; port.c_iflag &= ~INPCK; } else { FIXME("Cannot set MARK Parity\n"); return STATUS_NOT_SUPPORTED; } break; case SPACEPARITY: if (slc->WordLength < 8) { bytesize +=1; port.c_iflag &= ~INPCK; } else { FIXME("Cannot set SPACE Parity\n"); return STATUS_NOT_SUPPORTED; } break; #endif default: FIXME("Parity %d is not supported\n", slc->Parity); return STATUS_NOT_SUPPORTED; } port.c_cflag &= ~CSIZE; switch (bytesize) { case 5: port.c_cflag |= CS5; break; case 6: port.c_cflag |= CS6; break; case 7: port.c_cflag |= CS7; break; case 8: port.c_cflag |= CS8; break; default: FIXME("ByteSize %d is not supported\n", bytesize); return STATUS_NOT_SUPPORTED; } switch (stopbits) { case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break; case ONE5STOPBITS: /* will be selected if bytesize is 5 */ case TWOSTOPBITS: port.c_cflag |= CSTOPB; break; default: FIXME("StopBits %d is not supported\n", stopbits); return STATUS_NOT_SUPPORTED; } /* otherwise it hangs with pending input*/ if (tcsetattr(fd, TCSANOW, &port) == -1) { ERR("tcsetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } return STATUS_SUCCESS; }
static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr) { struct termios port; if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } switch (sbr->BaudRate) { case 0: cfsetospeed( &port, B0 ); break; case 50: cfsetospeed( &port, B50 ); break; case 75: cfsetospeed( &port, B75 ); break; case 110: case CBR_110: cfsetospeed( &port, B110 ); break; case 134: cfsetospeed( &port, B134 ); break; case 150: cfsetospeed( &port, B150 ); break; case 200: cfsetospeed( &port, B200 ); break; case 300: case CBR_300: cfsetospeed( &port, B300 ); break; case 600: case CBR_600: cfsetospeed( &port, B600 ); break; case 1200: case CBR_1200: cfsetospeed( &port, B1200 ); break; case 1800: cfsetospeed( &port, B1800 ); break; case 2400: case CBR_2400: cfsetospeed( &port, B2400 ); break; case 4800: case CBR_4800: cfsetospeed( &port, B4800 ); break; case 9600: case CBR_9600: cfsetospeed( &port, B9600 ); break; case 19200: case CBR_19200: cfsetospeed( &port, B19200 ); break; case 38400: case CBR_38400: cfsetospeed( &port, B38400 ); break; #ifdef B57600 case 57600: cfsetospeed( &port, B57600 ); break; #endif #ifdef B115200 case 115200: cfsetospeed( &port, B115200 ); break; #endif #ifdef B230400 case 230400: cfsetospeed( &port, B230400 ); break; #endif #ifdef B460800 case 460800: cfsetospeed( &port, B460800 ); break; #endif #ifdef B500000 case 500000: cfsetospeed( &port, B500000 ); break; #endif #ifdef B921600 case 921600: cfsetospeed( &port, B921600 ); break; #endif #ifdef B1000000 case 1000000: cfsetospeed( &port, B1000000 ); break; #endif #ifdef B1152000 case 1152000: cfsetospeed( &port, B1152000 ); break; #endif #ifdef B1500000 case 1500000: cfsetospeed( &port, B1500000 ); break; #endif #ifdef B2000000 case 2000000: cfsetospeed( &port, B2000000 ); break; #endif #ifdef B2500000 case 2500000: cfsetospeed( &port, B2500000 ); break; #endif #ifdef B3000000 case 3000000: cfsetospeed( &port, B3000000 ); break; #endif #ifdef B3500000 case 3500000: cfsetospeed( &port, B3500000 ); break; #endif #ifdef B4000000 case 4000000: cfsetospeed( &port, B4000000 ); break; #endif default: #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL) { struct serial_struct nuts; int arby; ioctl(fd, TIOCGSERIAL, &nuts); nuts.custom_divisor = nuts.baud_base / sbr->BaudRate; if (!(nuts.custom_divisor)) nuts.custom_divisor = 1; arby = nuts.baud_base / nuts.custom_divisor; nuts.flags &= ~ASYNC_SPD_MASK; nuts.flags |= ASYNC_SPD_CUST; WARN("You (or a program acting at your behest) have specified\n" "a non-standard baud rate %d. Wine will set the rate to %d,\n" "which is as close as we can get by our present understanding of your\n" "hardware. I hope you know what you are doing. Any disruption Wine\n" "has caused to your linux system can be undone with setserial\n" "(see man setserial). If you have incapacitated a Hayes type modem,\n" "reset it and it will probably recover.\n", sbr->BaudRate, arby); ioctl(fd, TIOCSSERIAL, &nuts); cfsetospeed( &port, B38400 ); } break; #else /* Don't have linux/serial.h or lack TIOCSSERIAL */ ERR("baudrate %d\n", sbr->BaudRate); return STATUS_NOT_SUPPORTED; #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */ } cfsetispeed( &port, cfgetospeed(&port) ); if (tcsetattr(fd, TCSANOW, &port) == -1) { ERR("tcsetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } return STATUS_SUCCESS; }
/****************************************************************** * COMM_DeviceIoControl * * */ NTSTATUS COMM_DeviceIoControl(HANDLE hDevice, HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine, PVOID UserApcContext, PIO_STATUS_BLOCK piosb, ULONG dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize) { DWORD sz = 0, access = FILE_READ_DATA; NTSTATUS status = STATUS_SUCCESS; int fd = -1; TRACE("%p %s %p %ld %p %ld %p\n", hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, piosb); piosb->Information = 0; if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS) if ((status = wine_server_handle_to_fd( hDevice, access, &fd, NULL ))) goto error; switch (dwIoControlCode) { case IOCTL_SERIAL_CLR_DTR: #ifdef TIOCM_DTR if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus(); #else status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_CLR_RTS: #ifdef TIOCM_RTS if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus(); #else status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_GET_BAUD_RATE: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE)) { if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer))) sz = sizeof(SERIAL_BAUD_RATE); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_CHARS: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS)) { if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer))) sz = sizeof(SERIAL_CHARS); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_COMMSTATUS: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS)) { if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer))) sz = sizeof(SERIAL_STATUS); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_HANDFLOW: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW)) { if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer))) sz = sizeof(SERIAL_HANDFLOW); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_LINE_CONTROL: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL)) { if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer))) sz = sizeof(SERIAL_LINE_CONTROL); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_MODEMSTATUS: if (lpOutBuffer && nOutBufferSize == sizeof(DWORD)) { if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer))) sz = sizeof(DWORD); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_TIMEOUTS: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS)) { if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer))) sz = sizeof(SERIAL_TIMEOUTS); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_WAIT_MASK: if (lpOutBuffer && nOutBufferSize == sizeof(DWORD)) { if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer))) sz = sizeof(DWORD); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_IMMEDIATE_CHAR: if (lpInBuffer && nInBufferSize == sizeof(CHAR)) status = xmit_immediate(hDevice, fd, lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_PURGE: if (lpInBuffer && nInBufferSize == sizeof(DWORD)) status = purge(fd, *(DWORD*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_RESET_DEVICE: FIXME("Unsupported\n"); break; case IOCTL_SERIAL_SET_BAUD_RATE: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE)) status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_BREAK_OFF: #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */ if (ioctl(fd, TIOCCBRK, 0) == -1) { TRACE("ioctl failed\n"); status = FILE_GetNtStatus(); } #else FIXME("ioctl not available\n"); status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_SET_BREAK_ON: #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */ if (ioctl(fd, TIOCSBRK, 0) == -1) { TRACE("ioctl failed\n"); status = FILE_GetNtStatus(); } #else FIXME("ioctl not available\n"); status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_SET_CHARS: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS)) status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_DTR: #ifdef TIOCM_DTR if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus(); #else status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_SET_HANDFLOW: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW)) status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_LINE_CONTROL: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL)) status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_QUEUE_SIZE: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE)) status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_RTS: #ifdef TIOCM_RTS if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus(); #else status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_SET_TIMEOUTS: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS)) status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_WAIT_MASK: if (lpInBuffer && nInBufferSize == sizeof(DWORD)) { status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_XOFF: status = set_XOff(fd); break; case IOCTL_SERIAL_SET_XON: status = set_XOn(fd); break; default: FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n", dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3, (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3); sz = 0; status = STATUS_INVALID_PARAMETER; break; } if (fd != -1) wine_server_release_fd( hDevice, fd ); error: piosb->u.Status = status; piosb->Information = sz; if (hEvent) NtSetEvent(hEvent, NULL); return status; }
static inline NTSTATUS TAPE_GetStatus( int error ) { if (!error) return STATUS_SUCCESS; return FILE_GetNtStatus(); }
/****************************************************************** * TAPE_DeviceIoControl * * SEE ALSO * NtDeviceIoControl. */ NTSTATUS TAPE_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_user, PIO_STATUS_BLOCK io_status, ULONG io_control, LPVOID in_buffer, DWORD in_size, LPVOID out_buffer, DWORD out_size ) { DWORD sz = 0; NTSTATUS status = STATUS_INVALID_PARAMETER; int fd, needs_close; TRACE( "%p %s %p %d %p %d %p\n", device, io2str(io_control), in_buffer, in_size, out_buffer, out_size, io_status ); io_status->Information = 0; if ((status = server_get_unix_fd( device, 0, &fd, &needs_close, NULL, NULL ))) goto error; switch (io_control) { case IOCTL_TAPE_CREATE_PARTITION: status = TAPE_CreatePartition( fd, in_buffer ); break; case IOCTL_TAPE_ERASE: status = TAPE_Erase( fd, in_buffer ); break; case IOCTL_TAPE_GET_DRIVE_PARAMS: status = TAPE_GetDriveParams( fd, out_buffer ); break; case IOCTL_TAPE_GET_MEDIA_PARAMS: status = TAPE_GetMediaParams( fd, out_buffer ); break; case IOCTL_TAPE_GET_POSITION: status = TAPE_GetPosition( fd, ((TAPE_GET_POSITION *)in_buffer)->Type, out_buffer ); break; case IOCTL_TAPE_GET_STATUS: status = FILE_GetNtStatus(); break; case IOCTL_TAPE_PREPARE: status = TAPE_Prepare( fd, in_buffer ); break; case IOCTL_TAPE_SET_DRIVE_PARAMS: status = TAPE_SetDriveParams( fd, in_buffer ); break; case IOCTL_TAPE_SET_MEDIA_PARAMS: status = TAPE_SetMediaParams( fd, in_buffer ); break; case IOCTL_TAPE_SET_POSITION: status = TAPE_SetPosition( fd, in_buffer ); break; case IOCTL_TAPE_WRITE_MARKS: status = TAPE_WriteMarks( fd, in_buffer ); break; case IOCTL_TAPE_CHECK_VERIFY: case IOCTL_TAPE_FIND_NEW_DEVICES: break; default: FIXME( "Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n", io_control, io_control >> 16, (io_control >> 14) & 3, (io_control >> 2) & 0xfff, io_control & 3 ); break; } if (needs_close) close( fd ); error: io_status->u.Status = status; io_status->Information = sz; if (event) NtSetEvent( event, NULL ); return status; }