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;
}