// File: /workspace/github_c_makefile_star2_O2/j-hoppe[P]tu58fs/serial.c
// Function: serial_devinit
void serial_devinit(serial_device_t *serial, char *port, int32_t speed, int32_t databits,
		char parity, int32_t stopbits) {
	serial->rx_lasttime_ms = 0;
	serial->tx_lasttime_ms = 0;

	// init unix serial port mode
	struct termios line;
	char name[64];
	unsigned int n;

	serial->baudrate = speed;
	serial->bitcount = 1 + databits + stopbits; // total bit count

	// open serial port
	int32_t euid = geteuid();
	int32_t uid = getuid();
	setreuid(euid, -1);
	if (sscanf(port, "%u", &n) == 1)
		sprintf(name, "/dev/ttyS%u", n - 1);
	else
		strcpy(name, port);
	if ((serial->fd = open(name, O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
		fatal("no serial line [%s]", name);
	setreuid(uid, euid);

	// get current line params, error if not a serial port
	if (tcgetattr(serial->fd, &serial->lineSave))
		fatal("not a serial device [%s]", name);

	// copy current parameters
	line = serial->lineSave;

	// input param
	line.c_iflag &= ~( IGNBRK | BRKINT | IMAXBEL | INPCK | ISTRIP |
	INLCR | IGNCR | ICRNL | IXON | IXOFF |
	IUCLC | IXANY | PARMRK | IGNPAR);
	line.c_iflag |= (0);

	// output param
	line.c_oflag &= ~( OPOST | OLCUC | OCRNL | ONLCR | ONOCR |
	ONLRET | OFILL | CRDLY | NLDLY | BSDLY |
	TABDLY | VTDLY | FFDLY | OFDEL);
	line.c_oflag |= (0);

	// control param
	line.c_cflag &= ~( CBAUD | CSIZE | CSTOPB | PARENB | PARODD |
	HUPCL | CRTSCTS | CLOCAL | CREAD);
	line.c_cflag |= ( CLOCAL | CREAD);

	// explicitly set size
	switch (databits) {
	case 5: // who needs this?
		line.c_cflag |= CS5;
		break;
	case 6: // who needs this?
		line.c_cflag |= CS6;
		break;
	case 7:
		line.c_cflag |= CS7;
		break;
	default:
		line.c_cflag |= CS8;
		break;
	}

	// explicitly set parity
	switch (toupper(parity)) {
	case 'E':
		line.c_cflag |= PARENB;
		line.c_cflag &= ~PARODD;
		serial->bitcount++; // one extra bit
		break;
	case 'O':
		line.c_cflag |= PARENB;
		line.c_cflag |= PARODD;
		serial->bitcount++; // one extra bit
		break;
	default: // no parity
		line.c_cflag &= ~PARENB;
		line.c_cflag &= ~PARODD;
	}

	// set two stop bits if requested, else default to one
	if (stopbits == 2)
		line.c_cflag |= CSTOPB;

	// local param
	line.c_lflag &= ~( ISIG | ICANON | ECHO | ECHOE | ECHOK |
	ECHONL | NOFLSH | TOSTOP | IEXTEN | FLUSHO |
	ECHOKE | ECHOCTL);
	line.c_lflag |= (0);

	// timing/read param
	line.c_cc[VMIN] = 1; // return a min of 1 chars
	line.c_cc[VTIME] = 0; // no timer

	// flush all existing input data
	tcflush(serial->fd, TCIFLUSH);

	// set baud rate, if it is legal
	if (devbaud(speed) == -1) {
		error("illegal serial speed %d., ignoring", speed);
	} else {
		cfsetispeed(&line, devbaud(speed));
		cfsetospeed(&line, devbaud(speed));
	}

	// set new device parameters
	tcsetattr(serial->fd, TCSANOW, &line);

	// and non-blocking also
	if (fcntl(serial->fd, F_SETFL, FNDELAY) == -1)
		error("failed to set non-blocking read");

	// zap current data, if any
	serial_devtxinit(serial);
	serial_devrxinit(serial);

	return;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movl %r8d, 0x8(%rsp)
movl %ecx, %r12d
movl %edx, %ebp
movq %rsi, %r14
movq %rdi, %rbx
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rdi)
movl %edx, 0x4(%rdi)
movq %r9, (%rsp)
leal (%r12,%r9), %eax
incl %eax
movl %eax, 0x8(%rdi)
callq 0x3230
movl %eax, %r13d
callq 0x31a0
movl %eax, %r15d
pushq $-0x1
popq %rsi
movl %r13d, %edi
callq 0x3410
leaq 0xe170(%rip), %rsi      # 0x16497
leaq 0xc(%rsp), %rdx
movq %r14, %rdi
xorl %eax, %eax
callq 0x33d0
cmpl $0x1, %eax
jne 0x8356
movl 0xc(%rsp), %edx
decl %edx
leaq 0xbe4b(%rip), %rsi      # 0x14193
leaq 0x50(%rsp), %rdi
xorl %eax, %eax
callq 0x3530
jmp 0x8363
leaq 0x50(%rsp), %rdi
movq %r14, %rsi
callq 0x30c0
leaq 0x50(%rsp), %rdi
movl $0x902, %esi            # imm = 0x902
xorl %eax, %eax
callq 0x34a0
movl %eax, (%rbx)
testl %eax, %eax
jns 0x838d
leaq 0xbe1e(%rip), %rdi      # 0x1419f
leaq 0x50(%rsp), %rsi
xorl %eax, %eax
callq 0x9b87
movl %r15d, %edi
movl %r13d, %esi
callq 0x3410
movl (%rbx), %edi
leaq 0x23c(%rbx), %r14
movq %r14, %rsi
callq 0x3480
testl %eax, %eax
je 0x83c0
leaq 0xbdff(%rip), %rdi      # 0x141b3
leaq 0x50(%rsp), %rsi
xorl %eax, %eax
callq 0x9b87
movups (%r14), %xmm0
movups 0x10(%r14), %xmm1
movups 0x20(%r14), %xmm2
movups 0x2c(%r14), %xmm3
movaps %xmm0, 0x10(%rsp)
movups %xmm3, 0x3c(%rsp)
movaps %xmm2, 0x30(%rsp)
movaps %xmm1, 0x20(%rsp)
movabsq $-0xffff00004000, %rax  # imm = 0xFFFF0000FFFFC000
andq %rax, 0x10(%rsp)
movl $0x7fffe000, %r14d      # imm = 0x7FFFE000
andl 0x18(%rsp), %r14d
cmpl $0x5, %r12d
je 0x8425
cmpl $0x7, %r12d
je 0x841c
cmpl $0x6, %r12d
jne 0x842e
orl $0x890, %r14d           # imm = 0x890
jmp 0x8435
orl $0x8a0, %r14d           # imm = 0x8A0
jmp 0x8435
orl $0x880, %r14d           # imm = 0x880
jmp 0x8435
orl $0x8b0, %r14d           # imm = 0x8B0
callq 0x3030
movq (%rax), %rax
movsbq 0x8(%rsp), %rcx
movl (%rax,%rcx,4), %eax
cmpl $0x4f, %eax
je 0x8460
andl $0x7ffffcff, %r14d      # imm = 0x7FFFFCFF
cmpl $0x45, %eax
jne 0x8471
orl $0x100, %r14d           # imm = 0x100
jmp 0x8467
orl $0x300, %r14d           # imm = 0x300
movl %r14d, 0x18(%rsp)
incl 0x8(%rbx)
jmp 0x8476
movl %r14d, 0x18(%rsp)
movq (%rsp), %rax
cmpl $0x2, %eax
jne 0x8488
orl $0x40, %r14d
movl %r14d, 0x18(%rsp)
andl $0xffff6404, 0x1c(%rsp) # imm = 0xFFFF6404
movw $0x100, 0x26(%rsp)      # imm = 0x100
movl (%rbx), %edi
xorl %esi, %esi
callq 0x31b0
movl %ebp, %edi
callq 0x852f
cmpl $-0x1, %eax
je 0x84cb
movl %eax, %r14d
leaq 0x10(%rsp), %r15
movq %r15, %rdi
movl %eax, %esi
callq 0x34c0
movq %r15, %rdi
movl %r14d, %esi
callq 0x3170
jmp 0x84db
leaq 0xbcfa(%rip), %rdi      # 0x141cc
movl %ebp, %esi
xorl %eax, %eax
callq 0x98f2
movl (%rbx), %edi
leaq 0x10(%rsp), %rdx
xorl %esi, %esi
callq 0x3490
movl (%rbx), %edi
pushq $0x4
popq %rsi
movl $0x800, %edx            # imm = 0x800
xorl %eax, %eax
callq 0x3120
cmpl $-0x1, %eax
jne 0x850d
leaq 0xbd09(%rip), %rdi      # 0x1420f
xorl %eax, %eax
callq 0x98f2
movq %rbx, %rdi
callq 0x8090
movq %rbx, %rdi
callq 0x80b2
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq