USBMon - a demonstration of prototype USB monitoring by the Linux kernel.


Sorry for the long post - if this is inappropriate for the group please
tell me off, any followups that don't relate to wider USB development concerns
should probably just be mailed to me.


Who am I and what am I doing?

        I am an undergraduate doing a final year project on the monitoring of
USB in Linux. I have spent a load of time understanding how USB is handled
by Linux and thinking about methods to access and analyse some of the data
generated by this process from user applications. I have created a prototype
implementation of these ideas that take the form of a kernel patch and (in
a short period of time) a GUI application that presents the data nicely.

        The reason I am posting to this mailing list is to ask for the
opinions of those far more qualified than myself on my assumptions,
designs, and code. Specifically, I am after advice on my kernel code, an
area I know little about. I fully recognise that I am not very experienced
in this level of design or coding so any constructive comments are more
than welcome. All useful comments will be credited in any work I submit to
anyone for accademic appraisal (if your really really worried you can cc
my supervisor - [EMAIL PROTECTED]).

        If the code is any use to anyone, feel free to play with it for your own
use. I will bung it up on a website with a proper GPL release as soon as I hand
in my dissertation but for now this is just a 'circulation of ideas'.

Why?

There are a number of reasons to know what is happening with the USB on a
system. Most obviously is usage and load monitoring, along the lines of
useful tools like top, vmstat, and netstat. It is my contention that at
the moment the
Linux USB system is somewhat secretive about what it is doing and when. There is
a reasonable argument that this should be handled by individual drivers,
however I disagree and see a host-controller as an individual system
resource which the system admin. should be able to monitor.

There is also the issue of Driver development. It can be very useful to
know exactly what is being sent to and from a working (or not working)
driver. Not all driver developer's can afford expensive hardware
development boards. To this end my solution aims to allow full monitoring
of the data being sent to and from a device.

General Design:

        I have concluded that the only really sensible place to monitor
USB traffic as a whole is in the USB core. The host controller driver is
too implementation specific and the individual drivers too diverse to
modify. So I have made modifications (hacks) to parts of the USB core in
order to facilitate monitoring. Unfortunately I soon discovered that I
did need to add a few (<10) lines to each of the host controller drivers
but hey..

        Due to the bandwidth of USB monitoring has to be configurable. My
design allows different levels of monitoring on an endpoint by endpoint
basis. These levels of monitoring would include No monitoring, URB header
reproting, and full data monitoring.

        The interface for the monitoring is what has taken the most time.
My eventual decision was to add to the /proc usbdevfs. There is already a
'file' generated to allow user mode device drivers to work. I have added
in a second file for each device. For example device 002 on bus 1 would
have the existing file /proc/bus/usb/001/002 and the monitoring file
/proc/bus/usb/001/002M. The monitored data is pushed out to user-land via
this file and changes is monitoring configuration (changing the level of
monitoring on different endpoints) is recieved vis input to this file. So
writing a 4-char command to this file can set the monitoring level on one
of its endpoints.

        The URB data is monitored just before the user defined completion
call is made from within the Host Controller driver. At the moment it is
just copied into a new URB structure, but a more suitable container may be
required, with features like timestamping in it.


Unfinished things:

 - No data monitoring yet.
 - No MUTEX locking, I can't see a problem but that doesn't mean there
   isn't one, I will need to prove some things in my head.
 - No nice front end application yet.


List of Bad things I have done:

 - changed the usb_device struct
 - stuck all my code at the bottom of devio.c - but it is a prototype
 - meddled with the host controller driver interface by adding in a new
 call before every call-back call that monitors the URB.
 - Done some frankly very ugly coding.
 - Lots else, I'm sure you'll tell me.


 Where can You find the code?

 Included with this mail is the kernel patch. You can also download it
from my  website - www.dcs.ed.ac.uk/~dxh/public/USB/, also included is a
couple of very simple scripts to play with it. Hopefully self-explanatory.

 The patch is against 2.4.1, judging by a lot of the traffic on this group
that is probably not nearly current enough for most of you, I know the patch
applies cleanly to 2.4.2 but I have not been able to test it on >2.4.1

 The patch will not work when using the uhci driver, only usb-uhci. I
have patched usb-ohci as well but this is completely untested.

 Some very simple example command line tools that make use of it are
 available from my website at http://www.dcs.ed.ac.uk/~dxh/public/USB/

 All my code comes with a major health warning - it is very experimental
and don't come crying to me if it dos nasty things, though do please tell me.


 Thanks to anyone who has read this far.

 Dave.

--
Dave Harding - [EMAIL PROTECTED]
http://www.dcs.ed.ac.uk/~dxh/
diff -urN -X exclusions linux/drivers/usb/devio.c linux-2.4.1-dev/drivers/usb/devio.c
--- linux/drivers/usb/devio.c   Thu Mar 15 22:46:20 2001
+++ linux-2.4.1-dev/drivers/usb/devio.c Fri Mar 16 15:57:53 2001
@@ -57,6 +57,7 @@
 
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
+       printk("usbdev_lseek called.\n");
        switch (orig) {
        case 0:
                file->f_pos = offset;
@@ -1214,3 +1215,374 @@
        open:           usbdev_open,
        release:        usbdev_release,
 };
+
+
+/*************************** USBMon Addition *********************************/
+
+
+static int usbmon_open(struct inode *inode, struct file *file)
+{
+       struct usb_device *dev;
+       int ret;
+
+       /*printk("[USBMon] usbmon_open called with inode=&%X\n",inode);*/
+       
+       lock_kernel();
+       ret = -ENOENT;
+       if (ITYPE(inode->i_ino) != IDEVICEMON)
+               goto out;
+       dev = inode->u.usbdev_i.p.dev;
+       if (!dev)
+               goto out;
+       
+       ret = 0;
+       
+       dev->USBMon_data->USBMon_urb_ll_buffered = 
+                                       dev->USBMon_data->USBMon_urb_ll_head;
+       wmb();
+       dev->USBMon_data->USBMon_urb_ll_head = NULL;
+       wmb();
+       dev->USBMon_data->USBMon_urb_ll_last = NULL;
+       wmb();
+       
+       file->private_data = dev;
+ out:
+       unlock_kernel();
+        return ret;
+}
+
+static int usbmon_release(struct inode *inode, struct file *file)
+{
+       urb_t *temp_urb1, *temp_urb2;
+       struct usb_device *dev;
+       
+       dev = (struct usb_device *)(file->private_data);
+       
+       temp_urb1=dev->USBMon_data->USBMon_urb_ll_buffered;
+
+       wmb(); 
+
+       dev->USBMon_data->USBMon_urb_ll_buffered=NULL;
+
+       
+       while(temp_urb1 != NULL){
+               temp_urb2 = temp_urb1;
+               if(temp_urb1->transfer_buffer){
+                       kfree(temp_urb1->transfer_buffer);
+               }
+               temp_urb1=temp_urb1->next;
+               kfree(temp_urb2);
+       }
+        return 0;
+}
+
+static ssize_t usbmon_read(struct file *file, char * buf, size_t nbytes, loff_t 
+*ppos)
+{
+       ssize_t ret = 0;
+       unsigned int len=0;
+       unsigned int already_copied=0;
+       unsigned int skipped=0;
+       int i;
+       loff_t pos;
+       char a[255];
+       struct usb_device *dev;
+       urb_t *purb;
+       int finished=0;
+
+       pos = *ppos;
+       
+       if (!file->private_data) {
+               ret = -ENODEV;
+               goto err;
+       } else if (pos < 0) {
+               ret = -EINVAL;
+               goto err;
+       }
+       
+       dev=(struct usb_device *)file->private_data;
+       
+       /*printk("[USBMon] read on device %d, buffered=%8X\n",
+               dev->devnum,
+               dev->USBMon_data->USBMon_urb_ll_buffered);
+       */
+       
+       purb = dev->USBMon_data->USBMon_urb_ll_buffered;
+       
+       if(purb == NULL){
+               finished=1;
+       }
+       while(finished == 0){
+               /*if(purb->dev==NULL){
+                       printk("[USBMon] AHHHHG - NULL dev ptr, skipping\n");
+                       purb=purb->next;
+                       if(purb==NULL){
+                               finished=1;
+                       }
+               }else*/{ 
+                       sprintf(a,"[URB completed on Device %3d, Endpoint %d, "
+                                 "Pipe = %8X, "
+                                 "status = %d, size = %d, transfer flags = %8X"
+                                 ", actual length = %d, error count = %d]\n",
+                               purb->dev->devnum,
+                               (purb->pipe & (0xf <<15))>>15,
+                               purb->pipe,
+                               purb->status,
+                               purb->transfer_buffer_length,
+                               purb->transfer_flags,
+                               purb->actual_length,
+                               purb->error_count);
+                       /*printk(a);*/
+                       if (pos+already_copied < (strlen(a)+skipped)) {
+                               len = (strlen(a)+skipped)-(pos+already_copied);
+                               if ((len+already_copied) >= nbytes){
+                                       len = nbytes-already_copied;
+                                       finished=1;
+                               }
+                               /*printk("sending %d bytes to user.\n",len);*/
+                               for(i=0;i<len;i++){
+                                      put_user(a[pos+already_copied-skipped+i],
+                                               buf+already_copied+i);
+                               }       
+                               already_copied += len;
+
+                       }else{
+                               skipped += strlen(a);
+                               purb = purb->next;
+                               if(purb == NULL){
+                                       finished=1;
+                               }
+                       }
+               }
+       }
+
+       *ppos += already_copied;
+       buf += already_copied;
+       nbytes -= already_copied;
+       ret = already_copied;
+       
+err:
+       return ret;
+}
+
+
+static ssize_t usbmon_write(struct file *file, char * buf, size_t nbytes, loff_t 
+*ppos)
+{
+
+       ssize_t ret = 0;
+       struct usbmon_endpoint_ll *new_endpoint;
+       loff_t pos;
+       char a[255];
+       struct usb_device *dev;
+       int i=0;
+
+       pos = *ppos;
+       
+       if (pos < 0) {
+               ret = -EINVAL;
+               goto err;
+       }
+       
+       dev=(struct usb_device *)file->private_data;
+       
+       /*printk("[USBMon] write on device %d, nbytes=%d\n",
+               dev->devnum, nbytes);
+       */
+       
+       if((nbytes) > 4){
+               printk("[USBMon] Warning - trying to write more than 4 
+bytes.pos=%d,nbytes=%d ... continuing\n",(int)pos,(int)nbytes);
+               /*ret=-EINVAL;
+               goto err;*/
+       }
+       if((nbytes) < 4){
+               printk("[USBMon] Warning - trying to write less than 4 
+bytes.pos=%d,nbytes=%d ... ignoring\n",(int)pos,(int)nbytes);
+               ret=-EINVAL;
+               goto err;
+       }
+       
+       for(i=0; i<4 && i<nbytes; i++){
+               get_user(a[i],buf+i);
+       }               
+
+       ret=i;
+       if((a[0] == 'E') &&
+          (a[2] == 'L')){
+               struct usbmon_endpoint_ll *tmp_ep, *tmp_ep_last;   
+               int found=0;
+               int tmp1;
+               
+               tmp1 = a[1];
+               
+               /*check to see if ep already exists*/
+               
+               tmp_ep = dev->USBMon_data->USBMon_monitored_endpoints;
+               tmp_ep_last=NULL;
+               while(tmp_ep != NULL){
+                       /*printk("[USBMon] checking ep=%8X\n",tmp_ep->value);*/
+                       if(tmp_ep->value==((dev->devnum << 8) | (tmp1 << 15))){
+                               if(a[3]==0){ /*remove it*/
+                                       printk("[USBMon]removing monitored endpoint. 
+device=%d",dev->devnum);
+                                       if(tmp_ep_last==NULL){
+                                               dev->USBMon_data->
+                                                    USBMon_monitored_endpoints=
+                                                                tmp_ep->next;
+                                       }else{
+                                               tmp_ep_last->next=tmp_ep->next;
+                                       }
+                                       kfree(tmp_ep);
+                               }else{
+                                       tmp_ep->level=a[3];
+                               }
+                               tmp_ep=NULL;
+                               found=1;
+                       }else{
+                               tmp_ep_last=tmp_ep;
+                               tmp_ep=tmp_ep->next;
+                       }
+               }
+               
+               if(!found){ /* ep doesn't already exist */
+                       new_endpoint = kmalloc(sizeof(struct    
+                                                   usbmon_endpoint_ll),
+                                                               GFP_KERNEL);
+                                               
+                       if(new_endpoint != NULL){
+
+                               new_endpoint->value =  ((dev->devnum << 8) | 
+                                                       (tmp1 << 15));
+                               printk("[USBMon] Monitoring endpoint %d on device %d, 
+value=%8X, new level=%d \n", tmp1, dev->devnum, new_endpoint->value, a[3]);
+                               /*printk("new ep=%8X\n",(int)new_endpoint);
+                               */
+                               new_endpoint->level = a[3];
+                       
+                               new_endpoint->next =    
+                                  dev->USBMon_data->USBMon_monitored_endpoints;
+                                       
+                               dev->USBMon_data->USBMon_monitored_endpoints = 
+                                                               new_endpoint;
+                       }else{
+                               ret=-ENOMEM;
+                               goto err;
+                       }
+               }
+       }else{
+               printk("[USBMon] Unrecognised Instruction from user on device %d\n", 
+dev->devnum);
+       }
+
+err:
+
+       return ret;
+}
+
+
+
+
+
+
+struct file_operations usbdevfs_devicemon_file_operations = {
+       /*llseek:               NULL,*/
+       read:           usbmon_read,
+       write:          usbmon_write,
+       /*poll:         NULL,
+       ioctl:          NULL,*/
+       open:           usbmon_open,
+       release:        usbmon_release,
+};
+
+
+
+purb_t USBMon_cpy_urb(urb_t *orig, int level)
+{
+       urb_t *cpy;
+       
+       cpy = kmalloc(sizeof(*cpy), GFP_KERNEL);
+       if(!cpy){
+               printk("[USBMon] Unable to kmalloc URB copy\n");
+               return NULL;
+       }
+       
+       cpy->dev = orig->dev;
+       cpy->pipe = orig->pipe;
+       cpy->status = orig->status;
+       cpy->transfer_flags = orig->transfer_flags;
+       cpy->transfer_buffer_length = orig->transfer_buffer_length;
+       cpy->actual_length = orig->actual_length;
+       cpy->bandwidth = orig->bandwidth;
+       cpy->setup_packet = orig->setup_packet;
+       cpy->start_frame = orig->start_frame;
+       cpy->number_of_packets = orig->number_of_packets;
+       cpy->interval = orig->interval;
+       cpy->error_count = orig->error_count;
+       
+       
+       if(level==3){
+               cpy->transfer_buffer = kmalloc(orig->transfer_buffer_length, 
+                                       GFP_KERNEL);
+               if(!cpy){
+                       printk("[USBMon] Unable to kmalloc URB buffer\n");
+                       return NULL;
+               }
+               memcpy( cpy->transfer_buffer, 
+                       orig->transfer_buffer,
+                       orig->transfer_buffer_length);
+       }else{
+               cpy->transfer_buffer = NULL;
+       }
+       return(cpy);
+}
+
+
+void USBMon_urb_pre_completion(urb_t *purb)
+{
+       urb_t *pcpy_urb;
+       struct usbmon_endpoint_ll *ep;
+       
+       
+       ep = (struct usbmon_endpoint_ll *) 
+                       purb->dev->USBMon_data->USBMon_monitored_endpoints;
+                       
+       
+       while(ep != NULL){
+               
+               if((purb->pipe & ((0x4f << 8) | (0xf << 15))) == ep->value){
+               
+                               
+                       pcpy_urb = USBMon_cpy_urb(purb, 0);
+                       if(pcpy_urb != NULL){
+       
+                               pcpy_urb->next=NULL;
+               
+                               if(purb->dev->USBMon_data->USBMon_urb_ll_head ==
+                                                                       NULL){
+                       
+                                       purb->dev->USBMon_data->
+                                                       USBMon_urb_ll_head = 
+                                                                      pcpy_urb;
+                                       purb->dev->USBMon_data->
+                                                       USBMon_urb_ll_last = 
+                                                                      pcpy_urb;
+                                       
+                               }else{
+                                       purb->dev->USBMon_data->
+                                                    USBMon_urb_ll_last->next =
+                                                               pcpy_urb;
+                                       wmb();
+                                       purb->dev->USBMon_data->
+                                                       USBMon_urb_ll_last= 
+                                                               pcpy_urb;
+                               }
+                               
+                       }else{
+                               printk("[USBMon] failed to copy URB for 
+monitoring\n");
+                       }
+                       
+                       ep = NULL; /* So as to break out of while loop faster*/
+                       
+               }else{ /* endif check on endpoint */
+               
+                       ep = ep->next;
+
+               }               
+       }
+}
+
+/*end USBMon Addition */
diff -urN -X exclusions linux/drivers/usb/inode.c linux-2.4.1-dev/drivers/usb/inode.c
--- linux/drivers/usb/inode.c   Thu Mar 15 22:46:20 2001
+++ linux-2.4.1-dev/drivers/usb/inode.c Thu Mar 15 22:46:44 2001
@@ -66,7 +66,7 @@
        const char *name;
        unsigned int s;
 
-       if (dentry->d_name.len != 3)
+       if ((dentry->d_name.len != 3) && (dentry->d_name.len != 4))/*USBMon*/
                return -1;
        name = dentry->d_name.name;
        if (name[0] < '0' || name[0] > '9' ||
@@ -87,6 +87,7 @@
 static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
 {
        struct inode *inode;
+       struct inode *inode2; /*USBMon Addition*/
        unsigned int devnum = dev->devnum;
        unsigned int busnum = dev->bus->busnum;
 
@@ -106,6 +107,24 @@
        inode->u.usbdev_i.p.dev = dev;
        list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
        list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes);
+       
+       /*USBMon Addition  */
+       
+       inode2 = iget(sb, IDEVICEMON | (busnum << 8) | devnum);
+       if (!inode) {
+               printk(KERN_ERR "usbdevfs: cannot create monitor inode for bus %u 
+device %u\n", busnum, devnum);
+               return;
+       }
+       inode2->i_atime = inode2->i_mtime = inode2->i_ctime = CURRENT_TIME;
+       inode2->i_uid = sb->u.usbdevfs_sb.devuid;
+       inode2->i_gid = sb->u.usbdevfs_sb.devgid;
+       inode2->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
+       inode2->i_fop = &usbdevfs_devicemon_file_operations;
+       inode2->i_size = 1024; /*** needs to change */
+       inode2->u.usbdev_i.p.dev = dev;
+       list_add_tail(&inode2->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
+       list_add_tail(&inode2->u.usbdev_i.dlist, &dev->inodes);
+       /*end USBMon Addition*/
 }
 
 static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb)
@@ -262,9 +281,15 @@
                return ERR_PTR(-EINVAL);
        dentry->d_op = &usbdevfs_dentry_operations;
        devnr = dnumber(dentry);
-       if (devnr < 1 || devnr > 127)
+       if (devnr < 1 || devnr > 127){
+               printk("[USBMon] Invalid dev id %d on lookup\n",devnr);
                return ERR_PTR(-ENOENT);
-       inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr);
+       }
+       if(dentry->d_name.len == 4){
+               inode = iget(dir->i_sb, IDEVICEMON | (dir->i_ino & (0xff << 8)) | 
+devnr);
+       }else{
+               inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr);
+       }
        if (!inode)
                return ERR_PTR(-EINVAL);
        if (inode && inode->u.usbdev_i.p.dev == NULL) {
@@ -336,17 +361,28 @@
 static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct 
file *filp, void *dirent, filldir_t filldir)
 {
        char numbuf[8];
+       char numbuf2[8]; /*USBMon*/
        unsigned int i;
 
        if (!dev)
                return pos;
        sprintf(numbuf, "%03d", dev->devnum);
+       sprintf(numbuf2, "%03dM", dev->devnum);/*USBMon*/
+       
        if (pos > 0)
                pos--;
        else {
-               if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 
0xff), DT_UNKNOWN) < 0)
+               if (filldir(dirent, numbuf, 3, filp->f_pos, IDEVICE | ino | 
+(dev->devnum & 0xff), DT_UNKNOWN) < 0)
                        return -1;
                filp->f_pos++;
+               
+               /*USBMon Addition*/
+               if (filldir(dirent, numbuf2, 4, filp->f_pos, IDEVICEMON | ino | 
+(dev->devnum & 0xff), DT_UNKNOWN) < 0){
+                       printk("[USBMon] FAILED to insert monitor file\n");
+                       return -1;
+               }
+               filp->f_pos++;
+               /*USBMon end*/
        }
        for (i = 0; i < dev->maxchild; i++) {
                if (!dev->children[i])
@@ -383,7 +419,7 @@
        default:
                lock_kernel();
                bus = usbdevfs_findbus(IBUSNR(ino));
-               bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), 
filp->f_pos-2, filp, dirent, filldir);
+               bus_readdir(bus->root_hub, ((bus->busnum & 0xff) << 8), filp->f_pos-2, 
+filp, dirent, filldir);/* has changed due to USBMon*/
                unlock_kernel();
                return 0;
        }
diff -urN -X exclusions linux/drivers/usb/usb-ohci.c 
linux-2.4.1-dev/drivers/usb/usb-ohci.c
--- linux/drivers/usb/usb-ohci.c        Thu Mar 15 22:46:20 2001
+++ linux-2.4.1-dev/drivers/usb/usb-ohci.c      Thu Mar 15 22:46:44 2001
@@ -406,6 +406,7 @@
 
        switch (usb_pipetype (urb->pipe)) {
                case PIPE_INTERRUPT:
+                       USBMon_urb_pre_completion(urb);/*USBMon*/
                        urb->complete (urb); /* call complete and requeue URB */       
 
                        urb->actual_length = 0;
                        urb->status = USB_ST_URB_PENDING;
@@ -415,7 +416,8 @@
                        
                case PIPE_ISOCHRONOUS:
                        for (urbt = urb->next; urbt && (urbt != urb); urbt = 
urbt->next);
-                       if (urbt) { /* send the reply and requeue URB */        
+                       if (urbt) { /* send the reply and requeue URB */
+                               USBMon_urb_pre_completion(urb);/*USBMon*/
                                urb->complete (urb);
                                
                                spin_lock_irqsave (&usb_ed_lock, flags);
@@ -433,6 +435,7 @@
                                
                        } else { /* unlink URB, call complete */
                                urb_rm_priv (urb);
+                               USBMon_urb_pre_completion(urb);/*USBMon*/
                                urb->complete (urb);    
                        }               
                        break;
@@ -440,6 +443,7 @@
                case PIPE_BULK:
                case PIPE_CONTROL: /* unlink URB, call complete */
                        urb_rm_priv (urb);
+                       USBMon_urb_pre_completion(urb);/*USBMon*/
                        urb->complete (urb);    
                        break;
        }
@@ -670,6 +674,8 @@
                        if (urb->transfer_flags & USB_ASYNC_UNLINK) {
                                urb->status = -ECONNRESET;
                                if (urb->complete)
+                                       USBMon_urb_pre_completion(urb); 
+                                                               /*USBMon*/
                                        urb->complete (urb); 
                        } else 
                                urb->status = -ENOENT;
@@ -1336,6 +1342,7 @@
        if (urb->transfer_flags & USB_ASYNC_UNLINK) {
                urb->status = -ECONNRESET;
                if (urb->complete)
+                       USBMon_urb_pre_completion(urb);/*USBMon*/
                        urb->complete (urb);
        } else {
                urb->status = -ENOENT;
@@ -1694,6 +1701,7 @@
                        urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
 #endif
                        if (urb->complete)
+                               USBMon_urb_pre_completion(urb);/*USBMon*/
                                urb->complete (urb);
                }
        }
@@ -1924,6 +1932,7 @@
        usb_dec_dev_use (usb_dev);
        urb->dev = NULL;
        if (urb->complete)
+               USBMon_urb_pre_completion(urb);/*USBMon*/
                urb->complete (urb);
        return 0;
 }
@@ -1945,6 +1954,7 @@
                if (urb->transfer_flags & USB_ASYNC_UNLINK) {
                        urb->status = -ECONNRESET;
                        if (urb->complete)
+                               USBMon_urb_pre_completion(urb);/*USBMon*/
                                urb->complete (urb);
                } else
                        urb->status = -ENOENT;
diff -urN -X exclusions linux/drivers/usb/usb-uhci.c 
linux-2.4.1-dev/drivers/usb/usb-uhci.c
--- linux/drivers/usb/usb-uhci.c        Thu Mar 15 22:46:21 2001
+++ linux-2.4.1-dev/drivers/usb/usb-uhci.c      Thu Mar 15 22:46:44 2001
@@ -1141,6 +1141,7 @@
                usb_dev = urb->dev;
                if (urb->complete) {
                        dbg("unlink_urb: calling completion");
+                       USBMon_urb_pre_completion(urb); /*USBMon*/
                        urb->dev = NULL;
                        urb->complete ((struct urb *) urb);
                }
