?? usersu.c
字號:
/* * usu.c * * Author : Lionetti Salvatore <salvatorelionetti@yahoo.it> * License: GPL * * "Usb in User Space" driver try to hide usb work, exposing simple object like file with only one reader/writer. * Have different struct for different behavior: * - isoc: reduce work during complete(), preallocating n urb, just switch between urb, * start input endpoint when were data requested. * - other: BuffReadT, organize data in ram area. * start input endpoint on probe * Now is !supported more interface of same type. * File exposed are sequential, with no lseek()/ppos. * * Interrupt(0x81) & Command(0x00) endpoint are linked in only one entity (now name='intr'). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include<linux/module.h>#include<linux/kernel.h> /* Added in 2.6.15.*/#include<linux/usb.h>#include<linux/timer.h>#include<linux/proc_fs.h>#include<linux/slab.h> /* To have SLAB_ATOMIC. */#include<asm/uaccess.h> /* copy_from_user(). */#include<linux/delay.h> /* mdelay(msec). *//*#include<linux/sched.h> * sched_clock(). Link !found.*//*#include<asm/spinlock.h> * spin_lock*(). Have redefinition error.*/#include<asm/semaphore.h> /* semaphore. */#include"msgq.h" /* dataQ_T */#include"urbAsByteStream.h" /* urbDataT. */#include"diag.h"#include"util.h" /* PRINT(), Snprintf() *//* One can choice /proc or /dev */#include"usu_config.h" /* Now only select underlyng fs.*/MODULE_LICENSE("GPL");int commandEcho=0;#define ISOC_URBSPRE 3#define ISOC_BYTESxP 17#define ISOC_NUMBOfP 3#define DATAQ_NUMOFB 5000/* * ==========START=========== * === Usb driver === * ========================== */static struct LinkT topol[]={ {{0x00, 6}}, /* Never pass under our probe() because already created.*/ {{0x81, 6}}, {{0x02, 7}}, {{0x82, 7}}, {{0x03, 10}}, {{0x83, 10}},};struct usb_device_id idta[] = { {USB_DEVICE(0x50d,0x012)}, /* Belkin.*/ {USB_DEVICE(0xa12,0x001)}, /* Surecom.*/ {USB_DEVICE(1131,1001)}, /* Sitel.*//* {USB_DEVICE(0xea0,0x2168)}, * UsbPen.*/ {}};/* * ===========END============ * === Usb driver === * ========================== */static void* blocks[]={ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 0..9 BuffRead.*/ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,}; /* 10..19 DoubleBuff.*//* Utility function.*/char* usb_getTypeStr(int addr) { int type = (addr & USB_ENDPOINT_XFERTYPE_MASK); char* typeStr[] = {"ctrl","isoc","bulk","intr","unkn"}; if (type<0 && type>3) type = 4; return typeStr[type];}char* usb_getDirStr(int addr) { int diri = (addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; return (diri?"ing":"usc");}int USBDo_send(struct usb_device* dev, char dest, unsigned char* data, int len);int USBDo_dumpUrb(struct urb *urb,char* buf,int len);static struct usb_device* dev=NULL;static int nurb_submitted = 0;static int stop_submit = 0;static int log = 0;/* Some common code.*/#define KMALLOC_FLAG GFP_ATOMIC/* procfs * blocks[l]->data (void*) * ->name * ->read_proc * ->write_proc * ->owner */ typedef int (*usbdo_fsProcT)(char *buf, unsigned int len, void *data);typedef struct _FsEntryT { void* data; char name[100]; usbdo_fsProcT read_proc; usbdo_fsProcT write_proc; int isOpen; /* 1 when file is opened.*/} FsEntryT;FsEntryT usbdo_fsEntry[16];static int usbdo_nofFiles=0;#ifdef USE_PROC_FSstatic struct file_operations usbdo_fsOps;static struct proc_dir_entry* usbdo_fs=NULL;static FsEntryT* usbdo_createFile(int bmAttr) { FsEntryT* data; struct proc_dir_entry* pe; char* nome; data = NULL; pe = NULL; nome = NULL; PRINT("Creating procfs..."); nome = usb_getTypeStr(bmAttr); if (!usbdo_fs) usbdo_fs = proc_mkdir("USBDo",NULL); if (usbdo_fs) pe = create_proc_entry(nome,0666,usbdo_fs); if (pe) { pe->proc_fops = &usbdo_fsOps; /* pe->read_proc = ProcFsRead; pe->write_proc = ProcFsWrite; NULL as default.*/ pe->owner = THIS_MODULE; pe->data = (void*)usbdo_nofFiles; data = &usbdo_fsEntry[usbdo_nofFiles]; strncpy(data->name, nome, 100); usbdo_nofFiles++; } return data;}static void usbdo_deleteFile(int bmAttr) { char* nome = NULL; PRINT("Deleting procfs..."); nome = usb_getTypeStr(bmAttr); remove_proc_entry(nome,usbdo_fs); usbdo_nofFiles--; if (usbdo_nofFiles==0) { PRINT("Removing /proc/USBDo"); remove_proc_entry("USBDo",NULL); usbdo_fs = NULL; }}#if 0int ProcFsRead( char* page, char** start, off_t off, int count, int *eof, void* data){ int ritorno = usbdo_fsEntry[(int)data].read_proc(page,count,usbdo_fsEntry[(int)data].data); if (ritorno<0) *eof=1; else *start=(char*)ritorno; return ritorno;}int ProcFsWrite( struct file *file, const char *buffer, unsigned long count, void *data){ return usbdo_fsEntry[(int)data].write_proc(buffer,count,usbdo_fsEntry[(int)data].data);}#endifstatic ssize_t ProcFsRead(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos){ struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry * pe; int ritorno; pe = PDE(inode); ritorno = usbdo_fsEntry[(int)pe->data].read_proc(buf,nbytes,usbdo_fsEntry[(int)pe->data].data); if (log) PRINT("ProcFsRead(%d)=%d",nbytes,ritorno); return ritorno;}static ssize_t ProcFsWrite(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){ struct inode *inode = file->f_dentry->d_inode; struct proc_dir_entry * pe; int ritorno; pe = PDE(inode); ritorno = usbdo_fsEntry[(int)pe->data].write_proc((char*)buffer,count,usbdo_fsEntry[(int)pe->data].data); if (log) PRINT("ProcFsWrite(%d)=%d",count,ritorno); return ritorno;}static struct file_operations usbdo_fsOps = { .read = ProcFsRead, .write = ProcFsWrite,};#else#include <linux/devfs_fs_kernel.h>#define USU_CHARFS_MAJOR 238static struct file_operations usbdo_fsOps;static FsEntryT* usbdo_createFile(int bmAttr) { FsEntryT* data; char* nome; int ret = -EBUSY; data=&usbdo_fsEntry[usbdo_nofFiles]; nome = NULL; if (usbdo_nofFiles==0) { ret = register_chrdev(238,"usu",&usbdo_fsOps); if (ret==0) ret = devfs_mk_dir("usu"); } if (ret == 0) { PRINT("Creating fsentry..."); nome = usb_getTypeStr(bmAttr); strncpy(data->name, nome, 100); /* Select from usb pipe -> minor. * 0 0 * 1 2 * 2 1 * 3 0 */ usbdo_nofFiles++; } return data;}static void usbdo_deleteFile(int bmAttr) { PRINT("Deleting fsentry..."); usbdo_nofFiles--; if (usbdo_nofFiles==0) { PRINT("Removing /dev/"); devfs_remove("usu"); unregister_chrdev(238, "usu"); }}static int CharFsOpen(struct inode *inode, struct file *file){ PRINT("open(inode 0x%p, file 0x%p) priv(%p)",inode,file,file->private_data); if (file->private_data==NULL) { file->private_data = (void*) MINOR(inode->i_rdev); PRINT("->(%p)",file->private_data); } PRINT(" (maj,min)=(%d,%d)",MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); PRINT("\n"); return 0;}static int CharFsRelease(struct inode *inode, struct file *file){ PRINT("close(inode 0x%p, file 0x%p) priv(%p)",inode,file,file->private_data); if (file->private_data) { file->private_data = (void*) 0; PRINT("->(%p)",file->private_data); } PRINT(" (maj,min)=(%d,%d)",MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); PRINT("\n"); return 0;}static ssize_t CharFsRead(struct file *file, char __user *buffer, size_t count, loff_t *ppos){ int minor = (int) file->private_data; return usbdo_fsEntry[minor].read_proc(buffer,count,usbdo_fsEntry[minor].data);}static ssize_t CharFsWrite(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){ int minor = (int) file->private_data; return usbdo_fsEntry[minor].write_proc((char*)buffer,count,usbdo_fsEntry[minor].data);}static struct file_operations usbdo_fsOps={ .owner = THIS_MODULE, .open = CharFsOpen, .read = CharFsRead, .write = CharFsWrite, .release = CharFsRelease,};#endifstruct BuffReadT { struct dataQ_T dq; atomic_t mutuaEsclusione;};int BuffRead_read(char* page, unsigned int count, void* data){ int ritorno=0; int whoR=0/*(int)data*/; struct BuffReadT *br=(struct BuffReadT*)data; if (count>0) ritorno=readQ(&(br->dq),whoR,page,count); if (log) PRINT("readQ(count=%d,spare=%d)=%d",count,br->dq.spar[whoR],ritorno); if (ritorno<0) err("readBulk(): ret %d.",ritorno); return ritorno;}/* From /kernel/sched.c: to show stack free space. This is a local symbolvoid show_state() {}*/int BuffRead_write(char *buffer, unsigned int count, void *data){ int ritorno; struct BuffReadT* br=(struct BuffReadT*)data; char* kdata; ritorno = -ENOMEM; kdata=kzalloc(count,KMALLOC_FLAG); if (kdata) { ritorno = -EFAULT; if (copy_from_user(kdata,buffer,count)==0) { char cmd = kdata[0]; if (cmd=='q') { char buf[3000]; int len=2900; dumpQ(&(br->dq),buf,len); /*show_state();*/ buf[len]='\x0'; PRINT("%s",buf); log = (log + 1) % 2; PRINT("log %s.",log?"enabled":"disabled"); } else if (cmd=='r') { reseQ(&(br->dq)); } else if (cmd=='t') { testUrbD(); } else if (cmd=='Q') { testQ(); } else { int l; char dest; FsEntryT* pe; struct urb* urb; pe = NULL; dest = 'u' /* unkn */; urb = (struct urb*) br->dq.context; if (commandEcho) writeQ(&(br->dq),kdata,count); for (l=0; l<sizeof(blocks)/sizeof(blocks[0]); l++) { pe = blocks[l]; if (pe && pe->data == (void*) br) { dest = usb_getTypeStr(pipe2addr(urb->pipe))[0]; } } ritorno=USBDo_send(dev,dest,kdata,count); } } kfree(kdata); } return ritorno; }void BuffRead_complete(struct urb *ingr_urb,struct pt_regs* regs) { int ritorno=ingr_urb->status; struct BuffReadT* br=(struct BuffReadT*)ingr_urb->context; char buf[160]; int len=150; int addr = pipe2addr(ingr_urb->pipe); char* dire = usb_getDirStr(addr); char* tipo = usb_getTypeStr(addr); nurb_submitted--; /* * So if any error, but some data, however remember bytes. * return error ?. */ if (log) PRINT("%s %s!",dire,tipo); if (ritorno==0 && dire[0]=='i' && ingr_urb->actual_length>0) { ritorno = writeQ(&(br->dq), ingr_urb->transfer_buffer, ingr_urb->actual_length); if (log) PRINT("writeQ()=%d",ritorno); } if (log) { USBDo_dumpUrb(ingr_urb,buf,len); buf[len]='\x0'; PRINT("%s",buf); } /* For kernel 2.4 is !necessary.*/ if (dire[0]=='i' && !stop_submit) { ingr_urb->dev=dev; ingr_urb->status=0; ritorno=usb_submit_urb(ingr_urb, KMALLOC_FLAG); if (ritorno==0) nurb_submitted++; if (log) PRINT("(resubmit res=%d)",ritorno); }}static int BuffRead_probe(int blockId, struct usb_endpoint_descriptor* endpoint) { int ritorno = 0; /* 3-1) Create object if !already.*/ if (blocks[blockId]==NULL) { FsEntryT* data; struct BuffReadT *br; char *buf; buf = NULL; br = NULL; data = usbdo_createFile(endpoint->bmAttributes); if (data) br = kzalloc(sizeof(*br) ,KMALLOC_FLAG); if (br) buf = kzalloc(DATAQ_NUMOFB ,KMALLOC_FLAG); if (data) data->data = (void*) br; if (br) { initQ(&(br->dq),buf,DATAQ_NUMOFB); br->dq.wrSrc = KERN; atomic_set(&(br->mutuaEsclusione),1); } if (data) { data->read_proc = BuffRead_read; data->write_proc = BuffRead_write; /*data->owner = THIS_MODULE;*/ } blocks[blockId] = /*ritorno?NULL:*/(void*) data; if (data==NULL) ritorno=-ENOENT; else if (buf==NULL) ritorno=-ENOMEM; PRINT("%s",ritorno?"NOOK!!!":"OK"); } /* 3-2) Start input endpoint (only for !isoc transfer).*/ if (ritorno==0) if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)==USB_DIR_IN) { FsEntryT* data; struct urb *urb; int pipe; char* bf; int size;/* dma_addr_t dma;*/ urb = NULL; bf = NULL; size=0; data = (FsEntryT*) blocks[blockId]; PRINT("Allocating&start input urb..."); urb = usb_alloc_urb(0, KMALLOC_FLAG); ((struct BuffReadT*)(data->data))->dq.context = (void*) urb; if (urb) { size = le16_to_cpu(endpoint->wMaxPacketSize); bf = kzalloc(size,KMALLOC_FLAG);/*usb_buffer_alloc(dev,size,GFP_KERNEL*SLAB_ATOMIC*,&dma);*/ } if (urb==NULL || bf==NULL) ritorno = -ENOMEM; if (ritorno==0) { switch (endpoint->bmAttributes){ /* case USB_ENDPOINT_XFER_CONTROL: { pipe=usb_rcvintpipe(dev,endpoint->bEndpointAddress); break; }*/ case USB_ENDPOINT_XFER_INT: { pipe=usb_rcvintpipe(dev,endpoint->bEndpointAddress); usb_fill_int_urb(urb,dev,pipe,bf,size,BuffRead_complete,NULL,endpoint->bInterval); break; } case USB_ENDPOINT_XFER_BULK: { pipe=usb_rcvbulkpipe(dev,endpoint->bEndpointAddress); usb_fill_bulk_urb(urb,dev,pipe,bf,size,BuffRead_complete,NULL); break; } default: break; } urb->context = data->data;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -