]> git.hungrycats.org Git - linux/commitdiff
v2.5.1.5 -> v2.5.1.6
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 07:59:46 +0000 (23:59 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 07:59:46 +0000 (23:59 -0800)
- Davide Libenzi: nicer timeslices for scheduler
- Arnaldo: wd7000 scsi driver cleanups and bio update
- Greg KH: USB update (including initial 2.0 support)
- me: strict typechecking on "kdev_t"

117 files changed:
Makefile
arch/cris/drivers/usb-host.c
arch/i386/defconfig
drivers/acorn/block/mfmhd.c
drivers/block/DAC960.c
drivers/block/acsi.c
drivers/block/blkpg.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cpqarray.c
drivers/block/elevator.c
drivers/block/floppy.c
drivers/block/genhd.c
drivers/block/ll_rw_blk.c
drivers/block/paride/pd.c
drivers/block/ps2esdi.c
drivers/block/xd.c
drivers/cdrom/cdrom.c
drivers/char/agp/agpgart_fe.c
drivers/char/console.c
drivers/char/drm/drm_drv.h
drivers/char/drm/drm_fops.h
drivers/char/drm/drm_stub.h
drivers/char/mem.c
drivers/char/misc.c
drivers/char/n_tty.c
drivers/char/pty.c
drivers/char/raw.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/char/vc_screen.c
drivers/ide/ataraid.c
drivers/ide/hd.c
drivers/ide/ide-cd.c
drivers/ide/ide-probe.c
drivers/ide/ide.c
drivers/md/lvm.c
drivers/md/md.c
drivers/message/i2o/i2o_block.c
drivers/mtd/ftl.c
drivers/mtd/nftlcore.c
drivers/net/irda/irda-usb.c
drivers/pcmcia/ds.c
drivers/s390/block/dasd_int.h
drivers/scsi/scsi_lib.c
drivers/scsi/scsicam.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/wd7000.c
drivers/sound/es1371.c
drivers/sound/sound_core.c
drivers/usb/audio.c
drivers/usb/dabusb.c
drivers/usb/dabusb.h
drivers/usb/devio.c
drivers/usb/hcd.c [new file with mode: 0644]
drivers/usb/hcd.h [new file with mode: 0644]
drivers/usb/hcd/Config.in [new file with mode: 0644]
drivers/usb/hcd/Makefile [new file with mode: 0644]
drivers/usb/hcd/ehci-dbg.c [new file with mode: 0644]
drivers/usb/hcd/ehci-hcd.c [new file with mode: 0644]
drivers/usb/hcd/ehci-hub.c [new file with mode: 0644]
drivers/usb/hcd/ehci-mem.c [new file with mode: 0644]
drivers/usb/hcd/ehci-q.c [new file with mode: 0644]
drivers/usb/hcd/ehci-sched.c [new file with mode: 0644]
drivers/usb/hcd/ehci.h [new file with mode: 0644]
drivers/usb/hub.c
drivers/usb/hub.h
drivers/usb/inode.c
drivers/usb/mdc800.c
drivers/usb/pwc-if.c
drivers/usb/pwc.h
drivers/usb/serial/ipaq.c [new file with mode: 0644]
drivers/usb/serial/ipaq.h [new file with mode: 0644]
drivers/usb/serial/kl5kusb105.c [new file with mode: 0644]
drivers/usb/serial/kl5kusb105.h [new file with mode: 0644]
drivers/usb/usb-debug.c
drivers/usb/usb.c
fs/autofs4/inode.c
fs/block_dev.c
fs/buffer.c
fs/devices.c
fs/inode.c
fs/isofs/rock.c
fs/lockd/svclock.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/read.c
fs/nfs/write.c
fs/nfsd/export.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsfh.c
fs/nfsd/nfsproc.c
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/partitions/atari.c
fs/partitions/check.c
fs/proc/array.c
fs/super.c
include/linux/blk.h
include/linux/blkdev.h
include/linux/cdrom.h
include/linux/fs.h
include/linux/genhd.h
include/linux/ide.h
include/linux/kdev_t.h
include/linux/nfsd/nfsfh.h
include/linux/raid/md_k.h
include/linux/usb.h
include/linux/usbdevice_fs.h
init/do_mounts.c
kernel/sched.c
mm/filemap.c
mm/page_io.c
mm/swapfile.c

index 0dd32d3539e99c0e41f17370bc93c5ca2ece0c96..ca461be4b83ced6f294cadd8cfa095198d9c44f1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 2
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index 19d87693170a15be38761f5d278eb87b59c8125a..233fdbbaeb0aaf66e57ae8549bb0adfa4ad4f1d6 100644 (file)
@@ -196,7 +196,7 @@ static urb_t *URB_List[NBR_OF_EP_DESC];
 static kmem_cache_t *usb_desc_cache;
 static struct usb_bus *etrax_usb_bus;
 
-static void dump_urb (purb_t purb);
+static void dump_urb (struct urb *urb);
 static void init_rx_buffers(void);
 static int etrax_rh_unlink_urb (urb_t *urb);
 static void etrax_rh_send_irq(urb_t *urb);
@@ -240,24 +240,24 @@ static struct usb_operations etrax_usb_device_operations =
 };
 
 #ifdef USB_DEBUG_DESC
-static void dump_urb(purb_t purb)
+static void dump_urb(struct urb *urb)
 {
-       printk("\nurb                   :0x%08X\n", purb);
-       printk("next                  :0x%08X\n", purb->next);
-       printk("dev                   :0x%08X\n", purb->dev);
-       printk("pipe                  :0x%08X\n", purb->pipe);
-       printk("status                :%d\n", purb->status);
-       printk("transfer_flags        :0x%08X\n", purb->transfer_flags);
-       printk("transfer_buffer       :0x%08X\n", purb->transfer_buffer);
-       printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-       printk("actual_length         :%d\n", purb->actual_length);
-       printk("setup_packet          :0x%08X\n", purb->setup_packet);
-       printk("start_frame           :%d\n", purb->start_frame);
-       printk("number_of_packets     :%d\n", purb->number_of_packets);
-       printk("interval              :%d\n", purb->interval);
-       printk("error_count           :%d\n", purb->error_count);
-       printk("context               :0x%08X\n", purb->context);
-       printk("complete              :0x%08X\n\n", purb->complete);
+       printk("\nurb                   :0x%08X\n", urb);
+       printk("next                  :0x%08X\n", urb->next);
+       printk("dev                   :0x%08X\n", urb->dev);
+       printk("pipe                  :0x%08X\n", urb->pipe);
+       printk("status                :%d\n", urb->status);
+       printk("transfer_flags        :0x%08X\n", urb->transfer_flags);
+       printk("transfer_buffer       :0x%08X\n", urb->transfer_buffer);
+       printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+       printk("actual_length         :%d\n", urb->actual_length);
+       printk("setup_packet          :0x%08X\n", urb->setup_packet);
+       printk("start_frame           :%d\n", urb->start_frame);
+       printk("number_of_packets     :%d\n", urb->number_of_packets);
+       printk("interval              :%d\n", urb->interval);
+       printk("error_count           :%d\n", urb->error_count);
+       printk("context               :0x%08X\n", urb->context);
+       printk("complete              :0x%08X\n\n", urb->complete);
 }
 
 static void dump_in_desc(USB_IN_Desc_t *in)
index c73c7bb74f5468e25c1f9d838cbfe7bab51d0bfc..49e258065ad50fd9661e196633c040c80b864ad8 100644 (file)
@@ -409,6 +409,7 @@ CONFIG_NET_PCI=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
+# CONFIG_DE2104X is not set
 # CONFIG_TULIP is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
@@ -624,7 +625,7 @@ CONFIG_AUTOFS4_FS=y
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
index c53ce346a91b7fc73024755740a439e5ebd85f85..9ad0510cc81fe8ac726ba8bab9e432ab86882eac 100644 (file)
@@ -1311,10 +1311,8 @@ static struct gendisk mfm_gendisk = {
        major:          MAJOR_NR,
        major_name:     "mfm",
        minor_shift:    6,
-       max_p:          1 << 6,
        part:           mfm,
        sizes:          mfm_sizes,
-       real_devices:   (void *)mfm_info,
 };
 
 static struct block_device_operations mfm_fops =
@@ -1473,7 +1471,7 @@ static int mfm_reread_partitions(kdev_t dev)
        mfm_info[target].busy = 1;
        restore_flags (flags);
 
-       maxp = mfm_gendisk.max_p;
+       maxp = 1 << mfm_gendisk.minor_shift;
        start = target << mfm_gendisk.minor_shift;
 
        for (i = maxp - 1; i >= 0; i--) {
index 123d341f5915d366271787d4935d6cd81f5b94e3..c5b61f436a86e80abf8ce363db9d581fde833c2f 100644 (file)
@@ -1973,9 +1973,7 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
   Controller->GenericDiskInfo.major = MajorNumber;
   Controller->GenericDiskInfo.major_name = "rd";
   Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
-  Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
   Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives;
-  Controller->GenericDiskInfo.real_devices = Controller;
   Controller->GenericDiskInfo.next = NULL;
   Controller->GenericDiskInfo.fops = &DAC960_BlockDeviceOperations;
   /*
@@ -2024,10 +2022,9 @@ static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
   Information Partition Sector Counts and Block Sizes.
 */
 
-static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller)
 {
-  DAC960_Controller_T *Controller =
-    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+  GenericDiskInfo_T *GenericDiskInfo = &Controller->GenericDiskInfo;
   int LogicalDriveNumber, i;
   for (LogicalDriveNumber = 0;
        LogicalDriveNumber < DAC960_MaxLogicalDrives;
@@ -2658,7 +2655,7 @@ static int DAC960_Initialize(void)
       int LogicalDriveNumber;
       if (Controller == NULL) continue;
       DAC960_InitializeController(Controller);
-      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+      DAC960_ComputeGenericDiskInfo(Controller);
       for (LogicalDriveNumber = 0;
           LogicalDriveNumber < DAC960_MaxLogicalDrives;
           LogicalDriveNumber++)
@@ -3161,7 +3158,7 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
                                Controller->ControllerNumber,
                                LogicalDriveNumber);
              Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
-             DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+             DAC960_ComputeGenericDiskInfo(Controller);
            }
          if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
            {
@@ -3173,7 +3170,7 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
                                Controller->ControllerNumber,
                                LogicalDriveNumber);
              Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
-             DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+             DAC960_ComputeGenericDiskInfo(Controller);
            }
          if (NewEnquiry->StatusFlags.DeferredWriteError !=
              OldEnquiry->StatusFlags.DeferredWriteError)
@@ -4513,7 +4510,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
                {
                  memset(LogicalDeviceInfo, 0,
                         sizeof(DAC960_V2_LogicalDeviceInfo_T));
-                 DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+                 DAC960_ComputeGenericDiskInfo(Controller);
                }
            }
          if (LogicalDeviceInfo != NULL)
@@ -4630,7 +4627,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
              kfree(LogicalDeviceInfo);
              Controller->LogicalDriveInitiallyAccessible
                          [LogicalDriveNumber] = false;
-             DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+             DAC960_ComputeGenericDiskInfo(Controller);
            }
          Controller->V2.NeedLogicalDeviceInformation = false;
        }
@@ -5299,7 +5296,7 @@ static int DAC960_Open(Inode_T *Inode, File_T *File)
   if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
     {
       Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
-      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+      DAC960_ComputeGenericDiskInfo(Controller);
       DAC960_RegisterDisk(Controller, LogicalDriveNumber);
     }
   if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
index 28e5ae8e04f5308277853774dfa4a6511685607a..7ff7d7656621719dfbd077e1ec7a07a9d27660cc 100644 (file)
@@ -1386,10 +1386,8 @@ static struct gendisk acsi_gendisk = {
        major:          MAJOR_NR,
        major_name:     "ad",
        minor_shift:    4,
-       max_p:          1 << 4,
        part:           acsi_part,
        sizes:          acsi_sizes,
-       real_devices:   (void *)acsi_info,
        fops:           &acsi_fops,
 };
        
index eb98633ec37c005691d0d48d37bc7d9284d05bec..9d1fdf03a2c46274aeed723988fdfb0ce94e87eb 100644 (file)
@@ -85,14 +85,16 @@ int add_partition(kdev_t dev, struct blkpg_partition *p)
                return -ENXIO;
 
        /* existing drive? */
-       drive = (MINOR(dev) >> g->minor_shift);
+       drive = (minor(dev) >> g->minor_shift);
        first_minor = (drive << g->minor_shift);
-       end_minor   = first_minor + g->max_p;
+       end_minor   = first_minor + (1 << g->minor_shift);
        if (drive >= g->nr_real)
                return -ENXIO;
 
        /* drive and partition number OK? */
-       if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+       if (first_minor != minor(dev))
+               return -EINVAL;
+       if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
                return -EINVAL;
 
        /* partition number in use? */
@@ -136,10 +138,13 @@ int del_partition(kdev_t dev, struct blkpg_partition *p)
                return -ENXIO;
 
        /* drive and partition number OK? */
-       drive = (MINOR(dev) >> g->minor_shift);
+       drive = (minor(dev) >> g->minor_shift);
        first_minor = (drive << g->minor_shift);
-       if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+
+       if (first_minor != minor(dev))
                return -EINVAL;
+       if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
+               return -EINVAL;
 
        /* existing drive and partition? */
        minor = first_minor + p->pno;
@@ -147,7 +152,7 @@ int del_partition(kdev_t dev, struct blkpg_partition *p)
                return -ENXIO;
 
        /* partition in use? Incomplete check for now. */
-       devp = MKDEV(MAJOR(dev), minor);
+       devp = mk_kdev(major(dev), minor);
        if (is_mounted(devp) || is_swap_partition(devp))
                return -EBUSY;
 
@@ -203,7 +208,7 @@ int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
        int intval, *iptr;
        unsigned short usval;
 
-       if (!dev)
+       if (kdev_none(dev))
                return -EINVAL;
 
        intval = block_ioctl(dev, cmd, arg);
@@ -227,25 +232,25 @@ int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
                                return -EACCES;
                        if(arg > 0xff)
                                return -EINVAL;
-                       read_ahead[MAJOR(dev)] = arg;
+                       read_ahead[major(dev)] = arg;
                        return 0;
                case BLKRAGET:
                        if (!arg)
                                return -EINVAL;
-                       return put_user(read_ahead[MAJOR(dev)], (long *) arg);
+                       return put_user(read_ahead[major(dev)], (long *) arg);
 
                case BLKFRASET:
                        if (!capable(CAP_SYS_ADMIN))
                                return -EACCES;
-                       if (!(iptr = max_readahead[MAJOR(dev)]))
+                       if (!(iptr = max_readahead[major(dev)]))
                                return -EINVAL;
-                       iptr[MINOR(dev)] = arg;
+                       iptr[minor(dev)] = arg;
                        return 0;
 
                case BLKFRAGET:
-                       if (!(iptr = max_readahead[MAJOR(dev)]))
+                       if (!(iptr = max_readahead[major(dev)]))
                                return -EINVAL;
-                       return put_user(iptr[MINOR(dev)], (long *) arg);
+                       return put_user(iptr[minor(dev)], (long *) arg);
 
                case BLKSECTGET:
                        if ((q = blk_get_queue(dev)) == NULL)
@@ -271,7 +276,7 @@ int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
                case BLKGETSIZE64:
                        g = get_gendisk(dev);
                        if (g)
-                               ullval = g->part[MINOR(dev)].nr_sects;
+                               ullval = g->part[minor(dev)].nr_sects;
 
                        if (cmd == BLKGETSIZE)
                                return put_user((unsigned long)ullval, (unsigned long *)arg);
index b038dde8b39d4480db463df4a24619376d238440..7a5645e95b2dc020e222922d5f734abe1e9ae439 100644 (file)
@@ -1886,7 +1886,6 @@ static int __init cciss_init_one(struct pci_dev *pdev,
        hba[i]->gendisk.major = MAJOR_NR + i;
        hba[i]->gendisk.major_name = "cciss";
        hba[i]->gendisk.minor_shift = NWD_SHIFT;
-       hba[i]->gendisk.max_p = MAX_PART;
        hba[i]->gendisk.part = hba[i]->hd;
        hba[i]->gendisk.sizes = hba[i]->sizes;
        hba[i]->gendisk.nr_real = hba[i]->num_luns;
index 03afe43dacf9924ec6ff614d8675b26523386f7a..1dafe1ec538eebbbeeefb3a3c6dabe8407f1b60f 100644 (file)
@@ -8,7 +8,7 @@
 
 #define NWD            16
 #define NWD_SHIFT      4
-#define MAX_PART       16
+#define MAX_PART       (1 << NWD_SHIFT)
 
 #define IO_OK          0
 #define IO_ERROR       1
index 5f2298ba9720df5da1319a38cec4304dfb290228..3fc4d0abb6c8e5ef2f94de5a084c05a8826c6b03 100644 (file)
@@ -483,7 +483,6 @@ int __init cpqarray_init(void)
                ida_gendisk[i].major = MAJOR_NR + i;
                ida_gendisk[i].major_name = "ida";
                ida_gendisk[i].minor_shift = NWD_SHIFT;
-               ida_gendisk[i].max_p = 16;
                ida_gendisk[i].part = ida + (i*256);
                ida_gendisk[i].sizes = ida_sizes + (i*256);
                ida_gendisk[i].nr_real = 0; 
index 9b1ca228b9ffc5ae11bac98654faf364ffd0742b..2dfaf4ebce7e13f66609163a7ea9232370e915fc 100644 (file)
@@ -70,7 +70,7 @@ inline int bio_rq_in_between(struct bio *bio, struct request *rq,
         * if the device is different (not a normal case) just check if
         * bio is after rq
         */
-       if (next_rq->rq_dev != rq->rq_dev)
+       if (!kdev_same(next_rq->rq_dev, rq->rq_dev))
                return bio->bi_sector > rq->sector;
 
        /*
@@ -113,7 +113,7 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
        /*
         * same device and no special stuff set, merge is ok
         */
-       if (rq->rq_dev == bio->bi_dev && !rq->waiting && !rq->special)
+       if (kdev_same(rq->rq_dev, bio->bi_dev) && !rq->waiting && !rq->special)
                return 1;
 
        return 0;
index 2fcdcc59ace7e792d59813afb6ddc09bcb4d3673..641b6868a3ffaf9e8a3029d2fb37104c1d3b0710 100644 (file)
@@ -270,10 +270,10 @@ static unsigned long fake_change;
 static int initialising=1;
 
 static inline int TYPE(kdev_t x) {
-       return  (MINOR(x)>>2) & 0x1f;
+       return  (minor(x)>>2) & 0x1f;
 }
 static inline int DRIVE(kdev_t x) {
-       return (MINOR(x)&0x03) | ((MINOR(x)&0x80) >> 5);
+       return (minor(x)&0x03) | ((minor(x)&0x80) >> 5);
 }
 #define ITYPE(x) (((x)>>2) & 0x1f)
 #define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
@@ -2906,7 +2906,7 @@ static void redo_fd_request(void)
                        unlock_fdc();
                        return;
                }
-               if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+               if (major(CURRENT->rq_dev) != MAJOR_NR)
                        panic(DEVICE_NAME ": request list destroyed");
 
                device = CURRENT->rq_dev;
@@ -3332,7 +3332,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                        if (ITYPE(drive_state[cnt].fd_device) == type &&
                            drive_state[cnt].fd_ref)
                                check_disk_change(
-                                       MKDEV(FLOPPY_MAJOR,
+                                       mk_kdev(FLOPPY_MAJOR,
                                              drive_state[cnt].fd_device));
                }
        } else {
@@ -3717,7 +3717,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
        if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
                return -ENXIO;
        old_dev = UDRS->fd_device;
-       if (UDRS->fd_ref && old_dev != MINOR(inode->i_rdev))
+       if (UDRS->fd_ref && old_dev != minor(inode->i_rdev))
                return -EBUSY;
 
        if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
@@ -3768,11 +3768,11 @@ static int floppy_open(struct inode * inode, struct file * filp)
                }
        }
 
-       UDRS->fd_device = MINOR(inode->i_rdev);
-       if (old_dev != -1 && old_dev != MINOR(inode->i_rdev)) {
+       UDRS->fd_device = minor(inode->i_rdev);
+       if (old_dev != -1 && old_dev != minor(inode->i_rdev)) {
                if (buffer_drive == drive)
                        buffer_track = -1;
-               invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev));
+               invalidate_buffers(mk_kdev(FLOPPY_MAJOR,old_dev));
        }
 
        /* Allow ioctls if we have write-permissions even if read-only open.
@@ -3806,7 +3806,7 @@ static int check_floppy_change(kdev_t dev)
 {
        int drive = DRIVE(dev);
 
-       if (MAJOR(dev) != MAJOR_NR) {
+       if (major(dev) != MAJOR_NR) {
                DPRINT("check_floppy_change: not a floppy\n");
                return 0;
        }
@@ -3868,7 +3868,7 @@ static int floppy_revalidate(kdev_t dev)
                        UDRS->generation++;
                if (NO_GEOM){
                        /* auto-sensing */
-                       int size = floppy_blocksizes[MINOR(dev)];
+                       int size = floppy_blocksizes[minor(dev)];
                        if (!size)
                                size = 1024;
                        if (!(bh = getblk(dev,0,size))){
@@ -4275,7 +4275,7 @@ int __init floppy_init(void)
                if (fdc_state[FDC(drive)].version == FDC_NONE)
                        continue;
                for (i = 0; i<NUMBER(floppy_type); i++)
-                       register_disk(NULL, MKDEV(MAJOR_NR,TOMINOR(drive)+i*4),
+                       register_disk(NULL, mk_kdev(MAJOR_NR,TOMINOR(drive)+i*4),
                                        1, &floppy_fops, 0);
        }
        return have_no_fdc;
index 2ecc7c6d3f01209bc7b85cd8b5c36f3c7e177fb6..bf0cec7f6f39ff491e50b7225d90fe0f912cffde 100644 (file)
@@ -103,7 +103,7 @@ struct gendisk *
 get_gendisk(kdev_t dev)
 {
        struct gendisk *gp = NULL;
-       int maj = MAJOR(dev);
+       int maj = major(dev);
 
        read_lock(&gendisk_lock);
        for (gp = gendisk_head; gp; gp = gp->next)
@@ -124,7 +124,7 @@ get_start_sect(kdev_t dev)
 
        gp = get_gendisk(dev);
        if (gp)
-               return gp->part[MINOR(dev)].start_sect;
+               return gp->part[minor(dev)].start_sect;
        return 0;
 }
 
@@ -137,7 +137,7 @@ get_nr_sects(kdev_t dev)
 
        gp = get_gendisk(dev);
        if (gp)
-               return gp->part[MINOR(dev)].nr_sects;
+               return gp->part[minor(dev)].nr_sects;
        return 0;
 }
 
index 8a6c3dd97c02d0123f31561553bfa8bb3554e272..060ebae4e7f295f7949f198bd87eeb8e8ab80bc8 100644 (file)
@@ -109,12 +109,12 @@ int blk_nohighio = 0;
  **/
 inline request_queue_t *blk_get_queue(kdev_t dev)
 {
-       struct blk_dev_struct *bdev = blk_dev + MAJOR(dev);
+       struct blk_dev_struct *bdev = blk_dev + major(dev);
 
        if (bdev->queue)
                return bdev->queue(dev);
        else
-               return &blk_dev[MAJOR(dev)].request_queue;
+               return &blk_dev[major(dev)].request_queue;
 }
 
 void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn)
@@ -309,7 +309,7 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
 {
        int bit;
 
-       printk("%s: dev %x: ", msg, rq->rq_dev);
+       printk("%s: dev %02x:%02x: ", msg, major(rq->rq_dev), minor(rq->rq_dev));
        bit = 0;
        do {
                if (rq->flags & (1 << bit))
@@ -910,8 +910,8 @@ int is_read_only(kdev_t dev)
 {
        int minor,major;
 
-       major = MAJOR(dev);
-       minor = MINOR(dev);
+       major = major(dev);
+       minor = minor(dev);
        if (major < 0 || major >= MAX_BLKDEV) return 0;
        return ro_bits[major][minor >> 5] & (1 << (minor & 31));
 }
@@ -920,8 +920,8 @@ void set_device_ro(kdev_t dev,int flag)
 {
        int minor,major;
 
-       major = MAJOR(dev);
-       minor = MINOR(dev);
+       major = major(dev);
+       minor = minor(dev);
        if (major < 0 || major >= MAX_BLKDEV) return;
        if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
        else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
@@ -929,7 +929,7 @@ void set_device_ro(kdev_t dev,int flag)
 
 void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
-       unsigned int major = MAJOR(rq->rq_dev);
+       unsigned int major = major(rq->rq_dev);
        int rw = rq_data_dir(rq);
        unsigned int index;
 
@@ -1016,7 +1016,7 @@ static void attempt_merge(request_queue_t *q, struct request *req,
                return;
 
        if (rq_data_dir(req) != rq_data_dir(next)
-           || req->rq_dev != next->rq_dev
+           || !kdev_same(req->rq_dev, next->rq_dev)
            || req->nr_sectors + next->nr_sectors > q->max_sectors
            || next->waiting || next->special)
                return;
@@ -1245,14 +1245,14 @@ static inline void blk_partition_remap(struct bio *bio)
        struct gendisk *g;
        kdev_t dev0;
 
-       major = MAJOR(bio->bi_dev);
+       major = major(bio->bi_dev);
        if ((g = get_gendisk(bio->bi_dev))) {
-               minor = MINOR(bio->bi_dev);
+               minor = minor(bio->bi_dev);
                drive = (minor >> g->minor_shift);
                minor0 = (drive << g->minor_shift); /* whole disk device */
                /* that is, minor0 = (minor & ~((1<<g->minor_shift)-1)); */
-               dev0 = MKDEV(major, minor0);
-               if (dev0 != bio->bi_dev) {
+               dev0 = mk_kdev(major, minor0);
+               if (!kdev_same(dev0, bio->bi_dev)) {
                        bio->bi_dev = dev0;
                        bio->bi_sector += g->part[minor].start_sect;
                }
@@ -1287,8 +1287,8 @@ static inline void blk_partition_remap(struct bio *bio)
  * */
 void generic_make_request(struct bio *bio)
 {
-       int major = MAJOR(bio->bi_dev);
-       int minor = MINOR(bio->bi_dev);
+       int major = major(bio->bi_dev);
+       int minor = minor(bio->bi_dev);
        request_queue_t *q;
        sector_t minorsize = 0;
        int ret, nr_sectors = bio_sectors(bio);
@@ -1477,7 +1477,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
        if (!nr)
                return;
 
-       major = MAJOR(bhs[0]->b_dev);
+       major = major(bhs[0]->b_dev);
 
        /* Determine correct block size for this device. */
        correct_size = get_hardsect_size(bhs[0]->b_dev);
index 8e1374c18d66c226a00f036aab23ba9112e66fd2..56499c8dd335648d07812ac1645df3941f738589 100644 (file)
@@ -347,7 +347,6 @@ static struct gendisk pd_gendisk = {
        major:          PD_MAJOR,
        major_name:     PD_NAME,
        minor_shift:    PD_BITS,
-       max_p:          PD_PARTNS,
        part:           pd_hd,
        sizes:          pd_sizes,
        fops:           &pd_fops,
index 9664721ec353bdfa9d3b2bef656a6622de8855e2..6e14b496e5bc07e4a0f3e0e44d1c55e2833a88e6 100644 (file)
@@ -160,10 +160,8 @@ static struct gendisk ps2esdi_gendisk =
        major:          MAJOR_NR,
        major_name:     "ed",
        minor_shift:    6,
-       max_p:          1 << 6,
        part:           ps2esdi,
        sizes:          ps2esdi_sizes,
-       real_devices:   (void *)ps2esdi_info,
        fops:           &ps2esdi_fops,
 };
 
index 55587b4640ad8cd9745b1c3efac99ba3cc0dc8b9..30aa2ee030a21a22357be841653429b45cd5cfb2 100644 (file)
@@ -130,10 +130,8 @@ static struct gendisk xd_gendisk = {
        major:          MAJOR_NR,
        major_name:     "xd",
        minor_shift:    6,
-       max_p:          1 << 6,
        part:           xd_struct,
        sizes:          xd_sizes,
-       real_devices:   (void *)xd_info,
        fops:           &xd_fops,
 };
 
index c10261686ddbf346783b07b2a346d9754280955e..229df11fee9049472ca897ae0b89087e4220f892 100644 (file)
@@ -337,7 +337,7 @@ static struct unique_numspace cdrom_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
 int register_cdrom(struct cdrom_device_info *cdi)
 {
        static char banner_printed;
-       int major = MAJOR(cdi->dev);
+       int major = major(cdi->dev);
         struct cdrom_device_ops *cdo = cdi->ops;
         int *change_capability = (int *)&cdo->capability; /* hack */
 
@@ -408,7 +408,7 @@ int register_cdrom(struct cdrom_device_info *cdi)
 int unregister_cdrom(struct cdrom_device_info *unreg)
 {
        struct cdrom_device_info *cdi, *prev;
-       int major = MAJOR(unreg->dev);
+       int major = major(unreg->dev);
 
        cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
 
@@ -417,7 +417,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
 
        prev = NULL;
        cdi = topCdromPtr;
-       while (cdi != NULL && cdi->dev != unreg->dev) {
+       while (cdi != NULL && !kdev_same(cdi->dev, unreg->dev)) {
                prev = cdi;
                cdi = cdi->next;
        }
@@ -440,7 +440,7 @@ struct cdrom_device_info *cdrom_find_device(kdev_t dev)
        struct cdrom_device_info *cdi;
 
        cdi = topCdromPtr;
-       while (cdi != NULL && cdi->dev != dev)
+       while (cdi != NULL && !kdev_same(cdi->dev, dev))
                cdi = cdi->next;
 
        return cdi;
index 2e6a7f63ee0c408d6d480315b570d67e6b81415b..7a2d48725337a3d691947b4baba43eba9ad74726 100644 (file)
@@ -694,7 +694,7 @@ static int agp_release(struct inode *inode, struct file *file)
 
 static int agp_open(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        agp_file_private *priv;
        agp_client *client;
        int rc = -ENXIO;
index 4522b9063b3a85831e758d1ed7e647a2fdacff5f..6565004c8946d3e35d8a7f937528f8fe559b3a5f 100644 (file)
@@ -2171,7 +2171,7 @@ quit:
 
 static kdev_t vt_console_device(struct console *c)
 {
-       return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
+       return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1);
 }
 
 struct console vt_console_driver = {
@@ -2325,7 +2325,7 @@ static void con_stop(struct tty_struct *tty)
        int console_num;
        if (!tty)
                return;
-       console_num = MINOR(tty->device) - (tty->driver.minor_start);
+       console_num = minor(tty->device) - (tty->driver.minor_start);
        if (!vc_cons_allocated(console_num))
                return;
        set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
@@ -2340,7 +2340,7 @@ static void con_start(struct tty_struct *tty)
        int console_num;
        if (!tty)
                return;
-       console_num = MINOR(tty->device) - (tty->driver.minor_start);
+       console_num = minor(tty->device) - (tty->driver.minor_start);
        if (!vc_cons_allocated(console_num))
                return;
        clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
@@ -2368,7 +2368,7 @@ static int con_open(struct tty_struct *tty, struct file * filp)
        unsigned int    currcons;
        int i;
 
-       currcons = MINOR(tty->device) - tty->driver.minor_start;
+       currcons = minor(tty->device) - tty->driver.minor_start;
 
        i = vc_allocate(currcons);
        if (i)
@@ -2391,7 +2391,7 @@ static void con_close(struct tty_struct *tty, struct file * filp)
        if (!tty)
                return;
        if (tty->count != 1) return;
-       vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1);
+       vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1);
        tty->driver_data = 0;
 }
 
index a4ee2537f8fec4c6928909ee8ef86a4f8bb9f999..c7a9a45adf729765d58e43c4591dc1b6fcc6f2d5 100644 (file)
@@ -719,7 +719,7 @@ int DRM(open)( struct inode *inode, struct file *filp )
        int i;
 
        for (i = 0; i < DRM(numdevs); i++) {
-               if (MINOR(inode->i_rdev) == DRM(minor)[i]) {
+               if (minor(inode->i_rdev) == DRM(minor)[i]) {
                        dev = &(DRM(device)[i]);
                        break;
                }
index 3656c5e9c17d40cbff1977f8d36528623c9a3487..ec88ad27eb6cd4c60e3d168bd286fa3a0822503c 100644 (file)
@@ -38,7 +38,7 @@
 
 int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev)
 {
-       kdev_t       minor = MINOR(inode->i_rdev);
+       int          minor = minor(inode->i_rdev);
        drm_file_t   *priv;
 
        if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */
index fe8a1bc9ddcb59da27b148855b2b132471780b6e..d37a017829bd11076e06fe9869db1c8e86b737bf 100644 (file)
@@ -53,7 +53,7 @@ static struct drm_stub_info {
 
 static int DRM(stub_open)(struct inode *inode, struct file *filp)
 {
-       int                    minor = MINOR(inode->i_rdev);
+       int                    minor = minor(inode->i_rdev);
        int                    err   = -ENODEV;
        struct file_operations *old_fops;
 
index 14f29671b5337a09fdba91629cde7b6f23eca55e..a81cb7fd725793f5d8b4209dac14dc669d4731af 100644 (file)
@@ -538,7 +538,7 @@ static struct file_operations full_fops = {
 
 static int memory_open(struct inode * inode, struct file * filp)
 {
-       switch (MINOR(inode->i_rdev)) {
+       switch (minor(inode->i_rdev)) {
                case 1:
                        filp->f_op = &mem_fops;
                        break;
index ed17f3f294d524d1b19bfdcab6af3bef397fd333..bb45e919fc01ef77a5704f31aaebc5e4045a02a4 100644 (file)
@@ -104,7 +104,7 @@ static int misc_read_proc(char *buf, char **start, off_t offset,
 
 static int misc_open(struct inode * inode, struct file * file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        struct miscdevice *c;
        int err = -ENODEV;
        struct file_operations *old_fops, *new_fops = NULL;
index 9f3bff5c89c9073f1bbeacd98b8297bc3cdd7aa4..815e8bb6dc2514c8435136ce485b98df7bba1958 100644 (file)
@@ -45,8 +45,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
-#define SYSCONS_DEV  MKDEV(TTYAUX_MAJOR,1)
+#define IS_CONSOLE_DEV(dev)    (kdev_val(dev) == __mkdev(TTY_MAJOR,0))
+#define IS_SYSCONS_DEV(dev)    (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
 
 #ifndef MIN
 #define MIN(a,b)       ((a) < (b) ? (a) : (b))
@@ -955,8 +955,8 @@ do_it_again:
        /* NOTE: not yet done after every sleep pending a thorough
           check of the logic of this change. -- jlc */
        /* don't stop on /dev/console */
-       if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
-           file->f_dentry->d_inode->i_rdev != SYSCONS_DEV &&
+       if (!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
+           !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev) &&
            current->tty == tty) {
                if (tty->pgrp <= 0)
                        printk("read_chan: tty->pgrp <= 0!\n");
@@ -1135,8 +1135,8 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
 
        /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
        if (L_TOSTOP(tty) && 
-           file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
-           file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
+           !IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
+           !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev)) {
                retval = tty_check_change(tty);
                if (retval)
                        return retval;
index 2d99ea6327732a6f94d36a08ced1d0ae5ec5bf9e..fc6d0fe36b664001d0bdf5a9a6ebde27f623197b 100644 (file)
@@ -88,14 +88,14 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
                {
-                       unsigned int major = MAJOR(tty->device) - UNIX98_PTY_MASTER_MAJOR;
+                       unsigned int major = major(tty->device) - UNIX98_PTY_MASTER_MAJOR;
                        if ( major < UNIX98_NR_MAJORS ) {
-                               devpts_pty_kill( MINOR(tty->device)
+                               devpts_pty_kill( minor(tty->device)
                          - tty->driver.minor_start + tty->driver.name_base );
                        }
                }
 #endif
-               tty_unregister_devfs (&tty->link->driver, MINOR (tty->device));
+               tty_unregister_devfs (&tty->link->driver, minor(tty->device));
                tty_vhangup(tty->link);
        }
 }
@@ -239,7 +239,7 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
 #ifdef CONFIG_UNIX98_PTYS
 static int pty_get_device_number(struct tty_struct *tty, unsigned int *value)
 {
-       unsigned int result = MINOR(tty->device)
+       unsigned int result = minor(tty->device)
                - tty->driver.minor_start + tty->driver.name_base;
        return put_user(result, value);
 }
@@ -314,7 +314,7 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
        retval = -ENODEV;
        if (!tty || !tty->link)
                goto out;
-       line = MINOR(tty->device) - tty->driver.minor_start;
+       line = minor(tty->device) - tty->driver.minor_start;
        if ((line < 0) || (line >= NR_PTYS))
                goto out;
        pty = (struct pty_struct *)(tty->driver.driver_state) + line;
@@ -336,7 +336,7 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
                tty_register_devfs(&tty->link->driver,
                                   DEVFS_FL_CURRENT_OWNER | DEVFS_FL_WAIT,
                                   tty->link->driver.minor_start +
-                                  MINOR(tty->device)-tty->driver.minor_start);
+                                  minor(tty->device)-tty->driver.minor_start);
        retval = 0;
 out:
        return retval;
index 3d0ce04fe156c577369c2dfe33057aa8abb44d49..79b5dfebb9aafa5e571a878020a2ac59673253f5 100644 (file)
@@ -74,7 +74,7 @@ int raw_open(struct inode *inode, struct file *filp)
        int sector_size;
        int sector_bits;
 
-       minor = MINOR(inode->i_rdev);
+       minor = minor(inode->i_rdev);
        
        /* 
         * Is it the control device? 
@@ -134,7 +134,7 @@ int raw_release(struct inode *inode, struct file *filp)
        int minor;
        struct block_device *bdev;
        
-       minor = MINOR(inode->i_rdev);
+       minor = minor(inode->i_rdev);
        down(&raw_devices[minor].mutex);
        bdev = raw_devices[minor].binding;
        raw_devices[minor].inuse--;
@@ -192,8 +192,8 @@ int raw_ctl_ioctl(struct inode *inode,
                         * major/minor numbers make sense. 
                         */
 
-                       if ((rq.block_major == NODEV && 
-                            rq.block_minor != NODEV) ||
+                       if ((rq.block_major == 0 && 
+                            rq.block_minor != 0) ||
                            rq.block_major > MAX_BLKDEV ||
                            rq.block_minor > MINORMASK) {
                                err = -EINVAL;
@@ -209,7 +209,7 @@ int raw_ctl_ioctl(struct inode *inode,
                        if (raw_devices[minor].binding)
                                bdput(raw_devices[minor].binding);
                        raw_devices[minor].binding = 
-                               bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor)));
+                               bdget(kdev_t_to_nr(mk_kdev(rq.block_major, rq.block_minor)));
                        up(&raw_devices[minor].mutex);
                } else {
                        struct block_device *bdev;
@@ -218,8 +218,8 @@ int raw_ctl_ioctl(struct inode *inode,
                        bdev = raw_devices[minor].binding;
                        if (bdev) {
                                dev = to_kdev_t(bdev->bd_dev);
-                               rq.block_major = MAJOR(dev);
-                               rq.block_minor = MINOR(dev);
+                               rq.block_major = major(dev);
+                               rq.block_minor = minor(dev);
                        } else {
                                rq.block_major = rq.block_minor = 0;
                        }
@@ -271,7 +271,7 @@ ssize_t     rw_raw_dev(int rw, struct file *filp, char *buf,
         * First, a few checks on device size limits 
         */
 
-       minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+       minor = minor(filp->f_dentry->d_inode->i_rdev);
 
        new_iobuf = 0;
        iobuf = filp->f_iobuf;
@@ -291,12 +291,12 @@ ssize_t   rw_raw_dev(int rw, struct file *filp, char *buf,
        sector_bits = raw_devices[minor].sector_bits;
        sector_mask = sector_size- 1;
        
-       if (blk_size[MAJOR(dev)])
-               limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
+       if (blk_size[major(dev)])
+               limit = (((loff_t) blk_size[major(dev)][minor(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
        else
                limit = INT_MAX;
        dprintk ("rw_raw_dev: dev %d:%d (+%d)\n",
-                MAJOR(dev), MINOR(dev), limit);
+                major(dev), minor(dev), limit);
        
        err = -EINVAL;
        if ((*offp & sector_mask) || (size & sector_mask))
index 8f5bcedb0de4a1a1c4373c3f37632ad0a6602527..aa8d818fb13c45ed69b735f81a5c52bb94c2313b 100644 (file)
@@ -3141,7 +3141,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
        unsigned long           page;
 
        MOD_INC_USE_COUNT;
-       line = MINOR(tty->device) - tty->driver.minor_start;
+       line = minor(tty->device) - tty->driver.minor_start;
        if ((line < 0) || (line >= NR_PORTS)) {
                MOD_DEC_USE_COUNT;
                return -ENODEV;
index e6fd8a89bc7f523afbe1808221bf1b9ad3e19712..78a2a16a3c446daaab20f873a1861c7d9012cd55 100644 (file)
 
 #include <linux/kmod.h>
 
-#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
-#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
-#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
-#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2)
+#define IS_CONSOLE_DEV(dev)    (kdev_val(dev) == __mkdev(TTY_MAJOR,0))
+#define IS_TTY_DEV(dev)                (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,0))
+#define IS_SYSCONS_DEV(dev)    (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
+#define IS_PTMX_DEV(dev)       (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,2))
 
 #undef TTY_DEBUG_HANGUP
 
@@ -185,7 +185,7 @@ static inline void free_tty_struct(struct tty_struct *tty)
 static char *
 _tty_make_name(struct tty_struct *tty, const char *name, char *buf)
 {
-       int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
+       int idx = (tty)? minor(tty->device) - tty->driver.minor_start:0;
 
        if (!tty) /* Hmm.  NULL pointer.  That's fun. */
                strcpy(buf, "NULL tty");
@@ -196,7 +196,7 @@ _tty_make_name(struct tty_struct *tty, const char *name, char *buf)
        return buf;
 }
 
-#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
+#define TTY_NUMBER(tty) (minor((tty)->device) - (tty)->driver.minor_start + \
                         (tty)->driver.name_base)
 
 char *tty_name(struct tty_struct *tty, char *buf)
@@ -331,8 +331,8 @@ struct tty_driver *get_tty_driver(kdev_t device)
        int     major, minor;
        struct tty_driver *p;
        
-       minor = MINOR(device);
-       major = MAJOR(device);
+       minor = minor(device);
+       major = major(device);
 
        for (p = tty_drivers; p; p = p->next) {
                if (p->major != major)
@@ -442,8 +442,8 @@ void do_tty_hangup(void *data)
        file_list_lock();
        for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) {
                struct file * filp = list_entry(l, struct file, f_list);
-               if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
-                   filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) {
+               if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) ||
+                   IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) {
                        cons_filp = filp;
                        continue;
                }
@@ -652,7 +652,7 @@ static ssize_t tty_read(struct file * file, char * buf, size_t count,
           moved it to there.  This should only be done for the N_TTY
           line discipline, anyway.  Same goes for write_chan(). -- jlc. */
 #if 0
-       if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
+       if (!IS_CONSOLE_DEV(inode->i_rdev) && /* don't stop on /dev/console */
            (tty->pgrp > 0) &&
            (current->tty == tty) &&
            (tty->pgrp != current->pgrp))
@@ -741,8 +741,8 @@ static ssize_t tty_write(struct file * file, const char * buf, size_t count,
         *      well as /dev/tty0.
         */
        inode = file->f_dentry->d_inode;
-       is_console = (inode->i_rdev == SYSCONS_DEV ||
-                     inode->i_rdev == CONSOLE_DEV);
+       is_console = IS_SYSCONS_DEV(inode->i_rdev) ||
+                    IS_CONSOLE_DEV(inode->i_rdev);
 
        if (is_console && redirect)
                tty = redirect;
@@ -803,7 +803,7 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
        if (!driver)
                return -ENODEV;
 
-       idx = MINOR(device) - driver->minor_start;
+       idx = minor(device) - driver->minor_start;
 
        /* 
         * Check whether we need to acquire the tty semaphore to avoid
@@ -857,7 +857,7 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
                if (!o_tty)
                        goto free_mem_out;
                initialize_tty_struct(o_tty);
-               o_tty->device = (kdev_t) MKDEV(driver->other->major,
+               o_tty->device = mk_kdev(driver->other->major,
                                        driver->other->minor_start + idx);
                o_tty->driver = *driver->other;
 
@@ -1049,7 +1049,7 @@ static void release_dev(struct file * filp)
 
        tty_fasync(-1, filp, 0);
 
-       idx = MINOR(tty->device) - tty->driver.minor_start;
+       idx = minor(tty->device) - tty->driver.minor_start;
        pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
                      tty->driver.subtype == PTY_TYPE_MASTER);
        o_tty = tty->link;
@@ -1285,7 +1285,7 @@ static int tty_open(struct inode * inode, struct file * filp)
 retry_open:
        noctty = filp->f_flags & O_NOCTTY;
        device = inode->i_rdev;
-       if (device == TTY_DEV) {
+       if (IS_TTY_DEV(device)) {
                if (!current->tty)
                        return -ENXIO;
                device = current->tty->device;
@@ -1293,13 +1293,13 @@ retry_open:
                /* noctty = 1; */
        }
 #ifdef CONFIG_VT
-       if (device == CONSOLE_DEV) {
+       if (IS_CONSOLE_DEV(device)) {
                extern int fg_console;
-               device = MKDEV(TTY_MAJOR, fg_console + 1);
+               device = mk_kdev(TTY_MAJOR, fg_console + 1);
                noctty = 1;
        }
 #endif
-       if (device == SYSCONS_DEV) {
+       if (IS_SYSCONS_DEV(device)) {
                struct console *c = console_drivers;
                while(c && !c->device)
                        c = c->next;
@@ -1310,7 +1310,7 @@ retry_open:
                noctty = 1;
        }
 
-       if (device == PTMX_DEV) {
+       if (IS_PTMX_DEV(device)) {
 #ifdef CONFIG_UNIX98_PTYS
 
                /* find a free pty. */
@@ -1324,7 +1324,7 @@ retry_open:
                        for (minor = driver->minor_start ;
                             minor < driver->minor_start + driver->num ;
                             minor++) {
-                               device = MKDEV(driver->major, minor);
+                               device = mk_kdev(driver->major, minor);
                                if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */
                        }
                }
@@ -1332,7 +1332,7 @@ retry_open:
        ptmx_found:
                set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
                minor -= driver->minor_start;
-               devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
+               devpts_pty_new(driver->other->name_base + minor, mk_kdev(driver->other->major, minor + driver->other->minor_start));
                tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
                                   pts_driver[major].minor_start + minor);
                noctty = 1;
@@ -1505,8 +1505,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
 static int tioccons(struct inode *inode,
        struct tty_struct *tty, struct tty_struct *real_tty)
 {
-       if (inode->i_rdev == SYSCONS_DEV ||
-           inode->i_rdev == CONSOLE_DEV) {
+       if (IS_SYSCONS_DEV(inode->i_rdev) ||
+           IS_CONSOLE_DEV(inode->i_rdev)) {
                if (!suser())
                        return -EPERM;
                redirect = NULL;
@@ -2002,7 +2002,7 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags, unsigned
 {
 #ifdef CONFIG_DEVFS_FS
        umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
-       kdev_t device = MKDEV (driver->major, minor);
+       kdev_t device = mk_kdev(driver->major, minor);
        int idx = minor - driver->minor_start;
        char buf[32];
 
@@ -2289,8 +2289,8 @@ void __init tty_init(void)
        dev_ptmx_driver = dev_tty_driver;
        dev_ptmx_driver.driver_name = "/dev/ptmx";
        dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5;
-       dev_ptmx_driver.major= MAJOR(PTMX_DEV);
-       dev_ptmx_driver.minor_start = MINOR(PTMX_DEV);
+       dev_ptmx_driver.major= TTYAUX_MAJOR;
+       dev_ptmx_driver.minor_start = 2;
        dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM;
        dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX;
 
index a7e1f2d679c0bd1449dfd235c87c03c1184d7939..157ac042486f60d19732122952cacbd301d4d1c2 100644 (file)
@@ -49,7 +49,8 @@ static int
 vcs_size(struct inode *inode)
 {
        int size;
-       int currcons = MINOR(inode->i_rdev) & 127;
+       int minor = minor(inode->i_rdev);
+       int currcons = minor & 127;
        if (currcons == 0)
                currcons = fg_console;
        else
@@ -59,7 +60,7 @@ vcs_size(struct inode *inode)
 
        size = video_num_lines * video_num_columns;
 
-       if (MINOR(inode->i_rdev) & 128)
+       if (minor & 128)
                size = 2*size + HEADER_SIZE;
        return size;
 }
@@ -97,7 +98,7 @@ static ssize_t
 vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
        struct inode *inode = file->f_dentry->d_inode;
-       unsigned int currcons = MINOR(inode->i_rdev);
+       unsigned int currcons = minor(inode->i_rdev);
        long pos = *ppos;
        long viewed, attr, read;
        int col, maxcol;
@@ -266,7 +267,7 @@ static ssize_t
 vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
        struct inode *inode = file->f_dentry->d_inode;
-       unsigned int currcons = MINOR(inode->i_rdev);
+       unsigned int currcons = minor(inode->i_rdev);
        long pos = *ppos;
        long viewed, attr, size, written;
        char *con_buf0;
@@ -449,7 +450,7 @@ unlock_out:
 static int
 vcs_open(struct inode *inode, struct file *filp)
 {
-       unsigned int currcons = (MINOR(inode->i_rdev) & 127);
+       unsigned int currcons = minor(inode->i_rdev) & 127;
        if(currcons && !vc_cons_allocated(currcons-1))
                return -ENXIO;
        return 0;
index 60725a4d41c833bfbd007161d495f77be12eacb1..3c10b9fac97b98217f9ddc868109fa7a2e3d88d7 100644 (file)
@@ -269,7 +269,6 @@ static __init int ataraid_init(void)
        ataraid_gendisk.major       = ATAMAJOR;
        ataraid_gendisk.major_name  = "ataraid";
        ataraid_gendisk.minor_shift = 4;
-       ataraid_gendisk.max_p       = 15;
        ataraid_gendisk.sizes       = &ataraid_gendisk_sizes[0];
        ataraid_gendisk.nr_real     = 16;
        ataraid_gendisk.fops        = &ataraid_fops;
index 08485cf66fe358900bbe7a2bd4fe391670e0db9d..7e9b1cd2f95ecb392b18f16f28dcd6dd97e3721d 100644 (file)
@@ -693,7 +693,6 @@ static struct gendisk hd_gendisk = {
        major:          MAJOR_NR,
        major_name:     "hd",
        minor_shift:    6,
-       max_p:          1 << 6,
        part:           hd,
        sizes:          hd_sizes,
        fops:           &hd_fops,
index addbe20a4b7f93e0c8cd5a3edf1cd06ed026d160..daf317775c95051ec805c61103d03fd8895c3ab9 100644 (file)
@@ -2015,7 +2015,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
 
        /* Now try to get the total cdrom capacity. */
        minor = (drive->select.b.unit) << PARTN_BITS;
-       dev = MKDEV(HWIF(drive)->major, minor);
+       dev = mk_kdev(HWIF(drive)->major, minor);
        stat = cdrom_get_last_written(dev, &toc->capacity);
        if (stat)
                stat = cdrom_read_capacity(drive, &toc->capacity, sense);
@@ -2481,7 +2481,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
        struct cdrom_device_info *devinfo = &info->devinfo;
        int minor = (drive->select.b.unit) << PARTN_BITS;
 
-       devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+       devinfo->dev = mk_kdev(HWIF(drive)->major, minor);
        devinfo->ops = &ide_cdrom_dops;
        devinfo->mask = 0;
        *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
@@ -2678,8 +2678,8 @@ int ide_cdrom_setup (ide_drive_t *drive)
        /*
         * default to read-only always and fix latter at the bottom
         */
-       set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
-       set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
+       set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1);
+       set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
        blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
 
        blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
@@ -2801,7 +2801,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
        nslots = ide_cdrom_probe_capabilities (drive);
 
        if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
-               set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
+               set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0);
 
        if (ide_cdrom_register (drive, nslots)) {
                printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
@@ -2848,7 +2848,7 @@ void ide_cdrom_release (struct inode *inode, struct file *file,
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-       return cdrom_media_changed(MKDEV (HWIF (drive)->major,
+       return cdrom_media_changed(mk_kdev (HWIF (drive)->major,
                        (drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2876,7 +2876,7 @@ void ide_cdrom_revalidate (ide_drive_t *drive)
         * 1024 even for CDROM's
         */
        blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
-       set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
+       set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
 }
 
 static
index 3f93dcc90fd318d275f5c1fb7854b54d462b4a0c..ba03af19c61b75bbeccf6f6beccad8904337ff31 100644 (file)
@@ -796,9 +796,7 @@ static void init_gendisk (ide_hwif_t *hwif)
        gd->major       = hwif->major;          /* our major device number */
        gd->major_name  = IDE_MAJOR_NAME;       /* treated special in genhd.c */
        gd->minor_shift = PARTN_BITS;           /* num bits for partitions */
-       gd->max_p       = 1<<PARTN_BITS;        /* 1 + max partitions / drive */
        gd->nr_real     = units;                /* current num real drives */
-       gd->real_devices= hwif;                 /* ptr to internal data */
        gd->next        = NULL;                 /* linked list of major devs */
        gd->fops        = ide_fops;             /* file operations */
        gd->de_arr      = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
index c4eb0a4a3c62080dec26ee85b7b8d5ed1320db35..f34006891592e0ee3762a6f1eae8230188ad3387 100644 (file)
@@ -580,7 +580,7 @@ inline int __ide_end_request(ide_hwgroup_t *hwgroup, int uptodate, int nr_secs)
        }
 
        if (!end_that_request_first(rq, uptodate, nr_secs)) {
-               add_blkdev_randomness(MAJOR(rq->rq_dev));
+               add_blkdev_randomness(major(rq->rq_dev));
                blkdev_dequeue_request(rq);
                hwgroup->rq = NULL;
                end_that_request_last(rq);
@@ -653,7 +653,7 @@ void ide_geninit (ide_hwif_t *hwif)
                        continue;
                if (drive->media!=ide_disk && drive->media!=ide_floppy)
                        continue;
-               register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+               register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
 #ifdef CONFIG_BLK_DEV_ISAPNP
                        (drive->forced_geom && drive->noprobe) ? 1 :
 #endif /* CONFIG_BLK_DEV_ISAPNP */
@@ -1223,7 +1223,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 {
        ide_startstop_t startstop;
        unsigned long block;
-       unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
+       unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS;
        ide_hwif_t *hwif = HWIF(drive);
 
        BUG_ON(!(rq->flags & REQ_STARTED));
@@ -1478,7 +1478,7 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
  */
 request_queue_t *ide_get_queue (kdev_t dev)
 {
-       ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+       ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data;
 
        return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
@@ -1784,7 +1784,7 @@ out_lock:
  */
 ide_drive_t *get_info_ptr (kdev_t i_rdev)
 {
-       int             major = MAJOR(i_rdev);
+       int             major = major(i_rdev);
        unsigned int    h;
 
        for (h = 0; h < MAX_HWIFS; ++h) {
@@ -1851,7 +1851,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
 #endif
        rq->errors = 0;
        rq->rq_status = RQ_ACTIVE;
-       rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+       rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<<PARTN_BITS);
        if (action == ide_wait)
                rq->waiting = &wait;
        spin_lock_irqsave(&ide_lock, flags);
@@ -1880,7 +1880,7 @@ void ide_revalidate_drive (ide_drive_t *drive)
 {
         struct gendisk *g = HWIF(drive)->gd;
         int minor = (drive->select.b.unit << g->minor_shift);
-        kdev_t dev = MKDEV(g->major, minor);
+        kdev_t dev = mk_kdev(g->major, minor);
 
         grok_partitions(dev, current_capacity(drive));
 }
@@ -1939,7 +1939,7 @@ static void revalidate_drives (void)
                        if (drive->revalidate) {
                                drive->revalidate = 0;
                                if (!initializing)
-                                       (void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));
+                                       (void) ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS));
                        }
                }
        }
@@ -2119,7 +2119,7 @@ void ide_unregister (unsigned int index)
                minor = drive->select.b.unit << PARTN_BITS;
                for (p = 0; p < (1<<PARTN_BITS); ++p) {
                        if (drive->part[p].nr_sects > 0) {
-                               kdev_t devp = MKDEV(hwif->major, minor+p);
+                               kdev_t devp = mk_kdev(hwif->major, minor+p);
                                invalidate_device(devp, 0);
                        }
                }
@@ -2624,9 +2624,8 @@ static int ide_ioctl (struct inode *inode, struct file *file,
        kdev_t dev;
        ide_settings_t *setting;
 
-       if (!inode || !(dev = inode->i_rdev))
-               return -EINVAL;
-       major = MAJOR(dev); minor = MINOR(dev);
+       dev = inode->i_rdev;
+       major = major(dev); minor = minor(dev);
        if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
                return -ENODEV;
 
@@ -2635,7 +2634,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        err = ide_read_setting(drive, setting);
                        return err >= 0 ? put_user(err, (long *) arg) : err;
                } else {
-                       if ((MINOR(inode->i_rdev) & PARTN_MASK))
+                       if ((minor(inode->i_rdev) & PARTN_MASK))
                                return -EINVAL;
                        return ide_write_setting(drive, setting, arg);
                }
@@ -2651,7 +2650,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
                        if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
                        if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-                       if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+                       if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
                                (unsigned long *) &loc->start)) return -EFAULT;
                        return 0;
                }
@@ -2664,7 +2663,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
                        if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
                        if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-                       if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+                       if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
                                (unsigned long *) &loc->start)) return -EFAULT;
                        return 0;
                }
@@ -2676,7 +2675,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
                        if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
                        if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-                       if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+                       if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
                                (unsigned long *) &loc->start)) return -EFAULT;
                        return 0;
                }
@@ -2687,7 +2686,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
 
                case HDIO_OBSOLETE_IDENTITY:
                case HDIO_GET_IDENTITY:
-                       if (MINOR(inode->i_rdev) & PARTN_MASK)
+                       if (minor(inode->i_rdev) & PARTN_MASK)
                                return -EINVAL;
                        if (drive->id == NULL)
                                return -ENOMSG;
index 4fc6e168006a32f9814066f9bc10f7e043265211..f17b86c621a4b7d0a99548438151b55c03fdbd44 100644 (file)
@@ -378,7 +378,6 @@ static struct gendisk lvm_gendisk =
        major:          MAJOR_NR,
        major_name:     LVM_NAME,
        minor_shift:    0,
-       max_p:          1,
        part:           lvm_hd_struct,
        sizes:          lvm_size,
        nr_real:        MAX_LV,
index 5c99d7fef8f0c8434d0aa55ca34a7683fab5bab0..ffec2c6f9f6c2fed840a1059d9cc0693963b4e4c 100644 (file)
@@ -118,11 +118,9 @@ static struct gendisk md_gendisk=
        major: MD_MAJOR,
        major_name: "md",
        minor_shift: 0,
-       max_p: 1,
        part: md_hd_struct,
        sizes: md_size,
        nr_real: MAX_MD_DEVS,
-       real_devices: NULL,
        next: NULL,
        fops: &md_fops,
 };
index c64b7393b484515b74f66f0b0a5b990458cb7ace..9387ad20f8e7fc4c61891670d200eb7ec6c95e41 100644 (file)
@@ -1778,7 +1778,6 @@ static struct gendisk i2ob_gendisk =
        major:          MAJOR_NR,
        major_name:     "i2o/hd",
        minor_shift:    4,
-       max_p:          1<<4,
        part:           i2ob,
        sizes:          i2ob_sizes,
        nr_real:        MAX_I2OB,
index d15d7413045c301cab17873299ded878202daacb..8e6ce8dab20e90e9b3f8ff09e83990367c11158d 100644 (file)
 #include <linux/hdreg.h>
 #include <stdarg.h>
 
-#if (LINUX_VERSION_CODE >= 0x20100)
 #include <linux/vmalloc.h>
-#endif
-#if (LINUX_VERSION_CODE >= 0x20303)
 #include <linux/blkpg.h>
-#endif
 
 #include <linux/mtd/ftl.h>
-/*====================================================================*/
-/* Stuff which really ought to be in compatmac.h */
-
-#if (LINUX_VERSION_CODE < 0x20328)
-#define register_disk(dev, drive, minors, ops, size) \
-    do { (dev)->part[(drive)*(minors)].nr_sects = size; \
-        if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
-        resetup_one_dev(dev, drive); } while (0);
-#endif
 
-#if (LINUX_VERSION_CODE < 0x20320)
-#define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn
-#define blk_init_queue(q, req)  q = (req)
-#define blk_cleanup_queue(q)    q = NULL
-#define request_arg_t           void
-#else
 #define request_arg_t           request_queue_t *q
-#endif
-
 
 /*====================================================================*/
 
@@ -206,10 +185,6 @@ static struct gendisk ftl_gendisk = {
     major:             FTL_MAJOR,
     major_name:                "ftl",
     minor_shift:       PART_BITS,
-    max_p:             MAX_PART,
-#if (LINUX_VERSION_CODE < 0x20328)
-    max_nr:            MAX_DEV*MAX_PART,
-#endif
     part:              ftl_hd,
     sizes:             ftl_sizes,
 };
@@ -224,23 +199,12 @@ static int ftl_reread_partitions(int minor);
 
 static void ftl_erase_callback(struct erase_info *done);
 
-#if LINUX_VERSION_CODE < 0x20326
-static struct file_operations ftl_blk_fops = {
-    open:      ftl_open,
-    release:   ftl_close,
-    ioctl:     ftl_ioctl,
-    read:      block_read,
-    write:     block_write,
-    fsync:     block_fsync
-};
-#else
 static struct block_device_operations ftl_blk_fops = {
     owner:     THIS_MODULE,
     open:      ftl_open,
     release:   ftl_close,
     ioctl:     ftl_ioctl,
 };
-#endif
 
 /*======================================================================
 
@@ -1177,22 +1141,11 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
     case BLKRRPART:
        ret = ftl_reread_partitions(minor);
        break;
-#if (LINUX_VERSION_CODE < 0x20303)
-    case BLKFLSBUF:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-#endif
-       fsync_dev(inode->i_rdev);
-       invalidate_buffers(inode->i_rdev);
-       break;
-    RO_IOCTLS(inode->i_rdev, arg);
-#else
     case BLKROSET:
     case BLKROGET:
     case BLKFLSBUF:
        ret = blk_ioctl(inode->i_rdev, cmd, arg);
        break;
-#endif
     default:
        ret = -EINVAL;
     }
index dc955e6612b7177b5e8d658654441edd41967dc9..38718c70e4999d7c22e1e6baba80dc00c3d1b7e8 100644 (file)
@@ -62,14 +62,9 @@ struct hd_struct part_table[256];
 static struct gendisk nftl_gendisk = {
        major:          MAJOR_NR,
        major_name:     "nftl",
-       minor_shift:    NFTL_PARTN_BITS,        /* Bits to shift to get real from partition */
-       max_p:          (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */
-#if LINUX_VERSION_CODE < 0x20328
-       max_nr:         MAX_NFTLS,      /* maximum number of real */
-       init:           dummy_init,     /* init function */
-#endif
-       part:           part_table,     /* hd struct */
-       sizes:          nftl_sizes,     /* block sizes */
+       minor_shift:    NFTL_PARTN_BITS,        /* # of partition bits */
+       part:           part_table,             /* hd struct */
+       sizes:          nftl_sizes,             /* block sizes */
 };
 
 struct NFTLrecord *NFTLs[MAX_NFTLS];
index 60defc2ad73bc6a4c46da225acf059c4740bcc7a..08e548505866cbdfbc0d5c3510a9cc1ec86845b6 100644 (file)
@@ -112,9 +112,9 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
 static int irda_usb_open(struct irda_usb_cb *self);
 static int irda_usb_close(struct irda_usb_cb *self);
-static void speed_bulk_callback(purb_t purb);
-static void write_bulk_callback(purb_t purb);
-static void irda_usb_receive(purb_t purb);
+static void speed_bulk_callback(struct urb *urb);
+static void write_bulk_callback(struct urb *urb);
+static void irda_usb_receive(struct urb *urb);
 static int irda_usb_net_init(struct net_device *dev);
 static int irda_usb_net_open(struct net_device *dev);
 static int irda_usb_net_close(struct net_device *dev);
@@ -248,15 +248,15 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
 {
        unsigned long flags;
        __u8 *frame;
-       purb_t purb;
+       struct urb *urb;
        int ret;
 
        IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
                   self->new_speed, self->new_xbofs);
 
        /* Grab the speed URB */
-       purb = &self->speed_urb;
-       if (purb->status != 0) {
+       urb = &self->speed_urb;
+       if (urb->status != 0) {
                WARNING(__FUNCTION__ "(), URB still in use!\n");
                return;
        }
@@ -270,15 +270,15 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
        irda_usb_build_header(self, frame, 1);
 
        /* Submit the 0 length IrDA frame to trigger new speed settings */
-        FILL_BULK_URB(purb, self->usbdev,
+        FILL_BULK_URB(urb, self->usbdev,
                      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
-       purb->transfer_buffer_length = USB_IRDA_HEADER;
-       purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
-       purb->timeout = MSECS_TO_JIFFIES(100);
+       urb->transfer_buffer_length = USB_IRDA_HEADER;
+       urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+       urb->timeout = MSECS_TO_JIFFIES(100);
 
-       if ((ret = usb_submit_urb(purb))) {
+       if ((ret = usb_submit_urb(urb))) {
                WARNING(__FUNCTION__ "(), failed Speed URB\n");
        }
        spin_unlock_irqrestore(&self->lock, flags);
@@ -288,9 +288,9 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
 /*
  * Note : this function will be called with both speed_urb and empty_urb...
  */
-static void speed_bulk_callback(purb_t purb)
+static void speed_bulk_callback(struct urb *urb)
 {
-       struct irda_usb_cb *self = purb->context;
+       struct irda_usb_cb *self = urb->context;
        
        IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
@@ -301,9 +301,9 @@ static void speed_bulk_callback(purb_t purb)
        }
 
        /* Check for timeout and other USB nasties */
-       if (purb->status != 0) {
+       if (urb->status != 0) {
                /* I get a lot of -ECONNABORTED = -103 here - Jean II */
-               IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+               IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags);
 
                /* Don't do anything here, that might confuse the USB layer.
                 * Instead, we will wait for irda_usb_net_timeout(), the
@@ -314,10 +314,10 @@ static void speed_bulk_callback(purb_t purb)
        }
 
        /* urb is now available */
-       purb->status = 0;
+       urb->status = 0;
 
        /* If it was the speed URB, allow the stack to send more packets */
-       if(purb == &self->speed_urb) {
+       if(urb == &self->speed_urb) {
                netif_wake_queue(self->netdev);
        }
 }
@@ -329,7 +329,7 @@ static void speed_bulk_callback(purb_t purb)
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct irda_usb_cb *self = netdev->priv;
-       purb_t purb = &self->tx_urb;
+       struct urb *urb = &self->tx_urb;
        unsigned long flags;
        s32 speed;
        s16 xbofs;
@@ -372,7 +372,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
                }
        }
 
-       if (purb->status != 0) {
+       if (urb->status != 0) {
                WARNING(__FUNCTION__ "(), URB still in use!\n");
                dev_kfree_skb(skb);
                return 0;
@@ -392,22 +392,22 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
        /* FIXME: Make macro out of this one */
        ((struct irda_skb_cb *)skb->cb)->context = self;
 
-        FILL_BULK_URB(purb, self->usbdev, 
+        FILL_BULK_URB(urb, self->usbdev, 
                      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
                       skb->data, IRDA_USB_MAX_MTU,
                       write_bulk_callback, skb);
-       purb->transfer_buffer_length = skb->len;
+       urb->transfer_buffer_length = skb->len;
        /* Note : unlink *must* be Asynchronous because of the code in 
         * irda_usb_net_timeout() -> call in irq - Jean II */
-       purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+       urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
        /* This flag (USB_ZERO_PACKET) indicates that what we send is not
         * a continuous stream of data but separate packets.
         * In this case, the USB layer will insert an empty USB frame (TD)
         * after each of our packets that is exact multiple of the frame size.
         * This is how the dongle will detect the end of packet - Jean II */
-       purb->transfer_flags |= USB_ZERO_PACKET;
+       urb->transfer_flags |= USB_ZERO_PACKET;
        /* Timeout need to be shorter than NET watchdog timer */
-       purb->timeout = MSECS_TO_JIFFIES(200);
+       urb->timeout = MSECS_TO_JIFFIES(200);
 
        /* Generate min turn time. FIXME: can we do better than this? */
        /* Trying to a turnaround time at this level is trying to measure
@@ -451,7 +451,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
        }
        
        /* Ask USB to send the packet */
-       if ((res = usb_submit_urb(purb))) {
+       if ((res = usb_submit_urb(urb))) {
                WARNING(__FUNCTION__ "(), failed Tx URB\n");
                self->stats.tx_errors++;
                /* Let USB recover : We will catch that in the watchdog */
@@ -472,9 +472,9 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 /*
  * Note : this function will be called only for tx_urb...
  */
-static void write_bulk_callback(purb_t purb)
+static void write_bulk_callback(struct urb *urb)
 {
-       struct sk_buff *skb = purb->context;
+       struct sk_buff *skb = urb->context;
        struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
        
        IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -487,12 +487,12 @@ static void write_bulk_callback(purb_t purb)
 
        /* Free up the skb */
        dev_kfree_skb_any(skb);
-       purb->context = NULL;
+       urb->context = NULL;
 
        /* Check for timeout and other USB nasties */
-       if (purb->status != 0) {
+       if (urb->status != 0) {
                /* I get a lot of -ECONNABORTED = -103 here - Jean II */
-               IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+               IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags);
 
                /* Don't do anything here, that might confuse the USB layer,
                 * and we could go in recursion and blow the kernel stack...
@@ -504,7 +504,7 @@ static void write_bulk_callback(purb_t purb)
        }
 
        /* urb is now available */
-       purb->status = 0;
+       urb->status = 0;
 
        /* If the network is closed, stop everything */
        if ((!self->netopen) || (!self->present)) {
@@ -534,7 +534,7 @@ static void write_bulk_callback(purb_t purb)
 static void irda_usb_net_timeout(struct net_device *netdev)
 {
        struct irda_usb_cb *self = netdev->priv;
-       purb_t purb;
+       struct urb *urb;
        int     done = 0;       /* If we have made any progress */
 
        IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
@@ -546,13 +546,13 @@ static void irda_usb_net_timeout(struct net_device *netdev)
        }
 
        /* Check speed URB */
-       purb = &(self->speed_urb);
-       if (purb->status != 0) {
-               IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
+       urb = &(self->speed_urb);
+       if (urb->status != 0) {
+               IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
-               switch (purb->status) {
+               switch (urb->status) {
                case -EINPROGRESS:
-                       usb_unlink_urb(purb);
+                       usb_unlink_urb(urb);
                        /* Note : above will  *NOT* call netif_wake_queue()
                         * in completion handler, we will come back here.
                         * Jean II */
@@ -563,7 +563,7 @@ static void irda_usb_net_timeout(struct net_device *netdev)
                case -ETIMEDOUT:                /* -110 */
                case -ENOENT:                   /* -2 (urb unlinked by us)  */
                default:                        /* ??? - Play safe */
-                       purb->status = 0;
+                       urb->status = 0;
                        netif_wake_queue(self->netdev);
                        done = 1;
                        break;
@@ -571,11 +571,11 @@ static void irda_usb_net_timeout(struct net_device *netdev)
        }
 
        /* Check Tx URB */
-       purb = &(self->tx_urb);
-       if (purb->status != 0) {
-               struct sk_buff *skb = purb->context;
+       urb = &(self->tx_urb);
+       if (urb->status != 0) {
+               struct sk_buff *skb = urb->context;
 
-               IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
+               IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
                /* Increase error count */
                self->stats.tx_errors++;
@@ -589,11 +589,11 @@ static void irda_usb_net_timeout(struct net_device *netdev)
                irda_usb_change_speed_xbofs(self);
 #endif /* IU_BUG_KICK_TIMEOUT */
 
-               switch (purb->status) {
+               switch (urb->status) {
                case -EINPROGRESS:
-                       usb_unlink_urb(purb);
+                       usb_unlink_urb(urb);
                        /* Note : above will  *NOT* call netif_wake_queue()
-                        * in completion handler, because purb->status will
+                        * in completion handler, because urb->status will
                         * be -ENOENT. We will fix that at the next watchdog,
                         * leaving more time to USB to recover...
                         * Also, we are in interrupt, so we need to have
@@ -608,9 +608,9 @@ static void irda_usb_net_timeout(struct net_device *netdev)
                default:                        /* ??? - Play safe */
                        if(skb != NULL) {
                                dev_kfree_skb_any(skb);
-                               purb->context = NULL;
+                               urb->context = NULL;
                        }
-                       purb->status = 0;
+                       urb->status = 0;
                        netif_wake_queue(self->netdev);
                        done = 1;
                        break;
@@ -685,7 +685,7 @@ static void irda_usb_net_timeout(struct net_device *netdev)
  *
  * Jean II
  */
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb)
 {
        struct irda_skb_cb *cb;
        int ret;
@@ -693,8 +693,8 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_
        IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
        /* Check that we have an urb */
-       if (!purb) {
-               WARNING(__FUNCTION__ "(), Bug : purb == NULL\n");
+       if (!urb) {
+               WARNING(__FUNCTION__ "(), Bug : urb == NULL\n");
                return;
        }
 
@@ -720,17 +720,17 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_
        cb->context = self;
 
        /* Reinitialize URB */
-       FILL_BULK_URB(purb, self->usbdev, 
+       FILL_BULK_URB(urb, self->usbdev, 
                      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 
                      skb->data, skb->truesize,
                       irda_usb_receive, skb);
-       purb->transfer_flags = USB_QUEUE_BULK;
+       urb->transfer_flags = USB_QUEUE_BULK;
        /* Note : unlink *must* be synchronous because of the code in 
         * irda_usb_net_close() -> free the skb - Jean II */
-       purb->status = 0;
-       purb->next = NULL;      /* Don't auto resubmit URBs */
+       urb->status = 0;
+       urb->next = NULL;       /* Don't auto resubmit URBs */
        
-       ret = usb_submit_urb(purb);
+       ret = usb_submit_urb(urb);
        if (ret) {
                /* If this ever happen, we are in deep s***.
                 * Basically, the Rx path will stop... */
@@ -740,19 +740,19 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_
 
 /*------------------------------------------------------------------*/
 /*
- * Function irda_usb_receive(purb)
+ * Function irda_usb_receive(urb)
  *
  *     Called by the USB subsystem when a frame has been received
  *
  */
-static void irda_usb_receive(purb_t purb) 
+static void irda_usb_receive(struct urb *urb) 
 {
-       struct sk_buff *skb = (struct sk_buff *) purb->context;
+       struct sk_buff *skb = (struct sk_buff *) urb->context;
        struct irda_usb_cb *self; 
        struct irda_skb_cb *cb;
        struct sk_buff *new;
        
-       IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length);
+       IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", urb->actual_length);
        
        /* Find ourselves */
        cb = (struct irda_skb_cb *) skb->cb;
@@ -768,27 +768,27 @@ static void irda_usb_receive(purb_t purb)
        }
        
        /* Check the status */
-       if (purb->status != 0) {
-               switch (purb->status) {
+       if (urb->status != 0) {
+               switch (urb->status) {
                case -EILSEQ:
                        self->stats.rx_errors++;
                        self->stats.rx_crc_errors++;    
                        break;
                case -ECONNRESET:               /* -104 */
-                       IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags);
+                       IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", urb->transfer_flags);
                        /* uhci_cleanup_unlink() is going to kill the Rx
                         * URB just after we return. No problem, at this
                         * point the URB will be idle ;-) - Jean II */
                        break;
                default:
-                       IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags);
+                       IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", urb->status, urb->transfer_flags);
                        break;
                }
                goto done;
        }
        
        /* Check for empty frames */
-       if (purb->actual_length <= USB_IRDA_HEADER) {
+       if (urb->actual_length <= USB_IRDA_HEADER) {
                WARNING(__FUNCTION__ "(), empty frame!\n");
                goto done;
        }
@@ -801,7 +801,7 @@ static void irda_usb_receive(purb_t purb)
         get_fast_time(&self->stamp);
 
        /* Fix skb, and remove USB-IrDA header */
-       skb_put(skb, purb->actual_length);
+       skb_put(skb, urb->actual_length);
        skb_pull(skb, USB_IRDA_HEADER);
 
        /* Don't waste a lot of memory on small IrDA frames */
@@ -834,7 +834,7 @@ static void irda_usb_receive(purb_t purb)
         netif_rx(new);
 
 done:
-       /* Note : at this point, the URB we've just received (purb)
+       /* Note : at this point, the URB we've just received (urb)
         * is still referenced by the USB layer. For example, if we
         * have received a -ECONNRESET, uhci_cleanup_unlink() will
         * continue to process it (in fact, cleaning it up).
@@ -848,8 +848,8 @@ done:
        /* Submit the idle URB to replace the URB we've just received */
        irda_usb_submit(self, skb, self->idle_rx_urb);
        /* Recycle Rx URB : Now, the idle URB is the present one */
-       self->idle_rx_urb = purb;
-       purb->context = NULL;
+       self->idle_rx_urb = urb;
+       urb->context = NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -992,14 +992,14 @@ static int irda_usb_net_close(struct net_device *netdev)
 
        /* Deallocate all the Rx path buffers (URBs and skb) */
        for (i = 0; i < IU_MAX_RX_URBS; i++) {
-               purb_t purb = &(self->rx_urb[i]);
-               struct sk_buff *skb = (struct sk_buff *) purb->context;
+               struct urb *urb = &(self->rx_urb[i]);
+               struct sk_buff *skb = (struct sk_buff *) urb->context;
                /* Cancel the receive command */
-               usb_unlink_urb(purb);
+               usb_unlink_urb(urb);
                /* The skb is ours, free it */
                if(skb) {
                        dev_kfree_skb(skb);
-                       purb->context = NULL;
+                       urb->context = NULL;
                }
        }
        /* Cancel Tx and speed URB */
index 03c48321a4e2b82a7475dade0c00d9d2fbb7c62e..d27aa6f63783054a5e9893a9c4331380dcc3f157 100644 (file)
@@ -558,7 +558,7 @@ static int unbind_request(int i, bind_info_t *bind_info)
 
 static int ds_open(struct inode *inode, struct file *file)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -590,7 +590,7 @@ static int ds_open(struct inode *inode, struct file *file)
 
 static int ds_release(struct inode *inode, struct file *file)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     user_info_t *user, **link;
 
@@ -622,7 +622,7 @@ out:
 static ssize_t ds_read(struct file *file, char *buf,
                       size_t count, loff_t *ppos)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -651,7 +651,7 @@ static ssize_t ds_read(struct file *file, char *buf,
 static ssize_t ds_write(struct file *file, const char *buf,
                        size_t count, loff_t *ppos)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -684,7 +684,7 @@ static ssize_t ds_write(struct file *file, const char *buf,
 /* No kernel lock - fine */
 static u_int ds_poll(struct file *file, poll_table *wait)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -707,7 +707,7 @@ static u_int ds_poll(struct file *file, poll_table *wait)
 static int ds_ioctl(struct inode * inode, struct file * file,
                    u_int cmd, u_long arg)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     u_int size;
     int ret, err;
index 6224a23897ad16263081404064ed472659a76499..f1deb2a35e805b313e11621b8e268df73186b3b5 100644 (file)
@@ -88,7 +88,6 @@ do { \
        major:D_MAJOR, \
        major_name:D_NAME, \
        minor_shift:D_PARTN_BITS, \
-       max_p:1 << D_PARTN_BITS, \
        max_nr:D_PER_MAJOR, \
        nr_real:D_PER_MAJOR,
 static inline struct request * 
@@ -111,7 +110,6 @@ do { \
        major:D_MAJOR, \
        major_name:D_NAME, \
        minor_shift:D_PARTN_BITS, \
-       max_p:1 << D_PARTN_BITS, \
        nr_real:D_PER_MAJOR, \
         fops:&dasd_device_operations, 
 static inline struct request * 
index 317f21858c1fade858282eab53a9c8d94c65c753..aea6ca3b6bfbdb20f45f77c6286373fa8b1c8add 100644 (file)
@@ -385,7 +385,7 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
        if (req->waiting)
                complete(req->waiting);
 
-       add_blkdev_randomness(MAJOR(req->rq_dev));
+       add_blkdev_randomness(major(req->rq_dev));
 
        /*
         * This will goose the queue request function at the end, so we don't
@@ -744,7 +744,7 @@ struct Scsi_Device_Template *scsi_get_request_dev(struct request *req)
 {
        struct Scsi_Device_Template *spnt;
        kdev_t dev = req->rq_dev;
-       int major = MAJOR(dev);
+       int major = major(dev);
 
        for (spnt = scsi_devicelist; spnt; spnt = spnt->next) {
                /*
index 148ec5fcf50b92804f290a7d8a71185c1f64468e..367d9716a27dd986b1b31e6da9a844e10f4a250c 100644 (file)
@@ -29,7 +29,7 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds
 unsigned char *scsi_bios_ptable(kdev_t dev)
 {
        unsigned char *res = kmalloc(66, GFP_KERNEL);
-       kdev_t rdev = MKDEV(MAJOR(dev), MINOR(dev) & ~0xf);
+       kdev_t rdev = mk_kdev(major(dev), minor(dev) & ~0x0f);
 
        if (res) {
                struct buffer_head *bh = bread(rdev, 0, block_size(rdev));
index 51e53faabd838825f40d730284c3b20ed40b3859..087b25b0d766434ea4d90debbaf4847cf9c50ba2 100644 (file)
@@ -66,7 +66,7 @@
 #define SCSI_DISKS_PER_MAJOR   16
 #define SD_MAJOR_NUMBER(i)     SD_MAJOR((i) >> 8)
 #define SD_MINOR_NUMBER(i)     ((i) & 255)
-#define MKDEV_SD_PARTITION(i)  MKDEV(SD_MAJOR_NUMBER(i), (i) & 255)
+#define MKDEV_SD_PARTITION(i)  mk_kdev(SD_MAJOR_NUMBER(i), (i) & 255)
 #define MKDEV_SD(index)                MKDEV_SD_PARTITION((index) << 4)
 #define N_USED_SD_MAJORS       (1 + ((sd_template.dev_max - 1) >> 4))
 
@@ -569,7 +569,6 @@ static struct gendisk sd_gendisk =
        major:          SCSI_DISK0_MAJOR,
        major_name:     "sd",
        minor_shift:    4,
-       max_p:          1 << 4,
        fops:           &sd_fops,
 };
 
@@ -1116,7 +1115,7 @@ static int sd_init()
        }
 
        for (i = 0; i < N_USED_SD_MAJORS; i++) {
-               request_queue_t *q = blk_get_queue(SD_MAJOR(i));
+               request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(i), 0));
                int parts_per_major = (SCSI_DISKS_PER_MAJOR << 4);
 
                blksize_size[SD_MAJOR(i)] =
@@ -1141,12 +1140,9 @@ static int sd_init()
                sd_gendisks[i].major = SD_MAJOR(i);
                sd_gendisks[i].major_name = "sd";
                sd_gendisks[i].minor_shift = 4;
-               sd_gendisks[i].max_p = 1 << 4;
                sd_gendisks[i].part = sd + i * (N << 4);
                sd_gendisks[i].sizes = sd_sizes + i * (N << 4);
                sd_gendisks[i].nr_real = 0;
-               sd_gendisks[i].real_devices =
-                   (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
        }
 
        return 0;
@@ -1309,7 +1305,7 @@ static void sd_detach(Scsi_Device * SDp)
        for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
                if (dpnt->device == SDp) {
 
-                       max_p = sd_gendisk.max_p;
+                       max_p = 1 << sd_gendisk.minor_shift;
                        start = i << sd_gendisk.minor_shift;
                        dev = MKDEV_SD_PARTITION(start);
                        wipe_partitions(dev);
index ce9c94440fe79f89bbbd117ec57d7d98d68c92a7..7e12f2696e057ad5553e2e3e80b8995c81d4bfdc 100644 (file)
@@ -45,7 +45,7 @@ extern kdev_t sd_find_target(void *host, int tgt);
 #define N_SD_MAJORS    8
 
 #define SD_MAJOR_MASK  (N_SD_MAJORS - 1)
-#define SD_PARTITION(i)                (((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255))
+#define SD_PARTITION(i)                (((major(i) & SD_MAJOR_MASK) << 8) | (minor(i) & 255))
 
 #endif
 
index e8c91abe09a5b5b8b5187f9354b631c0a4eeea46..40454961d3d579a6ee1db3eaf1775a43c919a5ee 100644 (file)
  *  03/01/1998
  *
  *  WD7000 driver now work on kernels >= 2.1.x
+ *
+ *
+ * 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * use host->host_lock, not io_request_lock, cleanups
  */
 
 #include <linux/module.h>
 
 #define ANY2SCSI_INLINE                /* undef this to use old macros */
 #undef  WD7000_DEBUG           /* general debug                */
+#ifdef WD7000_DEBUG
+#define dprintk printk
+#else
+#define dprintk(format,args...)
+#endif
 
 #include "wd7000.h"
 #include <linux/stat.h>
@@ -557,7 +567,7 @@ typedef union icb {
 } Icb;
 
 #ifdef MODULE
-static char * wd7000 = NULL;
+static char *wd7000;
 MODULE_PARM(wd7000, "s");
 #endif
 
@@ -568,23 +578,23 @@ MODULE_PARM(wd7000, "s");
  *  structure is not part of the Adapter structure.
  */
 static Scb scbs[MAX_SCBS];
-static Scb *scbfree = NULL;    /* free list         */
+static Scb *scbfree;           /* free list         */
 static int freescbs = MAX_SCBS;        /* free list counter */
 
 /*
  *  END of data/declarations - code follows.
  */
-static void setup_error (char *mesg, int *ints)
+static void __init setup_error(char *mesg, int *ints)
 {
     if (ints[0] == 3)
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
-                ints[1], ints[2], ints[3], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
+               ints[1], ints[2], ints[3], mesg);
     else if (ints[0] == 4)
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
-                ints[1], ints[2], ints[3], ints[4], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
+               ints[1], ints[2], ints[3], ints[4], mesg);
     else
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
-                ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
+               ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
 }
 
 
@@ -604,21 +614,23 @@ static void setup_error (char *mesg, int *ints)
  */
 static int __init wd7000_setup(char *str)
 {
-       static short wd7000_card_num = 0;
-       short i, j;
+       static short wd7000_card_num; /* .bss will zero this */
+       short i;
        int ints[6];
 
        (void)get_options(str, ARRAY_SIZE(ints), ints);
 
        if (wd7000_card_num >= NUM_CONFIGS) {
-               printk("wd7000_setup: Too many \"wd7000=\" configurations in "
-               "command line!\n");
+               printk(KERN_ERR __FUNCTION__
+                       ": Too many \"wd7000=\" configurations in "
+                       "command line!\n");
                return 0;
        }
 
        if ((ints[0] < 3) || (ints[0] > 5)) {
-               printk("wd7000_setup: Error in command line!  "
-               "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>[,<BUS_OFF>]]\n");
+               printk(KERN_ERR __FUNCTION__ ": Error in command line!  "
+                       "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>"
+                       "[,<BUS_OFF>]]\n");
        } else {
                for (i = 0; i < NUM_IRQS; i++)
                        if (ints[1] == wd7000_irq[i])
@@ -652,7 +664,8 @@ static int __init wd7000_setup(char *str)
 
                if (ints[0] > 3) {
                        if ((ints[4] < 500) || (ints[4] > 31875)) {
-                               setup_error("BUS_ON value is out of range (500 to 31875 nanoseconds)!", ints);
+                               setup_error("BUS_ON value is out of range (500"
+                                           " to 31875 nanoseconds)!", ints);
                                configs[wd7000_card_num].bus_on = BUS_ON;
                        } else
                                configs[wd7000_card_num].bus_on = ints[4] / 125;
@@ -661,36 +674,47 @@ static int __init wd7000_setup(char *str)
 
                if (ints[0] > 4) {
                        if ((ints[5] < 500) || (ints[5] > 31875)) {
-                               setup_error("BUS_OFF value is out of range (500 to 31875 nanoseconds)!", ints);
+                               setup_error("BUS_OFF value is out of range (500"
+                                           " to 31875 nanoseconds)!", ints);
                                configs[wd7000_card_num].bus_off = BUS_OFF;
                        } else
-                               configs[wd7000_card_num].bus_off = ints[5] / 125;
+                               configs[wd7000_card_num].bus_off = ints[5] /
+                                                                  125;
                } else
                        configs[wd7000_card_num].bus_off = BUS_OFF;
 
                if (wd7000_card_num) {
-                       for (i = 0; i < (wd7000_card_num - 1); i++)
-                               for (j = i + 1; j < wd7000_card_num; j++)
+                       for (i = 0; i < (wd7000_card_num - 1); i++) {
+                               int j = i + 1;
+
+                               for (; j < wd7000_card_num; j++)
                                        if (configs[i].irq == configs[j].irq) {
-                                               setup_error("duplicated IRQ!", ints);
+                                               setup_error("duplicated IRQ!",
+                                                           ints);
                                                return 0;
-                                       } else if (configs[i].dma == configs[j].dma) {
-                                               setup_error("duplicated DMA channel!", ints);
+                                       }
+                                       if (configs[i].dma == configs[j].dma) {
+                                               setup_error("duplicated DMA "
+                                                           "channel!", ints);
                                                return 0;
-                                       } else if (configs[i].iobase == configs[j].iobase) {
-                                               setup_error ("duplicated I/O base address!", ints);
+                                       }
+                                       if (configs[i].iobase ==
+                                           configs[j].iobase) {
+                                               setup_error("duplicated I/O "
+                                                           "base address!",
+                                                           ints);
                                                return 0;
                                        }
+                       }
                }
 
-#ifdef WD7000_DEBUG
-               printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",
+               dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
+                                 "BUS_ON=%dns, BUS_OFF=%dns\n",
                        configs[wd7000_card_num].irq,
                        configs[wd7000_card_num].dma,
                        configs[wd7000_card_num].iobase,
                        configs[wd7000_card_num].bus_on * 125,
                        configs[wd7000_card_num].bus_off * 125);
-#endif
 
                wd7000_card_num++;
        }
@@ -811,7 +835,7 @@ static inline int command_out (Adapter * host, unchar * cmd, int len)
        return (1);
     }
 
-    printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1);
+    printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
 
     return (0);
 }
@@ -827,7 +851,7 @@ static inline int command_out (Adapter * host, unchar * cmd, int len)
  *  the satisfiability of a request is not dependent on the size of the
  *  request.
  */
-static inline Scb *alloc_scbs (int needed)
+static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
 {
     register Scb *scb, *p;
     register unsigned long flags;
@@ -842,18 +866,18 @@ static inline Scb *alloc_scbs (int needed)
     save_flags (flags);
     cli ();
     while (busy) {             /* someone else is allocating */
-       spin_unlock_irq(&io_request_lock);
+       spin_unlock_irq(&host->host_lock);
        for (now = jiffies; now == jiffies; );  /* wait a jiffy */
-       spin_lock_irq(&io_request_lock);
+       spin_lock_irq(&host->host_lock);
     }
     busy = 1;                  /* not busy now; it's our turn */
 
     while (freescbs < needed) {
        timeout = jiffies + WAITnexttimeout;
        do {
-           spin_unlock_irq(&io_request_lock);
+           spin_unlock_irq(&host->host_lock);
            for (now = jiffies; now == jiffies; );      /* wait a jiffy */
-           spin_lock_irq(&io_request_lock);
+           spin_lock_irq(&host->host_lock);
        } while (freescbs < needed && time_before_eq(jiffies, timeout));
        /*
         *  If we get here with enough free Scbs, we can take them.
@@ -929,9 +953,7 @@ static int mail_out (Adapter *host, Scb *scbptr)
     Mailbox *ogmbs = host->mb.ogmb;
     int *next_ogmb = &(host->next_ogmb);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_mail_out: 0x%06lx", (long) scbptr);
-#endif
+    dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
 
     /* We first look for a free outgoing mailbox */
     save_flags (flags);
@@ -939,9 +961,7 @@ static int mail_out (Adapter *host, Scb *scbptr)
     ogmb = *next_ogmb;
     for (i = 0; i < OGMB_CNT; i++) {
        if (ogmbs[ogmb].status == 0) {
-#ifdef WD7000_DEBUG
-           printk (" using OGMB 0x%x", ogmb);
-#endif
+           dprintk(" using OGMB 0x%x", ogmb);
            ogmbs[ogmb].status = 1;
            any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
 
@@ -953,9 +973,7 @@ static int mail_out (Adapter *host, Scb *scbptr)
     }
     restore_flags (flags);
 
-#ifdef WD7000_DEBUG
-    printk (", scb is 0x%06lx", (long) scbptr);
-#endif
+    dprintk(", scb is 0x%06lx", (long) scbptr);
 
     if (i >= OGMB_CNT) {
        /*
@@ -966,9 +984,7 @@ static int mail_out (Adapter *host, Scb *scbptr)
         *  that marks OGMB's free, waiting even with interrupts off
         *  should work, since they are freed very quickly in most cases.
         */
-#ifdef WD7000_DEBUG
-       printk (", no free OGMBs.\n");
-#endif
+       dprintk(", no free OGMBs.\n");
        return (0);
     }
 
@@ -977,9 +993,7 @@ static int mail_out (Adapter *host, Scb *scbptr)
     start_ogmb = START_OGMB | ogmb;
     command_out (host, &start_ogmb, 1);
 
-#ifdef WD7000_DEBUG
-    printk (", awaiting interrupt.\n");
-#endif
+    dprintk(", awaiting interrupt.\n");
 
     return (1);
 }
@@ -1026,7 +1040,7 @@ int make_code (unsigned hosterr, unsigned scsierr)
     }
 #ifdef WD7000_DEBUG
     if (scsierr || hosterr)
-       printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
+       dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
                scsierr, in_error, hosterr);
 #endif
     return (scsierr | (hosterr << 16));
@@ -1035,10 +1049,7 @@ int make_code (unsigned hosterr, unsigned scsierr)
 
 static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
 {
-#ifdef WD7000_DEBUG
-    printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);
-#endif
-
+    dprintk("wd7000_scsi_done: 0x%06lx\n", (long)SCpnt);
     SCpnt->SCp.phase = 0;
 }
 
@@ -1057,15 +1068,11 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
 
     host->int_counter++;
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
-#endif
+    dprintk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
 
     flag = inb (host->iobase + ASC_INTR_STAT);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
-#endif
+    dprintk("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
 
     if (!(inb (host->iobase + ASC_STAT) & INT_IM)) {
        /* NB: these are _very_ possible if IRQ 15 is being used, since
@@ -1076,9 +1083,7 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
         * can sort these out.  Otherwise, electrical noise and other such
         * problems would be indistinguishable from valid interrupts...
         */
-#ifdef WD7000_DEBUG
-       printk ("wd7000_intr_handle: phantom interrupt...\n");
-#endif
+       dprintk("wd7000_intr_handle: phantom interrupt...\n");
        wd7000_intr_ack (host);
        return;
     }
@@ -1086,9 +1091,7 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
     if (flag & MB_INTR) {
        /* The interrupt is for a mailbox */
        if (!(flag & IMB_INTR)) {
-#ifdef WD7000_DEBUG
-           printk ("wd7000_intr_handle: free outgoing mailbox\n");
-#endif
+           dprintk("wd7000_intr_handle: free outgoing mailbox\n");
            /*
             * If sleep_on() and the "interrupt on free OGMB" command are
             * used in mail_out(), wake_up() should correspondingly be called
@@ -1102,10 +1105,8 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
            icmb = flag & MB_MASK;
            icmb_status = icmbs[icmb].status;
            if (icmb_status & 0x80) {   /* unsolicited - result in ICMB */
-#ifdef WD7000_DEBUG
-               printk ("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
+               dprintk("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
                        icmb_status);
-#endif
                wd7000_intr_ack (host);
                return;
            }
@@ -1135,18 +1136,17 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
 
     wd7000_intr_ack (host);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: return from interrupt handler\n");
-#endif
+    dprintk("wd7000_intr_handle: return from interrupt handler\n");
 }
 
 void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
 {
     unsigned long flags;
+    struct Scsi_Host *host = dev_id;
 
-    spin_lock_irqsave(&io_request_lock, flags);
+    spin_lock_irqsave(&host->host_lock, flags);
     wd7000_intr_handle(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(&host->host_lock, flags);
 }
 
 
@@ -1163,7 +1163,7 @@ int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
     idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
     SCpnt->scsi_done = done;
     SCpnt->SCp.phase = 1;
-    scb = alloc_scbs (1);
+    scb = alloc_scbs(SCpnt->host, 1);
     scb->idlun = idlun;
     memcpy (scb->cdb, cdb, cdblen);
     scb->direc = 0x40;         /* Disable direction check */
@@ -1179,9 +1179,7 @@ int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
        if (SCpnt->host->sg_tablesize == SG_NONE) {
            panic ("wd7000_queuecommand: scatter/gather not supported.\n");
        }
-#ifdef WD7000_DEBUG
-       printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
-#endif
+       dprintk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
 
        sgb = scb->sgb;
        scb->op = 1;
@@ -1367,14 +1365,12 @@ int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host)
     save_flags (flags);
     cli ();
 
-#ifdef WD7000_DEBUG
-    printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length);
-#endif
+    dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
 
     /*
      * Currently this is a no-op
      */
-    printk ("Sorry, this function is currently out of order...\n");
+    dprintk("Sorry, this function is currently out of order...\n");
 
     restore_flags (flags);
 
@@ -1521,9 +1517,7 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
     Adapter *host = NULL;
     struct Scsi_Host *sh;
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_detect: started\n");
-#endif
+    dprintk("wd7000_detect: started\n");
 
 #ifdef MODULE
        if (wd7000)
@@ -1573,12 +1567,12 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
         * BIOS SIGNATURE has been found.
         */
 #ifdef WD7000_DEBUG
-       printk ("wd7000_detect: pass %d\n", pass + 1);
+       dprintk("wd7000_detect: pass %d\n", pass + 1);
 
        if (biosaddr_ptr == NUM_ADDRS)
-           printk ("WD-7000 SST BIOS not detected...\n");
+           dprintk("WD-7000 SST BIOS not detected...\n");
        else
-           printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
+           dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
                    wd7000_biosaddr[biosaddr_ptr]);
 #endif
 
@@ -1587,15 +1581,11 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
 
        iobase = configs[pass].iobase;
 
-#ifdef WD7000_DEBUG
-       printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
-#endif
+       dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
 
        if (request_region (iobase, 4, "wd7000")) {
 
-#ifdef WD7000_DEBUG
-           printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
-#endif
+           dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
            /*
             * ASC reset...
             */
@@ -1603,17 +1593,11 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
            delay (1);
            outb (0, iobase + ASC_CONTROL);
 
-           if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
-#ifdef WD7000_DEBUG
-           {
-               printk ("failed!\n");
+           if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+               dprintk("failed!\n");
                goto err_release;
-           }
-           else 
-               printk ("ok!\n");
-#else
-           goto err_release;
-#endif
+           } else 
+               dprintk("ok!\n");
 
            if (inb (iobase + ASC_INTR_STAT) == 1) {
                /*
@@ -1629,10 +1613,8 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
 
                host = (Adapter *) sh->hostdata;
 
-#ifdef WD7000_DEBUG
-               printk ("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
-#endif
-
+               dprintk("wd7000_detect: adapter allocated at 0x%x\n",
+                       (int)host);
                memset (host, 0, sizeof (Adapter));
 
                host->irq = configs[pass].irq;
@@ -1643,11 +1625,9 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
                host->bus_off = configs[pass].bus_off;
                host->sh = wd7000_host[host->irq - IRQ_MIN] = sh;
 
-#ifdef WD7000_DEBUG
-               printk ("wd7000_detect: Trying init WD-7000 card at IO "
+               dprintk("wd7000_detect: Trying init WD-7000 card at IO "
                        "0x%x, IRQ %d, DMA %d...\n",
                        host->iobase, host->irq, host->dma);
-#endif
 
                if (!wd7000_init (host))        /* Initialization failed */
                    goto err_unregister;
@@ -1675,12 +1655,9 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
                 printk ("  BUS_ON time: %dns, BUS_OFF time: %dns\n",
                         host->bus_on * 125, host->bus_off * 125);
            }
-       }
-
-#ifdef WD7000_DEBUG
-       else
-           printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
-#endif
+       } else
+               dprintk("wd7000_detect: IO 0x%x region already allocated!\n",
+                       iobase);
 
        continue;
 
@@ -1730,9 +1707,8 @@ int wd7000_reset (Scsi_Cmnd *SCpnt, unsigned int unused)
  */
 int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
 {
-#ifdef WD7000_DEBUG
-    printk ("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity);
-#endif
+    dprintk("wd7000_biosparam: dev=%s, size=%d, ", kdevname(dev),
+           disk->capacity);
 
     /*
      * try default translation
@@ -1766,14 +1742,13 @@ int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
            ip[2] = info[2];
 
            if (info[0] == 255)
-               printk ("wd7000_biosparam: current partition table is using extended translation.\n");
+               printk(KERN_INFO __FUNCTION__ ": current partition table is "
+                       "using extended translation.\n");
        }
     }
 
-#ifdef WD7000_DEBUG
-    printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
-    printk ("WARNING: check, if the bios geometry is correct.\n");
-#endif
+    dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
+    dprintk("WARNING: check, if the bios geometry is correct.\n");
 
     return (0);
 }
index f685c5b1ec99edfc5848cbb062fb13662ae33432..53922db7d581613f075726a5dffe0a260848c3e5 100644 (file)
@@ -1213,7 +1213,7 @@ static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned lon
 
 static int es1371_open_mixdev(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        struct list_head *list;
        struct es1371_state *s;
 
@@ -1913,7 +1913,7 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 
 static int es1371_open(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        struct list_head *list;
@@ -2342,7 +2342,7 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int
 
 static int es1371_open_dac(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        struct list_head *list;
@@ -2584,7 +2584,7 @@ static unsigned int es1371_midi_poll(struct file *file, struct poll_table_struct
 
 static int es1371_midi_open(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        struct list_head *list;
index de05ee691ab28adeee361614e84be8e5aa500891..9fd55621ad240438e6a330ae06cf438076cd1894 100644 (file)
@@ -478,7 +478,7 @@ static struct sound_unit *__look_for_unit(int chain, int unit)
 int soundcore_open(struct inode *inode, struct file *file)
 {
        int chain;
-       int unit=MINOR(inode->i_rdev);
+       int unit = minor(inode->i_rdev);
        struct sound_unit *s;
        struct file_operations *new_fops = NULL;
 
index 593e4671d98979c2e1388c5e6a6f834a2e677a90..26a6a40c3d065801ba51b9d7bd4809338b7fc5ed 100644 (file)
@@ -833,7 +833,7 @@ static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int s
        }
 }              
 
-static int usbin_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
 {
        unsigned int i, maxsize, offs;
 
@@ -850,7 +850,7 @@ static int usbin_prepare_desc(struct usbin *u, purb_t urb)
  * return value: 0 if descriptor should be restarted, -1 otherwise
  * convert sample format on the fly if necessary
  */
-static int usbin_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_retire_desc(struct usbin *u, struct urb *urb)
 {
        unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
        unsigned char *cp;
@@ -930,7 +930,7 @@ static void usbin_completed(struct urb *urb)
 /*
  * we output sync data
  */
-static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
 {
        unsigned char *cp = urb->transfer_buffer;
        unsigned int i, offs;
@@ -948,7 +948,7 @@ static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb)
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbin_sync_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
 {
        unsigned int i;
        
@@ -996,7 +996,7 @@ static int usbin_start(struct usb_audiodev *as)
 {
        struct usb_device *dev = as->state->usbdev;
        struct usbin *u = &as->usbin;
-       purb_t urb;
+       struct urb *urb;
        unsigned long flags;
        unsigned int maxsze, bufsz;
 
@@ -1186,7 +1186,7 @@ static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int
        }
 }              
 
-static int usbout_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
 {
        unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
        unsigned char *cp = urb->transfer_buffer;
@@ -1238,7 +1238,7 @@ static int usbout_prepare_desc(struct usbout *u, purb_t urb)
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_retire_desc(struct usbout *u, struct urb *urb)
 {
        unsigned int i;
 
@@ -1285,7 +1285,7 @@ static void usbout_completed(struct urb *urb)
        spin_unlock_irqrestore(&as->lock, flags);
 }
 
-static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
 {
        unsigned int i, offs;
 
@@ -1299,7 +1299,7 @@ static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb)
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_sync_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
 {
        unsigned char *cp = urb->transfer_buffer;
        unsigned int f, i;
@@ -1361,7 +1361,7 @@ static int usbout_start(struct usb_audiodev *as)
 {
        struct usb_device *dev = as->state->usbdev;
        struct usbout *u = &as->usbout;
-       purb_t urb;
+       struct urb *urb;
        unsigned long flags;
        unsigned int maxsze, bufsz;
 
index 123bbc3224512ca788c56ff1d01852fe19ee929e..1b3d864312aa927231ef5b3afba07647af827046 100644 (file)
@@ -83,24 +83,24 @@ static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_
 }
 /*-------------------------------------------------------------------*/
 #ifdef DEBUG 
-static void dump_urb (purb_t purb)
+static void dump_urb (struct urb *urb)
 {
-       dbg("urb                   :%p", purb);
-       dbg("next                  :%p", purb->next);
-       dbg("dev                   :%p", purb->dev);
-       dbg("pipe                  :%08X", purb->pipe);
-       dbg("status                :%d", purb->status);
-       dbg("transfer_flags        :%08X", purb->transfer_flags);
-       dbg("transfer_buffer       :%p", purb->transfer_buffer);
-       dbg("transfer_buffer_length:%d", purb->transfer_buffer_length);
-       dbg("actual_length         :%d", purb->actual_length);
-       dbg("setup_packet          :%p", purb->setup_packet);
-       dbg("start_frame           :%d", purb->start_frame);
-       dbg("number_of_packets     :%d", purb->number_of_packets);
-       dbg("interval              :%d", purb->interval);
-       dbg("error_count           :%d", purb->error_count);
-       dbg("context               :%p", purb->context);
-       dbg("complete              :%p", purb->complete);
+       dbg("urb                   :%p", urb);
+       dbg("next                  :%p", urb->next);
+       dbg("dev                   :%p", urb->dev);
+       dbg("pipe                  :%08X", urb->pipe);
+       dbg("status                :%d", urb->status);
+       dbg("transfer_flags        :%08X", urb->transfer_flags);
+       dbg("transfer_buffer       :%p", urb->transfer_buffer);
+       dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
+       dbg("actual_length         :%d", urb->actual_length);
+       dbg("setup_packet          :%p", urb->setup_packet);
+       dbg("start_frame           :%d", urb->start_frame);
+       dbg("number_of_packets     :%d", urb->number_of_packets);
+       dbg("interval              :%d", urb->interval);
+       dbg("error_count           :%d", urb->error_count);
+       dbg("context               :%p", urb->context);
+       dbg("complete              :%p", urb->complete);
 }
 #endif
 /*-------------------------------------------------------------------*/
@@ -167,7 +167,7 @@ static int dabusb_free_buffers (pdabusb_t s)
        return 0;
 }
 /*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (purb_t purb)
+static void dabusb_iso_complete (struct urb *purb)
 {
        pbuff_t b = purb->context;
        pdabusb_t s = b->s;
@@ -482,7 +482,7 @@ static ssize_t dabusb_read (struct file *file, char *buf, size_t count, loff_t *
        int rem;
        int cnt;
        pbuff_t b;
-       purb_t purb = NULL;
+       struct urb *purb = NULL;
 
        dbg("dabusb_read");
 
index ddb4d8971573fc32e01c19912b0bf88b72933dfa..9fc09c8a289f19fc87ac827dc9638a859adb6fbd 100644 (file)
@@ -38,7 +38,7 @@ typedef struct
 typedef struct 
 {
        pdabusb_t s;
-       purb_t purb;
+       struct urb *purb;
        struct list_head buff_list;
 } buff_t,*pbuff_t;
 
index f88e4691042daad75bbfa8940d564c26edc2c0e5..ed919d1795b084813d6a3063ac668c217fe3d84e 100644 (file)
@@ -245,7 +245,7 @@ extern __inline__ struct async *async_getpending(struct dev_state *ps, void *use
         return NULL;
 }
 
-static void async_completed(purb_t urb)
+static void async_completed(struct urb *urb)
 {
         struct async *as = (struct async *)urb->context;
         struct dev_state *ps = as->ps;
@@ -471,9 +471,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
         */
        lock_kernel();
        ret = -ENOENT;
-       if (ITYPE(inode->i_ino) != IDEVICE)
-               goto out;
-       dev = inode->u.usbdev_i.p.dev;
+       dev = inode->u.generic_ip;
        if (!dev)
                goto out;
        ret = -ENOMEM;
diff --git a/drivers/usb/hcd.c b/drivers/usb/hcd.c
new file mode 100644 (file)
index 0000000..8ac1048
--- /dev/null
@@ -0,0 +1,1305 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/uts.h>                 /* for UTS_SYSNAME */
+
+#ifndef CONFIG_USB_DEBUG
+       #define CONFIG_USB_DEBUG        /* this is experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver framework
+ *
+ * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
+ * HCD-specific behaviors/bugs.
+ *
+ * This does error checks, tracks devices and urbs, and delegates to a
+ * "hc_driver" only for code (and data) that really needs to know about
+ * hardware differences.  That includes root hub registers, i/o queues,
+ * and so on ... but as little else as possible.
+ *
+ * Shared code includes most of the "root hub" code (these are emulated,
+ * though each HC's hardware works differently) and PCI glue, plus request
+ * tracking overhead.  The HCD code should only block on spinlocks or on
+ * hardware handshaking; blocking on software events (such as other kernel
+ * threads releasing resources, or completing actions) is all generic.
+ *
+ * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
+ * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
+ * only by the hub driver ... and that neither should be seen or used by
+ * usb client device drivers.
+ *
+ * Contributors of ideas or unattributed patches include: David Brownell,
+ * Roman Weissgaerber, Rory Bolt, ...
+ *
+ * HISTORY:
+ * 2001-12-12  Initial patch version for Linux 2.5.1 kernel.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* host controllers we manage */
+static LIST_HEAD (hcd_list);
+
+/* used when updating list of hcds */
+static DECLARE_MUTEX (hcd_list_lock);
+
+/* used when updating hcd data */
+static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+
+static struct usb_operations hcd_operations;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sharable chunks of root hub code.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* usb 2.0 root hub device descriptor */
+static const u8 usb2_rh_dev_descriptor [18] = {
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x00, 0x02, /*  __u16 bcdUSB; v2.0 */
+
+       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  bDeviceSubClass; */
+       0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
+       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+       0x00, 0x00, /*  __u16 idVendor; */
+       0x00, 0x00, /*  __u16 idProduct; */
+       0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+
+       0x03,       /*  __u8  iManufacturer; */
+       0x02,       /*  __u8  iProduct; */
+       0x01,       /*  __u8  iSerialNumber; */
+       0x01        /*  __u8  bNumConfigurations; */
+};
+
+/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
+
+/* usb 1.1 root hub device descriptor */
+static const u8 usb11_rh_dev_descriptor [18] = {
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x10, 0x01, /*  __u16 bcdUSB; v1.1 */
+
+       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  bDeviceSubClass; */
+       0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
+       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+       0x00, 0x00, /*  __u16 idVendor; */
+       0x00, 0x00, /*  __u16 idProduct; */
+       0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+
+       0x03,       /*  __u8  iManufacturer; */
+       0x02,       /*  __u8  iProduct; */
+       0x01,       /*  __u8  iSerialNumber; */
+       0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Configuration descriptor for all our root hubs */
+
+static const u8 rh_config_descriptor [] = {
+
+       /* one configuration */
+       0x09,       /*  __u8  bLength; */
+       0x02,       /*  __u8  bDescriptorType; Configuration */
+       0x19, 0x00, /*  __u16 wTotalLength; */
+       0x01,       /*  __u8  bNumInterfaces; (1) */
+       0x01,       /*  __u8  bConfigurationValue; */
+       0x00,       /*  __u8  iConfiguration; */
+       0x40,       /*  __u8  bmAttributes; 
+                                Bit 7: Bus-powered,
+                                    6: Self-powered,
+                                    5 Remote-wakwup,
+                                    4..0: resvd */
+       0x00,       /*  __u8  MaxPower; */
+      
+       /* USB 1.1:
+        * USB 2.0, single TT organization (mandatory):
+        *      one interface, protocol 0
+        *
+        * USB 2.0, multiple TT organization (optional):
+        *      two interfaces, protocols 1 (like single TT)
+        *      and 2 (multiple TT mode) ... config is
+        *      sometimes settable
+        *      NOT IMPLEMENTED
+        */
+
+       /* one interface */
+       0x09,       /*  __u8  if_bLength; */
+       0x04,       /*  __u8  if_bDescriptorType; Interface */
+       0x00,       /*  __u8  if_bInterfaceNumber; */
+       0x00,       /*  __u8  if_bAlternateSetting; */
+       0x01,       /*  __u8  if_bNumEndpoints; */
+       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  if_bInterfaceSubClass; */
+       0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+       0x00,       /*  __u8  if_iInterface; */
+     
+       /* one endpoint (status change endpoint) */
+       0x07,       /*  __u8  ep_bLength; */
+       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+       0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+       0x0c        /*  __u8  ep_bInterval; (12ms -- usb 2.0 spec) */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *ascii, u8 *utf, int utfmax)
+{
+       int retval;
+
+       for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+               *utf++ = *ascii++ & 0x7f;
+               *utf++ = 0;
+       }
+       return retval;
+}
+
+/*
+ * rh_string - provides manufacturer, product and serial strings for root hub
+ * @id: the string ID number (1: serial number, 2: product, 3: vendor)
+ * @pci_desc: PCI device descriptor for the relevant HC
+ * @type: string describing our driver 
+ * @data: return packet in UTF-16 LE
+ * @len: length of the return packet
+ *
+ * Produces either a manufacturer, product or serial number string for the
+ * virtual root hub device.
+ */
+static int rh_string (
+       int             id,
+       struct pci_dev  *pci_desc,
+       char            *type,
+       u8              *data,
+       int             len
+) {
+       char buf [100];
+
+       // language ids
+       if (id == 0) {
+               *data++ = 4; *data++ = 3;       /* 4 bytes string data */
+               *data++ = 0; *data++ = 0;       /* some language id */
+               return 4;
+
+       // serial number
+       } else if (id == 1) {
+               strcpy (buf, pci_desc->slot_name);
+
+       // product description
+       } else if (id == 2) {
+                strcpy (buf, pci_desc->name);
+
+       // id 3 == vendor description
+       } else if (id == 3) {
+                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type);
+
+       // unsupported IDs --> "protocol stall"
+       } else
+           return 0;
+
+       data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+       data [1] = 3;   /* type == string */
+       return data [0];
+}
+
+
+/* Root hub control transfers execute synchronously */
+static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
+{
+       devrequest      *cmd = (devrequest *) urb->setup_packet;
+       u16             typeReq, wValue, wIndex, wLength;
+       const u8        *bufp = 0;
+       u8              *ubuf = urb->transfer_buffer;
+       int             len = 0;
+
+       typeReq  = (cmd->requesttype << 8) | cmd->request;
+       wValue   = le16_to_cpu (cmd->value);
+       wIndex   = le16_to_cpu (cmd->index);
+       wLength  = le16_to_cpu (cmd->length);
+
+       if (wLength > urb->transfer_buffer_length)
+               goto error;
+
+       /* set up for success */
+       urb->status = 0;
+       urb->actual_length = wLength;
+       switch (typeReq) {
+
+       /* DEVICE REQUESTS */
+
+       case DeviceRequest | USB_REQ_GET_STATUS:
+               // DEVICE_REMOTE_WAKEUP
+               ubuf [0] = 1; // selfpowered
+               ubuf [1] = 0;
+                       /* FALLTHROUGH */
+       case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+       case DeviceOutRequest | USB_REQ_SET_FEATURE:
+               dbg ("no device features yet yet");
+               break;
+       case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+               ubuf [0] = 1;
+                       /* FALLTHROUGH */
+       case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+               break;
+       case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+               switch (wValue & 0xff00) {
+               case USB_DT_DEVICE << 8:
+                       if (hcd->driver->flags & HCD_USB2)
+                               bufp = usb2_rh_dev_descriptor;
+                       else if (hcd->driver->flags & HCD_USB11)
+                               bufp = usb11_rh_dev_descriptor;
+                       else
+                               goto error;
+                       len = 18;
+                       break;
+               case USB_DT_CONFIG << 8:
+                       bufp = rh_config_descriptor;
+                       len = sizeof rh_config_descriptor;
+                       break;
+               case USB_DT_STRING << 8:
+                       urb->actual_length = rh_string (
+                               wValue & 0xff,
+                                hcd->pdev,
+                               (char *) hcd->description,
+                               ubuf, wLength);
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case DeviceRequest | USB_REQ_GET_INTERFACE:
+               ubuf [0] = 0;
+                       /* FALLTHROUGH */
+       case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+               break;
+       case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+               // wValue == urb->dev->devaddr
+               dbg ("%s root hub device address %d",
+                       hcd->bus_name, wValue);
+               break;
+
+       /* INTERFACE REQUESTS (no defined feature/status flags) */
+
+       /* ENDPOINT REQUESTS */
+
+       case EndpointRequest | USB_REQ_GET_STATUS:
+               // ENDPOINT_HALT flag
+               ubuf [0] = 0;
+               ubuf [1] = 0;
+                       /* FALLTHROUGH */
+       case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+       case EndpointOutRequest | USB_REQ_SET_FEATURE:
+               dbg ("no endpoint features yet");
+               break;
+
+       /* CLASS REQUESTS (and errors) */
+
+       default:
+               /* non-generic request */
+               urb->status = hcd->driver->hub_control (hcd,
+                       typeReq, wValue, wIndex,
+                       ubuf, wLength);
+               break;
+error:
+               /* "protocol stall" on error */
+               urb->status = -EPIPE;
+               dbg ("unsupported hub control message (maxchild %d)",
+                               urb->dev->maxchild);
+       }
+       if (urb->status) {
+               urb->actual_length = 0;
+               dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d",
+                       typeReq, wValue, wIndex, wLength, urb->status);
+       }
+       if (bufp) {
+               if (urb->transfer_buffer_length < len)
+                       len = urb->transfer_buffer_length;
+               urb->actual_length = len;
+               // always USB_DIR_IN, toward host
+               memcpy (ubuf, bufp, len);
+       }
+
+       /* any errors get returned through the urb completion */
+       usb_hcd_giveback_urb (hcd, urb);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Root Hub interrupt transfers are synthesized with a timer.
+ * Completions are called in_interrupt() but not in_irq().
+ */
+
+static void rh_report_status (unsigned long ptr);
+
+static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 
+{
+       int     len = 1 + (urb->dev->maxchild / 8);
+
+       /* rh_timer protected by hcd_data_lock */
+       if (timer_pending (&hcd->rh_timer)
+                       || urb->status != -EINPROGRESS
+                       || !HCD_IS_RUNNING (hcd->state)
+                       || urb->transfer_buffer_length < len) {
+               dbg ("not queuing status urb, stat %d", urb->status);
+               return -EINVAL;
+       }
+
+       urb->hcpriv = hcd;      /* nonzero to indicate it's queued */
+       init_timer (&hcd->rh_timer);
+       hcd->rh_timer.function = rh_report_status;
+       hcd->rh_timer.data = (unsigned long) urb;
+       hcd->rh_timer.expires = jiffies
+               + (HZ * (urb->interval < 30
+                               ? 30
+                               : urb->interval)) / 1000;
+       add_timer (&hcd->rh_timer);
+       return 0;
+}
+
+/* timer callback */
+
+static void rh_report_status (unsigned long ptr)
+{
+       struct urb      *urb;
+       struct usb_hcd  *hcd;
+       int             length;
+       unsigned long   flags;
+
+       urb = (struct urb *) ptr;
+       spin_lock_irqsave (&urb->lock, flags);
+       if (!urb->dev) {
+               spin_unlock_irqrestore (&urb->lock, flags);
+               return;
+       }
+
+       hcd = urb->dev->bus->hcpriv;
+       if (urb->status == -EINPROGRESS) {
+               if (HCD_IS_RUNNING (hcd->state)) {
+                       length = hcd->driver->hub_status_data (hcd,
+                                       urb->transfer_buffer);
+                       spin_unlock_irqrestore (&urb->lock, flags);
+                       if (length > 0) {
+                               urb->actual_length = length;
+                               urb->status = 0;
+                               urb->complete (urb);
+                       }
+                       spin_lock_irqsave (&hcd_data_lock, flags);
+                       urb->status = -EINPROGRESS;
+                       if (HCD_IS_RUNNING (hcd->state)
+                                       && rh_status_urb (hcd, urb) != 0) {
+                               /* another driver snuck in? */
+                               dbg ("%s, can't resubmit roothub status urb?",
+                                       hcd->bus_name);
+                               spin_unlock_irqrestore (&hcd_data_lock, flags);
+                               BUG ();
+                       }
+                       spin_unlock_irqrestore (&hcd_data_lock, flags);
+               } else
+                       spin_unlock_irqrestore (&urb->lock, flags);
+       } else {
+               /* this urb's been unlinked */
+               urb->hcpriv = 0;
+               spin_unlock_irqrestore (&urb->lock, flags);
+
+               usb_hcd_giveback_urb (hcd, urb);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
+{
+       if (usb_pipeint (urb->pipe)) {
+               int             retval;
+               unsigned long   flags;
+
+               spin_lock_irqsave (&hcd_data_lock, flags);
+               retval = rh_status_urb (hcd, urb);
+               spin_unlock_irqrestore (&hcd_data_lock, flags);
+               return retval;
+       }
+       if (usb_pipecontrol (urb->pipe))
+               return rh_call_control (hcd, urb);
+       else
+               return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+       unsigned long   flags;
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       del_timer_sync (&hcd->rh_timer);
+       hcd->rh_timer.data = 0;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       /* we rely on RH callback code not unlinking its URB! */
+       usb_hcd_giveback_urb (hcd, urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PCI
+
+/* PCI-based HCs are normal, but custom bus glue should be ok */
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+static void hc_died (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct hc_driver        *driver;
+       unsigned long           resource, len;
+       void                    *base;
+       u8                      latency, limit;
+       struct usb_bus          *bus;
+       struct usb_hcd          *hcd;
+       int                     retval, region;
+       char                    buf [8], *bufp = buf;
+
+       if (!id || !(driver = (struct hc_driver *) id->driver_data))
+               return -EINVAL;
+
+       if (pci_enable_device (dev) < 0)
+               return -ENODEV;
+       
+        if (!dev->irq) {
+               err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
+                       dev->slot_name);
+               return -ENODEV;
+        }
+       
+       if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
+               region = 0;
+               resource = pci_resource_start (dev, 0);
+               len = pci_resource_len (dev, 0);
+               if (!request_mem_region (resource, len, driver->description)) {
+                       dbg ("controller already in use");
+                       return -EBUSY;
+               }
+               base = ioremap_nocache (resource, len);
+               if (base == NULL) {
+                       dbg ("error mapping memory");
+                       retval = -EFAULT;
+clean_1:
+                       release_mem_region (resource, len);
+                       err ("init %s fail, %d", dev->slot_name, retval);
+                       return retval;
+               }
+
+       } else {                                // UHCI
+               resource = len = 0;
+               for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+                       if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+                               continue;
+
+                       resource = pci_resource_start (dev, region);
+                       len = pci_resource_len (dev, region);
+                       if (request_region (resource, len,
+                                       driver->description))
+                               break;
+               }
+               if (region == PCI_ROM_RESOURCE) {
+                       dbg ("no i/o regions available");
+                       return -EBUSY;
+               }
+               base = (void *) resource;
+       }
+
+       // driver->start(), later on, will transfer device from
+       // control by SMM/BIOS to control by Linux (if needed)
+
+       pci_set_master (dev);
+       hcd = driver->hcd_alloc ();
+       if (hcd == NULL){
+               dbg ("hcd alloc fail");
+               retval = -ENOMEM;
+clean_2:
+               if (driver->flags & HCD_MEMORY) {
+                       iounmap (base);
+                       goto clean_1;
+               } else {
+                       release_region (resource, len);
+                       err ("init %s fail, %d", dev->slot_name, retval);
+                       return retval;
+               }
+       }
+       dev->driver_data = hcd;
+       hcd->driver = driver;
+       hcd->description = driver->description;
+       hcd->pdev = dev;
+       info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
+
+       pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+       if (latency) {
+               pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
+               if (limit && limit < latency) {
+                       dbg ("PCI latency reduced to max %d", limit);
+                       pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
+               }
+       }
+
+#ifndef __sparc__
+       sprintf (buf, "%d", dev->irq);
+#else
+       bufp = __irq_itoa(irq);
+#endif
+       if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
+                       != 0) {
+               err ("request interrupt %s failed", bufp);
+               retval = -EBUSY;
+clean_3:
+               driver->hcd_free (hcd);
+               goto clean_2;
+       }
+       hcd->irq = dev->irq;
+
+       hcd->regs = base;
+       hcd->region = region;
+       info ("irq %s, %s %p", bufp,
+               (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
+               base);
+
+// FIXME simpler: make "bus" be that data, not pointer to it.
+       bus = usb_alloc_bus (&hcd_operations);
+       if (bus == NULL) {
+               dbg ("usb_alloc_bus fail");
+               retval = -ENOMEM;
+               free_irq (dev->irq, hcd);
+               goto clean_3;
+       }
+       hcd->bus = bus;
+       hcd->bus_name = dev->slot_name;
+       bus->hcpriv = (void *) hcd;
+
+       INIT_LIST_HEAD (&hcd->dev_list);
+       INIT_LIST_HEAD (&hcd->hcd_list);
+
+       down (&hcd_list_lock);
+       list_add (&hcd->hcd_list, &hcd_list);
+       up (&hcd_list_lock);
+
+       usb_register_bus (bus);
+
+       if ((retval = driver->start (hcd)) < 0)
+               usb_hcd_pci_remove (dev);
+
+       return retval;
+} 
+EXPORT_SYMBOL (usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void usb_hcd_pci_remove (struct pci_dev *dev)
+{
+       struct usb_hcd          *hcd;
+       struct usb_device       *hub;
+
+       hcd = (struct usb_hcd *) dev->driver_data;
+       if (!hcd)
+               return;
+       info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+
+       if (in_interrupt ()) BUG ();
+
+       hub = hcd->bus->root_hub;
+       hcd->state = USB_STATE_QUIESCING;
+
+       dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+       usb_disconnect (&hub);
+       // usb_disconnect (&hcd->bus->root_hub);
+
+       hcd->driver->stop (hcd);
+       hcd->state = USB_STATE_HALT;
+
+       free_irq (hcd->irq, hcd);
+       if (hcd->driver->flags & HCD_MEMORY) {
+               iounmap (hcd->regs);
+               release_mem_region (pci_resource_start (dev, 0),
+                       pci_resource_len (dev, 0));
+       } else {
+               release_region (pci_resource_start (dev, hcd->region),
+                       pci_resource_len (dev, hcd->region));
+       }
+
+       down (&hcd_list_lock);
+       list_del (&hcd->hcd_list);
+       up (&hcd_list_lock);
+
+       usb_deregister_bus (hcd->bus);
+       usb_free_bus (hcd->bus);
+       hcd->bus = NULL;
+
+       hcd->driver->hcd_free (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_remove);
+
+
+#ifdef CONFIG_PM
+
+/*
+ * Some "sleep" power levels imply updating struct usb_driver
+ * to include a callback asking hcds to do their bit by checking
+ * if all the drivers can suspend.  Gets involved with remote wakeup.
+ *
+ * If there are pending urbs, then HCs will need to access memory,
+ * causing extra power drain.  New sleep()/wakeup() PM calls might
+ * be needed, beyond PCI suspend()/resume().  The root hub timer
+ * still be accessing memory though ...
+ *
+ * FIXME:  USB should have some power budgeting support working with
+ * all kinds of hubs.
+ *
+ * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
+ * D1 and D2 states should do something, yes?
+ *
+ * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
+ * for all supported states, so that USB remote wakeup can work for any
+ * devices that support it (and are connected via powered hubs).
+ *
+ * FIXME:  resume doesn't seem to work right any more...
+ */
+
+
+// 2.4 kernels have issued concurrent resumes (w/APM)
+// we defend against that error; PCI doesn't yet.
+
+/**
+ * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
+ * @dev: USB Host Controller being suspended
+ *
+ * Store this function in the HCD's struct pci_driver as suspend().
+ */
+int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+{
+       struct usb_hcd          *hcd;
+       int                     retval;
+
+       hcd = (struct usb_hcd *) dev->driver_data;
+       info ("suspend %s to state %d", hcd->bus_name, state);
+
+       pci_save_state (dev, hcd->pci_state);
+
+       // FIXME for all connected devices, leaf-to-root:
+       // driver->suspend()
+       // proposed "new 2.5 driver model" will automate that
+
+       /* driver may want to disable DMA etc */
+       retval = hcd->driver->suspend (hcd, state);
+       hcd->state = USB_STATE_SUSPENDED;
+
+       pci_set_power_state (dev, state);
+       return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_suspend);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as resume().
+ */
+int usb_hcd_pci_resume (struct pci_dev *dev)
+{
+       struct usb_hcd          *hcd;
+       int                     retval;
+
+       hcd = (struct usb_hcd *) dev->driver_data;
+       info ("resume %s", hcd->bus_name);
+
+       /* guard against multiple resumes (APM bug?) */
+       atomic_inc (&hcd->resume_count);
+       if (atomic_read (&hcd->resume_count) != 1) {
+               err ("concurrent PCI resumes for %s", hcd->bus_name);
+               retval = 0;
+               goto done;
+       }
+
+       retval = -EBUSY;
+       if (hcd->state != USB_STATE_SUSPENDED) {
+               dbg ("can't resume, not suspended!");
+               goto done;
+       }
+       hcd->state = USB_STATE_RESUMING;
+
+       pci_set_power_state (dev, 0);
+       pci_restore_state (dev, hcd->pci_state);
+
+       retval = hcd->driver->resume (hcd);
+       if (!HCD_IS_RUNNING (hcd->state)) {
+               dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+               hc_died (hcd);
+// FIXME:  recover, reset etc.
+       } else {
+               // FIXME for all connected devices, root-to-leaf:
+               // driver->resume ();
+               // proposed "new 2.5 driver model" will automate that
+       }
+
+done:
+       atomic_dec (&hcd->resume_count);
+       return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+#endif /* CONFIG_PM */
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Generic HC operations.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* called from khubd, or root hub init threads for hcd-private init */
+static int hcd_alloc_dev (struct usb_device *udev)
+{
+       struct hcd_dev          *dev;
+       struct usb_hcd          *hcd;
+       unsigned long           flags;
+
+       if (!udev || udev->hcpriv)
+               return -EINVAL;
+       if (!udev->bus || !udev->bus->hcpriv)
+               return -ENODEV;
+       hcd = udev->bus->hcpriv;
+       if (hcd->state == USB_STATE_QUIESCING)
+               return -ENOLINK;
+
+       dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);
+       if (dev == NULL)
+               return -ENOMEM;
+       memset (dev, 0, sizeof *dev);
+
+       INIT_LIST_HEAD (&dev->dev_list);
+       INIT_LIST_HEAD (&dev->urb_list);
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_add (&dev->dev_list, &hcd->dev_list);
+       // refcount is implicit
+       udev->hcpriv = dev;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void hc_died (struct usb_hcd *hcd)
+{
+       struct list_head        *devlist, *urblist;
+       struct hcd_dev          *dev;
+       struct urb              *urb;
+       unsigned long           flags;
+       
+       /* flag every pending urb as done */
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_for_each (devlist, &hcd->dev_list) {
+               dev = list_entry (devlist, struct hcd_dev, dev_list);
+               list_for_each (urblist, &dev->urb_list) {
+                       urb = list_entry (urblist, struct urb, urb_list);
+                       dbg ("shutdown %s urb %p pipe %x, current status %d",
+                               hcd->bus_name, urb, urb->pipe, urb->status);
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = -ESHUTDOWN;
+               }
+       }
+       urb = (struct urb *) hcd->rh_timer.data;
+       if (urb)
+               urb->status = -ESHUTDOWN;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       if (urb)
+               rh_status_dequeue (hcd, urb);
+       hcd->driver->stop (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount */
+/* caller surrenders "ownership" of urb (and chain at urb->next).  */
+
+static int hcd_submit_urb (struct urb *urb)
+{
+       int                     status;
+       struct usb_hcd          *hcd;
+       struct hcd_dev          *dev;
+       unsigned long           flags;
+       int                     pipe;
+       int                     mem_flags;
+
+       if (!urb || urb->hcpriv || !urb->complete)
+               return -EINVAL;
+
+       urb->status = -EINPROGRESS;
+       urb->actual_length = 0;
+       INIT_LIST_HEAD (&urb->urb_list);
+
+       if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
+               return -ENODEV;
+       hcd = urb->dev->bus->hcpriv;
+       dev = urb->dev->hcpriv;
+       if (!hcd || !dev)
+               return -ENODEV;
+
+       /* can't submit new urbs when quiescing, halted, ... */
+       if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
+               return -ESHUTDOWN;
+       pipe = urb->pipe;
+       if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
+                       usb_pipeout (pipe)))
+               return -EPIPE;
+
+       // FIXME paging/swapping requests over USB should not use GFP_KERNEL
+       // and might even need to use GFP_NOIO ... that flag actually needs
+       // to be passed from the higher level.
+       mem_flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+
+#ifdef DEBUG
+       {
+       unsigned int    orig_flags = urb->transfer_flags;
+       unsigned int    allowed;
+
+       /* enforce simple/standard policy */
+       allowed = USB_ASYNC_UNLINK;     // affects later unlinks
+       allowed |= USB_NO_FSBR;         // only affects UHCI
+       switch (usb_pipetype (pipe)) {
+       case PIPE_CONTROL:
+               allowed |= USB_DISABLE_SPD;
+               break;
+       case PIPE_BULK:
+               allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
+                               | USB_ZERO_PACKET | URB_NO_INTERRUPT;
+               break;
+       case PIPE_INTERRUPT:
+               allowed |= USB_DISABLE_SPD;
+               break;
+       case PIPE_ISOCHRONOUS:
+               allowed |= USB_ISO_ASAP;
+               break;
+       }
+       urb->transfer_flags &= allowed;
+
+       /* warn if submitter gave bogus flags */
+       if (urb->transfer_flags != orig_flags)
+               warn ("BOGUS urb flags, %x --> %x",
+                       orig_flags, urb->transfer_flags);
+       }
+#endif
+       /*
+        * FIXME:  alloc periodic bandwidth here, for interrupt and iso?
+        * Need to look at the ring submit mechanism for iso tds ... they
+        * aren't actually "periodic" in 2.4 kernels.
+        *
+        * FIXME:  make urb timeouts be generic, keeping the HCD cores
+        * as simple as possible.
+        */
+
+       // NOTE:  a generic device/urb monitoring hook would go here.
+       // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
+       // It would catch submission paths for all urbs.
+
+       /*
+        * Atomically queue the urb,  first to our records, then to the HCD.
+        * Access to urb->status is controlled by urb->lock ... changes on
+        * i/o completion (normal or fault) or unlinking.
+        */
+
+       // FIXME:  verify that quiescing hc works right (RH cleans up)
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
+               usb_inc_dev_use (urb->dev);
+               list_add (&urb->urb_list, &dev->urb_list);
+               status = 0;
+       } else {
+               INIT_LIST_HEAD (&urb->urb_list);
+               status = -ESHUTDOWN;
+       }
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       if (!status) {
+               if (urb->dev == hcd->bus->root_hub)
+                       status = rh_urb_enqueue (hcd, urb);
+               else
+                       status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+       }
+       if (status) {
+               if (urb->dev) {
+                       urb->status = status;
+                       usb_hcd_giveback_urb (hcd, urb);
+               }
+       }
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called in any context */
+static int hcd_get_frame_number (struct usb_device *udev)
+{
+       struct usb_hcd  *hcd = (struct usb_hcd *)udev->bus->hcpriv;
+       return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct completion_splice {             // modified urb context:
+       /* did we complete? */
+       int                     done;
+
+       /* original urb data */
+       void                    (*complete)(struct urb *);
+       void                    *context;
+};
+
+static void unlink_complete (struct urb *urb)
+{
+       struct completion_splice        *splice;
+
+       splice = (struct completion_splice *) urb->context;
+
+       /* issue original completion call */
+       urb->complete = splice->complete;
+       urb->context = splice->context;
+       urb->complete (urb);
+
+       splice->done = 1;
+}
+
+/*
+ * called in any context; note ASYNC_UNLINK restrictions
+ *
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+static int hcd_unlink_urb (struct urb *urb)
+{
+       struct hcd_dev                  *dev;
+       struct usb_hcd                  *hcd = 0;
+       unsigned long                   flags;
+       struct completion_splice        splice;
+       int                             retval;
+
+       if (!urb)
+               return -EINVAL;
+
+       // FIXME:  add some explicit records to flag the
+       // state where the URB is "in periodic completion".
+       // Workaround is for driver to set the urb status
+       // to "-EINPROGRESS", so it can get through here
+       // and unlink from the completion handler.
+
+       /*
+        * we contend for urb->status with the hcd core,
+        * which changes it while returning the urb.
+        */
+       spin_lock_irqsave (&urb->lock, flags);
+       if (!urb->hcpriv
+                       || urb->status != -EINPROGRESS
+                       || urb->transfer_flags & USB_TIMEOUT_KILLED) {
+               retval = -EINVAL;
+               goto done;
+       }
+
+       if (!urb->dev || !urb->dev->bus) {
+               retval = -ENODEV;
+               goto done;
+       }
+       dev = urb->dev->hcpriv;
+       hcd = urb->dev->bus->hcpriv;
+       if (!dev || !hcd) {
+               retval = -ENODEV;
+               goto done;
+       }
+
+       /* maybe set up to block on completion notification */
+       if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
+               urb->status = -ETIMEDOUT;
+       else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+               if (in_interrupt ()) {
+                       dbg ("non-async unlink in_interrupt");
+                       retval = -EWOULDBLOCK;
+                       goto done;
+               }
+               /* synchronous unlink: block till we see the completion */
+               splice.done = 0;
+               splice.complete = urb->complete;
+               splice.context = urb->context;
+               urb->complete = unlink_complete;
+               urb->context = &splice;
+               urb->status = -ENOENT;
+       } else {
+               /* asynchronous unlink */
+               urb->status = -ECONNRESET;
+       }
+       spin_unlock_irqrestore (&urb->lock, flags);
+
+       if (urb == (struct urb *) hcd->rh_timer.data) {
+               rh_status_dequeue (hcd, urb);
+               retval = 0;
+       } else {
+               retval = hcd->driver->urb_dequeue (hcd, urb);
+// FIXME:  if retval and we tried to splice, whoa!!
+if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
+       }
+
+       /* block till giveback, if needed */
+       if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
+                       && HCD_IS_RUNNING (hcd->state)
+                       && !retval) {
+               while (!splice.done) {
+                       set_current_state (TASK_UNINTERRUPTIBLE);
+                       schedule_timeout ((2/*msec*/ * HZ) / 1000);
+                       dbg ("%s: wait for giveback urb %p",
+                               hcd->bus_name, urb);
+               }
+       }
+       goto bye;
+done:
+       spin_unlock_irqrestore (&urb->lock, flags);
+bye:
+       if (retval)
+               dbg ("%s: hcd_unlink_urb fail %d",
+                   hcd ? hcd->bus_name : "(no bus?)",
+                   retval);
+       return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */
+
+// FIXME:  likely best to have explicit per-setting (config+alt)
+// setup primitives in the usbcore-to-hcd driver API, so nothing
+// is implicit.  kernel 2.5 needs a bunch of config cleanup...
+
+static int hcd_free_dev (struct usb_device *udev)
+{
+       struct hcd_dev          *dev;
+       struct usb_hcd          *hcd;
+       unsigned long           flags;
+
+       if (!udev || !udev->hcpriv)
+               return -EINVAL;
+
+       if (!udev->bus || !udev->bus->hcpriv)
+               return -ENODEV;
+
+       // should udev->devnum == -1 ??
+
+       dev = udev->hcpriv;
+       hcd = udev->bus->hcpriv;
+
+       /* device driver problem with refcounts? */
+       if (!list_empty (&dev->urb_list)) {
+               dbg ("free busy dev, %s devnum %d (bug!)",
+                       hcd->bus_name, udev->devnum);
+               return -EINVAL;
+       }
+
+       hcd->driver->free_config (hcd, udev);
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_del (&dev->dev_list);
+       udev->hcpriv = NULL;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       kfree (dev);
+       return 0;
+}
+
+static struct usb_operations hcd_operations = {
+       allocate:               hcd_alloc_dev,
+       get_frame_number:       hcd_get_frame_number,
+       submit_urb:             hcd_submit_urb,
+       unlink_urb:             hcd_unlink_urb,
+       deallocate:             hcd_free_dev,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+       struct usb_hcd          *hcd = __hcd;
+       int                     start = hcd->state;
+
+       hcd->driver->irq (hcd);
+       if (hcd->state != start && hcd->state == USB_STATE_HALT)
+               hc_died (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause deadlocks if it resubmits this URB,
+ * and won't confuse things by modifying and resubmitting this one.
+ * Bandwidth and other resources will be deallocated.
+ *
+ * HCDs must not use this for periodic URBs that are still scheduled
+ * and will be reissued.  They should just call their completion handlers
+ * until the urb is returned to the device driver by unlinking.
+ *
+ * In common cases, urb->next will be submitted before the completion
+ * function gets called.  That's not done if the URB includes error
+ * status (including unlinking).
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+       unsigned long           flags;
+       struct usb_device       *dev;
+
+       /* Release periodic transfer bandwidth */
+       if (urb->bandwidth) {
+               switch (usb_pipetype (urb->pipe)) {
+               case PIPE_INTERRUPT:
+                       usb_release_bandwidth (urb->dev, urb, 0);
+                       break;
+               case PIPE_ISOCHRONOUS:
+                       usb_release_bandwidth (urb->dev, urb, 1);
+                       break;
+               }
+       }
+
+       /* clear all state linking urb to this dev (and hcd) */
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_del_init (&urb->urb_list);
+       dev = urb->dev;
+       urb->dev = NULL;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       // NOTE:  a generic device/urb monitoring hook would go here.
+       // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
+       // It would catch exit/unlink paths for all urbs, but non-exit
+       // completions for periodic urbs need hooks inside the HCD.
+       // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
+
+       if (urb->status)
+               dbg ("giveback urb %p status %d", urb, urb->status);
+
+       /* if no error, make sure urb->next progresses */
+       else if (urb->next) {
+               int     status;
+
+               status = usb_submit_urb (urb->next);
+               if (status) {
+                       dbg ("urb %p chain fail, %d", urb->next, status);
+                       urb->next->status = -ENOTCONN;
+               }
+
+               /* HCDs never modify the urb->next chain, and only use it here,
+                * so that if urb->complete sees an URB there with -ENOTCONN,
+                * it knows the driver chained it but it couldn't be submitted.
+                */
+       }
+
+       /* pass ownership to the completion handler */
+       usb_dec_dev_use (dev);
+       urb->complete (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
diff --git a/drivers/usb/hcd.h b/drivers/usb/hcd.h
new file mode 100644 (file)
index 0000000..37ef85b
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver (usb_hcd) framework
+ *
+ * Since "struct usb_bus" is so thin, you can't share much code in it.
+ * This framework is a layer over that, and should be more sharable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_hcd {       /* usb_bus.hcpriv points to this */
+
+       /*
+        * housekeeping
+        */
+       struct usb_bus          *bus;           /* hcd is-a bus */
+       struct list_head        hcd_list;
+
+       const char              *bus_name;
+
+       const char              *description;   /* "ehci-hcd" etc */
+
+       struct timer_list       rh_timer;       /* drives root hub */
+       struct list_head        dev_list;       /* devices on this bus */
+
+       /*
+        * hardware info/state
+        */
+       struct hc_driver        *driver;        /* hw-specific hooks */
+       int                     irq;            /* irq allocated */
+       void                    *regs;          /* device memory/io */
+
+#ifdef CONFIG_PCI
+       /* a few non-PCI controllers exist, mostly for OHCI */
+       struct pci_dev          *pdev;          /* pci is typical */
+       int                     region;         /* pci region for regs */
+       u32                     pci_state [16]; /* for PM state save */
+       atomic_t                resume_count;   /* multiple resumes issue */
+#endif
+
+       int                     state;
+#      define  __ACTIVE                0x01
+#      define  __SLEEPY                0x02
+#      define  __SUSPEND               0x04
+#      define  __TRANSIENT             0x80
+
+#      define  USB_STATE_HALT          0
+#      define  USB_STATE_RUNNING       (__ACTIVE)
+#      define  USB_STATE_READY         (__ACTIVE|__SLEEPY)
+#      define  USB_STATE_QUIESCING     (__SUSPEND|__TRANSIENT|__ACTIVE)
+#      define  USB_STATE_RESUMING      (__SUSPEND|__TRANSIENT)
+#      define  USB_STATE_SUSPENDED     (__SUSPEND)
+
+#define        HCD_IS_RUNNING(state) ((state) & __ACTIVE)
+#define        HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
+
+       /* more shared queuing code would be good; it should support
+        * smarter scheduling, handle transaction translators, etc;
+        * input size of periodic table to an interrupt scheduler. 
+        * (ohci 32, uhci 1024, ehci 256/512/1024).
+        */
+};
+
+struct hcd_dev {       /* usb_device.hcpriv points to this */
+       struct list_head        dev_list;       /* on this hcd */
+       struct list_head        urb_list;       /* pending on this dev */
+
+       /* per-configuration HC/HCD state, such as QH or ED */
+       void                    *ep[32];
+};
+
+// urb.hcpriv is really hardware-specific
+
+struct hcd_timeout {   /* timeouts we allocate */
+       struct list_head        timeout_list;
+       struct timer_list       timer;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* each driver provides one of these, and hardware init support */
+
+struct hc_driver {
+       const char      *description;   /* "ehci-hcd" etc */
+
+       /* irq handler */
+       void    (*irq) (struct usb_hcd *hcd);
+
+       int     flags;
+#define        HCD_MEMORY      0x0001          /* HC regs use memory (else I/O) */
+#define        HCD_USB11       0x0010          /* USB 1.1 */
+#define        HCD_USB2        0x0020          /* USB 2.0 */
+
+       /* called to init HCD and root hub */
+       int     (*start) (struct usb_hcd *hcd);
+
+       /* called after all devices were suspended */
+       int     (*suspend) (struct usb_hcd *hcd, u32 state);
+
+       /* called before any devices get resumed */
+       int     (*resume) (struct usb_hcd *hcd);
+
+       /* cleanly make HCD stop writing memory and doing I/O */
+       void    (*stop) (struct usb_hcd *hcd);
+
+       /* return current frame number */
+       int     (*get_frame_number) (struct usb_hcd *hcd);
+
+// FIXME: rework generic-to-specific HCD linkage (specific contains generic)
+
+       /* memory lifecycle */
+       struct usb_hcd  *(*hcd_alloc) (void);
+       void            (*hcd_free) (struct usb_hcd *hcd);
+
+       /* manage i/o requests, device state */
+       int     (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,
+                                       int mem_flags);
+       int     (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+
+       // frees configuration resources -- allocated as needed during
+       // urb_enqueue, and not freed by urb_dequeue
+       void            (*free_config) (struct usb_hcd *hcd,
+                               struct usb_device *dev);
+
+       /* root hub support */
+       int             (*hub_status_data) (struct usb_hcd *hcd, char *buf);
+       int             (*hub_control) (struct usb_hcd *hcd,
+                               u16 typeReq, u16 wValue, u16 wIndex,
+                               char *buf, u16 wLength);
+};
+
+extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+
+#ifdef CONFIG_PCI
+
+extern int usb_hcd_pci_probe (struct pci_dev *dev,
+                               const struct pci_device_id *id);
+extern void usb_hcd_pci_remove (struct pci_dev *dev);
+
+#ifdef CONFIG_PM
+// FIXME:  see Documentation/power/pci.txt (2.4.6 and later?)
+// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_resume (struct pci_dev *dev);
+// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg);
+#endif /* CONFIG_PM */
+
+#endif /* CONFIG_PCI */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * HCD Root Hub support
+ */
+
+#include "hub.h"
+
+/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
+#define DeviceRequest \
+       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define DeviceOutRequest \
+       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+
+#define InterfaceRequest \
+       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+#define EndpointRequest \
+       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define EndpointOutRequest \
+       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+/* table 9.6 standard features */
+#define DEVICE_REMOTE_WAKEUP   1
+#define ENDPOINT_HALT          0
+
+/* class requests from the USB 2.0 hub spec, table 11-15 */
+/* GetBusState and SetHubDescriptor are optional, omitted */
+#define ClearHubFeature                (0x2000 | USB_REQ_CLEAR_FEATURE)
+#define ClearPortFeature       (0x2300 | USB_REQ_CLEAR_FEATURE)
+#define GetHubDescriptor       (0xa000 | USB_REQ_GET_DESCRIPTOR)
+#define GetHubStatus           (0xa000 | USB_REQ_GET_STATUS)
+#define GetPortStatus          (0xa300 | USB_REQ_GET_STATUS)
+#define SetHubFeature          (0x2000 | USB_REQ_SET_FEATURE)
+#define SetPortFeature         (0x2300 | USB_REQ_SET_FEATURE)
+
+
+/*-------------------------------------------------------------------------*/
+
+/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
+// bleech -- resurfaced in 2.4.11 or 2.4.12
+#define bitmap         DeviceRemovable
+
+
+/*-------------------------------------------------------------------------*/
+
+/* random stuff */
+
+#define        RUN_CONTEXT (in_irq () ? "in_irq" \
+               : (in_interrupt () ? "in_interrupt" : "can sleep"))
diff --git a/drivers/usb/hcd/Config.in b/drivers/usb/hcd/Config.in
new file mode 100644 (file)
index 0000000..1075256
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# USB Host Controller Drivers
+#
+dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate '  UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+
diff --git a/drivers/usb/hcd/Makefile b/drivers/usb/hcd/Makefile
new file mode 100644 (file)
index 0000000..4327408
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Makefile for USB Host Controller Driver
+# framework and drivers
+#
+
+O_TARGET       :=
+
+obj-$(CONFIG_EHCI_HCD)                 += ehci-hcd.o
+# obj-$(CONFIG_OHCI_HCD)                       += ohci-hcd.o
+# obj-$(CONFIG_UHCI_HCD)                       += uhci-hcd.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+multi-y                := $(filter $(list-multi), $(obj-y))
+multi-m                := $(filter $(list-multi), $(obj-m))
+int-y          := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m          := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Take multi-part drivers out of obj-y and put components in.
+obj-y          := $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+OX_OBJS                := $(obj-y)
+MX_OBJS                := $(obj-m)
+MIX_OBJS       := $(int-m)
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/hcd/ehci-dbg.c b/drivers/usb/hcd/ehci-dbg.c
new file mode 100644 (file)
index 0000000..442bbe3
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+#ifdef EHCI_VERBOSE_DEBUG
+#      define vdbg dbg
+#else
+       static inline void vdbg (char *fmt, ...) { }
+#endif
+
+#ifdef DEBUG
+
+/* check the values in the HCSPARAMS register - host controller structural parameters */
+/* see EHCI 0.95 Spec, Table 2-4 for each value */
+static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
+{
+       u32     params = readl (&ehci->caps->hcs_params);
+
+       dbg ("%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d",
+               label, params,
+               HCS_DEBUG_PORT (params),
+               HCS_INDICATOR (params) ? " ind" : "",
+               HCS_N_CC (params),
+               HCS_N_PCC (params),
+               HCS_PORTROUTED (params) ? "" : " ordered",
+               HCS_PPC (params) ? "" : " !ppc",
+               HCS_N_PORTS (params)
+               );
+       /* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
+       if (HCS_PORTROUTED (params)) {
+               int i;
+               char buf [46], tmp [7], byte;
+
+               buf[0] = 0;
+               for (i = 0; i < HCS_N_PORTS (params); i++) {
+                       byte = readb (&ehci->caps->portroute[(i>>1)]);
+                       sprintf(tmp, "%d ", 
+                               ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
+                       strcat(buf, tmp);
+               }
+               dbg ("%s: %s portroute %s", 
+                       ehci->hcd.bus_name, label,
+                       buf);
+       }
+}
+#else
+
+static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef DEBUG
+
+/* check the values in the HCCPARAMS register - host controller capability parameters */
+/* see EHCI 0.95 Spec, Table 2-5 for each value */
+static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
+{
+       u32     params = readl (&ehci->caps->hcc_params);
+
+       if (HCC_EXT_CAPS (params)) {
+               // EHCI 0.96 ... could interpret these (legacy?)
+               dbg ("%s extended capabilities at pci %d",
+                       label, HCC_EXT_CAPS (params));
+       }
+       if (HCC_ISOC_CACHE (params)) {
+               dbg ("%s hcc_params 0x%04x caching frame %s%s%s",
+                    label, params,
+                    HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+                    HCC_CANPARK (params) ? " park" : "",
+                    HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+       } else {
+               dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s",
+                    label,
+                    params,
+                    HCC_ISOC_THRES (params),
+                    HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+                    HCC_CANPARK (params) ? " park" : "",
+                    HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+       }
+}
+#else
+
+static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef DEBUG
+
+#if 0
+static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+       dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
+               qh, qh->hw_info1, qh->hw_info2,
+               qh->hw_current, qh->hw_qtd_next);
+       dbg ("  alt+errs= %x, token= %x, page0= %x, page1= %x",
+               qh->hw_alt_next, qh->hw_token,
+               qh->hw_buf [0], qh->hw_buf [1]);
+       if (qh->hw_buf [2]) {
+               dbg ("  page2= %x, page3= %x, page4= %x",
+                       qh->hw_buf [2], qh->hw_buf [3],
+                       qh->hw_buf [4]);
+       }
+}
+#endif
+
+static const char *const fls_strings [] =
+    { "1024", "512", "256", "??" };
+
+#else
+#if 0
+static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
+#endif
+#endif /* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+
+#define dbg_status(ehci, label, status) \
+       dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \
+               label, status, \
+               (status & STS_ASS) ? " Async" : "", \
+               (status & STS_PSS) ? " Periodic" : "", \
+               (status & STS_RECL) ? " Recl" : "", \
+               (status & STS_HALT) ? " Halt" : "", \
+               (status & STS_IAA) ? " IAA" : "", \
+               (status & STS_FATAL) ? " FATAL" : "", \
+               (status & STS_FLR) ? " FLR" : "", \
+               (status & STS_PCD) ? " PCD" : "", \
+               (status & STS_ERR) ? " ERR" : "", \
+               (status & STS_INT) ? " INT" : "" \
+               )
+
+#define dbg_cmd(ehci, label, command) \
+       dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \
+               label, command, \
+               (command & CMD_PARK) ? "park" : "(park)", \
+               CMD_PARK_CNT (command), \
+               (command >> 16) & 0x3f, \
+               (command & CMD_LRESET) ? " LReset" : "", \
+               (command & CMD_IAAD) ? " IAAD" : "", \
+               (command & CMD_ASE) ? " Async" : "", \
+               (command & CMD_PSE) ? " Periodic" : "", \
+               fls_strings [(command >> 2) & 0x3], \
+               (command & CMD_RESET) ? " Reset" : "", \
+               (command & CMD_RUN) ? "RUN" : "HALT" \
+               )
+
+#define dbg_port(hcd, label, port, status) \
+       dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \
+               label, port, status, \
+               (status & PORT_OWNER) ? " OWNER" : "", \
+               (status & PORT_POWER) ? " POWER" : "", \
+               (status >> 10) & 3, \
+               (status & PORT_RESET) ? " RESET" : "", \
+               (status & PORT_SUSPEND) ? " SUSPEND" : "", \
+               (status & PORT_RESUME) ? " RESUME" : "", \
+               (status & PORT_OCC) ? " OCC" : "", \
+               (status & PORT_OC) ? " OC" : "", \
+               (status & PORT_PEC) ? " PEC" : "", \
+               (status & PORT_PE) ? " PE" : "", \
+               (status & PORT_CSC) ? " CSC" : "", \
+               (status & PORT_CONNECT) ? " CONNECT" : "" \
+           )
+
diff --git a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c
new file mode 100644 (file)
index 0000000..83a3321
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2000-2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+
+#ifndef CONFIG_USB_DEBUG
+       #define CONFIG_USB_DEBUG        /* this is still experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "../hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+//#undef KERN_DEBUG
+//#define KERN_DEBUG ""
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hc_driver implementation ... experimental, incomplete.
+ * Based on the 0.96 register interface specification.
+ *
+ * There are lots of things to help out with here ... notably
+ * everything "periodic", and of course testing with all sorts
+ * of usb 2.0 devices and configurations.
+ *
+ * USB 2.0 shows up in upcoming www.pcmcia.org technology.
+ * First was PCMCIA, like ISA; then CardBus, which is PCI.
+ * Next comes "CardBay", using USB 2.0 signals.
+ *
+ * Contains additional contributions by:
+ *     Brad Hards
+ *     Rory Bolt
+ *     ...
+ */
+
+#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_AUTHOR "David Brownell"
+#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
+
+
+// #define EHCI_VERBOSE_DEBUG
+// #define have_iso
+
+#ifdef DEBUG
+#      define  EHCI_SLAB_FLAGS         (SLAB_POISON)
+#else
+#      define  EHCI_SLAB_FLAGS         0
+#endif
+
+/* magic numbers that can affect system performance */
+#define        EHCI_TUNE_CERR          3       /* 0-3 qtd retries; 0 == don't stop */
+#define        EHCI_TUNE_RL_HS         0       /* nak throttle; see 4.9 */
+#define        EHCI_TUNE_RL_TT         0
+#define        EHCI_TUNE_MULT_HS       1       /* 1-3 transactions/uframe; 4.10.3 */
+#define        EHCI_TUNE_MULT_TT       1
+
+/* Initial IRQ latency:  lower than default */
+static int log2_irq_thresh = 0;                // 0 to 6
+MODULE_PARM (log2_irq_thresh, "i");
+MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* Some A steppings of the NEC controller need soft retries */
+//#define      EHCI_SOFT_RETRIES       5       /* after CERR-induced fault */
+
+#define        INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci.h"
+#include "ehci-dbg.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * hc states include: unknown, halted, ready, running
+ * transitional states are messy just now
+ * trying to avoid "running" unless urbs are active
+ * a "ready" hc can be finishing prefetched work
+ */
+
+/* halt a non-running controller */
+static void ehci_reset (struct ehci_hcd *ehci)
+{
+       u32     command = readl (&ehci->regs->command);
+
+       command |= CMD_RESET;
+       dbg_cmd (ehci, "reset", command);
+       writel (command, &ehci->regs->command);
+       while (readl (&ehci->regs->command) & CMD_RESET)
+               continue;
+       ehci->hcd.state = USB_STATE_HALT;
+}
+
+/* idle the controller (from running) */
+static void ehci_ready (struct ehci_hcd *ehci)
+{
+       u32     command;
+
+#ifdef DEBUG
+       if (!HCD_IS_RUNNING (ehci->hcd.state))
+               BUG ();
+#endif
+
+       while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS)))
+               udelay (100);
+       command = readl (&ehci->regs->command);
+       command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+       writel (command, &ehci->regs->command);
+
+       // hardware can take 16 microframes to turn off ...
+       ehci->hcd.state = USB_STATE_READY;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci-hub.c"
+#include "ehci-mem.c"
+#include "ehci-q.c"
+#include "ehci-sched.c"
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_tasklet (unsigned long param);
+
+/* called by khubd or root hub init threads */
+
+static int ehci_start (struct usb_hcd *hcd)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       u32                     temp;
+       struct usb_device       *udev;
+       int                     retval;
+       u32                     hcc_params;
+       u8                      tempbyte;
+
+       // FIXME:  given EHCI 0.96 or later, and a controller with
+       // the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
+       // the BIOS doesn't still own this controller.
+
+       spin_lock_init (&ehci->lock);
+
+       ehci->caps = (struct ehci_caps *) hcd->regs;
+       ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length);
+       dbg_hcs_params (ehci, "ehci_start");
+       dbg_hcc_params (ehci, "ehci_start");
+
+       /*
+        * hw default: 1K periodic list heads, one per frame.
+        * periodic_size can shrink by USBCMD update if hcc_params allows.
+        */
+       ehci->periodic_size = DEFAULT_I_TDPS;
+       if ((retval = ehci_mem_init (ehci, EHCI_SLAB_FLAGS | SLAB_KERNEL)) < 0)
+               return retval;
+       hcc_params = readl (&ehci->caps->hcc_params);
+
+       /* controllers may cache some of the periodic schedule ... */
+       if (HCC_ISOC_CACHE (hcc_params))        // full frame cache
+               ehci->i_thresh = 8;
+       else                                    // N microframes cached
+               ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
+
+       ehci->async = 0;
+       ehci->reclaim = 0;
+       ehci->next_frame = -1;
+
+       /* controller state:  unknown --> reset */
+
+       /* EHCI spec section 4.1 */
+       ehci_reset (ehci);
+       writel (INTR_MASK, &ehci->regs->intr_enable);
+       writel (ehci->periodic_dma, &ehci->regs->frame_list);
+
+       /*
+        * hcc_params controls whether ehci->regs->segment must (!!!)
+        * be used; it constrains QH/ITD/SITD and QTD locations.
+        * By default, pci_alloc_consistent() won't hand out addresses
+        * above 4GB (via pdev->dma_mask) so we know this value.
+        *
+        * NOTE:  that pdev->dma_mask setting means that all DMA mappings
+        * for I/O buffers will have the same restriction, though it's
+        * neither necessary nor desirable in that case.
+        */
+       if (HCC_64BIT_ADDR (hcc_params)) {
+               writel (0, &ehci->regs->segment);
+               info ("using segment 0 for 64bit DMA addresses ...");
+       }
+
+       /* clear interrupt enables, set irq latency */
+       temp = readl (&ehci->regs->command) & 0xff;
+       if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+           log2_irq_thresh = 0;
+       temp |= 1 << (16 + log2_irq_thresh);
+       // keeping default periodic framelist size
+       temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
+       writel (temp, &ehci->regs->command);
+       dbg_cmd (ehci, "init", temp);
+
+       /* set async sleep time = 10 us ... ? */
+
+       ehci->tasklet.func = ehci_tasklet;
+       ehci->tasklet.data = (unsigned long) ehci;
+
+       /* wire up the root hub */
+       hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
+       if (!udev) {
+done2:
+               ehci_mem_cleanup (ehci);
+               return -ENOMEM;
+       }
+
+       /*
+        * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+        * are explicitly handed to companion controller(s), so no TT is
+        * involved with the root hub.
+        */
+       ehci->hcd.state = USB_STATE_READY;
+       writel (FLAG_CF, &ehci->regs->configured_flag);
+       readl (&ehci->regs->command);   /* unblock posted write */
+
+        /* PCI Serial Bus Release Number is at 0x60 offset */
+       pci_read_config_byte(hcd->pdev, 0x60, &tempbyte);
+       temp = readw (&ehci->caps->hci_version);
+       info ("USB %x.%x support enabled, EHCI rev %x.%2x",
+             ((tempbyte & 0xf0)>>4),
+             (tempbyte & 0x0f),
+              temp >> 8,
+              temp & 0xff);
+
+       /*
+        * From here on, khubd concurrently accesses the root
+        * hub; drivers will be talking to enumerated devices.
+        *
+        * Before this point the HC was idle/ready.  After, khubd
+        * and device drivers may start it running.
+        */
+       usb_connect (udev);
+       udev->speed = USB_SPEED_HIGH;
+       if (usb_new_device (udev) != 0) {
+               if (hcd->state == USB_STATE_RUNNING)
+                       ehci_ready (ehci);
+               while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+                       udelay (100);
+               ehci_reset (ehci);
+               // usb_disconnect (udev); 
+               hcd->bus->root_hub = 0;
+               usb_free_dev (udev); 
+               retval = -ENODEV;
+               goto done2;
+       }
+
+       return 0;
+}
+
+/* always called by thread; normally rmmod */
+
+static void ehci_stop (struct usb_hcd *hcd)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+
+       dbg ("%s: stop", hcd->bus_name);
+
+       if (hcd->state == USB_STATE_RUNNING)
+               ehci_ready (ehci);
+       while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+               udelay (100);
+       ehci_reset (ehci);
+
+       // root hub is shut down separately (first, when possible)
+       scan_async (ehci);
+       if (ehci->next_frame != -1)
+               scan_periodic (ehci);
+       ehci_mem_cleanup (ehci);
+
+       dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+}
+
+static int ehci_get_frame (struct usb_hcd *hcd)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+static int ehci_suspend (struct usb_hcd *hcd, u32 state)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       u32                     params;
+       int                     ports;
+       int                     i;
+
+       dbg ("%s: suspend to %d", hcd->bus_name, state);
+
+       params = readl (&ehci->caps->hcs_params);
+       ports = HCS_N_PORTS (params);
+
+       // FIXME:  This assumes what's probably a D3 level suspend...
+
+       // FIXME:  usb wakeup events on this bus should resume the machine.
+       // pci config register PORTWAKECAP controls which ports can do it;
+       // bios may have initted the register...
+
+       /* suspend each port, then stop the hc */
+       for (i = 0; i < ports; i++) {
+               int     temp = readl (&ehci->regs->port_status [i]);
+
+               if ((temp & PORT_PE) == 0
+                               || (temp & PORT_OWNER) != 0)
+                       continue;
+dbg ("%s: suspend port %d", hcd->bus_name, i);
+               temp |= PORT_SUSPEND;
+               writel (temp, &ehci->regs->port_status [i]);
+       }
+
+       if (hcd->state == USB_STATE_RUNNING)
+               ehci_ready (ehci);
+       while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+               udelay (100);
+       writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
+
+// save pci FLADJ value
+
+       /* who tells PCI to reduce power consumption? */
+
+       return 0;
+}
+
+static int ehci_resume (struct usb_hcd *hcd)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       u32                     params;
+       int                     ports;
+       int                     i;
+
+       dbg ("%s: resume", hcd->bus_name);
+
+       params = readl (&ehci->caps->hcs_params);
+       ports = HCS_N_PORTS (params);
+
+       // FIXME:  if controller didn't retain state,
+       // return and let generic code clean it up
+       // test configured_flag ?
+
+       /* resume HC and each port */
+// restore pci FLADJ value
+       // khubd and drivers will set HC running, if needed;
+       hcd->state = USB_STATE_READY;
+       for (i = 0; i < ports; i++) {
+               int     temp = readl (&ehci->regs->port_status [i]);
+
+               if ((temp & PORT_PE) == 0
+                               || (temp & PORT_SUSPEND) != 0)
+                       continue;
+dbg ("%s: resume port %d", hcd->bus_name, i);
+               temp |= PORT_RESUME;
+               writel (temp, &ehci->regs->port_status [i]);
+               readl (&ehci->regs->command);   /* unblock posted writes */
+
+               wait_ms (20);
+               temp &= ~PORT_RESUME;
+               writel (temp, &ehci->regs->port_status [i]);
+       }
+       readl (&ehci->regs->command);   /* unblock posted writes */
+       return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * tasklet scheduled by some interrupts and other events
+ * calls driver completion functions ... but not in_irq()
+ */
+static void ehci_tasklet (unsigned long param)
+{
+       struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
+
+       if (ehci->reclaim_ready)
+               end_unlink_async (ehci);
+       scan_async (ehci);
+       if (ehci->next_frame != -1)
+               scan_periodic (ehci);
+
+       // FIXME:  when nothing is connected to the root hub,
+       // turn off the RUN bit so the host can enter C3 "sleep" power
+       // saving mode; make root hub code scan memory less often.
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_irq (struct usb_hcd *hcd)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       u32                     status = readl (&ehci->regs->status);
+       int                     bh = 0;
+
+       /* clear (just) interrupts */
+       status &= INTR_MASK;
+       writel (status, &ehci->regs->status);
+       readl (&ehci->regs->command);   /* unblock posted write */
+
+       if (unlikely (hcd->state == USB_STATE_HALT))    /* irq sharing? */
+               return;
+
+#ifdef EHCI_VERBOSE_DEBUG
+       /* unrequested/ignored: Port Change Detect, Frame List Rollover */
+       if (status & INTR_MASK)
+               dbg_status (ehci, "irq", status);
+#endif
+
+       /* INT, ERR, and IAA interrupt rates can be throttled */
+
+       /* normal [4.15.1.2] or error [4.15.1.1] completion */
+       if (likely ((status & (STS_INT|STS_ERR)) != 0))
+               bh = 1;
+
+       /* complete the unlinking of some qh [4.15.2.3] */
+       if (status & STS_IAA) {
+               ehci->reclaim_ready = 1;
+               bh = 1;
+       }
+
+       /* PCI errors [4.15.2.4] */
+       if (unlikely ((status & STS_FATAL) != 0)) {
+               err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
+               ehci_reset (ehci);
+               // generic layer kills/unlinks all urbs
+               // then tasklet cleans up the rest
+               bh = 1;
+       }
+
+       /* most work doesn't need to be in_irq() */
+       if (likely (bh == 1))
+               tasklet_schedule (&ehci->tasklet);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd_dev.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE:  EHCI queues control and bulk requests transparently, like OHCI.
+ */
+static int ehci_urb_enqueue (
+       struct usb_hcd  *hcd,
+       struct urb      *urb,
+       int             mem_flags
+) {
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       struct list_head        qtd_list;
+
+       urb->transfer_flags &= ~EHCI_STATE_UNLINK;
+       INIT_LIST_HEAD (&qtd_list);
+       switch (usb_pipetype (urb->pipe)) {
+
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+               if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+                       return -ENOMEM;
+               submit_async (ehci, urb, &qtd_list, mem_flags);
+               break;
+
+       case PIPE_INTERRUPT:
+               if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+                       return -ENOMEM;
+               return intr_submit (ehci, urb, &qtd_list, mem_flags);
+
+       case PIPE_ISOCHRONOUS:
+#ifdef have_iso
+               if (urb->dev->speed == USB_SPEED_HIGH)
+                       return itd_submit (ehci, urb);
+               else
+                       return sitd_submit (ehci, urb);
+#else
+               // FIXME highspeed iso stuff is written but never run/tested.
+               // and the split iso support isn't even written yet.
+               dbg ("no iso support yet");
+               return -ENOSYS;
+#endif /* have_iso */
+
+       }
+       return 0;
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       struct ehci_qh          *qh = (struct ehci_qh *) urb->hcpriv;
+       unsigned long           flags;
+
+       dbg ("%s urb_dequeue %p qh state %d",
+               hcd->bus_name, urb, qh->qh_state);
+
+       switch (usb_pipetype (urb->pipe)) {
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+               spin_lock_irqsave (&ehci->lock, flags);
+               if (ehci->reclaim) {
+dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
+                       if (in_interrupt ()) {
+                               spin_unlock_irqrestore (&ehci->lock, flags);
+                               return -EAGAIN;
+                       }
+                       while (qh->qh_state == QH_STATE_LINKED
+                                       && ehci->reclaim
+                                       && ehci->hcd.state != USB_STATE_HALT
+                                       ) {
+                               spin_unlock_irqrestore (&ehci->lock, flags);
+// yeech ... this could spin for up to two frames!
+dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
+    qh->qh_state, ehci->reclaim, ehci->hcd.state
+);
+                               udelay (100);
+                               spin_lock_irqsave (&ehci->lock, flags);
+                       }
+               }
+               if (qh->qh_state == QH_STATE_LINKED)
+                       start_unlink_async (ehci, qh);
+               spin_unlock_irqrestore (&ehci->lock, flags);
+               return 0;
+
+       case PIPE_INTERRUPT:
+               intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
+               if (ehci->hcd.state == USB_STATE_HALT)
+                       urb->status = -ESHUTDOWN;
+               qh_completions (ehci, &qh->qtd_list, 1);
+               return 0;
+
+       case PIPE_ISOCHRONOUS:
+               // itd or sitd ...
+
+               // wait till next completion, do it then.
+               // completion irqs can wait up to 128 msec,
+               urb->transfer_flags |= EHCI_STATE_UNLINK;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// bulk qh holds the data toggle
+
+static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct hcd_dev          *dev = (struct hcd_dev *)udev->hcpriv;
+       struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       int                     i;
+       unsigned long           flags;
+
+       /* ASSERT:  nobody can be submitting urbs for this any more */
+
+       dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum);
+
+       spin_lock_irqsave (&ehci->lock, flags);
+       for (i = 0; i < 32; i++) {
+               if (dev->ep [i]) {
+                       struct ehci_qh          *qh;
+
+                       // FIXME:  this might be an itd/sitd too ...
+                       // or an interrupt urb (not on async list)
+                       // can use "union ehci_shadow"
+
+                       qh = (struct ehci_qh *) dev->ep [i];
+                       vdbg ("free_config, ep 0x%02x qh %p", i, qh);
+                       if (!list_empty (&qh->qtd_list)) {
+                               dbg ("ep 0x%02x qh %p not empty!", i, qh);
+                               BUG ();
+                       }
+                       dev->ep [i] = 0;
+
+                       /* wait_ms() won't spin here -- we're a thread */
+                       while (qh->qh_state == QH_STATE_LINKED
+                                       && ehci->reclaim
+                                       && ehci->hcd.state != USB_STATE_HALT
+                                       ) {
+                               spin_unlock_irqrestore (&ehci->lock, flags);
+                               wait_ms (1);
+                               spin_lock_irqsave (&ehci->lock, flags);
+                       }
+                       if (qh->qh_state == QH_STATE_LINKED) {
+                               start_unlink_async (ehci, qh);
+                               while (qh->qh_state != QH_STATE_IDLE) {
+                                       spin_unlock_irqrestore (&ehci->lock,
+                                               flags);
+                                       wait_ms (1);
+                                       spin_lock_irqsave (&ehci->lock, flags);
+                               }
+                       }
+                       qh_unput (ehci, qh);
+               }
+       }
+
+       spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const char      hcd_name [] = "ehci-hcd";
+
+static const struct hc_driver ehci_driver = {
+       description:            hcd_name,
+
+       /*
+        * generic hardware linkage
+        */
+       irq:                    ehci_irq,
+       flags:                  HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       start:                  ehci_start,
+#ifdef CONFIG_PM
+       suspend:                ehci_suspend,
+       resume:                 ehci_resume,
+#endif
+       stop:                   ehci_stop,
+
+       /*
+        * memory lifecycle (except per-request)
+        */
+       hcd_alloc:              ehci_hcd_alloc,
+       hcd_free:               ehci_hcd_free,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       urb_enqueue:            ehci_urb_enqueue,
+       urb_dequeue:            ehci_urb_dequeue,
+       free_config:            ehci_free_config,
+
+       /*
+        * scheduling support
+        */
+       get_frame_number:       ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       hub_status_data:        ehci_hub_status_data,
+       hub_control:            ehci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI spec says PCI is required. */
+
+/* PCI driver selection metadata; PCI hotplugging uses this */
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+
+       /* handle any USB 2.0 EHCI controller */
+
+       class:          ((PCI_CLASS_SERIAL_USB << 8) | 0x20),
+       class_mask:     ~0,
+       driver_data:    (unsigned long) &ehci_driver,
+
+       /* no matter who makes it */
+       vendor:         PCI_ANY_ID,
+       device:         PCI_ANY_ID,
+       subvendor:      PCI_ANY_ID,
+       subdevice:      PCI_ANY_ID,
+
+}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ehci_pci_driver = {
+       name:           (char *) hcd_name,
+       id_table:       pci_ids,
+
+       probe:          usb_hcd_pci_probe,
+       remove:         usb_hcd_pci_remove,
+
+#ifdef CONFIG_PM
+       suspend:        usb_hcd_pci_suspend,
+       resume:         usb_hcd_pci_resume,
+#endif
+};
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+EXPORT_NO_SYMBOLS;
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_LICENSE ("GPL");
+
+static int __init init (void) 
+{
+       dbg (DRIVER_INFO);
+       dbg ("block sizes: qh %d qtd %d itd %d sitd %d",
+               sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
+               sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
+
+       return pci_module_init (&ehci_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void) 
+{      
+       pci_unregister_driver (&ehci_pci_driver);
+}
+module_exit (cleanup);
diff --git a/drivers/usb/hcd/ehci-hub.c b/drivers/usb/hcd/ehci-hub.c
new file mode 100644 (file)
index 0000000..4234fd8
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete (
+       struct ehci_hcd *ehci,
+       int             index,
+       int             port_status
+) {
+       if (!(port_status & PORT_CONNECT)) {
+               ehci->reset_done [index] = 0;
+               return port_status;
+       }
+
+       /* if reset finished and it's still not enabled -- handoff */
+       if (!(port_status & PORT_PE)) {
+               dbg ("%s port %d full speed, give to companion, 0x%x",
+                       ehci->hcd.bus_name, index + 1, port_status);
+
+               // what happens if HCS_N_CC(params) == 0 ?
+               port_status |= PORT_OWNER;
+               writel (port_status, &ehci->regs->port_status [index]);
+
+       } else
+               dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1);
+
+       return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+       u32             temp, status = 0;
+       int             ports, i, retval = 1;
+       unsigned long   flags;
+
+       /* init status to no-changes */
+       buf [0] = 0;
+       temp = readl (&ehci->caps->hcs_params);
+       ports = HCS_N_PORTS (temp);
+       if (ports > 7) {
+               buf [1] = 0;
+               retval++;
+       }
+       
+       /* no hub change reports (bit 0) for now (power, ...) */
+
+       /* port N changes (bit N)? */
+       spin_lock_irqsave (&ehci->lock, flags);
+       for (i = 0; i < ports; i++) {
+               temp = readl (&ehci->regs->port_status [i]);
+               if (temp & PORT_OWNER) {
+                       // get disconnected ports back if no companion driver
+                       if (temp & PORT_CONNECT)
+                               continue;
+                       temp &= ~(PORT_OWNER|PORT_CSC);
+                       writel (temp, &ehci->regs->port_status [i]);
+               }
+               if (!(temp & PORT_CONNECT))
+                       ehci->reset_done [i] = 0;
+               if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
+                       set_bit (i, buf);
+                       status = STS_PCD;
+               }
+       }
+       spin_unlock_irqrestore (&ehci->lock, flags);
+       return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ehci_hub_descriptor (
+       struct ehci_hcd                 *ehci,
+       struct usb_hub_descriptor       *desc
+) {
+       u32             params = readl (&ehci->caps->hcs_params);
+       int             ports = HCS_N_PORTS (params);
+       u16             temp;
+
+       desc->bDescriptorType = 0x29;
+       desc->bPwrOn2PwrGood = 0;       /* FIXME: f(system power) */
+       desc->bHubContrCurrent = 0;
+
+       desc->bNbrPorts = ports;
+       temp = 1 + (ports / 8);
+       desc->bDescLength = 7 + 2 * temp;
+
+       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+       memset (&desc->bitmap [0], 0, temp);
+       memset (&desc->bitmap [temp], 0xff, temp);
+
+       temp = 0x0008;                  /* per-port overcurrent reporting */
+       if (HCS_PPC (params))           /* per-port power control */
+           temp |= 0x0001;
+       if (HCS_INDICATOR (params))     /* per-port indicators (LEDs) */
+           temp |= 0x0080;
+       desc->wHubCharacteristics = cpu_to_le16 (temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hub_control (
+       struct usb_hcd  *hcd,
+       u16             typeReq,
+       u16             wValue,
+       u16             wIndex,
+       char            *buf,
+       u16             wLength
+) {
+       struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+       u32             params = readl (&ehci->caps->hcs_params);
+       int             ports = HCS_N_PORTS (params);
+       u32             temp;
+       unsigned long   flags;
+       int             retval = 0;
+
+       /*
+        * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+        * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+        * (track current state ourselves) ... blink for diagnostics,
+        * power, "this is the one", etc.  EHCI spec supports this.
+        */
+
+       spin_lock_irqsave (&ehci->lock, flags);
+       switch (typeReq) {
+       case ClearHubFeature:
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* no hub-wide feature/status flags */
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case ClearPortFeature:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               temp = readl (&ehci->regs->port_status [wIndex]);
+               if (temp & PORT_OWNER)
+                       break;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       writel (temp & ~PORT_PE,
+                               &ehci->regs->port_status [wIndex]);
+                       break;
+               case USB_PORT_FEAT_C_ENABLE:
+                       writel (temp | PORT_PEC,
+                               &ehci->regs->port_status [wIndex]);
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+               case USB_PORT_FEAT_C_SUSPEND:
+                       /* ? */
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       if (HCS_PPC (params))
+                               writel (temp & ~PORT_POWER,
+                                       &ehci->regs->port_status [wIndex]);
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+                       writel (temp | PORT_CSC,
+                               &ehci->regs->port_status [wIndex]);
+                       break;
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       writel (temp | PORT_OCC,
+                               &ehci->regs->port_status [wIndex]);
+                       break;
+               case USB_PORT_FEAT_C_RESET:
+                       /* GetPortStatus clears reset */
+                       break;
+               default:
+                       goto error;
+               }
+               readl (&ehci->regs->command);   /* unblock posted write */
+               break;
+       case GetHubDescriptor:
+               ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
+                       buf);
+               break;
+       case GetHubStatus:
+               /* no hub-wide feature/status flags */
+               memset (buf, 0, 4);
+               //cpu_to_le32s ((u32 *) buf);
+               break;
+       case GetPortStatus:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               memset (buf, 0, 4);
+               temp = readl (&ehci->regs->port_status [wIndex]);
+
+               // wPortChange bits
+               if (temp & PORT_CSC)
+                       set_bit (USB_PORT_FEAT_C_CONNECTION, buf);
+               if (temp & PORT_PEC)
+                       set_bit (USB_PORT_FEAT_C_ENABLE, buf);
+               // USB_PORT_FEAT_C_SUSPEND
+               if (temp & PORT_OCC)
+                       set_bit (USB_PORT_FEAT_C_OVER_CURRENT, buf);
+
+               /* whoever resets must GetPortStatus to complete it!! */
+               if ((temp & PORT_RESET)
+                               && jiffies > ehci->reset_done [wIndex]) {
+                       set_bit (USB_PORT_FEAT_C_RESET, buf);
+
+                       /* force reset to complete */
+                       writel (temp & ~PORT_RESET,
+                                       &ehci->regs->port_status [wIndex]);
+                       do {
+                               temp = readl (
+                                       &ehci->regs->port_status [wIndex]);
+                               udelay (10);
+                       } while (temp & PORT_RESET);
+
+                       /* see what we found out */
+                       temp = check_reset_complete (ehci, wIndex, temp);
+               }
+
+               // don't show wPortStatus if it's owned by a companion hc
+               if (!(temp & PORT_OWNER)) {
+                       if (temp & PORT_CONNECT) {
+                               set_bit (USB_PORT_FEAT_CONNECTION, buf);
+                               set_bit (USB_PORT_FEAT_HIGHSPEED, buf);
+                       }
+                       if (temp & PORT_PE)
+                               set_bit (USB_PORT_FEAT_ENABLE, buf);
+                       if (temp & PORT_SUSPEND)
+                               set_bit (USB_PORT_FEAT_SUSPEND, buf);
+                       if (temp & PORT_OC)
+                               set_bit (USB_PORT_FEAT_OVER_CURRENT, buf);
+                       if (temp & PORT_RESET)
+                               set_bit (USB_PORT_FEAT_RESET, buf);
+                       if (temp & PORT_POWER)
+                               set_bit (USB_PORT_FEAT_POWER, buf);
+               }
+
+#ifndef        EHCI_VERBOSE_DEBUG
+       if (*(u16*)(buf+2))     /* only if wPortChange is interesting */
+#endif
+               dbg_port (hcd, "GetStatus", wIndex + 1, temp);
+               cpu_to_le32s ((u32 *) buf);
+               break;
+       case SetHubFeature:
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* no hub-wide feature/status flags */
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case SetPortFeature:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               temp = readl (&ehci->regs->port_status [wIndex]);
+               if (temp & PORT_OWNER)
+                       break;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       writel (temp | PORT_SUSPEND,
+                               &ehci->regs->port_status [wIndex]);
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       if (HCS_PPC (params))
+                               writel (temp | PORT_POWER,
+                                       &ehci->regs->port_status [wIndex]);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       /* line status bits may report this as low speed */
+                       if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+                                       && PORT_USB11 (temp)) {
+                               dbg ("%s port %d low speed, give to companion",
+                                       hcd->bus_name, wIndex + 1);
+                               temp |= PORT_OWNER;
+                       } else {
+                               vdbg ("%s port %d reset",
+                                       hcd->bus_name, wIndex + 1);
+                               temp |= PORT_RESET;
+                               temp &= ~PORT_PE;
+
+                               /*
+                                * caller must wait, then call GetPortStatus
+                                * usb 2.0 spec says 50 ms resets on root
+                                */
+                               ehci->reset_done [wIndex] = jiffies
+                                       + ((50 /* msec */ * HZ) / 1000);
+                       }
+                       writel (temp, &ehci->regs->port_status [wIndex]);
+                       break;
+               default:
+                       goto error;
+               }
+               readl (&ehci->regs->command);   /* unblock posted writes */
+               break;
+
+       default:
+error:
+               /* "stall" on error */
+               retval = -EPIPE;
+       }
+       spin_unlock_irqrestore (&ehci->lock, flags);
+       return retval;
+}
diff --git a/drivers/usb/hcd/ehci-mem.c b/drivers/usb/hcd/ehci-mem.c
new file mode 100644 (file)
index 0000000..b2ee617
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *     - data used only by the HCD ... kmalloc is fine
+ *     - async and periodic schedules, shared by HC and HCD ... these
+ *       need to use pci_pool or pci_alloc_consistent
+ *     - driver buffers, read/written by HC ... single shot DMA mapped 
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+/* 
+ * Allocator / cleanup for the per device structure
+ * Called by hcd init / removal code
+ */
+static struct usb_hcd *ehci_hcd_alloc (void)
+{
+       struct ehci_hcd *ehci;
+
+       ehci = (struct ehci_hcd *)
+               kmalloc (sizeof (struct ehci_hcd), GFP_KERNEL);
+       if (ehci != 0) {
+               memset (ehci, 0, sizeof (struct ehci_hcd));
+               return &ehci->hcd;
+       }
+       return 0;
+}
+
+static void ehci_hcd_free (struct usb_hcd *hcd)
+{
+       kfree (hcd_to_ehci (hcd));
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
+{
+       struct ehci_qtd         *qtd;
+       dma_addr_t              dma;
+
+       qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
+       if (qtd != 0) {
+               memset (qtd, 0, sizeof *qtd);
+               qtd->qtd_dma = dma;
+               qtd->hw_next = EHCI_LIST_END;
+               qtd->hw_alt_next = EHCI_LIST_END;
+               INIT_LIST_HEAD (&qtd->qtd_list);
+       }
+       return qtd;
+}
+
+static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+       pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
+{
+       struct ehci_qh          *qh;
+       dma_addr_t              dma;
+
+       qh = (struct ehci_qh *)
+               pci_pool_alloc (ehci->qh_pool, flags, &dma);
+       if (qh) {
+               memset (qh, 0, sizeof *qh);
+               atomic_set (&qh->refcount, 1);
+               qh->qh_dma = dma;
+               // INIT_LIST_HEAD (&qh->qh_list);
+               INIT_LIST_HEAD (&qh->qtd_list);
+       }
+       return qh;
+}
+
+/* to share a qh (cpu threads, or hc) */
+static inline struct ehci_qh *qh_put (/* ehci, */ struct ehci_qh *qh)
+{
+       // dbg ("put %p (%d++)", qh, qh->refcount.counter);
+       atomic_inc (&qh->refcount);
+       return qh;
+}
+
+static void qh_unput (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+       // dbg ("unput %p (--%d)", qh, qh->refcount.counter);
+       if (!atomic_dec_and_test (&qh->refcount))
+               return;
+       /* clean qtds first, and know this is not linked */
+       if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
+               dbg ("unused qh not empty!");
+               BUG ();
+       }
+       pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied 
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void ehci_mem_cleanup (struct ehci_hcd *ehci)
+{
+       /* PCI consistent memory and pools */
+       if (ehci->qtd_pool)
+               pci_pool_destroy (ehci->qtd_pool);
+       ehci->qtd_pool = 0;
+
+       if (ehci->qh_pool) {
+               pci_pool_destroy (ehci->qh_pool);
+               ehci->qh_pool = 0;
+       }
+
+       if (ehci->itd_pool)
+               pci_pool_destroy (ehci->itd_pool);
+       ehci->itd_pool = 0;
+
+       if (ehci->sitd_pool)
+               pci_pool_destroy (ehci->sitd_pool);
+       ehci->sitd_pool = 0;
+
+       if (ehci->periodic)
+               pci_free_consistent (ehci->hcd.pdev,
+                       ehci->periodic_size * sizeof (u32),
+                       ehci->periodic, ehci->periodic_dma);
+       ehci->periodic = 0;
+
+       /* shadow periodic table */
+       if (ehci->pshadow)
+               kfree (ehci->pshadow);
+       ehci->pshadow = 0;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
+{
+       int i;
+
+       /* QTDs for control/bulk/intr transfers */
+       ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev,
+                       sizeof (struct ehci_qtd),
+                       32 /* byte alignment (for hw parts) */,
+                       4096 /* can't cross 4K */,
+                       flags);
+       if (!ehci->qtd_pool) {
+               dbg ("no qtd pool");
+               ehci_mem_cleanup (ehci);
+               return -ENOMEM;
+       }
+
+       /* QH for control/bulk/intr transfers */
+       ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev,
+                       sizeof (struct ehci_qh),
+                       32 /* byte alignment (for hw parts) */,
+                       4096 /* can't cross 4K */,
+                       flags);
+       if (!ehci->qh_pool) {
+               dbg ("no qh pool");
+               ehci_mem_cleanup (ehci);
+               return -ENOMEM;
+       }
+
+       /* ITD for high speed ISO transfers */
+       ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev,
+                       sizeof (struct ehci_itd),
+                       32 /* byte alignment (for hw parts) */,
+                       4096 /* can't cross 4K */,
+                       flags);
+       if (!ehci->itd_pool) {
+               dbg ("no itd pool");
+               ehci_mem_cleanup (ehci);
+               return -ENOMEM;
+       }
+
+       /* SITD for full/low speed split ISO transfers */
+       ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev,
+                       sizeof (struct ehci_sitd),
+                       32 /* byte alignment (for hw parts) */,
+                       4096 /* can't cross 4K */,
+                       flags);
+       if (!ehci->sitd_pool) {
+               dbg ("no sitd pool");
+               ehci_mem_cleanup (ehci);
+               return -ENOMEM;
+       }
+
+       /* Hardware periodic table */
+       ehci->periodic = (u32 *)
+               pci_alloc_consistent (ehci->hcd.pdev,
+                       ehci->periodic_size * sizeof (u32),
+                       &ehci->periodic_dma);
+       if (ehci->periodic == 0) {
+               dbg ("no hw periodic table");
+               ehci_mem_cleanup (ehci);
+               return -ENOMEM;
+       }
+       for (i = 0; i < ehci->periodic_size; i++)
+               ehci->periodic [i] = EHCI_LIST_END;
+
+       /* software shadow of hardware table */
+       ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *),
+               flags & ~EHCI_SLAB_FLAGS);
+       if (ehci->pshadow == 0) {
+               dbg ("no shadow periodic table");
+               ehci_mem_cleanup (ehci);
+               return -ENOMEM;
+       }
+       memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
+
+       return 0;
+}
diff --git a/drivers/usb/hcd/ehci-q.c b/drivers/usb/hcd/ehci-q.c
new file mode 100644 (file)
index 0000000..25a305d
--- /dev/null
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hardware queue manipulation
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number).  We use one QH per endpoint, queue
+ * multiple (bulk or control) urbs per endpoint.  URBs may need several qtds.
+ * A scheduled interrupt qh always has one qtd, one urb.
+ *
+ * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
+ * interrupts) needs careful scheduling.  Performance improvements can be
+ * an ongoing challenge.
+ * 
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries.  TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+#ifdef EHCI_SOFT_RETRIES
+static int soft_retries = EHCI_SOFT_RETRIES;
+MODULE_PARM (soft_retries, "i");
+MODULE_PARM_DESC (soft_retries, "Number of software retries for endpoint i/o");
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
+{
+       int     i, count;
+
+       /* one buffer entry per 4K ... first might be short or unaligned */
+       qtd->hw_buf [0] = cpu_to_le32 (buf);
+       count = 0x1000 - (buf & 0x0fff);        /* rest of that page */
+       if (likely (len < count))               /* ... iff needed */
+               count = len;
+       else {
+               buf +=  0x1000;
+               buf &= ~0x0fff;
+
+               /* per-qtd limit: from 16K to 20K (best alignment) */
+               for (i = 1; count < len && i < 5; i++) {
+                       u64     addr = buf;
+                       qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
+                       qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
+                       buf += 0x1000;
+                       if ((count + 0x1000) < len)
+                               count += 0x1000;
+                       else
+                               count = len;
+               }
+       }
+       qtd->hw_token = cpu_to_le32 ((count << 16) | token);
+       qtd->length = count;
+
+#if 0
+       vdbg ("  qtd_fill %p, token %8x bytes %d dma %x",
+               qtd, le32_to_cpu (qtd->hw_token), count, qtd->hw_buf [0]);
+#endif
+
+       return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* update halted (but potentially linked) qh */
+
+static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
+{
+       qh->hw_current = 0;
+       qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
+       qh->hw_alt_next = EHCI_LIST_END;
+
+       /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+       qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
+{
+       /* count IN/OUT bytes, not SETUP (even short packets) */
+       if (likely (QTD_PID (token) != 2))
+               urb->actual_length += length - QTD_LENGTH (token);
+
+       /* don't modify error codes */
+       if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) {
+               if (token & QTD_STS_BABBLE) {
+                       urb->status = -EOVERFLOW;
+               } else if (!QTD_CERR (token)) {
+                       if (token & QTD_STS_DBE)
+                               urb->status = (QTD_PID (token) == 1) /* IN ? */
+                                       ? -ENOSR  /* hc couldn't read data */
+                                       : -ECOMM; /* hc couldn't write data */
+                       else if (token & QTD_STS_MMF)   /* missed tt uframe */
+                               urb->status = -EPROTO;
+                       else if (token & QTD_STS_XACT) {
+                               if (QTD_LENGTH (token))
+                                       urb->status = -EPIPE;
+                               else {
+                                       dbg ("3strikes");
+                                       urb->status = -EPROTO;
+                               }
+                       } else  /* presumably a stall */
+                               urb->status = -EPIPE;
+
+               /* CERR nonzero + data left + halt --> stall */
+               } else if (QTD_LENGTH (token))
+                       urb->status = -EPIPE;
+               else    /* unknown */
+                       urb->status = -EPROTO;
+               dbg ("devpath %s ep %d-%s qtd token %x --> status %d",
+                       urb->dev->devpath, usb_pipeendpoint (urb->pipe),
+                       usb_pipein (urb->pipe) ? "in" : "out",
+                       token, urb->status);
+
+               /* stall indicates some recovery action is needed */
+               if (urb->status == -EPIPE) {
+                       int     pipe = urb->pipe;
+
+                       if (!usb_pipecontrol (pipe))
+                               usb_endpoint_halt (urb->dev,
+                                       usb_pipeendpoint (pipe),
+                                       usb_pipeout (pipe));
+                       if (urb->dev->tt && !usb_pipeint (pipe)) {
+err ("must CLEAR_TT_BUFFER, hub %s port %d%s addr %d ep %d",
+    urb->dev->tt->hub->devpath, urb->dev->ttport,
+    urb->dev->tt->multi ? "" : " (all-ports TT)",
+    urb->dev->devnum, usb_pipeendpoint (urb->pipe));
+                               // FIXME something (khubd?) should make the hub
+                               // CLEAR_TT_BUFFER ASAP, it's blocking other
+                               // fs/ls requests... hub_tt_clear_buffer() ?
+                       }
+               }
+       }
+}
+
+static void ehci_urb_complete (
+       struct ehci_hcd         *ehci,
+       dma_addr_t              addr,
+       struct urb              *urb
+) {
+       if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
+               pci_dma_sync_single (ehci->hcd.pdev, addr,
+                       urb->transfer_buffer_length,
+                       PCI_DMA_FROMDEVICE);
+
+       /* cleanse status if we saw no error */
+       if (likely (urb->status == -EINPROGRESS)) {
+               if (urb->actual_length != urb->transfer_buffer_length
+                               && (urb->transfer_flags & USB_DISABLE_SPD))
+                       urb->status = -EREMOTEIO;
+               else
+                       urb->status = 0;
+       }
+
+       /* only report unlinks once */
+       if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
+               urb->complete (urb);
+}
+
+/* urb->lock ignored from here on (hcd is done with urb) */
+
+static void ehci_urb_done (
+       struct ehci_hcd         *ehci,
+       dma_addr_t              addr,
+       struct urb              *urb
+) {
+       if (urb->transfer_buffer_length)
+               pci_unmap_single (ehci->hcd.pdev,
+                       addr,
+                       urb->transfer_buffer_length,
+                       usb_pipein (urb->pipe)
+                           ? PCI_DMA_FROMDEVICE
+                           : PCI_DMA_TODEVICE);
+       if (likely (urb->hcpriv != 0)) {
+               qh_unput (ehci, (struct ehci_qh *) urb->hcpriv);
+               urb->hcpriv = 0;
+       }
+
+       if (likely (urb->status == -EINPROGRESS)) {
+               if (urb->actual_length != urb->transfer_buffer_length
+                               && (urb->transfer_flags & USB_DISABLE_SPD))
+                       urb->status = -EREMOTEIO;
+               else
+                       urb->status = 0;
+       }
+
+       /* hand off urb ownership */
+       usb_hcd_giveback_urb (&ehci->hcd, urb);
+}
+
+
+/*
+ * Process completed qtds for a qh, issuing completions if needed.
+ * When freeing:  frees qtds, unmaps buf, returns URB to driver.
+ * When not freeing (queued periodic qh):  retain qtds, mapping, and urb.
+ * Races up to qh->hw_current; returns number of urb completions.
+ */
+static int
+qh_completions (
+       struct ehci_hcd         *ehci,
+       struct list_head        *qtd_list,
+       int                     freeing
+) {
+       struct ehci_qtd         *qtd = 0;
+       struct list_head        *next = 0;
+       u32                     token;
+       struct ehci_qh          *qh = 0;
+       struct urb              *urb = 0;
+       int                     halted = 0;
+       unsigned long           flags;
+       int                     retval = 0;
+
+       spin_lock_irqsave (&ehci->lock, flags);
+       if (unlikely (list_empty (qtd_list))) {
+               spin_unlock_irqrestore (&ehci->lock, flags);
+               return retval;
+       }
+
+       for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+                       next != qtd_list;
+                       qtd = list_entry (next, struct ehci_qtd, qtd_list)) {
+               token = le32_to_cpu (qtd->hw_token);
+               if (!qh) {
+                       urb = qtd->urb;
+                       qh = (struct ehci_qh *) urb->hcpriv;
+               }
+               if (likely (qh != 0)) {
+                       halted = halted
+                               || (ehci->hcd.state == USB_STATE_HALT)
+                               || (qh->qh_state == QH_STATE_IDLE);
+
+                       if (unlikely ((token & QTD_STS_HALT) != 0)) {
+#ifdef EHCI_SOFT_RETRIES
+                               /* extra soft retries for protocol errors */
+                               if (!halted
+                                               && qh->retries < soft_retries
+                                               && (QTD_STS_HALT|QTD_STS_XACT)
+                                                       == (token & 0xff)
+                                               && QTD_CERR (token) == 0) {
+                                       if (qh->retries == 0)
+                                               dbg ("soft retry, qh %p qtd %p",
+                                                       qh, qtd);
+                                       qh->retries++;
+                                       token &= ~0x0ff;
+                                       token |= QTD_STS_ACTIVE;
+                                       token |= (EHCI_TUNE_CERR << 10);
+                                       /* qtd update not needed */
+                                       qh->hw_token = cpu_to_le32 (token);
+                                       spin_unlock_irqrestore (&ehci->lock,
+                                               flags);
+                                       return;
+
+                               } else if (qh->retries >= soft_retries
+                                               && soft_retries) {
+                                       dbg ("retried %d times, qh %p qtd %p",
+                                               qh->retries, qh, qtd);
+                               }
+#endif /* EHCI_SOFT_RETRIES */
+                               halted = 1;
+                       }
+
+                       if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
+                               /* stop scan if qtd is visible to the HC */
+                               if (!halted) {
+                                       urb = 0;
+                                       break;
+                               }
+
+                               /* continue cleanup if HC is halted */
+                               if (ehci->hcd.state == USB_STATE_HALT) {
+                                       urb->status = -ESHUTDOWN;
+                                       goto scrub;
+                               }
+
+                               /* stall? some other urb was unlinked? */
+                               if (urb->status == -EINPROGRESS) {
+dbg ("?why? qh %p, qtd %p halted, urb %p, token %8x, len %d",
+       qh, qtd, urb, token, urb->actual_length);
+spin_unlock_irqrestore (&ehci->lock, flags);
+return retval;
+           /*
+            * FIXME: write this code.  When one queued urb is unlinked,
+            * unlink every succeeding urb.
+            */
+                                       continue;
+                               }
+
+                               /* else stopped for some other reason */
+                       } 
+scrub:
+                       spin_lock (&urb->lock);
+                       qtd_copy_status (urb, qtd->length, token);
+                       spin_unlock (&urb->lock);
+               }
+               next = qtd->qtd_list.next;
+
+               /*
+                * NOTE:  this won't work right with interrupt urbs that
+                * need multiple qtds ... only the first scan of qh->qtd_list
+                * starts at the right qtd, yet multiple scans could happen
+                * for transfers that are scheduled across multiple uframes. 
+                */
+               if (likely (freeing != 0))
+                       list_del (&qtd->qtd_list);
+               else {
+                       /* restore everything the HC could change
+                        * from an interrupt QTD
+                        */
+                       qtd->hw_token = (qtd->hw_token
+                                       & ~__constant_cpu_to_le32 (0x8300))
+                               | cpu_to_le32 (qtd->length << 16)
+                               | __constant_cpu_to_le32 (QTD_IOC
+                                       | (EHCI_TUNE_CERR << 10)
+                                       | QTD_STS_ACTIVE);
+                       qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
+
+                       /* this offset, and the length above,
+                        * are likely wrong on QTDs #2..N
+                        */
+                       qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma);
+               }
+
+               spin_unlock_irqrestore (&ehci->lock, flags);
+
+#if 0
+               if (urb->status == -EINPROGRESS)
+                       vdbg ("  qtd %p ok, urb %p, token %8x, len %d",
+                               qtd, urb, token, urb->actual_length);
+               else
+                       vdbg ("urb %p status %d, qtd %p, token %8x, len %d",
+                               urb, urb->status, qtd, token,
+                               urb->actual_length);
+#endif
+
+               /* SETUP for control urb? */
+               if (unlikely (QTD_PID (token) == 2))
+                       pci_unmap_single (ehci->hcd.pdev,
+                               qtd->buf_dma, sizeof (devrequest),
+                               PCI_DMA_TODEVICE);
+
+               /* another queued urb? */
+               if (unlikely (qtd->urb != urb)) {
+                       if (likely (freeing != 0))
+                               ehci_urb_done (ehci, qtd->buf_dma, urb);
+                       else
+                               ehci_urb_complete (ehci, qtd->buf_dma, urb);
+                       retval++;
+                       urb = qtd->urb;
+               }
+
+               if (likely (freeing != 0))
+                       ehci_qtd_free (ehci, qtd);
+               spin_lock_irqsave (&ehci->lock, flags);
+               qtd = list_entry (next, struct ehci_qtd, qtd_list);
+       }
+
+       /* patch up list head? */
+       if (unlikely (halted && qh && !list_empty (qtd_list))) {
+               qh_update (qh, list_entry (qtd_list->next,
+                               struct ehci_qtd, qtd_list));
+       }
+       spin_unlock_irqrestore (&ehci->lock, flags);
+
+       /* last urb's completion might still need calling */
+       if (likely (qtd && urb)) {
+               if (likely (freeing != 0))
+                       ehci_urb_done (ehci, qtd->buf_dma, urb);
+               else
+                       ehci_urb_complete (ehci, qtd->buf_dma, urb);
+               retval++;
+       }
+       return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction (
+       struct ehci_hcd         *ehci,
+       struct urb              *urb,
+       struct list_head        *head,
+       int                     flags
+) {
+       struct ehci_qtd         *qtd, *qtd_prev;
+       dma_addr_t              buf, map_buf;
+       int                     len, maxpacket;
+       u32                     token;
+
+       /*
+        * URBs map to sequences of QTDs:  one logical transaction
+        */
+       qtd = ehci_qtd_alloc (ehci, flags);
+       if (unlikely (!qtd))
+               return 0;
+       qtd_prev = 0;
+       list_add_tail (&qtd->qtd_list, head);
+       qtd->urb = urb;
+
+       token = QTD_STS_ACTIVE;
+       token |= (EHCI_TUNE_CERR << 10);
+       /* for split transactions, SplitXState initialized to zero */
+
+       if (usb_pipecontrol (urb->pipe)) {
+               /* control request data is passed in the "setup" pid */
+
+               /* NOTE:  this isn't smart about 64bit DMA, since it uses the
+                * default (32bit) mask rather than using the whole address
+                * space.  we could set pdev->dma_mask to all-ones while
+                * getting this mapping, locking it and restoring before
+                * allocating qtd/qh/... or maybe only do that for the main
+                * data phase (below).
+                */
+               qtd->buf_dma = pci_map_single (
+                                       ehci->hcd.pdev,
+                                       urb->setup_packet,
+                                       sizeof (devrequest),
+                                       PCI_DMA_TODEVICE);
+               if (unlikely (!qtd->buf_dma))
+                       goto cleanup;
+
+               /* SETUP pid */
+               qtd_fill (qtd, qtd->buf_dma, sizeof (devrequest),
+                       token | (2 /* "setup" */ << 8));
+
+               /* ... and always at least one more pid */
+               token ^= QTD_TOGGLE;
+               qtd_prev = qtd;
+               qtd = ehci_qtd_alloc (ehci, flags);
+               if (unlikely (!qtd))
+                       goto cleanup;
+               qtd->urb = urb;
+               qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+               list_add_tail (&qtd->qtd_list, head);
+       } 
+
+       /*
+        * data transfer stage:  buffer setup
+        */
+       len = urb->transfer_buffer_length;
+       if (likely (len > 0)) {
+               /* NOTE:  sub-optimal mapping with 64bit DMA (see above) */
+               buf = map_buf = pci_map_single (ehci->hcd.pdev,
+                       urb->transfer_buffer, len,
+                       usb_pipein (urb->pipe)
+                           ? PCI_DMA_FROMDEVICE
+                           : PCI_DMA_TODEVICE);
+               if (unlikely (!buf))
+                       goto cleanup;
+       } else
+               buf = map_buf = 0;
+
+       if (!buf || usb_pipein (urb->pipe))
+               token |= (1 /* "in" */ << 8);
+       /* else it's already initted to "out" pid (0 << 8) */
+
+       maxpacket = usb_maxpacket (urb->dev, urb->pipe,
+                       usb_pipeout (urb->pipe));
+
+       /*
+        * buffer gets wrapped in one or more qtds;
+        * last one may be "short" (including zero len)
+        * and may serve as a control status ack
+        */
+       for (;;) {
+               int this_qtd_len;
+
+               qtd->urb = urb;
+               qtd->buf_dma = map_buf;
+               this_qtd_len = qtd_fill (qtd, buf, len, token);
+               len -= this_qtd_len;
+               buf += this_qtd_len;
+
+               /* qh makes control packets use qtd toggle; maybe switch it */
+               if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+                       token ^= QTD_TOGGLE;
+
+               if (likely (len <= 0))
+                       break;
+
+               qtd_prev = qtd;
+               qtd = ehci_qtd_alloc (ehci, flags);
+               if (unlikely (!qtd))
+                       goto cleanup;
+               qtd->urb = urb;
+               qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+               list_add_tail (&qtd->qtd_list, head);
+       }
+
+       /*
+        * control requests may need a terminating data "status" ack;
+        * bulk ones may need a terminating short packet (zero length).
+        */
+       if (likely (buf != 0)) {
+               int     one_more = 0;
+
+               if (usb_pipecontrol (urb->pipe)) {
+                       one_more = 1;
+                       token ^= 0x0100;        /* "in" <--> "out"  */
+                       token |= QTD_TOGGLE;    /* force DATA1 */
+               } else if (usb_pipebulk (urb->pipe)
+                               && (urb->transfer_flags & USB_ZERO_PACKET)
+                               && !(urb->transfer_buffer_length % maxpacket)) {
+                       one_more = 1;
+               }
+               if (one_more) {
+                       qtd_prev = qtd;
+                       qtd = ehci_qtd_alloc (ehci, flags);
+                       if (unlikely (!qtd))
+                               goto cleanup;
+                       qtd->urb = urb;
+                       qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+                       list_add_tail (&qtd->qtd_list, head);
+
+                       /* never any data in such packets */
+                       qtd_fill (qtd, 0, 0, token);
+               }
+       }
+
+       /* by default, enable interrupt on urb completion */
+       if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
+               qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
+       return head;
+
+cleanup:
+       urb->status = -ENOMEM;
+       qh_completions (ehci, head, 1);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
+ * the hardware data toggle in the QH, and set the pseudo-toggle in udev
+ * so we can see if usb_clear_halt() was called.  NOP for control, since
+ * we set up qh->hw_info1 to always use the QTD toggle bits. 
+ */
+static inline void
+clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
+{
+       vdbg ("clear toggle, dev %d ep 0x%x-%s",
+               udev->devnum, ep, is_out ? "out" : "in");
+       qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+       usb_settoggle (udev, ep, is_out, 1);
+}
+
+// Would be best to create all qh's from config descriptors,
+// when each interface/altsetting is established.  Unlink
+// any previous qh and cancel its urbs first; endpoints are
+// implicitly reset then (data toggle too).
+// That'd mean updating how usbcore talks to HCDs. (2.5?)
+
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled.  For highspeed, that's
+ * just one microframe in the s-mask.  For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct ehci_qh *
+ehci_qh_make (
+       struct ehci_hcd         *ehci,
+       struct urb              *urb,
+       struct list_head        *qtd_list,
+       int                     flags
+) {
+       struct ehci_qh          *qh = ehci_qh_alloc (ehci, flags);
+       u32                     info1 = 0, info2 = 0;
+
+       if (!qh)
+               return qh;
+
+       /*
+        * init endpoint/device data for this QH
+        */
+       info1 |= usb_pipeendpoint (urb->pipe) << 8;
+       info1 |= usb_pipedevice (urb->pipe) << 0;
+
+       /* using TT? */
+       switch (urb->dev->speed) {
+       case USB_SPEED_LOW:
+               info1 |= (1 << 12);     /* EPS "low" */
+               /* FALL THROUGH */
+
+       case USB_SPEED_FULL:
+               /* EPS 0 means "full" */
+               info1 |= (EHCI_TUNE_RL_TT << 28);
+               if (usb_pipecontrol (urb->pipe)) {
+                       info1 |= (1 << 27);     /* for TT */
+                       info1 |= 1 << 14;       /* toggle from qtd */
+               }
+               info1 |= usb_maxpacket (urb->dev, urb->pipe,
+                                       usb_pipeout (urb->pipe)) << 16;
+
+               info2 |= (EHCI_TUNE_MULT_TT << 30);
+               info2 |= urb->dev->ttport << 23;
+               info2 |= urb->dev->tt->hub->devnum << 16;
+
+               /* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
+                * ... and a 0.96 scheduler might use FSTN nodes too
+                */
+               break;
+
+       case USB_SPEED_HIGH:            /* no TT involved */
+               info1 |= (2 << 12);     /* EPS "high" */
+               info1 |= (EHCI_TUNE_RL_HS << 28);
+               if (usb_pipecontrol (urb->pipe)) {
+                       info1 |= 64 << 16;      /* usb2 fixed maxpacket */
+                       info1 |= 1 << 14;       /* toggle from qtd */
+               } else if (usb_pipebulk (urb->pipe)) {
+                       info1 |= 512 << 16;     /* usb2 fixed maxpacket */
+                       info2 |= (EHCI_TUNE_MULT_HS << 30);
+               } else
+                       info1 |= usb_maxpacket (urb->dev, urb->pipe,
+                                               usb_pipeout (urb->pipe)) << 16;
+               break;
+       default:
+#ifdef DEBUG
+               BUG ();
+#endif
+       }
+
+       /* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
+
+       qh->qh_state = QH_STATE_IDLE;
+       qh->hw_info1 = cpu_to_le32 (info1);
+       qh->hw_info2 = cpu_to_le32 (info2);
+
+       /* initialize sw and hw queues with these qtds */
+       list_splice (qtd_list, &qh->qtd_list);
+       qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+
+       /* initialize data toggle state */
+       if (!usb_pipecontrol (urb->pipe))
+               clear_toggle (urb->dev,
+                       usb_pipeendpoint (urb->pipe),
+                       usb_pipeout (urb->pipe),
+                       qh);
+
+       return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* move qh (and its qtds) onto async queue; maybe enable queue.  */
+
+static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+       u32             dma = QH_NEXT (qh->qh_dma);
+       struct ehci_qh  *q;
+
+       if (unlikely (!(q = ehci->async))) {
+               u32     cmd = readl (&ehci->regs->command);
+
+               /* in case a clear of CMD_ASE didn't take yet */
+               while (readl (&ehci->regs->status) & STS_ASS)
+                       udelay (100);
+
+               qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
+               qh->qh_next.qh = qh;
+               qh->hw_next = dma;
+               ehci->async = qh;
+               writel ((u32)qh->qh_dma, &ehci->regs->async_next);
+               cmd |= CMD_ASE | CMD_RUN;
+               writel (cmd, &ehci->regs->command);
+               ehci->hcd.state = USB_STATE_RUNNING;
+               /* posted write need not be known to HC yet ... */
+       } else {
+               /* splice right after "start" of ring */
+               qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
+               qh->qh_next = q->qh_next;
+               qh->hw_next = q->hw_next;
+               q->qh_next.qh = qh;
+               q->hw_next = dma;
+       }
+       qh->qh_state = QH_STATE_LINKED;
+       /* qtd completions reported later by interrupt */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+submit_async (
+       struct ehci_hcd         *ehci,
+       struct urb              *urb,
+       struct list_head        *qtd_list,
+       int                     mem_flags
+) {
+       struct ehci_qtd         *qtd;
+       struct hcd_dev          *dev;
+       int                     epnum;
+       unsigned long           flags;
+       struct ehci_qh          *qh = 0;
+
+       qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+       dev = (struct hcd_dev *)urb->dev->hcpriv;
+       epnum = usb_pipeendpoint (urb->pipe);
+       if (usb_pipein (urb->pipe))
+               epnum |= 0x10;
+
+       vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+               ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
+               epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+               qtd, dev ? dev->ep [epnum] : (void *)~0);
+
+       spin_lock_irqsave (&ehci->lock, flags);
+
+       qh = (struct ehci_qh *) dev->ep [epnum];
+       if (likely (qh != 0)) {
+               u32     hw_next = QTD_NEXT (qtd->qtd_dma);
+
+               /* maybe patch the qh used for set_address */
+               if (unlikely (epnum == 0
+                               && le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
+                       qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));
+
+               /* is an URB is queued to this qh already? */
+               if (unlikely (!list_empty (&qh->qtd_list))) {
+                       struct ehci_qtd         *last_qtd;
+
+                       // dbg_qh ("non-empty qh", ehci, qh);
+                       last_qtd = list_entry (qh->qtd_list.prev,
+                                       struct ehci_qtd, qtd_list);
+                       last_qtd->hw_next = hw_next;
+
+                       /* previous urb allows short rx? maybe optimize. */
+                       if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD)
+                                       && (epnum & 0x10)) {
+                               // only the last QTD for now
+                               last_qtd->hw_alt_next = hw_next;
+                       }
+
+               /* no URB queued */
+               } else {
+                       // dbg_qh ("empty qh", ehci, qh);
+
+// FIXME:  how handle usb_clear_halt() for an EP with queued URBs?
+// usbcore may not let us handle that cleanly...
+// likely must cancel them all first!
+
+                       /* usb_clear_halt() means qh data toggle gets reset */
+                       if (usb_pipebulk (urb->pipe)
+                                       && unlikely (!usb_gettoggle (urb->dev,
+                                               (epnum & 0x0f),
+                                               !(epnum & 0x10)))) {
+                               clear_toggle (urb->dev,
+                                       epnum & 0x0f, !(epnum & 0x10), qh);
+                       }
+                       qh_update (qh, qtd);
+               }
+               list_splice (qtd_list, qh->qtd_list.prev);
+
+       } else {
+               /* can't sleep here, we have ehci->lock... */
+               qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
+               if (likely (qh != 0)) {
+                       // dbg_qh ("new qh", ehci, qh);
+                       dev->ep [epnum] = qh;
+               } else
+                       urb->status = -ENOMEM;
+       }
+
+       /* Control/bulk operations through TTs don't need scheduling,
+        * the HC and TT handle it when the TT has a buffer ready.
+        */
+       if (likely (qh != 0)) {
+               urb->hcpriv = qh_put (qh);
+               if (likely (qh->qh_state == QH_STATE_IDLE))
+                       qh_link_async (ehci, qh_put (qh));
+       }
+       spin_unlock_irqrestore (&ehci->lock, flags);
+       if (unlikely (!qh))
+               qh_completions (ehci, qtd_list, 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the async qh for the qtds being reclaimed are now unlinked from the HC */
+/* caller must not own ehci->lock */
+
+static void end_unlink_async (struct ehci_hcd *ehci)
+{
+       struct ehci_qh          *qh = ehci->reclaim;
+
+       qh->qh_state = QH_STATE_IDLE;
+       qh->qh_next.qh = 0;
+       qh_unput (ehci, qh);                    // refcount from reclaim 
+       ehci->reclaim = 0;
+       ehci->reclaim_ready = 0;
+
+       qh_completions (ehci, &qh->qtd_list, 1);
+
+       // FIXME unlink any urb should unlink all following urbs,
+       // so that this will never happen
+       if (!list_empty (&qh->qtd_list)
+                       && HCD_IS_RUNNING (ehci->hcd.state))
+               qh_link_async (ehci, qh);
+       else
+               qh_unput (ehci, qh);            // refcount from async list
+}
+
+
+/* makes sure the async qh will become idle */
+/* caller must own ehci->lock */
+
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+       int             cmd = readl (&ehci->regs->command);
+       struct ehci_qh  *prev;
+
+#ifdef DEBUG
+       if (ehci->reclaim
+                       || !ehci->async
+                       || qh->qh_state != QH_STATE_LINKED
+#ifdef CONFIG_SMP
+// this macro lies except on SMP compiles
+                       || !spin_is_locked (&ehci->lock)
+#endif
+                       )
+               BUG ();
+#endif
+
+       qh->qh_state = QH_STATE_UNLINK;
+       ehci->reclaim = qh = qh_put (qh);
+
+       // dbg_qh ("start unlink", ehci, qh);
+
+       /* Remove the last QH (qhead)?  Stop async schedule first. */
+       if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
+               /* can't get here without STS_ASS set */
+               if (ehci->hcd.state != USB_STATE_HALT) {
+                       if (cmd & CMD_PSE)
+                               writel (cmd & __constant_cpu_to_le32 (~CMD_ASE),
+                                       &ehci->regs->command);
+                       else {
+                               ehci_ready (ehci);
+                               while (!(readl (&ehci->regs->status) & STS_ASS))
+                                       udelay (100);
+                       }
+               }
+               qh->qh_next.qh = ehci->async = 0;
+
+               ehci->reclaim_ready = 1;
+               tasklet_schedule (&ehci->tasklet);
+               return;
+       } 
+
+       if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
+               ehci->reclaim_ready = 1;
+               tasklet_schedule (&ehci->tasklet);
+               return;
+       }
+
+       prev = ehci->async;
+       while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async)
+               prev = prev->qh_next.qh;
+#ifdef DEBUG
+       if (prev->qh_next.qh != qh)
+               BUG ();
+#endif
+
+       if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
+               ehci->async = prev;
+               prev->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD);
+       }
+       prev->hw_next = qh->hw_next;
+       prev->qh_next = qh->qh_next;
+
+       ehci->reclaim_ready = 0;
+       cmd |= CMD_IAAD;
+       writel (cmd, &ehci->regs->command);
+       /* posted write need not be known to HC yet ... */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_async (struct ehci_hcd *ehci)
+{
+       struct ehci_qh          *qh;
+       unsigned long           flags;
+
+       spin_lock_irqsave (&ehci->lock, flags);
+rescan:
+       qh = ehci->async;
+       if (likely (qh != 0)) {
+               do {
+                       /* clean any finished work for this qh */
+                       if (!list_empty (&qh->qtd_list)) {
+                               // dbg_qh ("scan_async", ehci, qh);
+                               qh = qh_put (qh);
+                               spin_unlock_irqrestore (&ehci->lock, flags);
+
+                               /* concurrent unlink could happen here */
+                               qh_completions (ehci, &qh->qtd_list, 1);
+
+                               spin_lock_irqsave (&ehci->lock, flags);
+                               qh_unput (ehci, qh);
+                       }
+
+                       /* unlink idle entries (reduces PCI usage) */
+                       if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
+                               if (qh->qh_next.qh != qh) {
+                                       // dbg ("irq/empty");
+                                       start_unlink_async (ehci, qh);
+                               } else {
+                                       // FIXME:  arrange to stop
+                                       // after it's been idle a while.
+                               }
+                       }
+                       qh = qh->qh_next.qh;
+                       if (!qh)                /* unlinked? */
+                               goto rescan;
+               } while (qh != ehci->async);
+       }
+
+       spin_unlock_irqrestore (&ehci->lock, flags);
+}
diff --git a/drivers/usb/hcd/ehci-sched.c b/drivers/usb/hcd/ehci-sched.c
new file mode 100644 (file)
index 0000000..905e506
--- /dev/null
@@ -0,0 +1,1053 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI scheduled transaction support:  interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ */
+
+/*
+ * Ceiling microseconds (typical) for that many bytes at high speed
+ * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
+ * to preallocate bandwidth)
+ */
+#define EHCI_HOST_DELAY        5       /* nsec, guess */
+#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+       + ((2083UL * (3167 + BitTime (bytes)))/1000) \
+       + EHCI_HOST_DELAY)
+#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
+       + ((2083UL * (3167 + BitTime (bytes)))/1000) \
+       + EHCI_HOST_DELAY)
+       
+static int ehci_get_frame (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd/sitd
+ * @tag: hardware tag for type of this record
+ */
+static union ehci_shadow *
+periodic_next_shadow (union ehci_shadow *periodic, int tag)
+{
+       switch (tag) {
+       case Q_TYPE_QH:
+               return &periodic->qh->qh_next;
+       case Q_TYPE_FSTN:
+               return &periodic->fstn->fstn_next;
+#ifdef have_iso
+       case Q_TYPE_ITD:
+               return &periodic->itd->itd_next;
+       case Q_TYPE_SITD:
+               return &periodic->sitd->sitd_next;
+#endif /* have_iso */
+       }
+       dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
+       // BUG ();
+       return 0;
+}
+
+/* returns true after successful unlink */
+/* caller must hold ehci->lock */
+static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+{
+       union ehci_shadow       *prev_p = &ehci->pshadow [frame];
+       u32                     *hw_p = &ehci->periodic [frame];
+       union ehci_shadow       here = *prev_p;
+       union ehci_shadow       *next_p;
+
+       /* find predecessor of "ptr"; hw and shadow lists are in sync */
+       while (here.ptr && here.ptr != ptr) {
+               prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
+               hw_p = &here.qh->hw_next;
+               here = *prev_p;
+       }
+       /* an interrupt entry (at list end) could have been shared */
+       if (!here.ptr) {
+               dbg ("entry %p no longer on frame [%d]", ptr, frame);
+               return 0;
+       }
+       // vdbg ("periodic unlink %p from frame %d", ptr, frame);
+
+       /* update hardware list ... HC may still know the old structure, so
+        * don't change hw_next until it'll have purged its cache
+        */
+       next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
+       *hw_p = here.qh->hw_next;
+
+       /* unlink from shadow list; HCD won't see old structure again */
+       *prev_p = *next_p;
+       next_p->ptr = 0;
+
+       return 1;
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
+{
+       u32                     *hw_p = &ehci->periodic [frame];
+       union ehci_shadow       *q = &ehci->pshadow [frame];
+       unsigned                usecs = 0;
+#ifdef have_iso
+       u32                     temp = 0;
+#endif
+
+       while (q->ptr) {
+               switch (Q_NEXT_TYPE (*hw_p)) {
+               case Q_TYPE_QH:
+                       /* is it in the S-mask? */
+                       if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
+                               usecs += q->qh->usecs;
+                       q = &q->qh->qh_next;
+                       break;
+               case Q_TYPE_FSTN:
+                       /* for "save place" FSTNs, count the relevant INTR
+                        * bandwidth from the previous frame
+                        */
+                       if (q->fstn->hw_prev != EHCI_LIST_END) {
+                               dbg ("not counting FSTN bandwidth yet ...");
+                       }
+                       q = &q->fstn->fstn_next;
+                       break;
+#ifdef have_iso
+               case Q_TYPE_ITD:
+                       temp = le32_to_cpu (q->itd->transaction [uframe]);
+                       temp >>= 16;
+                       temp &= 0x0fff;
+                       if (temp)
+                               usecs += HS_USECS_ISO (temp);
+                       q = &q->itd->itd_next;
+                       break;
+               case Q_TYPE_SITD:
+                       temp = q->sitd->hw_fullspeed_ep &
+                               __constant_cpu_to_le32 (1 << 31);
+
+                       // FIXME:  this doesn't count data bytes right...
+
+                       /* is it in the S-mask?  (count SPLIT, DATA) */
+                       if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
+                               if (temp)
+                                       usecs += HS_USECS (188);
+                               else
+                                       usecs += HS_USECS (1);
+                       }
+
+                       /* ... C-mask?  (count CSPLIT, DATA) */
+                       if (q->sitd->hw_uframe &
+                                       cpu_to_le32 (1 << (8 + uframe))) {
+                               if (temp)
+                                       usecs += HS_USECS (0);
+                               else
+                                       usecs += HS_USECS (188);
+                       }
+                       q = &q->sitd->sitd_next;
+                       break;
+#endif /* have_iso */
+               default:
+                       BUG ();
+               }
+       }
+#ifdef DEBUG
+       if (usecs > 100)
+               err ("overallocated uframe %d, periodic is %d usecs",
+                       frame * 8 + uframe, usecs);
+#endif
+       return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void intr_deschedule (
+       struct ehci_hcd *ehci,
+       unsigned        frame,
+       struct ehci_qh  *qh,
+       unsigned        period
+) {
+       unsigned long   flags;
+
+       spin_lock_irqsave (&ehci->lock, flags);
+
+       do {
+               periodic_unlink (ehci, frame, qh);
+               qh_unput (ehci, qh);
+               frame += period;
+       } while (frame < ehci->periodic_size);
+
+       qh->qh_state = QH_STATE_UNLINK;
+       qh->qh_next.ptr = 0;
+       ehci->periodic_urbs--;
+
+       /* maybe turn off periodic schedule */
+       if (!ehci->periodic_urbs) {
+               u32     cmd = readl (&ehci->regs->command);
+
+               /* did setting PSE not take effect yet?
+                * takes effect only at frame boundaries...
+                */
+               while (!(readl (&ehci->regs->status) & STS_PSS))
+                       udelay (20);
+
+               cmd &= ~CMD_PSE;
+               writel (cmd, &ehci->regs->command);
+               /* posted write ... */
+
+               ehci->next_frame = -1;
+       } else
+               vdbg ("periodic schedule still enabled");
+
+       spin_unlock_irqrestore (&ehci->lock, flags);
+
+       /*
+        * If the hc may be looking at this qh, then delay a uframe
+        * (yeech!) to be sure it's done.
+        * No other threads may be mucking with this qh.
+        */
+       if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0)
+               udelay (125);
+
+       qh->qh_state = QH_STATE_IDLE;
+       qh->hw_next = EHCI_LIST_END;
+
+       vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
+               qh, period, frame,
+               atomic_read (&qh->refcount), ehci->periodic_urbs);
+}
+
+static int intr_submit (
+       struct ehci_hcd         *ehci,
+       struct urb              *urb,
+       struct list_head        *qtd_list,
+       int                     mem_flags
+) {
+       unsigned                epnum, period;
+       unsigned                temp;
+       unsigned short          mult, usecs;
+       unsigned long           flags;
+       struct ehci_qh          *qh;
+       struct hcd_dev          *dev;
+       int                     status = 0;
+
+       /* get endpoint and transfer data */
+       epnum = usb_pipeendpoint (urb->pipe);
+       if (usb_pipein (urb->pipe)) {
+               temp = urb->dev->epmaxpacketin [epnum];
+               epnum |= 0x10;
+       } else
+               temp = urb->dev->epmaxpacketout [epnum];
+       mult = 1;
+       if (urb->dev->speed == USB_SPEED_HIGH) {
+               /* high speed "high bandwidth" is coded in ep maxpacket */
+               mult += (temp >> 11) & 0x03;
+               temp &= 0x03ff;
+       } else {
+               dbg ("no intr/tt scheduling yet"); 
+               status = -ENOSYS;
+               goto done;
+       }
+
+       /*
+        * NOTE: current completion/restart logic doesn't handle more than
+        * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
+        * such big requests need many periods to transfer.
+        */
+       if (unlikely (qtd_list->next != qtd_list->prev)) {
+               dbg ("only one intr qtd per urb allowed"); 
+               status = -EINVAL;
+               goto done;
+       }
+
+       usecs = HS_USECS (urb->transfer_buffer_length);
+
+       /*
+        * force a power-of-two (frames) sized polling interval
+        *
+        * NOTE: endpoint->bInterval for highspeed is measured in uframes,
+        * while for full/low speeds it's in frames.  Here we "know" that
+        * urb->interval doesn't give acccess to high interrupt rates.
+        */
+       period = ehci->periodic_size;
+       temp = period;
+       if (unlikely (urb->interval < 1))
+               urb->interval = 1;
+       while (temp > urb->interval)
+               temp >>= 1;
+       period = urb->interval = temp;
+
+       spin_lock_irqsave (&ehci->lock, flags);
+
+       /* get the qh (must be empty and idle) */
+       dev = (struct hcd_dev *)urb->dev->hcpriv;
+       qh = (struct ehci_qh *) dev->ep [epnum];
+       if (qh) {
+               /* only allow one queued interrupt urb per EP */
+               if (unlikely (qh->qh_state != QH_STATE_IDLE
+                               || !list_empty (&qh->qtd_list))) {
+                       dbg ("interrupt urb already queued");
+                       status = -EBUSY;
+               } else {
+                       /* maybe reset hardware's data toggle in the qh */
+                       if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
+                                       !(epnum & 0x10)))) {
+                               qh->hw_token |=
+                                       __constant_cpu_to_le32 (QTD_TOGGLE);
+                               usb_settoggle (urb->dev, epnum & 0x0f,
+                                       !(epnum & 0x10), 1);
+                       }
+                       /* trust the QH was set up as interrupt ... */
+                       list_splice (qtd_list, &qh->qtd_list);
+                       qh_update (qh, list_entry (qtd_list->next,
+                                               struct ehci_qtd, qtd_list));
+               }
+       } else {
+               /* can't sleep here, we have ehci->lock... */
+               qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
+               qtd_list = &qh->qtd_list;
+               if (likely (qh != 0)) {
+                       // dbg ("new INTR qh %p", qh);
+                       dev->ep [epnum] = qh;
+               } else
+                       status = -ENOMEM;
+       }
+
+       /* Schedule this periodic QH. */
+       if (likely (status == 0)) {
+               unsigned        frame = urb->interval;
+
+               qh->hw_next = EHCI_LIST_END;
+               qh->hw_info2 |= cpu_to_le32 (mult << 30);
+               qh->usecs = usecs;
+
+               urb->hcpriv = qh_put (qh);
+               status = -ENOSPC;
+
+               /* pick a set of schedule slots, link the QH into them */
+               do {
+                       int     uframe;
+
+                       /* Select some frame 0..(urb->interval - 1) with a
+                        * microframe that can hold this transaction.
+                        *
+                        * FIXME for TT splits, need uframes for start and end.
+                        * FSTNs can put end into next frame (uframes 0 or 1).
+                        */
+                       frame--;
+                       for (uframe = 0; uframe < 8; uframe++) {
+                               int     claimed;
+                               claimed = periodic_usecs (ehci, frame, uframe);
+                               /* 80% periodic == 100 usec max committed */
+                               if ((claimed + usecs) <= 100) {
+                                       vdbg ("frame %d.%d: %d usecs, plus %d",
+                                               frame, uframe, claimed, usecs);
+                                       break;
+                               }
+                       }
+                       if (uframe == 8)
+                               continue;
+// FIXME delete when code below handles non-empty queues
+                       if (ehci->pshadow [frame].ptr)
+                               continue;
+
+                       /* QH will run once each period, starting there  */
+                       urb->start_frame = frame;
+                       status = 0;
+
+                       /* set S-frame mask */
+                       qh->hw_info2 |= cpu_to_le32 (1 << uframe);
+                       // dbg_qh ("Schedule INTR qh", ehci, qh);
+
+                       /* stuff into the periodic schedule */
+                       qh->qh_state = QH_STATE_LINKED;
+                       vdbg ("qh %p usecs %d period %d starting frame %d.%d",
+                               qh, qh->usecs, period, frame, uframe);
+                       do {
+                               if (unlikely ((int)ehci->pshadow [frame].ptr)) {
+// FIXME -- just link to the end, before any qh with a shorter period,
+// AND handle it already being (implicitly) linked into this frame
+                                       BUG ();
+                               } else {
+                                       ehci->pshadow [frame].qh = qh_put (qh);
+                                       ehci->periodic [frame] =
+                                               QH_NEXT (qh->qh_dma);
+                               }
+                               frame += period;
+                       } while (frame < ehci->periodic_size);
+
+                       /* maybe enable periodic schedule processing */
+                       if (!ehci->periodic_urbs++) {
+                               u32     cmd;
+
+                               /* did clearing PSE did take effect yet?
+                                * takes effect only at frame boundaries...
+                                */
+                               while (readl (&ehci->regs->status) & STS_PSS)
+                                       udelay (20);
+
+                               cmd = readl (&ehci->regs->command) | CMD_PSE;
+                               writel (cmd, &ehci->regs->command);
+                               /* posted write ... PSS happens later */
+                               ehci->hcd.state = USB_STATE_RUNNING;
+
+                               /* make sure tasklet scans these */
+                               ehci->next_frame = ehci_get_frame (&ehci->hcd);
+                       }
+                       break;
+
+               } while (frame);
+       }
+       spin_unlock_irqrestore (&ehci->lock, flags);
+done:
+       if (status) {
+               usb_complete_t  complete = urb->complete;
+
+               urb->complete = 0;
+               urb->status = status;
+               qh_completions (ehci, qtd_list, 1);
+               urb->complete = complete;
+       }
+       return status;
+}
+
+static unsigned long
+intr_complete (
+       struct ehci_hcd *ehci,
+       unsigned        frame,
+       struct ehci_qh  *qh,
+       unsigned long   flags           /* caller owns ehci->lock ... */
+) {
+       struct ehci_qtd *qtd;
+       struct urb      *urb;
+       int             unlinking;
+
+       /* nothing to report? */
+       if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
+                       != 0))
+               return flags;
+       
+       qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
+       urb = qtd->urb;
+       unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET);
+
+       /* call any completions, after patching for reactivation */
+       spin_unlock_irqrestore (&ehci->lock, flags);
+       /* NOTE:  currently restricted to one qtd per qh! */
+       if (qh_completions (ehci, &qh->qtd_list, 0) == 0)
+               urb = 0;
+       spin_lock_irqsave (&ehci->lock, flags);
+
+       /* never reactivate requests that were unlinked ... */
+       if (likely (urb != 0)) {
+               if (unlinking
+                               || urb->status == -ECONNRESET
+                               || urb->status == -ENOENT
+                               // || (urb->dev == null)
+                               || ehci->hcd.state == USB_STATE_HALT)
+                       urb = 0;
+               // FIXME look at all those unlink cases ... we always
+               // need exactly one completion that reports unlink.
+               // the one above might not have been it!
+       }
+
+       /* normally reactivate */
+       if (likely (urb != 0)) {
+               if (usb_pipeout (urb->pipe))
+                       pci_dma_sync_single (ehci->hcd.pdev,
+                               qtd->buf_dma,
+                               urb->transfer_buffer_length,
+                               PCI_DMA_TODEVICE);
+               urb->status = -EINPROGRESS;
+               urb->actual_length = 0;
+
+               /* patch qh and restart */
+               qh_update (qh, qtd);
+       }
+       return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef have_iso
+
+static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd)
+{
+       pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+}
+
+/*
+ * Create itd and allocate into uframes within specified frame.
+ * Caller must update the resulting uframe links.
+ */
+static struct ehci_itd *
+itd_make (
+       struct ehci_hcd *ehci,
+       struct urb      *urb,
+       unsigned        index,          // urb->iso_frame_desc [index]
+       unsigned        frame,          // scheduled start
+       dma_addr_t      dma,            // mapped transfer buffer
+       int             mem_flags
+) {
+       struct ehci_itd *itd;
+       u64             temp;
+       u32             buf1;
+       unsigned        epnum, maxp, multi, usecs;
+       unsigned        length;
+       unsigned        i, bufnum;
+
+       /* allocate itd, start to fill it */
+       itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma);
+       if (!itd)
+               return itd;
+
+       itd->hw_next = EHCI_LIST_END;
+       itd->urb = urb;
+       itd->index = index;
+       INIT_LIST_HEAD (&itd->itd_list);
+       itd->uframe = (frame * 8) % ehci->periodic_size;
+
+       /* tell itd about the buffer its transfers will consume */
+       length = urb->iso_frame_desc [index].length;
+       dma += urb->iso_frame_desc [index].offset;
+       temp = dma & ~0x0fff;
+       for (i = 0; i < 7; i++) {
+               itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
+               itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
+               temp += 0x0fff;
+       }
+
+       /*
+        * this might be a "high bandwidth" highspeed endpoint,
+        * as encoded in the ep descriptor's maxpacket field
+        */
+       epnum = usb_pipeendpoint (urb->pipe);
+       if (usb_pipein (urb->pipe)) {
+               maxp = urb->dev->epmaxpacketin [epnum];
+               buf1 = (1 << 11) | maxp;
+       } else {
+               maxp = urb->dev->epmaxpacketout [epnum];
+               buf1 = maxp;
+       }
+       multi = 1;
+       multi += (temp >> 11) & 0x03;
+       maxp &= 0x03ff;
+
+       /* "plus" info in low order bits of buffer pointers */
+       itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
+       itd->hw_bufp [1] |= cpu_to_le32 (buf1);
+       itd->hw_bufp [2] |= cpu_to_le32 (multi);
+
+       /* schedule as many uframes as needed */
+       maxp *= multi;
+       usecs = HS_USECS_ISO (maxp);
+       bufnum = 0;
+       for (i = 0; i < 8; i++) {
+               unsigned        t, offset, scratch;
+
+               if (length <= 0) {
+                       itd->hw_transaction [i] = 0;
+                       continue;
+               }
+
+               /* don't commit more than 80% periodic == 100 usec */
+               if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100)
+                       continue;
+
+               /* we'll use this uframe; figure hw_transaction */
+               t = EHCI_ISOC_ACTIVE;
+               t |= bufnum << 12;              // which buffer?
+               offset = temp & 0x0fff;         // offset therein
+               t |= offset;
+               if ((offset + maxp) >= 4096)    // hc auto-wraps end-of-"page"
+                       bufnum++;
+               if (length <= maxp) {
+                       // interrupt only needed at end-of-urb
+                       if ((index + 1) == urb->number_of_packets)
+                               t |= EHCI_ITD_IOC;
+                       scratch = length;
+               } else
+                       scratch = maxp;
+               t |= scratch << 16;
+               t = cpu_to_le32 (t);
+
+               itd->hw_transaction [i] = itd->transaction [i] = t;
+               length -= scratch;
+       }
+       if (length > 0) {
+               dbg ("iso frame too big, urb %p [%d], %d extra (of %d)",
+                       urb, index, length, urb->iso_frame_desc [index].length);
+               itd_free (ehci, itd);
+               itd = 0;
+       }
+       return itd;
+}
+
+static inline void
+itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+{
+       u32             ptr;
+
+       ptr = cpu_to_le32 (itd->itd_dma);       // type 0 == itd
+       if (ehci->pshadow [frame].ptr) {
+               if (!itd->itd_next.ptr) {
+                       itd->itd_next = ehci->pshadow [frame];
+                       itd->hw_next = ehci->periodic [frame];
+               } else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) {
+                       dbg ("frame %d itd link goof", frame);
+                       BUG ();
+               }
+       }
+       ehci->pshadow [frame].itd = itd;
+       ehci->periodic [frame] = ptr;
+}
+
+#define        ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+
+static unsigned long
+itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags)
+{
+       struct urb              *urb = itd->urb;
+
+       /* if not unlinking: */
+       if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
+                       && ehci->hcd.state != USB_STATE_HALT) {
+               int                     i;
+               iso_packet_descriptor_t *desc;
+               struct ehci_itd         *first_itd = urb->hcpriv;
+
+               /* update status for this frame's transfers */
+               desc = &urb->iso_frame_desc [itd->index];
+               desc->status = 0;
+               desc->actual_length = 0;
+               for (i = 0; i < 8; i++) {
+                       u32      t = itd->hw_transaction [i];
+                       if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) {
+                               if (t & EHCI_ISOC_ACTIVE)
+                                       desc->status = -EXDEV;
+                               else if (t & EHCI_ISOC_BUF_ERR)
+                                       desc->status = usb_pipein (urb->pipe)
+                                               ? -ENOSR  /* couldn't read */
+                                               : -ECOMM; /* couldn't write */
+                               else if (t & EHCI_ISOC_BABBLE)
+                                       desc->status = -EOVERFLOW;
+                               else /* (t & EHCI_ISOC_XACTERR) */
+                                       desc->status = -EPROTO;
+                               break;
+                       }
+                       desc->actual_length += EHCI_ITD_LENGTH (t);
+               }
+
+               /* handle completion now? */
+               if ((itd->index + 1) != urb->number_of_packets)
+                       return flags;
+
+               i = usb_pipein (urb->pipe);
+               if (i)
+                       pci_dma_sync_single (ehci->hcd.pdev,
+                               first_itd->buf_dma,
+                               urb->transfer_buffer_length,
+                               PCI_DMA_FROMDEVICE);
+
+               /* call completion with no locks; it can unlink ... */
+               spin_unlock_irqrestore (&ehci->lock, flags);
+               urb->complete (urb);
+               spin_lock_irqsave (&ehci->lock, flags);
+
+               /* re-activate this URB? or unlink? */
+               if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
+                               && ehci->hcd.state != USB_STATE_HALT) {
+                       if (!i)
+                               pci_dma_sync_single (ehci->hcd.pdev,
+                                       first_itd->buf_dma,
+                                       urb->transfer_buffer_length,
+                                       PCI_DMA_TODEVICE);
+
+                       itd = urb->hcpriv;
+                       do {
+                               for (i = 0; i < 8; i++)
+                                       itd->hw_transaction [i]
+                                               = itd->transaction [i];
+                               itd = list_entry (itd->itd_list.next,
+                                               struct ehci_itd, itd_list);
+                       } while (itd != urb->hcpriv);
+                       return flags;
+               }
+
+       /* unlink done only on the last itd */
+       } else if ((itd->index + 1) != urb->number_of_packets)
+               return flags;
+
+       /* we're unlinking ... */
+
+       /* decouple urb from the hcd */
+       spin_unlock_irqrestore (&ehci->lock, flags);
+       if (ehci->hcd.state == USB_STATE_HALT)
+               urb->status = -ESHUTDOWN;
+       itd = urb->hcpriv;
+       urb->hcpriv = 0;
+       ehci_urb_done (ehci, itd->buf_dma, urb);
+       spin_lock_irqsave (&ehci->lock, flags);
+
+       /* take itds out of the hc's periodic schedule */
+       list_entry (itd->itd_list.prev, struct ehci_itd, itd_list)
+               ->itd_list.next = 0;
+       do {
+               struct ehci_itd *next;
+
+               if (itd->itd_list.next)
+                       next = list_entry (itd->itd_list.next,
+                               struct ehci_itd, itd_list);
+               else
+                       next = 0;
+
+               // FIXME:  hc WILL (!) lap us here, if we get behind
+               // by 128 msec (or less, with smaller periodic_size).
+               // Reading/caching these itds will cause trouble...
+
+               periodic_unlink (ehci, itd->uframe, itd);
+               itd_free (ehci, itd);
+               itd = next;
+       } while (itd);
+       return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb)
+{
+       struct ehci_itd         *first_itd = 0, *itd;
+       unsigned                frame_index;
+       dma_addr_t              dma;
+       unsigned long           flags;
+
+       dbg ("itd_submit");
+
+       /* set up one dma mapping for this urb */
+       dma = pci_map_single (ehci->hcd.pdev,
+               urb->transfer_buffer, urb->transfer_buffer_length,
+               usb_pipein (urb->pipe)
+                   ? PCI_DMA_FROMDEVICE
+                   : PCI_DMA_TODEVICE);
+       if (dma == 0)
+               return -ENOMEM;
+
+       /*
+        * Schedule as needed.  This is VERY optimistic about free
+        * bandwidth!  But the API assumes drivers can pick frames
+        * intelligently (how?), so there's no other good option.
+        *
+        * FIXME  this doesn't handle urb->next rings, or try to
+        * use the iso periodicity.
+        */
+       if (urb->transfer_flags & USB_ISO_ASAP) { 
+               urb->start_frame = ehci_get_frame (&ehci->hcd);
+               urb->start_frame++;
+       }
+       urb->start_frame %= ehci->periodic_size;
+
+       /* create and populate itds (doing uframe scheduling) */
+       spin_lock_irqsave (&ehci->lock, flags);
+       for (frame_index = 0;
+                       frame_index < urb->number_of_packets;
+                       frame_index++) {
+               itd = itd_make (ehci, urb, frame_index,
+                       urb->start_frame + frame_index,
+                       dma, SLAB_ATOMIC);
+               if (itd) {
+                       if (first_itd)
+                               list_add_tail (&itd->itd_list,
+                                               &first_itd->itd_list);
+                       else
+                               first_itd = itd;
+               } else {
+                       spin_unlock_irqrestore (&ehci->lock, flags);
+                       if (first_itd) {
+                               while (!list_empty (&first_itd->itd_list)) {
+                                       itd = list_entry (
+                                               first_itd->itd_list.next,
+                                               struct ehci_itd, itd_list);
+                                       list_del (&itd->itd_list);
+                                       itd_free (ehci, itd);
+                               }
+                               itd_free (ehci, first_itd);
+                       }
+                       pci_unmap_single (ehci->hcd.pdev,
+                               dma, urb->transfer_buffer_length,
+                               usb_pipein (urb->pipe)
+                                   ? PCI_DMA_FROMDEVICE
+                                   : PCI_DMA_TODEVICE);
+                       return -ENOMEM;
+               }
+       }
+
+       /* stuff into the schedule */
+       itd = first_itd;
+       do {
+               unsigned        i;
+
+               for (i = 0; i < 8; i++) {
+                       if (!itd->hw_transaction [i])
+                               continue;
+                       itd_link (ehci, itd->uframe + i, itd);
+               }
+               itd = list_entry (itd->itd_list.next,
+                       struct ehci_itd, itd_list);
+       } while (itd != first_itd);
+       urb->hcpriv = first_itd;
+
+       spin_unlock_irqrestore (&ehci->lock, flags);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * "Split ISO TDs" ... used for USB 1.1 devices going through
+ * the TTs in USB 2.0 hubs.
+ */
+
+static inline void
+sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+{
+       pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
+}
+
+static struct ehci_sitd *
+sitd_make (
+       struct ehci_hcd *ehci,
+       struct urb      *urb,
+       unsigned        index,          // urb->iso_frame_desc [index]
+       unsigned        uframe,         // scheduled start
+       dma_addr_t      dma,            // mapped transfer buffer
+       int             mem_flags
+) {
+       struct ehci_sitd        *sitd;
+       unsigned                length;
+
+       sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);
+       if (!sitd)
+               return sitd;
+       sitd->urb = urb;
+       length = urb->iso_frame_desc [index].length;
+       dma += urb->iso_frame_desc [index].offset;
+
+#if 0
+       // FIXME:  do the rest!
+#else
+       sitd_free (ehci, sitd);
+       return 0;
+#endif
+
+}
+
+static inline void
+sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
+{
+       u32             ptr;
+
+       ptr = cpu_to_le32 (sitd->sitd_dma | 2); // type 2 == sitd
+       if (ehci->pshadow [frame].ptr) {
+               if (!sitd->sitd_next.ptr) {
+                       sitd->sitd_next = ehci->pshadow [frame];
+                       sitd->hw_next = ehci->periodic [frame];
+               } else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {
+                       dbg ("frame %d sitd link goof", frame);
+                       BUG ();
+               }
+       }
+       ehci->pshadow [frame].sitd = sitd;
+       ehci->periodic [frame] = ptr;
+}
+
+static unsigned long
+sitd_complete (
+       struct ehci_hcd *ehci,
+       struct ehci_sitd        *sitd,
+       unsigned long           flags
+) {
+       // FIXME -- implement!
+
+       dbg ("NYI -- sitd_complete");
+       return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
+{
+       // struct ehci_sitd     *first_sitd = 0;
+       unsigned                frame_index;
+       dma_addr_t              dma;
+       int                     mem_flags;
+
+       dbg ("NYI -- sitd_submit");
+
+       // FIXME -- implement!
+
+       // FIXME:  setup one big dma mapping
+       dma = 0;
+
+       mem_flags = SLAB_ATOMIC;
+
+       for (frame_index = 0;
+                       frame_index < urb->number_of_packets;
+                       frame_index++) {
+               struct ehci_sitd        *sitd;
+               unsigned                uframe;
+
+               // FIXME:  use real arguments, schedule this!
+               uframe = -1;
+
+               sitd = sitd_make (ehci, urb, frame_index,
+                               uframe, dma, mem_flags);
+
+               if (sitd) {
+    /*
+                       if (first_sitd)
+                               list_add_tail (&sitd->sitd_list,
+                                               &first_sitd->sitd_list);
+                       else
+                               first_sitd = sitd;
+    */
+               } else {
+                       // FIXME:  clean everything up
+               }
+       }
+
+       // if we have a first sitd, then
+               // store them all into the periodic schedule!
+               // urb->hcpriv = first sitd in sitd_list
+
+       return -ENOSYS;
+}
+
+#endif /* have_iso */
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_periodic (struct ehci_hcd *ehci)
+{
+       unsigned        frame;
+       unsigned        clock;
+       unsigned long   flags;
+
+       spin_lock_irqsave (&ehci->lock, flags);
+
+       /*
+        * When running, scan from last scan point up to "now"
+        * Touches as few pages as possible:  cache-friendly.
+        * It's safe to scan entries more than once, though.
+        */
+       if (HCD_IS_RUNNING (ehci->hcd.state)) {
+               frame = ehci->next_frame;
+               clock = ehci_get_frame (&ehci->hcd);
+
+       /* when shutting down, scan everything for thoroughness */
+       } else {
+               frame = 0;
+               clock = ehci->periodic_size - 1;
+       }
+       for (;;) {
+               union ehci_shadow        q;
+               u32     type;
+
+restart:
+               q.ptr = ehci->pshadow [frame].ptr;
+               type = Q_NEXT_TYPE (ehci->periodic [frame]);
+
+               /* scan each element in frame's queue for completions */
+               while (q.ptr != 0) {
+                       int                     last;
+                       union ehci_shadow       temp;
+
+                       switch (type) {
+                       case Q_TYPE_QH:
+                               last = (q.qh->hw_next == EHCI_LIST_END);
+                               flags = intr_complete (ehci, frame,
+                                               qh_put (q.qh), flags);
+                               type = Q_NEXT_TYPE (q.qh->hw_next);
+                               temp = q.qh->qh_next;
+                               qh_unput (ehci, q.qh);
+                               q = temp;
+                               break;
+                       case Q_TYPE_FSTN:
+                               last = (q.fstn->hw_next == EHCI_LIST_END);
+                               /* for "save place" FSTNs, look at QH entries
+                                * in the previous frame for completions.
+                                */
+                               if (q.fstn->hw_prev != EHCI_LIST_END) {
+                                       dbg ("ignoring completions from FSTNs");
+                               }
+                               type = Q_NEXT_TYPE (q.fstn->hw_next);
+                               temp = q.fstn->fstn_next;
+                               break;
+#ifdef have_iso
+                       case Q_TYPE_ITD:
+                               last = (q.itd->hw_next == EHCI_LIST_END);
+                               flags = itd_complete (ehci, q.itd, flags);
+                               type = Q_NEXT_TYPE (q.itd->hw_next);
+                               q = q.itd->itd_next;
+                               break;
+                       case Q_TYPE_SITD:
+                               last = (q.sitd->hw_next == EHCI_LIST_END);
+                               flags = sitd_complete (ehci, q.sitd, flags);
+                               type = Q_NEXT_TYPE (q.sitd->hw_next);
+                               q = q.sitd->sitd_next;
+                               break;
+#endif /* have_iso */
+                       default:
+                               dbg ("corrupt type %d frame %d shadow %p",
+                                       type, frame, q.ptr);
+                               // BUG ();
+                               last = 1;
+                               q.ptr = 0;
+                       }
+
+                       /* did completion remove an interior q entry? */
+                       if (unlikely (q.ptr == 0 && !last))
+                               goto restart;
+               }
+
+               /* stop when we catch up to the HC */
+
+               // FIXME:  this assumes we won't get lapped when
+               // latencies climb; that should be rare, but...
+               // detect it, and just go all the way around.
+               // FLR might help detect this case, so long as latencies
+               // don't exceed periodic_size msec (default 1.024 sec).
+
+               // FIXME:  likewise assumes HC doesn't halt mid-scan
+
+               if (frame == clock) {
+                       unsigned        now;
+
+                       if (!HCD_IS_RUNNING (ehci->hcd.state))
+                               break;
+                       ehci->next_frame = clock;
+                       now = ehci_get_frame (&ehci->hcd);
+                       if (clock == now)
+                               break;
+                       clock = now;
+               } else if (++frame >= ehci->periodic_size)
+                       frame = 0;
+       } 
+       spin_unlock_irqrestore (&ehci->lock, flags);
+ }
diff --git a/drivers/usb/hcd/ehci.h b/drivers/usb/hcd/ehci.h
new file mode 100644 (file)
index 0000000..eda9129
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_EHCI_HCD_H
+#define __LINUX_EHCI_HCD_H
+
+/* definitions used for the EHCI driver */
+
+/* ehci_hcd->lock guards shared data against other CPUs:
+ *   ehci_hcd: async, reclaim, periodic (and shadow), ...
+ *   hcd_dev:  ep[]
+ *   ehci_qh:  qh_next, qtd_list
+ *   ehci_qtd: qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define        EHCI_MAX_ROOT_PORTS     15              /* see HCS_N_PORTS */
+
+struct ehci_hcd {                      /* one per controller */
+       spinlock_t              lock;
+
+       /* async schedule support */
+       struct ehci_qh          *async;
+       struct ehci_qh          *reclaim;
+       int                     reclaim_ready;
+
+       /* periodic schedule support */
+#define        DEFAULT_I_TDPS          1024            /* some HCs can do less */
+       unsigned                periodic_size;
+       u32                     *periodic;      /* hw periodic table */
+       dma_addr_t              periodic_dma;
+       unsigned                i_thresh;       /* uframes HC might cache */
+
+       union ehci_shadow       *pshadow;       /* mirror hw periodic table */
+       int                     next_frame;     /* scan periodic, start here */
+       unsigned                periodic_urbs;  /* how many urbs scheduled? */
+
+       /* deferred work from IRQ, etc */
+       struct tasklet_struct   tasklet;
+
+       /* per root hub port */
+       unsigned long           reset_done [EHCI_MAX_ROOT_PORTS];
+
+       /* glue to PCI and HCD framework */
+       struct usb_hcd          hcd;
+       struct ehci_caps        *caps;
+       struct ehci_regs        *regs;
+
+       /* per-HC memory pools (could be per-PCI-bus, but ...) */
+       struct pci_pool         *qh_pool;       /* qh per active urb */
+       struct pci_pool         *qtd_pool;      /* one or more per qh */
+       struct pci_pool         *itd_pool;      /* itd per iso urb */
+       struct pci_pool         *sitd_pool;     /* sitd per split iso urb */
+};
+
+/* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
+#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
+
+/* NOTE:  urb->transfer_flags expected to not use this bit !!! */
+#define EHCI_STATE_UNLINK      0x8000          /* urb being unlinked */
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+       u8              length;         /* CAPLENGTH - size of this struct */
+       u8              reserved;       /* offset 0x1 */
+       u16             hci_version;    /* HCIVERSION - offset 0x2 */
+       u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)      (((p)>>20)&0xf) /* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_N_CC(p)            (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)           (((p)>>8)&0xf)  /* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)      ((p)&(1 << 7))  /* true: port routing */ 
+#define HCS_PPC(p)             ((p)&(1 << 4))  /* true: port power control */ 
+#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
+
+       u32             hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)                (((p)>>8)&0xff) /* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)         ((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+       u8              portroute [8];   /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+       /* USBCMD: offset 0x00 */
+       u32             command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK       (1<<11)         /* enable "park" on async qh */
+#define CMD_PARK_CNT(c)        (((c)>>8)&3)    /* how many transfers to park for */
+#define CMD_LRESET     (1<<7)          /* partial reset (no ports, etc) */
+#define CMD_IAAD       (1<<6)          /* "doorbell" interrupt async advance */
+#define CMD_ASE                (1<<5)          /* async schedule enable */
+#define CMD_PSE        (1<<4)          /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET      (1<<1)          /* reset HC not bus */
+#define CMD_RUN                (1<<0)          /* start/stop HC */
+
+       /* USBSTS: offset 0x04 */
+       u32             status;
+#define STS_ASS                (1<<15)         /* Async Schedule Status */
+#define STS_PSS                (1<<14)         /* Periodic Schedule Status */
+#define STS_RECL       (1<<13)         /* Reclamation */
+#define STS_HALT       (1<<12)         /* Not running (any reason) */
+/* some bits reserved */
+       /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA                (1<<5)          /* Interrupted on async advance */
+#define STS_FATAL      (1<<4)          /* such as some PCI access errors */
+#define STS_FLR                (1<<3)          /* frame list rolled over */
+#define STS_PCD                (1<<2)          /* port change detect */
+#define STS_ERR                (1<<1)          /* "error" completion (overflow, ...) */
+#define STS_INT                (1<<0)          /* "normal" completion (short, ...) */
+
+       /* USBINTR: offset 0x08 */
+       u32             intr_enable;
+
+       /* FRINDEX: offset 0x0C */
+       u32             frame_index;    /* current microframe number */
+       /* CTRLDSSEGMENT: offset 0x10 */
+       u32             segment;        /* address bits 63:32 if needed */
+       /* PERIODICLISTBASE: offset 0x14 */
+       u32             frame_list;     /* points to periodic list */
+       /* ASYNCICLISTADDR: offset 0x18 */
+       u32             async_next;     /* address of next async queue head */
+
+       u32             reserved [9];
+
+       /* CONFIGFLAG: offset 0x40 */
+       u32             configured_flag;
+#define FLAG_CF                (1<<0)          /* true: we'll support "high speed" */
+
+       /* PORTSC: offset 0x44 */
+       u32             port_status [0];        /* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E    (1<<22)         /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E  (1<<21)         /* wake on disconnect (enable) */
+#define PORT_WKCONN_E  (1<<20)         /* wake on connect (enable) */
+/* 19:16 for port testing */
+/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
+#define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
+#define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET     (1<<8)          /* reset port */
+#define PORT_SUSPEND   (1<<7)          /* suspend port */
+#define PORT_RESUME    (1<<6)          /* resume it */
+#define PORT_OCC       (1<<5)          /* over current change */
+#define PORT_OC                (1<<4)          /* over current active */
+#define PORT_PEC       (1<<3)          /* port enable change */
+#define PORT_PE                (1<<2)          /* port enable */
+#define PORT_CSC       (1<<1)          /* connect status change */
+#define PORT_CONNECT   (1<<0)          /* device connected */
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+#define        QTD_NEXT(dma)   cpu_to_le32((u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...) 
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+       /* first part defined by EHCI spec */
+       u32                     hw_next;          /* see EHCI 3.5.1 */
+       u32                     hw_alt_next;      /* see EHCI 3.5.2 */
+       u32                     hw_token;         /* see EHCI 3.5.3 */       
+#define        QTD_TOGGLE      (1 << 31)       /* data toggle */
+#define        QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define        QTD_IOC         (1 << 15)       /* interrupt on complete */
+#define        QTD_CERR(tok)   (((tok)>>10) & 0x3)
+#define        QTD_PID(tok)    (((tok)>>8) & 0x3)
+#define        QTD_STS_ACTIVE  (1 << 7)        /* HC may execute this */
+#define        QTD_STS_HALT    (1 << 6)        /* halted on error */
+#define        QTD_STS_DBE     (1 << 5)        /* data buffer error (in HC) */
+#define        QTD_STS_BABBLE  (1 << 4)        /* device was babbling (qtd halted) */
+#define        QTD_STS_XACT    (1 << 3)        /* device gave illegal response */
+#define        QTD_STS_MMF     (1 << 2)        /* incomplete split transaction */
+#define        QTD_STS_STS     (1 << 1)        /* split transaction state */
+#define        QTD_STS_PING    (1 << 0)        /* issue PING? */
+       u32                     hw_buf [5];        /* see EHCI 3.5.4 */
+       u32                     hw_buf_hi [5];        /* Appendix B */
+
+       /* the rest is HCD-private */
+       dma_addr_t              qtd_dma;                /* qtd address */
+       struct list_head        qtd_list;               /* sw qtd list */
+
+       /* dma same in urb's qtds, except 1st control qtd (setup buffer) */
+       struct urb              *urb;                   /* qtd's urb */
+       dma_addr_t              buf_dma;                /* buffer address */
+       size_t                  length;                 /* length of buffer */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,sitd,fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_ITD     __constant_cpu_to_le32 (0 << 1)
+#define Q_TYPE_QH      __constant_cpu_to_le32 (1 << 1)
+#define Q_TYPE_SITD    __constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN    __constant_cpu_to_le32 (3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define        QH_NEXT(dma)    (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define        EHCI_LIST_END   __constant_cpu_to_le32(1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure.  That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule.  Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union ehci_shadow {
+       struct ehci_qh          *qh;            /* Q_TYPE_QH */
+       struct ehci_itd         *itd;           /* Q_TYPE_ITD */
+       struct ehci_sitd        *sitd;          /* Q_TYPE_SITD */
+       struct ehci_fstn        *fstn;          /* Q_TYPE_FSTN */
+       void                    *ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+struct ehci_qh {
+       /* first part defined by EHCI spec */
+       u32                     hw_next;         /* see EHCI 3.6.1 */
+       u32                     hw_info1;        /* see EHCI 3.6.2 */
+#define        QH_HEAD         0x00008000
+       u32                     hw_info2;        /* see EHCI 3.6.2 */
+       u32                     hw_current;      /* qtd list - see EHCI 3.6.4 */
+       
+       /* qtd overlay (hardware parts of a struct ehci_qtd) */
+       u32                     hw_qtd_next;
+       u32                     hw_alt_next;
+       u32                     hw_token;
+       u32                     hw_buf [5];
+       u32                     hw_buf_hi [5];
+
+       /* the rest is HCD-private */
+       dma_addr_t              qh_dma;         /* address of qh */
+       union ehci_shadow       qh_next;        /* ptr to qh; or periodic */
+       struct list_head        qtd_list;       /* sw qtd list */
+
+       atomic_t                refcount;
+       unsigned short          usecs;          /* intr bandwidth */
+       short                   qh_state;
+#define        QH_STATE_LINKED         1               /* HC sees this */
+#define        QH_STATE_UNLINK         2               /* HC may still see this */
+#define        QH_STATE_IDLE           3               /* HC doesn't see this */
+
+#ifdef EHCI_SOFT_RETRIES
+       int                     retries;
+#endif
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct ehci_itd {
+       /* first part defined by EHCI spec */
+       u32                     hw_next;           /* see EHCI 3.3.1 */
+       u32                     hw_transaction [8]; /* see EHCI 3.3.2 */
+#define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
+#define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
+#define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
+#define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
+#define        EHCI_ITD_LENGTH(tok)    (((tok)>>16) & 0x7fff)
+#define        EHCI_ITD_IOC            (1 << 15)       /* interrupt on complete */
+
+       u32                     hw_bufp [7];    /* see EHCI 3.3.3 */ 
+       u32                     hw_bufp_hi [7]; /* Appendix B */
+
+       /* the rest is HCD-private */
+       dma_addr_t              itd_dma;        /* for this itd */
+       union ehci_shadow       itd_next;       /* ptr to periodic q entry */
+
+       struct urb              *urb;
+       unsigned                index;          /* in urb->iso_frame_desc */
+       struct list_head        itd_list;       /* list of urb frames' itds */
+       dma_addr_t              buf_dma;        /* frame's buffer address */
+
+       unsigned                uframe;         /* in periodic schedule */
+       u32                     transaction [8]; /* copy of hw_transaction */
+
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.4 
+ * siTD, aka split-transaction isochronous Transfer Descriptor
+ *       ... describe low/full speed iso xfers through TT in hubs
+ * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
+ */
+struct ehci_sitd {
+       /* first part defined by EHCI spec */
+       u32                     hw_next;
+/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
+       u32                     hw_fullspeed_ep;  /* see EHCI table 3-9 */
+       u32                     hw_uframe;        /* see EHCI table 3-10 */
+        u32                     hw_tx_results1;   /* see EHCI table 3-11 */
+       u32                     hw_tx_results2;   /* see EHCI table 3-12 */
+       u32                     hw_tx_results3;   /* see EHCI table 3-12 */
+        u32                     hw_backpointer;   /* see EHCI table 3-13 */
+       u32                     hw_buf_hi [2];    /* Appendix B */
+
+       /* the rest is HCD-private */
+       dma_addr_t              sitd_dma;
+       union ehci_shadow       sitd_next;      /* ptr to periodic q entry */
+       struct urb              *urb;
+       dma_addr_t              buf_dma;        /* buffer address */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct ehci_fstn {
+       u32                     hw_next;        /* any periodic q entry */
+       u32                     hw_prev;        /* qh or EHCI_LIST_END */
+
+       /* the rest is HCD-private */
+       dma_addr_t              fstn_dma;
+       union ehci_shadow       fstn_next;      /* ptr to periodic q entry */
+} __attribute__ ((aligned (32)));
+
+#endif /* __LINUX_EHCI_HCD_H */
index 0e52bf2ea3fcfcc5261fddd3a79e3f5d78240948..78b9f1926b6e1204aa2feb98853c02f4f3255594 100644 (file)
@@ -35,7 +35,7 @@ static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
 static DECLARE_MUTEX(usb_address0_sem);
 
 static LIST_HEAD(hub_event_list);      /* List of hubs needing servicing */
-static LIST_HEAD(hub_list);            /* List containing all of the hubs (for cleanup) */
+static LIST_HEAD(hub_list);            /* List of all hubs (for cleanup) */
 
 static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 static int khubd_pid = 0;                      /* PID of khubd */
@@ -110,22 +110,30 @@ static int usb_get_port_status(struct usb_device *dev, int port, void *data)
                data, sizeof(struct usb_hub_status), HZ);
 }
 
+/* completion function, fires on port status changes and various faults */
 static void hub_irq(struct urb *urb)
 {
        struct usb_hub *hub = (struct usb_hub *)urb->context;
        unsigned long flags;
 
-       /* Cause a hub reset after 10 consecutive errors */
-       if (urb->status) {
-               if (urb->status == -ENOENT)
-                       return;
-
-               dbg("nonzero status in irq %d", urb->status);
+       switch (urb->status) {
+       case -ENOENT:           /* synchronous unlink */
+       case -ECONNRESET:       /* async unlink */
+       case -ESHUTDOWN:        /* hardware going away */
+               return;
 
+       default:                /* presumably an error */
+               /* Cause a hub reset after 10 consecutive errors */
+               dbg("hub '%s' status %d for interrupt transfer",
+                       urb->dev->devpath, urb->status);
                if ((++hub->nerrors < 10) || hub->error)
                        return;
-
                hub->error = urb->status;
+               /* FALL THROUGH */
+       
+       /* let khubd handle things */
+       case 0:                 /* we got data:  port status changed */
+               break;
        }
 
        hub->nerrors = 0;
@@ -152,7 +160,8 @@ static void usb_hub_power_on(struct usb_hub *hub)
        wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
 }
 
-static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
+static int usb_hub_configure(struct usb_hub *hub,
+       struct usb_endpoint_descriptor *endpoint)
 {
        struct usb_device *dev = hub->dev;
        struct usb_hub_status hubstatus;
@@ -162,22 +171,30 @@ static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor
 
        hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
        if (!hub->descriptor) {
-               err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor));
+               err("Unable to kmalloc %Zd bytes for hub descriptor",
+                       sizeof(*hub->descriptor));
                return -1;
        }
 
-       /* Request the entire hub descriptor. */
-       ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor));
-               /* <hub->descriptor> is large enough for a hub with 127 ports;
-                * the hub can/will return fewer bytes here. */
+       /* Request the entire hub descriptor.
+        * hub->descriptor can handle USB_MAXCHILDREN ports,
+        * but the hub can/will return fewer bytes here.
+        */
+       ret = usb_get_hub_descriptor(dev, hub->descriptor,
+                       sizeof(*hub->descriptor));
        if (ret < 0) {
                err("Unable to get hub descriptor (err = %d)", ret);
                kfree(hub->descriptor);
                return -1;
+       } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+               err("Hub is too big! %d children", hub->descriptor->bNbrPorts);
+               kfree(hub->descriptor);
+               return -1;
        }
 
        dev->maxchild = hub->descriptor->bNbrPorts;
-       info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s");
+       info("%d port%s detected", dev->maxchild,
+               (dev->maxchild == 1) ? "" : "s");
 
        le16_to_cpus(&hub->descriptor->wHubCharacteristics);
 
@@ -217,9 +234,12 @@ static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor
                        break;
                case 1:
                        dbg("Single TT");
+                       hub->tt.hub = dev;
                        break;
                case 2:
-                       dbg("Multiple TT");
+                       dbg("TT per port");
+                       hub->tt.hub = dev;
+                       hub->tt.multi = 1;
                        break;
                default:
                        dbg("Unrecognized hub protocol %d",
@@ -244,13 +264,18 @@ static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor
        }
 
        dbg("Port indicators are %s supported", 
-           (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not");
+           (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND)
+               ? "" : "not");
 
-       dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2);
-       dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent);
+       dbg("power on to power good time: %dms",
+               hub->descriptor->bPwrOn2PwrGood * 2);
+       dbg("hub controller current requirement: %dmA",
+               hub->descriptor->bHubContrCurrent);
 
        for (i = 0; i < dev->maxchild; i++)
-               portstr[i] = hub->descriptor->DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R';
+               portstr[i] = hub->descriptor->DeviceRemovable
+                           [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+                       ? 'F' : 'R';
        portstr[dev->maxchild] = 0;
 
        dbg("port removable status: %s", portstr);
@@ -265,7 +290,8 @@ static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor
        le16_to_cpus(&hubstatus.wHubStatus);
 
        dbg("local power source is %s",
-               (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+               (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER)
+               ? "lost (inactive)" : "good");
 
        dbg("%sover-current condition exists",
                (hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
@@ -337,14 +363,15 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
        }
 
        /* If it's not an interrupt endpoint, we'd better punt! */
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
-               err("Device #%d is hub class, but has endpoint other than interrupt?",
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                       != USB_ENDPOINT_XFER_INT) {
+               err("Device #%d is hub class, but endpoint is not interrupt?",
                        dev->devnum);
                return NULL;
        }
 
        /* We found a hub */
-       info("USB hub found");
+       info("USB hub found at %s", dev->devpath);
 
        hub = kmalloc(sizeof(*hub), GFP_KERNEL);
        if (!hub) {
@@ -367,7 +394,7 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
        if (usb_hub_configure(hub, endpoint) >= 0)
                return hub;
 
-       err("hub configuration failed for device #%d", dev->devnum);
+       err("hub configuration failed for device at %s", dev->devpath);
 
        /* free hub, but first clean up its list. */
        spin_lock_irqsave(&hub_event_lock, flags);
@@ -436,7 +463,8 @@ static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
                                if (hub->children[i] == NULL)
                                        info->port[i] = 0;
                                else
-                                       info->port[i] = hub->children[i]->devnum;
+                                       info->port[i] =
+                                               hub->children[i]->devnum;
                        }
                }
                spin_unlock_irqrestore(&hub_event_lock, flags);
@@ -493,7 +521,7 @@ static void usb_hub_disconnect(struct usb_device *dev)
                }
        }
 
-       err("cannot disconnect hub %d", dev->devnum);
+       err("cannot disconnect hub %s", dev->devpath);
 }
 
 #define HUB_RESET_TRIES                5
@@ -510,14 +538,17 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
        struct usb_port_status portsts;
        unsigned short portchange, portstatus;
 
-       for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) {
+       for (delay_time = 0;
+                       delay_time < HUB_RESET_TIMEOUT;
+                       delay_time += delay) {
                /* wait to give the device a chance to reset */
                wait_ms(delay);
 
                /* read and decode port status */
                ret = usb_get_port_status(hub, port + 1, &portsts);
                if (ret < 0) {
-                       err("get_port_status(%d) failed (err = %d)", port + 1, ret);
+                       err("get_port_status(%d) failed (err = %d)",
+                               port + 1, ret);
                        return -1;
                }
 
@@ -546,8 +577,8 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
                if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
                        delay = HUB_LONG_RESET_TIME;
 
-               dbg("port %d of hub %d not reset yet, waiting %dms", port + 1,
-                       hub->devnum, delay);
+               dbg("port %d of hub %s not reset yet, waiting %dms", port + 1,
+                       hub->devpath, delay);
        }
 
        return -1;
@@ -566,17 +597,18 @@ static int usb_hub_port_reset(struct usb_device *hub, int port,
                /* return on disconnect or reset */
                status = usb_hub_port_wait_reset(hub, port, dev, delay);
                if (status != -1) {
-                       usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
+                       usb_clear_port_feature(hub,
+                               port + 1, USB_PORT_FEAT_C_RESET);
                        return status;
                }
 
-               dbg("port %d of hub %d not enabled, trying reset again...",
-                       port + 1, hub->devnum);
+               dbg("port %d of hub %s not enabled, trying reset again...",
+                       port + 1, hub->devpath);
                delay = HUB_LONG_RESET_TIME;
        }
 
-       err("Cannot enable port %i of hub %d, disabling port.",
-               port + 1, hub->devnum);
+       err("Cannot enable port %i of hub %s, disabling port.",
+               port + 1, hub->devpath);
        err("Maybe the USB cable is bad?");
 
        return -1;
@@ -588,23 +620,24 @@ void usb_hub_port_disable(struct usb_device *hub, int port)
 
        ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
        if (ret)
-               err("cannot disable port %d of hub %d (err = %d)",
-                       port + 1, hub->devnum, ret);
+               err("cannot disable port %d of hub %s (err = %d)",
+                       port + 1, hub->devpath, ret);
 }
 
-static void usb_hub_port_connect_change(struct usb_device *hub, int port,
+static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
                                        struct usb_port_status *portsts)
 {
+       struct usb_device *hub = hubstate->dev;
        struct usb_device *dev;
        unsigned short portstatus, portchange;
        unsigned int delay = HUB_SHORT_RESET_TIME;
        int i;
-       char *portstr, *tempstr;
 
        portstatus = le16_to_cpu(portsts->wPortStatus);
        portchange = le16_to_cpu(portsts->wPortChange);
-       dbg("port %d, portstatus %x, change %x, %s",
-               port + 1, portstatus, portchange, portspeed (portstatus));
+       dbg("hub %s port %d, portstatus %x, change %x, %s",
+               hub->devpath, port + 1,
+               portstatus, portchange, portspeed (portstatus));
 
        /* Clear the connection change status */
        usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
@@ -630,11 +663,9 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port,
 
        down(&usb_address0_sem);
 
-       tempstr = kmalloc(1024, GFP_KERNEL);
-       portstr = kmalloc(1024, GFP_KERNEL);
-
        for (i = 0; i < HUB_PROBE_TRIES; i++) {
-               struct usb_device *pdev, *cdev;
+               struct usb_device *pdev;
+               int     len;
 
                /* Allocate a new device struct */
                dev = usb_alloc_dev(hub, hub->bus);
@@ -645,41 +676,46 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port,
 
                hub->children[port] = dev;
 
-               /* Reset the device */
+               /* Reset the device, and detect its speed */
                if (usb_hub_port_reset(hub, port, dev, delay)) {
                        usb_free_dev(dev);
                        break;
                }
 
-               /* Find a new device ID for it */
+               /* Find a new address for it */
                usb_connect(dev);
 
-               /* Create a readable topology string */
-               cdev = dev;
-               pdev = dev->parent;
-               if (portstr && tempstr) {
-                       portstr[0] = 0;
-                       while (pdev) {
-                               int port;
-
-                               for (port = 0; port < pdev->maxchild; port++)
-                                       if (pdev->children[port] == cdev)
-                                               break;
-
-                               strcpy(tempstr, portstr);
-                               if (!strlen(tempstr))
-                                       sprintf(portstr, "%d", port + 1);
-                               else
-                                       sprintf(portstr, "%d/%s", port + 1, tempstr);
+               /* Set up TT records, if needed  */
+               if (hub->tt) {
+                       dev->tt = hub->tt;
+                       dev->ttport = hub->ttport;
+               } else if (dev->speed != USB_SPEED_HIGH
+                               && hub->speed == USB_SPEED_HIGH) {
+                       dev->tt = &hubstate->tt;
+                       dev->ttport = port + 1;
+               }
 
-                               cdev = pdev;
-                               pdev = pdev->parent;
-                       }
-                       info("USB new device connect on bus%d/%s, assigned device number %d",
-                               dev->bus->busnum, portstr, dev->devnum);
-               } else
-                       info("USB new device connect on bus%d, assigned device number %d",
-                               dev->bus->busnum, dev->devnum);
+               /* Save readable and stable topology id, distinguishing
+                * devices by location for diagnostics, tools, etc.  The
+                * string is a path along hub ports, from the root.  Each
+                * device's id will be stable until USB is re-cabled, and
+                * hubs are often labled with these port numbers.
+                *
+                * Initial size: "/NN" times five hubs + NUL = 16 bytes max
+                * (quite rare, since most hubs have 4-6 ports).
+                */
+               pdev = dev->parent;
+               if (pdev->devpath [1] != '\0')  /* parent not root */
+                       len = snprintf (dev->devpath, sizeof dev->devpath,
+                               "%s/%d", pdev->devpath, port + 1);
+               else    /* root == "/", root port 2 == "/2" */
+                       len = snprintf (dev->devpath, sizeof dev->devpath,
+                               "/%d", port + 1);
+               if (len == sizeof dev->devpath)
+                       warn ("devpath size! usb/%03d/%03d path %s",
+                               dev->bus->busnum, dev->devnum, dev->devpath);
+               info("new USB device on bus %d path %s, assigned address %d",
+                       dev->bus->busnum, dev->devpath, dev->devnum);
 
                /* Run it through the hoops (find a driver, etc) */
                if (!usb_new_device(dev))
@@ -696,10 +732,6 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port,
        usb_hub_port_disable(hub, port);
 done:
        up(&usb_address0_sem);
-       if (portstr)
-               kfree(portstr);
-       if (tempstr)
-               kfree(tempstr);
 }
 
 static void usb_hub_events(void)
@@ -737,10 +769,12 @@ static void usb_hub_events(void)
                spin_unlock_irqrestore(&hub_event_lock, flags);
 
                if (hub->error) {
-                       dbg("resetting hub %d for error %d", dev->devnum, hub->error);
+                       dbg("resetting hub %s for error %d",
+                               dev->devpath, hub->error);
 
                        if (usb_hub_reset(hub)) {
-                               err("error resetting hub %d - disconnecting", dev->devnum);
+                               err("error resetting hub %s - disconnecting",
+                                       dev->devpath);
                                up(&hub->khubd_sem);
                                usb_hub_disconnect(dev);
                                continue;
@@ -756,7 +790,8 @@ static void usb_hub_events(void)
 
                        ret = usb_get_port_status(dev, i + 1, &portsts);
                        if (ret < 0) {
-                               err("get_port_status failed (err = %d)", ret);
+                               err("hub %s get_port_status failed (err = %d)",
+                                       dev->devpath, ret);
                                continue;
                        }
 
@@ -764,55 +799,68 @@ static void usb_hub_events(void)
                        portchange = le16_to_cpu(portsts.wPortChange);
 
                        if (portchange & USB_PORT_STAT_C_CONNECTION) {
-                               dbg("port %d connection change", i + 1);
-
-                               usb_hub_port_connect_change(dev, i, &portsts);
+                               dbg("hub %s port %d connection change",
+                                       dev->devpath, i + 1);
+                               usb_hub_port_connect_change(hub, i, &portsts);
                        } else if (portchange & USB_PORT_STAT_C_ENABLE) {
-                               dbg("port %d enable change, status %x", i + 1, portstatus);
-                               usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
+                               dbg("hub %s port %d enable change, status %x",
+                                       dev->devpath, i + 1, portstatus);
+                               usb_clear_port_feature(dev,
+                                       i + 1, USB_PORT_FEAT_C_ENABLE);
 
                                /*
-                                * EM interference sometimes causes bad shielded USB devices to 
-                                * be shutdown by the hub, this hack enables them again.
+                                * EM interference sometimes causes badly
+                                * shielded USB devices to be shutdown by
+                                * the hub, this hack enables them again.
                                 * Works at least with mouse driver. 
                                 */
-                               if (!(portstatus & USB_PORT_STAT_ENABLE) && 
-                                   (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
-                                       err("already running port %i disabled by hub (EMI?), re-enabling...",
-                                               i + 1);
-                                       usb_hub_port_connect_change(dev, i, &portsts);
+                               if (!(portstatus & USB_PORT_STAT_ENABLE)
+                                   && (portstatus & USB_PORT_STAT_CONNECTION)
+                                   && (dev->children[i])) {
+                                       err("already running hub %s port %i "
+                                           "disabled by hub (EMI?), "
+                                           "re-enabling...",
+                                               dev->devpath, i + 1);
+                                       usb_hub_port_connect_change(hub,
+                                               i, &portsts);
                                }
                        }
 
                        if (portchange & USB_PORT_STAT_C_SUSPEND) {
-                               dbg("port %d suspend change", i + 1);
-                               usb_clear_port_feature(dev, i + 1,  USB_PORT_FEAT_C_SUSPEND);
+                               dbg("hub %s port %d suspend change",
+                                       dev->devpath, i + 1);
+                               usb_clear_port_feature(dev,
+                                       i + 1,  USB_PORT_FEAT_C_SUSPEND);
                        }
                        
                        if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
-                               err("port %d over-current change", i + 1);
-                               usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+                               err("hub %s port %d over-current change",
+                                       dev->devpath, i + 1);
+                               usb_clear_port_feature(dev,
+                                       i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
                                usb_hub_power_on(hub);
                        }
 
                        if (portchange & USB_PORT_STAT_C_RESET) {
-                               dbg("port %d reset change", i + 1);
-                               usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
+                               dbg("hub %s port %d reset change",
+                                       dev->devpath, i + 1);
+                               usb_clear_port_feature(dev,
+                                       i + 1, USB_PORT_FEAT_C_RESET);
                        }
                } /* end for i */
 
                /* deal with hub status changes */
                if (usb_get_hub_status(dev, &hubsts) < 0)
-                       err("get_hub_status failed");
+                       err("get_hub_status %s failed", dev->devpath);
                else {
                        hubstatus = le16_to_cpup(&hubsts.wHubStatus);
                        hubchange = le16_to_cpup(&hubsts.wHubChange);
                        if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-                               dbg("hub power change");
+                               dbg("hub %s power change", dev->devpath);
                                usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
                        }
                        if (hubchange & HUB_CHANGE_OVERCURRENT) {
-                               dbg("hub overcurrent change");
+                               dbg("hub %s overcurrent change", dev->devpath);
                                wait_ms(500);   /* Cool down */
                                usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
                                usb_hub_power_on(hub);
@@ -851,6 +899,8 @@ static int usb_hub_thread(void *__hub)
 }
 
 static struct usb_device_id hub_id_table [] = {
+    { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS,
+      bDeviceClass: USB_CLASS_HUB},
     { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
       bInterfaceClass: USB_CLASS_HUB},
     { }                                                /* Terminating entry */
@@ -989,9 +1039,13 @@ int usb_reset_device(struct usb_device *dev)
                ret = usb_get_device_descriptor(dev);
                if (ret < sizeof(dev->descriptor)) {
                        if (ret < 0)
-                               err("unable to get device descriptor (error=%d)", ret);
+                               err("unable to get device %s descriptor "
+                                       "(error=%d)", dev->devpath, ret);
                        else
-                               err("USB device descriptor short read (expected %Zi, got %i)", sizeof(dev->descriptor), ret);
+                               err("USB device %s descriptor short read "
+                                       "(expected %Zi, got %i)",
+                                       dev->devpath,
+                                       sizeof(dev->descriptor), ret);
         
                        clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
                        dev->devnum = -1;
@@ -1015,17 +1069,22 @@ int usb_reset_device(struct usb_device *dev)
 
        ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
        if (ret < 0) {
-               err("failed to set active configuration (error=%d)", ret);
+               err("failed to set dev %s active configuration (error=%d)",
+                       dev->devpath, ret);
                return ret;
        }
 
        for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
                struct usb_interface *intf = &dev->actconfig->interface[i];
-               struct usb_interface_descriptor *as = &intf->altsetting[intf->act_altsetting];
+               struct usb_interface_descriptor *as;
 
-               ret = usb_set_interface(dev, as->bInterfaceNumber, as->bAlternateSetting);
+               as = &intf->altsetting[intf->act_altsetting];
+               ret = usb_set_interface(dev, as->bInterfaceNumber,
+                       as->bAlternateSetting);
                if (ret < 0) {
-                       err("failed to set active alternate setting for interface %d (error=%d)", i, ret);
+                       err("failed to set active alternate setting "
+                               "for dev %s interface %d (error=%d)",
+                               dev->devpath, i, ret);
                        return ret;
                }
        }
index 50ae148c5156ca6b4cd8a6bda38fbc5bd6720e40..566da376d553b1a3a0d4f5e374afdcc293fe75c3 100644 (file)
@@ -1,6 +1,13 @@
 #ifndef __LINUX_HUB_H
 #define __LINUX_HUB_H
 
+/*
+ * Hub protocol and driver data structures.
+ *
+ * Some of these are known to the "virtual root hub" code
+ * in host controller drivers.
+ */
+
 #include <linux/list.h>
 
 /*
 #define USB_RT_HUB     (USB_TYPE_CLASS | USB_RECIP_DEVICE)
 #define USB_RT_PORT    (USB_TYPE_CLASS | USB_RECIP_OTHER)
 
+/*
+ * Hub class requests
+ * See USB 2.0 spec Table 11-16
+ */
+#define HUB_CLEAR_TT_BUFFER    8
+#define HUB_RESET_TT           9
+#define HUB_GET_TT_STATE       10
+#define HUB_STOP_TT            11
+
 /*
  * Hub Class feature numbers
  * See USB 2.0 spec Table 11-17
@@ -55,7 +71,7 @@ struct usb_port_status {
 #define USB_PORT_STAT_SUSPEND          0x0004
 #define USB_PORT_STAT_OVERCURRENT      0x0008
 #define USB_PORT_STAT_RESET            0x0010
-/* bits 5 for 7 are reserved */
+/* bits 5 to 7 are reserved */
 #define USB_PORT_STAT_POWER            0x0100
 #define USB_PORT_STAT_LOW_SPEED                0x0200
 #define USB_PORT_STAT_HIGH_SPEED        0x0400
@@ -120,22 +136,21 @@ struct usb_hub_descriptor {
 struct usb_device;
 
 struct usb_hub {
-       struct usb_device *dev;
-
-       struct urb *urb;                /* Interrupt polling pipe */
-
-       char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */
-                                       /* and add 7 bits to round up to byte boundary */
-       int error;
-       int nerrors;
+       struct usb_device       *dev;           /* the "real" device */
+       struct urb              *urb;           /* for interrupt polling pipe */
 
-       struct list_head hub_list;
+       /* buffer for urb ... 1 bit each for hub and children, rounded up */
+       char                    buffer[(USB_MAXCHILDREN + 1 + 7) / 8];
 
-       struct list_head event_list;
+       int                     error;          /* last reported error */
+       int                     nerrors;        /* track consecutive errors */
 
-       struct usb_hub_descriptor *descriptor;
+       struct list_head        hub_list;       /* all hubs */
+       struct list_head        event_list;     /* hubs w/data or errs ready */
 
-       struct semaphore khubd_sem;
+       struct usb_hub_descriptor *descriptor;  /* class descriptor */
+       struct semaphore        khubd_sem;
+       struct usb_tt           tt;             /* Transaction Translator */
 };
 
 #endif /* __LINUX_HUB_H */
index cd38ce06a7833bb09512d089659ec9c3f8c385d9..a73a209dc971384fcbb8deee56991bb5bd3b5725 100644 (file)
@@ -3,8 +3,8 @@
 /*
  *     inode.c  --  Inode/Dentry functions for the USB device file system.
  *
- *     Copyright (C) 2000
- *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *     Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *     Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  *
  *     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
  *     along with this program; if not, write to the Free Software
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *  $Id: inode.c,v 1.3 2000/01/11 13:58:25 tom Exp $
- *
  *  History:
  *   0.1  04.01.2000  Created
+ *   0.2  10.12.2001  converted to use the vfs layer better
  */
 
 /*****************************************************************************/
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/locks.h>
+#include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
-#include <asm/uaccess.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * This list of superblocks is still used,
- * but since usbdevfs became FS_SINGLE
- * there is only one super_block.
- */
-static LIST_HEAD(superlist);
-
-struct special {
-       const char *name;
-       struct file_operations *fops;
-       struct inode *inode;
-       struct list_head inodes;
-};
-
-static struct special special[] = { 
-       { "devices", &usbdevfs_devices_fops,  },
-       { "drivers", &usbdevfs_drivers_fops,  }
-};
-
-#define NRSPECIAL (sizeof(special)/sizeof(special[0]))
-
-/* --------------------------------------------------------------------- */
-
-static int dnumber(struct dentry *dentry)
-{
-       const char *name;
-       unsigned int s;
-
-       if (dentry->d_name.len != 3)
-               return -1;
-       name = dentry->d_name.name;
-       if (name[0] < '0' || name[0] > '9' ||
-           name[1] < '0' || name[1] > '9' ||
-           name[2] < '0' || name[2] > '9')
-               return -1;
-       s = name[0] - '0';
-       s = s * 10 + name[1] - '0';
-       s = s * 10 + name[2] - '0';
-       return s;
-}
-
-/*
- * utility functions; should be called with the kernel lock held
- * to protect against busses/devices appearing/disappearing
- */
-
-static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
-{
-       struct inode *inode;
-       unsigned int devnum = dev->devnum;
-       unsigned int busnum = dev->bus->busnum;
-
-       if (devnum < 1 || devnum > 127 || busnum > 255)
-               return;
-       inode = iget(sb, IDEVICE | (busnum << 8) | devnum);
-       if (!inode) {
-               printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum);
-               return;
-       }
-       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       inode->i_uid = sb->u.usbdevfs_sb.devuid;
-       inode->i_gid = sb->u.usbdevfs_sb.devgid;
-       inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
-       inode->i_fop = &usbdevfs_device_file_operations;
-       inode->i_size = sizeof(struct usb_device_descriptor);
-       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);
-}
 
-static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb)
-{
-       unsigned int i;
 
-       if (!dev)
-               return;
-       new_dev_inode(dev, sb);
-       for (i = 0; i < dev->maxchild; i++) {
-                if (!dev->children[i])
-                        continue;
-               recurse_new_dev_inode(dev->children[i], sb);
-       }
-}
-
-static void new_bus_inode(struct usb_bus *bus, struct super_block *sb)
-{
-       struct inode *inode;
-       unsigned int busnum = bus->busnum;
-
-       if (busnum > 255)
-               return;
-       inode = iget(sb, IBUS | (busnum << 8));
-       if (!inode) {
-               printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum);
-               return;
-       }
-       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       inode->i_uid = sb->u.usbdevfs_sb.busuid;
-       inode->i_gid = sb->u.usbdevfs_sb.busgid;
-       inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR;
-       inode->i_op = &usbdevfs_bus_inode_operations;
-       inode->i_fop = &usbdevfs_bus_file_operations;
-       inode->u.usbdev_i.p.bus = bus;
-       list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
-       list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);
-}
-
-static void free_inode(struct inode *inode)
-{
-       inode->u.usbdev_i.p.bus = NULL;
-       inode->u.usbdev_i.p.dev = NULL;
-       inode->i_mode &= ~S_IRWXUGO;
-       inode->i_uid = inode->i_gid = 0;
-       inode->i_size = 0;
-       list_del(&inode->u.usbdev_i.slist);
-       INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
-       list_del(&inode->u.usbdev_i.dlist);
-       INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
-       iput(inode);
-}
+static struct super_operations usbfs_ops;
+static struct address_space_operations usbfs_aops;
+static struct file_operations usbfs_dir_operations;
+static struct file_operations default_file_operations;
+static struct inode_operations usbfs_dir_inode_operations;
+static struct vfsmount *usbfs_mount;
+static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
+static int mount_count;        /* = 0 */
+
+static struct dentry *devices_dentry;
+static struct dentry *drivers_dentry;
+static int num_buses;  /* = 0 */
+
+static uid_t devuid;   /* = 0 */
+static uid_t busuid;   /* = 0 */
+static uid_t listuid;  /* = 0 */
+static gid_t devgid;   /* = 0 */
+static gid_t busgid;   /* = 0 */
+static gid_t listgid;  /* = 0 */
+static umode_t devmode = S_IWUSR | S_IRUGO;
+static umode_t busmode = S_IXUGO | S_IRUGO;
+static umode_t listmode = S_IRUGO;
 
 static int parse_options(struct super_block *s, char *data)
 {
-       uid_t devuid = 0, busuid = 0, listuid = 0;
-       gid_t devgid = 0, busgid = 0, listgid = 0;
-       umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO;
        char *curopt = NULL, *value;
 
-       /* parse options */
        if (data)
                curopt = strtok(data, ",");
        for (; curopt; curopt = strtok(NULL, ",")) {
@@ -242,481 +135,572 @@ static int parse_options(struct super_block *s, char *data)
                }
        }
 
-       s->u.usbdevfs_sb.devuid = devuid;
-       s->u.usbdevfs_sb.devgid = devgid;
-       s->u.usbdevfs_sb.devmode = devmode;
-       s->u.usbdevfs_sb.busuid = busuid;
-       s->u.usbdevfs_sb.busgid = busgid;
-       s->u.usbdevfs_sb.busmode = busmode;
-       s->u.usbdevfs_sb.listuid = listuid;
-       s->u.usbdevfs_sb.listgid = listgid;
-       s->u.usbdevfs_sb.listmode = listmode;
-
        return 0;
 }
 
-static struct usb_bus *usbdevfs_findbus(int busnr)
+
+/* --------------------------------------------------------------------- */
+
+static struct dentry *usbfs_lookup (struct inode *dir, struct dentry *dentry)
 {
-        struct list_head *list;
-        struct usb_bus *bus;
+       d_add(dentry, NULL);
+       return NULL;
+}
 
-       down (&usb_bus_list_lock);
-        for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
-                bus = list_entry(list, struct usb_bus, bus_list);
-                if (bus->busnum == busnr) {
-                       up (&usb_bus_list_lock);
-                        return bus;
+static int usbfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+       buf->f_type = USBDEVICE_SUPER_MAGIC;
+       buf->f_bsize = PAGE_CACHE_SIZE;
+       buf->f_namelen = NAME_MAX;
+       return 0;
+}
+
+static struct inode *usbfs_get_inode (struct super_block *sb, int mode, int dev)
+{
+       struct inode *inode = new_inode(sb);
+
+       if (inode) {
+               inode->i_mode = mode;
+               inode->i_uid = current->fsuid;
+               inode->i_gid = current->fsgid;
+               inode->i_blksize = PAGE_CACHE_SIZE;
+               inode->i_blocks = 0;
+               inode->i_rdev = NODEV;
+               inode->i_mapping->a_ops = &usbfs_aops;
+               inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+               switch (mode & S_IFMT) {
+               default:
+                       init_special_inode(inode, mode, dev);
+                       break;
+               case S_IFREG:
+                       inode->i_fop = &default_file_operations;
+                       break;
+               case S_IFDIR:
+                       inode->i_op = &usbfs_dir_inode_operations;
+                       inode->i_fop = &usbfs_dir_operations;
+                       break;
                }
-        }
-       up (&usb_bus_list_lock);
-        return NULL;
+       }
+       return inode; 
 }
 
-#if 0
-static struct usb_device *finddev(struct usb_device *dev, int devnr)
+static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
+                       int dev)
 {
-        unsigned int i;
-        struct usb_device *d2;
+       struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev);
+       int error = -ENOSPC;
 
-        if (!dev)
-                return NULL;
-        if (dev->devnum == devnr)
-                return dev;
-        for (i = 0; i < dev->maxchild; i++) {
-                if (!dev->children[i])
-                        continue;
-                if ((d2 = finddev(dev->children[i], devnr)))
-                        return d2;
-        }
-        return NULL;
+       if (inode) {
+               d_instantiate(dentry, inode);
+               dget(dentry);
+               error = 0;
+       }
+       return error;
 }
 
-static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr)
+static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
 {
-        return finddev(bus->root_hub, devnr);
+       return usbfs_mknod (dir, dentry, mode | S_IFDIR, 0);
 }
-#endif
 
-/* --------------------------------------------------------------------- */
+static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode)
+{
+       return usbfs_mknod (dir, dentry, mode | S_IFREG, 0);
+}
 
-static int usbdevfs_revalidate(struct dentry *dentry, int flags)
+static int usbfs_link (struct dentry *old_dentry, struct inode *dir,
+                      struct dentry *dentry)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = old_dentry->d_inode;
 
-        if (!inode)
-                return 0;
-       if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus)
-               return 0;
-       if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev)
-               return 0;
-       return 1;
+       if(S_ISDIR(inode->i_mode))
+               return -EPERM;
+
+       inode->i_nlink++;
+       atomic_inc(&inode->i_count);
+       dget(dentry);
+       d_instantiate(dentry, inode);
+       return 0;
 }
 
-static struct dentry_operations usbdevfs_dentry_operations = {
-       d_revalidate:   usbdevfs_revalidate,
-};
+static inline int usbfs_positive (struct dentry *dentry)
+{
+       return dentry->d_inode && !d_unhashed(dentry);
+}
 
-static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry)
+static int usbfs_empty (struct dentry *dentry)
 {
-       int busnr;
-       unsigned long ino = 0;
-       unsigned int i;
-       struct inode *inode;
+       struct list_head *list;
 
-       /* sanity check */
-       if (dir->i_ino != IROOT)
-               return ERR_PTR(-EINVAL);
-       dentry->d_op = &usbdevfs_dentry_operations;
-       busnr = dnumber(dentry);
-       if (busnr >= 0 && busnr <= 255)
-               ino = IBUS | (busnr << 8);
-       if (!ino) {
-               for (i = 0; i < NRSPECIAL; i++) {
-                       if (strlen(special[i].name) == dentry->d_name.len && 
-                           !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) {
-                               ino = ISPECIAL | (i + IROOT + 1);
-                               break;
-                       }
+       spin_lock(&dcache_lock);
+
+       list_for_each(list, &dentry->d_subdirs) {
+               struct dentry *de = list_entry(list, struct dentry, d_child);
+               if (usbfs_positive(de)) {
+                       spin_unlock(&dcache_lock);
+                       return 0;
                }
        }
-       if (!ino)
-               return ERR_PTR(-ENOENT);
-       inode = iget(dir->i_sb, ino);
-       if (!inode)
-               return ERR_PTR(-EINVAL);
-       if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) {
-               iput(inode);
-               inode = NULL;
-       }
-       d_add(dentry, inode);
-       return NULL;
+
+       spin_unlock(&dcache_lock);
+       return 1;
 }
 
-static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry)
+static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
 {
-       struct inode *inode;
-       int devnr;
-
-       /* sanity check */
-       if (ITYPE(dir->i_ino) != IBUS)
-               return ERR_PTR(-EINVAL);
-       dentry->d_op = &usbdevfs_dentry_operations;
-       devnr = dnumber(dentry);
-       if (devnr < 1 || devnr > 127)
-               return ERR_PTR(-ENOENT);
-       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) {
-               iput(inode);
-               inode = NULL;
+       int error = -ENOTEMPTY;
+
+       if (usbfs_empty(dentry)) {
+               struct inode *inode = dentry->d_inode;
+
+               inode->i_nlink--;
+               dput(dentry);
+               error = 0;
        }
-       d_add(dentry, inode);
-       return NULL;
+       return error;
 }
 
-static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int usbfs_rename (struct inode *old_dir, struct dentry *old_dentry,
+                        struct inode *new_dir, struct dentry *new_dentry)
 {
-       struct inode *inode = filp->f_dentry->d_inode;
-       unsigned long ino = inode->i_ino;
-       struct special *spec;
-       struct list_head *list;
-       struct usb_bus *bus;
-       char numbuf[8];
-       unsigned int i;
-
-       /* sanity check */
-       if (ino != IROOT)
-               return -EINVAL;
-       i = filp->f_pos;
-       switch (i) {
-       case 0:
-               if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0)
-                       return 0;
-               filp->f_pos++;
-               i++;
-               /* fall through */
+       int error = -ENOTEMPTY;
 
-       case 1:
-               if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0)
-                       return 0;
-               filp->f_pos++;
-               i++;
-               /* fall through */
-
-       default:
-               
-               while (i >= 2 && i < 2+NRSPECIAL) {
-                       spec = &special[filp->f_pos-2];
-                       if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0)
-                               return 0;
-                       filp->f_pos++;
-                       i++;
-               }
-               if (i < 2+NRSPECIAL)
-                       return 0;
-               i -= 2+NRSPECIAL;
-               down (&usb_bus_list_lock);
-               for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
-                       if (i > 0) {
-                               i--;
-                               continue;
-                       }
-                       bus = list_entry(list, struct usb_bus, bus_list);
-                       sprintf(numbuf, "%03d", bus->busnum);
-                       if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0)
-                               break;
-                       filp->f_pos++;
+       if (usbfs_empty(new_dentry)) {
+               struct inode *inode = new_dentry->d_inode;
+               if (inode) {
+                       inode->i_nlink--;
+                       dput(new_dentry);
                }
-               up (&usb_bus_list_lock);
-               return 0;
+               error = 0;
        }
+       return error;
 }
 
-static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir)
+#define usbfs_rmdir usbfs_unlink
+
+/* default file operations */
+static ssize_t default_read_file (struct file *file, char *buf,
+                                 size_t count, loff_t *ppos)
 {
-       char numbuf[8];
-       unsigned int i;
+       return 0;
+}
 
-       if (!dev)
-               return pos;
-       sprintf(numbuf, "%03d", dev->devnum);
-       if (pos > 0)
-               pos--;
-       else {
-               if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0)
-                       return -1;
-               filp->f_pos++;
-       }
-       for (i = 0; i < dev->maxchild; i++) {
-               if (!dev->children[i])
-                       continue;
-               pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir);
-               if (pos < 0)
-                       return -1;
-       }
-       return pos;
+static ssize_t default_write_file (struct file *file, const char *buf,
+                                  size_t count, loff_t *ppos)
+{
+       return count;
 }
 
-static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
 {
-       struct inode *inode = filp->f_dentry->d_inode;
-       unsigned long ino = inode->i_ino;
-       struct usb_bus *bus;
+       loff_t retval = -EINVAL;
 
-       /* sanity check */
-       if (ITYPE(ino) != IBUS)
-               return -EINVAL;
-       switch ((unsigned int)filp->f_pos) {
+       switch(orig) {
        case 0:
-               if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0)
-                       return 0;
-               filp->f_pos++;
-               /* fall through */
-
+               if (offset > 0) {
+                       file->f_pos = offset;
+                       retval = file->f_pos;
+               } 
+               break;
        case 1:
-               if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0)
-                       return 0;
-               filp->f_pos++;
-               /* fall through */
-
+               if ((offset + file->f_pos) > 0) {
+                       file->f_pos += offset;
+                       retval = file->f_pos;
+               } 
+               break;
        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);
-               unlock_kernel();
-               return 0;
+               break;
        }
+       return retval;
+}
+
+static int default_open (struct inode *inode, struct file *filp)
+{
+       if (inode->u.generic_ip)
+               filp->private_data = inode->u.generic_ip;
+
+       return 0;
+}
+
+static int default_sync_file (struct file *file, struct dentry *dentry,
+                             int datasync)
+{
+       return 0;
 }
 
-static struct file_operations usbdevfs_root_file_operations = {
-       readdir: usbdevfs_root_readdir,
+static struct address_space_operations usbfs_aops = {
 };
 
-static struct inode_operations usbdevfs_root_inode_operations = {
-       lookup: usbdevfs_root_lookup,
+static struct file_operations usbfs_dir_operations = {
+       read:           generic_read_dir,
+       readdir:        dcache_readdir,
+       fsync:          default_sync_file,
 };
 
-static struct file_operations usbdevfs_bus_file_operations = {
-       readdir: usbdevfs_bus_readdir,
+static struct file_operations default_file_operations = {
+       read:           default_read_file,
+       write:          default_write_file,
+       open:           default_open,
+       llseek:         default_file_lseek,
+       fsync:          default_sync_file,
+       mmap:           generic_file_mmap,
 };
 
-static struct inode_operations usbdevfs_bus_inode_operations = {
-       lookup: usbdevfs_bus_lookup,
+static struct inode_operations usbfs_dir_inode_operations = {
+       create:         usbfs_create,
+       lookup:         usbfs_lookup,
+       link:           usbfs_link,
+       unlink:         usbfs_unlink,
+       mkdir:          usbfs_mkdir,
+       rmdir:          usbfs_rmdir,
+       mknod:          usbfs_mknod,
+       rename:         usbfs_rename,
 };
 
-static void usbdevfs_read_inode(struct inode *inode)
-{
-       struct special *spec;
-
-       inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME;
-       inode->i_mode = S_IFREG;
-       inode->i_gid = inode->i_uid = 0;
-       INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
-       INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
-       inode->u.usbdev_i.p.dev = NULL;
-       inode->u.usbdev_i.p.bus = NULL;
-       switch (ITYPE(inode->i_ino)) {
-       case ISPECIAL:
-               if (inode->i_ino == IROOT) {
-                       inode->i_op = &usbdevfs_root_inode_operations;
-                       inode->i_fop = &usbdevfs_root_file_operations;
-                       inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
-                       return;
-               }
-               if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL)
-                       return;
-               spec = &special[inode->i_ino-(IROOT+1)];
-               inode->i_fop = spec->fops;
-               return;
+static struct super_operations usbfs_ops = {
+       statfs:         usbfs_statfs,
+       put_inode:      force_delete,
+};
 
-       case IDEVICE:
-               return;
+static struct super_block *usbfs_read_super (struct super_block *sb, void *data, 
+                                            int silent)
+{
+       struct inode *inode;
+       struct dentry *root;
 
-       case IBUS:
-               return;
+       if (parse_options(sb, data)) {
+               warn("usbfs: mount parameter error:");
+               return NULL;
+       }
 
-       default:
-               return;
-        }
-}
+       sb->s_blocksize = PAGE_CACHE_SIZE;
+       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+       sb->s_magic = USBDEVICE_SUPER_MAGIC;
+       sb->s_op = &usbfs_ops;
+       inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
 
-static void usbdevfs_put_super(struct super_block *sb)
-{
-       list_del(&sb->u.usbdevfs_sb.slist);
-       INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist);
-       while (!list_empty(&sb->u.usbdevfs_sb.ilist))
-               free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist));
-}
+       if (!inode) {
+               dbg("%s: could not get inode!\n",__FUNCTION__);
+               return NULL;
+       }
 
-static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf)
-{
-        buf->f_type = USBDEVICE_SUPER_MAGIC;
-        buf->f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
-        buf->f_bfree = 0;
-        buf->f_bavail = 0;
-        buf->f_ffree = 0;
-        buf->f_namelen = NAME_MAX;
-        return 0;
+       root = d_alloc_root(inode);
+       if (!root) {
+               dbg("%s: could not get root dentry!\n",__FUNCTION__);
+               iput(inode);
+               return NULL;
+       }
+       sb->s_root = root;
+       return sb;
 }
 
-static int usbdevfs_remount(struct super_block *s, int *flags, char *data)
+/**
+ * fs_create_by_name - create a file, given a name
+ * @name:      name of file
+ * @mode:      type of file
+ * @parent:    dentry of directory to create it in
+ * @dentry:    resulting dentry of file
+ *
+ * There is a bit of overhead in creating a file - basically, we 
+ * have to hash the name of the file, then look it up. This will
+ * prevent files of the same name. 
+ * We then call the proper vfs_ function to take care of all the 
+ * file creation details. 
+ * This function handles both regular files and directories.
+ */
+static int fs_create_by_name (const char *name, mode_t mode,
+                             struct dentry *parent, struct dentry **dentry)
 {
-       struct list_head *ilist = s->u.usbdevfs_sb.ilist.next;
-       struct inode *inode;
-       int ret;
+       struct dentry *d = NULL;
+       struct qstr qstr;
+       int error;
+
+       /* If the parent is not specified, we create it in the root.
+        * We need the root dentry to do this, which is in the super 
+        * block. A pointer to that is in the struct vfsmount that we
+        * have around.
+        */
+       if (!parent ) {
+               if (usbfs_mount && usbfs_mount->mnt_sb) {
+                       parent = usbfs_mount->mnt_sb->s_root;
+               }
+       }
 
-       if ((ret = parse_options(s, data))) {
-               printk(KERN_WARNING "usbdevfs: remount parameter error\n");
-               return ret;
+       if (!parent) {
+               dbg("Ah! can not find a parent!\n");
+               return -EFAULT;
        }
 
-       for (; ilist != &s->u.usbdevfs_sb.ilist; ilist = ilist->next) {
-               inode = list_entry(ilist, struct inode, u.usbdev_i.slist);
+       *dentry = NULL;
+       qstr.name = name;
+       qstr.len = strlen(name);
+       qstr.hash = full_name_hash(name,qstr.len);
 
-               switch (ITYPE(inode->i_ino)) {
-                       case ISPECIAL :
-                               inode->i_uid = s->u.usbdevfs_sb.listuid;
-                               inode->i_gid = s->u.usbdevfs_sb.listgid;
-                               inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG;
-                               break;
-                       case IBUS :
-                               inode->i_uid = s->u.usbdevfs_sb.busuid;
-                               inode->i_gid = s->u.usbdevfs_sb.busgid;
-                               inode->i_mode = s->u.usbdevfs_sb.busmode | S_IFDIR;
+       parent = dget(parent);
+
+       down(&parent->d_inode->i_sem);
+
+       d = lookup_hash(&qstr,parent);
+
+       error = PTR_ERR(d);
+       if (!IS_ERR(d)) {
+               switch(mode & S_IFMT) {
+                       case 0: 
+                       case S_IFREG:
+                               error = vfs_create(parent->d_inode,d,mode);
                                break;
-                       case IDEVICE :
-                               inode->i_uid = s->u.usbdevfs_sb.devuid;
-                               inode->i_gid = s->u.usbdevfs_sb.devgid;
-                               inode->i_mode = s->u.usbdevfs_sb.devmode | S_IFREG;
+                       case S_IFDIR:
+                               error = vfs_mkdir(parent->d_inode,d,mode);
                                break;
+                       default:
+                               err("cannot create special files\n");
                }
+               *dentry = d;
        }
+       up(&parent->d_inode->i_sem);
 
-       return 0;
+       dput(parent);
+       return error;
 }
 
-static struct super_operations usbdevfs_sops = { 
-       read_inode:     usbdevfs_read_inode,
-       put_super:      usbdevfs_put_super,
-       statfs:         usbdevfs_statfs,
-       remount_fs:     usbdevfs_remount,
-};
+static struct dentry *fs_create_file (const char *name, mode_t mode,
+                                     struct dentry *parent, void *data,
+                                     struct file_operations *fops,
+                                     uid_t uid, gid_t gid)
+{
+       struct dentry *dentry;
+       int error;
+
+       dbg("creating file '%s'\n",name);
+
+       error = fs_create_by_name(name,mode,parent,&dentry);
+       if (error) {
+               dentry = NULL;
+       } else {
+               if (dentry->d_inode) {
+                       if (data)
+                               dentry->d_inode->u.generic_ip = data;
+                       if (fops)
+                               dentry->d_inode->i_fop = fops;
+                       dentry->d_inode->i_uid = uid;
+                       dentry->d_inode->i_gid = gid;
+               }
+       }
+
+       return dentry;
+}
 
-struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent)
+static void fs_remove_file (struct dentry *dentry)
 {
-        struct inode *root_inode, *inode;
-       struct list_head *blist;
-       struct usb_bus *bus;
-       unsigned int i;
+       struct dentry *parent = dentry->d_parent;
+       
+       if (!parent || !parent->d_inode)
+               return;
 
-       if (parse_options(s, data)) {
-               printk(KERN_WARNING "usbdevfs: mount parameter error\n");
-               return NULL;
-       }
+       down(&parent->d_inode->i_sem);
+       if (usbfs_positive(dentry)) {
+               if (dentry->d_inode) {
+                       if (S_ISDIR(dentry->d_inode->i_mode))
+                               vfs_rmdir(parent->d_inode,dentry);
+                       else
+                               vfs_unlink(parent->d_inode,dentry);
+               }
 
-       /* fill superblock */
-        s->s_blocksize = 1024;
-        s->s_blocksize_bits = 10;
-        s->s_magic = USBDEVICE_SUPER_MAGIC;
-        s->s_op = &usbdevfs_sops;
-       INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist);
-       INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist);
-       root_inode = iget(s, IROOT);
-        if (!root_inode)
-                goto out_no_root;
-        s->s_root = d_alloc_root(root_inode);
-        if (!s->s_root)
-                goto out_no_root;
-       list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
-       for (i = 0; i < NRSPECIAL; i++) {
-               if (!(inode = iget(s, IROOT+1+i)))
-                       continue;
-               inode->i_uid = s->u.usbdevfs_sb.listuid;
-               inode->i_gid = s->u.usbdevfs_sb.listgid;
-               inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG;
-               special[i].inode = inode;
-               list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
-               list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
-       }
-       down (&usb_bus_list_lock);
-       for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
-               bus = list_entry(blist, struct usb_bus, bus_list);
-               new_bus_inode(bus, s);
-               recurse_new_dev_inode(bus->root_hub, s);
+               dput(dentry);
        }
-       up (&usb_bus_list_lock);
-        return s;
-
- out_no_root:
-        printk("usbdevfs_read_super: get root inode failed\n");
-        iput(root_inode);
-        return NULL;
+       up(&parent->d_inode->i_sem);
 }
 
+/* --------------------------------------------------------------------- */
+
+
+
 /*
- * The usbdevfs name is now depreciated (as of 2.5.1).
+ * The usbdevfs name is now deprecated (as of 2.5.1).
  * It will be removed when the 2.7.x development cycle is started.
  * You have been warned :)
  */
-static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE);
-static DECLARE_FSTYPE(usb_fs_type, "usbfs", usbdevfs_read_super, FS_SINGLE);
+static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbfs_read_super, FS_SINGLE);
+static DECLARE_FSTYPE(usb_fs_type,       "usbfs",    usbfs_read_super, FS_SINGLE);
 
 /* --------------------------------------------------------------------- */
+static int get_mount (void)
+{
+       struct vfsmount *mnt;
+
+       spin_lock (&mount_lock);
+       if (usbfs_mount) {
+               mntget(usbfs_mount);
+               ++mount_count;
+               spin_unlock (&mount_lock);
+               goto go_ahead;
+       }
+
+       spin_unlock (&mount_lock);
+       mnt = kern_mount (&usbdevice_fs_type);
+       if (IS_ERR(mnt)) {
+               err ("could not mount the fs...erroring out!\n");
+               return -ENODEV;
+       }
+       spin_lock (&mount_lock);
+       if (!usbfs_mount) {
+               usbfs_mount = mnt;
+               ++mount_count;
+               spin_unlock (&mount_lock);
+               goto go_ahead;
+       }
+       mntget(usbfs_mount);
+       ++mount_count;
+       spin_unlock (&mount_lock);
+       mntput(mnt);
+
+go_ahead:
+       dbg("mount_count = %d\n", mount_count);
+       return 0;
+}
+
+static void remove_mount (void)
+{
+       struct vfsmount *mnt;
+
+       spin_lock (&mount_lock);
+       mnt = usbfs_mount;
+       --mount_count;
+       if (!mount_count)
+               usbfs_mount = NULL;
+
+       spin_unlock (&mount_lock);
+       mntput(mnt);
+       dbg("mount_count = %d\n", mount_count);
+}
 
-static void update_special_inodes (void)
+static int create_special_files (void)
 {
-       int i;
-       for (i = 0; i < NRSPECIAL; i++) {
-               struct inode *inode = special[i].inode;
+       int retval;
+
+       /* create the devices and drivers special files */
+       retval = get_mount ();
+       if (retval)
+               return retval;
+       devices_dentry = fs_create_file ("devices",
+                                        listmode | S_IFREG,
+                                        NULL, NULL,
+                                        &usbdevfs_devices_fops,
+                                        listuid, listgid);
+       if (devices_dentry == NULL) {
+               err ("Unable to create devices usbfs file");
+               return -ENODEV;
+       }
+
+       drivers_dentry = fs_create_file ("drivers",
+                                        listmode | S_IFREG,
+                                        NULL, NULL,
+                                        &usbdevfs_drivers_fops,
+                                        listuid, listgid);
+       if (drivers_dentry == NULL) {
+               err ("Unable to create drivers usbfs file");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void remove_special_files (void)
+{
+       if (devices_dentry)
+               fs_remove_file (devices_dentry);
+       if (drivers_dentry)
+               fs_remove_file (drivers_dentry);
+       devices_dentry = NULL;
+       drivers_dentry = NULL;
+       remove_mount();
+}
+
+void usbfs_update_special (void)
+{
+       struct inode *inode;
+
+       if (devices_dentry) {
+               inode = devices_dentry->d_inode;
+               if (inode)
+                       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       }
+       if (drivers_dentry) {
+               inode = devices_dentry->d_inode;
                if (inode)
                        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        }
 }
 
-
-void usbdevfs_add_bus(struct usb_bus *bus)
+void usbfs_add_bus(struct usb_bus *bus)
 {
-       struct list_head *slist;
+       char name[8];
+       int retval;
+
+       /* create the special files if this is the first bus added */
+       if (num_buses == 0) {
+               retval = create_special_files();
+               if (retval)
+                       return;
+       }
+       ++num_buses;
+
+       sprintf (name, "%03d", bus->busnum);
+       bus->dentry = fs_create_file (name,
+                                     busmode | S_IFDIR,
+                                     NULL, bus, NULL,
+                                     busuid, busgid);
+       if (bus->dentry == NULL)
+               return;
 
-       lock_kernel();
-       for (slist = superlist.next; slist != &superlist; slist = slist->next)
-               new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
-       update_special_inodes();
-       unlock_kernel();
+       usbfs_update_special();
        usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_remove_bus(struct usb_bus *bus)
+
+void usbfs_remove_bus(struct usb_bus *bus)
 {
-       lock_kernel();
-       while (!list_empty(&bus->inodes))
-               free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
-       update_special_inodes();
-       unlock_kernel();
+       if (bus->dentry) {
+               fs_remove_file (bus->dentry);
+               bus->dentry = NULL;
+       }
+
+       --num_buses;
+       if (num_buses <= 0) {
+               remove_special_files();
+               num_buses = 0;
+       }
+
+       usbfs_update_special();
        usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_add_device(struct usb_device *dev)
+void usbfs_add_device(struct usb_device *dev)
 {
-       struct list_head *slist;
+       char name[8];
+
+       sprintf (name, "%03d", dev->devnum);
+       dev->dentry = fs_create_file (name,
+                                     devmode | S_IFREG,
+                                     dev->bus->dentry, dev,
+                                     &usbdevfs_device_file_operations,
+                                     devuid, devgid);
+       if (dev->dentry == NULL)
+               return;
 
-       lock_kernel();
-       for (slist = superlist.next; slist != &superlist; slist = slist->next)
-               new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
-       update_special_inodes();
-       unlock_kernel();
+       usbfs_update_special();
        usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_remove_device(struct usb_device *dev)
+void usbfs_remove_device(struct usb_device *dev)
 {
        struct dev_state *ds;
        struct siginfo sinfo;
 
-       lock_kernel();
-       while (!list_empty(&dev->inodes))
-               free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist));
+       if (dev->dentry) {
+               fs_remove_file (dev->dentry);
+               dev->dentry = NULL;
+       }
        while (!list_empty(&dev->filelist)) {
                ds = list_entry(dev->filelist.next, struct dev_state, list);
                list_del(&ds->list);
@@ -732,9 +716,7 @@ void usbdevfs_remove_device(struct usb_device *dev)
                        send_sig_info(ds->discsignr, &sinfo, ds->disctask);
                }
        }
-
-       update_special_inodes();
-       unlock_kernel();
+       usbfs_update_special();
        usbdevfs_conn_disc_event();
 }
 
@@ -744,39 +726,42 @@ void usbdevfs_remove_device(struct usb_device *dev)
 static struct proc_dir_entry *usbdir = NULL;
 #endif 
 
-int __init usbdevfs_init(void)
+int __init usbfs_init(void)
 {
-       int ret;
+       int retval;
 
-       for (ret = 0; ret < NRSPECIAL; ret++) {
-               INIT_LIST_HEAD(&special[ret].inodes);
-       }
-       if ((ret = usb_register(&usbdevfs_driver)))
-               return ret;
-       if ((ret = register_filesystem(&usb_fs_type))) {
+       retval = usb_register(&usbdevfs_driver);
+       if (retval)
+               return retval;
+
+       retval = register_filesystem(&usb_fs_type);
+       if (retval) {
                usb_deregister(&usbdevfs_driver);
-               return ret;
+               return retval;
        }
-       if ((ret = register_filesystem(&usbdevice_fs_type))) {
+       retval = register_filesystem(&usbdevice_fs_type);
+       if (retval) {
                unregister_filesystem(&usb_fs_type);
                usb_deregister(&usbdevfs_driver);
-               return ret;
+               return retval;
        }
+
 #ifdef CONFIG_PROC_FS          
        /* create mount point for usbdevfs */
        usbdir = proc_mkdir("usb", proc_bus);
 #endif 
-       return ret;
+
+       return 0;
 }
 
-void __exit usbdevfs_cleanup(void)
+void __exit usbfs_cleanup(void)
 {
        usb_deregister(&usbdevfs_driver);
        unregister_filesystem(&usb_fs_type);
        unregister_filesystem(&usbdevice_fs_type);
 #ifdef CONFIG_PROC_FS  
-        if (usbdir)
-                remove_proc_entry("usb", proc_bus);
+       if (usbdir)
+               remove_proc_entry("usb", proc_bus);
 #endif
 }
 
index d2a1ebe71ed80e5fd96bedfd53838d16e056c77b..a6b2e0c549e8bc915dc3c6501122e04b6c49b81a 100644 (file)
@@ -140,7 +140,7 @@ struct mdc800_data
 
        unsigned int            endpoint [4];
 
-       purb_t                  irq_urb;
+       struct urb *            irq_urb;
        wait_queue_head_t       irq_wait;
        int                     irq_woken;
        char*                   irq_urb_buffer;
@@ -149,13 +149,13 @@ struct mdc800_data
        int                     camera_request_ready; // Status to synchronize with irq
        char                    camera_response [8];  // last Bytes send after busy
 
-       purb_t                  write_urb;
+       struct urb *            write_urb;
        char*                   write_urb_buffer;
        wait_queue_head_t       write_wait;
        int                     written;
 
 
-       purb_t                  download_urb;
+       struct urb *            download_urb;
        char*                   download_urb_buffer;
        wait_queue_head_t       download_wait;
        int                     downloaded;
index 7acd2d2bea2d49e5ac8c999983edc56688efcde0..91ed0880f9ebc94f4a0f0c5348b454b3c7ae4124 100644 (file)
@@ -624,7 +624,7 @@ static int pwc_set_palette(struct pwc_device *pdev, int pal)
 /* This gets called for the Isochronous pipe (video). This is done in
  * interrupt time, so it has to be fast, not crash, and not stall. Neat.
  */
-static void pwc_isoc_handler(purb_t urb)
+static void pwc_isoc_handler(struct urb *urb)
 {
        struct pwc_device *pdev;
        int i, fst, flen;
@@ -786,7 +786,7 @@ static void pwc_isoc_handler(purb_t urb)
 static int pwc_isoc_init(struct pwc_device *pdev)
 {
        struct usb_device *udev;
-       purb_t urb;
+       struct urb *urb;
        int i, j, ret;
 
        struct usb_interface_descriptor *idesc;
index 40bfb27847223868da9579cc3111862db6fc4786..2b897700fa49ffaabc0c6f543520b46c438c6ae7 100644 (file)
@@ -96,7 +96,7 @@ struct pwc_iso_buf
        void *data;
        int  length;
        int  read;
-       purb_t urb;
+       struct urb *urb;
 };
 
 /* intermediate buffers with raw data from the USB cam */
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
new file mode 100644 (file)
index 0000000..6966bd9
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * USB Compaq iPAQ driver
+ *
+ *     Copyright (C) 2001
+ *         Ganesh Varadarajan <ganesh@veritas.com>
+ *
+ *     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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+       static int debug = 1;
+#else
+       static int debug = 0;
+#endif
+
+#include "usb-serial.h"
+#include "ipaq.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
+#define DRIVER_DESC "USB Compaq iPAQ driver"
+
+/* Function prototypes for an ipaq */
+static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
+static void ipaq_close (struct usb_serial_port *port, struct file *filp);
+static int  ipaq_startup (struct usb_serial *serial);
+static void ipaq_shutdown (struct usb_serial *serial);
+static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+                      int count);
+static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+                          int count);
+static int ipaq_write_flush(struct usb_serial_port *port);
+static void ipaq_read_bulk_callback (struct urb *urb);
+static void ipaq_write_bulk_callback(struct urb *urb);
+static int ipaq_write_room(struct usb_serial_port *port);
+static int ipaq_chars_in_buffer(struct usb_serial_port *port);
+static void ipaq_destroy_lists(struct usb_serial_port *port);
+
+
+static __devinitdata struct usb_device_id ipaq_id_table [] = {
+       { USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) },
+       { }                                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, ipaq_id_table);
+
+/* All of the device info needed for the Compaq iPAQ */
+struct usb_serial_device_type ipaq_device = {
+       owner:                  THIS_MODULE,
+       name:                   "Compaq iPAQ",
+       id_table:               ipaq_id_table,
+       num_interrupt_in:       0,
+       num_bulk_in:            1,
+       num_bulk_out:           1,
+       num_ports:              1,
+       open:                   ipaq_open,
+       close:                  ipaq_close,
+       startup:                ipaq_startup,
+       shutdown:               ipaq_shutdown,
+       write:                  ipaq_write,
+       write_room:             ipaq_write_room,
+       chars_in_buffer:        ipaq_chars_in_buffer,
+       read_bulk_callback:     ipaq_read_bulk_callback,
+       write_bulk_callback:    ipaq_write_bulk_callback,
+};
+
+static spinlock_t      write_list_lock;
+static int             bytes_in;
+static int             bytes_out;
+
+static int ipaq_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial       *serial = port->serial;
+       struct ipaq_private     *priv;
+       struct ipaq_packet      *pkt;
+       int                     i, result = 0;
+
+       if (port_paranoia_check(port, __FUNCTION__)) {
+               return -ENODEV;
+       }
+       
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       down(&port->sem);
+       
+       ++port->open_count;
+       
+       if (port->open_count == 1) {
+               bytes_in = 0;
+               bytes_out = 0;
+               priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+               if (priv == NULL) {
+                       err(__FUNCTION__ " - Out of memory");
+                       return -ENOMEM;
+               }
+               port->private = (void *)priv;
+               priv->active = 0;
+               priv->queue_len = 0;
+               INIT_LIST_HEAD(&priv->queue);
+               INIT_LIST_HEAD(&priv->freelist);
+
+               for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
+                       pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
+                       if (pkt == NULL) {
+                               goto enomem;
+                       }
+                       pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
+                       if (pkt->data == NULL) {
+                               kfree(pkt);
+                               goto enomem;
+                       }
+                       pkt->len = 0;
+                       pkt->written = 0;
+                       INIT_LIST_HEAD(&pkt->list);
+                       list_add(&pkt->list, &priv->freelist);
+                       priv->free_len += PACKET_SIZE;
+               }
+
+               /*
+                * Force low latency on. This will immediately push data to the line
+                * discipline instead of queueing.
+                */
+
+               port->tty->low_latency = 1;
+
+               /*
+                * Lose the small buffers usbserial provides. Make larger ones.
+                */
+
+               kfree(port->bulk_in_buffer);
+               kfree(port->bulk_out_buffer);
+               port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+               if (port->bulk_in_buffer == NULL) {
+                       goto enomem;
+               }
+               port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+               if (port->bulk_out_buffer == NULL) {
+                       kfree(port->bulk_in_buffer);
+                       goto enomem;
+               }
+               port->read_urb->transfer_buffer = port->bulk_in_buffer;
+               port->write_urb->transfer_buffer = port->bulk_out_buffer;
+               port->read_urb->transfer_buffer_length = URBDATA_SIZE;
+               port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
+               
+               /* Start reading from the device */
+               FILL_BULK_URB(port->read_urb, serial->dev, 
+                             usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+                             port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+                             ipaq_read_bulk_callback, port);
+               result = usb_submit_urb(port->read_urb);
+               if (result) {
+                       err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+               }
+
+               /*
+                * Send out two control messages observed in win98 sniffs. Not sure what
+                * they do.
+                */
+
+               result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+                               0x1, 0, NULL, 0, 5 * HZ);
+               if (result < 0) {
+                       err(__FUNCTION__ " - failed doing control urb, error %d", result);
+               }
+               result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+                               0x1, 0, NULL, 0, 5 * HZ);
+               if (result < 0) {
+                       err(__FUNCTION__ " - failed doing control urb, error %d", result);
+               }
+       }
+       
+       up(&port->sem);
+       
+       return result;
+
+enomem:
+       ipaq_destroy_lists(port);
+       kfree(priv);
+       err(__FUNCTION__ " - Out of memory");
+       return -ENOMEM;
+}
+
+
+static void ipaq_close(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial       *serial;
+       struct ipaq_private     *priv = port->private;
+
+       if (port_paranoia_check(port, __FUNCTION__)) {
+               return; 
+       }
+       
+       dbg(__FUNCTION__ " - port %d", port->number);
+                        
+       serial = get_usb_serial(port, __FUNCTION__);
+       if (!serial)
+               return;
+       
+       down (&port->sem);
+
+       --port->open_count;
+
+       if (port->open_count <= 0) {
+
+               /*
+                * shut down bulk read and write
+                */
+
+               usb_unlink_urb(port->write_urb);
+               usb_unlink_urb(port->read_urb);
+               ipaq_destroy_lists(port);
+               kfree(priv);
+               port->private = NULL;
+               port->open_count = 0;
+
+       }
+       up (&port->sem);
+
+       /* Uncomment the following line if you want to see some statistics in your syslog */
+       /* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+}
+
+static void ipaq_read_bulk_callback(struct urb *urb)
+{
+       struct usb_serial_port  *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial       *serial = get_usb_serial (port, __FUNCTION__);
+       struct tty_struct       *tty;
+       unsigned char           *data = urb->transfer_buffer;
+       int                     i, result;
+
+       if (port_paranoia_check(port, __FUNCTION__))
+               return;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+
+       if (urb->status) {
+               dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+               return;
+       }
+
+       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+       tty = port->tty;
+       if (urb->actual_length) {
+               for (i = 0; i < urb->actual_length ; ++i) {
+                       /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       /* this doesn't actually push the data through unless tty->low_latency is set */
+                       tty_insert_flip_char(tty, data[i], 0);
+               }
+               tty_flip_buffer_push(tty);
+               bytes_in += urb->actual_length;
+       }
+
+       /* Continue trying to always read  */
+       FILL_BULK_URB(port->read_urb, serial->dev, 
+                     usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+                     port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+                     ipaq_read_bulk_callback, port);
+       result = usb_submit_urb(port->read_urb);
+       if (result)
+               err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+       return;
+}
+
+static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+                      int count)
+{
+       const unsigned char     *current_position = buf;
+       int                     bytes_sent = 0;
+       int                     transfer_size;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
+       
+       while (count > 0) {
+               transfer_size = min(count, PACKET_SIZE);
+               if (ipaq_write_bulk(port, from_user, current_position, transfer_size)) {
+                       break;
+               }
+               current_position += transfer_size;
+               bytes_sent += transfer_size;
+               count -= transfer_size;
+               bytes_out += transfer_size;
+       }
+
+       return bytes_sent;
+} 
+
+static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+                          int count)
+{
+       struct ipaq_private     *priv = port->private;
+       struct ipaq_packet      *pkt = NULL;
+       int                     result = 0;
+       unsigned long           flags;
+
+       if (priv->free_len <= 0) {
+               dbg(__FUNCTION__ " - we're stuffed");
+               return -EAGAIN;
+       }
+
+       spin_lock_irqsave(&write_list_lock, flags);
+       if (!list_empty(&priv->freelist)) {
+               pkt = list_entry(priv->freelist.next, struct ipaq_packet, list);
+               list_del(&pkt->list);
+               priv->free_len -= PACKET_SIZE;
+       }
+       spin_unlock_irqrestore(&write_list_lock, flags);
+       if (pkt == NULL) {
+               dbg(__FUNCTION__ " - we're stuffed");
+               return -EAGAIN;
+       }
+
+       if (from_user) {
+               copy_from_user(pkt->data, buf, count);
+       } else {
+               memcpy(pkt->data, buf, count);
+       }
+       usb_serial_debug_data(__FILE__, __FUNCTION__, count, pkt->data);
+
+       pkt->len = count;
+       pkt->written = 0;
+       spin_lock_irqsave(&write_list_lock, flags);
+       list_add_tail(&pkt->list, &priv->queue);
+       priv->queue_len += count;
+       if (priv->active == 0) {
+               priv->active = 1;
+               result = ipaq_write_flush(port);
+       }
+       spin_unlock_irqrestore(&write_list_lock, flags);
+       return result;
+}
+
+static int ipaq_write_flush(struct usb_serial_port *port)
+{
+       struct ipaq_private     *priv = (struct ipaq_private *)port->private;
+       struct usb_serial       *serial = port->serial;
+       int                     count, room, result;
+       struct ipaq_packet      *pkt;
+       struct urb              *urb = port->write_urb;
+       struct list_head        *tmp;
+
+       if (urb->status == -EINPROGRESS) {
+               /* Should never happen */
+               err(__FUNCTION__ " - flushing while urb is active !");
+               return -EAGAIN;
+       }
+       room = URBDATA_SIZE;
+       for (tmp = priv->queue.next; tmp != &priv->queue;) {
+               pkt = list_entry(tmp, struct ipaq_packet, list);
+               tmp = tmp->next;
+               count = min(room, (int)(pkt->len - pkt->written));
+               memcpy(urb->transfer_buffer + (URBDATA_SIZE - room),
+                      pkt->data + pkt->written, count);
+               room -= count;
+               pkt->written += count;
+               priv->queue_len -= count;
+               if (pkt->written == pkt->len) {
+                       list_del(&pkt->list);
+                       list_add(&pkt->list, &priv->freelist);
+                       priv->free_len += PACKET_SIZE;
+               }
+               if (room == 0) {
+                       break;
+               }
+       }
+
+       count = URBDATA_SIZE - room;
+       FILL_BULK_URB(port->write_urb, serial->dev, 
+                     usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+                     port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
+                     port);
+       result = usb_submit_urb(urb);
+       if (result) {
+               err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+       }
+       return result;
+}
+
+static void ipaq_write_bulk_callback(struct urb *urb)
+{
+       struct usb_serial_port  *port = (struct usb_serial_port *)urb->context;
+       struct ipaq_private     *priv = (struct ipaq_private *)port->private;
+       unsigned long           flags;
+
+       if (port_paranoia_check (port, __FUNCTION__)) {
+               return;
+       }
+       
+       dbg(__FUNCTION__ " - port %d", port->number);
+       
+       if (urb->status) {
+               dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+       }
+
+       spin_lock_irqsave(&write_list_lock, flags);
+       if (!list_empty(&priv->queue)) {
+               ipaq_write_flush(port);
+       } else {
+               priv->active = 0;
+       }
+       spin_unlock_irqrestore(&write_list_lock, flags);
+       queue_task(&port->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+       
+       return;
+}
+
+static int ipaq_write_room(struct usb_serial_port *port)
+{
+       struct ipaq_private     *priv = (struct ipaq_private *)port->private;
+
+       dbg(__FUNCTION__ " - freelen %d", priv->free_len);
+       return priv->free_len;
+}
+
+static int ipaq_chars_in_buffer(struct usb_serial_port *port)
+{
+       struct ipaq_private     *priv = (struct ipaq_private *)port->private;
+
+       dbg(__FUNCTION__ " - queuelen %d", priv->queue_len);
+       return priv->queue_len;
+}
+
+static void ipaq_destroy_lists(struct usb_serial_port *port)
+{
+       struct ipaq_private     *priv = (struct ipaq_private *)port->private;
+       struct list_head        *tmp;
+       struct ipaq_packet      *pkt;
+
+       for (tmp = priv->queue.next; tmp != &priv->queue;) {
+               pkt = list_entry(tmp, struct ipaq_packet, list);
+               tmp = tmp->next;
+               kfree(pkt->data);
+               kfree(pkt);
+       }
+       for (tmp = priv->freelist.next; tmp != &priv->freelist;) {
+               pkt = list_entry(tmp, struct ipaq_packet, list);
+               tmp = tmp->next;
+               kfree(pkt->data);
+               kfree(pkt);
+       }
+       return;
+}
+
+
+static int ipaq_startup(struct usb_serial *serial)
+{
+       dbg(__FUNCTION__);
+       usb_set_configuration(serial->dev, 1);
+       return 0;
+}
+
+static void ipaq_shutdown(struct usb_serial *serial)
+{
+       int i;
+
+       dbg (__FUNCTION__);
+
+       /* stop reads and writes on all ports */
+       for (i=0; i < serial->num_ports; ++i) {
+               while (serial->port[i].open_count > 0) {
+                       ipaq_close(&serial->port[i], NULL);
+               }
+       }
+}
+
+static int __init ipaq_init(void)
+{
+       usb_serial_register(&ipaq_device);
+       info(DRIVER_DESC " " DRIVER_VERSION);
+
+       return 0;
+}
+
+
+static void __exit ipaq_exit(void)
+{
+       usb_serial_deregister(&ipaq_device);
+}
+
+
+module_init(ipaq_init);
+module_exit(ipaq_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff --git a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h
new file mode 100644 (file)
index 0000000..665900d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * USB Compaq iPAQ driver
+ *
+ *     Copyright (C) 2001
+ *         Ganesh Varadarajan <ganesh@veritas.com>
+ *
+ *     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.
+ *
+ * 
+ */
+
+#ifndef __LINUX_USB_SERIAL_IPAQ_H
+#define __LINUX_USB_SERIAL_IPAQ_H
+
+
+#define IPAQ_VENDOR_ID                 0x049f
+#define IPAQ_PRODUCT_ID                        0x0003
+
+/*
+ * Since we can't queue our bulk write urbs (don't know why - it just
+ * doesn't work), we can send down only one write urb at a time. The simplistic
+ * approach taken by the generic usbserial driver will work, but it's not good
+ * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write
+ * requests coming from the line discipline. This is done by chaining them
+ * in lists of struct ipaq_packet, each packet holding a maximum of
+ * PACKET_SIZE bytes.
+ *
+ * ipaq_write() can be called from bottom half context; hence we can't
+ * allocate memory for packets there. So we initialize a pool of packets at
+ * the first open and maintain a freelist.
+ *
+ * The value of PACKET_SIZE was empirically determined by
+ * checking the maximum write sizes sent down by the ppp ldisc.
+ * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size
+ * supported by the iPAQ.
+ */
+
+struct ipaq_packet {
+       char                    *data;
+       size_t                  len;
+       size_t                  written;
+       struct list_head        list;
+};
+
+struct ipaq_private {
+       int                     active;
+       int                     queue_len;
+       int                     free_len;
+       struct list_head        queue;
+       struct list_head        freelist;
+};
+
+#define URBDATA_SIZE           4096
+#define URBDATA_QUEUE_MAX      (64 * 1024)
+#define PACKET_SIZE            256
+
+#endif
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
new file mode 100644 (file)
index 0000000..4278bcb
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * KLSI KL5KUSB105 chip RS232 converter driver
+ *
+ *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
+ *
+ *   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.
+ *
+ * All information about the device was acquired using SniffUSB ans snoopUSB
+ * on Windows98.
+ * It was written out of frustration with the PalmConnect USB Serial adapter
+ * sold by Palm Inc.
+ * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided
+ * information that was not already available.
+ *
+ * It seems that KLSI bought some silicon-design information from ScanLogic, 
+ * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI.
+ * KLSI has firmware available for their devices; it is probable that the
+ * firmware differs from that used by KLSI in their products. If you have an
+ * original KLSI device and can provide some information on it, I would be 
+ * most interested in adding support for it here. If you have any information 
+ * on the protocol used (or find errors in my reverse-engineered stuff), please
+ * let me know.
+ *
+ * The code was only tested with a PalmConnect USB adapter; if you
+ * are adventurous, try it with any KLSI-based device and let me know how it
+ * breaks so that I can fix it!
+ */
+
+/* TODO:
+ *     check modem line signals
+ *     implement handshaking or decide that we do not support it
+ */
+
+/* History:
+ *   0.3a - implemented pools of write URBs
+ *   0.3  - alpha version for public testing
+ *   0.2  - TIOCMGET works, so autopilot(1) can be used!
+ *   0.1  - can be used to to pilot-xfer -p /dev/ttyUSB0 -l
+ *
+ *   The driver skeleton is mainly based on mct_u232.c and various other 
+ *   pieces of code shamelessly copied from the drivers/usb/serial/ directory.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+       static int debug = 1;
+#else
+       static int debug;
+#endif
+
+#include "usb-serial.h"
+#include "kl5kusb105.h"
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.3a"
+#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>"
+#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
+
+
+/*
+ * Function prototypes
+ */
+static int  klsi_105_startup            (struct usb_serial *serial);
+static void klsi_105_shutdown           (struct usb_serial *serial);
+static int  klsi_105_open               (struct usb_serial_port *port,
+                                         struct file *filp);
+static void klsi_105_close              (struct usb_serial_port *port,
+                                         struct file *filp);
+static int  klsi_105_write              (struct usb_serial_port *port,
+                                         int from_user,
+                                         const unsigned char *buf,
+                                         int count);
+static void klsi_105_write_bulk_callback (struct urb *urb);
+static int  klsi_105_chars_in_buffer     (struct usb_serial_port *port);
+static int  klsi_105_write_room          (struct usb_serial_port *port);
+
+static void klsi_105_read_bulk_callback  (struct urb *urb);
+static void klsi_105_set_termios         (struct usb_serial_port *port,
+                                         struct termios * old);
+static int  klsi_105_ioctl              (struct usb_serial_port *port,
+                                         struct file * file,
+                                         unsigned int cmd,
+                                         unsigned long arg);
+static void klsi_105_throttle           (struct usb_serial_port *port);
+static void klsi_105_unthrottle                 (struct usb_serial_port *port);
+/*
+static void klsi_105_break_ctl          (struct usb_serial_port *port,
+                                         int break_state );
+ */
+
+/*
+ * All of the device info needed for the KLSI converters.
+ */
+static __devinitdata struct usb_device_id id_table [] = {
+       { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
+       { USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
+       { }             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+
+static struct usb_serial_device_type kl5kusb105d_device = {
+       owner:               THIS_MODULE,
+       name:                "KL5KUSB105D / PalmConnect",
+       id_table:            id_table,
+       num_interrupt_in:    1,
+       num_bulk_in:         1,
+       num_bulk_out:        1,
+       num_ports:           1,
+       open:                klsi_105_open,
+       close:               klsi_105_close,
+       write:               klsi_105_write,
+       write_bulk_callback: klsi_105_write_bulk_callback,
+       chars_in_buffer:     klsi_105_chars_in_buffer,
+       write_room:          klsi_105_write_room,
+       read_bulk_callback:  klsi_105_read_bulk_callback,
+       ioctl:               klsi_105_ioctl,
+       set_termios:         klsi_105_set_termios,
+       /*break_ctl:         klsi_105_break_ctl,*/
+       startup:             klsi_105_startup,
+       shutdown:            klsi_105_shutdown,
+       throttle:            klsi_105_throttle,
+       unthrottle:          klsi_105_unthrottle,
+};
+
+struct klsi_105_port_settings {
+       __u8    pktlen;         /* always 5, it seems */
+       __u8    baudrate;
+       __u8    databits;
+       __u8    unknown1;
+       __u8    unknown2;
+} __attribute__ ((packed));
+
+/* we implement a pool of NUM_URBS urbs per usb_serial */
+#define NUM_URBS                       1
+#define URB_TRANSFER_BUFFER_SIZE       64
+struct klsi_105_private {
+       struct klsi_105_port_settings   cfg;
+       struct termios                  termios;
+       unsigned long                   line_state; /* modem line settings */
+       /* write pool */
+       struct urb *                    write_urb_pool[NUM_URBS];
+       spinlock_t                      write_urb_pool_lock;
+       unsigned long                   bytes_in;
+       unsigned long                   bytes_out;
+};
+
+
+/*
+ * Handle vendor specific USB requests
+ */
+
+
+#define KLSI_TIMEOUT    (HZ * 5 ) /* default urb timeout */
+
+static int klsi_105_chg_port_settings(struct usb_serial *serial,
+                                     struct klsi_105_port_settings *settings)
+{
+       int rc;
+
+        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                            KL5KUSB105A_SIO_SET_DATA,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE,
+                            0, /* value */
+                            0, /* index */
+                            settings,
+                            sizeof(struct klsi_105_port_settings),
+                            KLSI_TIMEOUT);
+       if (rc < 0)
+               err("Change port settings failed (error = %d)", rc);
+       info(__FUNCTION__ " - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",
+           settings->pktlen,
+           settings->baudrate, settings->databits,
+           settings->unknown1, settings->unknown2);
+        return rc;
+} /* klsi_105_chg_port_settings */
+
+/* translate a 16-bit status value from the device to linux's TIO bits */
+static unsigned long klsi_105_status2linestate(const __u16 status)
+{
+       unsigned long res = 0;
+
+       res =   ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0)
+             | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0)
+             ;
+
+       return res;
+}
+/* 
+ * Read line control via vendor command and return result through
+ * *line_state_p 
+ */
+/* It seems that the status buffer has always only 2 bytes length */
+#define KLSI_STATUSBUF_LEN     2
+static int klsi_105_get_line_state(struct usb_serial *serial,
+                                  unsigned long *line_state_p)
+{
+       int rc;
+       __u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1};
+       __u16 status;
+
+       info(__FUNCTION__ " - sending SIO Poll request");
+        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+                            KL5KUSB105A_SIO_POLL,
+                             USB_TYPE_VENDOR | USB_DIR_IN,
+                            0, /* value */
+                            0, /* index */
+                            status_buf, KLSI_STATUSBUF_LEN,
+                            10*HZ
+                            );
+       if (rc < 0)
+               err("Reading line status failed (error = %d)", rc);
+       else {
+               status = status_buf[0] + (status_buf[1]<<8);
+
+               info(__FUNCTION__ " - read status %x %x",
+                    status_buf[0], status_buf[1]);
+
+               *line_state_p = klsi_105_status2linestate(status);
+       }
+
+        return rc;
+}
+
+
+/*
+ * Driver's tty interface functions
+ */
+
+static int klsi_105_startup (struct usb_serial *serial)
+{
+       struct klsi_105_private *priv;
+       int i;
+
+       /* check if we support the product id (see keyspan.c)
+        * FIXME
+        */
+
+       /* allocate the private data structure */
+       for (i=0; i<serial->num_ports; i++) {
+               serial->port[i].private = kmalloc(sizeof(struct klsi_105_private),
+                                                  GFP_KERNEL);
+               if (!serial->port[i].private) {
+                       dbg(__FUNCTION__ "kmalloc for klsi_105_private failed.");
+                       return (-1); /* error */
+               }
+               priv = (struct klsi_105_private *)serial->port[i].private;
+               /* set initial values for control structures */
+               priv->cfg.pktlen    = 5;
+               priv->cfg.baudrate  = kl5kusb105a_sio_b9600;
+               priv->cfg.databits  = kl5kusb105a_dtb_8;
+               priv->cfg.unknown1  = 0;
+               priv->cfg.unknown2  = 1;
+
+               priv->line_state    = 0;
+
+               priv->bytes_in      = 0;
+               priv->bytes_out     = 0;
+
+               spin_lock_init (&priv->write_urb_pool_lock);
+               for (i=0; i<NUM_URBS; i++) {
+                       struct urb* urb = usb_alloc_urb(0);
+
+                       priv->write_urb_pool[i] = urb;
+                       if (urb == NULL) {
+                               err("No more urbs???");
+                               continue;
+                       }
+
+                       urb->transfer_buffer = NULL;
+                       urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,
+                                                       GFP_KERNEL);
+                       if (!urb->transfer_buffer) {
+                               err (__FUNCTION__ 
+                                    " - out of memory for urb buffers.");
+                               continue;
+                       }
+               }
+
+               /* priv->termios is left uninitalized until port opening */
+               init_waitqueue_head(&serial->port[i].write_wait);
+       }
+       
+       return (0);
+} /* klsi_105_startup */
+
+
+static void klsi_105_shutdown (struct usb_serial *serial)
+{
+       int i;
+       
+       dbg (__FUNCTION__);
+
+       /* stop reads and writes on all ports */
+       for (i=0; i < serial->num_ports; ++i) {
+               struct klsi_105_private *priv = 
+                       (struct klsi_105_private*) serial->port[i].private;
+               unsigned long flags;
+               while (serial->port[i].open_count > 0) {
+                       klsi_105_close (&serial->port[i], NULL);
+               }
+
+               if (priv) {
+                       /* kill our write urb pool */
+                       int j;
+                       struct urb **write_urbs = priv->write_urb_pool;
+                       spin_lock_irqsave(&priv->write_urb_pool_lock,flags);
+
+                       for (j = 0; j < NUM_URBS; j++) {
+                               if (write_urbs[j]) {
+                                       /* FIXME - uncomment the following
+                                        * usb_unlink_urb call when the host
+                                        * controllers get fixed to set
+                                        * urb->dev = NULL after the urb is
+                                        * finished.  Otherwise this call
+                                        * oopses. */
+                                       /* usb_unlink_urb(write_urbs[j]); */
+                                       if (write_urbs[j]->transfer_buffer)
+                                                   kfree(write_urbs[j]->transfer_buffer);
+                                       usb_free_urb (write_urbs[j]);
+                               }
+                       }
+
+                       spin_unlock_irqrestore (&priv->write_urb_pool_lock,
+                                               flags);
+
+                       kfree(serial->port[i].private);
+               }
+       }
+} /* klsi_105_shutdown */
+
+static int  klsi_105_open (struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial = port->serial;
+       struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+       int retval = 0;
+
+       dbg(__FUNCTION__" port %d", port->number);
+
+       down (&port->sem);
+       
+       ++port->open_count;
+
+       if (port->open_count == 1) {
+               int rc;
+               int i;
+               unsigned long line_state;
+
+               /* force low_latency on so that our tty_push actually forces
+                * the data through
+                * port->tty->low_latency = 1; */
+
+               /* Do a defined restart:
+                * Set up sane default baud rate and send the 'READ_ON'
+                * vendor command. 
+                * FIXME: set modem line control (how?)
+                * Then read the modem line control and store values in
+                * priv->line_state.
+                */
+               priv->cfg.pktlen   = 5;
+               priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+               priv->cfg.databits = kl5kusb105a_dtb_8;
+               priv->cfg.unknown1 = 0;
+               priv->cfg.unknown2 = 1;
+               klsi_105_chg_port_settings(serial, &(priv->cfg));
+               
+               /* set up termios structure */
+               priv->termios.c_iflag = port->tty->termios->c_iflag;
+               priv->termios.c_oflag = port->tty->termios->c_oflag;
+               priv->termios.c_cflag = port->tty->termios->c_cflag;
+               priv->termios.c_lflag = port->tty->termios->c_lflag;
+               for (i=0; i<NCCS; i++)
+                       priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
+
+
+               /* READ_ON and urb submission */
+               FILL_BULK_URB(port->read_urb, serial->dev, 
+                             usb_rcvbulkpipe(serial->dev,
+                                             port->bulk_in_endpointAddress),
+                             port->read_urb->transfer_buffer,
+                             port->read_urb->transfer_buffer_length,
+                             klsi_105_read_bulk_callback,
+                             port);
+               port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+               rc = usb_submit_urb(port->read_urb);
+               if (rc) {
+                       err(__FUNCTION__ 
+                           " - failed submitting read urb, error %d", rc);
+                       retval = rc;
+                       goto exit;
+               }
+
+               rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
+                                    KL5KUSB105A_SIO_CONFIGURE,
+                                    USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
+                                    KL5KUSB105A_SIO_CONFIGURE_READ_ON,
+                                    0, /* index */
+                                    NULL,
+                                    0,
+                                    KLSI_TIMEOUT);
+               if (rc < 0) {
+                       err("Enabling read failed (error = %d)", rc);
+                       retval = rc;
+               } else 
+                       dbg(__FUNCTION__ " - enabled reading");
+
+               rc = klsi_105_get_line_state(serial, &line_state);
+               if (rc >= 0) {
+                       priv->line_state = line_state;
+                       dbg(__FUNCTION__ 
+                           " - read line state 0x%lx", line_state);
+                       retval = 0;
+               } else
+                       retval = rc;
+       }
+
+exit:
+       up (&port->sem);
+       
+       return retval;
+} /* klsi_105_open */
+
+
+static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial;
+       struct klsi_105_private *priv 
+               = (struct klsi_105_private *)port->private;
+       dbg(__FUNCTION__" port %d", port->number);
+
+       serial = get_usb_serial (port, __FUNCTION__);
+
+       if(!serial)
+               return;
+
+       down (&port->sem);
+
+       --port->open_count;
+
+       if (port->open_count <= 0) {
+               /* send READ_OFF */
+               int rc = usb_control_msg(serial->dev,
+                                        usb_sndctrlpipe(serial->dev, 0),
+                                        KL5KUSB105A_SIO_CONFIGURE,
+                                        USB_TYPE_VENDOR | USB_DIR_OUT,
+                                        KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+                                        0, /* index */
+                                        NULL, 0,
+                                        KLSI_TIMEOUT);
+               if (rc < 0)
+                           err("Disabling read failed (error = %d)", rc);
+
+               /* shutdown our bulk reads and writes */
+               usb_unlink_urb (port->write_urb);
+               usb_unlink_urb (port->read_urb);
+               /* unlink our write pool */
+               /* FIXME */
+               /* wgg - do I need this? I think so. */
+               usb_unlink_urb (port->interrupt_in_urb);
+               port->open_count = 0;
+               info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
+       }
+       
+       up (&port->sem);
+} /* klsi_105_close */
+
+
+/* We need to write a complete 64-byte data block and encode the
+ * number actually sent in the first double-byte, LSB-order. That 
+ * leaves at most 62 bytes of payload.
+ */
+#define KLSI_105_DATA_OFFSET   2   /* in the bulk urb data block */
+
+
+static int klsi_105_write (struct usb_serial_port *port, int from_user,
+                          const unsigned char *buf, int count)
+{
+       struct usb_serial *serial = port->serial;
+       struct klsi_105_private *priv = 
+               (struct klsi_105_private*) port->private;
+       int result, size;
+       int bytes_sent=0;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       down (&port->sem);      /* to lock against someone else trying to
+                                  take an URB we just selected from the pool */
+
+       while (count > 0) {
+               /* try to find a free urb (write 0 bytes if none) */
+               struct urb *urb = NULL;
+               unsigned long flags;
+               int i;
+               /* since the pool is per-port we might not need the spin lock !? */
+               spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+               for (i=0; i<NUM_URBS; i++) {
+                       if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+                               urb = priv->write_urb_pool[i];
+                               dbg(__FUNCTION__ " - using pool URB %d", i);
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+               if (urb==NULL) {
+                       dbg (__FUNCTION__ " - no more free urbs");
+                       goto exit;
+               }
+
+               if (urb->transfer_buffer == NULL) {
+                       urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+                       if (urb->transfer_buffer == NULL) {
+                               err(__FUNCTION__ " - no more kernel memory...");
+                               goto exit;
+                       }
+               }
+
+               size = min (count, port->bulk_out_size - KLSI_105_DATA_OFFSET);
+               size = min (size, URB_TRANSFER_BUFFER_SIZE - KLSI_105_DATA_OFFSET);
+
+               if (from_user) {
+                       if (copy_from_user(urb->transfer_buffer
+                                          + KLSI_105_DATA_OFFSET, buf, size)) {
+                               up (&port->sem);
+                               return -EFAULT;
+                       }
+               } else {
+                       memcpy (urb->transfer_buffer + KLSI_105_DATA_OFFSET,
+                               buf, size);
+               }
+
+               /* write payload size into transfer buffer */
+               ((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF);
+               ((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8);
+
+               /* set up our urb */
+               FILL_BULK_URB(urb, serial->dev,
+                             usb_sndbulkpipe(serial->dev,
+                                             port->bulk_out_endpointAddress),
+                             urb->transfer_buffer,
+                             URB_TRANSFER_BUFFER_SIZE,
+                             klsi_105_write_bulk_callback,
+                             port);
+               urb->transfer_flags |= USB_QUEUE_BULK;
+
+
+               /* send the data out the bulk port */
+               result = usb_submit_urb(urb);
+               if (result) {
+                       err(__FUNCTION__
+                           " - failed submitting write urb, error %d", result);
+                       goto exit;
+               }
+               buf += size;
+               bytes_sent += size;
+               count -= size;
+       }
+exit:
+       up (&port->sem);
+       priv->bytes_out+=bytes_sent;
+
+       return bytes_sent;      /* that's how much we wrote */
+} /* klsi_105_write */
+
+static void klsi_105_write_bulk_callback ( struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial *serial = port->serial;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+       
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+
+       if (urb->status) {
+               dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+                   urb->status);
+               return;
+       }
+
+       /* from generic_write_bulk_callback */
+       queue_task(&port->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+
+       return;
+} /* klsi_105_write_bulk_completion_callback */
+
+
+/* return number of characters currently in the writing process */
+static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
+{
+       int chars = 0;
+       int i;
+       unsigned long flags;
+       struct klsi_105_private *priv = 
+               (struct klsi_105_private*) port->private;
+
+       spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
+                       chars += URB_TRANSFER_BUFFER_SIZE;
+               }
+       }
+
+       spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+       dbg (__FUNCTION__ " - returns %d", chars);
+       return (chars);
+}
+
+static int klsi_105_write_room (struct usb_serial_port *port)
+{
+       unsigned long flags;
+       int i;
+       int room = 0;
+       struct klsi_105_private *priv = 
+               (struct klsi_105_private*) port->private;
+
+       spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+                       room += URB_TRANSFER_BUFFER_SIZE;
+               }
+       }
+
+       spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+       dbg(__FUNCTION__ " - returns %d", room);
+       return (room);
+}
+
+
+
+static void klsi_105_read_bulk_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial *serial = port->serial;
+       struct klsi_105_private *priv = 
+               (struct klsi_105_private*) port->private;
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
+       int rc;
+
+        dbg(__FUNCTION__ " - port %d", port->number);
+
+       /* The urb might have been killed. */
+        if (urb->status) {
+                dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
+                   urb->status);
+                return;
+        }
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+       
+       /* The data received is again preceded by a length double-byte in LSB-
+        * first order (see klsi_105_write() )
+        */
+       if (urb->actual_length == 0) {
+               /* empty urbs seem to happen, we ignore them */
+               /* dbg(__FUNCTION__ " - emtpy URB"); */
+              ;
+       } else if (urb->actual_length <= 2) {
+               dbg(__FUNCTION__ " - size %d URB not understood",
+                   urb->actual_length);
+               usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+       } else {
+               int i;
+               int bytes_sent = ((__u8 *) data)[0] +
+                                ((unsigned int) ((__u8 *) data)[1] << 8);
+               tty = port->tty;
+               /* we should immediately resubmit the URB, before attempting
+                * to pass the data on to the tty layer. But that needs locking
+                * against re-entry an then mixed-up data because of
+                * intermixed tty_flip_buffer_push()s
+                * FIXME
+                */ 
+               usb_serial_debug_data (__FILE__, __FUNCTION__,
+                                      urb->actual_length, data);
+
+               if (bytes_sent + 2 > urb->actual_length) {
+                       dbg(__FUNCTION__ 
+                           " - trying to read more data than available"
+                           " (%d vs. %d)",
+                           bytes_sent+2, urb->actual_length);
+                       /* cap at implied limit */
+                       bytes_sent = urb->actual_length - 2;
+               }
+
+               for (i = 2; i < 2+bytes_sent; i++) {
+                       /* if we insert more than TTY_FLIPBUF_SIZE characters,
+                        * we drop them. */
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       /* this doesn't actually push the data through unless 
+                        * tty->low_latency is set */
+                       tty_insert_flip_char(tty, ((__u8*) data)[i], 0);
+               }
+               tty_flip_buffer_push(tty);
+               priv->bytes_in += bytes_sent;
+       }
+       /* Continue trying to always read  */
+       FILL_BULK_URB(port->read_urb, serial->dev, 
+                     usb_rcvbulkpipe(serial->dev,
+                                     port->bulk_in_endpointAddress),
+                     port->read_urb->transfer_buffer,
+                     port->read_urb->transfer_buffer_length,
+                     klsi_105_read_bulk_callback,
+                     port);
+       rc = usb_submit_urb(port->read_urb);
+       if (rc)
+               err(__FUNCTION__ 
+                   " - failed resubmitting read urb, error %d", rc);
+} /* klsi_105_read_bulk_callback */
+
+
+static void klsi_105_set_termios (struct usb_serial_port *port,
+                                 struct termios *old_termios)
+{
+       struct usb_serial *serial = port->serial;
+       struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+       unsigned int iflag = port->tty->termios->c_iflag;
+       unsigned int old_iflag = old_termios->c_iflag;
+       unsigned int cflag = port->tty->termios->c_cflag;
+       unsigned int old_cflag = old_termios->c_cflag;
+       
+       /*
+        * Update baud rate
+        */
+       if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
+               /* reassert DTR and (maybe) RTS on transition from B0 */
+               if( (old_cflag & CBAUD) == B0 ) {
+                       dbg(__FUNCTION__ ": baud was B0");
+#if 0
+                       priv->control_state |= TIOCM_DTR;
+                       /* don't set RTS if using hardware flow control */
+                       if (!(old_cflag & CRTSCTS)) {
+                               priv->control_state |= TIOCM_RTS;
+                       }
+                       mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+               }
+               
+               switch(cflag & CBAUD) {
+               case B0: /* handled below */
+                       break;
+               case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+                       break;
+               case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+                       break;
+               case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+                       break;
+               case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+                       break;
+               case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+                       break;
+               case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+                       break;
+               case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+                       break;
+               case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+                       break;
+               default:
+                       err("KLSI USB->Serial converter:"
+                           " unsupported baudrate request, using default"
+                           " of 9600");
+                       priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+                       break;
+               }
+               if ((cflag & CBAUD) == B0 ) {
+                       dbg(__FUNCTION__ ": baud is B0");
+                       /* Drop RTS and DTR */
+                       /* maybe this should be simulated by sending read
+                        * disable and read enable messages?
+                        */
+                       ;
+#if 0
+                       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+                       mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+               }
+       }
+
+       if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
+               /* set the number of data bits */
+               switch (cflag & CSIZE) {
+               case CS5:
+                       dbg(__FUNCTION__ " - 5 bits/byte not supported");
+                       return ;
+               case CS6:
+                       dbg(__FUNCTION__ " - 6 bits/byte not supported");
+                       return ;
+               case CS7:
+                       priv->cfg.databits = kl5kusb105a_dtb_7;
+                       break;
+               case CS8:
+                       priv->cfg.databits = kl5kusb105a_dtb_8;
+                       break;
+               default:
+                       err("CSIZE was not CS5-CS8, using default of 8");
+                       priv->cfg.databits = kl5kusb105a_dtb_8;
+                       break;
+               }
+       }
+
+       /*
+        * Update line control register (LCR)
+        */
+       if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
+           || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
+               
+#if 0
+               priv->last_lcr = 0;
+
+               /* set the parity */
+               if (cflag & PARENB)
+                       priv->last_lcr |= (cflag & PARODD) ?
+                               MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
+               else
+                       priv->last_lcr |= MCT_U232_PARITY_NONE;
+
+               /* set the number of stop bits */
+               priv->last_lcr |= (cflag & CSTOPB) ?
+                       MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
+
+               mct_u232_set_line_ctrl(serial, priv->last_lcr);
+#endif
+               ;
+       }
+       
+       /*
+        * Set flow control: well, I do not really now how to handle DTR/RTS.
+        * Just do what we have seen with SniffUSB on Win98.
+        */
+       if( (iflag & IXOFF) != (old_iflag & IXOFF)
+           || (iflag & IXON) != (old_iflag & IXON)
+           ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) {
+               
+               /* Drop DTR/RTS if no flow control otherwise assert */
+#if 0
+               if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
+                       priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+               else
+                       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+               mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+               ;
+       }
+
+       /* now commit changes to device */
+       klsi_105_chg_port_settings(serial, &(priv->cfg));
+} /* klsi_105_set_termios */
+
+
+#if 0
+static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
+{
+       struct usb_serial *serial = port->serial;
+       struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+       unsigned char lcr = priv->last_lcr;
+
+       dbg (__FUNCTION__ "state=%d", break_state);
+
+       if (break_state)
+               lcr |= MCT_U232_SET_BREAK;
+
+       mct_u232_set_line_ctrl(serial, lcr);
+} /* mct_u232_break_ctl */
+#endif
+
+static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
+                          unsigned int cmd, unsigned long arg)
+{
+       struct usb_serial *serial = port->serial;
+       struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+       int mask;
+       
+       dbg (__FUNCTION__ "cmd=0x%x", cmd);
+
+       /* Based on code from acm.c and others */
+       switch (cmd) {
+       case TIOCMGET: {
+               int rc;
+               unsigned long line_state;
+               dbg (__FUNCTION__ " - TIOCMGET request, just guessing");
+
+               rc = klsi_105_get_line_state(serial, &line_state);
+               if (rc < 0) {
+                       err("Reading line control failed (error = %d)", rc);
+                       /* better return value? EAGAIN? */
+                       return -ENOIOCTLCMD;
+               } else {
+                       priv->line_state = line_state;
+                       dbg(__FUNCTION__ " - read line state 0x%lx", line_state);
+               }
+               return put_user(priv->line_state, (unsigned long *) arg); 
+              };
+
+       case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+       case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+       case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+               if (get_user(mask, (unsigned long *) arg))
+                       return -EFAULT;
+
+               if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+                       /* RTS needs set */
+                       if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
+                           (cmd == TIOCMBIS) )
+                               dbg (__FUNCTION__ " - set RTS not handled");
+                               /* priv->control_state |=  TIOCM_RTS; */
+                       else
+                               dbg (__FUNCTION__ " - clear RTS not handled");
+                               /* priv->control_state &= ~TIOCM_RTS; */
+               }
+
+               if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+                       /* DTR needs set */
+                       if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
+                           (cmd == TIOCMBIS) )
+                               dbg (__FUNCTION__ " - set DTR not handled");
+                       /*      priv->control_state |=  TIOCM_DTR; */
+                       else
+                               dbg (__FUNCTION__ " - clear DTR not handled");
+                               /* priv->control_state &= ~TIOCM_DTR; */
+               }
+               /*
+               mct_u232_set_modem_ctrl(serial, priv->control_state);
+               */
+               break;
+                                       
+       case TIOCMIWAIT:
+               /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+               /* TODO */
+               dbg (__FUNCTION__ " - TIOCMIWAIT not handled");
+               return -ENOIOCTLCMD;
+
+       case TIOCGICOUNT:
+               /* return count of modemline transitions */
+               /* TODO */
+               dbg (__FUNCTION__ " - TIOCGICOUNT not handled");
+               return -ENOIOCTLCMD;
+       case TCGETS: {
+            /* return current info to caller */
+            int retval;
+
+            dbg (__FUNCTION__ " - TCGETS data faked/incomplete");
+
+            retval = verify_area(VERIFY_WRITE, (void *)arg,
+                                 sizeof(struct termios));
+
+            if (retval)
+                        return(retval);
+
+            kernel_termios_to_user_termios((struct termios *)arg,  
+                                           &priv->termios);
+            return(0);
+            }
+       case TCSETS: {
+               /* set port termios to the one given by the user */
+               int retval;
+
+               dbg (__FUNCTION__ " - TCSETS not handled");
+
+               retval = verify_area(VERIFY_READ, (void *)arg,
+                                    sizeof(struct termios));
+
+               if (retval)
+                           return(retval);
+
+               user_termios_to_kernel_termios(&priv->termios,
+                                              (struct termios *)arg);
+               klsi_105_set_termios(port, &priv->termios);
+               return(0);
+            }
+       case TCSETSW: {
+               /* set port termios and try to wait for completion of last
+                * write operation */
+               /* We guess here. If there are not too many write urbs
+                * outstanding, we lie. */
+               /* what is the right way to wait here? schedule() ? */
+               /*
+               while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE)
+                           schedule();
+                */
+               return -ENOIOCTLCMD;
+                     }
+       default:
+               dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd);
+               return(-ENOIOCTLCMD);
+               break;
+       }
+       return 0;
+} /* klsi_105_ioctl */
+
+static void klsi_105_throttle (struct usb_serial_port *port)
+{
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       down (&port->sem);
+
+       usb_unlink_urb (port->read_urb);
+
+       up (&port->sem);
+
+       return;
+}
+static void klsi_105_unthrottle (struct usb_serial_port *port)
+{
+       int result;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       down (&port->sem);
+
+       port->read_urb->dev = port->serial->dev;
+       result = usb_submit_urb(port->read_urb);
+       if (result)
+               err(__FUNCTION__ " - failed submitting read urb, error %d",
+                   result);
+
+       up (&port->sem);
+
+       return;
+}
+
+
+
+static int __init klsi_105_init (void)
+{
+       usb_serial_register (&kl5kusb105d_device);
+
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return 0;
+}
+
+
+static void __exit klsi_105_exit (void)
+{
+       usb_serial_deregister (&kl5kusb105d_device);
+}
+
+
+module_init (klsi_105_init);
+module_exit (klsi_105_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL"); 
+
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "enable extensive debugging messages");
+/* FIXME: implement
+MODULE_PARM(num_urbs, "i");
+MODULE_PARM_DESC(num_urbs, "number of URBs to use in write pool");
+*/
+
+/* vim: set sts=8 ts=8 sw=8: */
diff --git a/drivers/usb/serial/kl5kusb105.h b/drivers/usb/serial/kl5kusb105.h
new file mode 100644 (file)
index 0000000..2e15a2d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Definitions for the KLSI KL5KUSB105 serial port adapter
+ */
+
+/* vendor/product pairs that are known to contain this chipset */
+#define PALMCONNECT_VID                0x0830
+#define PALMCONNECT_PID                0x0080
+
+#define KLSI_VID               0x05e9
+#define KLSI_KL5KUSB105D_PID   0x00c0
+
+/* Vendor commands: */
+
+
+/* port table -- the chip supports up to 4 channels */
+
+/* baud rates */
+
+typedef enum {
+  kl5kusb105a_sio_b115200 = 0,
+  kl5kusb105a_sio_b57600  = 1,
+  kl5kusb105a_sio_b38400  = 2,
+  kl5kusb105a_sio_b19200  = 4,
+  kl5kusb105a_sio_b14400  = 5,
+  kl5kusb105a_sio_b9600   = 6,
+  kl5kusb105a_sio_b4800   = 8,   /* unchecked */
+  kl5kusb105a_sio_b2400   = 9,   /* unchecked */
+  kl5kusb105a_sio_b1200   = 0xa,  /* unchecked */
+  kl5kusb105a_sio_b600    = 0xb   /* unchecked */
+} KL5KUSB105A_SIO_baudrate_t;
+
+/* data bits */
+#define kl5kusb105a_dtb_7   7
+#define kl5kusb105a_dtb_8   8
+
+
+
+/* requests: */
+#define KL5KUSB105A_SIO_SET_DATA  1
+#define KL5KUSB105A_SIO_POLL      2
+#define KL5KUSB105A_SIO_CONFIGURE      3
+/* values used for request KL5KUSB105A_SIO_CONFIGURE */
+#define KL5KUSB105A_SIO_CONFIGURE_READ_ON      3
+#define KL5KUSB105A_SIO_CONFIGURE_READ_OFF     2
+
+/* Interpretation of modem status lines */
+/* These need sorting out by individually connecting pins and checking
+ * results. FIXME!
+ * When data is being sent we see 0x30 in the lower byte; this must
+ * contain DSR and CTS ...
+ */
+#define KL5KUSB105A_DSR                        ((1<<4) | (1<<5))
+#define KL5KUSB105A_CTS                        ((1<<5) | (1<<4))
+
+#define KL5KUSB105A_WANTS_TO_SEND      0x30
+//#define KL5KUSB105A_DTR                      /* Data Terminal Ready */
+//#define KL5KUSB105A_CTS                      /* Clear To Send */
+//#define KL5KUSB105A_CD                       /* Carrier Detect */
+//#define KL5KUSB105A_DSR                      /* Data Set Ready */
+//#define KL5KUSB105A_RxD                      /* Receive pin */
+
+//#define KL5KUSB105A_LE
+//#define KL5KUSB105A_RTS              
+//#define KL5KUSB105A_ST               
+//#define KL5KUSB105A_SR               
+//#define KL5KUSB105A_RI                       /* Ring Indicator */
+
+/* vim: set ts=8 sts=8: */
+
index a2958fc6cf42e0ceda489c2014ec2615fcef7e0f..35bebc612c479f9c53f1b1824f00a305dbbe2f3d 100644 (file)
@@ -181,23 +181,23 @@ void usb_show_string(struct usb_device *dev, char *id, int index)
        kfree(buf);
 }
 
-void usb_dump_urb (purb_t purb)
+void usb_dump_urb (struct urb *urb)
 {
-       printk ("urb                   :%p\n", purb);
-       printk ("next                  :%p\n", purb->next);
-       printk ("dev                   :%p\n", purb->dev);
-       printk ("pipe                  :%08X\n", purb->pipe);
-       printk ("status                :%d\n", purb->status);
-       printk ("transfer_flags        :%08X\n", purb->transfer_flags);
-       printk ("transfer_buffer       :%p\n", purb->transfer_buffer);
-       printk ("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-       printk ("actual_length         :%d\n", purb->actual_length);
-       printk ("setup_packet          :%p\n", purb->setup_packet);
-       printk ("start_frame           :%d\n", purb->start_frame);
-       printk ("number_of_packets     :%d\n", purb->number_of_packets);
-       printk ("interval              :%d\n", purb->interval);
-       printk ("error_count           :%d\n", purb->error_count);
-       printk ("context               :%p\n", purb->context);
-       printk ("complete              :%p\n", purb->complete);
+       printk ("urb                   :%p\n", urb);
+       printk ("next                  :%p\n", urb->next);
+       printk ("dev                   :%p\n", urb->dev);
+       printk ("pipe                  :%08X\n", urb->pipe);
+       printk ("status                :%d\n", urb->status);
+       printk ("transfer_flags        :%08X\n", urb->transfer_flags);
+       printk ("transfer_buffer       :%p\n", urb->transfer_buffer);
+       printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+       printk ("actual_length         :%d\n", urb->actual_length);
+       printk ("setup_packet          :%p\n", urb->setup_packet);
+       printk ("start_frame           :%d\n", urb->start_frame);
+       printk ("number_of_packets     :%d\n", urb->number_of_packets);
+       printk ("interval              :%d\n", urb->interval);
+       printk ("error_count           :%d\n", urb->error_count);
+       printk ("context               :%p\n", urb->context);
+       printk ("complete              :%p\n", urb->complete);
 }
 
index 1003eaf5212fa6e4de17ed68c3e0b35d6fcc1181..0f7f43f96df879e0c7001b2325f7eaa0a322dd64 100644 (file)
@@ -97,6 +97,8 @@ int usb_register(struct usb_driver *new_driver)
 
        usb_scan_devices();
 
+       usbfs_update_special();
+
        return 0;
 }
 
@@ -192,6 +194,8 @@ void usb_deregister(struct usb_driver *driver)
                usb_drivers_purge(driver, bus->root_hub);
        }
        up (&usb_bus_list_lock);
+
+       usbfs_update_special();
 }
 
 /**
@@ -421,7 +425,6 @@ struct usb_bus *usb_alloc_bus(struct usb_operations *op)
        bus->bandwidth_isoc_reqs = 0;
 
        INIT_LIST_HEAD(&bus->bus_list);
-       INIT_LIST_HEAD(&bus->inodes);
 
        atomic_set(&bus->refcnt, 1);
 
@@ -468,7 +471,7 @@ void usb_register_bus(struct usb_bus *bus)
        list_add(&bus->bus_list, &usb_bus_list);
        up (&usb_bus_list_lock);
 
-       usbdevfs_add_bus(bus);
+       usbfs_add_bus(bus);
 
        info("new USB bus registered, assigned bus number %d", bus->busnum);
 }
@@ -494,7 +497,7 @@ void usb_deregister_bus(struct usb_bus *bus)
        list_del(&bus->bus_list);
        up (&usb_bus_list_lock);
 
-       usbdevfs_remove_bus(bus);
+       usbfs_remove_bus(bus);
 
        clear_bit(bus->busnum, busmap.busmap);
 
@@ -923,7 +926,7 @@ static void call_policy (char *verb, struct usb_device *dev)
 
                /* a simple/common case: one config, one interface, one driver
                 * with current altsetting being a reasonable setting.
-                * everything needs a smart agent and usbdevfs; or can rely on
+                * everything needs a smart agent and usbfs; or can rely on
                 * device-specific binding policies.
                 */
                envp [i++] = scratch;
@@ -1013,10 +1016,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
 
        usb_bus_get(bus);
 
+       if (!parent)
+               dev->devpath [0] = '/';
        dev->bus = bus;
        dev->parent = parent;
        atomic_set(&dev->refcnt, 1);
-       INIT_LIST_HEAD(&dev->inodes);
        INIT_LIST_HEAD(&dev->filelist);
 
        init_MUTEX(&dev->serialize);
@@ -1906,7 +1910,7 @@ void usb_disconnect(struct usb_device **pdev)
        /* Free the device number and remove the /proc/bus/usb entry */
        if (dev->devnum > 0) {
                clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
-               usbdevfs_remove_device(dev);
+               usbfs_remove_device(dev);
        }
 
        /* Free up the device itself */
@@ -2579,7 +2583,7 @@ int usb_new_device(struct usb_device *dev)
 #endif
 
        /* now that the basic setup is over, add a /proc/bus/usb entry */
-       usbdevfs_add_device(dev);
+       usbfs_add_device(dev);
 
        /* find drivers willing to handle this device */
        usb_find_drivers(dev);
@@ -2592,7 +2596,7 @@ int usb_new_device(struct usb_device *dev)
 
 static int usb_open(struct inode * inode, struct file * file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        struct usb_driver *c = usb_minors[minor/16];
        int err = -ENODEV;
        struct file_operations *old_fops, *new_fops = NULL;
@@ -2660,7 +2664,7 @@ static int __init usb_init(void)
 {
        init_MUTEX(&usb_bus_list_lock);
        usb_major_init();
-       usbdevfs_init();
+       usbfs_init();
        usb_hub_init();
 
        return 0;
@@ -2672,7 +2676,7 @@ static int __init usb_init(void)
 static void __exit usb_exit(void)
 {
        usb_major_cleanup();
-       usbdevfs_cleanup();
+       usbfs_cleanup();
        usb_hub_cleanup();
 }
 
index 8d58e82c5bf2df04a01075d82a40bcc3df50d567..1f2d29f6d0cdcc141efe7ede83ced0c26d1085dc 100644 (file)
@@ -308,7 +308,7 @@ struct inode *autofs4_get_inode(struct super_block *sb,
        }
        inode->i_blksize = PAGE_CACHE_SIZE;
        inode->i_blocks = 0;
-       inode->i_rdev = 0;
+       inode->i_rdev = NODEV;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 
        if (S_ISDIR(inf->mode)) {
index b548b2e1c1942345698c092cf09331d8e18bec50..7e04cec34db06f38756504acc90f471b248aa146 100644 (file)
 static unsigned long max_block(kdev_t dev)
 {
        unsigned int retval = ~0U;
-       int major = MAJOR(dev);
+       int major = major(dev);
 
        if (blk_size[major]) {
-               int minor = MINOR(dev);
+               int minor = minor(dev);
                unsigned int blocks = blk_size[major][minor];
                if (blocks) {
                        unsigned int size = block_size(dev);
@@ -47,10 +47,10 @@ static unsigned long max_block(kdev_t dev)
 static loff_t blkdev_size(kdev_t dev)
 {
        unsigned int blocks = ~0U;
-       int major = MAJOR(dev);
+       int major = major(dev);
 
        if (blk_size[major]) {
-               int minor = MINOR(dev);
+               int minor = minor(dev);
                blocks = blk_size[major][minor];
        }
        return (loff_t) blocks << BLOCK_SIZE_BITS;
@@ -77,25 +77,25 @@ int set_blocksize(kdev_t dev, int size)
                return -EINVAL;
 
        /* No blocksize array? Implies hardcoded BLOCK_SIZE */
-       if (!blksize_size[MAJOR(dev)]) {
+       if (!blksize_size[major(dev)]) {
                if (size == BLOCK_SIZE)
                        return 0;
                return -EINVAL;
        }
 
-       oldsize = blksize_size[MAJOR(dev)][MINOR(dev)];
+       oldsize = blksize_size[major(dev)][minor(dev)];
        if (oldsize == size)
                return 0;
 
        if (!oldsize && size == BLOCK_SIZE) {
-               blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+               blksize_size[major(dev)][minor(dev)] = size;
                return 0;
        }
 
        /* Ok, we're actually changing the blocksize.. */
-       bdev = bdget(dev);
+       bdev = bdget(kdev_t_to_nr(dev));
        sync_buffers(dev, 2);
-       blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+       blksize_size[major(dev)][minor(dev)] = size;
        bdev->bd_inode->i_blkbits = blksize_bits(size);
        kill_bdev(bdev);
        bdput(bdev);
@@ -511,13 +511,13 @@ int check_disk_change(kdev_t dev)
        int i;
        const struct block_device_operations * bdops = NULL;
 
-       i = MAJOR(dev);
+       i = major(dev);
        if (i < MAX_BLKDEV)
                bdops = blkdevs[i].bdops;
        if (bdops == NULL) {
                devfs_handle_t de;
 
-               de = devfs_find_handle (NULL, NULL, i, MINOR (dev),
+               de = devfs_find_handle (NULL, NULL, i, minor(dev),
                                        DEVFS_SPECIAL_BLK, 0);
                if (de) {
                        bdops = devfs_get_ops (de);
@@ -563,7 +563,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
        down(&bdev->bd_sem);
        lock_kernel();
        if (!bdev->bd_op)
-               bdev->bd_op = get_blkfops(MAJOR(dev));
+               bdev->bd_op = get_blkfops(major(dev));
        if (bdev->bd_op) {
                ret = 0;
                if (bdev->bd_op->owner)
@@ -686,11 +686,11 @@ struct file_operations def_blk_fops = {
 const char * bdevname(kdev_t dev)
 {
        static char buffer[32];
-       const char * name = blkdevs[MAJOR(dev)].name;
+       const char * name = blkdevs[major(dev)].name;
 
        if (!name)
                name = "unknown-block";
 
-       sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+       sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
        return buffer;
 }
index a9eb58f672c50702a7fc11842ae83d3959e84639..816686216176ef8be596396800b1a44057b0f256 100644 (file)
@@ -203,7 +203,7 @@ static int write_some_buffers(kdev_t dev)
                struct buffer_head * bh = next;
                next = bh->b_next_free;
 
-               if (dev && bh->b_dev != dev)
+               if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
                        continue;
                if (test_and_set_bit(BH_Lock, &bh->b_state))
                        continue;
@@ -261,7 +261,7 @@ static int wait_for_buffers(kdev_t dev, int index, int refile)
                                __refile_buffer(bh);
                        continue;
                }
-               if (dev && bh->b_dev != dev)
+               if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
                        continue;
 
                get_bh(bh);
@@ -346,7 +346,7 @@ int fsync_dev(kdev_t dev)
 
        lock_kernel();
        sync_inodes(dev);
-       if (dev) {
+       if (!kdev_none(dev)) {
                struct super_block *sb = get_super(dev);
                if (sb) {
                        DQUOT_SYNC(sb);
@@ -371,7 +371,7 @@ void sync_dev(kdev_t dev)
 
 asmlinkage long sys_sync(void)
 {
-       fsync_dev(0);
+       fsync_dev(NODEV);
        return 0;
 }
 
@@ -571,7 +571,7 @@ struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
                        continue;
                if (bh->b_size != size)
                        continue;
-               if (bh->b_dev != dev)
+               if (!kdev_same(bh->b_dev, dev))
                        continue;
                get_bh(bh);
                break;
@@ -675,7 +675,7 @@ void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
                        bh_next = bh->b_next_free;
 
                        /* Another device? */
-                       if (bh->b_dev != dev)
+                       if (!kdev_same(bh->b_dev, dev))
                                continue;
                        /* Not hashed? */
                        if (!bh->b_pprev)
@@ -718,7 +718,7 @@ out:
 
 void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
 {
-       struct block_device *bdev = bdget(dev);
+       struct block_device *bdev = bdget(kdev_t_to_nr(dev));
        if (bdev) {
                invalidate_bdev(bdev, destroy_dirty_buffers);
                bdput(bdev);
@@ -2396,7 +2396,7 @@ cleaned_buffers_try_again:
                struct buffer_head * p = tmp;
                tmp = tmp->b_this_page;
 
-               if (p->b_dev == B_FREE) BUG();
+               if (kdev_same(p->b_dev, B_FREE)) BUG();
 
                remove_inode_queue(p);
                __remove_from_queues(p);
@@ -2562,7 +2562,7 @@ static int sync_old_buffers(void)
 {
        lock_kernel();
        sync_unlocked_inodes();
-       sync_supers(0);
+       sync_supers(NODEV);
        unlock_kernel();
 
        for (;;) {
index 3b4448e8d0e816da4d1d235a672fd87bd693e26d..e859ba71db84ba7e9c9fc73e9f3345d325182675 100644 (file)
@@ -27,7 +27,7 @@
 /* serial module kmod load support */
 struct tty_driver *get_tty_driver(kdev_t device);
 #define isa_tty_dev(ma)        (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
-#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
+#define need_serial(ma,mi) (get_tty_driver(mk_kdev(ma,mi)) == NULL)
 #endif
 
 struct device_struct {
@@ -145,7 +145,7 @@ int chrdev_open(struct inode * inode, struct file * filp)
 {
        int ret = -ENODEV;
 
-       filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
+       filp->f_op = get_chrfops(major(inode->i_rdev), minor(inode->i_rdev));
        if (filp->f_op) {
                ret = 0;
                if (filp->f_op->open != NULL) {
@@ -173,18 +173,18 @@ static struct file_operations def_chr_fops = {
 const char * kdevname(kdev_t dev)
 {
        static char buffer[32];
-       sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
+       sprintf(buffer, "%02x:%02x", major(dev), minor(dev));
        return buffer;
 }
 
 const char * cdevname(kdev_t dev)
 {
        static char buffer[32];
-       const char * name = chrdevs[MAJOR(dev)].name;
+       const char * name = chrdevs[major(dev)].name;
 
        if (!name)
                name = "unknown-char";
-       sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+       sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
        return buffer;
 }
   
index f29ecfee234326766d43fe80639b267d7c9520b6..5b7f3e1a75a9b6d0edf8bf85948e4c9d20168189 100644 (file)
@@ -382,7 +382,7 @@ void sync_inodes(kdev_t dev)
        /*
         * Search the super_blocks array for the device(s) to sync.
         */
-       if (dev) {
+       if (!kdev_none(dev)) {
                if ((s = get_super(dev)) != NULL) {
                        sync_inodes_sb(s);
                        drop_super(s);
@@ -826,7 +826,7 @@ struct inode * get_empty_inode(void)
                inodes_stat.nr_inodes++;
                list_add(&inode->i_list, &inode_in_use);
                inode->i_sb = NULL;
-               inode->i_dev = 0;
+               inode->i_dev = NODEV;
                inode->i_blkbits = 0;
                inode->i_ino = ++last_ino;
                inode->i_flags = 0;
index 6906a8ebac09584ed7f640bbd3785e180aa7c972..f5a2e2e678db694af685ba7dad186ef2813bdb1b 100644 (file)
@@ -297,9 +297,9 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
           * stored in the low field, and use that.
           */
          if((low & ~0xff) && high == 0) {
-           inode->i_rdev = MKDEV(low >> 8, low & 0xff);
+           inode->i_rdev = mk_kdev(low >> 8, low & 0xff);
          } else {
-           inode->i_rdev = MKDEV(high, low);
+           inode->i_rdev = mk_kdev(high, low);
          }
        }
        break;
index 2b8113d747da845516cdc405176490f57da2377a..db4be6f1012f24d2f29559340a64806e81f27a43 100644 (file)
@@ -306,8 +306,9 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
        struct nlm_block        *block;
        int                     error;
 
-       dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
-                               file->f_file.f_dentry->d_inode->i_dev,
+       dprintk("lockd: nlmsvc_lock(%02x:%02x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
+                               major(file->f_file.f_dentry->d_inode->i_dev),
+                               minor(file->f_file.f_dentry->d_inode->i_dev),
                                file->f_file.f_dentry->d_inode->i_ino,
                                lock->fl.fl_type, lock->fl.fl_pid,
                                (long long)lock->fl.fl_start,
@@ -385,8 +386,9 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
 {
        struct file_lock        *fl;
 
-       dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
-                               file->f_file.f_dentry->d_inode->i_dev,
+       dprintk("lockd: nlmsvc_testlock(%02x:%02x/%ld, ty=%d, %Ld-%Ld)\n",
+                               major(file->f_file.f_dentry->d_inode->i_dev),
+                               minor(file->f_file.f_dentry->d_inode->i_dev),
                                file->f_file.f_dentry->d_inode->i_ino,
                                lock->fl.fl_type,
                                (long long)lock->fl.fl_start,
@@ -417,8 +419,9 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
 {
        int     error;
 
-       dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
-                               file->f_file.f_dentry->d_inode->i_dev,
+       dprintk("lockd: nlmsvc_unlock(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n",
+                               major(file->f_file.f_dentry->d_inode->i_dev),
+                               minor(file->f_file.f_dentry->d_inode->i_dev),
                                file->f_file.f_dentry->d_inode->i_ino,
                                lock->fl.fl_pid,
                                (long long)lock->fl.fl_start,
@@ -445,8 +448,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
 {
        struct nlm_block        *block;
 
-       dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
-                               file->f_file.f_dentry->d_inode->i_dev,
+       dprintk("lockd: nlmsvc_cancel(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n",
+                               major(file->f_file.f_dentry->d_inode->i_dev),
+                               minor(file->f_file.f_dentry->d_inode->i_dev),
                                file->f_file.f_dentry->d_inode->i_ino,
                                lock->fl.fl_pid,
                                (long long)lock->fl.fl_start,
index 590d31c4e488f410f317ae168b47842e910381e9..5113acea59c7c058428fea1ee597924f22fdd897 100644 (file)
@@ -1589,7 +1589,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
                goto exit_lock;
 
        error = -EXDEV;
-       if (dir->i_dev != inode->i_dev)
+       if (!kdev_same(dir->i_dev, inode->i_dev))
                goto exit_lock;
 
        /*
@@ -1707,7 +1707,7 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
        if (error)
                return error;
 
-       if (new_dir->i_dev != old_dir->i_dev)
+       if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
                return -EXDEV;
 
        if (!new_dentry->d_inode)
@@ -1787,7 +1787,7 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
        if (error)
                return error;
 
-       if (new_dir->i_dev != old_dir->i_dev)
+       if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
                return -EXDEV;
 
        if (!new_dentry->d_inode)
index 68513e6afbdc62abdb7de9474fd287350d3efd1e..08c972763a7578801f547381f61afc5405de1d18 100644 (file)
@@ -643,8 +643,8 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
        struct nfs_fh fhandle;
        int error;
 
-       dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-               dir->i_dev, dir->i_ino, dentry->d_name.name);
+       dfprintk(VFS, "NFS: create(%x:%x/%ld, %s\n",
+               major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
@@ -675,8 +675,8 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
        struct nfs_fh fhandle;
        int error;
 
-       dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-               dir->i_dev, dir->i_ino, dentry->d_name.name);
+       dfprintk(VFS, "NFS: mknod(%x:%x/%ld, %s\n",
+               major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
@@ -701,8 +701,8 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct nfs_fh fhandle;
        int error;
 
-       dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
-               dir->i_dev, dir->i_ino, dentry->d_name.name);
+       dfprintk(VFS, "NFS: mkdir(%x:%x/%ld, %s\n",
+               major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
        attr.ia_valid = ATTR_MODE;
        attr.ia_mode = mode | S_IFDIR;
@@ -730,8 +730,8 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
-       dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-               dir->i_dev, dir->i_ino, dentry->d_name.name);
+       dfprintk(VFS, "NFS: rmdir(%x:%x/%ld, %s\n",
+               major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
        nfs_zap_caches(dir);
        error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
@@ -877,8 +877,8 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
-       dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
-               dir->i_dev, dir->i_ino, dentry->d_name.name);
+       dfprintk(VFS, "NFS: unlink(%x:%x/%ld, %s)\n",
+               major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
        error = nfs_sillyrename(dir, dentry);
        if (error && error != -EBUSY) {
@@ -900,8 +900,8 @@ nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        unsigned int maxlen;
        int error;
 
-       dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-               dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
+       dfprintk(VFS, "NFS: symlink(%x:%x/%ld, %s, %s)\n",
+               major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name, symname);
 
        error = -ENAMETOOLONG;
        maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
index c2587108c62d26673fd1f1a399b3dc92f85cc9b8..edbd649fad107da0b008413ba286d734d8cc7dec 100644 (file)
@@ -73,7 +73,8 @@ nfs_file_flush(struct file *file)
        struct inode    *inode = file->f_dentry->d_inode;
        int             status;
 
-       dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino);
+       dfprintk(VFS, "nfs: flush(%02x:%02x/%ld)\n",
+               major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
        /* Make sure all async reads have been sent off. We don't bother
         * waiting on them though... */
@@ -132,7 +133,8 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
        struct inode *inode = dentry->d_inode;
        int status;
 
-       dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
+       dfprintk(VFS, "nfs: fsync(%02x:%02x/%ld)\n",
+               major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
        lock_kernel();
        status = nfs_wb_file(inode, file);
@@ -245,8 +247,8 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
        struct inode * inode = filp->f_dentry->d_inode;
        int     status = 0;
 
-       dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
-                       inode->i_dev, inode->i_ino,
+       dprintk("NFS: nfs_lock(f=%02x:%02x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
+                       major(inode->i_dev), minor(inode->i_dev), inode->i_ino,
                        fl->fl_type, fl->fl_flags,
                        (long long)fl->fl_start, (long long)fl->fl_end);
 
index 3b802b3b9293794a64ef55bdbd1919f8501ffaf6..73029044c724a745d1b2bef656d1e288e6df2c42 100644 (file)
@@ -104,7 +104,7 @@ nfs_read_inode(struct inode * inode)
 {
        inode->i_blksize = inode->i_sb->s_blocksize;
        inode->i_mode = 0;
-       inode->i_rdev = 0;
+       inode->i_rdev = NODEV;
        /* We can't support UPDATE_ATIME(), since the server will reset it */
        inode->i_flags |= S_NOATIME;
        INIT_LIST_HEAD(&inode->u.nfs_i.read);
@@ -127,7 +127,7 @@ nfs_write_inode(struct inode *inode, int sync)
 static void
 nfs_delete_inode(struct inode * inode)
 {
-       dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+       dprintk("NFS: delete_inode(%x:%x/%ld)\n", major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
        /*
         * The following can never actually happen...
@@ -747,8 +747,9 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                goto out_no_inode;
 
        nfs_fill_inode(inode, fh, fattr);
-       dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n",
-               inode->i_dev, (long long)NFS_FILEID(inode),
+       dprintk("NFS: __nfs_fhget(%x:%x/%Ld ct=%d)\n",
+               major(inode->i_dev), minor(inode->i_dev),
+               (long long)NFS_FILEID(inode),
                atomic_read(&inode->i_count));
 
 out:
@@ -902,8 +903,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        int              status = -ESTALE;
        struct nfs_fattr fattr;
 
-       dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
-               inode->i_dev, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: revalidating (%x:%x/%Ld)\n",
+               major(inode->i_dev), minor(inode->i_dev),
+               (long long)NFS_FILEID(inode));
 
        lock_kernel();
        if (!inode || is_bad_inode(inode))
@@ -924,8 +926,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        status = NFS_PROTO(inode)->getattr(inode, &fattr);
        if (status) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
-                        inode->i_dev, (long long)NFS_FILEID(inode), status);
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x:%x/%Ld) getattr failed, error=%d\n",
+                        major(inode->i_dev), minor(inode->i_dev),
+                        (long long)NFS_FILEID(inode), status);
                if (status == -ESTALE) {
                        NFS_FLAGS(inode) |= NFS_INO_STALE;
                        if (inode != inode->i_sb->s_root->d_inode)
@@ -936,12 +939,14 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        status = nfs_refresh_inode(inode, &fattr);
        if (status) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
-                        inode->i_dev, (long long)NFS_FILEID(inode), status);
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x:%x/%Ld) refresh failed, error=%d\n",
+                        major(inode->i_dev), minor(inode->i_dev),
+                        (long long)NFS_FILEID(inode), status);
                goto out;
        }
-       dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
-               inode->i_dev, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: (%x:%x/%Ld) revalidation complete\n",
+               major(inode->i_dev), minor(inode->i_dev),
+               (long long)NFS_FILEID(inode));
 
        NFS_FLAGS(inode) &= ~NFS_INO_STALE;
 out:
@@ -1000,8 +1005,8 @@ __nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
        time_t          new_atime;
        int             invalid = 0;
 
-       dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
-                       inode->i_dev, inode->i_ino,
+       dfprintk(VFS, "NFS: refresh_inode(%x:%x/%ld ct=%d info=0x%x)\n",
+                       major(inode->i_dev), minor(inode->i_dev), inode->i_ino,
                        atomic_read(&inode->i_count), fattr->valid);
 
        if (NFS_FSID(inode) != fattr->fsid ||
@@ -1100,7 +1105,7 @@ __nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
                inode->i_blocks = fattr->du.nfs2.blocks;
                inode->i_blksize = fattr->du.nfs2.blocksize;
        }
-       inode->i_rdev = 0;
+       inode->i_rdev = NODEV;
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
                inode->i_rdev = to_kdev_t(fattr->rdev);
  
index fd12f2fe38dba578903812a013134a5c86155fd7..a7bca2f68a41a9fd373563300463a720f4abcce7 100644 (file)
@@ -108,9 +108,10 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
                if (count < rsize)
                        rsize = count;
 
-               dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n",
+               dprintk("NFS: nfs_proc_read(%s, (%x:%x/%Ld), %Ld, %d, %p)\n",
                        NFS_SERVER(inode)->hostname,
-                       inode->i_dev, (long long)NFS_FILEID(inode),
+                       major(inode->i_dev), minor(inode->i_dev),
+                       (long long)NFS_FILEID(inode),
                        (long long)offset, rsize, buffer);
 
                lock_kernel();
@@ -265,9 +266,10 @@ nfs_pagein_one(struct list_head *head, struct inode *inode)
        msg.rpc_cred = data->cred;
 
        /* Start the async call */
-       dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
+       dprintk("NFS: %4d initiated read call (req %x:%x/%Ld count %d nriov %d.\n",
                task->tk_pid,
-               inode->i_dev, (long long)NFS_FILEID(inode),
+               major(inode->i_dev), minor(inode->i_dev),
+               (long long)NFS_FILEID(inode),
                data->args.count, data->args.nriov);
 
        rpc_clnt_sigmask(clnt, &oldset);
@@ -423,8 +425,9 @@ nfs_readpage_result(struct rpc_task *task)
                kunmap(page);
                UnlockPage(page);
 
-               dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
-                        req->wb_inode->i_dev,
+               dprintk("NFS: read (%x:%x/%Ld %d@%Ld)\n",
+                        major(req->wb_inode->i_dev),
+                        minor(req->wb_inode->i_dev),
                         (long long)NFS_FILEID(req->wb_inode),
                         req->wb_bytes,
                         (long long)(page_offset(page) + req->wb_offset));
index 4b6c039bb9498b726cbb4fcff1adf63a1f19fde2..9589e2f2959445fcc0eef79364d22142b001d5ab 100644 (file)
@@ -159,8 +159,9 @@ nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
        if (!cred)
                cred = get_rpccred(NFS_I(inode)->mm_cred);
 
-       dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%Ld)\n",
-               inode->i_dev, (long long)NFS_FILEID(inode),
+       dprintk("NFS:      nfs_writepage_sync(%x:%x/%Ld %d@%Ld)\n",
+               major(inode->i_dev), minor(inode->i_dev),
+               (long long)NFS_FILEID(inode),
                count, (long long)(page_offset(page) + offset));
 
        buffer = kmap(page) + offset;
@@ -934,9 +935,9 @@ nfs_flush_one(struct list_head *head, struct inode *inode, int how)
        msg.rpc_resp = &data->res;
        msg.rpc_cred = data->cred;
 
-       dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
+       dprintk("NFS: %4d initiated write call (req %x:%x/%Ld count %d nriov %d)\n",
                task->tk_pid, 
-               inode->i_dev,
+               major(inode->i_dev), minor(inode->i_dev),
                (long long)NFS_FILEID(inode),
                data->args.count, data->args.nriov);
 
@@ -1049,8 +1050,9 @@ nfs_writeback_done(struct rpc_task *task)
 
                kunmap(page);
 
-               dprintk("NFS: write (%x/%Ld %d@%Ld)",
-                       req->wb_inode->i_dev,
+               dprintk("NFS: write (%x:%x/%Ld %d@%Ld)",
+                       major(req->wb_inode->i_dev),
+                       minor(req->wb_inode->i_dev),
                        (long long)NFS_FILEID(req->wb_inode),
                        req->wb_bytes,
                        (long long)(page_offset(page) + req->wb_offset));
index 4b5219a878393e0661d13518acf3cec381f8ff59..64977e9e4114bcd82d5b81c88a7b1e1095443871 100644 (file)
@@ -50,7 +50,7 @@ static int            exp_verify_string(char *cp, int max);
 #define CLIENT_HASH(a) \
                ((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
 /* XXX: is this adequate for 32bit kdev_t ? */
-#define EXPORT_HASH(dev)       ((dev) & (NFSCLNT_EXPMAX - 1))
+#define EXPORT_HASH(dev)       (minor(dev) & (NFSCLNT_EXPMAX - 1))
 
 struct svc_clnthash {
        struct svc_clnthash *   h_next;
@@ -76,7 +76,7 @@ exp_find(svc_client *clp, kdev_t dev)
        svc_export *    exp;
 
        exp = clp->cl_export[EXPORT_HASH(dev)];
-       while (exp && exp->ex_dev != dev)
+       while (exp && !kdev_same(exp->ex_dev, dev))
                exp = exp->ex_next;
        return exp;
 }
@@ -95,7 +95,7 @@ exp_get(svc_client *clp, kdev_t dev, ino_t ino)
        exp = clp->cl_export[EXPORT_HASH(dev)];
        if (exp)
                do {
-                       if (exp->ex_ino == ino && exp->ex_dev == dev)
+                       if (exp->ex_ino == ino && kdev_same(exp->ex_dev, dev))
                                goto out;
                } while (NULL != (exp = exp->ex_next));
        exp = NULL;
@@ -198,9 +198,10 @@ exp_export(struct nfsctl_export *nxp)
 
        inode = nd.dentry->d_inode;
        err = -EINVAL;
-       if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
-               printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
-                       inode->i_dev, dev); 
+       if (!kdev_same(inode->i_dev, dev) || inode->i_ino != nxp->ex_ino) {
+               printk(KERN_DEBUG "exp_export: i_dev = %02x:%02x, dev = %02x:%02x\n",
+                       major(inode->i_dev), minor(inode->i_dev),
+                       major(dev), minor(dev)); 
                /* I'm just being paranoid... */
                goto finish;
        }
@@ -302,7 +303,7 @@ exp_do_unexport(svc_export *unexp)
        dentry = unexp->ex_dentry;
        mnt = unexp->ex_mnt;
        inode = dentry->d_inode;
-       if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
+       if (!kdev_same(unexp->ex_dev, inode->i_dev) || unexp->ex_ino != inode->i_ino)
                printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
        dput(dentry);
        mntput(mnt);
@@ -353,9 +354,10 @@ exp_unexport(struct nfsctl_export *nxp)
        err = -EINVAL;
        clp = exp_getclientbyname(nxp->ex_client);
        if (clp) {
-               expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);
+               kdev_t ex_dev = to_kdev_t(nxp->ex_dev);
+               expp = clp->cl_export + EXPORT_HASH(ex_dev);
                while ((exp = *expp) != NULL) {
-                       if (exp->ex_dev == nxp->ex_dev) {
+                       if (kdev_same(exp->ex_dev, ex_dev)) {
                                if (exp->ex_ino == nxp->ex_ino) {
                                        *expp = exp->ex_next;
                                        exp_do_unexport(exp);
@@ -397,12 +399,13 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
                dev = nd.dentry->d_inode->i_dev;
                ino = nd.dentry->d_inode->i_ino;
        
-               dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
-                        path, nd.dentry, clp->cl_ident, dev, (long) ino);
+               dprintk("nfsd: exp_rootfh(%s [%p] %s:%02x:%02x/%ld)\n",
+                        path, nd.dentry, clp->cl_ident,
+                        major(dev), minor(dev), (long) ino);
                exp = exp_parent(clp, dev, nd.dentry);
        } else {
-               dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
-                        clp->cl_ident, dev, (long) ino);
+               dprintk("nfsd: exp_rootfh(%s:%02x:%02x/%ld)\n",
+                        clp->cl_ident, major(dev), minor(dev), (long) ino);
                if ((exp = exp_get(clp, dev, ino))) {
                        nd.mnt = mntget(exp->ex_mnt);
                        nd.dentry = dget(exp->ex_dentry);
@@ -418,11 +421,12 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
                printk("exp_rootfh: Aieee, NULL d_inode\n");
                goto out;
        }
-       if (inode->i_dev != dev || inode->i_ino != ino) {
+       if (!kdev_same(inode->i_dev, dev) || inode->i_ino != ino) {
                printk("exp_rootfh: Aieee, ino/dev mismatch\n");
-               printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
-                      " inode[dev(%x):ino(%ld)]\n",
-                      dev, (long) ino, inode->i_dev, (long) inode->i_ino);
+               printk("exp_rootfh: arg[dev(%02x:%02x):ino(%ld)]"
+                      " inode[dev(%02x:%02x):ino(%ld)]\n",
+                      major(dev), minor(dev), (long) ino,
+                      major(inode->i_dev), minor(inode->i_dev), (long) inode->i_ino);
        }
 
        /*
index 7e5dc7360d253f2efa84dac0af19bf945170cdd8..25c4288bf818df1b244160c6b0d06764bea7f5fd 100644 (file)
@@ -125,7 +125,7 @@ nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
        if (!(clp = exp_getclient(sin)))
                err = -EPERM;
        else
-               err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
+               err = exp_rootfh(clp, NODEV, 0, data->gd_path, res, data->gd_maxlen);
        exp_unlock();
        return err;
 }
@@ -148,7 +148,7 @@ nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res)
        if (!(clp = exp_getclient(sin)))
                err = -EPERM;
        else
-               err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE);
+               err = exp_rootfh(clp, NODEV, 0, data->gd_path, &fh, NFS_FHSIZE);
        exp_unlock();
 
        if (err == 0) {
index 417b4173c477ad1f79c77766226cb77a90c51567..952e012591a2cb836358f1d8858998677edfa074 100644 (file)
@@ -424,7 +424,8 @@ find_fh_dentry(struct super_block *sb, __u32 *datap, int len, int fhtype, int ne
        /* It's a directory, or we are required to confirm the file's
         * location in the tree.
         */
-       dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,datap[0]);
+       dprintk("nfs_fh: need to look harder for %02x:%02x/%d\n",
+               major(sb->s_dev), minor(sb->s_dev), datap[0]);
 
        if (!S_ISDIR(result->d_inode->i_mode)) {
                nfsdstats.fh_nocache_nondir++;
@@ -556,7 +557,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                        case 0:
                                if ((data_left-=2)<0) goto out;
                                nfsdev = ntohl(*datap++);
-                               xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
+                               xdev = mk_kdev(nfsdev>>16, nfsdev&0xFFFF);
                                xino = *datap++;
                                break;
                        default:
@@ -788,8 +789,8 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
        struct dentry *parent = dentry->d_parent;
        __u32 *datap;
 
-       dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
-               exp->ex_dev, (long) exp->ex_ino,
+       dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
+               major(exp->ex_dev), minor(exp->ex_dev), (long) exp->ex_ino,
                parent->d_name.name, dentry->d_name.name,
                (inode ? inode->i_ino : 0));
 
@@ -811,7 +812,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
                memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
                fhp->fh_handle.fh_size = NFS_FHSIZE;
                fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
-               fhp->fh_handle.ofh_dev =  htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+               fhp->fh_handle.ofh_dev =  htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
                fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
                fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino);
                fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
@@ -823,7 +824,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
                fhp->fh_handle.fh_fsid_type = 0;
                datap = fhp->fh_handle.fh_auth+0;
                /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
-               *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+               *datap++ = htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
                *datap++ = ino_t_to_u32(exp->ex_ino);
                fhp->fh_handle.fh_size = 3*4;
                if (inode) {
index c8ac22111c26d17f77d3ff88124ce25d1afdd140..8c4599d20d4b3af0d50e78856b31facb9338eb7b 100644 (file)
@@ -197,7 +197,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
        struct inode    *inode;
        struct dentry   *dchild;
        int             nfserr, type, mode;
-       dev_t           rdev = NODEV;
+       dev_t           rdev = 0;
 
        dprintk("nfsd: CREATE   %s %.*s\n",
                SVCFH_fmt(dirfhp), argp->len, argp->name);
@@ -255,7 +255,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                                case S_IFCHR:
                                case S_IFBLK:
                                        /* reserve rdev for later checking */
-                                       attr->ia_size = inode->i_rdev;
+                                       attr->ia_size = kdev_t_to_nr(inode->i_rdev);
                                        attr->ia_valid |= ATTR_SIZE;
 
                                        /* FALLTHROUGH */
@@ -313,7 +313,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                /* Make sure the type and device matches */
                nfserr = nfserr_exist;
                if (inode && (type != (inode->i_mode & S_IFMT) || 
-                   (is_borc && inode->i_rdev != rdev)))
+                   (is_borc && kdev_t_to_nr(inode->i_rdev) != rdev)))
                        goto out_unlock;
        }
        
index 0ee659ed43d853c25c4ee7cac0220e586b287e6e..d557f956fd3a34362f18fbc5d6156241566894e4 100644 (file)
@@ -149,11 +149,11 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
        }
        *p++ = htonl((u32) inode->i_blksize);
        if (S_ISCHR(type) || S_ISBLK(type))
-               *p++ = htonl((u32) inode->i_rdev);
+               *p++ = htonl((u32) kdev_t_to_nr(inode->i_rdev));
        else
                *p++ = htonl(0xffffffff);
        *p++ = htonl((u32) inode->i_blocks);
-       *p++ = htonl((u32) inode->i_dev);
+       *p++ = htonl((u32) kdev_t_to_nr(inode->i_dev));
        *p++ = htonl((u32) inode->i_ino);
        *p++ = htonl((u32) inode->i_atime);
        *p++ = 0;
index 7d00745d89fd074581a5c902cb3eea594470ea26..61de7f971a5afbd4ad7ee19fe3f71210253bdb19 100644 (file)
@@ -66,7 +66,7 @@ struct raparms {
        struct raparms          *p_next;
        unsigned int            p_count;
        ino_t                   p_ino;
-       dev_t                   p_dev;
+       kdev_t                  p_dev;
        unsigned long           p_reada,
                                p_ramax,
                                p_raend,
@@ -543,13 +543,13 @@ nfsd_sync_dir(struct dentry *dp)
  * specified by (dev, ino).
  */
 static inline struct raparms *
-nfsd_get_raparms(dev_t dev, ino_t ino)
+nfsd_get_raparms(kdev_t dev, ino_t ino)
 {
        struct raparms  *ra, **rap, **frap = NULL;
        int depth = 0;
        
        for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
-               if (ra->p_ino == ino && ra->p_dev == dev)
+               if (ra->p_ino == ino && kdev_same(ra->p_dev, dev))
                        goto found;
                depth++;
                if (ra->p_count == 0)
@@ -730,7 +730,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
                 */
                if (EX_WGATHER(exp)) {
                        if (atomic_read(&inode->i_writecount) > 1
-                           || (last_ino == inode->i_ino && last_dev == inode->i_dev)) {
+                           || (last_ino == inode->i_ino && kdev_same(last_dev, inode->i_dev))) {
                                dprintk("nfsd: write defer %d\n", current->pid);
                                set_current_state(TASK_UNINTERRUPTIBLE);
                                schedule_timeout((HZ+99)/100);
@@ -1245,7 +1245,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        tdir = tdentry->d_inode;
 
        err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
-       if (fdir->i_dev != tdir->i_dev)
+       if (!kdev_same(fdir->i_dev, tdir->i_dev))
                goto out;
 
        err = nfserr_perm;
index 11a7b4a79625e901933466af582021d0fcb3c221..e01a3e461961762c0458e61f065f51d5f58cce63 100644 (file)
@@ -43,7 +43,7 @@ static inline int OK_id(char *s)
 int atari_partition (struct gendisk *hd, struct block_device *bdev,
                     unsigned long first_sector, int minor)
 {
-       int m_lim = minor + hd->max_p;
+       int m_lim = minor + (1 << hd->minor_shift);
        Sector sect;
        struct rootsector *rs;
        struct partition_info *pi;
index 66c4d7aff15a57da508e84d821b3beb104fad1eb..14b26548eb15671c93ec29376a791448ff28c592 100644 (file)
@@ -38,7 +38,8 @@
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
-static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = {
+static int (*check_part[])(struct gendisk *hd, struct block_device *bdev,
+                          unsigned long first_sect, int first_minor) = {
 #ifdef CONFIG_ACORN_PARTITION
        acorn_partition,
 #endif
@@ -227,26 +228,26 @@ static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor
        if (first_time)
                printk(KERN_INFO "Partition check:\n");
        first_time = 0;
-       first_sector = hd->part[MINOR(dev)].start_sect;
+       first_sector = hd->part[minor(dev)].start_sect;
 
        /*
         * This is a kludge to allow the partition check to be
         * skipped for specific drives (e.g. IDE CD-ROM drives)
         */
        if ((int)first_sector == -1) {
-               hd->part[MINOR(dev)].start_sect = 0;
+               hd->part[minor(dev)].start_sect = 0;
                return;
        }
 
        if (hd->de_arr)
-               de = hd->de_arr[MINOR(dev) >> hd->minor_shift];
+               de = hd->de_arr[minor(dev) >> hd->minor_shift];
        i = devfs_generate_path (de, buf, sizeof buf);
        if (i >= 0)
                printk(KERN_INFO " /dev/%s:", buf + i);
        else
-               printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
+               printk(KERN_INFO " %s:", disk_name(hd, minor(dev), buf));
        bdev = bdget(kdev_t_to_nr(dev));
-       bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9;
+       bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9;
        bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
        for (i = 0; check_part[i]; i++) {
                int res;
@@ -333,11 +334,12 @@ static void devfs_register_disc (struct gendisk *dev, int minor)
 void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
 {
 #ifdef CONFIG_DEVFS_FS
-       int part;
+       int part, max_p;
 
        if (!unregister)
                devfs_register_disc (dev, minor);
-       for (part = 1; part < dev->max_p; part++) {
+       max_p = (1 << dev->minor_shift);
+       for (part = 1; part < max_p; part++) {
                if ( unregister || (dev->part[part + minor].nr_sects < 1) ) {
                        devfs_unregister (dev->part[part + minor].de);
                        dev->part[part + minor].de = NULL;
@@ -381,10 +383,10 @@ void grok_partitions(kdev_t dev, long size)
                return;
 
        minors = 1 << g->minor_shift;
-       first_minor = MINOR(dev);
+       first_minor = minor(dev);
        if (first_minor & (minors-1)) {
                printk("grok_partitions: bad device 0x%02x:%02x\n",
-                      MAJOR(dev), first_minor);
+                      major(dev), first_minor);
                first_minor &= ~(minors-1);
        }
        end_minor = first_minor + minors;
@@ -404,7 +406,7 @@ void grok_partitions(kdev_t dev, long size)
                        g->sizes[i] = 0;
        }
        blk_size[g->major] = g->sizes;
-       check_partition(g, MKDEV(g->major, first_minor), 1 + first_minor);
+       check_partition(g, mk_kdev(g->major, first_minor), 1 + first_minor);
 
        /*
         * We need to set the sizes array before we will be able to access
@@ -450,8 +452,8 @@ int wipe_partitions(kdev_t dev)
                return -EINVAL;
 
        max_p = 1 << g->minor_shift;
-       major = MAJOR(dev);
-       minor = MINOR(dev);
+       major = major(dev);
+       minor = minor(dev);
        minor0 = minor & ~(max_p - 1);
        if (minor0 != minor)            /* for now only whole-disk reread */
                return -EINVAL;         /* %%% later.. */
@@ -459,7 +461,7 @@ int wipe_partitions(kdev_t dev)
        /* invalidate stuff */
        for (p = max_p - 1; p >= 0; p--) {
                minor = minor0 + p;
-               devp = MKDEV(major,minor);
+               devp = mk_kdev(major,minor);
 #if 0                                  /* %%% superfluous? */
                if (g->part[minor].nr_sects == 0)
                        continue;
index 5be5492c5e9a0160dcccc18c7f32fa4b303e6d17..c25745603e640312ec9af5e4b74fb329830bd479 100644 (file)
@@ -555,7 +555,7 @@ static int proc_pid_maps_get_line (char *buf, struct vm_area_struct *map)
        str[3] = flags & VM_MAYSHARE ? 's' : 'p';
        str[4] = 0;
 
-       dev = 0;
+       dev = NODEV;
        ino = 0;
        if (map->vm_file != NULL) {
                dev = map->vm_file->f_dentry->d_inode->i_dev;
index 933d484c1a71fb9adece7a5a9faef294b67ad094..fd59a186c3bf9989a0b86466e2266cd531e37b57 100644 (file)
@@ -418,7 +418,7 @@ static inline struct super_block * find_super(kdev_t dev)
 
        list_for_each(p, &super_blocks) {
                struct super_block * s = sb_entry(p);
-               if (s->s_dev == dev) {
+               if (kdev_same(s->s_dev, dev)) {
                        s->s_count++;
                        return s;
                }
@@ -450,7 +450,7 @@ void sync_supers(kdev_t dev)
 {
        struct super_block * sb;
 
-       if (dev) {
+       if (!kdev_none(dev)) {
                sb = get_super(dev);
                if (sb) {
                        if (sb->s_dirt)
@@ -487,7 +487,7 @@ struct super_block * get_super(kdev_t dev)
 {
        struct super_block * s;
 
-       if (!dev)
+       if (kdev_none(dev))
                return NULL;
 
        while (1) {
@@ -540,7 +540,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data)
 {
        int retval;
        
-       if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
+       if (!(flags & MS_RDONLY) && !kdev_none(sb->s_dev) && is_read_only(sb->s_dev))
                return -EACCES;
                /*flags |= MS_RDONLY;*/
        if (flags & MS_RDONLY)
@@ -578,7 +578,7 @@ static spinlock_t unnamed_dev_lock = SPIN_LOCK_UNLOCKED;/* protects the above */
 static void put_anon_dev(kdev_t dev)
 {
        spin_lock(&unnamed_dev_lock);
-       clear_bit(MINOR(dev), unnamed_dev_in_use);
+       clear_bit(minor(dev), unnamed_dev_in_use);
        spin_unlock(&unnamed_dev_lock);
 }
 
@@ -608,7 +608,7 @@ struct super_block *get_anon_super(struct file_system_type *type,
        int (*compare)(struct super_block *,void *), void *data)
 {
        struct super_block *s = alloc_super();
-       kdev_t dev;
+       int dev;
        struct list_head *p;
 
        if (!s)
@@ -637,7 +637,7 @@ retry:
                return old;
        }
 
-       s->s_dev = dev;
+       s->s_dev = mk_kdev(0, dev);
        insert_super(s, type);
        return s;
 }
@@ -699,7 +699,7 @@ restart:
 
        list_for_each(p, &super_blocks) {
                struct super_block *old = sb_entry(p);
-               if (old->s_dev != dev)
+               if (!kdev_same(old->s_dev, dev))
                        continue;
                if (old->s_type != fs_type ||
                    ((flags ^ old->s_flags) & MS_RDONLY)) {
index 384b2cc97d361ffbf7deb9ddfb3678000e91be97..2b8cebfa07ca43814da761cff8c798f82f7337e6 100644 (file)
@@ -106,14 +106,14 @@ extern inline struct request *elv_next_request(request_queue_t *q)
 
 #ifdef IDE_DRIVER
 
-#define DEVICE_NR(device)      (MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device)      (minor(device) >> PARTN_BITS)
 #define DEVICE_NAME "ide"
 
 #elif (MAJOR_NR == RAMDISK_MAJOR)
 
 /* ram disk */
 #define DEVICE_NAME "ramdisk"
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 #define DEVICE_NO_RANDOM
 
 #elif (MAJOR_NR == Z2RAM_MAJOR)
@@ -121,7 +121,7 @@ extern inline struct request *elv_next_request(request_queue_t *q)
 /* Zorro II Ram */
 #define DEVICE_NAME "Z2RAM"
 #define DEVICE_REQUEST do_z2_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == FLOPPY_MAJOR)
 
@@ -130,7 +130,7 @@ static void floppy_off(unsigned int nr);
 #define DEVICE_NAME "floppy"
 #define DEVICE_INTR do_floppy
 #define DEVICE_REQUEST do_fd_request
-#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 ))
+#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 ))
 #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
 
 #elif (MAJOR_NR == HD_MAJOR)
@@ -140,188 +140,188 @@ static void floppy_off(unsigned int nr);
 #define DEVICE_INTR do_hd
 #define TIMEOUT_VALUE (6*HZ)
 #define DEVICE_REQUEST do_hd_request
-#define DEVICE_NR(device) (MINOR(device)>>6)
+#define DEVICE_NR(device) (minor(device)>>6)
 
 #elif (SCSI_DISK_MAJOR(MAJOR_NR))
 
 #define DEVICE_NAME "scsidisk"
 #define TIMEOUT_VALUE (2*HZ)
-#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
+#define DEVICE_NR(device) (((major(device) & SD_MAJOR_MASK) << (8 - 4)) + (minor(device) >> 4))
 
 /* Kludge to use the same number for both char and block major numbers */
 #elif  (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)
 
 #define DEVICE_NAME "Multiple devices driver"
 #define DEVICE_REQUEST do_md_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == SCSI_TAPE_MAJOR)
 
 #define DEVICE_NAME "scsitape"
 #define DEVICE_INTR do_st  
-#define DEVICE_NR(device) (MINOR(device) & 0x7f)
+#define DEVICE_NR(device) (minor(device) & 0x7f)
 
 #elif (MAJOR_NR == OSST_MAJOR)
 
 #define DEVICE_NAME "onstream" 
 #define DEVICE_INTR do_osst
-#define DEVICE_NR(device) (MINOR(device) & 0x7f) 
+#define DEVICE_NR(device) (minor(device) & 0x7f) 
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device) 
 
 #elif (MAJOR_NR == SCSI_CDROM_MAJOR)
 
 #define DEVICE_NAME "CD-ROM"
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == XT_DISK_MAJOR)
 
 #define DEVICE_NAME "xt disk"
 #define DEVICE_REQUEST do_xd_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == PS2ESDI_MAJOR)
 
 #define DEVICE_NAME "PS/2 ESDI"
 #define DEVICE_REQUEST do_ps2esdi_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
 
 #define DEVICE_NAME "CDU31A"
 #define DEVICE_REQUEST do_cdu31a_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE))
 
 #define DEVICE_NAME "ACSI"
 #define DEVICE_INTR do_acsi
 #define DEVICE_REQUEST do_acsi_request
-#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_NR(device) (minor(device) >> 4)
 
 #elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
 
 #define DEVICE_NAME "Mitsumi CD-ROM"
 /* #define DEVICE_INTR do_mcd */
 #define DEVICE_REQUEST do_mcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR)
 
 #define DEVICE_NAME "Mitsumi CD-ROM"
 /* #define DEVICE_INTR do_mcdx */
 #define DEVICE_REQUEST do_mcdx_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #1"
 #define DEVICE_REQUEST do_sbpcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #2"
 #define DEVICE_REQUEST do_sbpcd2_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #3"
 #define DEVICE_REQUEST do_sbpcd3_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #4"
 #define DEVICE_REQUEST do_sbpcd4_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == AZTECH_CDROM_MAJOR)
 
 #define DEVICE_NAME "Aztech CD-ROM"
 #define DEVICE_REQUEST do_aztcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == CDU535_CDROM_MAJOR)
 
 #define DEVICE_NAME "SONY-CDU535"
 #define DEVICE_INTR do_cdu535
 #define DEVICE_REQUEST do_cdu535_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR)
 
 #define DEVICE_NAME "Goldstar R420"
 #define DEVICE_REQUEST do_gscd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == CM206_CDROM_MAJOR)
 #define DEVICE_NAME "Philips/LMS CD-ROM cm206"
 #define DEVICE_REQUEST do_cm206_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == OPTICS_CDROM_MAJOR)
 
 #define DEVICE_NAME "DOLPHIN 8000AT CD-ROM"
 #define DEVICE_REQUEST do_optcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == SANYO_CDROM_MAJOR)
 
 #define DEVICE_NAME "Sanyo H94A CD-ROM"
 #define DEVICE_REQUEST do_sjcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == APBLOCK_MAJOR)
 
 #define DEVICE_NAME "apblock"
 #define DEVICE_REQUEST ap_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == DDV_MAJOR)
 
 #define DEVICE_NAME "ddv"
 #define DEVICE_REQUEST ddv_request
-#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS)
+#define DEVICE_NR(device) (minor(device)>>PARTN_BITS)
 
 #elif (MAJOR_NR == MFM_ACORN_MAJOR)
 
 #define DEVICE_NAME "mfm disk"
 #define DEVICE_INTR do_mfm
 #define DEVICE_REQUEST do_mfm_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == NBD_MAJOR)
 
 #define DEVICE_NAME "nbd"
 #define DEVICE_REQUEST do_nbd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MDISK_MAJOR)
 
 #define DEVICE_NAME "mdisk"
 #define DEVICE_REQUEST mdisk_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == DASD_MAJOR)
 
 #define DEVICE_NAME "dasd"
 #define DEVICE_REQUEST do_dasd_request
-#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device) (minor(device) >> PARTN_BITS)
 
 #elif (MAJOR_NR == I2O_MAJOR)
 
 #define DEVICE_NAME "I2O block"
 #define DEVICE_REQUEST i2ob_request
-#define DEVICE_NR(device) (MINOR(device)>>4)
+#define DEVICE_NR(device) (minor(device)>>4)
 
 #elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
 
 #define DEVICE_NAME "ida"
 #define TIMEOUT_VALUE (25*HZ)
 #define DEVICE_REQUEST do_ida_request
-#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_NR(device) (minor(device) >> 4)
 
 #endif /* MAJOR_NR == whatever */
 
@@ -375,7 +375,7 @@ static void (DEVICE_REQUEST)(request_queue_t *);
                CLEAR_INTR;                                     \
                return;                                         \
        }                                                       \
-       if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)                 \
+       if (major(CURRENT->rq_dev) != MAJOR_NR)                         \
                panic(DEVICE_NAME ": request list destroyed");  \
        if (!CURRENT->bio)                                      \
                panic(DEVICE_NAME ": no bio");                  \
@@ -395,7 +395,7 @@ static inline void end_request(int uptodate)
                return;
 
 #ifndef DEVICE_NO_RANDOM
-       add_blkdev_randomness(MAJOR(req->rq_dev));
+       add_blkdev_randomness(major(req->rq_dev));
 #endif
        DEVICE_OFF(req->rq_dev);
        blkdev_dequeue_request(req);
index d084e28ef4b930735bb282a427deb84d26d1acf2..8c3033d1dd688c59b04caba56ea491f7c8bb93ae 100644 (file)
@@ -371,10 +371,10 @@ extern inline unsigned int blksize_bits(unsigned int size)
 extern inline unsigned int block_size(kdev_t dev)
 {
        int retval = BLOCK_SIZE;
-       int major = MAJOR(dev);
+       int major = major(dev);
 
        if (blksize_size[major]) {
-               int minor = MINOR(dev);
+               int minor = minor(dev);
                if (blksize_size[major][minor])
                        retval = blksize_size[major][minor];
        }
index 3329b21a20dd3ed71b2f81f569d0d585e37d843c..b3a349fc341d8b8a02e97cb428c41a3c6f979f71 100644 (file)
@@ -792,7 +792,7 @@ static inline void devfs_plain_cdrom(struct cdrom_device_info *cdi,
 
        sprintf (vname, "cdroms/cdrom%d", cdi->number);
        cdi->de = devfs_register (NULL, vname, DEVFS_FL_DEFAULT,
-                                   MAJOR (cdi->dev), MINOR (cdi->dev),
+                                   major(cdi->dev), minor(cdi->dev),
                                    S_IFBLK | S_IRUGO | S_IWUGO,
                                    ops, NULL);
 }
index 8d46053267d0e600ad7526a918c0401add6d908d..7964e1490e8dab74677fa51563afde256c2d78ee 100644 (file)
@@ -311,7 +311,6 @@ extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long
 #include <linux/udf_fs_i.h>
 #include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
-#include <linux/usbdev_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
 
@@ -502,7 +501,6 @@ struct inode {
                struct ncp_inode_info           ncpfs_i;
                struct proc_inode_info          proc_i;
                struct socket                   socket_i;
-               struct usbdev_inode_info        usbdev_i;
                struct jffs2_inode_info         jffs2_i;
                void                            *generic_ip;
        } u;
@@ -686,7 +684,6 @@ struct quota_mount_options
 #include <linux/bfs_fs_sb.h>
 #include <linux/udf_fs_sb.h>
 #include <linux/ncp_fs_sb.h>
-#include <linux/usbdev_fs_sb.h>
 #include <linux/cramfs_fs_sb.h>
 #include <linux/jffs2_fs_sb.h>
 
@@ -744,7 +741,6 @@ struct super_block {
                struct bfs_sb_info      bfs_sb;
                struct udf_sb_info      udf_sb;
                struct ncp_sb_info      ncpfs_sb;
-               struct usbdev_sb_info   usbdevfs_sb;
                struct jffs2_sb_info    jffs2_sb;
                struct cramfs_sb_info   cramfs_sb;
                void                    *generic_sbp;
index 18f8d66ebe91361a2216b31896b22005e54d966d..18c981dafbf3f8cc79bb55980946997557ea826f 100644 (file)
@@ -71,13 +71,11 @@ struct gendisk {
        const char *major_name;         /* name of major driver */
        int minor_shift;                /* number of times minor is shifted to
                                           get real minor */
-       int max_p;                      /* maximum partitions per device */
 
        struct hd_struct *part;         /* [indexed by minor] */
        int *sizes;                     /* [idem], device size in blocks */
        int nr_real;                    /* number of real devices */
 
-       void *real_devices;             /* internal use */
        struct gendisk *next;
        struct block_device_operations *fops;
 
@@ -247,7 +245,7 @@ extern void devfs_register_partitions (struct gendisk *dev, int minor,
 static inline unsigned int disk_index (kdev_t dev)
 {
        struct gendisk *g = get_gendisk(dev);
-       return g ? (MINOR(dev) >> g->minor_shift) : 0;
+       return g ? (minor(dev) >> g->minor_shift) : 0;
 }
 
 #endif
index 5bcdab80f3f7ae31e4c68e4c9a1b4c02234803e4..e76cd83d297b6ba209b229d82a53f9ef9d997c7b 100644 (file)
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to four IDE interfaces, on one or more IRQs (usually 14, 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
- * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
- * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
- * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
- * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
+ * Primary i/f:    ide0: major=3;  (hda) minor=0; (hdb) minor=64
+ * Secondary i/f:  ide1: major=22; (hdc) minor=0; (hdd) minor=64
+ * Tertiary i/f:   ide2: major=33; (hde) minor=0; (hdf) minor=64
+ * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64
  */
 
 /******************************************************************************
index 7ef189ef0e6f5ca7c735b3f37c67e471567c6943..f9e74fd52f96e3af2c3eadc7f1a433db6cc7959c 100644 (file)
@@ -57,48 +57,84 @@ when some module is inserted).
 aeb - 950811
 */
 
-/* Since MINOR(dev) is used as index in static arrays,
-   the kernel is not quite ready yet for larger minors.
-   However, everything runs fine with an arbitrary kdev_t type. */
 
+/*
+ * NOTE NOTE NOTE!
+ *
+ * The kernel-internal "kdev_t" will eventually have
+ * 20 bits for minor numbers, and 12 bits for majors.
+ *
+ * HOWEVER, the external representation is still 8+8
+ * bits, and there is no way to generate the extended
+ * "kdev_t" format yet. Which is just as well, since
+ * we still use "minor" as an index into various
+ * static arrays, and they are sized for a 8-bit index.
+ */
+typedef struct {
+       unsigned short value;
+} kdev_t;
+
+#define KDEV_MINOR_BITS                8
+#define KDEV_MAJOR_BITS                8
+
+#define __mkdev(major,minor)   (((major) << KDEV_MINOR_BITS) + (minor))
+
+#define mk_kdev(major, minor)  ((kdev_t) { __mkdev(major,minor) } )
+
+/*
+ * The "values" are just _cookies_, usable for 
+ * internal equality comparisons and for things
+ * like NFS filehandle conversion.
+ */
+static inline unsigned int kdev_val(kdev_t dev)
+{
+       return dev.value;
+}
+
+static inline kdev_t val_to_kdev(unsigned int val)
+{
+       kdev_t dev;
+       dev.value = val;
+       return dev;
+}
+
+#define HASHDEV(dev)   (kdev_val(dev))
+#define NODEV          (mk_kdev(0,0))
+#define B_FREE         (mk_kdev(0xff,0xff))
+
+extern const char * kdevname(kdev_t);  /* note: returns pointer to static data! */
+
+static inline int kdev_same(kdev_t dev1, kdev_t dev2)
+{
+       return dev1.value == dev2.value;
+}
+
+#define kdev_none(d1)  (!kdev_val(d1))
+
+/* Mask off the high bits for now.. */
+#define minor(dev)     ((dev).value & 0xff)
+#define major(dev)     (((dev).value >> KDEV_MINOR_BITS) & 0xff)
+
+/* These are for user-level "dev_t" */
 #define MINORBITS      8
 #define MINORMASK      ((1U << MINORBITS) - 1)
 
-typedef unsigned short kdev_t;
-
 #define MAJOR(dev)     ((unsigned int) ((dev) >> MINORBITS))
 #define MINOR(dev)     ((unsigned int) ((dev) & MINORMASK))
-#define HASHDEV(dev)   ((unsigned int) (dev))
-#define NODEV          0
 #define MKDEV(ma,mi)   (((ma) << MINORBITS) | (mi))
-#define B_FREE         0xffff          /* yuk */
-
-extern const char * kdevname(kdev_t);  /* note: returns pointer to static data! */
 
 /*
-As long as device numbers in the outside world have 16 bits only,
-we use these conversions.
-*/
+ * Conversion functions
+ */
 
-static inline unsigned int kdev_t_to_nr(kdev_t dev) {
-       return (MAJOR(dev)<<8) | MINOR(dev);
+static inline int kdev_t_to_nr(kdev_t dev)
+{
+       return MKDEV(major(dev), minor(dev));
 }
 
 static inline kdev_t to_kdev_t(int dev)
 {
-       int major, minor;
-#if 0
-       major = (dev >> 16);
-       if (!major) {
-               major = (dev >> 8);
-               minor = (dev & 0xff);
-       } else
-               minor = (dev & 0xffff);
-#else
-       major = (dev >> 8);
-       minor = (dev & 0xff);
-#endif
-       return MKDEV(major, minor);
+       return mk_kdev(MAJOR(dev),MINOR(dev));
 }
 
 #else /* __KERNEL__ || _LVM_H_INCLUDE */
index 11ffdacdadf8af29d29c35a8c6a77f31b0de5060..84c72958f99b4394d288c9a07939cc2a727abe03 100644 (file)
@@ -119,15 +119,37 @@ struct knfsd_fh {
 
 /*
  * Conversion macros for the filehandle fields.
+ *
+ * Keep the device numbers in "backwards compatible
+ * format", ie the low 16 bits contain the low 8 bits
+ * of the 20-bit minor and the 12-bit major number.
+ *
+ * The high 16 bits contain the rest (4 bits major
+ * and 12 bits minor),
  */
 static inline __u32 kdev_t_to_u32(kdev_t dev)
 {
-       return (__u32) dev;
+       unsigned int minor = minor(dev);
+       unsigned int major = major(dev);
+       __u32 udev;
+
+       /* Create the low 16 bits.. */
+       udev = ((major & 0xff) << 8) + (minor & 0xff);
+
+       /* ..and then the rest. */
+       major >>= 8; minor >>= 8;
+       udev |= (major << 28) | (minor << 16);
+
+       return udev;
 }
 
 static inline kdev_t u32_to_kdev_t(__u32 udev)
 {
-       return (kdev_t) udev;
+       unsigned int minor, major;
+
+       minor = (udev & 0xff) | ((udev >> 8) & 0xfff00);
+       major = ((udev >> 8) & 0xff) | ((udev >> 20) & 0xf00);
+       return mk_kdev(major, minor);
 }
 
 static inline __u32 ino_t_to_u32(ino_t ino)
index d9b7870f363d4353ad9a651cf78d76f7f6b26a20..c0c21e26f2c3a50522ac838c4e1a0e8d59aad6f3 100644 (file)
@@ -77,9 +77,9 @@ extern dev_mapping_t mddev_map [MAX_MD_DEVS];
 
 static inline mddev_t * kdev_to_mddev (kdev_t dev)
 {
-       if (MAJOR(dev) != MD_MAJOR)
+       if (major(dev) != MD_MAJOR)
                BUG();
-        return mddev_map[MINOR(dev)].mddev;
+        return mddev_map[minor(dev)].mddev;
 }
 
 /*
@@ -256,7 +256,7 @@ static inline int mdidx (mddev_t * mddev)
 
 static inline kdev_t mddev_to_kdev(mddev_t * mddev)
 {
-       return MKDEV(MD_MAJOR, mdidx(mddev));
+       return mk_kdev(MD_MAJOR, mdidx(mddev));
 }
 
 extern mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev);
index 7af47915e3839b214e7f4fc7235dc30cf20694da..172e0918ec5ec400d8fc1af55c7deb517000c575 100644 (file)
@@ -521,7 +521,7 @@ struct usb_driver {
 
        struct semaphore serialize;
 
-       /* ioctl -- userspace apps can talk to drivers through usbdevfs */
+       /* ioctl -- userspace apps can talk to drivers through usbfs */
        int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
 
        /* support for "new-style" USB hotplugging */
@@ -567,7 +567,7 @@ typedef struct
        unsigned int length;            /* expected length */
        unsigned int actual_length;
        unsigned int status;
-} iso_packet_descriptor_t, *piso_packet_descriptor_t;
+} iso_packet_descriptor_t;
 
 struct urb;
 
@@ -629,7 +629,7 @@ typedef void (*usb_complete_t)(struct urb *);
  *
  * This structure identifies USB transfer requests.  URBs may be allocated
  * in any way, although usb_alloc_urb() is often convenient.  Initialization
- * may be done using various FILL_*_URB() macros.  URBs are submitted
+ * may be done using various usb_fill_*_urb() functions.  URBs are submitted
  * using usb_submit_urb(), and pending requests may be canceled using
  * usb_unlink_urb().
  *
@@ -729,87 +729,7 @@ struct urb
        iso_packet_descriptor_t iso_frame_desc[0];      /* (in) ISO ONLY */
 };
 
-typedef struct urb urb_t, *purb_t;
-
-/**
- * FILL_CONTROL_URB - macro to help initialize a control urb
- * @URB: pointer to the urb to initialize.
- * @DEV: pointer to the struct usb_device for this urb.
- * @PIPE: the endpoint pipe
- * @SETUP_PACKET: pointer to the setup_packet buffer
- * @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 control urb with the proper information needed to submit
- * it to a device.  This macro is depreciated, the usb_fill_control_urb()
- * function should be used instead.
- */
-#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
-    do {\
-       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;\
-    } while (0)
-
-/**
- * FILL_BULK_URB - macro to help initialize a bulk 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.
- *
- * Initializes a bulk urb with the proper information needed to submit it
- * to a device.  This macro is depreciated, the usb_fill_bulk_urb()
- * function should be used instead.
- */
-#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
-    do {\
-       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;\
-    } while (0)
-    
-/**
- * FILL_INT_URB - macro to help initialize a 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.
- *
- * Initializes a interrupt urb with the proper information needed to submit
- * it to a device.  This macro is depreciated, the usb_fill_int_urb()
- * function should be used instead.
- */
-#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \
-    do {\
-       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;\
-       (URB)->interval=INTERVAL;\
-       (URB)->start_frame=-1;\
-    } while (0)
+typedef struct urb urb_t;
 
 /**
  * usb_fill_control_urb - initializes a control urb
@@ -908,11 +828,22 @@ static inline void usb_fill_int_urb (struct urb *urb,
        urb->interval = interval;
        urb->start_frame = -1;
 }
-    
+
+/*
+ * old style macros to enable 2.4 and 2.2 drivers to build
+ * properly.  Please do not use these for new USB drivers.
+ */
+#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    usb_fill_control_urb(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT)
+#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    usb_fill_bulk_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT)
+#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \
+    usb_fill_int_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL)
+
 extern struct urb *usb_alloc_urb(int iso_packets);
-extern void usb_free_urb(struct urb *purb);
-extern int usb_submit_urb(struct urb *purb);
-extern int usb_unlink_urb(struct urb *purb);
+extern void usb_free_urb(struct urb *urb);
+extern int usb_submit_urb(struct urb *urb);
+extern int usb_unlink_urb(struct urb *urb);
 
 /*-------------------------------------------------------------------*
  *                         SYNCHRONOUS CALL SUPPORT                  *
@@ -959,8 +890,8 @@ struct usb_operations {
        int (*allocate)(struct usb_device *);
        int (*deallocate)(struct usb_device *);
        int (*get_frame_number) (struct usb_device *usb_dev);
-       int (*submit_urb) (struct urb* purb);
-       int (*unlink_urb) (struct urb* purb);
+       int (*submit_urb) (struct urb *urb);
+       int (*unlink_urb) (struct urb *urb);
 };
 
 #define DEVNUM_ROUND_ROBIN     /***** OPTION *****/
@@ -989,8 +920,7 @@ struct usb_bus {
        int bandwidth_int_reqs;         /* number of Interrupt requesters */
        int bandwidth_isoc_reqs;        /* number of Isoc. requesters */
 
-       /* usbdevfs inode list */
-       struct list_head inodes;
+       struct dentry *dentry;          /* usbfs dentry entry for the bus */
 
        atomic_t refcnt;
 };
@@ -1028,6 +958,21 @@ extern int usb_root_hub_string(int id, int serial,
 #define NS_TO_US(ns)   ((ns + 500L) / 1000L)
                        /* convert & round nanoseconds to microseconds */
 
+/*
+ * As of USB 2.0, full/low speed devices are segregated into trees.
+ * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
+ * The other type grows from high speed hubs when they connect to
+ * full/low speed devices using "Transaction Translators" (TTs).
+ *
+ * TTs should only be known to the hub driver, and high speed bus
+ * drivers (only EHCI for now).  They affect periodic scheduling and
+ * sometimes control/bulk error recovery.
+ */
+struct usb_tt {
+       struct usb_device       *hub;   /* upstream highspeed hub */
+       int                     multi;  /* true means one TT per port */
+};
+
 
 /* -------------------------------------------------------------------------- */
 
@@ -1056,7 +1001,8 @@ extern int usb_set_address(struct usb_device *dev);
 #define USB_MAXCHILDREN                (16)
 
 struct usb_device {
-       int devnum;                     /* Device number on USB bus */
+       int             devnum;         /* Address on USB bus */
+       char            devpath [16];   /* Use in messages: /port/port/... */
 
        enum {
                USB_SPEED_UNKNOWN = 0,                  /* enumerating */
@@ -1064,8 +1010,8 @@ struct usb_device {
                USB_SPEED_HIGH                          /* usb 2.0 */
        } speed;
 
-       struct usb_device *tt;          /* usb1.1 device on usb2.0 bus */
-       int ttport;                     /* device/hub port on that tt */
+       struct usb_tt   *tt;            /* low/full speed dev, highspeed hub */
+       int             ttport;         /* device port on that tt hub */
 
        atomic_t refcnt;                /* Reference count */
        struct semaphore serialize;
@@ -1090,9 +1036,8 @@ struct usb_device {
   
        void *hcpriv;                   /* Host Controller private data */
        
-        /* usbdevfs inode list */
-       struct list_head inodes;
        struct list_head filelist;
+       struct dentry *dentry;          /* usbfs dentry entry for the device */
 
        /*
         * Child devices - these can be either new devices
@@ -1254,7 +1199,7 @@ void usb_show_string(struct usb_device *dev, char *id, int index);
 
 /*
  * bus and driver list
- * exported only for usbdevfs (not visible outside usbcore)
+ * exported only for usbfs (not visible outside usbcore)
  */
 
 extern struct list_head usb_driver_list;
@@ -1271,23 +1216,25 @@ extern struct semaphore usb_bus_list_lock;
  * these are expected to be called from the USB core/hub thread
  * with the kernel lock held
  */
-extern void usbdevfs_add_bus(struct usb_bus *bus);
-extern void usbdevfs_remove_bus(struct usb_bus *bus);
-extern void usbdevfs_add_device(struct usb_device *dev);
-extern void usbdevfs_remove_device(struct usb_device *dev);
+extern void usbfs_add_bus(struct usb_bus *bus);
+extern void usbfs_remove_bus(struct usb_bus *bus);
+extern void usbfs_add_device(struct usb_device *dev);
+extern void usbfs_remove_device(struct usb_device *dev);
+extern void usbfs_update_special (void);
 
-extern int usbdevfs_init(void);
-extern void usbdevfs_cleanup(void);
+extern int usbfs_init(void);
+extern void usbfs_cleanup(void);
 
 #else /* CONFIG_USB_DEVICEFS */
 
-static inline void usbdevfs_add_bus(struct usb_bus *bus) {}
-static inline void usbdevfs_remove_bus(struct usb_bus *bus) {}
-static inline void usbdevfs_add_device(struct usb_device *dev) {}
-static inline void usbdevfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_add_bus(struct usb_bus *bus) {}
+static inline void usbfs_remove_bus(struct usb_bus *bus) {}
+static inline void usbfs_add_device(struct usb_device *dev) {}
+static inline void usbfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_update_special (void) {}
 
-static inline int usbdevfs_init(void) { return 0; }
-static inline void usbdevfs_cleanup(void) { }
+static inline int usbfs_init(void) { return 0; }
+static inline void usbfs_cleanup(void) { }
 
 #endif /* CONFIG_USB_DEVICEFS */
 
index fd8a34b4571d85aa86e045714ee429e32c08096a..69008e23610cafe4ee3b52c8cd3ac2710f8eb234 100644 (file)
@@ -150,17 +150,6 @@ struct usbdevfs_hub_portinfo {
 #include <linux/list.h>
 #include <asm/semaphore.h>
 
-/*
- * inode number macros
- */
-#define ITYPE(x)   ((x)&(0xf<<28))
-#define ISPECIAL   (0<<28)
-#define IBUS       (1<<28)
-#define IDEVICE    (2<<28)
-#define IBUSNR(x)  (((x)>>8)&0xff)
-#define IDEVNR(x)  ((x)&0xff)
-
-#define IROOT      1
 
 struct dev_state {
        struct list_head list;      /* state list */
index 9e20f7d795034b92a78d5c8849c94d1996649db6..925ea33ee3823cf74dda32d7229c2d4969b50c40 100644 (file)
@@ -1,5 +1,7 @@
 #define __KERNEL_SYSCALLS__
 #include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/unistd.h>
@@ -7,6 +9,7 @@
 #include <linux/blk.h>
 #include <linux/fd.h>
 #include <linux/tty.h>
+#include <linux/init.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
@@ -351,8 +354,8 @@ static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
        if (!do_devfs)
                return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev));
 
-       handle = devfs_find_handle(NULL, dev ? NULL : devfs_name,
-                               MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1);
+       handle = devfs_find_handle(NULL, kdev_none(dev) ? devfs_name : NULL,
+                               major(dev), minor(dev), DEVFS_SPECIAL_BLK, 1);
        if (!handle)
                return -1;
        n = devfs_generate_path(handle, path + 5, sizeof (path) - 5);
@@ -707,11 +710,11 @@ static void __init mount_root(void)
        devfs_make_root(root_device_name);
        create_dev("/dev/root", ROOT_DEV, root_device_name);
 #ifdef CONFIG_BLK_DEV_FD
-       if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+       if (major(ROOT_DEV) == FLOPPY_MAJOR) {
                /* rd_doload is 2 for a dual initrd/ramload setup */
                if (rd_doload==2) {
                        if (rd_load_disk(1)) {
-                               ROOT_DEV = MKDEV(RAMDISK_MAJOR, 1);
+                               ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 1);
                                create_dev("/dev/root", ROOT_DEV, NULL);
                        }
                } else
@@ -809,7 +812,7 @@ static int __init initrd_load(void)
  */
 void prepare_namespace(void)
 {
-       int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
+       int is_floppy = major(ROOT_DEV) == FLOPPY_MAJOR;
 #ifdef CONFIG_BLK_DEV_INITRD
        if (!initrd_start)
                mount_initrd = 0;
@@ -825,12 +828,12 @@ void prepare_namespace(void)
 
        create_dev("/dev/root", ROOT_DEV, NULL);
        if (mount_initrd) {
-               if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) {
+               if (initrd_load() && kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) {
                        handle_initrd();
                        goto out;
                }
        } else if (is_floppy && rd_doload && rd_load_disk(0))
-               ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+               ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0);
        mount_root();
 out:
        sys_umount("/dev", 0);
index 1de65396fee7c985a6b54efc401a615934adc606..29ff8ab914920859521d5c80de2b5c8489f7ec8a 100644 (file)
@@ -51,25 +51,16 @@ extern void mem_use(void);
  * NOTE! The unix "nice" value influences how long a process
  * gets. The nice value ranges from -20 to +19, where a -20
  * is a "high-priority" task, and a "+10" is a low-priority
- * task.
- *
- * We want the time-slice to be around 50ms or so, so this
- * calculation depends on the value of HZ.
+ * task. The default time slice for zero-nice tasks will be 43ms.
  */
-#if HZ < 200
-#define TICK_SCALE(x)  ((x) >> 2)
-#elif HZ < 400
-#define TICK_SCALE(x)  ((x) >> 1)
-#elif HZ < 800
-#define TICK_SCALE(x)  (x)
-#elif HZ < 1600
-#define TICK_SCALE(x)  ((x) << 1)
-#else
-#define TICK_SCALE(x)  ((x) << 2)
-#endif
+#define NICE_RANGE     40
+#define MIN_NICE_TSLICE        10000
+#define MAX_NICE_TSLICE        80000
+#define TASK_TIMESLICE(p)      ((int) ts_table[19 - (p)->nice])
 
-#define TASK_TIMESLICE(p)      (TICK_SCALE(20-(p)->nice)+1)
+static unsigned char ts_table[NICE_RANGE];
 
+#define MM_AFFINITY_BONUS      1
 
 /*
  *     Init task must be ok at boot for the ix86 as we will check its signals
@@ -181,7 +172,7 @@ static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struc
 
                /* .. and a slight advantage to the current MM */
                if (p->mm == this_mm || !p->mm)
-                       weight += 1;
+                       weight += MM_AFFINITY_BONUS;
                weight += 20 - p->nice;
                goto out;
        }
@@ -1328,6 +1319,15 @@ void __init init_idle(void)
 
 extern void init_timervecs (void);
 
+static void fill_tslice_map(void)
+{
+       int i;
+
+       for (i = 0; i < NICE_RANGE; i++)
+               ts_table[i] = ((MIN_NICE_TSLICE +
+                                               ((MAX_NICE_TSLICE - MIN_NICE_TSLICE) / NICE_RANGE) * i) * HZ) / 1000000;
+}
+
 void __init sched_init(void)
 {
        /*
@@ -1342,6 +1342,8 @@ void __init sched_init(void)
        for(nr = 0; nr < PIDHASH_SZ; nr++)
                pidhash[nr] = NULL;
 
+       fill_tslice_map();
+
        init_timervecs();
 
        init_bh(TIMER_BH, timer_bh);
index 0ae33bcc1a3d8dc05c2d2279f9b98fa4428ffe21..fa4140a6717b4391f9b266ad9dec6ab88dd9017f 100644 (file)
@@ -1132,9 +1132,9 @@ static void profile_readahead(int async, struct file *filp)
 
 static inline int get_max_readahead(struct inode * inode)
 {
-       if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)])
+       if (kdev_none(inode->i_dev) || !max_readahead[major(inode->i_dev)])
                return MAX_READAHEAD;
-       return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)];
+       return max_readahead[major(inode->i_dev)][minor(inode->i_dev)];
 }
 
 static void generic_file_readahead(int reada_ok,
index feb74055d0a2e6b04fdf448598165bfdb742a7cd..79700f304b18bf5ae802cf8e55b5ab50564b9738 100644 (file)
@@ -38,7 +38,7 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
        unsigned long offset;
        sector_t zones[PAGE_SIZE/512];
        int zones_used;
-       kdev_t dev = 0;
+       kdev_t dev = NODEV;
        int block_size;
        struct inode *swapf = 0;
 
@@ -49,7 +49,7 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
                kstat.pswpout++;
 
        get_swaphandle_info(entry, &offset, &dev, &swapf);
-       if (dev) {
+       if (!kdev_none(dev)) {
                zones[0] = offset;
                zones_used = 1;
                block_size = PAGE_SIZE;
index c620e0e9a4e1057dbc8b09854647e8ce7903161e..ff9a8e1f00ef5ce31d46af4c3cee5cd7cfa7d77b 100644 (file)
@@ -774,7 +774,7 @@ asmlinkage long sys_swapoff(const char * specialfile)
                swap_list_unlock();
                goto out_dput;
        }
-       if (p->swap_device)
+       if (!kdev_none(p->swap_device))
                blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
        path_release(&nd);
 
@@ -784,7 +784,7 @@ asmlinkage long sys_swapoff(const char * specialfile)
        nd.dentry = p->swap_file;
        p->swap_vfsmnt = NULL;
        p->swap_file = NULL;
-       p->swap_device = 0;
+       p->swap_device = NODEV;
        p->max = 0;
        swap_map = p->swap_map;
        p->swap_map = NULL;
@@ -826,7 +826,7 @@ int get_swaparea_info(char *buf)
                                }
                        len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
                                       path,
-                                      ptr->swap_device ? "partition" : "file\t",
+                                      kdev_none(ptr->swap_device) ? "file\t" : "partition",
                                       ptr->pages << (PAGE_SHIFT - 10),
                                       usedswap << (PAGE_SHIFT - 10),
                                       ptr->prio);
@@ -842,7 +842,7 @@ int is_swap_partition(kdev_t dev) {
 
        for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
                if (ptr->flags & SWP_USED)
-                       if (ptr->swap_device == dev)
+                       if (kdev_same(ptr->swap_device, dev))
                                return 1;
        }
        return 0;
@@ -888,7 +888,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
        p->flags = SWP_USED;
        p->swap_file = NULL;
        p->swap_vfsmnt = NULL;
-       p->swap_device = 0;
+       p->swap_device = NODEV;
        p->swap_map = NULL;
        p->lowest_bit = 0;
        p->highest_bit = 0;
@@ -931,12 +931,12 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
                        goto bad_swap_2;
                set_blocksize(dev, PAGE_SIZE);
                error = -ENODEV;
-               if (!dev || (blk_size[MAJOR(dev)] &&
-                    !blk_size[MAJOR(dev)][MINOR(dev)]))
+               if (kdev_none(dev) || (blk_size[major(dev)] &&
+                    !blk_size[major(dev)][minor(dev)]))
                        goto bad_swap;
                swapfilesize = 0;
-               if (blk_size[MAJOR(dev)])
-                       swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
+               if (blk_size[major(dev)])
+                       swapfilesize = blk_size[major(dev)][minor(dev)]
                                >> (PAGE_SHIFT - 10);
        } else if (S_ISREG(swap_inode->i_mode))
                swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
@@ -1092,7 +1092,7 @@ bad_swap_2:
        swap_map = p->swap_map;
        nd.mnt = p->swap_vfsmnt;
        nd.dentry = p->swap_file;
-       p->swap_device = 0;
+       p->swap_device = NODEV;
        p->swap_file = NULL;
        p->swap_vfsmnt = NULL;
        p->swap_map = NULL;
@@ -1245,7 +1245,7 @@ void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
                return;
        }
 
-       if (p->swap_device) {
+       if (!kdev_none(p->swap_device)) {
                *dev = p->swap_device;
        } else if (p->swap_file) {
                *swapf = p->swap_file->d_inode;