Imported Upstream version 007
[platform/upstream/usbutils.git] / usbhid-dump / lib / iface_list.c
1 /** @file
2  * @brief usbhid-dump - interface list
3  *
4  * Copyright (C) 2010 Nikolai Kondrashov
5  *
6  * This file is part of usbhid-dump.
7  *
8  * Usbhid-dump is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * Usbhid-dump is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with usbhid-dump; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  * @author Nikolai Kondrashov <spbnick@gmail.com>
23  *
24  * @(#) $Id$
25  */
26
27 #include "config.h"
28
29 #include "uhd/iface_list.h"
30 #include <assert.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33
34 bool
35 uhd_iface_list_valid(const uhd_iface *list)
36 {
37     UHD_IFACE_LIST_FOR_EACH(list, list)
38         if (!uhd_iface_valid(list))
39             return false;
40
41     return true;
42 }
43
44
45 size_t
46 uhd_iface_list_len(const uhd_iface *list)
47 {
48     size_t  len = 0;
49
50     UHD_IFACE_LIST_FOR_EACH(list, list)
51         len++;
52
53     return len;
54 }
55
56
57 void
58 uhd_iface_list_free(uhd_iface *list)
59 {
60     uhd_iface *next;
61
62     for (; list != NULL; list = next)
63     {
64         next = list->next;
65         uhd_iface_free(list);
66     }
67 }
68
69
70 enum libusb_error
71 uhd_iface_list_new(uhd_dev     *dev_list,
72                    uhd_iface  **plist)
73 {
74     enum libusb_error   err = LIBUSB_ERROR_OTHER;
75
76     uhd_dev                                    *dev;
77     struct libusb_config_descriptor            *config          = NULL;
78     const struct libusb_interface              *lusb_iface;
79     const struct libusb_endpoint_descriptor    *ep_list;
80     uint8_t                                     ep_num;
81     const struct libusb_endpoint_descriptor    *ep;
82     uhd_iface                                  *list            = NULL;
83     uhd_iface                                  *iface;
84
85     assert(uhd_dev_list_valid(dev_list));
86
87     UHD_DEV_LIST_FOR_EACH(dev, dev_list)
88     {
89         /* Retrieve active configuration descriptor */
90         err = libusb_get_active_config_descriptor(libusb_get_device(dev->handle),
91                                                   &config);
92         if (err != LIBUSB_SUCCESS)
93             goto cleanup;
94
95         /*
96          * Build the matching interface list
97          */
98
99         /* For each interface */
100         for (lusb_iface = config->interface;
101              lusb_iface - config->interface < config->bNumInterfaces;
102              lusb_iface++)
103         {
104             /* Skip interfaces with altsettings and non-HID interfaces */
105             if (lusb_iface->num_altsetting != 1 ||
106                 lusb_iface->altsetting->bInterfaceClass != LIBUSB_CLASS_HID)
107                 continue;
108
109             /* Retrieve endpoint list */
110             ep_list = lusb_iface->altsetting->endpoint;
111             ep_num = lusb_iface->altsetting->bNumEndpoints;
112
113             /* For each endpoint */
114             for (ep = ep_list; (ep - ep_list) < ep_num; ep++)
115             {
116                 /* Skip non-interrupt and non-in endpoints */
117                 if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) !=
118                     LIBUSB_TRANSFER_TYPE_INTERRUPT ||
119                     (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) !=
120                     LIBUSB_ENDPOINT_IN)
121                     continue;
122
123                 /* Create the interface */
124                 iface = uhd_iface_new(
125                             dev,
126                             lusb_iface->altsetting->bInterfaceNumber,
127                             ep->bEndpointAddress, ep->wMaxPacketSize);
128                 if (iface == NULL)
129                 {
130                     err = LIBUSB_ERROR_NO_MEM;
131                     goto cleanup;
132                 }
133
134                 /* Add the interface */
135                 iface->next = list;
136                 list = iface;
137
138                 break;
139             }
140         }
141
142         /* Free the config descriptor */
143         libusb_free_config_descriptor(config);
144         config = NULL;
145     }
146
147     /* Output the resulting list, if requested */
148     assert(uhd_iface_list_valid(list));
149     if (plist != NULL)
150     {
151         *plist = list;
152         list = NULL;
153     }
154
155     /* Done! */
156     err = LIBUSB_SUCCESS;
157
158 cleanup:
159
160     libusb_free_config_descriptor(config);
161     uhd_iface_list_free(list);
162
163     return err;
164 }
165
166
167 uhd_iface *
168 uhd_iface_list_fltr_by_num(uhd_iface   *list,
169                            uint8_t      number)
170 {
171     uhd_iface  *prev;
172     uhd_iface  *iface;
173     uhd_iface  *next;
174
175     assert(uhd_iface_list_valid(list));
176     assert(number < UINT8_MAX);
177
178     for (prev = NULL, iface = list; iface != NULL; iface = next)
179     {
180         next = iface->next;
181         if (iface->number == number)
182             prev = iface;
183         else
184         {
185             if (prev == NULL)
186                 list = next;
187             else
188                 prev->next = next;
189             uhd_iface_free(iface);
190         }
191     }
192
193     return list;
194 }
195
196