@@ -1208,6 +1209,7 @@
 
                        if (urb->complete) {
                                spin_unlock(&s->urb_list_lock);
+                               USBMon_urb_pre_completion(urb);/*USBMon*/
                                urb->dev = NULL;
                                urb->complete ((struct urb *) urb);
                                spin_lock(&s->urb_list_lock);
@@ -1868,6 +1870,7 @@
        if ((data > 0) && (uhci->rh.send != 0)) {
                dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
                     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
+               USBMon_urb_pre_completion(urb);/*USBMon*/
                urb->complete (urb);
        }
        return 0;
@@ -1887,8 +1890,10 @@
                len = rh_send_irq (urb);
                if (len > 0) {
                        urb->actual_length = len;
-                       if (urb->complete)
+                       if (urb->complete){
+                               USBMon_urb_pre_completion(urb);/*USBMon*/
                                urb->complete (urb);
+                       }
                }
        }
        rh_init_int_timer (urb);
@@ -2121,9 +2126,12 @@
 
        urb->actual_length = len;
        urb->status = stat;
-       urb->dev=NULL;
-       if (urb->complete)
+       /*urb->dev=NULL;   commented out for USBMon*/
+       if (urb->complete){
+               USBMon_urb_pre_completion(urb);/*USBMon*/
+               urb->dev=NULL;/*USBMon*/
                urb->complete (urb);
+       }
        return 0;
 }
 /*-------------------------------------------------------------------------*/
