Κοινή χρήση τεχνολογίας

Ανάπτυξη-επεξεργασία στατικών ροών ομαδικών μεταφορών προγραμμάτων οδήγησης συσκευών USB των Windows

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Σε συσκευές USB 2.0 και προηγούμενες συσκευές, ένα μαζικό τελικό σημείο μπορεί να στείλει ή να λάβει μία μόνο ροή δεδομένων μέσω του τελικού σημείου. Στις συσκευές USB 3.0, το μαζικό τελικό σημείο έχει τη δυνατότητα αποστολής και λήψης πολλαπλών ροών δεδομένων μέσω του τελικού σημείου.

Η στοίβα προγραμμάτων οδήγησης USB που παρέχεται από τη Microsoft στα Windows υποστηρίζει πολλαπλές ροές. Αυτό επιτρέπει στα προγράμματα οδήγησης πελατών να στέλνουν ανεξάρτητες αιτήσεις εισόδου/εξόδου σε κάθε ροή που σχετίζεται με ένα μαζικό τελικό σημείο σε μια συσκευή USB 3.0, χωρίς να συντάσσουν σειριακά αιτήματα σε διαφορετικές ροές.

Για ένα πρόγραμμα οδήγησης πελάτη, μια ροή αντιπροσωπεύει πολλαπλά λογικά τελικά σημεία με το ίδιο σύνολο χαρακτηριστικών. Για να στείλει ένα αίτημα σε μια συγκεκριμένη ροή, το πρόγραμμα οδήγησης πελάτη χρειάζεται μια λαβή σε αυτήν τη ροή (παρόμοια με τη λαβή σωλήνα τελικού σημείου). Το URB για αιτήματα εισόδου/εξόδου ροής είναι παρόμοιο με το URB για αιτήματα εισόδου/εξόδου για μαζικά τελικά σημεία. Η μόνη διαφορά είναι η λαβή του σωλήνα. Για να στείλετε ένα αίτημα I/O σε μια ροή, το πρόγραμμα οδήγησης καθορίζει μια λαβή σωλήνα στη ροή.

Κατά τη διαμόρφωση της συσκευής, το πρόγραμμα οδήγησης πελάτη στέλνει ένα αίτημα επιλογής διαμόρφωσης και προαιρετικά ένα αίτημα επιλογής διεπαφής. Αυτά τα αιτήματα ανακτούν ένα σύνολο λαβών σωλήνων για τα τελικά σημεία που ορίζονται στις ρυθμίσεις δραστηριότητας της διεπαφής. Για τελικά σημεία με επίγνωση ροής, η λαβή του σωλήνα τελικού σημείου μπορεί να χρησιμοποιηθεί για την αποστολή αιτημάτων εισόδου/εξόδου στην προεπιλεγμένη ροή (την πρώτη ροή) έως ότου το πρόγραμμα οδήγησης ανοίξει τη ροή.

Εάν ένα πρόγραμμα οδήγησης πελάτη θέλει να στείλει αιτήματα σε ροές διαφορετικές από την προεπιλεγμένη ροή, το πρόγραμμα οδήγησης πρέπει να ανοίξει και να λάβει λαβές σε όλες τις ροές. Για να γίνει αυτό, το πρόγραμμα οδήγησης πελάτη στέλνει ένα αίτημα ανοιχτής ροής καθορίζοντας τον αριθμό των ροών που θα ανοίξουν. Αφού ένα πρόγραμμα οδήγησης πελάτη ολοκληρώσει τη χρήση ροών, το πρόγραμμα οδήγησης μπορεί να επιλέξει να τις κλείσει στέλνοντας ένα αίτημα κλεισίματος ροής.

Το Kernel Mode Driver Framework (KMDF) δεν υποστηρίζει εγγενώς στατικές ροές. Τα προγράμματα οδήγησης πελατών πρέπει να χρησιμοποιούν το μοντέλο προγράμματος οδήγησης των Windows (WDM) για να ανοίγουν και να κλείνουν ροές. Τα προγράμματα οδήγησης προγράμματος-πελάτη Driver Framework (UMDF) σε λειτουργία χρήστη δεν μπορούν να χρησιμοποιήσουν τη δυνατότητα στατικής ροής.

Τα παρακάτω ενδέχεται να περιέχουν ορισμένα σχόλια με την ένδειξη WDM Drivers. Αυτές οι οδηγίες περιγράφουν τις ρουτίνες για ένα πρόγραμμα οδήγησης πελάτη USB που βασίζεται σε WDM που θέλει να στείλει αιτήματα ροής.

προαπαιτούμενα

Για να μπορέσει ένα πρόγραμμα οδήγησης πελάτη να ανοίξει ή να κλείσει μια ροή, το πρόγραμμα οδήγησης πρέπει να έχει:

1. Καλέστε τη μέθοδο WdfUsbTargetDeviceCreateWithParameters. Η μέθοδος απαιτεί έκδοση πρωτοκόλλου πελάτη USBD_CLIENT_CONTRACT_VERSION_602. Καθορίζοντας αυτήν την έκδοση, το πρόγραμμα οδήγησης πελάτη πρέπει να συμμορφώνεται με ένα σύνολο κανόνων.

Καλέστε για να ανακτήσετε τη λαβή WDFUSBDEVICE του αντικειμένου συσκευής στόχου USB του πλαισίου. Η λαβή απαιτείται για επόμενες κλήσεις στην ανοιχτή ροή. Συνήθως, ένα πρόγραμμα οδήγησης πελάτη εγγράφεται στη ρουτίνα επανάκλησης συμβάντος EVT_WDF_DEVICE_PREPARE_HARDWARE του προγράμματος οδήγησης.

Πρόγραμμα οδήγησης WDM: Καλέστε τη ρουτίνα USBD_CreateHandle και αποκτήστε τη λαβή USBD που έχει καταχωριστεί από το πρόγραμμα οδήγησης στη στοίβα προγραμμάτων οδήγησης USB.

2. Διαμόρφωσε τις παραμέτρους της συσκευής και έλαβε τη λαβή σωλήνα WDFUSBPIPE για το μαζικό τελικό σημείο που υποστηρίζει ροή. Για να αποκτήσετε μια λαβή σωλήνα, καλέστε τη μέθοδο WdfUsbInterfaceGetConfiguredPipe στις τρέχουσες εναλλακτικές ρυθμίσεις της διεπαφής στην επιλεγμένη διαμόρφωση.

Πρόγραμμα οδήγησης WDM: Αποκτά τη λαβή του σωλήνα USBD στέλνοντας ένα αίτημα επιλογής διαμόρφωσης ή επιλογής διεπαφής.

Πώς να ανοίξετε μια στατική ροή

1. Προσδιορίστε εάν η υποκείμενη στοίβα προγράμματος οδήγησης USB και ο ελεγκτής κεντρικού υπολογιστή υποστηρίζουν τη δυνατότητα στατικής ροής καλώντας τη μέθοδο WdfUsbTargetDeviceQueryUsbCapability. Συνήθως, τα προγράμματα οδήγησης πελατών καλούν ρουτίνες στη ρουτίνα επανάκλησης συμβάντων EVT_WDF_DEVICE_PREPARE_HARDWARE του προγράμματος οδήγησης.

Πρόγραμμα οδήγησης WDM: Καλεί τη ρουτίνα USBD_QueryUsbCapability. Συνήθως, ένα πρόγραμμα οδήγησης ρωτά τη λειτουργία που θα χρησιμοποιηθεί στη ρουτίνα της συσκευής εκκίνησης του προγράμματος οδήγησης, (IRP_MN_START_DEVICE).

Δώστε τις ακόλουθες πληροφορίες:

  • Η λαβή στο αντικείμενο της συσκευής USB που ανακτήθηκε σε προηγούμενη κλήση στο WdfUsbTargetDeviceCreateWithParameters, που χρησιμοποιήθηκε για την εγγραφή του προγράμματος οδήγησης πελάτη.

Πρόγραμμα οδήγησης WDM: Περάστε τη λαβή USBD που ανακτήθηκε στην προηγούμενη κλήση στο USBD_CreateHandle.

Εάν ένα πρόγραμμα οδήγησης πελάτη θέλει να χρησιμοποιήσει μια συγκεκριμένη δυνατότητα, το πρόγραμμα οδήγησης πρέπει πρώτα να υποβάλει ερώτημα στην υποκείμενη στοίβα προγραμμάτων οδήγησης USB για να προσδιορίσει εάν η στοίβα προγράμματος οδήγησης και ο ελεγκτής κεντρικού υπολογιστή υποστηρίζουν τη δυνατότητα. Εάν η δυνατότητα υποστηρίζεται, τότε μόνο τότε θα πρέπει το πρόγραμμα οδήγησης να στείλει αίτημα για χρήση της δυνατότητας. Ορισμένα αιτήματα απαιτούν URB, όπως η λειτουργικότητα ροής που συζητήθηκε στο Βήμα 5. Για αυτά τα αιτήματα, βεβαιωθείτε ότι χρησιμοποιείτε την ίδια λαβή για να υποβάλετε ερώτημα στη συνάρτηση και να εκχωρήσετε το URB. Αυτό συμβαίνει επειδή η στοίβα προγραμμάτων οδήγησης χρησιμοποιεί λαβές για να παρακολουθεί τις υποστηριζόμενες δυνατότητες που μπορεί να χρησιμοποιήσει το πρόγραμμα οδήγησης.

Για παράδειγμα, εάν το USBD_HANDLE αποκτήθηκε καλώντας το USBD_CreateHandle, η στοίβα του προγράμματος οδήγησης ερωτάται καλώντας το USBD_QueryUsbCapability και το URB εκχωρείται καλώντας το USBD_UrbAllocate. Περάστε το ίδιο USBD_HANDLE και στις δύο κλήσεις.

Εάν καλέσετε τις μεθόδους KMDF, WdfUsbTargetDeviceQueryUsbCapability και WdfUsbTargetDeviceCreateUrb, καθορίστε την ίδια λαβή WDFUSBDEVICE για το αντικείμενο προορισμού πλαισίου σε αυτές τις κλήσεις μεθόδου.

  • Το GUID εκχωρήθηκε σε GUID_USB_CAPABILITY_STATIC_STREAMS.
  • Δείκτης προς την προσωρινή μνήμη εξόδου (δείχνει το USHORT). Μόλις ολοκληρωθεί, το buffer θα γεμίσει με (μέγιστο αριθμό ροών για) κάθε τελικό σημείο που υποστηρίζεται από τον ελεγκτή κεντρικού υπολογιστή.
  • Το μήκος του buffer εξόδου, σε byte. Για ρέματα, το μήκος είναι μέγεθος (USHORT).

2. Αξιολογήστε την επιστρεφόμενη τιμή NTSTATUS. Εάν η ρουτίνα ολοκληρωθεί με επιτυχία, επιστρέφεται το STATUS_SUCCESS και υποστηρίζεται η λειτουργία στατικής ροής. Διαφορετικά, η μέθοδος επιστρέφει τον κατάλληλο κωδικό σφάλματος.

3. Προσδιορίστε τον αριθμό των ροών που θα ανοίξουν. Ο μέγιστος αριθμός ροών που μπορούν να ανοίξουν περιορίζεται από:

  • Ο μέγιστος αριθμός ροών που υποστηρίζονται από τον ελεγκτή κεντρικού υπολογιστή. WdfUsbTargetDeviceQueryUsbCapability (λαμβάνει WdfUsbTargetDeviceQueryUsbCapabilityUSBD_QueryUsbCapability) στην προσωρινή μνήμη εξόδου που παρέχεται από τον καλούντα. Η στοίβα προγραμμάτων οδήγησης USB που παρέχεται από τη Microsoft υποστηρίζει έως και 255 ροές. Το WdfUsbTargetDeviceQueryUsbCapability λαμβάνει αυτό το όριο υπόψη κατά τον υπολογισμό του αριθμού των ροών. Η μέθοδος δεν επιστρέφει ποτέ τιμή μεγαλύτερη από 255.
  • Ο μέγιστος αριθμός ροών που υποστηρίζονται από το τελικό σημείο στη συσκευή. Για να λάβετε αυτόν τον αριθμό, ελέγξτε τον συνοδευτικό περιγραφέα τελικού σημείου (στο Usbspec.h) για USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR. Για να αποκτήσετε τον συνοδευτικό περιγραφέα τελικού σημείου, πρέπει να αναλυθεί ο περιγραφέας διαμόρφωσης. Για να αποκτήσετε τον περιγραφέα διαμόρφωσης, το πρόγραμμα οδήγησης πελάτη πρέπει να καλέσει τη μέθοδο WdfUsbTargetDeviceRetrieveConfigDescriptor. Πρέπει να χρησιμοποιηθούν οι βοηθητικές ρουτίνες, USBD_ParseConfigurationDescriptorEx και USBD_ParseDescriptor.

Για να προσδιορίσετε τον μέγιστο αριθμό ροών, επιλέξτε τη μικρότερη από τις δύο τιμές που υποστηρίζονται από τον ελεγκτή κεντρικού υπολογιστή και το τελικό σημείο.

4. Εκχωρήστε έναν πίνακα δομών n-στοιχείων USBD_STREAM_INFORMATION, όπου n είναι ο αριθμός των ροών που θα ανοίξουν. Το πρόγραμμα οδήγησης πελάτη είναι υπεύθυνο για την απελευθέρωση αυτού του πίνακα μετά την ολοκλήρωση του προγράμματος οδήγησης χρησιμοποιώντας τη ροή.

5. Εκχωρήστε ένα URB για το αίτημα ανοιχτής ροής καλώντας τη μέθοδο WdfUsbTargetDeviceCreateUrb. Εάν η κλήση ολοκληρωθεί με επιτυχία, η μέθοδος ανακτά το αντικείμενο μνήμης WDF και τη διεύθυνση της δομής URB που έχει εκχωρηθεί από τη στοίβα προγράμματος οδήγησης USB.

Πρόγραμμα οδήγησης WDM: Καλεί τη ρουτίνα USBD_UrbAllocate.

6. Ορίστε τη μορφή URB του αιτήματος ανοιχτής ροής. Το URB χρησιμοποιεί τη δομή _URB_OPEN_STATIC_STREAMS για να ορίσει αιτήματα. Για να μορφοποιήσετε ένα URB, χρειάζεστε:

  • Λαβή σωλήνα USBD που δείχνει προς το τελικό σημείο. Εάν υπάρχει αντικείμενο σωλήνα WDF, μπορείτε να λάβετε τη λαβή του σωλήνα USBD καλώντας τη μέθοδο WdfUsbTargetPipeWdmGetPipeHandle.
  • Δημιουργήθηκε στο βήμα 4 (συστοιχία ροής)
  • Δείξτε τη δομή URB που δημιουργήθηκε στο (βήμα 5).

Για να μορφοποιήσετε ένα URB, καλέστε το UsbBuildOpenStaticStreamsRequest και μεταβιβάστε τις απαιτούμενες πληροφορίες ως τιμές παραμέτρων. Βεβαιωθείτε ότι ο αριθμός των ροών που καθορίζεται στο UsbBuildOpenStaticStreamsRequest δεν υπερβαίνει τον μέγιστο αριθμό ροών που υποστηρίζονται.

7. Στείλτε το URB ως αντικείμενο αίτησης WDF καλώντας τη μέθοδο WdfRequestSend. Για να στείλετε το αίτημα συγχρονισμένα, καλέστε τη μέθοδο WdfUsbTargetDeviceSendUrbSynchronously.

Πρόγραμμα οδήγησης WDM: Συσχετίζει το URB με το IRP και υποβάλλει το IRP στη στοίβα προγραμμάτων οδήγησης USB.

8. Αφού ολοκληρωθεί το αίτημα, ελέγξτε την κατάσταση του αιτήματος.Εάν το αίτημα στοίβας προγράμματος οδήγησης USB αποτύχει, η κατάσταση URB περιέχει τον σχετικό κωδικό σφάλματος.

Εάν η κατάσταση του αιτήματος (αντικείμενο αιτήματος IRP ή WDF) υποδεικνύει USBD_STATUS_SUCCESS, το αίτημα ολοκληρώθηκε με επιτυχία. Πίνακας δομών USBD_STREAM_INFORMATION που ελήφθησαν όταν ολοκληρωθεί ο έλεγχος. Ο πίνακας συμπληρώνεται με πληροφορίες σχετικά με τη ροή που ζητήθηκε. Η στοίβα προγράμματος οδήγησης USB γεμίζει κάθε δομή στη συστοιχία με πληροφορίες ροής, όπως τη λαβή λήψης USBD_PIPE_HANDLE, το αναγνωριστικό ροής και το μέγιστο μέγεθος αριθμητικής μεταφοράς. Η ροή μπορεί πλέον να μεταφέρει δεδομένα.

