static int leuart_fifo_state (sBSPACMperiphUARTstate * usp) { BSPACM_CORE_SAVED_INTERRUPT_STATE(istate); LEUART_TypeDef * const leuart = (LEUART_TypeDef *)usp->uart; int rv = 0; BSPACM_CORE_DISABLE_INTERRUPT(); do { if (! (leuart->STATUS & LEUART_STATUS_TXC)) { rv |= eBSPACMperiphUARTfifoState_HWTX; } if (leuart->STATUS & LEUART_STATUS_RXDATAV) { rv |= eBSPACMperiphUARTfifoState_HWRX; } if (usp->tx_fifo_ni_ && (! fifo_empty(usp->tx_fifo_ni_))) { rv |= eBSPACMperiphUARTfifoState_SWTX; } if (usp->rx_fifo_ni_ && (! fifo_empty(usp->rx_fifo_ni_))) { rv |= eBSPACMperiphUARTfifoState_SWRX; } } while (0); BSPACM_CORE_REENABLE_INTERRUPT(istate); return rv; }
static int bch_allocator_thread(void *arg) { struct cache *ca = arg; mutex_lock(&ca->set->bucket_lock); while (1) { /* * First, we pull buckets off of the unused and free_inc lists, * possibly issue discards to them, then we add the bucket to * the free list: */ while (1) { long bucket; if ((!atomic_read(&ca->set->prio_blocked) || !CACHE_SYNC(&ca->set->sb)) && !fifo_empty(&ca->unused)) fifo_pop(&ca->unused, bucket); else if (!fifo_empty(&ca->free_inc)) fifo_pop(&ca->free_inc, bucket); else break; if (ca->discard) { mutex_unlock(&ca->set->bucket_lock); blkdev_issue_discard(ca->bdev, bucket_to_sector(ca->set, bucket), ca->sb.block_size, GFP_KERNEL, 0); mutex_lock(&ca->set->bucket_lock); } allocator_wait(ca, bch_allocator_push(ca, bucket)); wake_up(&ca->set->bucket_wait); } /* * We've run out of free buckets, we need to find some buckets * we can invalidate. First, invalidate them in memory and add * them to the free_inc list: */ allocator_wait(ca, ca->set->gc_mark_valid && (ca->need_save_prio > 64 || !ca->invalidate_needs_gc)); invalidate_buckets(ca); /* * Now, we write their new gens to disk so we can start writing * new stuff to them: */ allocator_wait(ca, !atomic_read(&ca->set->prio_blocked)); if (CACHE_SYNC(&ca->set->sb) && (!fifo_empty(&ca->free_inc) || ca->need_save_prio > 64)) bch_prio_write(ca); } }
void nextkbd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { if(fifo_empty()) return; send(); }
static void serial_transmit(struct serial_port *sp) { unsigned char lsr; unsigned char b; while (1) { // Is UART ready to transmit next byte lsr = inp((unsigned short) (sp->iobase + UART_LSR)); sp->linestatus |= (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)); //kprintf("serial_transmit: lsr=%02X\n", lsr); if (!(lsr & LSR_TXRDY)) break; // Is tx queue empty if (fifo_empty(&sp->txq)) { sp->tx_busy = 0; break; } // Get next byte from queue b = fifo_get(&sp->txq); //kprintf("fifo get: h:%d t:%d c:%d\n", sp->txq.head, sp->txq.tail, sp->txq.count); //kprintf("serial: xmit %02X\n", b); outp(sp->iobase + UART_TX, b); sp->tx_busy = 1; sp->tx_queue_rel++; } }
/** * Check if any work has appeared in the queue; work it if there * * The background task spends time waiting for something to do. * One of the places where work comes from is via the fifo queue, * which will contain data buffers that must be sent out over the ccn network. * This function will look for work and get it done if present. * Not too much work is donw however, since there are other things to be * done by the background task. Hence we limit the number of buffers will * will process from the queue. * We shall return soon enough to this spot to keep working the queue contents. * * \param me context sink element where the fifo queues are allocated */ static void check_fifo (Gstccnxsink * me) { GstClockTime ts; gint i; guint size; guint8 *data; GstBuffer *buffer; for (i = 0; i < 3; ++i) { if (fifo_empty (me)) return; if (!(buffer = fifo_pop (me))) return; size = GST_BUFFER_SIZE (buffer); data = GST_BUFFER_DATA (buffer); ts = 0; GST_INFO ("CCNxSink: pubish size: %d\n", size); if (0 == ts || GST_CLOCK_TIME_NONE == ts) ts = me->ts; if (0 == ts || GST_CLOCK_TIME_NONE == ts) { ts = tNow (); me->ts = ts; } GST_INFO ("CCNxSink: pubish time: %0X\n", ts); gst_ccnxsink_send (me, data, size, ts); gst_buffer_unref (buffer); } }
/** * Returns data to the pipeline for media processing * * Whe our downstream elements need more data, the GST framework sees to * it that this function is called so we can produce some data to give them. * For us that means taking data off of the FIFO being fed by the background * task. If it should be empty, we sit around and wait. Once data does * arrive, we take it and send it into the pipeline [we return]. * * \param psrc -> to the element context needing to produce data * \param offset \todo I don't use this, why? * \param size \todo I don't use this, why? * \param buf where the data is to be placed * \return a GST status showing if we were successful in getting data * \retval GST_FLOW_OK buffer has been loaded with data * \retval GST_FLOW_ERROR something bad has happened */ static GstFlowReturn gst_ccnxsrc_create (GstBaseSrc * psrc, /*@unused@ */ guint64 offset, /*@unused@ */ guint size, GstBuffer ** buf) { Gstccnxsrc *me; gboolean looping = TRUE; GstBuffer *ans = NULL; me = GST_CCNXSRC (psrc); GST_DEBUG ("create called"); while (looping) { GST_DEBUG ("create looping"); if (fifo_empty (me)) { msleep (50); } else { ans = fifo_pop (me); looping = FALSE; } } if (ans) { guint sz; sz = GST_BUFFER_SIZE (ans); GST_LOG_OBJECT (me, "got some data %d", sz); *buf = ans; } else { return GST_FLOW_ERROR; } GST_DEBUG ("create returning a buffer"); return GST_FLOW_OK; }
/* * Read 1 char from fifo. * Returns 0 if fifo is empty, otherwise 1. */ u8 fifo_read_char(char *c) { if (fifo_empty()) return 0; *c = sbp_msg_fifo[head]; head = (head+1) % FIFO_LEN; return 1; }
// Dequeue 1 byte in the fifo // The caller should check that the fifo is not empty byte fifo_dequeue(struct instance_fifo *fifo) { if (!fifo_empty(fifo)) { byte result = fifo->fifo[fifo->fifo_head]; fifo->fifo_head = (fifo->fifo_head + 1) % fifo->fifo_size; return result; } return 0; }
// Dequeue 1 byte in the fifo. // The caller should check that the fifo is not empty byte fifo_dequeue() { if (!fifo_empty()) { byte result = fifo[fifo_head]; fifo_head = (fifo_head + 1) % FIFO_SIZE; return result; } return 0; }
void vBSPACMdeviceEFM32periphUSARTtxirqhandler (sBSPACMperiphUARTstate * const usp) { BSPACM_CORE_SAVED_INTERRUPT_STATE(istate); USART_TypeDef * const usart = (USART_TypeDef *)usp->uart; if (usp->tx_fifo_ni_ && (USART_STATUS_TXBL & usart->STATUS)) { BSPACM_CORE_DISABLE_INTERRUPT(); while ((USART_STATUS_TXBL & usart->STATUS) && (! fifo_empty(usp->tx_fifo_ni_))) { usart->TXDATA = fifo_pop_tail(usp->tx_fifo_ni_, 0); usp->tx_count += 1; } if (fifo_empty(usp->tx_fifo_ni_)) { usart->IEN &= ~USART_IF_TXBL; } } BSPACM_CORE_REENABLE_INTERRUPT(istate); }
uint8_t fifo_read(fifo_t *fifo, uint8_t *byte) { if(fifo_empty(fifo)) return 1; *byte = fifo->data[fifo->read]; fifo->read++; if(fifo->read >= fifo->size) fifo->read = 0; return 0; }
void fifo_shift(struct fifo *f, void *val) { struct node *el = malloc(sizeof(*el)); el->val = val; if(fifo_empty(f)) { f->F = f->L = el; el->next = NULL; } else { f->L->next = el; f->L = el; } }
void *fifo_unshift(struct fifo *f) { assert(!fifo_empty(f)); struct node *el = f->F; if(el->next != NULL) f->F = el->next; else f->L = f->F = NULL; void *val = el->val; free(el); return val; }
void vBSPACMdeviceEFM32periphLEUARTirqhandler (sBSPACMperiphUARTstate * const usp) { BSPACM_CORE_SAVED_INTERRUPT_STATE(istate); LEUART_TypeDef * const leuart = (LEUART_TypeDef *)usp->uart; BSPACM_CORE_DISABLE_INTERRUPT(); if (LEUART_STATUS_RXDATAV & leuart->STATUS) { while (LEUART_STATUS_RXDATAV & leuart->STATUS) { uint16_t rxdatax = leuart->RXDATAX; if (0 == ((LEUART_RXDATAX_PERR | LEUART_RXDATAX_FERR) & rxdatax)) { if ((! usp->rx_fifo_ni_) || (0 > fifo_push_head(usp->rx_fifo_ni_, leuart->RXDATA))) { usp->rx_dropped_errors += 1; } usp->rx_count += 1; } else { if (LEUART_RXDATAX_PERR & rxdatax) { usp->rx_parity_errors += 1; } if (LEUART_RXDATAX_FERR & rxdatax) { usp->rx_frame_errors += 1; } } }; } if (usp->tx_fifo_ni_ && (LEUART_STATUS_TXBL & leuart->STATUS)) { while ((LEUART_STATUS_TXBL & leuart->STATUS) && (! fifo_empty(usp->tx_fifo_ni_))) { leuart->TXDATA = fifo_pop_tail(usp->tx_fifo_ni_, 0); usp->tx_count += 1; } if (fifo_empty(usp->tx_fifo_ni_)) { leuart->IEN &= ~LEUART_IF_TXBL; } } BSPACM_CORE_REENABLE_INTERRUPT(istate); }
/* fifo_get -- retire un élément de la file et renvoie un pointeur * sur son contenu. * Retourne NULL si la file est vide. * Complexité: O(1) */ void *fifo_get(Fifo *fifo) { void *ret; assert((fifo != NULL) && (fifo->items != NULL)); if (fifo_empty(fifo)) return NULL; else ret = fifo->items[fifo->oldest++]; if (fifo->oldest == fifo->max_size) fifo->oldest = 0; return ret; }
static int pop(position_t *pos) { if (!fifo_empty()) { *pos = movement[read]; read = (read + 1) % (MOV_MAX + 1); last_op = 0; return 1; } else { return 0; } }
static void worker_runphase1(workqueue_t *wq) { wip_t *wipslot; tdata_t *pow; int wipslotnum, pownum; for (;;) { pthread_mutex_lock(&wq->wq_queue_lock); while (fifo_empty(wq->wq_queue)) { if (wq->wq_nomorefiles == 1) { pthread_cond_broadcast(&wq->wq_work_avail); pthread_mutex_unlock(&wq->wq_queue_lock); /* on to phase 2 ... */ return; } pthread_cond_wait(&wq->wq_work_avail, &wq->wq_queue_lock); } /* there's work to be done! */ pow = fifo_remove(wq->wq_queue); pownum = wq->wq_nextpownum++; pthread_cond_broadcast(&wq->wq_work_removed); assert(pow != NULL); /* merge it into the right slot */ wipslotnum = pownum % wq->wq_nwipslots; wipslot = &wq->wq_wip[wipslotnum]; pthread_mutex_lock(&wipslot->wip_lock); pthread_mutex_unlock(&wq->wq_queue_lock); wip_add_work(wipslot, pow); if (wipslot->wip_nmerged == wq->wq_maxbatchsz) wip_save_work(wq, wipslot, wipslotnum); pthread_mutex_unlock(&wipslot->wip_lock); } }
void thread_pool_exit_all( thread_pool_t *pool ) { dna_mutex_lock( pool->mutex ); fifo_each( pool->tasks, &delete_task ); fifo_empty(pool->tasks); fifo_each( pool->thread_queue, &kill_thread ); /* push new "work" into the queue to unblock threads waiting on the list */ int x = 0; for ( x = 0; x < fifo_count( pool->thread_queue ); x++) { /* We guard and don't execute NULL function pointers This merely meets the needs of the fifo for unblocking. */ thread_pool_enqueue( pool, NULL, NULL ); } dna_cond_signal( pool->wait ); dna_mutex_unlock( pool->mutex ); }
int main( int argc, char **argv ) { fifo_queue_t q; fifo_init(&q); #pragma omp parallel #pragma omp single nowait { int i; for(i=1;i<5;++i) { #pragma omp task { int j; for(j = 0; j < 1000; ++j) { fifo_enqueue(&q, i*1000+j); } } #pragma omp task { int d, j; for(j = 0; j < 1000; ++j) { d = fifo_dequeue(&q); if (d) printf("dequeue %d\n", d); } } } } int d; while (true) { d = fifo_dequeue(&q); if (d == -1) break; printf("dequeue %d\n", d); } assert(fifo_empty(&q)); #pragma omp taskwait fifo_free(&q); return 0; }
static void test2() { fifo_t *f1 = fifo_new(1024 * 4); int i; void *p; for (i = 0; i < 1023; i++) { p = fifo_alloc(f1, 13); assert(p); *(int *)p = i; fifo_put(f1, p, 13); p = fifo_get(f1, 13); assert(p); assert(*(int *)p == i); fifo_end(f1, p, 13); } assert(fifo_empty(f1)); }
/*@null@*/ static GstBuffer * fifo_pop (Gstccnxsink * me) { GstBuffer *ans; int next; GST_DEBUG ("CCNxSink: fifo popping"); if (fifo_empty (me)) { return NULL; } next = me->fifo_head; ans = me->fifo[next]; if (++next >= CCNX_SINK_FIFO_MAX) next = 0; g_mutex_lock (me->fifo_lock); me->fifo_head = next; g_cond_signal (me->fifo_cond); g_mutex_unlock (me->fifo_lock); return ans; }
/* * Notify if possible receive data ready. Must be called * with sc->mutex held (cyapa_lock(sc)). */ static void cyapa_notify(struct cyapa_softc *sc) { CYAPA_LOCK_ASSERT(sc); if (sc->data_signal || !fifo_empty(sc, &sc->rfifo)) { KNOTE_LOCKED(&sc->selinfo.si_note, 0); if (sc->blocked || sc->isselect) { if (sc->blocked) { sc->blocked = 0; wakeup(&sc->blocked); } if (sc->isselect) { sc->isselect = 0; selwakeup(&sc->selinfo); } } } }
static void drain_tx_queue(struct serial_port *sp) { unsigned char lsr; unsigned char b; int count; count = 0; while (1) { cli(); // Is UART ready to transmit next byte lsr = inp((unsigned short) (sp->iobase + UART_LSR)); sp->linestatus |= (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)); //kprintf("drain_tx_queue: lsr=%02X\n", lsr); if (!(lsr & LSR_TXRDY)) { sti(); break; } // Is tx queue empty if (fifo_empty(&sp->txq)) { sti(); break; } // Get next byte from queue b = fifo_get(&sp->txq); //kprintf("fifo get: h:%d t:%d c:%d\n", sp->txq.head, sp->txq.tail, sp->txq.count); //kprintf("serial: xmit %02X (drain)\n", b); outp(sp->iobase + UART_TX, b); sp->tx_busy = 1; count++; sti(); } // Release transmitter queue resources if (count > 0) release_sem(&sp->tx_sem, count); }
static void test3() { fifo_t *f1 = fifo_new(1024 * 4); int i; void *p; for (i = 0; i < 1023; i++) { p = fifo_alloc(f1, 13); assert(p); *(int *)p = i; fifo_put(f1, p, 13); p = fifo_extend(f1, p, 13, 13 * 2); assert(p); fifo_put(f1, p, 26); printf("%u %u\n", f1->pt, f1->gt); p = fifo_get(f1, 26); assert(p); assert(*(int *)p == i); fifo_end(f1, p, 26); } assert(fifo_empty(f1)); }
int signal_wait(struct thread* thread, uint64_t wait_mask) { int retval = 0; struct thread *sleeping = 0; // set if thread should go to sleep. { struct process* process = thread->process; SPIN_GUARD_RAW(process->signal.lock); SPIN_GUARD_RAW(thread->signal.lock); // is a waited signal already pending? int process_signum = __builtin_ffsll(process->signal.pending_mask & wait_mask); int thread_signum = __builtin_ffsll(thread->signal.pending_mask & wait_mask); if (process_signum && (!thread_signum || process_signum < thread_signum)) { int signum = process_signum - 1; uint64_t sigbit = 1ull << (signum%SIGNAL_LIMIT); struct process_signal_info* sig = process->signal.sig + signum; fifo_item_t *fi = fifo_pop(&sig->pending); if (fifo_empty(&sig->pending)) process->signal.pending_mask &= ~sigbit; struct signal_pending* pending = fifo_container(fi, struct signal_pending, item); thread->signal.wait_mask = 0; thread->signal.wait_signum = retval = signum; thread->signal.wait_sigval = pending->sigval; heap_free(pending); } else if (thread_signum) {
/** * @fn int z_compress(z_t zip, const z_file_t zname, const char* password, z_clevel_et level, _Bool append, _Bool exclude_path, fifo_t files) * @brief Creation of a new ZIP file. * @param zip The ZIP context. * @param zname The zip file name. * @param password the zip password else NULL or empty. * @param level The compression level. * @param append Append mode. * @param exclude_path Exclude the file path. * @param files The file list. * @retunr 0 on success else -1. */ int z_compress(z_t zip, const z_file_t zname, const char* password, z_clevel_et level, _Bool append, _Bool exclude_path, fifo_t files) { struct z_s* z = Z_CAST(zip); z_file_t filename_try; int size_buf = 0; void* buf = NULL; zipFile zf; size_buf = Z_WRITE_BUFFER_SIZE; buf = (void*)malloc(size_buf); if (!buf) { logger(LOG_ERR, "Error allocating memory\n"); return -1; } bzero(filename_try, sizeof(z_file_t)); strcpy(filename_try, zname); if(!string_indexof(filename_try, ".") == -1) strcat(filename_try, ".zip"); zf = zipOpen64(filename_try, (append) ? 2 : 0); if (!zf) { free(buf); logger(LOG_ERR, "Error opening %s\n", filename_try); return -1; } else logger(LOG_DEBUG, "Creating %s\n", filename_try); while(!fifo_empty(files)) { const char* filenameinzip = fifo_pop(files); FILE * fin; int size_read; const char *savefilenameinzip; zip_fileinfo zi; unsigned long crc_file = 0; int zip64 = 0; memset(&zi, 0, sizeof(zip_fileinfo)); if(file_is_dir(filenameinzip)) { ((char*)filenameinzip)[strlen(filenameinzip)] = z->dir_delimiter; strncat((char*)filenameinzip, ".empty", sizeof(file_name_t)); file_touch(filenameinzip); } logger(LOG_DEBUG, "Trying to add file '%s'\n", filenameinzip); file_time(filenameinzip, (struct tm*)&zi.tmz_date); if(password != NULL && strlen(password)) if(z_get_file_crc(filenameinzip, buf, size_buf, &crc_file) != ZIP_OK) { zipClose(zf, NULL); free(buf); logger(LOG_ERR, "Error getting the crc for the file %s\n", filenameinzip); return -1; } zip64 = file_is_large_file(filenameinzip); /* The path name saved, should not include a leading slash. */ /*if it did, windows/xp and dynazip couldn't read the zip file. */ savefilenameinzip = filenameinzip; while(savefilenameinzip[0] == z->dir_delimiter) savefilenameinzip++; /*should the zip file contain any path at all?*/ if(exclude_path) { const char *tmpptr; const char *lastslash = 0; for(tmpptr = savefilenameinzip; *tmpptr; tmpptr++) { if(*tmpptr == z->dir_delimiter) lastslash = tmpptr; } if(lastslash) savefilenameinzip = lastslash+1; // base filename follows last slash. } if(zipOpenNewFileInZip3_64(zf, savefilenameinzip, &zi, NULL, 0, NULL, 0, NULL /* comment*/, (level != 0) ? Z_DEFLATED : 0, level,0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, (password != NULL && strlen(password)) ? password : NULL, crc_file, zip64) != ZIP_OK) { zipClose(zf, NULL); free(buf); logger(LOG_ERR, "Error in opening %s in zipfile\n", filenameinzip); return -1; } fin = fopen64(filenameinzip, "rb"); if(!fin) { zipCloseFileInZip(zf); zipClose(zf, NULL); free(buf); logger(LOG_ERR, "Error in opening %s for reading\n", filenameinzip); return -1; } do { size_read = (int)fread(buf,1,size_buf,fin); if(size_read < size_buf) if(!feof(fin)) { logger(LOG_ERR, "Error in reading %s\n",filenameinzip); break; } if (size_read > 0) { if(zipWriteInFileInZip(zf, buf, size_read) < 0) { logger(LOG_ERR, "Error in writing %s in the zipfile\n", filenameinzip); break; } } } while(size_read > 0); if(fin) fclose(fin); if(zipCloseFileInZip(zf) != ZIP_OK) { logger(LOG_ERR, "Error in closing %s in the zipfile\n", filenameinzip); break; } } if(zipClose(zf, NULL) != ZIP_OK) logger(LOG_ERR, "Error in closing %s\n",filename_try); free(buf); return 0; }
static int bch_allocator_thread(void *arg) { struct cache *ca = arg; mutex_lock(&ca->set->bucket_lock); while (1) { /* * First, we pull buckets off of the unused and free_inc lists, * possibly issue discards to them, then we add the bucket to * the free list: */ while (!fifo_empty(&ca->free_inc)) { long bucket; fifo_pop(&ca->free_inc, bucket); if (ca->discard) { mutex_unlock(&ca->set->bucket_lock); blkdev_issue_discard(ca->bdev, bucket_to_sector(ca->set, bucket), ca->sb.block_size, GFP_KERNEL, 0); mutex_lock(&ca->set->bucket_lock); } allocator_wait(ca, bch_allocator_push(ca, bucket)); wake_up(&ca->set->btree_cache_wait); wake_up(&ca->set->bucket_wait); } /* * We've run out of free buckets, we need to find some buckets * we can invalidate. First, invalidate them in memory and add * them to the free_inc list: */ retry_invalidate: allocator_wait(ca, ca->set->gc_mark_valid && !ca->invalidate_needs_gc); invalidate_buckets(ca); /* * Now, we write their new gens to disk so we can start writing * new stuff to them: */ allocator_wait(ca, !atomic_read(&ca->set->prio_blocked)); if (CACHE_SYNC(&ca->set->sb)) { /* * This could deadlock if an allocation with a btree * node locked ever blocked - having the btree node * locked would block garbage collection, but here we're * waiting on garbage collection before we invalidate * and free anything. * * But this should be safe since the btree code always * uses btree_check_reserve() before allocating now, and * if it fails it blocks without btree nodes locked. */ if (!fifo_full(&ca->free_inc)) goto retry_invalidate; bch_prio_write(ca); } } }
static int cyaparead(struct cdev *dev, struct uio *uio, int ioflag) { struct cyapa_softc *sc; int error; int didread; size_t n; char* ptr; sc = dev->si_drv1; /* If buffer is empty, load a new event if it is ready */ cyapa_lock(sc); again: if (fifo_empty(sc, &sc->rfifo) && (sc->data_signal || sc->delta_x || sc->delta_y || sc->track_but != sc->reported_but)) { uint8_t c0; uint16_t but; int delta_x; int delta_y; int delta_z; /* Accumulate delta_x, delta_y */ sc->data_signal = 0; delta_x = sc->delta_x; delta_y = sc->delta_y; delta_z = sc->delta_z; if (delta_x > 255) { delta_x = 255; sc->data_signal = 1; } if (delta_x < -256) { delta_x = -256; sc->data_signal = 1; } if (delta_y > 255) { delta_y = 255; sc->data_signal = 1; } if (delta_y < -256) { delta_y = -256; sc->data_signal = 1; } if (delta_z > 255) { delta_z = 255; sc->data_signal = 1; } if (delta_z < -256) { delta_z = -256; sc->data_signal = 1; } but = sc->track_but; /* Adjust baseline for next calculation */ sc->delta_x -= delta_x; sc->delta_y -= delta_y; sc->delta_z -= delta_z; sc->reported_but = but; /* * Fuzz reduces movement jitter by introducing some * hysteresis. It operates without cumulative error so * if you swish around quickly and return your finger to * where it started, so to will the mouse. */ delta_x = cyapa_fuzz(delta_x, &sc->fuzz_x); delta_y = cyapa_fuzz(delta_y, &sc->fuzz_y); delta_z = cyapa_fuzz(delta_z, &sc->fuzz_z); /* * Generate report */ c0 = 0; if (delta_x < 0) c0 |= 0x10; if (delta_y < 0) c0 |= 0x20; c0 |= 0x08; if (but & CYAPA_FNGR_LEFT) c0 |= 0x01; if (but & CYAPA_FNGR_MIDDLE) c0 |= 0x04; if (but & CYAPA_FNGR_RIGHT) c0 |= 0x02; fifo_write_char(sc, &sc->rfifo, c0); fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_x); fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_y); switch(sc->zenabled) { case 1: /* Z axis all 8 bits */ fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_z); break; case 2: /* * Z axis low 4 bits + 4th button and 5th button * (high 2 bits must be left 0). Auto-scale * delta_z to fit to avoid a wrong-direction * overflow (don't try to retain the remainder). */ while (delta_z > 7 || delta_z < -8) delta_z >>= 1; c0 = (uint8_t)delta_z & 0x0F; fifo_write_char(sc, &sc->rfifo, c0); break; default: /* basic PS/2 */ break; } cyapa_notify(sc); }