查看linux驱动使用的头文件,[转载]linux下usb驱动头文件的usb.h(二)
#define URB_NO_FSBR 0x0020 /* UHCI-specific */
#define URB_ZERO_PACKET 0x0040 /* 完成大块分解成小包输出
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */
struct usb_iso_packet_descriptor {
unsigned int offset;
unsigned int length; /* expected length */
unsigned int actual_length;
unsigned int status;
};
struct urb;
struct pt_regs;
typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
/**
struct urb - USB 请求块
◎usb_list 给当前的urb拥有者使用
◎pipe 保持端点的数字,方向,类型,或更多。创建这些值要同时对八个macros可访问的。usb_{snd,rcv}TYPEpipe(dev,endpoint中的TYPE是"ctrl" (control), "bulk", "int" (interrupt), or "iso" (isochronous).同步。例如usb_sndbulkpipe() or usb_rcvintpipe().
端点的数字从0到15。注意到in端点2和out端点2是不同的端点(管道)。当前的配置控制任何给定端点的存在,类型和最大的包大小
◎dev usb设备执行请求的标识符
◎status 在不同步的完成函数中被读取以获得特殊请求的状态。同步完成中只用它来区分urb是否被断开。每个帧的详细的状态在iso_freame-desc的域中
◎transfer_flag 一个变化的标志可能会被用在影响URB怎样提交,断开,或操作。不同的URB能用不同的flag
◎transfer_buffer 这个标识I/O请求从哪里的缓存开始执行,或者到那里完成。(除非URB_NO_TRANSFER_DMA_MAP 被置位)这个缓存不许对DMA有效的,它和kmalloc()或其等价物一起分配。这缓存被用来控制传输的数据进程。
◎trancfer_dma 当transfer_buffer包含有URB_NO_TRANSFER_DMA_MAP时,设备的驱动程序已经表示提供给DMA地址,那么主机端的主控制器的驱动程序会优先使用transfer_buffe作缓存
◎trancfer_lengeh 在不同步的完成函数中被读取,它显示有多少bytes被传输了。一般它和请求的是一样的,除非出现错误或者发生short read 。这个The URB_SHORT_NOT_OK 传输标志被用来把这些报告的short read作为错误。
◎transfer_buffer_lengeh transfer_buffer的大小。传输可能会根据端点最大包的大小来把数据变成一个个包。(包的大小在配置中完成,并在管道中编码。当长度为零时transfer_buffer 和 trancfer_dma多无效。
◎setup_packet 只在控制传输中使用,setup数据包包含八个比特控制传输总是发送这个数据包到设备,然后对transfer_buffer进行必要的读写(如果需要的话)
◎setup_dma 和URB_NO_TRANSFER_DMA_MAP设置一起在控制传输中使用。设备的驱动程序为setup_packet提供DMA地址。主机控制器驱动程序应当优先使用它(相对于setup_packet包)
◎start_frame 为同步传输返回返回原始的帧
◎number_of_packets 列出同步传输的缓存数量
◎interval 为中断或同步传输指定polling间隔。对于全速或低速设备它的单元是帧,对于高速,他的单元的微帧。
◎error_count 返回同步传输中报告的错误数
◎context 在完成状态函数中使用,它一般指向request-specific 驱动的上下
◎Complete 完成训练者。URB传递参数给完成状态函数。完成状态函数然后就会对URB进行操作,包括重新提交或释放它。
@iso_frame_desc: 用来给ISO transfer buffer提供数组,并收集每个缓存的传输状态
@timeout: 如果设置为零的话,那么URB将永远不会超时,否则这就是URB超时的时间。
这个结构表示usb的传输请求URB必须被calling usb_alloc_urb() 函数分配,用 usb_free_urb().函数来释放。用各种usb_fill_*_urb() 函数来做初始化. URBs使用usb_submit_urb()来提交请求, 并通过函数unlink_urb() or usb_kill_urb().来结束那些还没完成的的请求 。
数据传输缓存
一般来说驱动程序用函数kmalloc()来提供I/O缓存,否则就从一般的页池中得到。那是由tranfer_buffer提供的(控制请求也使用setup_packet),主机控制器的驱动为每个用于传输的缓存执行一个dma对应操作(或不对应),这些对应的操作在某些平台上可能会花费巨大(可能使用一个dmabounce buffer或同一个IOMMU对话)
作为选择的,驱动程序可能传递URB_NO_xxx_DMA_MAP传输标志,这个传输标志将会告诉主机控制器的驱动程序没有相应的DMA被需要,因为这个设备的驱动程序是知道DMA的。例如
一个设备驱动程序用usb_buffer_alloc() or call usb_buffer_map()分配一个DMA缓存。当这些传输标志被提供了,主机驱动程序将会试着用DMA地址在transfer_dma 或(和)setup_dma域中去发现,而不是他们自己决定一个DMA地址。(注意到transfer_dma 或(和)setup_dma必须仍然被设置因为不是所有的主机控制器使用DMA,实际的根hub也不是多使用DMA)
初始化
所有的URBs提交必须初始化设备,管道,传输标志(可能是零),完成标志,超时标志(可能是零)。The URB_ASYNC_UNLINK 传输标志影响以后的 the usb_unlink_urb()路由。注意:如果用usb_unlink_urb()设置 URB_ASYNC_UNLINK 失败这被忽略。因为同步的断开连接使用
usb_kill_urb() 代替 。
所有的URBs也必须初始化transfer_buffer 和transfer_buffer_length他们可能提供 URB_SHORT_NOT_OK 传输标志,他表明shor他 read 将会被认为是错误的,那个标志在写请求中是无效的。
Bulk URBs may
使用 URB_ZERO_PACKET传输标志,表明大的OUT传输应当总是以一个小的包作为结束。 即便是加上一个额外的零长度的包。
控制URBs必须提供一个setup_packet。这个setup_packet 和transfer_buffer可能和 DMA一一对应或者不是,他们是相互独立的。这个传输标志 URB_NO_TRANSFER_DMA_MAP和 URB_NO_SETUP_DMA_MAP 表明已经被对应上了。对于不是URBs控制请求 URB_NO_SETUP_DMA_MAP 将被忽略。
中断URBs必须提供一个时间间隔,表示间隔多久给传输投票。在URB提交提交以后,这个interval域实际反映了传输是如何被列成进度表的。这个投票间隔可能比请求更加的频繁。例如:某些控制器有最大的间隔为32微秒,而其他的可能为1024微秒。同步的UEBs也有传输间隔。(注意到对于同步端点和告诉的中断端点,在端点标识符的传输编码是对数的。设备驱动必须通过他们自己把这些值转化为线性单元。
同步URBs一般使用URB_ISO_ASAP 传输标志,他表明主机控制器把传输列成表只要带宽利用允许,然后设置start_frame 以反映实际在提交期被选中的帧。否则这个驱动程序必须指定start_frame然后处理传输不能开始的情况。然而驱动程序不知道当前带宽是如何分配的,当他们用usb_get_current_frame_number () 找到当前帧,他们就不知道这个帧数字的变化(帧计数器值的变化范围从256―――65535)
同步URBs有一个不同的数据传输模型,因为他的服务只是尽最大努力。发话方用iso_frame_desc 结构中的number_of_packets的值提供特殊的分配URBs,每个这样的包是独立的ISO传输。同步URBs一般被排成队列,驱动程序保证传输具有两倍的缓存后提交请求,然后在and then explicitly resubmitted in completion handlers 。所以那些视频(音频)数据流以恒定比特率传输因为主机控制器支持队列。
Completion Callbacks:
这个Completion Callbacks在in_interrupt() 中产生,其中完成处理的第一件事应该事检查状态域。
这个状态域为所有的URBs提供。他被用来报告断开的urbs,和所有non-ISO 传输的状态。他不应该在URb被返回到完成处理(ompletion handler.)前被检验。
这个context域一般用来连接URBs并返回相关的驱动和请求状态
当这个Completion Callbacks: 为non-isochronous URB而被调用。这个actual_length 域表明有多少比特被传输。这个域被更新即使URb因为错误或断开终止。
同步传输的状态在status and actual_length fields (包含在 iso_frame_desc array 数组中)。错误数包含在error_count 。而这个Completion callbacks 则是通过提交urb来保证一个恒定的传输比特率。
struct urb
{
/* private, usb core and host controller only fields in the urb */
struct kref kref; /* reference涉及count of the URB */
spinlock_t lock; /* lock for the URB */
void *hcpriv; /* private data for host controller */
struct list_head urb_list; /* list pointer to all active urbs */
int bandwidth; /* bandwidth for INT/ISO request */
atomic_t use_count; /* concurrent submissions counter */
u8 reject; /* submissions will fail */
/* public, documented备有证明文件的fields in the urb that can be used by drivers *
struct usb_device *dev; /* (in) pointer to associated关联的device */
unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
int transfer_buffer_length; /* (in) data buffer length */
int actual_length; /* (return) actual实际的transfer length */
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
int start_frame; /* (modify修改) start frame (ISO) */
int number_of_packets; /* (in) number of ISO packets */
int interval; /* (modify) transfer interval (INT/ISO) */
int error_count; /* (return) number of ISO errors */
int timeout; /* (in) timeout, in jiffies */
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */
};
* usb_fill_control_urb – 初始化一个控制URB
* @urb: 指向要初始化的URB的指针
* @dev: 指向对应这个URB的usb_devicce的结构的指针
* @pipe: the endpoint pipe
* @setup_packet: 指向setup_packet buffer的指针
* @transfer_buffer: 指向 the transfer buffer 的指针
* @buffer_length: the transfer buffer 的长度
* @complete:指向 usb_complete_t 的指针
* @context: what to set the urb context to.
*
* 初始化这个控制URBs进行适当的信息提交
* it to a device.
*/
static inline void usb_fill_control_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete,
void *context)
{
spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->setup_packet = setup_packet;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete;
urb->context = context;
}
/**
* usb_fill_bulk_urb – 帮助初始化一个bulk urb(((((同上)))))
* @urb: 指向要初始化的URB的指针
* @dev: pointer to the struct usb_device for this urb.
* @pipe: the endpoint pipe
* @transfer_buffer: pointer to the transfer buffer
* @buffer_length: length of the transfer buffer
* @complete: pointer to the usb_complete_t function
* @context: what to set the urb context to.
*
* Initializes a bulk urb with the proper information needed to submit it
* to a device.
*/
static inline void usb_fill_bulk_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete,
void *context)
{
spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete;
urb->context = context;
}
/**
* usb_fill_int_urb – 帮助初始化interrupt urb
* @urb: pointer to the urb to initialize.
* @dev: pointer to the struct usb_device for this urb.
* @pipe: the endpoint pipe
* @transfer_buffer: pointer to the transfer buffer
* @buffer_length: length of the transfer buffer
* @complete: pointer to the usb_complete_t function
* @context: what to set the urb context to.
* @interval: what to set the urb interval to, encoded like
通过把适当的信息递交给设备来初始化一个interrupt urb
注意到高速中断端点对端点间隔进行对数编码,在微帧中表达polling intervals (每毫秒8微帧)而在帧中为一帧每毫秒
static inline void usb_fill_int_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete,
void *context,
int interval)
{
spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete;
urb->context = context;
if (dev->speed == USB_SPEED_HIGH)
urb->interval = 1 << (interval - 1);
else
urb->interval = interval;
urb->start_frame = -1;
}
extern void usb_init_urb(struct urb *urb);
extern struct urb *usb_alloc_urb(int iso_packets, int mem_flags);
extern void usb_free_urb(struct urb *urb);
#define usb_put_urb usb_free_urb
extern struct urb *usb_get_urb(struct urb *urb);
extern int usb_submit_urb(struct urb *urb, int mem_flags);
extern int usb_unlink_urb(struct urb *urb);
extern void usb_kill_urb(struct urb *urb);
#define HAVE_USB_BUFFERS
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
int mem_flags, dma_addr_t *dma);
void usb_buffer_free (struct usb_device *dev, size_t size,
void *addr, dma_addr_t dma);
struct urb *usb_buffer_map (struct urb *urb);
#if 0
void usb_buffer_dmasync (struct urb *urb);
#endif
void usb_buffer_unmap (struct urb *urb);
struct scatterlist;
int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int nents);
#if 0
void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents);
#endif
/*-------------------------------------------------------------------*
* SYNCHRONOUS CALL SUPPORT *
*-------------------------------------------------------------------*/
extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size, int timeout);
extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length,
int timeout);
/* selective suspend/resume */
extern int usb_suspend_device(struct usb_device *dev, u32 state);
extern int usb_resume_device(struct usb_device *dev);
/* wrappers around usb_control_msg() for the most common standard requests */
extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
unsigned char descindex, void *buf, int size);
extern int usb_get_status(struct usb_device *dev,
int type, int target, void *data);
extern int usb_get_string(struct usb_device *dev,
unsigned short langid, unsigned char index, void *buf, int size);
extern int usb_string(struct usb_device *dev, int index,
char *buf, size_t size);
/* wrappers that also update important state inside usbcore */
extern int usb_clear_halt(struct usb_device *dev, int pipe);
extern int usb_reset_configuration(struct usb_device *dev);
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
timeouts, in seconds,被用来发送或接收控制信息。具有代表性的他们一般在他们被声明后几个帧后完成。Usb标识5秒为超时,或者在某些时候多一点
#define USB_CTRL_GET_TIMEOUT 5
#define USB_CTRL_SET_TIMEOUT 5
struct usb_sg_request 对分散/集中的I/O的支持
* @status:0代表正确,其他代表错误
* @bytes: 计算传输的比特
这些请求被usb_sg_init() 初始化,然后被用作请求操作传递给usb_sg_wait() or usb_sg_cancel()。大多数请求目标的成员不是给驱动程序作为入口
这个状态和比特数的值只在usb_sg_wait() 返回后有效。如果这status是零的话,那么bytecount就符合请求的总数。
在一个错误完成以后,驱动程序就能够在端点处清除一个暂停的情形
struct usb_sg_request {
int status;
size_t bytes;
一以下的成员对usb核私有不对外开放
spinlock_t lock;
struct usb_device *dev;
int pipe;
struct scatterlist *sg;
int nents;
int entries;
struct urb **urbs;
int count;
struct completion complete;
};
int usb_sg_init (
struct usb_sg_request *io,
struct usb_device *dev,
unsigned pipe,
unsigned period,
struct scatterlist *sg,
int nents,
size_t length,
int mem_flags
);
void usb_sg_cancel (struct usb_sg_request *io);
void usb_sg_wait (struct usb_sg_request *io);
/* -------------------------------------------------------------------------- */
称这个实体为管道是形象化的说法,一个usb管道就是把一些阻碍简单化,它基本具备一以下条件:
设备数字(7bit)
端点数字(4bit)
当前的Data0/1 的状态(1bit)在usb1.1时使用,现在没有了
方向(1bit)
速度(1bit)(历史的,在usb1.1时明确规定,现在没有了)
最大的包尺寸(2 bits: 8, 16, 32 or 64) 在usb1.1时使用,现在没有了
管道类型(2bit:控制,中断,块,同步)
那是18比特,实际上,没有更多。Usb开发人员把这18个bit作为”光荣“的数据结构
我们不要进入这个圈套,我们只要简单的认为他是一个unsigned int类型。它的编码就是
* - max size: bits 0-1 [Historical; now gone.]
* - direction: bit 7 (0 = Host-to-Device [Out],
* 1 = Device-to-Host [In] ...
* like endpoint bEndpointAddress)
* - device: bits 8-14 ... bit positions known to uhci-hcd
* - endpoint: bits 15-18 ... bit positions known to uhci-hcd
* - Data0/1: bit 19 [Historical; now gone. ]
* - lowspeed: bit 26 [Historical; now gone. ]
* - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt,
* 10 = control, 11 = bulk)
为什么呢?因为这是任意的,我们选择无论什么编码,多取决域我们自己。这个和那个UHCI规格有很多共享的比特,因此很多的UHCI驱动程序能够适当的掩盖比特位。
注:这些不是标准的USB_ENDPOINT_XFER_*值
#define PIPE_ISOCHRONOUS 0
#define PIPE_INTERRUPT 1
#define PIPE_CONTROL 2
#define PIPE_BULK 3
#define usb_maxpacket(dev, pipe, out) (out
? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)]
: (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )
#define usb_pipein(pipe) ((pipe) & USB_DIR_IN)
#define usb_pipeout(pipe) (!usb_pipein(pipe))
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT)
#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL)
#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK)
/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep)))
#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep)))
/* Endpoint halt control/status ... likewise USE WITH CAUTION */
端点暂停 控制和状态 和USE WITH CAUTION 相似
#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
{
return (dev->devnum << 8) | (endpoint << 15);
}
/* Create various pipes... */
#define usb_sndctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
#define usb_rcvctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
#define usb_rcvisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
#define usb_rcvbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
/* -------------------------------------
#ifdef DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "n" , __FILE__ , ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
#define err(format, arg...) printk(KERN_ERR "%s: " format "n" , __FILE__ , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "n" , __FILE__ , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "n" , __FILE__ , ## arg)
#endif /* __KERNEL__ */
#endif
查看linux驱动使用的头文件,[转载]linux下usb驱动头文件的usb.h(二)相关推荐
- Linux驱动开发常用头文件
头文件目录中总共有32个.h头文件.其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个.这些头文件各自的功能如下: 1.主目录 <a.out.h> ...
- linux打开core文件,[转载]linux下core文件设置与查看
程序异常推出时,内核会生成一个core文件(是内存映像以及调试信息).可以通过使用gdb来查看core文件,指示出导致程序出错的代码所在的文件和行数. 1.查看系统中core文件生成的开关是否打开 1 ...
- enc28j60 linux 驱动_enc28j60网卡驱动模块添加进Linux内核,Kconfig,Makefile配置过程...
这里是要把 http://www.linuxidc.com/Linux/2017-02/140819.htm 中的enc28j60网卡驱动模块,添加到2.6.22.6内核中,这个模块代码不需要任何修改 ...
- ac3165 linux驱动_一文读懂Linux系统启动流程
Linux启动管理 11.1 CentOS 6.x系统启动过程详解 CentOS 6.x系统启动过程发生了较大的变化,使用Upstart启动服务取代了原先的System V init启动服务.Upst ...
- Linux 驱动开发 四十八:Linux INPUT 子系统实验
一.input 子系统简介 input 就是输入的意思,因此 input 子系统就是管理输入的子系统,是 Linux 内核针对某一类设备而创建的框架. 比如按键输入.键盘.鼠标.触摸屏等等这些都属于输 ...
- Linux驱动视频教程推荐,隆重推荐:linux驱动基础开发系列免费教程独家版本
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 相信大家经常网上闲逛,会经常碰到很多的linux免费教程之类得,但是今天我推荐的这个linux驱动基础开发系列免费教程可不是网上可以随意找到得.废话少说: ...
- h3c linux驱动 wn612_H3C iNode智能客户端安装指导(Linux)-7.3-5PW102
如果系统中已经存在老版本的iNode客户端,需要先卸载老版本的客户端,然后再安装新版本的客户端. Linux iNode支持在主流的Linux操作系统中安装,比较常用的Linux操作系统包括: · ...
- Linux 驱动开发 四十六:Linux MISC驱动实验
misc 的意思是混合.杂项的,因此MISC 驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动. MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 p ...
- Linux 驱动开发 三十五:Linux 内核时钟管理
参考: linux时间管理,时钟中断,系统节拍_u010936265的博客-CSDN博客_系统节拍时钟中断 Linux内核时钟系统和定时器实现_anonymalias的专栏-CSDN博客_linux内 ...
- linux删除文件_【Linux实战】Vim编辑器和恢复ext4下误删除的文件
学神IT教育:XueGod-IT 良心教育 贴心服务 1. vim主要模式介绍,vim命令模式. 确保系统已经安装了VIM工具 [root@panda ~]# rpm -qf `which vim` ...
最新文章
- setFilters使用方法
- php html实例代码,PHP生成HTML静态页面实例代码
- Quartz 入门详解
- Jmeter测试Mysql数据库-入门篇
- sqlmap 进行sql漏洞注入
- ActionT 无参数委托详解
- 【初窥javascript奥秘之闭包】叶大侠病都好了,求不踩了:)
- [Javascript_库编写]创建自己的“JavaScript库”
- genymotion 极速模拟器
- python入门之字符串处理_Python基础之字符串操作,格式化。
- 网关Spring Cloud Gateway的配置和使用
- Emeditor 常用的正则表达式
- 兼容性所有浏览器的透明CSS设置
- 视频转换器如何将腾讯QLV格式转换成MP4视频文件
- 韩版S8/NOTE8/S9原版固件8.0 破解VOLTE设置密码
- 一元云购qq互联回调地址错误解决办法
- HDU 6441 Find Integer 费马大定理
- 作为面试官的一点心得
- python画太极图
- Atcoder F - Mirrored(思维+搜索)
热门文章
- Unity2D-Dash SpeedUp
- span标签限制显示的字数长度
- 在游标中如何实现Select * from AAA where BB in XXX
- 网鱼网咖-利用数加快速搭建大数据平台,极致洞察,为客户带来从所未有的体验。
- Openfire加Smack实现IM
- 查询比本部门平均工资高的员工信息
- 2021年上半年健身总结
- 论文解读:《Learning Linear Transformations for Fast Image and Video Style Transfer》,CVPR 2019
- swift-类结构源码探寻(一)
- 初级会计实务--第四章第二节、资本公积