Για αιτήματα ανοιχτής ροής, πρέπει να εκχωρηθούν URB και πίνακες. Αφού ολοκληρωθεί το αίτημα ανοιχτής ροής, το πρόγραμμα οδήγησης πελάτη πρέπει να απελευθερώσει το URB καλώντας τη μέθοδο WdfObjectDelete στο σχετικό αντικείμενο μνήμης WDF. Εάν το πρόγραμμα οδήγησης στείλει την αίτηση συγχρονισμένα καλώντας το WdfUsbTargetDeviceSendUrbSynchronously, το αντικείμενο μνήμης WDF πρέπει να απελευθερωθεί μετά την επιστροφή της μεθόδου. Εάν ένα πρόγραμμα οδήγησης πελάτη στείλει ένα αίτημα ασύγχρονα καλώντας το WdfRequestSend, το πρόγραμμα οδήγησης πρέπει να απελευθερώσει το αντικείμενο μνήμης WDF στη ρουτίνα ολοκλήρωσης που υλοποιείται από το πρόγραμμα οδήγησης που σχετίζεται με το αίτημα.

Η συστοιχία ροής μπορεί να απελευθερωθεί αφού το πρόγραμμα οδήγησης πελάτη ολοκληρώσει τη χρήση της ροής ή μπορεί να αποθηκευτεί για αιτήματα εισόδου/εξόδου. Στο παράδειγμα κώδικα που περιλαμβάνεται παρακάτω, το πρόγραμμα οδήγησης αποθηκεύει έναν πίνακα ροής στο περιβάλλον της συσκευής. Το πρόγραμμα οδήγησης απελευθερώνει το περιβάλλον της συσκευής πριν απελευθερώσει το αντικείμενο της συσκευής.

Πώς να μεταφέρετε δεδομένα σε μια συγκεκριμένη ροή
Για να στείλετε ένα αίτημα μεταφοράς δεδομένων σε μια συγκεκριμένη ροή, απαιτείται ένα αντικείμενο αίτησης WDF. Συνήθως, τα προγράμματα οδήγησης-πελάτες δεν χρειάζεται να εκχωρούν αντικείμενα αίτησης WDF. Όταν ο διαχειριστής εισόδου/εξόδου λαμβάνει ένα αίτημα από μια εφαρμογή, ο διαχειριστής εισόδου/εξόδου δημιουργεί ένα IRP για το αίτημα. Το IRP αναχαιτίστηκε από το πλαίσιο. Στη συνέχεια, το πλαίσιο εκχωρεί ένα αντικείμενο αίτησης WDF για να αναπαραστήσει το IRP. Στη συνέχεια, το πλαίσιο μεταβιβάζει το αντικείμενο αίτησης WDF στο πρόγραμμα οδήγησης πελάτη. Το πρόγραμμα οδήγησης πελάτη μπορεί στη συνέχεια να συσχετίσει το αντικείμενο αίτησης με το URB μεταφοράς δεδομένων και να το στείλει στη στοίβα προγράμματος οδήγησης USB.

Εάν ένα πρόγραμμα οδήγησης πελάτη δεν λάβει ένα αντικείμενο αίτησης WDF από το πλαίσιο και θέλει να στείλει το αίτημα ασύγχρονα, το πρόγραμμα οδήγησης πρέπει να εκχωρήσει ένα αντικείμενο αίτησης WDF καλώντας τη μέθοδο WdfRequestCreate. Μορφοποιήστε το νέο αντικείμενο καλώντας το WdfUsbTargetPipeFormatRequestForUrb και στείλτε το αίτημα καλώντας το WdfRequestSend.

Στη σύγχρονη περίπτωση, η μετάδοση του αντικειμένου αίτησης WDF είναι προαιρετική.

Για τη μεταφορά δεδομένων σε μια ροή, πρέπει να χρησιμοποιηθεί το URB. Το URB πρέπει να μορφοποιηθεί καλώντας το WdfUsbTargetPipeFormatRequestForUrb.

Οι ροές δεν υποστηρίζουν τις ακόλουθες μεθόδους WDF:

  • WdfUsbTargetPipeFormatRequestForRead
  • WdfUsbTargetPipeFormatRequestForWrite
  • WdfUsbTargetPipeReadSynchronously
  • WdfUsbTargetPipeWriteSynchronously

Η ακόλουθη διαδικασία προϋποθέτει ότι το πρόγραμμα οδήγησης πελάτη λαμβάνει το αντικείμενο αίτησης από το πλαίσιο.

  1. Εκχωρήστε το URB καλώντας το WdfUsbTargetDeviceCreateUrb. Αυτή η μέθοδος εκχωρεί ένα αντικείμενο μνήμης WDF που περιέχει το πρόσφατα εκχωρημένο URB. Τα προγράμματα οδήγησης πελατών μπορούν να επιλέξουν να εκχωρήσουν ένα URB για κάθε αίτημα εισόδου/εξόδου ή να εκχωρήσουν ένα URB και να το χρησιμοποιήσουν για αιτήματα του ίδιου τύπου.
  2. Μορφοποιήστε το URB για μαζική μεταφορά καλώντας το UsbBuildInterruptOrBulkTransferRequest. Στην παράμετρο PipeHandle, καθορίστε τη λαβή της ροής. Η λαβή ροής λαμβάνεται στο προηγούμενο αίτημα, όπως περιγράφεται στην ενότητα Πώς να ανοίξετε μια στατική ροή.
  3. Μορφοποιήστε το αντικείμενο αίτησης WDF καλώντας τη μέθοδο WdfUsbTargetPipeFormatRequestForUrb. Στην κλήση, καθορίστε το αντικείμενο μνήμης WDF που περιέχει το URB μεταφοράς δεδομένων. Το αντικείμενο μνήμης εκχωρήθηκε στο βήμα 1.
  4. Στείλτε το URB ως αίτημα WDF καλώντας το WdfRequestSend ή το WdfUsbTargetPipeSendUrbΣυγχρονικά. Εάν καλέσετε το WdfRequestSend, πρέπει να καθορίσετε μια ρουτίνα ολοκλήρωσης καλώντας το WdfRequestSetCompletionRoutine, ώστε το πρόγραμμα οδήγησης πελάτη να μπορεί να ειδοποιηθεί όταν ολοκληρωθεί η ασύγχρονη λειτουργία. Το URB μεταφοράς δεδομένων πρέπει να απελευθερωθεί στη ρουτίνα ολοκλήρωσης.

Πρόγραμμα οδήγησης WDM: Εκχωρεί ένα URB καλώντας το USBD_UrbAllocate και το μορφοποιεί για μαζική μεταφορά (δείτε _URB_BULK_OR_INTERRUPT_TRANSFER). Για να μορφοποιήσετε ένα URB, μπορείτε να καλέσετε το UsbBuildInterruptOrBulkTransferRequest ή να μορφοποιήσετε μη αυτόματα τη δομή URB. Καθορίστε τη λαβή της ροής στο μέλος UrbBulkOrInterruptTransfer.PipeHandle του URB.

Πώς να κλείσετε μια στατική ροή

Το πρόγραμμα οδήγησης πελάτη μπορεί να κλείσει τη ροή αφού το πρόγραμμα οδήγησης ολοκληρώσει τη χρήση της. Ωστόσο, το κλείσιμο του αιτήματος ροής είναι προαιρετικό. Η στοίβα προγράμματος οδήγησης USB κλείνει όλες τις ροές όταν το τελικό σημείο που σχετίζεται με τη ροή δεν έχει διαμορφωθεί. Τα τελικά σημεία δεν διαμορφώνονται κατά την επιλογή μιας εναλλακτικής διαμόρφωσης ή διεπαφής, τη διαγραφή μιας συσκευής κ.λπ. Εάν το πρόγραμμα οδήγησης πελάτη θέλει να ανοίξει διαφορετικό αριθμό ροών, πρέπει να κλείσει τις ροές. Στείλτε ένα αίτημα κλεισίματος ροής:

1. Εκχωρήστε τη δομή URB καλώντας το WdfUsbTargetDeviceCreateUrb.

2. Ορίστε τη μορφή URB για το κλείσιμο του αιτήματος ροής. Το μέλος UrbPipeRequest της δομής URB είναι η δομή _URB_PIPE_REQUEST. Συμπληρώστε τα μέλη του ως εξής:

  • Απαιτούμενο μέλος Hdr του URB_FUNCTION_CLOSE_STATIC_STREAMS_URB_PIPE_REQUEST
  • Το μέλος PipeHandle πρέπει να είναι μια λαβή που περιέχει το τελικό σημείο που χρησιμοποιείται για το άνοιγμα της ροής.

3. Στείλτε το URB ως αίτημα WDF καλώντας το WdfRequestSend ή το WdfUsbTargetDeviceSendUrbSynchronously.

Η λαβή κλεισίματος ζητά το κλείσιμο όλων των ροών που είχαν ανοίξει προηγουμένως από το πρόγραμμα οδήγησης πελάτη. Το πρόγραμμα οδήγησης πελάτη δεν μπορεί να χρησιμοποιήσει αιτήματα για να κλείσει μια συγκεκριμένη ροή στο τελικό σημείο.

Βέλτιστες πρακτικές για την αποστολή αιτημάτων στατικής ροής

Η στοίβα προγράμματος οδήγησης USB εκτελεί επαλήθευση στο ληφθέν URB. Για να αποφύγετε σφάλματα επικύρωσης, κάντε τα εξής:

  • Μην στέλνετε αιτήματα ανοιχτής ροής ή κλεισίματος ροής σε τελικά σημεία που δεν υποστηρίζουν ροές. Καλέστε το WdfUsbTargetDeviceQueryUsbCapability (, USBD_QueryUsbCapability) του προγράμματος οδήγησης WDM για να προσδιορίσετε την υποστήριξη στατικής ροής και να στείλετε αιτήματα ροής μόνο εάν το υποστηρίζει το τελικό σημείο.
  • Μην ζητάτε περισσότερες ροές (ανοιχτές) από τον μέγιστο αριθμό ροών που υποστηρίζονται και μην στέλνετε αίτημα χωρίς να καθορίσετε τον αριθμό των ροών. Ο αριθμός των ροών καθορίζεται με βάση τον αριθμό των ροών που υποστηρίζονται από τη στοίβα προγράμματος οδήγησης USB και το τελικό σημείο της συσκευής.
  • Μην στέλνετε αίτημα ανοιχτής ροής σε τελικό σημείο που έχει ήδη ανοιχτή ροή.
  • Μην στέλνετε αίτημα κλεισίματος ροής σε τελικό σημείο που δεν έχει ανοιχτή ροή.
  • Αφού ανοίξετε μια στατική ροή για ένα τελικό σημείο, μην στέλνετε αιτήματα εισόδου/εξόδου χρησιμοποιώντας τη λαβή του σωλήνα τελικού σημείου που λαμβάνεται μέσω μιας επιλεγμένης διαμόρφωσης ή επιλογής αιτήματος διεπαφής. Αυτό ισχύει ακόμα κι αν η στατική ροή είναι κλειστή.
Επαναφορά και ακύρωση εργασιών αγωγού

Περιστασιακά, οι μεταφορές προς ή από ένα τελικό σημείο ενδέχεται να αποτύχουν. Τέτοιες αποτυχίες μπορεί να προκληθούν από συνθήκες σφάλματος στο τελικό σημείο ή στον ελεγκτή κεντρικού υπολογιστή, όπως μια κατάσταση διακοπής ή διακοπής. Για την εκκαθάριση της συνθήκης σφάλματος, το πρόγραμμα οδήγησης πελάτη πρώτα ακυρώνει την εκκρεμή μεταφορά και, στη συνέχεια, επαναφέρει τον σωλήνα που σχετίζεται με το τελικό σημείο. Για να ακυρώσετε μια εκκρεμή μεταφορά, το πρόγραμμα οδήγησης πελάτη μπορεί να στείλει ένα αίτημα διακοπής του σωλήνα. Για να επαναφέρετε έναν σωλήνα, το πρόγραμμα οδήγησης πελάτη πρέπει να στείλει ένα αίτημα επαναφοράς σωλήνα.

Για ροή, τα αιτήματα abort-pipe και reset-pipe δεν υποστηρίζονται για μεμονωμένες ροές που σχετίζονται με το μαζικό τελικό σημείο. Εάν μια μεταφορά σε έναν συγκεκριμένο σωλήνα ροής αποτύχει, ο ελεγκτής κεντρικού υπολογιστή θα σταματήσει τις μεταφορές σε όλους τους άλλους αγωγούς για άλλες ροές Για να ανακάμψει από την κατάσταση σφάλματος, το πρόγραμμα οδήγησης πελάτη θα πρέπει να ακυρώσει χειροκίνητα τη μεταφορά σε κάθε ροή μια λαβή σωλήνα για την αποστολή αιτήματος επαναφοράς σωλήνα στο τελικό σημείο Για αυτό το αίτημα, το πρόγραμμα οδήγησης πελάτη πρέπει να καθορίσει τη λαβή του αγωγού του τελικού σημείου στη δομή _URB_PIPE_REQUEST και να ορίσει τη συνάρτηση URB (Hdr.Function) σε URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL.

Ολοκληρωμένο παράδειγμα

