static void ajoy_enable(FAR const struct ajoy_lowerhalf_s *lower, ajoy_buttonset_t press, ajoy_buttonset_t release, ajoy_handler_t handler, FAR void *arg) { irqstate_t flags; ajoy_buttonset_t either = press | release; ajoy_buttonset_t bit; bool rising; bool falling; int i; /* Start with all interrupts disabled */ flags = enter_critical_section(); ajoy_disable(); iinfo("press: %02x release: %02x handler: %p arg: %p\n", press, release, handler, arg); /* If no events are indicated or if no handler is provided, then this * must really be a request to disable interrupts. */ if (either && handler) { /* Save the new the handler and argument */ g_ajoyhandler = handler; g_ajoyarg = arg; /* Check each GPIO. */ for (i = 0; i < AJOY_NGPIOS; i++) { /* Enable interrupts on each pin that has either a press or * release event associated with it. */ bit = (1 << i); if ((either & bit) != 0) { /* Active low so a press corresponds to a falling edge and * a release corresponds to a rising edge. */ falling = ((press & bit) != 0); rising = ((release & bit) != 0); iinfo("GPIO %d: rising: %d falling: %d\n", i, rising, falling); (void)stm32_gpiosetevent(g_joygpio[i], rising, falling, true, ajoy_interrupt, NULL); } } } leave_critical_section(flags); }
static int max11802_open(FAR struct file *filep) { #ifdef CONFIG_MAX11802_REFCNT FAR struct inode *inode; FAR struct max11802_dev_s *priv; uint8_t tmp; int ret; iinfo("Opening\n"); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct max11802_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = sem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(errno == EINTR); return -EINTR; } /* Increment the reference count */ tmp = priv->crefs + 1; if (tmp == 0) { /* More than 255 opens; uint8_t overflows to zero */ ret = -EMFILE; goto errout_with_sem; } /* When the reference increments to 1, this is the first open event * on the driver.. and an opportunity to do any one-time initialization. */ /* Save the new open count on success */ priv->crefs = tmp; errout_with_sem: sem_post(&priv->devsem); return ret; #else iinfo("Opening\n"); return OK; #endif }
static int tsc_attach(FAR struct ads7843e_config_s *state, xcpt_t isr) { /* Attach the ADS7843E interrupt */ iinfo("Attaching %p to IRQ %d\n", isr, SAM_TCS_IRQ); return irq_attach(SAM_TCS_IRQ, isr, NULL); }
static uint16_t ads7843e_sendcmd(FAR struct ads7843e_dev_s *priv, uint8_t cmd) { uint8_t buffer[2]; uint16_t result; /* Select the ADS7843E */ SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), true); /* Send the command */ (void)SPI_SEND(priv->spi, cmd); /* Wait a tiny amount to make sure that the acquisition time is complete */ up_udelay(3); /* 3 microseconds */ /* Read the 12-bit data (LS 4 bits will be padded with zero) */ SPI_RECVBLOCK(priv->spi, buffer, 2); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), false); result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1]; result = result >> 4; iinfo("cmd:%02x response:%04x\n", cmd, result); return result; }
static uint16_t max11802_sendcmd(FAR struct max11802_dev_s *priv, uint8_t cmd, int *tags) { uint8_t buffer[2]; uint16_t result; /* Select the MAX11802 */ SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); /* Send the command */ (void)SPI_SEND(priv->spi, cmd); /* Read the data */ SPI_RECVBLOCK(priv->spi, buffer, 2); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1]; *tags = result & 0xF; result >>= 4; /* Get rid of tags */ iinfo("cmd:%02x response:%04x\n", cmd, result); return result; }
static uint16_t tc_adc_read_sample(void) { uint16_t retval; uint32_t adcsr; uint16_t count = 0; /* Validate the conversion is complete */ adcsr = tc_adc_getreg(STM32_ADC_SR_OFFSET); while ((adcsr & ADC_SR_EOC) == 0) { adcsr = tc_adc_getreg(STM32_ADC_SR_OFFSET); count++; } /* Read the sample */ retval = tc_adc_getreg(STM32_ADC_DR_OFFSET); retval &= ADC_DR_DATA_MASK; if (count > 0) { iinfo("Count = %d\n", count); } return retval; }
static bool tsc_pendown(FAR struct ads7843e_config_s *state) { /* The /PENIRQ value is active low */ bool pendown = !sam_gpioread(GPIO_TCS_IRQ); iinfo("pendown:%d\n", pendown); return pendown; }
static int tc_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { #if 1 iinfo("cmd: %d arg: %ld\n", cmd, arg); return -ENOTTY; /* None yet supported */ #else FAR struct inode *inode; FAR struct tc_dev_s *priv; int ret; iinfo("cmd: %d arg: %ld\n", cmd, arg); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct tc_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = nxsem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); return ret; } /* Process the IOCTL by command */ switch (cmd) { /* ADD IOCTL COMMAND CASES HERE */ default: ret = -ENOTTY; break; } nxsem_post(&priv->devsem); return ret; #endif }
static int max11802_close(FAR struct file *filep) { #ifdef CONFIG_MAX11802_REFCNT FAR struct inode *inode; FAR struct max11802_dev_s *priv; int ret; iinfo("Closing\n"); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct max11802_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = sem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(errno == EINTR); return -EINTR; } /* Decrement the reference count unless it would decrement a negative * value. When the count decrements to zero, there are no further * open references to the driver. */ if (priv->crefs >= 1) { priv->crefs--; } sem_post(&priv->devsem); #endif iinfo("Closing\n"); return OK; }
static int max11802_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode; FAR struct max11802_dev_s *priv; int ret; iinfo("cmd: %d arg: %ld\n", cmd, arg); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct max11802_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = sem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(errno == EINTR); return -EINTR; } /* Process the IOCTL by command */ switch (cmd) { case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ { FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); DEBUGASSERT(priv->config != NULL && ptr != NULL); priv->config->frequency = SPI_SETFREQUENCY(priv->spi, *ptr); } break; case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ { FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); DEBUGASSERT(priv->config != NULL && ptr != NULL); *ptr = priv->config->frequency; } break; default: ret = -ENOTTY; break; } sem_post(&priv->devsem); return ret; }
static void ajoy_enable(FAR const struct ajoy_lowerhalf_s *lower, ajoy_buttonset_t press, ajoy_buttonset_t release, ajoy_handler_t handler, FAR void *arg) { irqstate_t flags; ajoy_buttonset_t either = press | release; ajoy_buttonset_t bit; int i; /* Start with all interrupts disabled */ flags = enter_critical_section(); ajoy_disable(); iinfo("press: %02x release: %02x handler: %p arg: %p\n", press, release, handler, arg); /* If no events are indicated or if no handler is provided, then this * must really be a request to disable interrupts. */ if (either && handler) { /* Save the new the handler and argument */ g_ajoyhandler = handler; g_ajoyarg = arg; /* Check each GPIO. */ for (i = 0; i < AJOY_NGPIOS; i++) { /* Enable interrupts on each pin that has either a press or * release event associated with it. */ bit = (1 << i); if ((either & bit) != 0) { /* REVISIT: It would be better if we reconfigured for * the edges of interest so that we do not get spurious * interrupts. */ sam_pioirqenable(g_joyirq[i]); } } } leave_critical_section(flags); }
static void tsc_enable(FAR struct ads7843e_config_s *state, bool enable) { /* Attach and enable, or detach and disable */ iinfo("IRQ:%d enable:%d\n", SAM_TCS_IRQ, enable); if (enable) { sam_gpioirqenable(SAM_TCS_IRQ); } else { sam_gpioirqdisable(SAM_TCS_IRQ); } }
static void tc_notify(FAR struct tc_dev_s *priv) { #ifndef CONFIG_DISABLE_POLL int i; #endif /* If no threads have the driver open, then just dump the state */ #ifdef CONFIG_TOUCHSCREEN_REFCNT if ((priv->crefs == 0) && priv->sample.contact == CONTACT_UP) { priv->sample.contact = CONTACT_NONE; priv->sample.valid = false; priv->id++; return; } #endif /* If there are threads waiting for read data, then signal one of them * that the read data is available. */ if (priv->nwaiters > 0) { /* After posting this semaphore, we need to exit because the touchscreen * is no longer available. */ nxsem_post(&priv->waitsem); } /* If there are threads waiting on poll() for touchscreen data to become available, * then wake them up now. NOTE: we wake up all waiting threads because we * do not know that they are going to do. If they all try to read the data, * then some make end up blocking after all. */ #ifndef CONFIG_DISABLE_POLL for (i = 0; i < CONFIG_TOUCHSCREEN_NPOLLWAITERS; i++) { struct pollfd *fds = priv->fds[i]; if (fds) { fds->revents |= POLLIN; iinfo("Report events: %02x\n", fds->revents); nxsem_post(fds->sem); } } #endif }
static bool tsc_busy(FAR struct ads7843e_config_s *state) { #if defined(CONFIG_DEBUG_INPUT) && defined(CONFIG_DEBUG_INFO) static bool last = (bool)-1; #endif /* BUSY is high impedance when CS is high (not selected). When CS is * is low, BUSY is active high. */ bool busy = sam_gpioread(GPIO_TCS_BUSY); #if defined(CONFIG_DEBUG_INPUT) && defined(CONFIG_DEBUG_INFO) if (busy != last) { iinfo("busy:%d\n", busy); last = busy; } #endif return busy; }
/***************************************************************************************************************************** open Prepares the database for use. An existing database is opened or otherwise an empty database is created. If the database is openend a table _META with meta info is loaded into a dictionary _META. The dictionary key is the code of the data element. A data element is either a tabel (dimension/event) or a field (characteristic/property). The value of the dictionary is the MET_INFO structure. This structure contains meta data about the data element. If the database is created an empty table _META is created. The function calls virtual functions, db_, which must be overriden by a derived class for a specific database implementation. ******************************************************************************************************************************/ void ARAS::open(DBInfo dbInfo) { if (isopen) return; // store db information this->dbInfo = dbInfo; // open or create database // performs the database specific initialization code, the specific information to be used is stored in the struct DBInfo. db_init_database(); // performs the database specific code to check whether a database alreay exists and open it. if (db_open_database()) { // read _META table from database into dictionary _META TABLE values; db_select_table("_META", {"CODE","INFO"}, values); for (auto i : values) _META.insert(std::pair<std::string, META_INFO>(i[0], META_INFO(i[1]))); } else { // performs the database specific code to create a new database based on DBInfo. db_create_database(); // create table _META: define the columns META_INFO imeta(data_type::DIM, 0, "_META", "", "", "_META", "CODE", 0, 0, 0, 0); META_INFO icode(data_type::STR, SIZE_META_CODE_MAX, "_META", "", "","_META", "", 0, 0, 1, 0); META_INFO idescs(data_type::STR, SIZE_DESCS_MAX, "_META", "", "", "_META", "", 0, 0, 0, 0); META_INFO idescl(data_type::STR, SIZE_DESCL_MAX, "_META", "", "", "_META", "", 0, 0, 0, 0); META_INFO iinfo(data_type::STR, 0, "_META", "", "", "_META", "",0, 0, 0, 0); // define the table META_TABLE meta = { { "_META", "Meta data", "Meta data", imeta }, { "CODE", "CODE", "CODE", icode }, { "DESCS", "Short Description", "Short Description", idescs }, { "DESCL", "Long Description", "Long Description", idescl }, { "INFO", "INFO", "INFO", iinfo } }; // performs the database specific code to create a new table db_create_table(meta); // load the meta data into the dictionary and the database table _META for (auto i : meta) insert_meta(i); } }
static ajoy_buttonset_t ajoy_buttons(FAR const struct ajoy_lowerhalf_s *lower) { ajoy_buttonset_t ret = 0; int i; /* Read each joystick GPIO value */ for (i = 0; i < AJOY_NGPIOS; i++) { /* Button outputs are pulled high. So a sensed low level means that the * button is pressed. */ if (!stm32_gpioread(g_joygpio[i])) { ret |= (1 << i); } } iinfo("Returning: %02x\n", ret); return ret; }
static void max11802_notify(FAR struct max11802_dev_s *priv) { #ifndef CONFIG_DISABLE_POLL int i; #endif /* If there are threads waiting for read data, then signal one of them * that the read data is available. */ if (priv->nwaiters > 0) { /* After posting this semaphore, we need to exit because the sample * is no longer available. */ sem_post(&priv->waitsem); } /* If there are threads waiting on poll() for MAX11802 data to become * available, then wake them up now. NOTE: we wake up all waiting * threads because we do not know that they are going to do. If they * all try to read the data, then some make end up blocking after all. */ #ifndef CONFIG_DISABLE_POLL for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++) { struct pollfd *fds = priv->fds[i]; if (fds) { fds->revents |= POLLIN; iinfo("Report events: %02x\n", fds->revents); sem_post(fds->sem); } } #endif }
int sam_tsc_setup(int minor) { FAR struct spi_dev_s *dev; int ret; iinfo("minor %d\n", minor); DEBUGASSERT(minor == 0); /* Configure and enable the ADS7843E interrupt pin as an input */ (void)sam_configgpio(GPIO_TCS_BUSY); (void)sam_configgpio(GPIO_TCS_IRQ); /* Configure the PIO interrupt */ sam_gpioirq(GPIO_TCS_IRQ); /* Get an instance of the SPI interface for the touchscreen chip select */ dev = sam_spibus_initialize(TSC_CSNUM); if (!dev) { ierr("ERROR: Failed to initialize SPI chip select %d\n", TSC_CSNUM); return -ENODEV; } /* Initialize and register the SPI touschscreen device */ ret = ads7843e_register(dev, &g_tscinfo, CONFIG_ADS7843E_DEVMINOR); if (ret < 0) { ierr("ERROR: Failed to initialize SPI chip select %d\n", TSC_CSNUM); /* sam_spibus_uninitialize(dev); */ return -ENODEV; } return OK; }
static int max11802_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) { FAR struct inode *inode; FAR struct max11802_dev_s *priv; int ret; int i; iinfo("setup: %d\n", (int)setup); DEBUGASSERT(filep && fds); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct max11802_dev_s *)inode->i_private; /* Are we setting up the poll? Or tearing it down? */ ret = sem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(errno == EINTR); return -EINTR; } if (setup) { /* Ignore waits that do not include POLLIN */ if ((fds->events & POLLIN) == 0) { ret = -EDEADLK; goto errout; } /* This is a request to set up the poll. Find an available * slot for the poll structure reference */ for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++) { /* Find an available slot */ if (!priv->fds[i]) { /* Bind the poll structure and this slot */ priv->fds[i] = fds; fds->priv = &priv->fds[i]; break; } } if (i >= CONFIG_MAX11802_NPOLLWAITERS) { fds->priv = NULL; ret = -EBUSY; goto errout; } /* Should we immediately notify on any of the requested events? */ if (priv->penchange) { max11802_notify(priv); } } else if (fds->priv) { /* This is a request to tear down the poll. */ struct pollfd **slot = (struct pollfd **)fds->priv; DEBUGASSERT(slot != NULL); /* Remove all memory of the poll setup */ *slot = NULL; fds->priv = NULL; } errout: sem_post(&priv->devsem); return ret; }
static ssize_t max11802_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode; FAR struct max11802_dev_s *priv; FAR struct touch_sample_s *report; struct max11802_sample_s sample; int ret; iinfo("buffer:%p len:%d\n", buffer, len); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct max11802_dev_s *)inode->i_private; /* Verify that the caller has provided a buffer large enough to receive * the touch data. */ if (len < SIZEOF_TOUCH_SAMPLE_S(1)) { /* We could provide logic to break up a touch report into segments and * handle smaller reads... but why? */ ierr("ERROR: Unsupported read size: %d\n", len); return -ENOSYS; } /* Get exclusive access to the driver data structure */ ret = sem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was cancelled by an signal */ ierr("ERROR: sem_wait: %d\n", errno); DEBUGASSERT(errno == EINTR); return -EINTR; } /* Try to read sample data. */ ret = max11802_sample(priv, &sample); if (ret < 0) { /* Sample data is not available now. We would ave to wait to get * receive sample data. If the user has specified the O_NONBLOCK * option, then just return an error. */ iinfo("Sample data is not available\n"); if (filep->f_oflags & O_NONBLOCK) { ret = -EAGAIN; goto errout; } /* Wait for sample data */ ret = max11802_waitsample(priv, &sample); if (ret < 0) { /* We might have been awakened by a signal */ ierr("ERROR: max11802_waitsample: %d\n", ret); goto errout; } } /* In any event, we now have sampled MAX11802 data that we can report * to the caller. */ report = (FAR struct touch_sample_s *)buffer; memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); report->npoints = 1; report->point[0].id = sample.id; report->point[0].x = sample.x; report->point[0].y = sample.y; /* Report the appropriate flags */ if (sample.contact == CONTACT_UP) { /* Pen is now up. Is the positional data valid? This is important to * know because the release will be sent to the window based on its * last positional data. */ if (sample.valid) { report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID; } else { report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; } } else if (sample.contact == CONTACT_DOWN) { /* First contact */ report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; } else /* if (sample->contact == CONTACT_MOVE) */ { /* Movement of the same contact */ report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; } iinfo(" id: %d\n", report->point[0].id); iinfo(" flags: %02x\n", report->point[0].flags); iinfo(" x: %d\n", report->point[0].x); iinfo(" y: %d\n", report->point[0].y); ret = SIZEOF_TOUCH_SAMPLE_S(1); errout: sem_post(&priv->devsem); iinfo("Returning: %d\n", ret); return ret; }
static ajoy_buttonset_t ajoy_supported(FAR const struct ajoy_lowerhalf_s *lower) { iinfo("Supported: %02x\n", AJOY_SUPPORTED); return (ajoy_buttonset_t)AJOY_SUPPORTED; }
static int ajoy_sample(FAR const struct ajoy_lowerhalf_s *lower, FAR struct ajoy_sample_s *sample) { #ifndef NO_JOYSTICK_ADC struct adc_msg_s adcmsg[MAX_ADC_CHANNELS]; FAR struct adc_msg_s *ptr; ssize_t nread; ssize_t offset; int have; int i; /* Read all of the available samples (handling the case where additional * channels are enabled). */ nread = file_read(&g_adcfile, adcmsg, MAX_ADC_CHANNELS * sizeof(struct adc_msg_s)); if (nread < 0) { if (nread != -EINTR) { ierr("ERROR: read failed: %d\n", (int)nread); } return nread; } else if (nread < NJOYSTICK_CHANNELS * sizeof(struct adc_msg_s)) { ierr("ERROR: read too small: %ld\n", (long)nread); return -EIO; } /* Sample and the raw analog inputs */ #ifdef CONFIG_ADC_DMA have = 0; #else /* If DMA is not supported, then we will have only a single ADC channel */ have = 2; sample->as_y = 0; #endif for (i = 0, offset = 0; i < MAX_ADC_CHANNELS && offset < nread && have != 3; i++, offset += sizeof(struct adc_msg_s)) { ptr = &adcmsg[i]; /* Is this one of the channels that we need? */ if ((have & 1) == 0 && ptr->am_channel == 0) { int32_t tmp = ptr->am_data; sample->as_x = (int16_t)tmp; have |= 1; iinfo("X sample: %ld -> %d\n", (long)tmp, (int)sample->as_x); } #ifdef CONFIG_ADC_DMA if ((have & 2) == 0 && ptr->am_channel == 1) { int32_t tmp = ptr->am_data; sample->as_y = (int16_t)tmp; have |= 2; iinfo("Y sample: %ld -> %d\n", (long)tmp, (int)sample->as_y); } #endif } if (have != 3) { ierr("ERROR: Could not find joystick channels\n"); return -EIO; } #else /* ADC support is disabled */ sample->as_x = 0; sample->as_y = 0; #endif /* Sample the discrete button inputs */ sample->as_buttons = ajoy_buttons(lower); iinfo("Returning: %02x\n", sample->as_buttons); return OK; }
static void max11802_worker(FAR void *arg) { FAR struct max11802_dev_s *priv = (FAR struct max11802_dev_s *)arg; FAR struct max11802_config_s *config; uint16_t x; uint16_t y; uint16_t xdiff; uint16_t ydiff; bool pendown; int ret; int tags, tags2; ASSERT(priv != NULL); /* Get a pointer the callbacks for convenience (and so the code is not so * ugly). */ config = priv->config; DEBUGASSERT(config != NULL); /* Disable the watchdog timer. This is safe because it is started only * by this function and this function is serialized on the worker thread. */ wd_cancel(priv->wdog); /* Lock the SPI bus so that we have exclusive access */ max11802_lock(priv->spi); /* Start coordinate measurement */ (void)max11802_sendcmd(priv, MAX11802_CMD_MEASUREXY, &tags); /* Get exclusive access to the driver data structure */ do { ret = sem_wait(&priv->devsem); /* This should only fail if the wait was cancelled by an signal * (and the worker thread will receive a lot of signals). */ DEBUGASSERT(ret == OK || errno == EINTR); } while (ret < 0); /* Check for pen up or down by reading the PENIRQ GPIO. */ pendown = config->pendown(config); /* Handle the change from pen down to pen up */ if (pendown) { iinfo("\nPD\n"); } else { iinfo("\nPU\n"); } if (!pendown) { /* The pen is up.. reset thresholding variables. */ priv->threshx = INVALID_THRESHOLD; priv->threshy = INVALID_THRESHOLD; /* Ignore the interrupt if the pen was already up (CONTACT_NONE == * pen up and already reported; CONTACT_UP == pen up, but not * reported). */ iinfo("\nPC%d\n", priv->sample.contact); if (priv->sample.contact == CONTACT_NONE || priv->sample.contact == CONTACT_UP) { goto ignored; } /* The pen is up. NOTE: We know from a previous test, that this is a * loss of contact condition. This will be changed to CONTACT_NONE * after the loss of contact is sampled. */ priv->sample.contact = CONTACT_UP; } /* It is a pen down event. If the last loss-of-contact event has not been * processed yet, then we have to ignore the pen down event (or else it * will look like a drag event) */ else if (priv->sample.contact == CONTACT_UP) { /* If we have not yet processed the last pen up event, then we * cannot handle this pen down event. We will have to discard it. * That should be okay because we will set the timer to to sample * again later. */ iinfo("Previous pen up event still in buffer\n"); max11802_notify(priv); wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1, (uint32_t)priv); goto ignored; } else { /* Wait for data ready * * Note: MAX11802 signals the readiness of the results using * the lowest 4 bits of the result. However these are the * last bits to be read out of the device. It appears that * the hardware value can change in the middle of the readout, * causing the upper bits to be still invalid even though lower * bits indicate valid result. * * We work around this by reading the registers once more after * the tags indicate they are ready. */ int readycount = 0; do { #ifdef CONFIG_MAX11802_SWAPXY x = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags); y = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags2); #else x = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags); y = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags2); #endif if (tags != 0xF && tags2 != 0xF) { readycount++; } } while (readycount < 2); /* Continue to sample the position while the pen is down */ wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1, (uint32_t)priv); /* Check if data is valid */ if ((tags & 0x03) != 0) { iinfo("Touch ended before measurement\n"); goto ignored; } /* Perform a thresholding operation so that the results will be more * stable. If the difference from the last sample is small, then * ignore the event. * * REVISIT: Should a large change in pressure also generate a event? */ xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x); ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y); /* Check the thresholds. Bail if there is no significant difference */ if (xdiff < CONFIG_MAX11802_THRESHX && ydiff < CONFIG_MAX11802_THRESHY) { /* Little or no change in either direction ... don't report anything. */ goto ignored; } /* When we see a big difference, snap to the new x/y thresholds */ priv->threshx = x; priv->threshy = y; /* Update the x/y position in the sample data */ priv->sample.x = priv->threshx; priv->sample.y = priv->threshy; /* The X/Y positional data is now valid */ priv->sample.valid = true; /* If this is the first (acknowledged) pen down report, then report * this as the first contact. If contact == CONTACT_DOWN, it will be * set to set to CONTACT_MOVE after the contact is first sampled. */ if (priv->sample.contact != CONTACT_MOVE) { /* First contact */ priv->sample.contact = CONTACT_DOWN; } } /* Indicate the availability of new sample data for this ID */ priv->sample.id = priv->id; priv->penchange = true; /* Notify any waiters that new MAX11802 data is available */ max11802_notify(priv); ignored: config->enable(config, true); /* Release our lock on the state structure and unlock the SPI bus */ sem_post(&priv->devsem); max11802_unlock(priv->spi); }
static int max11802_waitsample(FAR struct max11802_dev_s *priv, FAR struct max11802_sample_s *sample) { irqstate_t flags; int ret; /* Interrupts must be disabled when this is called to (1) prevent posting * of semaphores from interrupt handlers, and (2) to prevent sampled data * from changing until it has been reported. * * In addition, we will also disable pre-emption to prevent other threads * from getting control while we muck with the semaphores. */ sched_lock(); flags = enter_critical_section(); /* Now release the semaphore that manages mutually exclusive access to * the device structure. This may cause other tasks to become ready to * run, but they cannot run yet because pre-emption is disabled. */ sem_post(&priv->devsem); /* Try to get the a sample... if we cannot, then wait on the semaphore * that is posted when new sample data is available. */ while (max11802_sample(priv, sample) < 0) { /* Wait for a change in the MAX11802 state */ iinfo("Waiting..\n"); priv->nwaiters++; ret = sem_wait(&priv->waitsem); priv->nwaiters--; if (ret < 0) { /* If we are awakened by a signal, then we need to return * the failure now. */ ierr("ERROR: sem_wait: %d\n", errno); DEBUGASSERT(errno == EINTR); ret = -EINTR; goto errout; } } iinfo("Sampled\n"); /* Re-acquire the semaphore that manages mutually exclusive access to * the device structure. We may have to wait here. But we have our * sample. Interrupts and pre-emption will be re-enabled while we wait. */ ret = sem_wait(&priv->devsem); errout: /* Then re-enable interrupts. We might get interrupt here and there * could be a new sample. But no new threads will run because we still * have pre-emption disabled. */ leave_critical_section(flags); /* Restore pre-emption. We might get suspended here but that is okay * because we already have our sample. Note: this means that if there * were two threads reading from the MAX11802 for some reason, the data * might be read out of order. */ sched_unlock(); return ret; }
int max11802_register(FAR struct spi_dev_s *spi, FAR struct max11802_config_s *config, int minor) { FAR struct max11802_dev_s *priv; char devname[DEV_NAMELEN]; #ifdef CONFIG_MAX11802_MULTIPLE irqstate_t flags; #endif int ret; iinfo("spi: %p minor: %d\n", spi, minor); /* Debug-only sanity checks */ DEBUGASSERT(spi != NULL && config != NULL && minor >= 0 && minor < 100); /* Create and initialize a MAX11802 device driver instance */ #ifndef CONFIG_MAX11802_MULTIPLE priv = &g_max11802; #else priv = (FAR struct max11802_dev_s *)kmm_malloc(sizeof(struct max11802_dev_s)); if (!priv) { ierr("ERROR: kmm_malloc(%d) failed\n", sizeof(struct max11802_dev_s)); return -ENOMEM; } #endif /* Initialize the MAX11802 device driver instance */ memset(priv, 0, sizeof(struct max11802_dev_s)); priv->spi = spi; /* Save the SPI device handle */ priv->config = config; /* Save the board configuration */ priv->wdog = wd_create(); /* Create a watchdog timer */ priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */ priv->threshy = INVALID_THRESHOLD; /* Initialize thresholding logic */ /* Initialize semaphores */ sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ /* The pen event semaphore is used for signaling and, hence, should not * have priority inheritance enabled. */ sem_setprotocol(&priv->waitsem, SEM_PRIO_NONE); /* Make sure that interrupts are disabled */ config->clear(config); config->enable(config, false); /* Attach the interrupt handler */ ret = config->attach(config, max11802_interrupt); if (ret < 0) { ierr("ERROR: Failed to attach interrupt\n"); goto errout_with_priv; } iinfo("Mode: %d Bits: 8 Frequency: %d\n", CONFIG_MAX11802_SPIMODE, CONFIG_MAX11802_FREQUENCY); /* Lock the SPI bus so that we have exclusive access */ max11802_lock(spi); /* Configure MAX11802 registers */ SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_WR); (void)SPI_SEND(priv->spi, MAX11802_MODE); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_AVG_WR); (void)SPI_SEND(priv->spi, MAX11802_AVG); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_TIMING_WR); (void)SPI_SEND(priv->spi, MAX11802_TIMING); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_DELAY_WR); (void)SPI_SEND(priv->spi, MAX11802_DELAY); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); /* Test that the device access was successful. */ SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_RD); ret = SPI_SEND(priv->spi, 0); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); /* Unlock the bus */ max11802_unlock(spi); if (ret != MAX11802_MODE) { ierr("ERROR: max11802 mode readback failed: %02x\n", ret); goto errout_with_priv; } /* Register the device as an input device */ (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); iinfo("Registering %s\n", devname); ret = register_driver(devname, &max11802_fops, 0666, priv); if (ret < 0) { ierr("ERROR: register_driver() failed: %d\n", ret); goto errout_with_priv; } /* If multiple MAX11802 devices are supported, then we will need to add * this new instance to a list of device instances so that it can be * found by the interrupt handler based on the recieved IRQ number. */ #ifdef CONFIG_MAX11802_MULTIPLE flags = enter_critical_section(); priv->flink = g_max11802list; g_max11802list = priv; leave_critical_section(flags); #endif /* Schedule work to perform the initial sampling and to set the data * availability conditions. */ ret = work_queue(HPWORK, &priv->work, max11802_worker, priv, 0); if (ret != 0) { ierr("ERROR: Failed to queue work: %d\n", ret); goto errout_with_priv; } /* And return success (?) */ return OK; errout_with_priv: sem_destroy(&priv->devsem); #ifdef CONFIG_MAX11802_MULTIPLE kmm_free(priv); #endif return ret; }
static void tc_worker(FAR void *arg) { FAR struct tc_dev_s *priv = (FAR struct tc_dev_s *)arg; uint32_t delay = TC_PENUP_POLL_TICKS; uint16_t value; uint16_t newx = 0; int16_t xdiff; int16_t ydiff; int ret; DEBUGASSERT(priv != NULL); /* Perform the next action based on the state of the conversions */ switch (priv->state) { /* The touchscreen is IDLE and we are ready to begin the next sample */ case TC_READY: { /* Select DRIVE for Y sampling */ /* Configure XL, XR with drive voltages and disable YU drive. Note that * this is configuring the DRIVEA and DRIVEB outputs to enable the on-board * transistor drive logic to energize the touch panel. */ *((uint32_t *) LCD_TP_PORT_SETRESET) = LCD_SAMPY_BITS; /* Allow time for the Y DRIVE to settle */ priv->resamplecount = 0; priv->sampcount = 0; priv->value = 0; priv->state = TC_READY_SETTLE; delay = TC_SETTLE_TICKS; } break; case TC_READY_SETTLE: { /* Start Y sampling */ tc_y_sample(); /* Allow time for the Y pend down sampling */ priv->state = TC_YPENDOWN; delay = TC_SAMPLE_TICKS; } break; /* The Y sampling time has elapsed and the Y value should be ready * for conversion */ case TC_YPENDOWN: { /* Convert the Y sample value */ value = tc_adc_read_sample(); /* A converted value at the minimum would mean that there is no touch * and that the sampling period is complete. */ if (!tc_valid_sample(value)) { priv->state = TC_PENUP; } else { /* Allow time for touch inputs to stabilize */ priv->state = TC_DEBOUNCE; delay = TC_DEBOUNCE_TICKS; } } break; /* The debounce time period has elapsed and we are ready to re-sample * the touchscreen. */ case TC_RESAMPLE: { /* Select DRIVE for Y sampling */ /* Configure XL, XR with drive voltages and disable YU drive. Note that * this is configuring the DRIVEA and DRIVEB outputs to enable the on-board * transistor drive logic to energize the touch panel. */ *((uint32_t *) LCD_TP_PORT_SETRESET) = LCD_SAMPY_BITS; /* Allow time for the Y DRIVE to settle */ priv->state = TC_DEBOUNCE; delay = TC_SETTLE_TICKS; } break; case TC_DEBOUNCE: { /* (Re-)start Y sampling */ tc_y_sample(); /* Allow time for the Y sampling */ priv->state = TC_YSAMPLE; delay = TC_SAMPLE_TICKS; } break; /* The Y sampling period has elapsed and we are ready to perform the * conversion. */ case TC_YSAMPLE: /* Allowing time for the Y sampling */ { /* Read the Y axis position */ value = tc_adc_read_sample(); /* A converted value at the minimum would mean that we lost the contact * before all of the conversions were completed. At converted value at * the maximum value is probably bad too. */ if (!tc_valid_sample(value)) { #ifdef CONFIG_TOUCHSCREEN_RESAMPLE priv->state = TC_RESAMPLE; delay = TC_RESAMPLE_TICKS; #else priv->state = TC_PENUP; #endif } else { value = MAX_ADC - value; priv->value += value; if (++priv->sampcount < CONFIG_TOUCHSCREEN_AVG_SAMPLES) { priv->state = TC_READY_SETTLE; delay = 1; break; } priv->newy = value / CONFIG_TOUCHSCREEN_AVG_SAMPLES; priv->value = 0; priv->sampcount = 0; iinfo("Y=%d\n", priv->newy); /* Configure YU and YD with drive voltages and disable XR drive. Note that * this is configuring the DRIVEA and DRIVEB outputs to enable the on-board * transistor drive logic to energize the touch panel. */ *((uint32_t *) LCD_TP_PORT_SETRESET) = LCD_SAMPX_BITS; /* Allow time for the X sampling */ priv->state = TC_XSETTLE; delay = TC_SETTLE_TICKS; } } break; case TC_XRESAMPLE: /* Perform X resampling */ { if (priv->resamplecount-- == 0) { priv->state = TC_PENUP; break; } } case TC_XSETTLE: /* Allowing time X to settle after changing DRIVE */ { /* The X Drive settling time has elaspsed and it's time to start * the conversion */ /* Start X sampling */ tc_x_sample(); /* Allow time for the X sampling */ priv->state = TC_XSAMPLE; delay = TC_SAMPLE_TICKS; } break; case TC_XSAMPLE: /* Allowing time for the X sampling */ { /* Read the converted X axis position */ value = tc_adc_read_sample(); /* A converted value at the minimum would mean that we lost the contact * before all of the conversions were completed. At converted value at * the maximum value is probably bad too. */ if (!tc_valid_sample(value)) { #ifdef CONFIG_TOUCHSCREEN_RESAMPLE priv->state = TC_XRESAMPLE; if (priv->resamplecount == 0) priv->resamplecount = 1; delay = TC_RESAMPLE_TICKS; #else priv->state = TC_PENUP; #endif } else { /* Calculate the X axis position */ //value = MAX_ADC - value; priv->value += value; if (++priv->sampcount < CONFIG_TOUCHSCREEN_AVG_SAMPLES) { priv->state = TC_XSETTLE; delay = 1; break; } newx = value / CONFIG_TOUCHSCREEN_AVG_SAMPLES; iinfo("X=%d\n", newx); /* Samples are available */ priv->state = TC_PENDOWN; } } break; } /* Check for terminal conditions.. */ /* Check if the sampling resulted in a pen up decision. If so, we need to * handle the change from pen down to pen up. */ if (priv->state == TC_PENUP) { /* Ignore if the pen was already down (CONTACT_NONE == pen up and already * reported. CONTACT_UP == pen up, but not reported) */ if (priv->sample.contact != CONTACT_NONE && priv->sample.contact != CONTACT_UP) { /* The pen is up. We know from the above test, that this is a * loss of contact condition. This will be changed to CONTACT_NONE * after the loss of contact is sampled. */ priv->sample.contact = CONTACT_UP; /* Indicate the availability of new sample data for this ID */ priv->sample.id = priv->id; priv->penchange = true; /* Notify any waiters that new touchscreen data is available */ iinfo("1:X=%d, Y=%d\n", priv->sample.x, priv->sample.y); tc_notify(priv); } /* Set up for the next poll */ priv->sample.valid = false; priv->state = TC_READY; delay = TC_PENUP_POLL_TICKS; } /* Check if the sampling resulted in a pen down decision. */ else if (priv->state == TC_PENDOWN) { /* It is a pen down event. If the last loss-of-contact event has not been * processed yet, then we have to ignore the pen down event (or else it will * look like a drag event) */ if (priv->sample.contact != CONTACT_UP) { /* Perform a thresholding operation so that the results will be more stable. * If the difference from the last sample is small, then ignore the event. */ xdiff = (int16_t)priv->sample.x - (int16_t)newx; if (xdiff < 0) { xdiff = -xdiff; } ydiff = (int16_t)priv->sample.y - (int16_t)priv->newy; if (ydiff < 0) { ydiff = -ydiff; } if (xdiff >= CONFIG_TOUCHSCREEN_THRESHX || ydiff >= CONFIG_TOUCHSCREEN_THRESHY) { /* There is some change above the threshold... Report the change. */ #ifdef CONFIG_LCD_LANDSCAPE priv->sample.x = MAX_ADC - priv->newy; priv->sample.y = newx; #else priv->sample.x = newx; priv->sample.y = priv->newy; #endif priv->sample.valid = true; /* If this is the first (acknowledged) penddown report, then report * this as the first contact. If contact == CONTACT_DOWN, it will be * set to set to CONTACT_MOVE after the contact is first sampled. */ if (priv->sample.contact != CONTACT_MOVE) { /* First contact */ priv->sample.contact = CONTACT_DOWN; } /* Indicate the availability of new sample data for this ID */ priv->sample.id = priv->id; priv->penchange = true; /* Notify any waiters that nes touchscreen data is available */ iinfo("2:X=%d, Y=%d\n", priv->sample.x, priv->sample.y); tc_notify(priv); } } /* Set up for the next poll */ priv->state = TC_READY; delay = TC_PENDOWN_POLL_TICKS; } /* Set up the next sample event */ ret = work_queue(HPWORK, &priv->work, tc_worker, priv, delay); DEBUGASSERT(ret == 0); }
int stm32_tsc_setup(int minor) { FAR struct tc_dev_s *priv; char devname[DEV_NAMELEN]; #ifdef CONFIG_TOUCHSCREEN_MULTIPLE irqstate_t flags; #endif int ret; iinfo("minor: %d\n", minor); DEBUGASSERT(minor >= 0 && minor < 100); /* If we only have one touchscreen, check if we already did init */ #ifndef CONFIG_TOUCHSCREEN_MULTIPLE if (g_touchinitdone) { return OK; } #endif /* Configure the touchscreen DRIVEA and DRIVEB pins for output */ stm32_configgpio(GPIO_TP_DRIVEA); stm32_configgpio(GPIO_TP_DRIVEB); /* Configure Analog inputs for sampling X and Y coordinates */ stm32_configgpio(GPIO_TP_XL); stm32_configgpio(GPIO_TP_YD); tc_adc_init(); /* Create and initialize a touchscreen device driver instance */ #ifndef CONFIG_TOUCHSCREEN_MULTIPLE priv = &g_touchscreen; #else priv = (FAR struct tc_dev_s *)kmm_malloc(sizeof(struct tc_dev_s)); if (!priv) { ierr("ERROR: kmm_malloc(%d) failed\n", sizeof(struct tc_dev_s)); return -ENOMEM; } #endif /* Initialize the touchscreen device driver instance */ memset(priv, 0, sizeof(struct tc_dev_s)); nxsem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ nxsem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ /* Register the device as an input device */ (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); iinfo("Registering %s\n", devname); ret = register_driver(devname, &tc_fops, 0666, priv); if (ret < 0) { ierr("ERROR: register_driver() failed: %d\n", ret); goto errout_with_priv; } /* Schedule work to perform the initial sampling and to set the data * availability conditions. */ priv->state = TC_READY; ret = work_queue(HPWORK, &priv->work, tc_worker, priv, 0); if (ret != 0) { ierr("ERROR: Failed to queue work: %d\n", ret); goto errout_with_priv; } /* And return success (?) */ #ifndef CONFIG_TOUCHSCREEN_MULTIPLE g_touchinitdone = true; #endif return OK; errout_with_priv: nxsem_destroy(&priv->devsem); #ifdef CONFIG_TOUCHSCREEN_MULTIPLE kmm_free(priv); #endif return ret; }
static void djoy_sample(FAR struct djoy_upperhalf_s *priv) { FAR const struct djoy_lowerhalf_s *lower = priv->du_lower; FAR struct djoy_open_s *opriv; djoy_buttonset_t sample; #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) djoy_buttonset_t change; djoy_buttonset_t press; djoy_buttonset_t release; #endif irqstate_t flags; #ifndef CONFIG_DISABLE_POLL int i; #endif DEBUGASSERT(priv && priv->du_lower); lower = priv->du_lower; /* This routine is called both task level and interrupt level, so * interrupts must be disabled. */ flags = enter_critical_section(); /* Sample the new button state */ DEBUGASSERT(lower->dl_sample); sample = lower->dl_sample(lower); #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) /* Determine which buttons have been newly pressed and which have been * newly released. */ change = sample ^ priv->du_sample; press = change & sample; DEBUGASSERT(lower->dl_supported); release = change & (lower->dl_supported(lower) & ~sample); /* Visit each opened reference to the device */ for (opriv = priv->du_open; opriv; opriv = opriv->do_flink) { #ifndef CONFIG_DISABLE_POLL /* Have any poll events occurred? */ if ((press & opriv->do_pollevents.dp_press) != 0 || (release & opriv->do_pollevents.dp_release) != 0) { /* Yes.. Notify all waiters */ for (i = 0; i < CONFIG_DJOYSTICK_NPOLLWAITERS; i++) { FAR struct pollfd *fds = opriv->do_fds[i]; if (fds) { fds->revents |= (fds->events & POLLIN); if (fds->revents != 0) { iinfo("Report events: %02x\n", fds->revents); sem_post(fds->sem); } } } } #endif #ifndef CONFIG_DISABLE_SIGNALS /* Have any signal events occurred? */ if ((press & opriv->do_notify.dn_press) != 0 || (release & opriv->do_notify.dn_release) != 0) { /* Yes.. Signal the waiter */ #ifdef CONFIG_CAN_PASS_STRUCTS union sigval value; value.sival_int = (int)sample; (void)sigqueue(opriv->do_pid, opriv->do_notify.dn_signo, value); #else (void)sigqueue(opriv->do_pid, opriv->do_notify.dn.signo, (FAR void *)sample); #endif } #endif } /* Enable/disable interrupt handling */ djoy_enable(priv); #endif priv->du_sample = sample; leave_critical_section(flags); }
int board_ajoy_initialize(void) { int ret; int i; #ifndef NO_JOYSTICK_ADC int fd; iinfo("Initialize ADC driver: /dev/adc0\n"); /* NOTE: The ADC driver was initialized earlier in the bring-up sequence. */ /* Open the ADC driver for reading. */ fd = open("/dev/adc0", O_RDONLY); if (fd < 0) { int errcode = get_errno(); ierr("ERROR: Failed to open /dev/adc0: %d\n", errcode); return -errcode; } /* Detach the file structure from the file descriptor so that it can be * used on any thread. */ ret = file_detach(fd, &g_adcfile); if (ret < 0) { ierr("ERROR: Failed to detach from file descriptor: %d\n", ret); (void)close(fd); return ret; } #endif /* Configure the GPIO pins as interrupting inputs. NOTE: This is * unnecessary for interrupting pins since it will also be done by * stm32_gpiosetevent(). */ for (i = 0; i < AJOY_NGPIOS; i++) { /* Configure the PIO as an input */ stm32_configgpio(g_joygpio[i]); } /* Register the joystick device as /dev/ajoy0 */ iinfo("Initialize joystick driver: /dev/ajoy0\n"); ret = ajoy_register("/dev/ajoy0", &g_ajoylower); if (ret < 0) { ierr("ERROR: ajoy_register failed: %d\n", ret); #ifndef NO_JOYSTICK_ADC file_close_detached(&g_adcfile); #endif } return ret; }
int stmpe811_register(STMPE811_HANDLE handle, int minor) { FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; char devname[DEV_NAMELEN]; int ret; iinfo("handle=%p minor=%d\n", handle, minor); DEBUGASSERT(priv); /* Get exclusive access to the device structure */ ret = sem_wait(&priv->exclsem); if (ret < 0) { int errval = errno; ierr("ERROR: sem_wait failed: %d\n", errval); return -errval; } /* Make sure that the pins (4-7) need by the TSC are not already in use */ if ((priv->inuse & TSC_PIN_SET) != 0) { ierr("ERROR: TSC pins is already in-use: %02x\n", priv->inuse); sem_post(&priv->exclsem); return -EBUSY; } /* Initialize the TS structure fields to their default values */ priv->minor = minor; priv->penchange = false; priv->threshx = 0; priv->threshy = 0; /* Create a timer for catching missed pen up conditions */ priv->wdog = wd_create(); if (!priv->wdog) { ierr("ERROR: Failed to create a watchdog\n", errno); sem_post(&priv->exclsem); return -ENOSPC; } /* Register the character driver */ snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); ret = register_driver(devname, &g_stmpe811fops, 0666, priv); if (ret < 0) { ierr("ERROR: Failed to register driver %s: %d\n", devname, ret); sem_post(&priv->exclsem); return ret; } /* Initialize the touchscreen controller */ stmpe811_tscinitialize(priv); /* Inidicate that the touchscreen controller was successfully initialized */ priv->inuse |= TSC_PIN_SET; /* Pins 4-7 are now in-use */ priv->flags |= STMPE811_FLAGS_TSC_INITIALIZED; /* TSC function is initialized */ sem_post(&priv->exclsem); return ret; }