USBGPS OpenSource Project homepage  

กก

Project Maintainer: Yu Lu   




Introduction

Hardware

Firmware

Device Driver

App Software

Download

Document

Thanks


Device Driver

At first I need to say that I am not an expert in driver developping, instead I am just a beginner in this field. I finish this driver just for the very basic function: To communicate with PC. In the current version of my device driver, there is no consideration for time-out, crash recovery, power management..., which are necessary for a professional driver. I have not so much time to implement all this functions, becasuse to learn how to implement these will take longer time. For more information about driver developping, I have some helpful reference here.

To write device driver, you must follow some designing rules defined by operating system. Device driver is written in C, but don't expect to understand the source code if you have no knowledge of these rules, ---- even you are a master of C language. Also to debug the device driver is a real nightmare to programmer: In user mode, your code will just give wrong result in the existence of bugs; but in kernel code, a minor bug will crash the whole system. I don't remember how many times I have rebooted my computer while I wrote this "simple" device driver for this project. Because I only wrote WDM driver under Windows now, I just want to say something that I can understand about driver-writting under Windows. Of course I will jump directly to some points which are special to my USBGPS driver, I will assume that you already have some basic knowledge about WDM driver, such as IRP, IO manager, FDO, URB...

To understand driver, you should understand hardware and firmware. This is obvious becase the resources driver need to visit are provided by hardware&firmware. Generally in USB device, the resouce include configuration, interface, endpoints. For this project, I only have one interface and one configuration, so I only need to talk about endpoints. In my USB configuration, there are 5 endpoints:
Endpoint 0
Endpoint0 is used to configure device. It is bi-directional, namely, PC<--->hardware. PC finish all necessary USB event through this endpoint, such as CLEAR_FEATURE, GET_DESCRIPTOR, GET_STATUS,SET_CONFIGURATION, etc. All these events are generated by system, so endpoint 0 doesn't appear in my driver's source code.
Endpoint 1
Endpoint1 is used to send system commands to hardware, like reading the vale of USBN9603's registers, reading C51's registers, controlling C51's timer... Most commands here are for debugging purpose. This endpoint is from PC to hardware, namely, PC--->hardware.
Endpoint 2
The purpose of Endpoint2 is combined with Endpoint1: PC send command to hardware through Endpoint1, Endpoint2 send the result of the command to PC(if this command requires result returned). So endpoint2 is from hardware to PC, namely, PC<---hardware. Endpoint2 combined with endpoint1 provides debugging channel for me in the debug state. Also it provides a method to control GP2021, but this method is not practical in real time. It's just for me to check if the GP2021 interface functions correctly.
Endpoint 5
Endpoint5 is used to send control commands to GP2021 in real-time mode. Its direction is from PC--->hardware. The command from PC is organized in the format of Buffer 3 I give in the firmware description. While hardware receives this bunch of commands, it will write these commands to corresponding registers of GP2021.
Endpoint 6
Endpoint6 is used to send 4 collections(3.6ms) of 6 channel's data to PC in real-time mode. It is from hardware to PC, PC<----hardware. Firmware organizes these data into the format of Buffer1 (or Buffer2) as I give in firmware description.
Now we have clear understanding of resources provided by hardware, a question arises: How to visit these resources? This question should be answerred by device driver. It's lucky for a programmer to write USB device driver, because USB driver has no hassle about IO port, interrupt, DMA setting. USB driver visits all resource through URB. Here is a piece of code about generating a URB in my source code:

URB urb ;

pch = (PUCHAR) ioBuffer;
UsbBuildInterruptOrBulkTransferRequest(&urb,
           sizeof( _URB_BULK_OR_INTERRUPT_TRANSFER),
           pdx->Pipe1,
           pch,
           NULL,
           cbin,
           USBD_SHORT_TRANSFER_OK,
           NULL);
          
here pdx->Pipe1 indicates the endpoint number. pch is a pointer pointing to the address of the buffer we want to send to hardware. For the meaning of other arguments, please read the reference.

In user application, user-mode code call device driver through I/O Control Operations. An application uses the standard Microsoft Win32 API function DeviceIoControl to perform such an operation. I don't provide function call like ReadFile() or WriteFile() because I think DeviceIoControl() is enough for this project. For example, I define I/O control code like this ( from ioctls.h):
#define IOCTL_USBGPS_BULK_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
The processing of this I/O control code is given below in Control.cpp:
NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp){
           ...
           ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
          
           switch (code)
           { // process request
           ...
          
           case IOCTL_USBGPS_BULK_WRITE: // code == 0x803
           { // IOCTL_USBGPS_USBGPS_WRITE
           if(ioBuffer && cbin >= 0 && cbout >= 0)
           {
           URB urb ;
          
           pch = (PUCHAR) ioBuffer;
           UsbBuildInterruptOrBulkTransferRequest(&urb,
           sizeof( _URB_BULK_OR_INTERRUPT_TRANSFER),
           pdx->Pipe1,
           pch,
           NULL,
           cbin,
           USBD_SHORT_TRANSFER_OK,
           NULL);
           status = SendAwaitUrb(fdo,&urb);
          
           if(NT_SUCCESS(status))
           info = cbin;
           else
           info = 0;
          
           // TODO insert code here to handle this IOCTL, which uses METHOD_BUFFERED
           }
           break;
           }
           ...
           }


From this segment of code, you can see that the driver doesn't understand the data structure of the tranmitted buffer. The driver is just responsible for packaging the buffer into URB and sending URB to USB controller, then waiting for response. The high-level user code and the low-level firmware should understant that for furture processing. So device driver is just the media for user code and firmware to talk to each other.

The compiler for devide driver is Win2000 DDK.

Some helpful reference

Welcome to USBGPS Opensource Project Homepage
© Copyright 2004    Email:   Yu Lu