Το ακόλουθο παράδειγμα κώδικα δείχνει πώς να ανοίξετε μια ροή.

  1. NTSTATUS
  2. OpenStreams (
  3. _In_ WDFDEVICE Device,
  4. _In_ WDFUSBPIPE Pipe)
  5. {
  6. NTSTATUS status;
  7. PDEVICE_CONTEXT deviceContext;
  8. PPIPE_CONTEXT pipeContext;
  9. USHORT cStreams = 0;
  10. USBD_PIPE_HANDLE usbdPipeHandle;
  11. WDFMEMORY urbMemory = NULL;
  12. PURB urb = NULL;
  13. PAGED_CODE();
  14. deviceContext =GetDeviceContext(Device);
  15. pipeContext = GetPipeContext (Pipe);
  16. if (deviceContext->MaxStreamsController == 0)
  17. {
  18. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  19. "%!FUNC! Static streams are not supported.");
  20. status = STATUS_NOT_SUPPORTED;
  21. goto Exit;
  22. }
  23. // If static streams are not supported, number of streams supported is zero.
  24. if (pipeContext->MaxStreamsSupported == 0)
  25. {
  26. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  27. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  28. "%!FUNC! Static streams are not supported by the endpoint.");
  29. goto Exit;
  30. }
  31. // Determine the number of streams to open.
  32. // Compare the number of streams supported by the endpoint with the
  33. // number of streams supported by the host controller, and choose the
  34. // lesser of the two values. The deviceContext->MaxStreams value was
  35. // obtained in a previous call to WdfUsbTargetDeviceQueryUsbCapability
  36. // that determined whether or not static streams is supported and
  37. // retrieved the maximum number of streams supported by the
  38. // host controller. The device context stores the values for IN and OUT
  39. // endpoints.
  40. // Allocate an array of USBD_STREAM_INFORMATION structures to store handles to streams.
  41. // The number of elements in the array is the number of streams to open.
  42. // The code snippet stores the array in its device context.
  43. cStreams = min(deviceContext->MaxStreamsController, pipeContext->MaxStreamsSupported);
  44. // Allocate an array of streams associated with the IN bulk endpoint
  45. // This array is released in CloseStreams.
  46. pipeContext->StreamInfo = (PUSBD_STREAM_INFORMATION) ExAllocatePoolWithTag (
  47. NonPagedPool,
  48. sizeof (USBD_STREAM_INFORMATION) * cStreams,
  49. USBCLIENT_TAG);
  50. if (pipeContext->StreamInfo == NULL)
  51. {
  52. status = STATUS_INSUFFICIENT_RESOURCES;
  53. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  54. "%!FUNC! Could not allocate stream information array.");
  55. goto Exit;
  56. }
  57. RtlZeroMemory (pipeContext->StreamInfo,
  58. sizeof (USBD_STREAM_INFORMATION) * cStreams);
  59. // Get USBD pipe handle from the WDF target pipe object. The client driver received the
  60. // endpoint pipe handles during device configuration.
  61. usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle (Pipe);
  62. // Allocate an URB for the open streams request.
  63. // WdfUsbTargetDeviceCreateUrb returns the address of the
  64. // newly allocated URB and the WDFMemory object that
  65. // contains the URB.
  66. status = WdfUsbTargetDeviceCreateUrb (
  67. deviceContext->UsbDevice,
  68. NULL,
  69. &urbMemory,
  70. &urb);
  71. if (status != STATUS_SUCCESS)
  72. {
  73. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  74. "%!FUNC! Could not allocate URB for an open-streams request.");
  75. goto Exit;
  76. }
  77. // Format the URB for the open-streams request.
  78. // The UsbBuildOpenStaticStreamsRequest inline function formats the URB by specifying the
  79. // pipe handle to the entire bulk endpoint, number of streams to open, and the array of stream structures.
  80. UsbBuildOpenStaticStreamsRequest (
  81. urb,
  82. usbdPipeHandle,
  83. (USHORT)cStreams,
  84. pipeContext->StreamInfo);
  85. // Send the request synchronously.
  86. // Upon completion, the USB driver stack populates the array of with handles to streams.
  87. status = WdfUsbTargetPipeSendUrbSynchronously (
  88. Pipe,
  89. NULL,
  90. NULL,
  91. urb);
  92. if (status != STATUS_SUCCESS)
  93. {
  94. goto Exit;
  95. }
  96. Exit:
  97. if (urbMemory)
  98. {
  99. WdfObjectDelete (urbMemory);
  100. }
  101. return status;
  102. }