📄 usb-func.c
字号:
#include <linux/module.h>
#include <linux/socket.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
#include "define.h"
#include "go7007drv.h"
/* Debug status */
static int debug = 0;
/* Redefine debug macro */
#undef dbg
#define dbg(format, arg...) \
do { if (debug) printk(KERN_DEBUG __FILE__ ": [" __FUNCTION__ "] " \
format "\n" , ## arg); \
} while (0)
#undef err
#define err(format, arg...) printk(KERN_ERR __FILE__ ": [" __FUNCTION__ "] " \
format "\n" , ## arg)
/* Version Information */
#define DRIVER_VERSION "v0.4"
#define DRIVER_DESC "USB Skeleton Driver"
/* basic usb pipe function */
#define STREAM_PIPE 1
#define CONTROL_PIPE 2
#define DOWNLOAD_PIPE 3
#define INTERRUPT_PIPE 4
#define USB_TIMEOUT 5 // second
/*
* Devices information
*/
#define USB_GO_MAJOR 240
#define USB_GO_MINOR_BASE 0
#define MAX_DEVICES 256
#define GODEV_MINOR(busnum, devnum) \
((((busnum-1) & 7)*32) + ((devnum-1) & 31))
/* Device array and mutex */
static usb_t *usb_dev_table[MAX_DEVICES];
static DECLARE_MUTEX (usb_dev_table_mutex);
static int buffers = 256;
//char tmpCMD_PACKET[72];
/* Local purpose */
#define IOCTL_GO_COMMAND _IOWR('W', 0x80, CMD_PACKET)
//#define IOCTL_GO_COMMAND _IOWR('W', 0X80, tmpCMD_PACKET)
/*
static struct
{
short allow_irq;
unsigned short ready;
unsigned short retval;
unsigned short retdata;
} rd_irq_data;
*/
/* static void interrupt_pipe_complete(purb_t purb); */
/*
* Begin of basic usb pipe function
*/
/* Stream buffer */
DECLARE_WAIT_QUEUE_HEAD(stream_pipe_wq);
static void read_stream_submit(pusb_t s);
void stream_pipe_complete(purb_t purb)
{
pusb_t s = (pusb_t) purb->context;
dbg("Usb transfer complete");
if(s->StreamThreadState) {
#if 0
StreamBuffer_AddBlock(&(s->StreamBuffer),
s->bulk_in_buffer,
BULK_IN_BUFSIZE);
read_stream_submit(s);
#else
tasklet_schedule(&(s->bh));
#endif
// read_stream_submit(s);
// err("stream pipe complete");
}
else {
wake_up(&(s->wq_stop_stream_thread));
}
}
int ReadStreamPipe(pusb_t s, unsigned char *pbuf, int len)
{
int pipe;
purb_t purb = NULL;
int r=0;
pipe = usb_rcvbulkpipe(s->usbdev, STREAM_PIPE);
purb = s->bulkin_urb;
s->stream_in_ready = 0;
FILL_BULK_URB(purb, s->usbdev, pipe, pbuf, len, stream_pipe_complete, s);
usb_submit_urb(purb);
// r = sleep_on_timeout(&s->wq_stream_pipe, USB_TIMEOUT*HZ);
while(!s->stream_in_ready)
r = sleep_on_timeout(&stream_pipe_wq, USB_TIMEOUT*HZ);
return r;
}
static void read_stream_submit(pusb_t s)
{
int pipe;
purb_t purb = NULL;
unsigned char *pbuf;
pipe = usb_rcvbulkpipe(s->usbdev, STREAM_PIPE);
purb = s->bulkin_urb;
pbuf = s->bulk_in_buffer;
FILL_BULK_URB(purb, s->usbdev, pipe, pbuf, BULK_IN_BUFSIZE, stream_pipe_complete, s);
usb_submit_urb(purb);
}
static void read_stream_bh(unsigned long data)
{
pusb_t s = (pusb_t) data;
StreamBuffer_AddBlock(&(s->StreamBuffer),
s->bulk_in_buffer, BULK_IN_BUFSIZE);
read_stream_submit(s);
}
void begin_stream_input(pusb_t s)
{
read_stream_submit(s);
}
/// init buffer
// DECLARE_WAIT_QUEUE_HEAD(download_pipe_wq);
void download_pipe_complete(purb_t purb)
{
pusb_t s = (pusb_t) purb->context;
dbg("Usb transfer complete");
wake_up(&s->wq_download_pipe);
}
int DownloadBuffer(pusb_t s, unsigned char *pbuf, int len)
{
int pipe;
purb_t purb = NULL;
int r;
pipe = usb_sndbulkpipe(s->usbdev, DOWNLOAD_PIPE);
purb = usb_alloc_urb(0);
dbg("download pipe : %x",pipe);
dbg("bulk size / max bulk out size : %d / %d",
len, s->bulk_out_size);
{
unsigned char *trans_buf;
trans_buf = kmalloc(len, GFP_KERNEL | __GFP_DMA);
copy_from_user(trans_buf, pbuf, len);
FILL_BULK_URB_TO(purb, s->usbdev, pipe, trans_buf, len,
download_pipe_complete, s, 500);
purb->transfer_flags |= USB_QUEUE_BULK;
r = usb_submit_urb(purb);
if(r)
dbg("usb_submit_urb error: %d", r);
r = sleep_on_timeout(&s->wq_download_pipe, USB_TIMEOUT*HZ);
if(!r)
{
dbg("download timeout : %d",r);
}
dbg("download return: %d", r);
kfree(trans_buf);
}
usb_unlink_urb(purb);
usb_free_urb(purb);
return r;
}
//// read interrupt
// DECLARE_WAIT_QUEUE_HEAD(interrupt_pipe_wq);
void interrupt_pipe_complete(purb_t purb)
{
pusb_t s;
s = (pusb_t) purb->context;
if(!s->rd_irq_data.allow_irq)
{
dbg("IRQ is not allowed!");
return;
}
dbg("USB interrupt complete: status = %d", purb->status);
s->rd_irq_data.ready = 1;
memcpy(&(s->rd_irq_data.retdata), purb->transfer_buffer, 2);
memcpy(&(s->rd_irq_data.retval), purb->transfer_buffer+2, 2);
dbg("rd_irq_data.ready = %d", s->rd_irq_data.ready);
wake_up(&s->wq_interrupt_pipe);
}
int ReadInterruptPipe(pusb_t s, unsigned short *pIntRetVal, unsigned short *pIntRetData)
{
int r;
int cnt;
dbg("Enter");
cnt = 0;
while(!s->rd_irq_data.ready)
{
r = sleep_on_timeout(&s->wq_interrupt_pipe, 0.1*HZ);
cnt++;
if(cnt > 10) break;
}
dbg("irq_data: 0x%04X, 0x%04X, 0x%04X",
s->rd_irq_data.ready,
s->rd_irq_data.retdata,
s->rd_irq_data.retval);
if(s->rd_irq_data.ready)
{
*pIntRetData = s->rd_irq_data.retdata;
*pIntRetVal = s->rd_irq_data.retval;
s->rd_irq_data.ready = 0;
r = 1;
}
else
{
r = 0;
}
dbg("interrupt sleep return : %d, val : %04x, data : %04x", r, *pIntRetVal, *pIntRetData);
dbg("Leave");
return r;
}
//// write interrupt through control pipe
// DECLARE_WAIT_QUEUE_HEAD(control_pipe_wq);
void control_pipe_complete(purb_t purb)
{
pusb_t s = (pusb_t) purb->context;
dbg("Usb control complete");
wake_up(&s->wq_control_pipe);
}
int WriteInterrupt(pusb_t s, unsigned short Addr, unsigned short Data)
{
int pipe;
purb_t purb = NULL;
int r;
unsigned short *transbuf;
unsigned char *setuppacket;
transbuf=kmalloc(8,GFP_KERNEL);
setuppacket=kmalloc(8,GFP_KERNEL);
transbuf[0] = Data;
transbuf[1] = Addr;
transbuf[2] = 0;
transbuf[3] = 0;
setuppacket[0] = 0x42;
setuppacket[1] = 0x00;
setuppacket[2] = 0xaa;
setuppacket[3] = 0x55;
setuppacket[4] = 0xf0;
setuppacket[5] = 0xf0;
setuppacket[6] = 0x08;
setuppacket[7] = 0x00;
pipe = usb_sndctrlpipe(s->usbdev, CONTROL_PIPE);
dbg("control pipe : %x",pipe);
purb = usb_alloc_urb(0);
FILL_CONTROL_URB_TO(purb, s->usbdev, pipe, setuppacket, transbuf, 8,
control_pipe_complete, s, 100);
usb_submit_urb(purb);
r = sleep_on_timeout(&s->wq_control_pipe, USB_TIMEOUT*HZ);
kfree(transbuf);
kfree(setuppacket);
dbg("control sleep return : %d",r);
usb_unlink_urb(purb);
dbg("WriteInterrupt: free urb");
usb_free_urb(purb);
return r;
}
// end of basic usb pipe function
/*
* Driver interface
*/
static inline void go_delete(usb_t *s)
{
usb_dev_table[s->minor] = NULL;
if(s->irq_buf != NULL)
kfree(s->irq_buf);
kfree(s);
}
static ssize_t go_read (struct file *file, char *buf, size_t count, loff_t * ppos)
{
pusb_t s;
int rv;
int FrameSize = count;
dbg("Enter");
s = (pusb_t) file->private_data;
/* Get data from stream buffer */
rv = StreamBuffer_GetFrame(&(s->StreamBuffer), buf, &FrameSize);
if(rv == 0)
rv = FrameSize;
else
rv = 0;
dbg("Leave");
return rv;
}
static ssize_t go_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
{
pusb_t s;
int rv;
dbg("Enter");
err("go_write %d %d", buf[0], count);
s = (pusb_t) file->private_data;
/* Process writing */
if(OnWriteProc(s,buf)==0)
rv = count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -