C# 实现自定义的USB设备与上位机进行通信(上位机部分)

  因为以前没用过USB,对USB也不了解,于是上网查了很多资料,不过网上的资料都是零零散散,不清不楚的,于是我自己总结了一下,下面几个链接是网上这么多零散资料里,我觉得比较有参考意义的。

  USB设备连接思路参考:https://www.cnblogs.com/xyzyx/articles/2959610.html#undefined

  代码参考:http://www.cnblogs.com/xidongs/archive/2011/11/28/2266100.html#

  收发数据参考:https://blog.csdn.net/zouwen198317/article/details/5814212

  整个思路概况为3步:1、识别设备;2、连接设备;3、数据传输。

  而我这里所有的步骤都是基于直接调用Windos的DLL实现的,调用了hid.dll、setupapi.dll、kernel32.dll,建立好工程后,可以从你自己的电脑里复制出这几个文件到工程目录下使用,调用DLL思路如下:

            /*          使用USB传输数据思路
             * 0.连接DALL的库函数做好准备工作
             * 1.调用HidD_GetHidGuid获取到GUID
             * 2.调用SetupDiGetClassDevs获取全部的HID值
             * 3.调用SetupDiEnumDeviceInterfaces,填写PSP_DEVICE_INTERFACE_DATA结构数据项,
             *   该结构用于识别一个HID设备接口,结构具体作用参考函数说明
             * 4.调用SetupDiGetDeviceInterfaceDetail获取特定的HID路径名
             * 5.调用CreateFile获得设备HID句柄
             * 6.调用HidD_GetAttributes,填写HID_ATTRIBUTES结构的数据项,
             *   该结构包含设备的厂商ID、产品ID和产品序列号,程序可比照这些获取到的参数值确定该设备是否是查找的设备
             * 7.查找成功完成,未成功重复3 4 5 6 步
             * 8.与自己需要的USB设备连接成功后,调用WriteFile和ReadFile进行数据传输
             * 9.关闭时调用SetupDiDestroyDeviceInfoList(hDevInfo)和CloseHandle(HidHandle)断开连接并关闭USB设备
             */

  接下来开始按上面的步骤来操作。

