/* ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. This file is part of ChibiOS. ChibiOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file chbsem.h * @brief Binary semaphores structures and macros. * @details Binary semaphores related APIs and services. *

Operation mode

* Binary semaphores are implemented as a set of inline functions * that use the existing counting semaphores primitives. The * difference between counting and binary semaphores is that the * counter of binary semaphores is not allowed to grow above the * value 1. Repeated signal operation are ignored. A binary * semaphore can thus have only two defined states: * - Taken, when its counter has a value of zero or lower * than zero. A negative number represent the number of threads * queued on the binary semaphore. * - Not taken, when its counter has a value of one. * . * Binary semaphores are different from mutexes because there is no * concept of ownership, a binary semaphore can be taken by a * thread and signaled by another thread or an interrupt handler, * mutexes can only be taken and released by the same thread. Another * difference is that binary semaphores, unlike mutexes, do not * implement the priority inheritance protocol.
* In order to use the binary semaphores APIs the * @p CH_CFG_USE_SEMAPHORES option must be enabled in @p chconf.h. * * @addtogroup oslib_binary_semaphores * @{ */ #ifndef CHBSEM_H #define CHBSEM_H #if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) /*===========================================================================*/ /* Module constants. */ /*===========================================================================*/ /*===========================================================================*/ /* Module pre-compile time settings. */ /*===========================================================================*/ /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ /*===========================================================================*/ /* Module data structures and types. */ /*===========================================================================*/ /** * @extends semaphore_t * * @brief Binary semaphore type. */ typedef struct ch_binary_semaphore { semaphore_t sem; } binary_semaphore_t; /*===========================================================================*/ /* Module macros. */ /*===========================================================================*/ /** * @brief Data part of a static semaphore initializer. * @details This macro should be used when statically initializing a semaphore * that is part of a bigger structure. * * @param[in] name the name of the semaphore variable * @param[in] taken the semaphore initial state */ #define _BSEMAPHORE_DATA(name, taken) \ {_SEMAPHORE_DATA(name.sem, ((taken) ? 0 : 1))} /** * @brief Static semaphore initializer. * @details Statically initialized semaphores require no explicit * initialization using @p chBSemInit(). * * @param[in] name the name of the semaphore variable * @param[in] taken the semaphore initial state */ #define BSEMAPHORE_DECL(name, taken) \ binary_semaphore_t name = _BSEMAPHORE_DATA(name, taken) /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ /*===========================================================================*/ /* Module inline functions. */ /*===========================================================================*/ /** * @brief Initializes a binary semaphore. * * @param[out] bsp pointer to a @p binary_semaphore_t structure * @param[in] taken initial state of the binary semaphore: * - @a false, the initial state is not taken. * - @a true, the initial state is taken. * . * * @init */ static inline void chBSemObjectInit(binary_semaphore_t *bsp, bool taken) { chSemObjectInit(&bsp->sem, taken ? (cnt_t)0 : (cnt_t)1); } /** * @brief Wait operation on the binary semaphore. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * @return A message specifying how the invoking thread has been * released from the semaphore. * @retval MSG_OK if the binary semaphore has been successfully taken. * @retval MSG_RESET if the binary semaphore has been reset using * @p bsemReset(). * * @api */ static inline msg_t chBSemWait(binary_semaphore_t *bsp) { return chSemWait(&bsp->sem); } /** * @brief Wait operation on the binary semaphore. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * @return A message specifying how the invoking thread has been * released from the semaphore. * @retval MSG_OK if the binary semaphore has been successfully taken. * @retval MSG_RESET if the binary semaphore has been reset using * @p bsemReset(). * * @sclass */ static inline msg_t chBSemWaitS(binary_semaphore_t *bsp) { chDbgCheckClassS(); return chSemWaitS(&bsp->sem); } /** * @brief Wait operation on the binary semaphore. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return A message specifying how the invoking thread has been * released from the semaphore. * @retval MSG_OK if the binary semaphore has been successfully taken. * @retval MSG_RESET if the binary semaphore has been reset using * @p bsemReset(). * @retval MSG_TIMEOUT if the binary semaphore has not been signaled or reset * within the specified timeout. * * @sclass */ static inline msg_t chBSemWaitTimeoutS(binary_semaphore_t *bsp, sysinterval_t timeout) { chDbgCheckClassS(); return chSemWaitTimeoutS(&bsp->sem, timeout); } /** * @brief Wait operation on the binary semaphore. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return A message specifying how the invoking thread has been * released from the semaphore. * @retval MSG_OK if the binary semaphore has been successfully taken. * @retval MSG_RESET if the binary semaphore has been reset using * @p bsemReset(). * @retval MSG_TIMEOUT if the binary semaphore has not been signaled or reset * within the specified timeout. * * @api */ static inline msg_t chBSemWaitTimeout(binary_semaphore_t *bsp, sysinterval_t timeout) { return chSemWaitTimeout(&bsp->sem, timeout); } /** * @brief Reset operation on the binary semaphore. * @note The released threads can recognize they were waked up by a reset * rather than a signal because the @p bsemWait() will return * @p MSG_RESET instead of @p MSG_OK. * @note This function does not reschedule. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * @param[in] taken new state of the binary semaphore * - @a false, the new state is not taken. * - @a true, the new state is taken. * . * * @iclass */ static inline void chBSemResetI(binary_semaphore_t *bsp, bool taken) { chDbgCheckClassI(); chSemResetI(&bsp->sem, taken ? (cnt_t)0 : (cnt_t)1); } /** * @brief Reset operation on the binary semaphore. * @note The released threads can recognize they were waked up by a reset * rather than a signal because the @p bsemWait() will return * @p MSG_RESET instead of @p MSG_OK. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * @param[in] taken new state of the binary semaphore * - @a false, the new state is not taken. * - @a true, the new state is taken. * . * * @api */ static inline void chBSemReset(binary_semaphore_t *bsp, bool taken) { chSemReset(&bsp->sem, taken ? (cnt_t)0 : (cnt_t)1); } /** * @brief Performs a signal operation on a binary semaphore. * @note This function does not reschedule. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * * @iclass */ static inline void chBSemSignalI(binary_semaphore_t *bsp) { chDbgCheckClassI(); if (bsp->sem.cnt < (cnt_t)1) { chSemSignalI(&bsp->sem); } } /** * @brief Performs a signal operation on a binary semaphore. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * * @api */ static inline void chBSemSignal(binary_semaphore_t *bsp) { chSysLock(); chBSemSignalI(bsp); chSchRescheduleS(); chSysUnlock(); } /** * @brief Returns the binary semaphore current state. * * @param[in] bsp pointer to a @p binary_semaphore_t structure * @return The binary semaphore current state. * @retval false if the binary semaphore is not taken. * @retval true if the binary semaphore is taken. * * @iclass */ static inline bool chBSemGetStateI(const binary_semaphore_t *bsp) { chDbgCheckClassI(); return (bsp->sem.cnt > (cnt_t)0) ? false : true; } #endif /* CH_CFG_USE_SEMAPHORES == TRUE */ #endif /* CHBSEM_H */ /** @} */ Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* Name: opendevice.c
 * Project: V-USB host-side library
 * Author: Christian Starkjohann
 * Creation Date: 2008-04-10
 * Tabsize: 4
 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
 */

/*
General Description:
The functions in this module can be used to find and open a device based on
libusb or libusb-win32.
*/

#include <stdio.h>
#include "opendevice.h"

/* ------------------------------------------------------------------------- */

#define MATCH_SUCCESS			1
#define MATCH_FAILED			0
#define MATCH_ABORT				-1

/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */
static int  _shellStyleMatch(char *text, char *p)
{
int last, matched, reverse;

    for(; *p; text++, p++){
        if(*text == 0 && *p != '*')
            return MATCH_ABORT;
        switch(*p){
        case '\\':
            /* Literal match with following character. */
            p++;
            /* FALLTHROUGH */
        default:
            if(*text != *p)
                return MATCH_FAILED;
            continue;
        case '?':
            /* Match anything. */
            continue;
        case '*':
            while(*++p == '*')
                /* Consecutive stars act just like one. */
                continue;
            if(*p == 0)
                /* Trailing star matches everything. */
                return MATCH_SUCCESS;
            while(*text)
                if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED)
                    return matched;
            return MATCH_ABORT;
        case '[':
            reverse = p[1] == '^';
            if(reverse) /* Inverted character class. */
                p++;
            matched = MATCH_FAILED;
            if(p[1] == ']' || p[1] == '-')
                if(*++p == *text)
                    matched = MATCH_SUCCESS;
            for(last = *p; *++p && *p != ']'; last = *p)
                if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p)
                    matched = MATCH_SUCCESS;
            if(matched == reverse)
                return MATCH_FAILED;
            continue;
        }
    }
    return *text == 0;
}

