VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/usb/UsbTest.cpp@ 60860

Last change on this file since 60860 was 60860, checked in by vboxsync, 9 years ago

ValidationKit/usb/UsbTest: New test to check that the reported device speed matches what we want to test

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 KB
Line 
1/* $Id: UsbTest.cpp 60860 2016-05-06 12:14:10Z vboxsync $ */
2/** @file
3 * UsbTest - User frontend for the Linux usbtest USB test and benchmarking module.
4 * Integrates with our test framework for nice outputs.
5 */
6
7/*
8 * Copyright (C) 2014-2015 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * The contents of this file may alternatively be used under the terms
19 * of the Common Development and Distribution License Version 1.0
20 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
21 * VirtualBox OSE distribution, in which case the provisions of the
22 * CDDL are applicable instead of those of the GPL.
23 *
24 * You may elect to license modified versions of this file under the
25 * terms and conditions of either the GPL or the CDDL or both.
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/dir.h>
33#include <iprt/err.h>
34#include <iprt/file.h>
35#include <iprt/getopt.h>
36#include <iprt/path.h>
37#include <iprt/param.h>
38#include <iprt/process.h>
39#include <iprt/stream.h>
40#include <iprt/string.h>
41#include <iprt/test.h>
42
43#include <iprt/linux/sysfs.h>
44
45#include <unistd.h>
46#include <errno.h>
47#include <limits.h>
48
49#include <sys/types.h>
50#include <sys/stat.h>
51#include <fcntl.h>
52
53#include <sys/ioctl.h>
54#include <linux/usbdevice_fs.h>
55
56
57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
60
61/*********************************************************************************************************************************
62* Structures and Typedefs *
63*********************************************************************************************************************************/
64
65/**
66 * USB test request data.
67 * There is no public header with this information so we define it ourself here.
68 */
69typedef struct USBTESTPARMS
70{
71 /** Specifies the test to run. */
72 uint32_t idxTest;
73 /** How many iterations the test should be executed. */
74 uint32_t cIterations;
75 /** Size of the data packets. */
76 uint32_t cbData;
77 /** Size of */
78 uint32_t cbVariation;
79 /** Length of the S/G list for the test. */
80 uint32_t cSgLength;
81 /** Returned time data after completing the test. */
82 struct timeval TimeTest;
83} USBTESTPARAMS;
84/** Pointer to a test parameter structure. */
85typedef USBTESTPARAMS *PUSBTESTPARAMS;
86
87/**
88 * USB device descriptor. Used to search for the test device based
89 * on the vendor and product id.
90 */
91#pragma pack(1)
92typedef struct USBDEVDESC
93{
94 uint8_t bLength;
95 uint8_t bDescriptorType;
96 uint16_t bcdUSB;
97 uint8_t bDeviceClass;
98 uint8_t bDeviceSubClass;
99 uint8_t bDeviceProtocol;
100 uint8_t bMaxPacketSize0;
101 uint16_t idVendor;
102 uint16_t idProduct;
103 uint16_t bcdDevice;
104 uint8_t iManufacturer;
105 uint8_t iProduct;
106 uint8_t iSerialNumber;
107 uint8_t bNumConfigurations;
108} USBDEVDESC;
109#pragma pack()
110
111#define USBTEST_REQUEST _IOWR('U', 100, USBTESTPARMS)
112
113/**
114 * Callback to set up the test parameters for a specific test.
115 *
116 * @returns IPRT status code.
117 * @retval VINF_SUCCESS if setting the parameters up succeeded. Any other error code
118 * otherwise indicating the kind of error.
119 * @param idxTest The test index.
120 * @param pszTest Test name.
121 * @param pParams The USB test parameters to set up.
122 */
123typedef DECLCALLBACK(int) FNUSBTESTPARAMSSETUP(unsigned idxTest, const char *pszTest, PUSBTESTPARAMS pParams);
124/** Pointer to a USB test parameters setup callback. */
125typedef FNUSBTESTPARAMSSETUP *PFNUSBTESTPARAMSSETUP;
126
127/**
128 * USB test descriptor.
129 */
130typedef struct USBTESTDESC
131{
132 /** (Sort of) Descriptive test name. */
133 const char *pszName;
134 /** Flag whether the test is excluded. */
135 bool fExcluded;
136 /** The parameter setup callback. */
137 PFNUSBTESTPARAMSSETUP pfnParamsSetup;
138} USBTESTDESC;
139/** Pointer a USB test descriptor. */
140typedef USBTESTDESC *PUSBTESTDESC;
141
142/**
143 * USB speed values.
144 */
145typedef enum USBTESTSPEED
146{
147 USBTESTSPEED_ANY = 0,
148 USBTESTSPEED_UNKNOWN,
149 USBTESTSPEED_LOW,
150 USBTESTSPEED_FULL,
151 USBTESTSPEED_HIGH,
152 USBTESTSPEED_SUPER
153} USBTESTSPEED;
154
155/*********************************************************************************************************************************
156* Global Variables *
157*********************************************************************************************************************************/
158
159/** Some forward method declarations. */
160static DECLCALLBACK(int) usbTestParamsSetupReadWrite(unsigned idxTest, const char *pszTest, PUSBTESTPARAMS pParams);
161static DECLCALLBACK(int) usbTestParamsSetupControlWrites(unsigned idxTest, const char *pszTest, PUSBTESTPARAMS pParams);
162
163/** Command line parameters */
164static const RTGETOPTDEF g_aCmdOptions[] =
165{
166 {"--device", 'd', RTGETOPT_REQ_STRING },
167 {"--help", 'h', RTGETOPT_REQ_NOTHING},
168 {"--exclude", 'e', RTGETOPT_REQ_UINT32},
169 {"--expected-speed", 's', RTGETOPT_REQ_STRING }
170};
171
172static USBTESTDESC g_aTests[] =
173{
174 /* pszTest fExcluded pfnParamsSetup */
175 {"NOP", false, usbTestParamsSetupReadWrite},
176 {"Non-queued Bulk write", false, usbTestParamsSetupReadWrite},
177 {"Non-queued Bulk read", false, usbTestParamsSetupReadWrite},
178 {"Non-queued Bulk write variabe size", false, usbTestParamsSetupReadWrite},
179 {"Non-queued Bulk read variabe size", false, usbTestParamsSetupReadWrite},
180 {"Queued Bulk write", false, usbTestParamsSetupReadWrite},
181 {"Queued Bulk read", false, usbTestParamsSetupReadWrite},
182 {"Queued Bulk write variabe size", false, usbTestParamsSetupReadWrite},
183 {"Queued Bulk read variabe size", false, usbTestParamsSetupReadWrite},
184 {"Chapter 9 Control Test", false, usbTestParamsSetupReadWrite},
185 {"Queued control messaging", false, usbTestParamsSetupReadWrite},
186 {"Unlink reads", false, usbTestParamsSetupReadWrite},
187 {"Unlink writes", false, usbTestParamsSetupReadWrite},
188 {"Set/Clear halts", false, usbTestParamsSetupReadWrite},
189 {"Control writes", false, usbTestParamsSetupControlWrites},
190 {"Isochronous write", false, usbTestParamsSetupReadWrite},
191 {"Isochronous read", false, usbTestParamsSetupReadWrite},
192 {"Bulk write unaligned (DMA)", false, usbTestParamsSetupReadWrite},
193 {"Bulk read unaligned (DMA)", false, usbTestParamsSetupReadWrite},
194 {"Bulk write unaligned (no DMA)", false, usbTestParamsSetupReadWrite},
195 {"Bulk read unaligned (no DMA)", false, usbTestParamsSetupReadWrite},
196 {"Control writes unaligned", false, usbTestParamsSetupControlWrites},
197 {"Isochronous write unaligned", false, usbTestParamsSetupReadWrite},
198 {"Isochronous read unaligned", false, usbTestParamsSetupReadWrite},
199 {"Unlink queued Bulk", false, usbTestParamsSetupReadWrite}
200};
201
202/** The test handle. */
203static RTTEST g_hTest;
204/** The expected device speed. */
205static USBTESTSPEED g_enmSpeed = USBTESTSPEED_ANY;
206
207/**
208 * Setup callback for basic read/write (bulk, isochronous) tests.
209 *
210 * @copydoc FNUSBTESTPARAMSSETUP
211 */
212static DECLCALLBACK(int) usbTestParamsSetupReadWrite(unsigned idxTest, const char *pszTest, PUSBTESTPARAMS pParams)
213{
214 NOREF(idxTest);
215 NOREF(pszTest);
216
217 pParams->cIterations = 1000;
218 pParams->cbData = 512;
219 pParams->cbVariation = 512;
220 pParams->cSgLength = 32;
221
222 return VINF_SUCCESS;
223}
224
225/**
226 * Setup callback for the control writes test.
227 *
228 * @copydoc FNUSBTESTPARAMSSETUP
229 */
230static DECLCALLBACK(int) usbTestParamsSetupControlWrites(unsigned idxTest, const char *pszTest, PUSBTESTPARAMS pParams)
231{
232 NOREF(idxTest);
233 NOREF(pszTest);
234
235 pParams->cIterations = 1000;
236 pParams->cbData = 512;
237 /*
238 * Must be smaller than cbData or the parameter check in the usbtest module fails,
239 * no idea yet why it must be this.
240 */
241 pParams->cbVariation = 256;
242 pParams->cSgLength = 32;
243
244 return VINF_SUCCESS;
245}
246
247/**
248 * Shows tool usage text.
249 */
250static void usbTestUsage(PRTSTREAM pStrm)
251{
252 char szExec[RTPATH_MAX];
253 RTStrmPrintf(pStrm, "usage: %s [options]\n",
254 RTPathFilename(RTProcGetExecutablePath(szExec, sizeof(szExec))));
255 RTStrmPrintf(pStrm, "\n");
256 RTStrmPrintf(pStrm, "options: \n");
257
258
259 for (unsigned i = 0; i < RT_ELEMENTS(g_aCmdOptions); i++)
260 {
261 const char *pszHelp;
262 switch (g_aCmdOptions[i].iShort)
263 {
264 case 'h':
265 pszHelp = "Displays this help and exit";
266 break;
267 case 'd':
268 pszHelp = "Use the specified test device";
269 break;
270 case 'e':
271 pszHelp = "Exclude the given test id from the list";
272 break;
273 case 's':
274 pszHelp = "The device speed to expect";
275 break;
276 default:
277 pszHelp = "Option undocumented";
278 break;
279 }
280 char szOpt[256];
281 RTStrPrintf(szOpt, sizeof(szOpt), "%s, -%c", g_aCmdOptions[i].pszLong, g_aCmdOptions[i].iShort);
282 RTStrmPrintf(pStrm, " %-30s%s\n", szOpt, pszHelp);
283 }
284}
285
286/**
287 * Searches for a USB test device and returns the bus and device ID and the device speed.
288 */
289static int usbTestDeviceQueryBusAndDevId(uint16_t *pu16BusId, uint16_t *pu16DevId, USBTESTSPEED *penmSpeed)
290{
291 bool fFound = false;
292
293#define USBTEST_USB_DEV_SYSFS "/sys/bus/usb/devices/"
294
295 PRTDIR pDirUsb = NULL;
296 int rc = RTDirOpen(&pDirUsb, USBTEST_USB_DEV_SYSFS);
297 if (RT_SUCCESS(rc))
298 {
299 do
300 {
301 RTDIRENTRY DirUsbBus;
302 rc = RTDirRead(pDirUsb, &DirUsbBus, NULL);
303 if ( RT_SUCCESS(rc)
304 && RTStrNCmp(DirUsbBus.szName, "usb", 3)
305 && RTLinuxSysFsExists(USBTEST_USB_DEV_SYSFS "%s/idVendor", DirUsbBus.szName))
306 {
307 int64_t idVendor = 0;
308 int64_t idProduct = 0;
309 int64_t iBusId = 0;
310 int64_t iDevId = 0;
311 char aszSpeed[20];
312
313 rc = RTLinuxSysFsReadIntFile(16, &idVendor, USBTEST_USB_DEV_SYSFS "%s/idVendor", DirUsbBus.szName);
314 if (RT_SUCCESS(rc))
315 rc = RTLinuxSysFsReadIntFile(16, &idProduct, USBTEST_USB_DEV_SYSFS "%s/idProduct", DirUsbBus.szName);
316 if (RT_SUCCESS(rc))
317 rc = RTLinuxSysFsReadIntFile(16, &iBusId, USBTEST_USB_DEV_SYSFS "%s/busnum", DirUsbBus.szName);
318 if (RT_SUCCESS(rc))
319 rc = RTLinuxSysFsReadIntFile(16, &iDevId, USBTEST_USB_DEV_SYSFS "%s/devnum", DirUsbBus.szName);
320 if (RT_SUCCESS(rc))
321 rc = RTLinuxSysFsReadStrFile(&aszSpeed[0], sizeof(aszSpeed), NULL, USBTEST_USB_DEV_SYSFS "%s/speed", DirUsbBus.szName);
322
323 if ( RT_SUCCESS(rc)
324 && idVendor == 0x0525
325 && idProduct == 0xa4a0)
326 {
327 if (penmSpeed)
328 {
329 /* Parse the speed. */
330 if (!RTStrCmp(&aszSpeed[0], "1.5"))
331 *penmSpeed = USBTESTSPEED_LOW;
332 else if (!RTStrCmp(&aszSpeed[0], "12"))
333 *penmSpeed = USBTESTSPEED_FULL;
334 else if (!RTStrCmp(&aszSpeed[0], "480"))
335 *penmSpeed = USBTESTSPEED_HIGH;
336 else if ( !RTStrCmp(&aszSpeed[0], "5000")
337 || !RTStrCmp(&aszSpeed[0], "10000"))
338 *penmSpeed = USBTESTSPEED_SUPER;
339 else
340 *penmSpeed = USBTESTSPEED_UNKNOWN;
341 }
342
343 if (pu16BusId)
344 *pu16BusId = (uint16_t)iBusId;
345 if (pu16DevId)
346 *pu16DevId = (uint16_t)iDevId;
347 fFound = true;
348 break;
349 }
350 }
351 else if (rc != VERR_NO_MORE_FILES)
352 rc = VINF_SUCCESS;
353
354 } while ( RT_SUCCESS(rc)
355 && !fFound);
356
357 if (rc == VERR_NO_MORE_FILES)
358 rc = VINF_SUCCESS;
359
360 RTDirClose(pDirUsb);
361 }
362
363 if (RT_SUCCESS(rc) && !fFound)
364 rc = VERR_NOT_FOUND;
365
366 return rc;
367}
368
369/**
370 * Search for a USB test device and return the device path.
371 *
372 * @returns Path to the USB test device or NULL if none was found.
373 */
374static char *usbTestFindDevice(void)
375{
376 /*
377 * Very crude and quick way to search for the correct test device.
378 * Assumption is that the path looks like /dev/bus/usb/%3d/%3d.
379 */
380 char *pszDevPath = NULL;
381
382 PRTDIR pDirUsb = NULL;
383 int rc = RTDirOpen(&pDirUsb, "/dev/bus/usb");
384 if (RT_SUCCESS(rc))
385 {
386 do
387 {
388 RTDIRENTRY DirUsbBus;
389 rc = RTDirRead(pDirUsb, &DirUsbBus, NULL);
390 if (RT_SUCCESS(rc))
391 {
392 char aszPath[RTPATH_MAX + 1];
393 RTStrPrintf(&aszPath[0], RT_ELEMENTS(aszPath), "/dev/bus/usb/%s", DirUsbBus.szName);
394
395 PRTDIR pDirUsbBus = NULL;
396 rc = RTDirOpen(&pDirUsbBus, &aszPath[0]);
397 if (RT_SUCCESS(rc))
398 {
399 do
400 {
401 RTDIRENTRY DirUsbDev;
402 rc = RTDirRead(pDirUsbBus, &DirUsbDev, NULL);
403 if (RT_SUCCESS(rc))
404 {
405 char aszPathDev[RTPATH_MAX + 1];
406 RTStrPrintf(&aszPathDev[0], RT_ELEMENTS(aszPathDev), "/dev/bus/usb/%s/%s",
407 DirUsbBus.szName, DirUsbDev.szName);
408
409 RTFILE hFileDev;
410 rc = RTFileOpen(&hFileDev, aszPathDev, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
411 if (RT_SUCCESS(rc))
412 {
413 USBDEVDESC DevDesc;
414
415 rc = RTFileRead(hFileDev, &DevDesc, sizeof(DevDesc), NULL);
416 RTFileClose(hFileDev);
417
418 if ( RT_SUCCESS(rc)
419 && DevDesc.idVendor == 0x0525
420 && DevDesc.idProduct == 0xa4a0)
421 pszDevPath = RTStrDup(aszPathDev);
422 }
423
424 rc = VINF_SUCCESS;
425 }
426 else if (rc != VERR_NO_MORE_FILES)
427 rc = VINF_SUCCESS;
428
429 } while ( RT_SUCCESS(rc)
430 && !pszDevPath);
431
432 rc = VINF_SUCCESS;
433 RTDirClose(pDirUsbBus);
434 }
435 }
436 else if (rc != VERR_NO_MORE_FILES)
437 rc = VINF_SUCCESS;
438 } while ( RT_SUCCESS(rc)
439 && !pszDevPath);
440
441 RTDirClose(pDirUsb);
442 }
443
444 return pszDevPath;
445}
446
447static int usbTestIoctl(int iDevFd, int iInterface, PUSBTESTPARAMS pParams)
448{
449 struct usbdevfs_ioctl IoCtlData;
450
451 IoCtlData.ifno = iInterface;
452 IoCtlData.ioctl_code = (int)USBTEST_REQUEST;
453 IoCtlData.data = pParams;
454 return ioctl(iDevFd, USBDEVFS_IOCTL, &IoCtlData);
455}
456
457/**
458 * Test execution worker.
459 *
460 * @returns nothing.
461 * @param pszDevice The device to use for testing.
462 */
463static void usbTestExec(const char *pszDevice)
464{
465 int iDevFd;
466
467 RTTestSub(g_hTest, "Opening device");
468 iDevFd = open(pszDevice, O_RDWR);
469 if (iDevFd != -1)
470 {
471 USBTESTPARAMS Params;
472
473 RTTestPassed(g_hTest, "Opening device successful\n");
474
475 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
476 {
477 RTTestSub(g_hTest, g_aTests[i].pszName);
478
479 if (g_aTests[i].fExcluded)
480 {
481 RTTestSkipped(g_hTest, "Excluded from list");
482 continue;
483 }
484
485 int rc = g_aTests[i].pfnParamsSetup(i, g_aTests[i].pszName, &Params);
486 if (RT_SUCCESS(rc))
487 {
488 Params.idxTest = i;
489
490 /* Assume the test interface has the number 0 for now. */
491 int rcPosix = usbTestIoctl(iDevFd, 0, &Params);
492 if (rcPosix < 0 && errno == EOPNOTSUPP)
493 {
494 RTTestSkipped(g_hTest, "Not supported");
495 continue;
496 }
497
498 if (rcPosix < 0)
499 RTTestFailed(g_hTest, "Test failed with %Rrc\n", RTErrConvertFromErrno(errno));
500 else
501 {
502 uint64_t u64Ns = Params.TimeTest.tv_sec * RT_NS_1SEC + Params.TimeTest.tv_usec * RT_NS_1US;
503 RTTestValue(g_hTest, "Runtime", u64Ns, RTTESTUNIT_NS);
504 }
505 }
506 else
507 RTTestFailed(g_hTest, "Setting up test parameters failed with %Rrc\n", rc);
508 RTTestSubDone(g_hTest);
509 }
510
511 close(iDevFd);
512 }
513 else
514 RTTestFailed(g_hTest, "Opening device failed with %Rrc\n", RTErrConvertFromErrno(errno));
515
516}
517
518int main(int argc, char *argv[])
519{
520 /*
521 * Init IPRT and globals.
522 */
523 int rc = RTTestInitAndCreate("UsbTest", &g_hTest);
524 if (rc)
525 return rc;
526
527 /*
528 * Default values.
529 */
530 const char *pszDevice = NULL;
531
532 RTGETOPTUNION ValueUnion;
533 RTGETOPTSTATE GetState;
534 RTGetOptInit(&GetState, argc, argv, g_aCmdOptions, RT_ELEMENTS(g_aCmdOptions), 1, 0 /* fFlags */);
535 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
536 {
537 switch (rc)
538 {
539 case 'h':
540 usbTestUsage(g_pStdOut);
541 return RTEXITCODE_SUCCESS;
542 case 'd':
543 pszDevice = ValueUnion.psz;
544 break;
545 case 's':
546 if (!RTStrICmp(ValueUnion.psz, "Low"))
547 g_enmSpeed = USBTESTSPEED_LOW;
548 else if (!RTStrICmp(ValueUnion.psz, "Full"))
549 g_enmSpeed = USBTESTSPEED_FULL;
550 else if (!RTStrICmp(ValueUnion.psz, "High"))
551 g_enmSpeed = USBTESTSPEED_HIGH;
552 else if (!RTStrICmp(ValueUnion.psz, "Super"))
553 g_enmSpeed = USBTESTSPEED_SUPER;
554 else
555 {
556 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Invalid speed passed to --expected-speed\n");
557 RTTestErrorInc(g_hTest);
558 return RTGetOptPrintError(VERR_INVALID_PARAMETER, &ValueUnion);
559 }
560 break;
561 case 'e':
562 if (ValueUnion.u32 < RT_ELEMENTS(g_aTests))
563 g_aTests[ValueUnion.u32].fExcluded = true;
564 else
565 {
566 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Invalid test number passed to --exclude\n");
567 RTTestErrorInc(g_hTest);
568 return RTGetOptPrintError(VERR_INVALID_PARAMETER, &ValueUnion);
569 }
570 break;
571 default:
572 return RTGetOptPrintError(rc, &ValueUnion);
573 }
574 }
575
576 /*
577 * Start testing.
578 */
579 RTTestBanner(g_hTest);
580
581 /* Find the first test device if none was given. */
582 if (!pszDevice)
583 {
584 RTTestSub(g_hTest, "Detecting device");
585 pszDevice = usbTestFindDevice();
586 if (!pszDevice)
587 RTTestFailed(g_hTest, "Failed to find suitable device\n");
588
589 RTTestSubDone(g_hTest);
590 }
591
592 if (pszDevice)
593 {
594 /* First check that the requested speed matches. */
595 if (g_enmSpeed != USBTESTSPEED_ANY)
596 {
597 RTTestSub(g_hTest, "Checking correct device speed");
598
599 USBTESTSPEED enmSpeed = USBTESTSPEED_UNKNOWN;
600 rc = usbTestDeviceQueryBusAndDevId(NULL, NULL, &enmSpeed);
601 if (RT_SUCCESS(rc))
602 {
603 if (enmSpeed == g_enmSpeed)
604 RTTestPassed(g_hTest, "Reported device speed matches requested speed\n");
605 else
606 RTTestFailed(g_hTest, "Reported device speed doesn'match requested speed (%u vs %u)\n",
607 enmSpeed, g_enmSpeed);
608 }
609 else
610 RTTestFailed(g_hTest, "Failed to query device speed with rc=%Rrc\n", rc);
611
612 RTTestSubDone(g_hTest);
613 }
614 usbTestExec(pszDevice);
615 }
616
617 RTEXITCODE rcExit = RTTestSummaryAndDestroy(g_hTest);
618 return rcExit;
619}
620
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette