static void in_complete (io_context_t ctx, struct iocb *iocb, long res, long res2) { int status; if (verbose > 2) fprintf(stderr, "%s uiocb %p status %ld %ld\n", __FUNCTION__, iocb, res, res2); /* fail on short write _OR_ fault */ if (res != iocb->u.c.nbytes || res2 != 0) goto fail; /* get data we'll write to the host */ iocb->u.c.nbytes = fill_in_buf (iocb->u.c.buf, iosize); if (iocb->u.c.nbytes < 0) { fprintf (stderr, "%s %p refill fail, %d (%s)\n", __FUNCTION__, iocb, errno, strerror (errno)); goto clean; } /* resubmit */ status = io_submit (ctx, 1, &iocb); if (status == 1) return; fprintf (stderr, "%s %p resubmit fail, %d (%s)\n", __FUNCTION__, iocb, errno, strerror (errno)); goto clean; fail: if (res < 0) errno = -res; else if (res2 < 0) errno = -res2; fprintf (stderr, "%s %p fail %ld/%ld, %d (%s)\n", __FUNCTION__, iocb, res, iocb->u.c.nbytes, errno, strerror (errno)); clean: aio_in_pending--; return; }
static void *simple_source_thread (void *param) { char *name = (char *) param; int status; char buf [USB_BUFSIZE]; status = source_open (name); if (status < 0) return 0; source_fd = status; pthread_cleanup_push (close_fd, &source_fd); do { unsigned long len; /* original LinuxThreads cancelation didn't work right * so test for it explicitly. */ pthread_testcancel (); len = fill_in_buf (buf, sizeof buf); if (len > 0) status = write (source_fd, buf, len); else status = 0; } while (status > 0); if (status == 0) { if (verbose) fprintf (stderr, "done %s\n", __FUNCTION__); } else if (verbose > 2 || errno != ESHUTDOWN) /* normal disconnect */ perror ("write"); fflush (stdout); fflush (stderr); pthread_cleanup_pop (1); return 0; }
static void *aio_in_thread (void *param) { char *name = (char *) param; int status; io_context_t ctx = 0; struct iocb *queue, *iocb; unsigned i; status = source_open (name); if (status < 0) return 0; source_fd = status; pthread_cleanup_push (close_fd, &source_fd); /* initialize i/o queue */ status = io_setup (aio_in, &ctx); if (status < 0) { perror ("aio_in_thread, io_setup"); return 0; } pthread_cleanup_push (queue_release, &ctx); if (aio_in == 0) aio_in = 1; queue = alloca (aio_in * sizeof *iocb); /* populate and (re)run the queue */ for (i = 0, iocb = queue; i < aio_in; i++, iocb++) { char *buf = malloc (iosize); if (!buf) { fprintf(stderr, "%s can't get buffer[%d]\n", __FUNCTION__, i); return 0; } /* host receives the data we're writing */ io_prep_pwrite (iocb, source_fd, buf, fill_in_buf (buf, iosize), 0); io_set_callback (iocb, in_complete); iocb->key = USB_DIR_IN; status = io_submit (ctx, 1, &iocb); if (status < 0) { perror (__FUNCTION__); break; } aio_in_pending++; if (verbose > 2) fprintf(stderr, "%s submit uiocb %p\n", __FUNCTION__, iocb); } status = io_run (ctx, &aio_in_pending); if (status < 0) perror ("aio_in_thread, io_run"); /* clean up */ fflush (stderr); pthread_cleanup_pop (1); pthread_cleanup_pop (1); return 0; }
int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size, uint8_t *in, int in_size, int flags) { int i; int started = (flags & I2C_XFER_START) ? 0 : 1; uint8_t reg_sts; if (out_size == 0 && in_size == 0) return EC_SUCCESS; wait_idle(port); reg_sts = MEC1322_I2C_STATUS(port); if (!started && (((reg_sts & (STS_BER | STS_LAB)) || !(reg_sts & STS_NBB)) || (i2c_get_line_levels(port) != I2C_LINE_IDLE))) { CPRINTS("I2C%d bad status 0x%02x, SCL=%d, SDA=%d", port, reg_sts, i2c_get_line_levels(port) & I2C_LINE_SCL_HIGH, i2c_get_line_levels(port) & I2C_LINE_SDA_HIGH); /* Attempt to unwedge the port. */ i2c_unwedge(port); /* Bus error, bus busy, or arbitration lost. Reset port. */ reset_port(port); /* * We don't know what edges the slave saw, so sleep long enough * that the slave will see the new start condition below. */ usleep(1000); } if (out) { MEC1322_I2C_DATA(port) = (uint8_t)slave_addr; /* * Clock out the slave address. Send START bit if start flag is * set. */ MEC1322_I2C_CTRL(port) = CTRL_PIN | CTRL_ESO | CTRL_ENI | CTRL_ACK | (started ? 0 : CTRL_STA); if (!started) started = 1; for (i = 0; i < out_size; ++i) { if (wait_byte_done(port)) goto err_i2c_xfer; MEC1322_I2C_DATA(port) = out[i]; } if (wait_byte_done(port)) goto err_i2c_xfer; /* * Send STOP bit if the stop flag is on, and caller * doesn't expect to receive data. */ if ((flags & I2C_XFER_STOP) && in_size == 0) { MEC1322_I2C_CTRL(port) = CTRL_PIN | CTRL_ESO | CTRL_STO | CTRL_ACK; } } if (in_size) { if (out_size) { /* resend start bit when change direction */ MEC1322_I2C_CTRL(port) = CTRL_ESO | CTRL_STA | CTRL_ACK | CTRL_ENI; } MEC1322_I2C_DATA(port) = (uint8_t)slave_addr | 0x01; if (!started) { started = 1; /* Clock out slave address with START bit */ MEC1322_I2C_CTRL(port) = CTRL_PIN | CTRL_ESO | CTRL_STA | CTRL_ACK | CTRL_ENI; } /* On MEC1322, first byte read is dummy read (slave addr) */ in_size++; for (i = 0; i < in_size - 2; ++i) { if (wait_byte_done(port)) goto err_i2c_xfer; fill_in_buf(in, i, MEC1322_I2C_DATA(port)); } if (wait_byte_done(port)) goto err_i2c_xfer; /* * De-assert ACK bit before reading the next to last byte, * so that the last byte is NACK'ed. */ MEC1322_I2C_CTRL(port) = CTRL_ESO | CTRL_ENI; fill_in_buf(in, in_size - 2, MEC1322_I2C_DATA(port)); if (wait_byte_done(port)) goto err_i2c_xfer; /* Send STOP if stop flag is set */ MEC1322_I2C_CTRL(port) = CTRL_PIN | CTRL_ESO | CTRL_ACK | ((flags & I2C_XFER_STOP) ? CTRL_STO : 0); /* Now read the last byte */ fill_in_buf(in, in_size - 1, MEC1322_I2C_DATA(port)); } /* Check for error conditions */ if (MEC1322_I2C_STATUS(port) & (STS_LAB | STS_BER)) return EC_ERROR_UNKNOWN; return EC_SUCCESS; err_i2c_xfer: /* Send STOP and return error */ MEC1322_I2C_CTRL(port) = CTRL_PIN | CTRL_ESO | CTRL_STO | CTRL_ACK; return EC_ERROR_UNKNOWN; }