@@ -2407,6 +2415,8 @@
 
                        spin_unlock(&s->urb_list_lock);
                        
+                       USBMon_urb_pre_completion(urb);/*USBMon*/
+                       
                        urb->complete ((struct urb *) urb);
                        
                        spin_lock(&s->urb_list_lock);
@@ -2625,6 +2635,7 @@
 
                        // Completion
                        if (urb->complete) {
+                               USBMon_urb_pre_completion(urb);/*USBMon*/
                                urb->dev = NULL;
                                spin_unlock(&s->urb_list_lock);
                                urb->complete ((struct urb *) urb);
diff -urN -X exclusions linux/drivers/usb/usb.c linux-2.4.1-dev/drivers/usb/usb.c
--- linux/drivers/usb/usb.c     Thu Mar 15 22:46:21 2001
+++ linux-2.4.1-dev/drivers/usb/usb.c   Fri Mar 16 17:08:17 2001
@@ -256,7 +256,8 @@
 /*
  * usb_check_bandwidth():
  *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
+ * old_
+  is from host_controller->bandwidth_allocated in microseconds;
  * bustime is from calc_bus_time(), but converted to microseconds.
  *
  * returns <bustime in us> if successful,
@@ -885,6 +886,15 @@
        INIT_LIST_HEAD(&dev->inodes);
        INIT_LIST_HEAD(&dev->filelist);
 
+       dev->USBMon_data = kmalloc(sizeof(struct USBMon_data), GFP_KERNEL);
+       if(dev->USBMon_data == NULL){
+               return(NULL);
+       }
+       dev->USBMon_data->USBMon_urb_ll_head = NULL;/*USBMon*/
+       dev->USBMon_data->USBMon_urb_ll_last = NULL;/*USBMon*/
+       dev->USBMon_data->USBMon_urb_ll_buffered = NULL;/*USBMon*/
+       dev->USBMon_data->USBMon_monitored_endpoints = NULL;/*USBMon*/
+
        dev->bus->op->allocate(dev);
 
        return dev;
@@ -892,7 +902,22 @@
 
 void usb_free_dev(struct usb_device *dev)
 {
+       /*USBMon*/
+       struct usbmon_endpoint_ll *tmp_ep1,*tmp_ep2;                    
+       /*
+       tmp_ep1=dev->USBMon_data->USBMon_monitored_endpoints;
+       while(tmp_ep1 != NULL){
+               tmp_ep2=tmp_ep1->next;
+               kfree(tmp_ep1);
+               tmp_ep1=tmp_ep2;
+       }
+       kfree(dev->USBMon_data);
+       /*end USBMon*/
+       
+       
        if (atomic_dec_and_test(&dev->refcnt)) {
+       
+               
                dev->bus->op->deallocate(dev);
                usb_destroy_configuration(dev);
                kfree(dev);
diff -urN -X exclusions linux/include/linux/usb.h linux-2.4.1-dev/include/linux/usb.h
--- linux/include/linux/usb.h   Thu Mar 15 22:46:21 2001
+++ linux-2.4.1-dev/include/linux/usb.h Thu Mar 15 22:46:44 2001
@@ -580,6 +580,22 @@
 };
 
 #define USB_MAXCHILDREN                (16)    /* This is arbitrary */
+/*
+struct usbmon_endpoint_ll;
+*/
+struct usbmon_endpoint_ll {
+       unsigned int value;
+       struct usbmon_endpoint_ll *next;
+       int level;
+};
+
+struct USBMon_data {
+       struct usbmon_endpoint_ll *USBMon_monitored_endpoints; /*USBMon*/
+       urb_t *USBMon_urb_ll_head;/*USBMon*/
+       urb_t *USBMon_urb_ll_last;/*USBMon*/
+       urb_t *USBMon_urb_ll_buffered;/*USBMon*/
+       unsigned char USBMon_write_buffer[4];
+};
 
 struct usb_device {
        int devnum;                     /* Device number on USB bus */
@@ -621,6 +637,7 @@
 
        int maxchild;                   /* Number of ports if hub */
        struct usb_device *children[USB_MAXCHILDREN];
+       struct USBMon_data *USBMon_data;
 };
 
 extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
diff -urN -X exclusions linux/include/linux/usbdevice_fs.h 
linux-2.4.1-dev/include/linux/usbdevice_fs.h
--- linux/include/linux/usbdevice_fs.h  Thu Mar 15 22:46:21 2001
+++ linux-2.4.1-dev/include/linux/usbdevice_fs.h        Thu Mar 15 22:46:44 2001
@@ -157,6 +157,7 @@
 #define ISPECIAL   (0<<28)
 #define IBUS       (1<<28)
 #define IDEVICE    (2<<28)
+#define IDEVICEMON (4<<28)  /*USBMon Addition */
 #define IBUSNR(x)  (((x)>>8)&0xff)
 #define IDEVNR(x)  ((x)&0xff)
 
@@ -193,7 +194,8 @@
 extern struct usb_driver usbdevfs_driver;
 extern struct file_operations usbdevfs_drivers_fops;
 extern struct file_operations usbdevfs_devices_fops;
-extern struct file_operations usbdevfs_device_file_operations;
+extern struct file_operations usbdevfs_devicemon_file_operations;
+extern struct file_operations usbdevfs_device_file_operations; /*USBMon*/
 extern struct inode_operations usbdevfs_device_inode_operations;
 extern struct inode_operations usbdevfs_bus_inode_operations;
 extern struct file_operations usbdevfs_bus_file_operations;

tools.tar.gz

Reply via email to