0、连接DALL的库函数做好准备工作
/*  ======================声明dll文件中需要调用的函数,以下是调用windows的API的函数======================= */

        //获得USB设备的GUID
        [DllImport("hid.dll")]
        public static extern void HidD_GetHidGuid(ref Guid HidGuid);
        Guid guidHID = Guid.Empty;

        //获得一个包含全部HID信息的结构数组的指针,具体配置看函数说明:https://docs.microsoft.com/zh-cn/windows/desktop/api/setupapi/nf-setupapi-setupdigetclassdevsw
        [DllImport("setupapi.dll", SetLastError = true)]
        public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags);
        IntPtr hDevInfo;

        public enum DIGCF
        {
            DIGCF_DEFAULT = 0x1,
            DIGCF_PRESENT = 0x2,
            DIGCF_ALLCLASSES = 0x4,
            DIGCF_PROFILE = 0x8,
            DIGCF_DEVICEINTERFACE = 0x10
        }

        //该结构用于识别一个HID设备接口,获取设备,true获取到
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
        //SetupDiEnumDeviceInterfaces 识别出来的SP_DEVICE_INTERFACE_DATA结构,该结构标识满足搜索参数的接口
        public struct SP_DEVICE_INTERFACE_DATA
        {
            public int cbSize;                     //SP_DEVICE_INTERFACE_DATA结构的大小
            public Guid interfaceClassGuid;        //设备接口所属的类的GUID
            public int flags;                      //接口转态标记
            public int reserved;                   //保留,不做使用
        }

        // 获得一个指向该设备的路径名,接口的详细信息 必须调用两次 第1次返回长度 第2次获取数据
        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData,
                                                                   int deviceInterfaceDetailDataSize, ref int requiredSize, SP_DEVINFO_DATA deviceInfoData);

        [StructLayout(LayoutKind.Sequential)]
        public class SP_DEVINFO_DATA
        {
            public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
            public Guid classGuid = Guid.Empty; // temp
            public int devInst = 0; // dumy
            public int reserved = 0;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 2)]
        internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
        {
            internal int cbSize;
            internal short devicePath;
        }

        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);

        //获取设备文件(获取句柄)
        [DllImport("kernel32.dll", SetLastError = true)]
        //根据要求可在下面设定参数,具体参考参数说明:https://docs.microsoft.com/zh-cn/windows/desktop/api/fileapi/nf-fileapi-createfilea
        private static extern int CreateFile
            (
             string lpFileName,                             // file name 文件名
             uint   dwDesiredAccess,                        // access mode 访问模式
             uint   dwShareMode,                            // share mode 共享模式
             uint   lpSecurityAttributes,                   // SD 安全属性
             uint   dwCreationDisposition,                  // how to create 如何创建
             uint   dwFlagsAndAttributes,                   // file attributes 文件属性
             uint   hTemplateFile                           // handle to template file 模板文件的句柄
            );

        [DllImport("Kernel32.dll", SetLastError = true)]  //接收函数DLL
        private static extern bool ReadFile
            (
                IntPtr hFile,
                byte[] lpBuffer,
                uint nNumberOfBytesToRead,
                ref uint lpNumberOfBytesRead,
                IntPtr lpOverlapped
            );

        [DllImport("kernel32.dll", SetLastError = true)] //发送数据DLL
        public static extern Boolean WriteFile
            (
                IntPtr hFile,
                byte[] lpBuffer,
                uint nNumberOfBytesToWrite,
                ref uint nNumberOfBytesWrite,
                IntPtr lpOverlapped
            );

        [DllImport("hid.dll")]
        /*HidDeviceObject:指定顶级集合的打开句柄
          Attributes:指向调用者分配的HIDD_ATTRIBUTES结构的指针,该结构返回由HidDeviceObject指定的集合的属性*/
        private static extern Boolean HidD_GetAttributes(IntPtr hidDeviceObject, out HIDD_ATTRIBUTES HIDD_ATTRIBUTES);
        //HidD_GetAttributes的调用者使用此结构来对比查找设备
        public unsafe struct HIDD_ATTRIBUTES
        {
            public int    Size;            //指定HIDD_ATTRIBUTES结构的大小(以字节为单位)
            public ushort VendorID;        //指定HID设备的供应商ID( VID )
            public ushort ProductID;       //指定HID设备的产品ID( PID )
            public ushort VersionNumber;   //指定HIDClass设备的制造商版本号
        }

        //自定义的结构体,用来存放自己要操作的设备信息
        public unsafe struct my_usb_id
        {
            public ushort my_vid;
            public ushort my_Pid;
            public ushort my_number;
        }

        /**/
        [DllImport("hid.dll")]
        /*HidP_GetCaps返回一个顶级集合的 HIDP_CAPS结构,获取设备具体信息,这里暂时用不上
        PreparsedData:指向顶级集合的预分析数据的指针; Capabilities:指向调用程序分配的缓冲区的指针,该缓冲区用于返回集合的HIDP_CAPS结构*/
        private static extern uint HidP_GetCaps(IntPtr PreparsedData, out HIDP_CAPS Capabilities);
        [StructLayout(LayoutKind.Sequential)]
        public unsafe struct HIDP_CAPS
        {
            public ushort UsagePage;                                            //指定顶级集合的使用情况
            public uint   Usage;                                                //指定顶级集合的 使用ID
            public ushort InputReportByteLength;                                //指定所有输入报告的最大大小(以字节为单位)
            public ushort OutputReportByteLength;                               //指定所有输出报告的最大大小(以字节为单位)
            public ushort FeatureReportByteLength;                              //指定所有功能报告的最大长度(以字节为单位)
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]               //保留供内部系统使用数组
            public ushort NumberLinkCollectionNodes;                            //指定的数量HIDP_LINK_COLLECTION_NODE了为这个顶级集合返回的结构HidP_GetLinkCollectionNodes
            public ushort NumberInputButtonCaps;                                //指定HidP_GetButtonCaps返回的输入HIDP_BUTTON_CAPS结构的数量
            public ushort NumberInputValueCaps;                                 //指定HidP_GetValueCaps返回的输入HIDP_VALUE_CAPS结构的数量
            public ushort NumberInputDataIndices;                               //指定分配给所有输入报告中的按钮和值的数据索引数
            public ushort NumberOutputButtonCaps;                               //指定HidP_GetButtonCaps返回的输出HIDP_BUTTON_CAPS结构的数量
            public ushort NumberOutputValueCaps;                                //指定HidP_GetValueCaps返回的输出HIDP_VALUE_CAPS结构的数量
            public ushort NumberOutputDataIndices;                              //指定分配给所有输出报告中的按钮和值的数据索引数
            public ushort NumberFeatureButtonCaps;                              //指定HidP_GetButtonCaps返回的功能HIDP_BUTTONS_CAPS结构的总数
            public ushort NumberFeatureValueCaps;                               //指定HidP_GetValueCaps返回的功能HIDP_VALUE_CAPS结构的总数
            public ushort NumberFeatureDataIndices;                             //指定分配给所有要素报告中的按钮和值的数据索引数
        }

        [DllImport("hid.dll")]
        private static extern Boolean HidD_GetPreparsedData(IntPtr hidDeviceObject, out IntPtr PreparsedData);     

        //释放设备
        [DllImport("hid.dll")]
        static public extern bool HidD_FreePreparsedData(ref IntPtr PreparsedData);

        //关闭访问设备句柄,结束进程的时候把这个加上保险点
        [DllImport("kernel32.dll")]
        static public extern int CloseHandle(int hObject);

        //查看数据传输异常函数
        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress", SetLastError = true)]
        public static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);
  上面的DLL调用在 public partial class Form1 : Form{}函数里直接声明就好了
1~7连接USB设备  连接前先定义一些要用到的变量,再调用 UsBMethod 函数连接,这个函数里面包含了1~7的所有步骤:
        //定于句柄序号和一些参数,具体可以去网上找这些API的参数说明
        int HidHandle = -1;
        int sele = 0;
        int usb_flag = 0;
        bool result;
        string devicePathName;

        //CreateFile参数配置
        public const uint GENERIC_READ = 0x80000000;
        public const uint GENERIC_WRITE = 0x40000000;
        public const uint FILE_SHARE_READ = 0x00000001;
        public const uint FILE_SHARE_WRITE = 0x00000002;
        public const int OPEN_EXISTING = 3;

        private void UsBMethod(int index)
        {
            //获取USB设备的GUID
            HidD_GetHidGuid(ref guidHID);

            //Console.WriteLine(" GUID_HID = "+ guidHID);       //输出guid信息调试用

            //获取系统中存在的所有设备的列表,这些设备已从存储卷设备接口类启用了接口
            hDevInfo = SetupDiGetClassDevs(ref guidHID, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);

            int bufferSize = 0;
            ArrayList HIDUSBAddress = new ArrayList();

            while (true)
            {

                //获取设备,true获取到
                SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
                DeviceInterfaceData.cbSize = Marshal.SizeOf(DeviceInterfaceData);

                for (int i = 0; i < 3; i++)
                {
                    //识别HID设备接口,获取设备,返回true成功
                    result = SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref guidHID, (UInt32)index, ref DeviceInterfaceData);
                }

                //Console.WriteLine(" 识别HID接口\t"+result);       //识别接口打印信息查看

                //第一次调用出错,但可以返回正确的Size
                SP_DEVINFO_DATA strtInterfaceData = new SP_DEVINFO_DATA();
                //获得一个指向该设备的路径名,接口的详细信息 必须调用两次 第1次返回路径长度
                result = SetupDiGetDeviceInterfaceDetail(hDevInfo, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, strtInterfaceData);

                //第二次调用传递返回值,调用即可成功 , 第2次获取路径数据
                IntPtr detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
                SP_DEVICE_INTERFACE_DETAIL_DATA detailData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
                detailData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));

                Marshal.StructureToPtr(detailData, detailDataBuffer, false);
                result = SetupDiGetDeviceInterfaceDetail(hDevInfo, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, strtInterfaceData);

                if (result == false)
                {
                    break;
                }

                //获取设备路径访
                IntPtr pdevicePathName = (IntPtr)((int)detailDataBuffer + 4);
                devicePathName = Marshal.PtrToStringAuto(pdevicePathName);
                HIDUSBAddress.Add(devicePathName);

                //Console.WriteLine(" Get_DvicePathName = "+ devicePathName);     //打印路径信息,调试用

                //连接USB设备文件
                int aa = CT_CreateFile(devicePathName);
                usb_flag = aa;
                if (aa == 1)                                    //设备连接成功
                {
                    //获取设备VID PID 出厂编号信息判断是否跟自定义的USB设备匹配,匹配返回 1
                    usb_flag = HidD_GetAttributes(HidHandle);
                    if (usb_flag == 1) break;
                    else usb_flag = 0;
                }
                else usb_flag = 0;
                index++;
            }

        }

  上面的函数调用到了一个建立和设备的连接的函数,该函数主要是用来跟设备建立连接,函数如下:

  /*  =================建立和设备的连接==================    */
        public unsafe int CT_CreateFile(string DeviceName)
        {
            HidHandle = CreateFile
            (
                DeviceName,
                //GENERIC_READ |          // | GENERIC_WRITE,//读写,或者一起
                GENERIC_READ | GENERIC_WRITE,
                //FILE_SHARE_READ |       // | FILE_SHARE_WRITE,//共享读写,或者一起
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                0,
                OPEN_EXISTING,
                0,
                0
             );

            //Console.WriteLine(" IN_DeviceName = " + DeviceName);                    //查看参数是否传入           

            if (HidHandle == -1) //INVALID_HANDLE_VALUE实际值等于-1,连接失败
            {

                //Console.WriteLine(" 失败 HidHandle = 0x" + "{0:x}",HidHandle );     //查看状态,打印调试用
                return 0;
            }
            else    //连接成功
            {
                //Console.WriteLine(" 成功 HidHandle = 0x" + "{0:x}",HidHandle);      //查看状态,打印调试用
                return 1;
            }
        }

  调用函数建立好连接后,就要判断是否是自己需要的USB设备了,这里就调用了一个判断函数:

 /*  ==============获取设备的VID PID 出厂编号等信息,存放到HIDD_ATTRIBUTES==============   */
        public unsafe int HidD_GetAttributes(int handle)
        {
            HIDD_ATTRIBUTES HIDD_ATTRIBUTE = new HIDD_ATTRIBUTES();
            //handle是CreateFile函数返回一个有效的设备操作句柄,HIDD_ATTRIBUTES是函数返回的结构体信息(VID PID 设备号)
            bool sel = HidD_GetAttributes((IntPtr)handle, out HIDD_ATTRIBUTE);

            /*//打印VID、PID信息以16进制显示调试用,打印数据前不能接+号,不然打印不出来,信息为0
            Console.Write("\t" + "VID:{0:x}", HIDD_ATTRIBUTE.VendorID );
            Console.Write("\t" + "PID:{0:x}", HIDD_ATTRIBUTE.ProductID);
            Console.WriteLine("\r\n");   */

            if (sel == true)  //获取设备信息成功
            {
                //对自己定义的my_usb_id结构体赋值,输入自己要操作的设备参数,用来跟读取出来的设备参数比较
                my_usb_id my_usb_id = new my_usb_id();
                my_usb_id.my_vid = 4292;        //自定义的USB设备VID 0x10c4=4292
                my_usb_id.my_Pid = 33485;       //自定义的USB设备PID 0x82cd=33485

                if (my_usb_id.my_vid == HIDD_ATTRIBUTE.VendorID && my_usb_id.my_Pid == HIDD_ATTRIBUTE.ProductID) //判断识别出来的是不是自定义的USB设备
                {
                    //Console.WriteLine("获取VID PID成功"); //打印信息调试用
                    sele = 1;
                }
                else sele = 0;
                return sele;
            }
            else
            {
                //Console.WriteLine("获取VID PID失败");     //打印信息调试用
                return sele = 0;
            }
        }

  到这里就已经连接上USB设备了,接下来可以收发数据了。

8、调用WriteFile和ReadFile进行数据传输  这里的发送函数使用的是同步发送,至于怎样同步异步各位可以自行到https://docs.microsoft.com/zh-cn/windows/desktop/api/fileapi/nf-fileapi-writefile查看,或者看我前面的收发数据的参考链接
 private void button2_Click(object sender, EventArgs e)
        {
            if (usb_flag == 1)   //USB识别成功后发送数据
            {
                uint read = 0;
                byte[] src = { 1, 3,1 };
                bool isread = WriteFile((IntPtr)HidHandle, src, (uint)9, ref read, IntPtr.Zero);
                if (isread == false)
                {
                    int errCode = Marshal.GetLastWin32Error();
                    // Console.WriteLine("数据发送失败!错误代码:" + errCode);
                }
            }
        }
注意这里缓存区要比你的报文描述符多一个字节,不然会出错,至于接收,使用异步接收,在接收前要做一个调用DLL声明:
        /*构建一个Overlapped结构,异步通信用,
           internal是错误码,internalHigh是传输字节,这个两个是IO操作完成后需要填写的内容*/
        [StructLayout(LayoutKind.Sequential)]
        public struct OVERLAPPED
        {
            public IntPtr Internal;         //I/O请求的状态代码
            public IntPtr InternalHigh;     //传输I/O请求的字节数
            public int Offset;              //文件读写起始位置
            public int OffsetHigh;          //地址偏移量
            public IntPtr hEvent;           //操作完成时系统将设置为信号状态的事件句柄
        }

        /*监听异步通信函数*/
        [DllImport("Kernel32.dll")]
        public static extern unsafe long WaitForSingleObject(IntPtr hHandle, long dwMilliseconds);
  声明好后就开始写接收函数了,接收函数怎么异步接收各位可以自行百度,或者官网查阅,也可以看穷前面的收发函数参考链接。
        public void redata()//USB异步接收数据
        {
            //初始化Overlapped
            OVERLAPPED overlap = new OVERLAPPED();
            overlap.Offset = 0;
            overlap.OffsetHigh = 0;

            //创建事件对象
            overlap.hEvent = CreateEvent(IntPtr.Zero, false, false, null);

            //接收数据缓存区:接收到的数据如果比这个小,则按实际数据大小,接收到一个ID+64个数据
            byte[] buffer = new byte[70];
            int dwRead = 0;
            Console.WriteLine("read... ");
            //while (true)
            {
                //读设备
                bool re = ReadFile(HidHandle, buffer, 70, out dwRead, out overlap);
                if (re != false)
                {
                    SetupDiDestroyDeviceInfoList(hDevInfo);
                    for (int i = 0; i < 70; i++)
                    {
                        Console.WriteLine("i = " + i + " \t buffer = " + buffer[i]);
                    }
                    MessageBox.Show(" READ OK !");
                    //break;
                }
            }
            // long cc=WaitForSingleObject(overlap.hEvent, 5000);
        }

  这样异步接收可以开一个定时器时不时检测是否有数据接收,来实现,开定时是可以参考我的隐藏窗体功能的那篇文章:https://www.cnblogs.com/xingboy/p/10110443.html

  收发完函数后,就可以关闭通道了,以便节约资源嘛。

9、关闭USB设备

  /*  释放关闭USB设备   */
        public void Dispost()
        {
            //释放设备资源(hDevInfo是SetupDiGetClassDevs获取的)
            SetupDiDestroyDeviceInfoList(hDevInfo);
            //关闭连接(HidHandle是Create的时候获取的)
            CloseHandle(HidHandle);
        }
        //===================================================

以上就是USB通信上位机部分的内容了,这些函数都放在 public partial class Form1 : Form{ } 完成,至于下位机的部分各位可以参考:https://www.cnblogs.com/xingboy/p/9913963.html

补充一点:如果链接在你的电脑可正常使用,在别的电脑不可以用的话,解决方法可以参考我另一个文章:https://www.cnblogs.com/xingboy/p/9876812.html
 
 

原文地址:https://www.cnblogs.com/xingboy/p/9816234.html

时间: 2024-10-09 16:10:01

C# 实现自定义的USB设备与上位机进行通信(上位机部分)的相关文章

12.PMAC上位机-中断通信(下位机通知上位机)

之前说过,上位机控制硬件都是通过发送指令进行的,这是单向的.那么反过来,下位机硬件给上位机发送指令怎么才能实现呢?对于PMAC来说,最常见的情况就是,当PMAC一次运动完成时通知当前PC程序运动已完成. 1.下位机通知上位机原理 如下图所示, PC给PMAC发送指令控制它做什么,当运动程序完成后中断通知上位机,在中断的同时发送一个标识P100表明完成的程序号,这个标明到底是1号轴运动完,还是是2号轴运动完.在PC端有一个中断回调函数,下位机发送中断后,会自动跳转到该函数中,中断函数接受中断,根据

基于libUSB的USB设备固件更新程序(下载数据)(转)

源:基于libUSB的USB设备固件更新程序(下载数据) 本文紧接上一篇日志:基于libUSB-Win32的USB设备固件更新程序(前言),相关背景以及起因等,此处不再赘述,如感兴趣请移步. libUSB-Win32给出的example里面,有一个bulk.c文件,分析其关键代码,结合libusb官方文档,摘出其关键代码如下: int main(void) { usb_dev_handle *dev = NULL; /* the device handle */ usb_init(); /* i

linux下虚拟机virtualbox USB设备设置

1.装好virtualbox以及扩展包后,系统将自动生成vboxusers的用户组,将自己的用户名添加到bvoxusers组,否则无法使用vbox. sudo usermod -G vboxusers your_user_name 2.使用USB设备: 在Virtualbox虚拟机配置面板中打开USB设备选项,分别勾选上“启动USB控制器”“启用usb2.0控制器”选项. 1.最简单的办法如下:$ sudo gedit /etc/fstab在末尾加上# the USB group# 对所有用户开

Linux下的硬件驱动——USB设备(转载)

usb_bulk_msg函数 当对usb设备进行一次读或者写时,usb_bulk_msg 函数是非常有用的; 然而, 当你需要连续地对设备进行读/写时,建议你建立一个自己的urbs,同时将urbs 提交给usb子系统. 转载于此http://os.chinaunix.net/a2003/0630/1056/000001056933.shtml Linux下的硬件驱动——USB设备(上)(驱动配置部分) USB设备越来越多,而Linux在硬件配置上仍然没有做到完全即插即用,对于Linux怎样配置和

USB设备驱动概述

USB设备驱动 ·  17.1 USB总线协议 ·  17.1.1 USB设备简介 ·  17.1.2 USB连接拓扑结构 ·  17.1.3 USB通信的流程 ·  17.1.4 USB四种传输模式 ·  17.2.1 观察USB设备的工具 ·  17.2.2 USB设备请求 ·  17.2.3 设备描述符 ·  17.2.4 配置描述符 ·  17.2.5 接口描述符 ·  17.2.6 端点描述符 ·  17.3.1 功能驱动与物理总线驱动 ·  17.3.2 构造USB请求包 ·  17

Linux usb子系统(二):USB设备驱动usb-skeleton.c

usb驱动分为通过usbfs操作设备的用户空间驱动,内核空间的内核驱动.两者不能同时进行,否则容易引发对共享资源访问的问题,死锁!使用了内核驱动,就不能在usbfs里驱动该设备. 下面转载的一篇分析usb-skeleton.c文章. 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结当然不可缺,更何况我决定为嵌入式卖命了.好,言归正传,我说一说这段时间的收获,跟大家分享一下Linux的驱动开发.但这次只先针对Linux的USB子系统作分析,因为周五研讨老板催

利用mass storage class 做免驱动usb设备.

当需要使用usb bulk传输,想让设备像串口通讯那样和PC主机通信, 通常需要自己做一个PC端的驱动,比较麻烦. 为避免在pc上编写usb设备驱动的麻烦,可以将设备做成mass storage 类的设备,使用通用的驱动. 在通讯之前设备端需要先做两件事: 1,实现mass storage 类的描述符和类请求. 2,实现必要的SCSI命令,让PC认为该设备已正常运作. 我利用修改linux中的gadget zero设备做了一个简单的设备. 如果是在裸机程序下面做,应该也差不多,直接拿芯片厂商BS

Virtualbox使用点滴(共享USB设备,Linux下我的用户没有加到vboxuser中去)

由于网银客户端的问题,只能够在windows环境下支付,所以一直保存着一个激活的virtualbox下的windows,用来完成在线支付. 过去这个激活的windows是安装在ubuntu 10.10 32bit版本上的,通过将usb设备共享给虚拟机实现网银支付. 由于机器更新,从virtualbox导出,安装到ubuntu 11.04 64bit版本上,可是每次试图开启usb共享时都会报错,终于到了周末,有些时间来跟踪这个问题了. 首先看错误报告,错误报告说需要为virtualbox安装ext

VMware虚拟机找不到USB设备该怎么办?

VMware虚拟机找不到USB设备该怎么办?打开虚拟机发现竟然找不到usb设备,键盘和鼠标都是usb的,这该怎么办呢?出现这个问题是因为VMUSBArbService服务没有开启,下面分享开启的方法 vm虚拟机下找不到USB设备的解决办法,开启VMUSBArbService服务项.必要是开启为自动. 一.windows系统的解决办法 1.开始菜单->服务 2.VMUSBArbService->右键->开启 3.重新启动拟虚机,是不是就看见了?如果没有,请检查USB设备是否插入正确. 二.