static int gsmi_exec()

in google/gsmi.c [190:304]


static int gsmi_exec(u8 func, u8 sub)
{
	u16 cmd = (sub << 8) | func;
	u16 result = 0;
	int rc = 0;

	/*
	 * AH  : Subfunction number
	 * AL  : Function number
	 * EBX : Parameter block address
	 * DX  : SMI command port
	 *
	 * Three protocols here. See also the comment in gsmi_init().
	 */
	if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_CF) {
		/*
		 * If handshake_type == HANDSHAKE_CF then set CF on the
		 * way in and wait for the handler to clear it; this avoids
		 * corrupting register state on those chipsets which have
		 * a delay between writing the SMI trigger register and
		 * entering SMM.
		 */
		asm volatile (
			"stc\n"
			"outb %%al, %%dx\n"
		"1:      jc 1b\n"
			: "=a" (result)
			: "0" (cmd),
			  "d" (gsmi_dev.smi_cmd),
			  "b" (gsmi_dev.param_buf->address)
			: "memory", "cc"
		);
	} else if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_SPIN) {
		/*
		 * If handshake_type == HANDSHAKE_SPIN we spin a
		 * hundred-ish usecs to ensure the SMI has triggered.
		 */
		asm volatile (
			"outb %%al, %%dx\n"
		"1:      loop 1b\n"
			: "=a" (result)
			: "0" (cmd),
			  "d" (gsmi_dev.smi_cmd),
			  "b" (gsmi_dev.param_buf->address),
			  "c" (spincount)
			: "memory", "cc"
		);
	} else {
		/*
		 * If handshake_type == HANDSHAKE_NONE we do nothing;
		 * either we don't need to or it's legacy firmware that
		 * doesn't understand the CF protocol.
		 */
		asm volatile (
			"outb %%al, %%dx\n\t"
			: "=a" (result)
			: "0" (cmd),
			  "d" (gsmi_dev.smi_cmd),
			  "b" (gsmi_dev.param_buf->address)
			: "memory", "cc"
		);
	}

	/* check return code from SMI handler */
	switch (result) {
	case GSMI_SUCCESS:
		break;
	case GSMI_VAR_NOT_FOUND:
		/* not really an error, but let the caller know */
		rc = 1;
		break;
	case GSMI_INVALID_PARAMETER:
		printk(KERN_ERR "gsmi: exec 0x%04x: Invalid parameter\n", cmd);
		rc = -EINVAL;
		break;
	case GSMI_BUFFER_TOO_SMALL:
		printk(KERN_ERR "gsmi: exec 0x%04x: Buffer too small\n", cmd);
		rc = -ENOMEM;
		break;
	case GSMI_UNSUPPORTED:
	case GSMI_UNSUPPORTED2:
		if (sub != GSMI_CMD_HANDSHAKE_TYPE)
			printk(KERN_ERR "gsmi: exec 0x%04x: Not supported\n",
			       cmd);
		rc = -ENOSYS;
		break;
	case GSMI_NOT_READY:
		printk(KERN_ERR "gsmi: exec 0x%04x: Not ready\n", cmd);
		rc = -EBUSY;
		break;
	case GSMI_DEVICE_ERROR:
		printk(KERN_ERR "gsmi: exec 0x%04x: Device error\n", cmd);
		rc = -EFAULT;
		break;
	case GSMI_NOT_FOUND:
		printk(KERN_ERR "gsmi: exec 0x%04x: Data not found\n", cmd);
		rc = -ENOENT;
		break;
	case GSMI_LOG_FULL:
		printk(KERN_ERR "gsmi: exec 0x%04x: Log full\n", cmd);
		rc = -ENOSPC;
		break;
	case GSMI_HANDSHAKE_CF:
	case GSMI_HANDSHAKE_SPIN:
	case GSMI_HANDSHAKE_NONE:
		rc = result;
		break;
	default:
		printk(KERN_ERR "gsmi: exec 0x%04x: Unknown error 0x%04x\n",
		       cmd, result);
		rc = -ENXIO;
	}

	return rc;
}