uru4000: Unify register I/O

This commit is contained in:
Daniel Drake 2008-03-19 17:25:53 +00:00
parent d3d68be490
commit fb49c24ae2

View file

@ -120,7 +120,8 @@ struct uru4k_dev {
const struct uru4k_dev_profile *profile; const struct uru4k_dev_profile *profile;
uint8_t interface; uint8_t interface;
enum fp_imgdev_state activate_state; enum fp_imgdev_state activate_state;
unsigned char last_hwstat_rd; unsigned char last_reg_rd;
unsigned char last_hwstat;
struct libusb_transfer *irq_transfer; struct libusb_transfer *irq_transfer;
struct libusb_transfer *img_transfer; struct libusb_transfer *img_transfer;
@ -145,35 +146,40 @@ static const unsigned char crkey[] = {
0x98, 0xe0, 0x0f, 0x3c, 0x59, 0x8f, 0x5f, 0x4b, 0x98, 0xe0, 0x0f, 0x3c, 0x59, 0x8f, 0x5f, 0x4b,
}; };
typedef void (*set_reg_cb_fn)(struct fp_img_dev *dev, int status, /***** REGISTER I/O *****/
typedef void (*write_regs_cb_fn)(struct fp_img_dev *dev, int status,
void *user_data); void *user_data);
struct set_reg_data { struct write_regs_data {
struct fp_img_dev *dev; struct fp_img_dev *dev;
set_reg_cb_fn callback; write_regs_cb_fn callback;
void *user_data; void *user_data;
}; };
static void set_reg_cb(struct libusb_transfer *transfer) static void write_regs_cb(struct libusb_transfer *transfer)
{ {
struct set_reg_data *srdata = transfer->user_data; struct write_regs_data *wrdata = transfer->user_data;
struct libusb_control_setup *setup =
libusb_control_transfer_get_setup(transfer);
int r = 0; int r = 0;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
r = -EIO; r = -EIO;
else if (transfer->actual_length != 1) else if (transfer->actual_length != setup->wLength)
r = -EPROTO; r = -EPROTO;
g_free(transfer->buffer); g_free(transfer->buffer);
libusb_free_transfer(transfer); libusb_free_transfer(transfer);
srdata->callback(srdata->dev, r, srdata->user_data); wrdata->callback(wrdata->dev, r, wrdata->user_data);
g_free(srdata); g_free(wrdata);
} }
static int set_reg(struct fp_img_dev *dev, uint16_t reg, static int write_regs(struct fp_img_dev *dev, uint16_t first_reg,
unsigned char value, set_reg_cb_fn callback, void *user_data) uint16_t num_regs, unsigned char *values, write_regs_cb_fn callback,
void *user_data)
{ {
struct set_reg_data *srdata; struct write_regs_data *wrdata;
struct libusb_transfer *transfer = libusb_alloc_transfer(); struct libusb_transfer *transfer = libusb_alloc_transfer();
unsigned char *data; unsigned char *data;
int r; int r;
@ -181,26 +187,98 @@ static int set_reg(struct fp_img_dev *dev, uint16_t reg,
if (!transfer) if (!transfer)
return -ENOMEM; return -ENOMEM;
srdata = g_malloc(sizeof(*srdata)); wrdata = g_malloc(sizeof(*wrdata));
srdata->dev = dev; wrdata->dev = dev;
srdata->callback = callback; wrdata->callback = callback;
srdata->user_data = user_data; wrdata->user_data = user_data;
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
data[LIBUSB_CONTROL_SETUP_SIZE] = value; memcpy(data + LIBUSB_CONTROL_SETUP_SIZE, values, num_regs);
libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, reg, 0, 1); libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, first_reg, 0, num_regs);
libusb_fill_control_transfer(transfer, dev->udev, data, set_reg_cb, libusb_fill_control_transfer(transfer, dev->udev, data, write_regs_cb,
srdata, CTRL_TIMEOUT); wrdata, CTRL_TIMEOUT);
r = libusb_submit_transfer(transfer); r = libusb_submit_transfer(transfer);
if (r < 0) { if (r < 0) {
g_free(srdata); g_free(wrdata);
g_free(data); g_free(data);
libusb_free_transfer(transfer); libusb_free_transfer(transfer);
} }
return r; return r;
} }
static int write_reg(struct fp_img_dev *dev, uint16_t reg,
unsigned char value, write_regs_cb_fn callback, void *user_data)
{
return write_regs(dev, reg, 1, &value, callback, user_data);
}
typedef void (*read_regs_cb_fn)(struct fp_img_dev *dev, int status,
unsigned char *data, void *user_data);
struct read_regs_data {
struct fp_img_dev *dev;
read_regs_cb_fn callback;
void *user_data;
};
static void read_regs_cb(struct libusb_transfer *transfer)
{
struct read_regs_data *rrdata = transfer->user_data;
struct libusb_control_setup *setup =
libusb_control_transfer_get_setup(transfer);
unsigned char *data = NULL;
int r = 0;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
r = -EIO;
else if (transfer->actual_length != setup->wLength)
r = -EPROTO;
else
data = libusb_control_transfer_get_data(transfer);
rrdata->callback(rrdata->dev, r, data, rrdata->user_data);
g_free(rrdata);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
uint16_t num_regs, read_regs_cb_fn callback, void *user_data)
{
struct read_regs_data *rrdata;
struct libusb_transfer *transfer = libusb_alloc_transfer();
unsigned char *data;
int r;
if (!transfer)
return -ENOMEM;
rrdata = g_malloc(sizeof(*rrdata));
rrdata->dev = dev;
rrdata->callback = callback;
rrdata->user_data = user_data;
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
libusb_fill_control_setup(data, CTRL_IN, USB_RQ, first_reg, 0, num_regs);
libusb_fill_control_transfer(transfer, dev->udev, data, read_regs_cb,
rrdata, CTRL_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(rrdata);
g_free(data);
libusb_free_transfer(transfer);
}
return r;
}
static int read_reg(struct fp_img_dev *dev, uint16_t reg,
read_regs_cb_fn callback, void *user_data)
{
return read_regs(dev, reg, 1, callback, user_data);
}
/* /*
* HWSTAT * HWSTAT
* *
@ -226,74 +304,38 @@ static int set_reg(struct fp_img_dev *dev, uint16_t reg,
* and interrupt to the host. Maybe? * and interrupt to the host. Maybe?
*/ */
typedef void (*challenge_response_cb)(struct fp_img_dev *dev, int result, static void response_cb(struct fp_img_dev *dev, int status, void *user_data)
void *user_data);
struct c_r_data {
struct fp_img_dev *dev;
challenge_response_cb callback;
void *user_data;
};
static void response_cb(struct libusb_transfer *transfer)
{ {
struct c_r_data *crdata = transfer->user_data; struct fpi_ssm *ssm = user_data;
int r = 0; if (status == 0)
fpi_ssm_next_state(ssm);
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) else
r = -EIO; fpi_ssm_mark_aborted(ssm, status);
else if (transfer->actual_length != CR_LENGTH)
r = -EPROTO;
g_free(transfer->buffer);
libusb_free_transfer(transfer);
crdata->callback(crdata->dev, r, crdata->user_data);
} }
static void challenge_cb(struct libusb_transfer *transfer) static void challenge_cb(struct fp_img_dev *dev, int status,
unsigned char *data, void *user_data)
{ {
struct c_r_data *crdata = transfer->user_data; struct fpi_ssm *ssm = user_data;
struct fp_img_dev *dev = crdata->dev;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
struct libusb_transfer *resp_transfer;
unsigned char *respdata; unsigned char *respdata;
int r; int r;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { if (status != 0) {
crdata->callback(crdata->dev, -EIO, crdata->user_data); fpi_ssm_mark_aborted(ssm, status);
goto out; return;
} else if (transfer->actual_length != CR_LENGTH) {
crdata->callback(crdata->dev, -EPROTO, crdata->user_data);
goto out;
} }
/* submit response */ /* submit response */
resp_transfer = libusb_alloc_transfer();
if (!resp_transfer) {
crdata->callback(crdata->dev, -ENOMEM, crdata->user_data);
goto out;
}
respdata = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + CR_LENGTH);
libusb_fill_control_setup(respdata, CTRL_OUT, USB_RQ, REG_RESPONSE, 0,
CR_LENGTH);
libusb_fill_control_transfer(transfer, dev->udev, respdata, response_cb,
crdata, CTRL_TIMEOUT);
/* produce response from challenge */ /* produce response from challenge */
AES_encrypt(libusb_control_transfer_get_data(transfer), /* FIXME would this work in-place? */
respdata + LIBUSB_CONTROL_SETUP_SIZE, &urudev->aeskey); respdata = g_malloc(CR_LENGTH);
AES_encrypt(data, respdata, &urudev->aeskey);
r = libusb_submit_transfer(resp_transfer);
if (r < 0) { r = write_regs(dev, REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm);
g_free(respdata); g_free(respdata);
libusb_free_transfer(resp_transfer); if (r < 0)
crdata->callback(crdata->dev, r, crdata->user_data); fpi_ssm_mark_aborted(ssm, r);
}
out:
g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
/* /*
@ -301,36 +343,15 @@ out:
* authentication scheme, where the device challenges the authenticity of the * authentication scheme, where the device challenges the authenticity of the
* driver. * driver.
*/ */
static int do_challenge_response(struct fp_img_dev *dev, static void sm_do_challenge_response(struct fpi_ssm *ssm)
challenge_response_cb callback, void *user_data)
{ {
struct libusb_transfer *transfer = libusb_alloc_transfer();; struct fp_img_dev *dev = ssm->priv;
struct c_r_data *crdata;
unsigned char *data;
int r; int r;
fp_dbg(""); fp_dbg("");
if (!transfer) r = read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm);
return -ENOMEM; if (r < 0)
fpi_ssm_mark_aborted(ssm, r);
crdata = g_malloc(sizeof(*crdata));
crdata->dev = dev;
crdata->callback = callback;
crdata->user_data = user_data;
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + CR_LENGTH);
libusb_fill_control_setup(data, CTRL_IN, USB_RQ, REG_CHALLENGE, 0,
CR_LENGTH);
libusb_fill_control_transfer(transfer, dev->udev, data, challenge_cb,
crdata, CTRL_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(crdata);
g_free(data);
libusb_free_transfer(transfer);
}
return r;
} }
/***** INTERRUPT HANDLING *****/ /***** INTERRUPT HANDLING *****/
@ -524,7 +545,7 @@ static void finger_presence_irq_cb(struct fp_img_dev *dev, int status,
fp_warn("ignoring unexpected interrupt %04x", type); fp_warn("ignoring unexpected interrupt %04x", type);
} }
static void change_state_set_reg_cb(struct fp_img_dev *dev, int status, static void change_state_write_reg_cb(struct fp_img_dev *dev, int status,
void *user_data) void *user_data)
{ {
if (status) if (status)
@ -542,21 +563,21 @@ static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
if (!IRQ_HANDLER_IS_RUNNING(urudev)) if (!IRQ_HANDLER_IS_RUNNING(urudev))
return -EIO; return -EIO;
urudev->irq_cb = finger_presence_irq_cb; urudev->irq_cb = finger_presence_irq_cb;
return set_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON, return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON,
change_state_set_reg_cb, NULL); change_state_write_reg_cb, NULL);
case IMGDEV_STATE_CAPTURE: case IMGDEV_STATE_CAPTURE:
urudev->irq_cb = NULL; urudev->irq_cb = NULL;
start_imaging_loop(dev); start_imaging_loop(dev);
return set_reg(dev, REG_MODE, MODE_CAPTURE, change_state_set_reg_cb, return write_reg(dev, REG_MODE, MODE_CAPTURE, change_state_write_reg_cb,
NULL); NULL);
case IMGDEV_STATE_AWAIT_FINGER_OFF: case IMGDEV_STATE_AWAIT_FINGER_OFF:
if (!IRQ_HANDLER_IS_RUNNING(urudev)) if (!IRQ_HANDLER_IS_RUNNING(urudev))
return -EIO; return -EIO;
urudev->irq_cb = finger_presence_irq_cb; urudev->irq_cb = finger_presence_irq_cb;
return set_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF, return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
change_state_set_reg_cb, NULL); change_state_write_reg_cb, NULL);
default: default:
fp_err("unrecognised state %d", state); fp_err("unrecognised state %d", state);
@ -566,7 +587,7 @@ static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
/***** GENERIC STATE MACHINE HELPER FUNCTIONS *****/ /***** GENERIC STATE MACHINE HELPER FUNCTIONS *****/
static void sm_set_reg_cb(struct fp_img_dev *dev, int result, void *user_data) static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data)
{ {
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = user_data;
@ -576,11 +597,37 @@ static void sm_set_reg_cb(struct fp_img_dev *dev, int result, void *user_data)
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
} }
static void sm_set_reg(struct fpi_ssm *ssm, uint16_t reg, static void sm_write_reg(struct fpi_ssm *ssm, uint16_t reg,
unsigned char value) unsigned char value)
{ {
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
int r = set_reg(dev, reg, value, sm_set_reg_cb, ssm); int r = write_reg(dev, reg, value, sm_write_reg_cb, ssm);
if (r < 0)
fpi_ssm_mark_aborted(ssm, r);
}
static void sm_read_reg_cb(struct fp_img_dev *dev, int result,
unsigned char *data, void *user_data)
{
struct fpi_ssm *ssm = user_data;
struct uru4k_dev *urudev = dev->priv;
if (result) {
fpi_ssm_mark_aborted(ssm, result);
} else {
urudev->last_reg_rd = *data;
fp_dbg("reg value %x", urudev->last_reg_rd);
fpi_ssm_next_state(ssm);
}
}
static void sm_read_reg(struct fpi_ssm *ssm, uint16_t reg)
{
struct fp_img_dev *dev = ssm->priv;
int r;
fp_dbg("read reg %x", reg);
r = read_reg(dev, reg, sm_read_reg_cb, ssm);
if (r < 0) if (r < 0)
fpi_ssm_mark_aborted(ssm, r); fpi_ssm_mark_aborted(ssm, r);
} }
@ -588,81 +635,30 @@ static void sm_set_reg(struct fpi_ssm *ssm, uint16_t reg,
static void sm_set_mode(struct fpi_ssm *ssm, unsigned char mode) static void sm_set_mode(struct fpi_ssm *ssm, unsigned char mode)
{ {
fp_dbg("mode %02x", mode); fp_dbg("mode %02x", mode);
sm_set_reg(ssm, REG_MODE, mode); sm_write_reg(ssm, REG_MODE, mode);
} }
static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value) static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value)
{ {
fp_dbg("set %02x", value); fp_dbg("set %02x", value);
sm_set_reg(ssm, REG_HWSTAT, value); sm_write_reg(ssm, REG_HWSTAT, value);
} }
static void sm_get_hwstat_cb(struct libusb_transfer *transfer) static void sm_fix_fw_read_cb(struct fp_img_dev *dev, int status,
unsigned char *data, void *user_data)
{ {
struct fpi_ssm *ssm = transfer->user_data; struct fpi_ssm *ssm = user_data;
struct fp_img_dev *dev = ssm->priv;
struct uru4k_dev *urudev = dev->priv;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_mark_aborted(ssm, -EIO);
} else if (transfer->actual_length != 1) {
fpi_ssm_mark_aborted(ssm, -EPROTO);
} else {
urudev->last_hwstat_rd = libusb_control_transfer_get_data(transfer)[0];
fp_dbg("value %02x", urudev->last_hwstat_rd);
fpi_ssm_next_state(ssm);
}
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
static void sm_get_hwstat(struct fpi_ssm *ssm)
{
struct fp_img_dev *dev = ssm->priv;
struct libusb_transfer *transfer = libusb_alloc_transfer();
unsigned char *data;
int r;
if (!transfer) {
fpi_ssm_mark_aborted(ssm, -ENOMEM);
return;
}
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
/* The windows driver uses a request of 0x0c here. We use 0x04 to be
* consistent with every other command we know about. */
/* FIXME is the above comment still true? */
libusb_fill_control_setup(data, CTRL_IN, USB_RQ, REG_HWSTAT, 0, 1);
libusb_fill_control_transfer(transfer, dev->udev, data, sm_get_hwstat_cb,
ssm, CTRL_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, -EIO);
}
}
static void sm_fix_fw_read_cb(struct libusb_transfer *transfer)
{
struct fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = ssm->priv;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
unsigned char new; unsigned char new;
unsigned char fwenc; unsigned char fwenc;
uint16_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset; uint16_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { if (status != 0) {
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, status);
goto out; return;
} else if (transfer->actual_length != 1) {
fpi_ssm_mark_aborted(ssm, -EPROTO);
goto out;
} }
fwenc = libusb_control_transfer_get_data(transfer)[0]; fwenc = data[0];
fp_dbg("firmware encryption byte at %x reads %02x", enc_addr, fwenc); fp_dbg("firmware encryption byte at %x reads %02x", enc_addr, fwenc);
if (fwenc != 0x07 && fwenc != 0x17) if (fwenc != 0x07 && fwenc != 0x17)
fp_dbg("strange encryption byte value, please report this"); fp_dbg("strange encryption byte value, please report this");
@ -672,12 +668,8 @@ static void sm_fix_fw_read_cb(struct libusb_transfer *transfer)
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
} else { } else {
fp_dbg("fixed encryption byte to %02x", new); fp_dbg("fixed encryption byte to %02x", new);
sm_set_reg(ssm, enc_addr, new); sm_write_reg(ssm, enc_addr, new);
} }
out:
g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
static void sm_fix_firmware(struct fpi_ssm *ssm) static void sm_fix_firmware(struct fpi_ssm *ssm)
@ -685,26 +677,11 @@ static void sm_fix_firmware(struct fpi_ssm *ssm)
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
uint16_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset; uint16_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset;
struct libusb_transfer *transfer = libusb_alloc_transfer();
unsigned char *data;
int r; int r;
if (!transfer) { r = read_reg(dev, enc_addr, sm_fix_fw_read_cb, ssm);
fpi_ssm_mark_aborted(ssm, -ENOMEM); if (r < 0)
return;
}
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
libusb_fill_control_setup(data, 0xc0, 0x0c, enc_addr, 0, 1);
libusb_fill_control_transfer(transfer, dev->udev, data, sm_fix_fw_read_cb,
ssm, CTRL_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, r); fpi_ssm_mark_aborted(ssm, r);
}
} }
/***** INITIALIZATION *****/ /***** INITIALIZATION *****/
@ -755,13 +732,14 @@ static void rebootpwr_run_state(struct fpi_ssm *ssm)
switch (ssm->cur_state) { switch (ssm->cur_state) {
case REBOOTPWR_SET_HWSTAT: case REBOOTPWR_SET_HWSTAT:
urudev->rebootpwr_ctr = 100; urudev->rebootpwr_ctr = 100;
sm_set_hwstat(ssm, urudev->last_hwstat_rd & 0xf); sm_set_hwstat(ssm, urudev->last_hwstat & 0xf);
break; break;
case REBOOTPWR_GET_HWSTAT: case REBOOTPWR_GET_HWSTAT:
sm_get_hwstat(ssm); sm_read_reg(ssm, REG_HWSTAT);
break; break;
case REBOOTPWR_CHECK_HWSTAT: case REBOOTPWR_CHECK_HWSTAT:
if (urudev->last_hwstat_rd & 0x1) urudev->last_hwstat = urudev->last_reg_rd;
if (urudev->last_hwstat & 0x1)
fpi_ssm_mark_completed(ssm); fpi_ssm_mark_completed(ssm);
else else
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
@ -805,6 +783,7 @@ enum powerup_states {
POWERUP_CHECK_HWSTAT, POWERUP_CHECK_HWSTAT,
POWERUP_PAUSE, POWERUP_PAUSE,
POWERUP_CHALLENGE_RESPONSE, POWERUP_CHALLENGE_RESPONSE,
POWERUP_CHALLENGE_RESPONSE_SUCCESS,
POWERUP_NUM_STATES, POWERUP_NUM_STATES,
}; };
@ -824,36 +803,26 @@ static void powerup_pause_cb(void *data)
} }
} }
static void powerup_challenge_response_cb(struct fp_img_dev *dev, int result,
void *data)
{
struct fpi_ssm *ssm = data;
if (result)
fpi_ssm_mark_aborted(ssm, result);
else
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
}
static void powerup_run_state(struct fpi_ssm *ssm) static void powerup_run_state(struct fpi_ssm *ssm)
{ {
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
int r;
switch (ssm->cur_state) { switch (ssm->cur_state) {
case POWERUP_INIT: case POWERUP_INIT:
urudev->powerup_ctr = 100; urudev->powerup_ctr = 100;
urudev->powerup_hwstat = urudev->last_hwstat_rd & 0xf; urudev->powerup_hwstat = urudev->last_hwstat & 0xf;
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
break; break;
case POWERUP_SET_HWSTAT: case POWERUP_SET_HWSTAT:
sm_set_hwstat(ssm, urudev->powerup_hwstat); sm_set_hwstat(ssm, urudev->powerup_hwstat);
break; break;
case POWERUP_GET_HWSTAT: case POWERUP_GET_HWSTAT:
sm_get_hwstat(ssm); sm_read_reg(ssm, REG_HWSTAT);
break; break;
case POWERUP_CHECK_HWSTAT: case POWERUP_CHECK_HWSTAT:
if ((urudev->last_hwstat_rd & 0x80) == 0) urudev->last_hwstat = urudev->last_reg_rd;
if ((urudev->last_reg_rd & 0x80) == 0)
fpi_ssm_mark_completed(ssm); fpi_ssm_mark_completed(ssm);
else else
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
@ -863,9 +832,10 @@ static void powerup_run_state(struct fpi_ssm *ssm)
fpi_ssm_mark_aborted(ssm, -ETIME); fpi_ssm_mark_aborted(ssm, -ETIME);
break; break;
case POWERUP_CHALLENGE_RESPONSE: case POWERUP_CHALLENGE_RESPONSE:
r = do_challenge_response(dev, powerup_challenge_response_cb, ssm); sm_do_challenge_response(ssm);
if (r < 0) break;
fpi_ssm_mark_aborted(ssm, r); case POWERUP_CHALLENGE_RESPONSE_SUCCESS:
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
break; break;
} }
} }
@ -947,10 +917,11 @@ static void init_run_state(struct fpi_ssm *ssm)
switch (ssm->cur_state) { switch (ssm->cur_state) {
case INIT_GET_HWSTAT: case INIT_GET_HWSTAT:
sm_get_hwstat(ssm); sm_read_reg(ssm, REG_HWSTAT);
break; break;
case INIT_CHECK_HWSTAT_REBOOT: case INIT_CHECK_HWSTAT_REBOOT:
if ((urudev->last_hwstat_rd & 0x84) == 0x84) urudev->last_hwstat = urudev->last_reg_rd;
if ((urudev->last_hwstat & 0x84) == 0x84)
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
else else
fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN); fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN);
@ -962,8 +933,8 @@ static void init_run_state(struct fpi_ssm *ssm)
fpi_ssm_start_subsm(ssm, rebootsm); fpi_ssm_start_subsm(ssm, rebootsm);
break; break;
case INIT_CHECK_HWSTAT_POWERDOWN: case INIT_CHECK_HWSTAT_POWERDOWN:
if ((urudev->last_hwstat_rd & 0x80) == 0) if ((urudev->last_hwstat & 0x80) == 0)
sm_set_hwstat(ssm, urudev->last_hwstat_rd | 0x80); sm_set_hwstat(ssm, urudev->last_hwstat | 0x80);
else else
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
break; break;