/* public interface for shell style matching: returns 0 if fails, 1 if matches */
static int shellStyleMatch(char *text, char *pattern)
{
    if(pattern == NULL) /* NULL pattern is synonymous to "*" */
        return 1;
    return _shellStyleMatch(text, pattern) == MATCH_SUCCESS;
}

/* ------------------------------------------------------------------------- */

int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen)
{
char    buffer[256];
int     rval, i;

    if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */
        return rval;
    if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0)
        return rval;
    if(buffer[1] != USB_DT_STRING){
        *buf = 0;
        return 0;
    }
    if((unsigned char)buffer[0] < rval)
        rval = (unsigned char)buffer[0];
    rval /= 2;
    /* lossy conversion to ISO Latin1: */
    for(i=1;i<rval;i++){
        if(i > buflen)              /* destination buffer overflow */
            break;
        buf[i-1] = buffer[2 * i];
        if(buffer[2 * i + 1] != 0)  /* outside of ISO Latin1 range */
            buf[i-1] = '?';
    }
    buf[i-1] = 0;
    return i-1;
}

/* ------------------------------------------------------------------------- */

int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp)
{
struct usb_bus      *bus;
struct usb_device   *dev;
usb_dev_handle      *handle = NULL;
int                 errorCode = USBOPEN_ERR_NOTFOUND;

    usb_find_busses();
    usb_find_devices();
    for(bus = usb_get_busses(); bus; bus = bus->next){
        for(dev = bus->devices; dev; dev = dev->next){  /* iterate over all devices on all busses */
            if((vendorID == 0 || dev->descriptor.idVendor == vendorID)
                        && (productID == 0 || dev->descriptor.idProduct == productID)){
                char    vendor[256], product[256], serial[256];
                int     len;
                handle = usb_open(dev); /* we need to open the device in order to query strings */
                if(!handle){
                    errorCode = USBOPEN_ERR_ACCESS;
                    if(warningsFp != NULL)
                        fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
                    continue;
                }
                /* now check whether the names match: */
                len = vendor[0] = 0;
                if(dev->descriptor.iManufacturer > 0){
                    len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor));
                }
                if(len < 0){
                    errorCode = USBOPEN_ERR_ACCESS;
                    if(warningsFp != NULL)
                        fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
                }else{
                    errorCode = USBOPEN_ERR_NOTFOUND;
                    /* printf("seen device from vendor ->%s<-\n", vendor); */
                    if(shellStyleMatch(vendor, vendorNamePattern)){
                        len = product[0] = 0;
                        if(dev->descriptor.iProduct > 0){
                            len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product));
                        }
                        if(len < 0){
                            errorCode = USBOPEN_ERR_ACCESS;
                            if(warningsFp != NULL)
                                fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
                        }else{
                            errorCode = USBOPEN_ERR_NOTFOUND;
                            /* printf("seen product ->%s<-\n", product); */
                            if(shellStyleMatch(product, productNamePattern)){
                                len = serial[0] = 0;
                                if(dev->descriptor.iSerialNumber > 0){
                                    len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial));
                                }
                                if(len < 0){
                                    errorCode = USBOPEN_ERR_ACCESS;
                                    if(warningsFp != NULL)
                                        fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
                                }
                                if(shellStyleMatch(serial, serialNamePattern)){
                                    if(printMatchingDevicesFp != NULL){
                                        if(serial[0] == 0){
                                            fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product);
                                        }else{
                                            fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial);
                                        }
                                    }else{
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                usb_close(handle);
                handle = NULL;
            }
        }
        if(handle)  /* we have found a deice */
            break;
    }
    if(handle != NULL){
        errorCode = 0;
        *device = handle;
    }
    if(printMatchingDevicesFp != NULL)  /* never return an error for listing only */
        errorCode = 0;
    return errorCode;
}

/* ------------------------------------------------------------------------- */