## Automatically generated incremental diff ## From: linux-2.5.2-pre5 ## To: linux-2.5.2-pre6 ## Robot: $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $ diff -urN linux-2.5.2-pre5/Makefile linux/Makefile --- linux-2.5.2-pre5/Makefile Tue Jan 1 14:04:24 2002 +++ linux/Makefile Tue Jan 1 14:04:27 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 2 -EXTRAVERSION =-pre5 +EXTRAVERSION =-pre6 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux-2.5.2-pre5/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c --- linux-2.5.2-pre5/arch/cris/drivers/usb-host.c Mon Oct 8 11:43:54 2001 +++ linux/arch/cris/drivers/usb-host.c Tue Jan 1 14:04:27 2002 @@ -196,7 +196,7 @@ 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 @@ }; #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) diff -urN linux-2.5.2-pre5/arch/i386/defconfig linux/arch/i386/defconfig --- linux-2.5.2-pre5/arch/i386/defconfig Sat Dec 8 20:30:25 2001 +++ linux/arch/i386/defconfig Tue Jan 1 14:04:27 2002 @@ -409,6 +409,7 @@ # 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_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 diff -urN linux-2.5.2-pre5/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c --- linux-2.5.2-pre5/drivers/acorn/block/mfmhd.c Thu Oct 25 13:58:35 2001 +++ linux/drivers/acorn/block/mfmhd.c Tue Jan 1 14:04:27 2002 @@ -1311,10 +1311,8 @@ 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 @@ 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--) { diff -urN linux-2.5.2-pre5/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- linux-2.5.2-pre5/drivers/block/DAC960.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/block/DAC960.c Tue Jan 1 14:04:27 2002 @@ -1973,9 +1973,7 @@ 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 @@ 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 @@ 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 @@ Controller->ControllerNumber, LogicalDriveNumber); Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives; - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); } if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount) { @@ -3173,7 +3170,7 @@ 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 @@ { memset(LogicalDeviceInfo, 0, sizeof(DAC960_V2_LogicalDeviceInfo_T)); - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); } } if (LogicalDeviceInfo != NULL) @@ -4630,7 +4627,7 @@ kfree(LogicalDeviceInfo); Controller->LogicalDriveInitiallyAccessible [LogicalDriveNumber] = false; - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); } Controller->V2.NeedLogicalDeviceInformation = false; } @@ -5299,7 +5296,7 @@ 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) diff -urN linux-2.5.2-pre5/drivers/block/acsi.c linux/drivers/block/acsi.c --- linux-2.5.2-pre5/drivers/block/acsi.c Sun Dec 16 12:20:20 2001 +++ linux/drivers/block/acsi.c Tue Jan 1 14:04:27 2002 @@ -1386,10 +1386,8 @@ 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, }; diff -urN linux-2.5.2-pre5/drivers/block/blkpg.c linux/drivers/block/blkpg.c --- linux-2.5.2-pre5/drivers/block/blkpg.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/block/blkpg.c Tue Jan 1 14:04:27 2002 @@ -85,14 +85,16 @@ 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 @@ 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 @@ 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 intval, *iptr; unsigned short usval; - if (!dev) + if (kdev_none(dev)) return -EINVAL; intval = block_ioctl(dev, cmd, arg); @@ -227,25 +232,25 @@ 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 @@ 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); diff -urN linux-2.5.2-pre5/drivers/block/cciss.c linux/drivers/block/cciss.c --- linux-2.5.2-pre5/drivers/block/cciss.c Sun Dec 16 12:20:20 2001 +++ linux/drivers/block/cciss.c Tue Jan 1 14:04:27 2002 @@ -1886,7 +1886,6 @@ 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; diff -urN linux-2.5.2-pre5/drivers/block/cciss.h linux/drivers/block/cciss.h --- linux-2.5.2-pre5/drivers/block/cciss.h Wed Dec 12 13:41:03 2001 +++ linux/drivers/block/cciss.h Tue Jan 1 14:04:27 2002 @@ -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 diff -urN linux-2.5.2-pre5/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- linux-2.5.2-pre5/drivers/block/cpqarray.c Sun Dec 16 12:20:20 2001 +++ linux/drivers/block/cpqarray.c Tue Jan 1 14:04:27 2002 @@ -483,7 +483,6 @@ 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; diff -urN linux-2.5.2-pre5/drivers/block/elevator.c linux/drivers/block/elevator.c --- linux-2.5.2-pre5/drivers/block/elevator.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/block/elevator.c Tue Jan 1 14:04:27 2002 @@ -70,7 +70,7 @@ * 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 @@ /* * 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; diff -urN linux-2.5.2-pre5/drivers/block/floppy.c linux/drivers/block/floppy.c --- linux-2.5.2-pre5/drivers/block/floppy.c Sun Dec 16 12:23:05 2001 +++ linux/drivers/block/floppy.c Tue Jan 1 14:04:27 2002 @@ -270,10 +270,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } - 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 @@ { 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 @@ 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 @@ if (fdc_state[FDC(drive)].version == FDC_NONE) continue; for (i = 0; inext) @@ -124,7 +124,7 @@ 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 @@ gp = get_gendisk(dev); if (gp) - return gp->part[MINOR(dev)].nr_sects; + return gp->part[minor(dev)].nr_sects; return 0; } diff -urN linux-2.5.2-pre5/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- linux-2.5.2-pre5/drivers/block/ll_rw_blk.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/block/ll_rw_blk.c Tue Jan 1 14:04:27 2002 @@ -109,12 +109,12 @@ **/ 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 @@ { 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 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 @@ { 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 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 @@ 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 @@ 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<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 @@ * */ 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 @@ 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); diff -urN linux-2.5.2-pre5/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c --- linux-2.5.2-pre5/drivers/block/paride/pd.c Sun Dec 16 15:38:31 2001 +++ linux/drivers/block/paride/pd.c Tue Jan 1 14:04:27 2002 @@ -347,7 +347,6 @@ major: PD_MAJOR, major_name: PD_NAME, minor_shift: PD_BITS, - max_p: PD_PARTNS, part: pd_hd, sizes: pd_sizes, fops: &pd_fops, diff -urN linux-2.5.2-pre5/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- linux-2.5.2-pre5/drivers/block/ps2esdi.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/block/ps2esdi.c Tue Jan 1 14:04:27 2002 @@ -160,10 +160,8 @@ 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, }; diff -urN linux-2.5.2-pre5/drivers/block/xd.c linux/drivers/block/xd.c --- linux-2.5.2-pre5/drivers/block/xd.c Sun Dec 16 12:20:20 2001 +++ linux/drivers/block/xd.c Tue Jan 1 14:04:27 2002 @@ -130,10 +130,8 @@ 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, }; diff -urN linux-2.5.2-pre5/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- linux-2.5.2-pre5/drivers/cdrom/cdrom.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/cdrom/cdrom.c Tue Jan 1 14:04:27 2002 @@ -337,7 +337,7 @@ 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 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 @@ 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 *cdi; cdi = topCdromPtr; - while (cdi != NULL && cdi->dev != dev) + while (cdi != NULL && !kdev_same(cdi->dev, dev)) cdi = cdi->next; return cdi; diff -urN linux-2.5.2-pre5/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c --- linux-2.5.2-pre5/drivers/char/agp/agpgart_fe.c Fri Nov 30 08:26:04 2001 +++ linux/drivers/char/agp/agpgart_fe.c Tue Jan 1 14:04:27 2002 @@ -694,7 +694,7 @@ 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; diff -urN linux-2.5.2-pre5/drivers/char/console.c linux/drivers/char/console.c --- linux-2.5.2-pre5/drivers/char/console.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/char/console.c Tue Jan 1 14:04:27 2002 @@ -2171,7 +2171,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } diff -urN linux-2.5.2-pre5/drivers/char/drm/drm_drv.h linux/drivers/char/drm/drm_drv.h --- linux-2.5.2-pre5/drivers/char/drm/drm_drv.h Sun Oct 21 10:40:36 2001 +++ linux/drivers/char/drm/drm_drv.h Tue Jan 1 14:04:27 2002 @@ -719,7 +719,7 @@ 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; } diff -urN linux-2.5.2-pre5/drivers/char/drm/drm_fops.h linux/drivers/char/drm/drm_fops.h --- linux-2.5.2-pre5/drivers/char/drm/drm_fops.h Sun Dec 16 15:43:58 2001 +++ linux/drivers/char/drm/drm_fops.h Tue Jan 1 14:04:27 2002 @@ -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 */ diff -urN linux-2.5.2-pre5/drivers/char/drm/drm_stub.h linux/drivers/char/drm/drm_stub.h --- linux-2.5.2-pre5/drivers/char/drm/drm_stub.h Sun Dec 16 15:43:58 2001 +++ linux/drivers/char/drm/drm_stub.h Tue Jan 1 14:04:27 2002 @@ -53,7 +53,7 @@ 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; diff -urN linux-2.5.2-pre5/drivers/char/mem.c linux/drivers/char/mem.c --- linux-2.5.2-pre5/drivers/char/mem.c Fri Sep 14 14:04:07 2001 +++ linux/drivers/char/mem.c Tue Jan 1 14:04:27 2002 @@ -538,7 +538,7 @@ 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; diff -urN linux-2.5.2-pre5/drivers/char/misc.c linux/drivers/char/misc.c --- linux-2.5.2-pre5/drivers/char/misc.c Fri Nov 2 17:46:47 2001 +++ linux/drivers/char/misc.c Tue Jan 1 14:04:27 2002 @@ -104,7 +104,7 @@ 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; diff -urN linux-2.5.2-pre5/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- linux-2.5.2-pre5/drivers/char/n_tty.c Fri Apr 6 10:42:55 2001 +++ linux/drivers/char/n_tty.c Tue Jan 1 14:04:28 2002 @@ -45,8 +45,8 @@ #include #include -#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 @@ /* 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 @@ /* 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; diff -urN linux-2.5.2-pre5/drivers/char/pty.c linux/drivers/char/pty.c --- linux-2.5.2-pre5/drivers/char/pty.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/char/pty.c Tue Jan 1 14:04:28 2002 @@ -88,14 +88,14 @@ 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 @@ #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 @@ 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 @@ 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; diff -urN linux-2.5.2-pre5/drivers/char/raw.c linux/drivers/char/raw.c --- linux-2.5.2-pre5/drivers/char/raw.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/char/raw.c Tue Jan 1 14:04:28 2002 @@ -74,7 +74,7 @@ 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 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 @@ * 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 @@ 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 @@ 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 @@ * 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 @@ 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)) diff -urN linux-2.5.2-pre5/drivers/char/serial.c linux/drivers/char/serial.c --- linux-2.5.2-pre5/drivers/char/serial.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/char/serial.c Tue Jan 1 14:04:28 2002 @@ -3141,7 +3141,7 @@ 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; diff -urN linux-2.5.2-pre5/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- linux-2.5.2-pre5/drivers/char/tty_io.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/char/tty_io.c Tue Jan 1 14:04:28 2002 @@ -102,10 +102,10 @@ #include -#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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ noctty = 1; } - if (device == PTMX_DEV) { + if (IS_PTMX_DEV(device)) { #ifdef CONFIG_UNIX98_PTYS /* find a free pty. */ @@ -1324,7 +1324,7 @@ 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 @@ 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 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 @@ { #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 @@ 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; diff -urN linux-2.5.2-pre5/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- linux-2.5.2-pre5/drivers/char/vc_screen.c Sun Sep 16 21:22:40 2001 +++ linux/drivers/char/vc_screen.c Tue Jan 1 14:04:28 2002 @@ -49,7 +49,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; diff -urN linux-2.5.2-pre5/drivers/ide/ataraid.c linux/drivers/ide/ataraid.c --- linux-2.5.2-pre5/drivers/ide/ataraid.c Thu Oct 25 13:58:35 2001 +++ linux/drivers/ide/ataraid.c Tue Jan 1 14:04:28 2002 @@ -269,7 +269,6 @@ 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; diff -urN linux-2.5.2-pre5/drivers/ide/hd.c linux/drivers/ide/hd.c --- linux-2.5.2-pre5/drivers/ide/hd.c Sun Dec 16 15:37:16 2001 +++ linux/drivers/ide/hd.c Tue Jan 1 14:04:28 2002 @@ -693,7 +693,6 @@ major: MAJOR_NR, major_name: "hd", minor_shift: 6, - max_p: 1 << 6, part: hd, sizes: hd_sizes, fops: &hd_fops, diff -urN linux-2.5.2-pre5/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- linux-2.5.2-pre5/drivers/ide/ide-cd.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/ide/ide-cd.c Tue Jan 1 14:04:28 2002 @@ -2015,7 +2015,7 @@ /* 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 @@ 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 @@ /* * 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 @@ 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 @@ 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 @@ * 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 diff -urN linux-2.5.2-pre5/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c --- linux-2.5.2-pre5/drivers/ide/ide-probe.c Sun Dec 16 12:20:20 2001 +++ linux/drivers/ide/ide-probe.c Tue Jan 1 14:04:28 2002 @@ -796,9 +796,7 @@ 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<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); diff -urN linux-2.5.2-pre5/drivers/ide/ide.c linux/drivers/ide/ide.c --- linux-2.5.2-pre5/drivers/ide/ide.c Sun Dec 16 12:21:02 2001 +++ linux/drivers/ide/ide.c Tue Jan 1 14:04:28 2002 @@ -580,7 +580,7 @@ } 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 @@ continue; if (drive->media!=ide_disk && drive->media!=ide_floppy) continue; - register_disk(gd,MKDEV(hwif->major,unit<major,unit<forced_geom && drive->noprobe) ? 1 : #endif /* CONFIG_BLK_DEV_ISAPNP */ @@ -1223,7 +1223,7 @@ { 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 @@ */ 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 @@ */ 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 @@ #endif rq->errors = 0; rq->rq_status = RQ_ACTIVE; - rq->rq_dev = MKDEV(major,(drive->select.b.unit)<rq_dev = mk_kdev(major,(drive->select.b.unit)<waiting = &wait; spin_lock_irqsave(&ide_lock, flags); @@ -1880,7 +1880,7 @@ { 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 @@ if (drive->revalidate) { drive->revalidate = 0; if (!initializing) - (void) ide_revalidate_disk(MKDEV(hwif->major, unit<major, unit<select.b.unit << PARTN_BITS; for (p = 0; p < (1<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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; diff -urN linux-2.5.2-pre5/drivers/md/lvm.c linux/drivers/md/lvm.c --- linux-2.5.2-pre5/drivers/md/lvm.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/md/lvm.c Tue Jan 1 14:04:28 2002 @@ -378,7 +378,6 @@ major: MAJOR_NR, major_name: LVM_NAME, minor_shift: 0, - max_p: 1, part: lvm_hd_struct, sizes: lvm_size, nr_real: MAX_LV, diff -urN linux-2.5.2-pre5/drivers/md/md.c linux/drivers/md/md.c --- linux-2.5.2-pre5/drivers/md/md.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/md/md.c Tue Jan 1 14:04:28 2002 @@ -118,11 +118,9 @@ 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, }; diff -urN linux-2.5.2-pre5/drivers/message/i2o/i2o_block.c linux/drivers/message/i2o/i2o_block.c --- linux-2.5.2-pre5/drivers/message/i2o/i2o_block.c Sun Dec 16 12:20:20 2001 +++ linux/drivers/message/i2o/i2o_block.c Tue Jan 1 14:04:28 2002 @@ -1778,7 +1778,6 @@ major: MAJOR_NR, major_name: "i2o/hd", minor_shift: 4, - max_p: 1<<4, part: i2ob, sizes: i2ob_sizes, nr_real: MAX_I2OB, diff -urN linux-2.5.2-pre5/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c --- linux-2.5.2-pre5/drivers/mtd/ftl.c Tue Nov 27 09:23:27 2001 +++ linux/drivers/mtd/ftl.c Tue Jan 1 14:04:28 2002 @@ -72,33 +72,12 @@ #include #include -#if (LINUX_VERSION_CODE >= 0x20100) #include -#endif -#if (LINUX_VERSION_CODE >= 0x20303) #include -#endif #include -/*====================================================================*/ -/* 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 @@ 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 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 @@ 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; } diff -urN linux-2.5.2-pre5/drivers/mtd/nftlcore.c linux/drivers/mtd/nftlcore.c --- linux-2.5.2-pre5/drivers/mtd/nftlcore.c Tue Nov 27 09:23:27 2001 +++ linux/drivers/mtd/nftlcore.c Tue Jan 1 14:04:28 2002 @@ -62,14 +62,9 @@ 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<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 @@ 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 @@ /* * 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 @@ } /* 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 @@ } /* 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 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 @@ } } - 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 @@ /* 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 @@ } /* 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 @@ /* * 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 @@ /* 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 @@ } /* 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 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 @@ } /* 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 @@ 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 @@ } /* 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 @@ 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 @@ 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 @@ * * 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 @@ 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 @@ 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 @@ /*------------------------------------------------------------------*/ /* - * 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 @@ } /* 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 @@ 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 @@ 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 @@ /* 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 @@ /* 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 */ diff -urN linux-2.5.2-pre5/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c --- linux-2.5.2-pre5/drivers/pcmcia/ds.c Fri Nov 30 08:26:04 2001 +++ linux/drivers/pcmcia/ds.c Tue Jan 1 14:04:28 2002 @@ -558,7 +558,7 @@ 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_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 @@ 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_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 @@ /* 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 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; diff -urN linux-2.5.2-pre5/drivers/s390/block/dasd_int.h linux/drivers/s390/block/dasd_int.h --- linux-2.5.2-pre5/drivers/s390/block/dasd_int.h Sun Sep 30 12:26:07 2001 +++ linux/drivers/s390/block/dasd_int.h Tue Jan 1 14:04:28 2002 @@ -88,7 +88,6 @@ 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 @@ 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 * diff -urN linux-2.5.2-pre5/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- linux-2.5.2-pre5/drivers/scsi/scsi_lib.c Sun Dec 16 12:20:21 2001 +++ linux/drivers/scsi/scsi_lib.c Tue Jan 1 14:04:28 2002 @@ -385,7 +385,7 @@ 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 *spnt; kdev_t dev = req->rq_dev; - int major = MAJOR(dev); + int major = major(dev); for (spnt = scsi_devicelist; spnt; spnt = spnt->next) { /* diff -urN linux-2.5.2-pre5/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c --- linux-2.5.2-pre5/drivers/scsi/scsicam.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/scsi/scsicam.c Tue Jan 1 14:04:28 2002 @@ -29,7 +29,7 @@ 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)); diff -urN linux-2.5.2-pre5/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- linux-2.5.2-pre5/drivers/scsi/sd.c Tue Jan 1 14:04:25 2002 +++ linux/drivers/scsi/sd.c Tue Jan 1 14:04:28 2002 @@ -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 @@ major: SCSI_DISK0_MAJOR, major_name: "sd", minor_shift: 4, - max_p: 1 << 4, fops: &sd_fops, }; @@ -1116,7 +1115,7 @@ } 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 @@ 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 @@ 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); diff -urN linux-2.5.2-pre5/drivers/scsi/sd.h linux/drivers/scsi/sd.h --- linux-2.5.2-pre5/drivers/scsi/sd.h Sun Dec 16 15:46:45 2001 +++ linux/drivers/scsi/sd.h Tue Jan 1 14:04:28 2002 @@ -45,7 +45,7 @@ #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 diff -urN linux-2.5.2-pre5/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- linux-2.5.2-pre5/drivers/scsi/wd7000.c Sun Sep 30 12:26:08 2001 +++ linux/drivers/scsi/wd7000.c Tue Jan 1 14:04:28 2002 @@ -140,6 +140,11 @@ * 03/01/1998 * * WD7000 driver now work on kernels >= 2.1.x + * + * + * 12/31/2001 - Arnaldo Carvalho de Melo + * + * use host->host_lock, not io_request_lock, cleanups */ #include @@ -166,6 +171,11 @@ #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 @@ -557,7 +567,7 @@ } Icb; #ifdef MODULE -static char * wd7000 = NULL; +static char *wd7000; MODULE_PARM(wd7000, "s"); #endif @@ -568,23 +578,23 @@ * 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 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=,,IO>[,[,]]\n"); + printk(KERN_ERR __FUNCTION__ ": Error in command line! " + "Usage: wd7000=,,IO>[," + "[,]]\n"); } else { for (i = 0; i < NUM_IRQS; i++) if (ints[1] == wd7000_irq[i]) @@ -652,7 +664,8 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ * 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 @@ 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 @@ } #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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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_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 @@ 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); } diff -urN linux-2.5.2-pre5/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- linux-2.5.2-pre5/drivers/sound/es1371.c Sun Sep 30 12:26:08 2001 +++ linux/drivers/sound/es1371.c Tue Jan 1 14:04:28 2002 @@ -1213,7 +1213,7 @@ 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_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_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 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; diff -urN linux-2.5.2-pre5/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- linux-2.5.2-pre5/drivers/sound/sound_core.c Sun Nov 25 10:17:47 2001 +++ linux/drivers/sound/sound_core.c Tue Jan 1 14:04:28 2002 @@ -478,7 +478,7 @@ 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; diff -urN linux-2.5.2-pre5/drivers/usb/audio.c linux/drivers/usb/audio.c --- linux-2.5.2-pre5/drivers/usb/audio.c Sat Dec 8 20:28:44 2001 +++ linux/drivers/usb/audio.c Tue Jan 1 14:04:28 2002 @@ -833,7 +833,7 @@ } } -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 @@ * 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 @@ /* * 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 @@ /* * 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 @@ { 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 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 @@ /* * 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 @@ 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 @@ /* * 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 @@ { 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; diff -urN linux-2.5.2-pre5/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c --- linux-2.5.2-pre5/drivers/usb/dabusb.c Fri Nov 30 08:26:04 2001 +++ linux/drivers/usb/dabusb.c Tue Jan 1 14:04:28 2002 @@ -83,24 +83,24 @@ } /*-------------------------------------------------------------------*/ #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 @@ 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 @@ int rem; int cnt; pbuff_t b; - purb_t purb = NULL; + struct urb *purb = NULL; dbg("dabusb_read"); diff -urN linux-2.5.2-pre5/drivers/usb/dabusb.h linux/drivers/usb/dabusb.h --- linux-2.5.2-pre5/drivers/usb/dabusb.h Tue Oct 3 09:24:40 2000 +++ linux/drivers/usb/dabusb.h Tue Jan 1 14:04:28 2002 @@ -38,7 +38,7 @@ typedef struct { pdabusb_t s; - purb_t purb; + struct urb *purb; struct list_head buff_list; } buff_t,*pbuff_t; diff -urN linux-2.5.2-pre5/drivers/usb/devio.c linux/drivers/usb/devio.c --- linux-2.5.2-pre5/drivers/usb/devio.c Sat Dec 8 20:28:44 2001 +++ linux/drivers/usb/devio.c Tue Jan 1 14:04:28 2002 @@ -245,7 +245,7 @@ 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 @@ */ 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 -urN linux-2.5.2-pre5/drivers/usb/hcd/Config.in linux/drivers/usb/hcd/Config.in --- linux-2.5.2-pre5/drivers/usb/hcd/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/Config.in Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hcd/Makefile linux/drivers/usb/hcd/Makefile --- linux-2.5.2-pre5/drivers/usb/hcd/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/Makefile Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-dbg.c linux/drivers/usb/hcd/ehci-dbg.c --- linux-2.5.2-pre5/drivers/usb/hcd/ehci-dbg.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/ehci-dbg.c Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c --- linux-2.5.2-pre5/drivers/usb/hcd/ehci-hcd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/ehci-hcd.c Tue Jan 1 14:04:28 2002 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_USB_DEBUG + #define CONFIG_USB_DEBUG /* this is still experimental! */ +#endif + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include "../hcd.h" + +#include +#include +#include +#include + +//#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 -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-hub.c linux/drivers/usb/hcd/ehci-hub.c --- linux-2.5.2-pre5/drivers/usb/hcd/ehci-hub.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/ehci-hub.c Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-mem.c linux/drivers/usb/hcd/ehci-mem.c --- linux-2.5.2-pre5/drivers/usb/hcd/ehci-mem.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/ehci-mem.c Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-q.c linux/drivers/usb/hcd/ehci-q.c --- linux-2.5.2-pre5/drivers/usb/hcd/ehci-q.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/ehci-q.c Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c --- linux-2.5.2-pre5/drivers/usb/hcd/ehci-sched.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/ehci-sched.c Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci.h linux/drivers/usb/hcd/ehci.h --- linux-2.5.2-pre5/drivers/usb/hcd/ehci.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd/ehci.h Tue Jan 1 14:04:28 2002 @@ -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 */ diff -urN linux-2.5.2-pre5/drivers/usb/hcd.c linux/drivers/usb/hcd.c --- linux-2.5.2-pre5/drivers/usb/hcd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd.c Tue Jan 1 14:04:28 2002 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 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 +#include "hcd.h" + +#include +#include +#include +#include + + +/*-------------------------------------------------------------------------*/ + +/* + * 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 -urN linux-2.5.2-pre5/drivers/usb/hcd.h linux/drivers/usb/hcd.h --- linux-2.5.2-pre5/drivers/usb/hcd.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hcd.h Tue Jan 1 14:04:28 2002 @@ -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 -urN linux-2.5.2-pre5/drivers/usb/hub.c linux/drivers/usb/hub.c --- linux-2.5.2-pre5/drivers/usb/hub.c Mon Nov 12 09:34:16 2001 +++ linux/drivers/usb/hub.c Tue Jan 1 14:04:28 2002 @@ -35,7 +35,7 @@ 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 @@ 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 @@ 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 @@ 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)); - /* 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 @@ 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 @@ } 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 @@ 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 @@ } /* 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 @@ 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 @@ 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 @@ } } - err("cannot disconnect hub %d", dev->devnum); + err("cannot disconnect hub %s", dev->devpath); } #define HUB_RESET_TRIES 5 @@ -510,14 +538,17 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 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 @@ 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 @@ 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; } } diff -urN linux-2.5.2-pre5/drivers/usb/hub.h linux/drivers/usb/hub.h --- linux-2.5.2-pre5/drivers/usb/hub.h Sun Dec 16 15:47:13 2001 +++ linux/drivers/usb/hub.h Tue Jan 1 14:04:28 2002 @@ -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 /* @@ -11,6 +18,15 @@ #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 @@ #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_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 */ diff -urN linux-2.5.2-pre5/drivers/usb/inode.c linux/drivers/usb/inode.c --- linux-2.5.2-pre5/drivers/usb/inode.c Sat Dec 8 20:28:44 2001 +++ linux/drivers/usb/inode.c Tue Jan 1 14:04:28 2002 @@ -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 @@ -20,10 +20,9 @@ * 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 */ /*****************************************************************************/ @@ -32,146 +31,40 @@ #include #include #include -#include -#include -#include +#include #include #include #include #include -#include - -/* --------------------------------------------------------------------- */ - -/* - * 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 @@ } } - 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 dentry *usbfs_lookup (struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +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 usb_bus *usbdevfs_findbus(int busnr) +static struct inode *usbfs_get_inode (struct super_block *sb, int mode, int dev) { - struct list_head *list; - struct usb_bus *bus; + struct inode *inode = new_inode(sb); - 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; + 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; + int error = -ENOTEMPTY; - /* 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; + 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 struct file_operations usbdevfs_root_file_operations = { - readdir: usbdevfs_root_readdir, +static int default_sync_file (struct file *file, struct dentry *dentry, + int datasync) +{ + return 0; +} + +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; +static struct super_operations usbfs_ops = { + statfs: usbfs_statfs, + put_inode: force_delete, +}; - 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_block *usbfs_read_super (struct super_block *sb, void *data, + int silent) +{ + struct inode *inode; + struct dentry *root; - case IDEVICE: - return; + if (parse_options(sb, data)) { + warn("usbfs: mount parameter error:"); + return NULL; + } - case IBUS: - 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); - default: - return; - } -} + if (!inode) { + dbg("%s: could not get inode!\n",__FUNCTION__); + return NULL; + } -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)); + 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_statfs(struct super_block *sb, struct statfs *buf) +/** + * 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) { - 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; -} + struct dentry *d = NULL; + struct qstr qstr; + int error; -static int usbdevfs_remount(struct super_block *s, int *flags, char *data) -{ - struct list_head *ilist = s->u.usbdevfs_sb.ilist.next; - struct inode *inode; - int ret; + /* 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, -}; - -struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent) +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 inode *root_inode, *inode; - struct list_head *blist; - struct usb_bus *bus; - unsigned int i; + struct dentry *dentry; + int error; - if (parse_options(s, data)) { - printk(KERN_WARNING "usbdevfs: mount parameter error\n"); - return NULL; + 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; + } } - /* 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); - } - up (&usb_bus_list_lock); - return s; - - out_no_root: - printk("usbdevfs_read_super: get root inode failed\n"); - iput(root_inode); - return NULL; + return dentry; } +static void fs_remove_file (struct dentry *dentry) +{ + struct dentry *parent = dentry->d_parent; + + if (!parent || !parent->d_inode) + return; + + 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); + } + + dput(dentry); + } + 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; -static void update_special_inodes (void) + 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 int create_special_files (void) +{ + 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) { - int i; - for (i = 0; i < NRSPECIAL; i++) { - struct inode *inode = special[i].inode; + 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]; - 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(); + 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; + + 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 @@ send_sig_info(ds->discsignr, &sinfo, ds->disctask); } } - - update_special_inodes(); - unlock_kernel(); + usbfs_update_special(); usbdevfs_conn_disc_event(); } @@ -744,39 +726,42 @@ 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 } diff -urN linux-2.5.2-pre5/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c --- linux-2.5.2-pre5/drivers/usb/mdc800.c Sat Dec 8 20:28:44 2001 +++ linux/drivers/usb/mdc800.c Tue Jan 1 14:04:28 2002 @@ -140,7 +140,7 @@ 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 @@ 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; diff -urN linux-2.5.2-pre5/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c --- linux-2.5.2-pre5/drivers/usb/pwc-if.c Mon Nov 26 17:09:10 2001 +++ linux/drivers/usb/pwc-if.c Tue Jan 1 14:04:28 2002 @@ -624,7 +624,7 @@ /* 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 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; diff -urN linux-2.5.2-pre5/drivers/usb/pwc.h linux/drivers/usb/pwc.h --- linux-2.5.2-pre5/drivers/usb/pwc.h Mon Nov 26 17:09:10 2001 +++ linux/drivers/usb/pwc.h Tue Jan 1 14:04:28 2002 @@ -96,7 +96,7 @@ void *data; int length; int read; - purb_t urb; + struct urb *urb; }; /* intermediate buffers with raw data from the USB cam */ diff -urN linux-2.5.2-pre5/drivers/usb/serial/ipaq.c linux/drivers/usb/serial/ipaq.c --- linux-2.5.2-pre5/drivers/usb/serial/ipaq.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/ipaq.c Tue Jan 1 14:04:28 2002 @@ -0,0 +1,525 @@ +/* + * USB Compaq iPAQ driver + * + * Copyright (C) 2001 + * Ganesh Varadarajan + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 " +#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 -urN linux-2.5.2-pre5/drivers/usb/serial/ipaq.h linux/drivers/usb/serial/ipaq.h --- linux-2.5.2-pre5/drivers/usb/serial/ipaq.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/ipaq.h Tue Jan 1 14:04:28 2002 @@ -0,0 +1,60 @@ +/* + * USB Compaq iPAQ driver + * + * Copyright (C) 2001 + * Ganesh Varadarajan + * + * 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 -urN linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.c linux/drivers/usb/serial/kl5kusb105.c --- linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/kl5kusb105.c Tue Jan 1 14:04:28 2002 @@ -0,0 +1,1086 @@ +/* + * KLSI KL5KUSB105 chip RS232 converter driver + * + * Copyright (C) 2001 Utz-Uwe Haus + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 " +#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; inum_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; iwrite_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; itermios.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; iwrite_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 -urN linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.h linux/drivers/usb/serial/kl5kusb105.h --- linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/kl5kusb105.h Tue Jan 1 14:04:28 2002 @@ -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: */ + diff -urN linux-2.5.2-pre5/drivers/usb/usb-debug.c linux/drivers/usb/usb-debug.c --- linux-2.5.2-pre5/drivers/usb/usb-debug.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/usb/usb-debug.c Tue Jan 1 14:04:28 2002 @@ -181,23 +181,23 @@ 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); } diff -urN linux-2.5.2-pre5/drivers/usb/usb.c linux/drivers/usb/usb.c --- linux-2.5.2-pre5/drivers/usb/usb.c Sat Dec 8 20:28:45 2001 +++ linux/drivers/usb/usb.c Tue Jan 1 14:04:28 2002 @@ -97,6 +97,8 @@ usb_scan_devices(); + usbfs_update_special(); + return 0; } @@ -192,6 +194,8 @@ usb_drivers_purge(driver, bus->root_hub); } up (&usb_bus_list_lock); + + usbfs_update_special(); } /** @@ -421,7 +425,6 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ /* 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 @@ #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 @@ 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 @@ { init_MUTEX(&usb_bus_list_lock); usb_major_init(); - usbdevfs_init(); + usbfs_init(); usb_hub_init(); return 0; @@ -2672,7 +2676,7 @@ static void __exit usb_exit(void) { usb_major_cleanup(); - usbdevfs_cleanup(); + usbfs_cleanup(); usb_hub_cleanup(); } diff -urN linux-2.5.2-pre5/fs/autofs4/inode.c linux/fs/autofs4/inode.c --- linux-2.5.2-pre5/fs/autofs4/inode.c Fri Nov 9 14:11:14 2001 +++ linux/fs/autofs4/inode.c Tue Jan 1 14:04:28 2002 @@ -308,7 +308,7 @@ } 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)) { diff -urN linux-2.5.2-pre5/fs/block_dev.c linux/fs/block_dev.c --- linux-2.5.2-pre5/fs/block_dev.c Tue Jan 1 14:04:25 2002 +++ linux/fs/block_dev.c Tue Jan 1 14:04:28 2002 @@ -27,10 +27,10 @@ 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 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 @@ 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 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 @@ 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 @@ 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; } diff -urN linux-2.5.2-pre5/fs/buffer.c linux/fs/buffer.c --- linux-2.5.2-pre5/fs/buffer.c Tue Jan 1 14:04:25 2002 +++ linux/fs/buffer.c Tue Jan 1 14:04:28 2002 @@ -203,7 +203,7 @@ 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 @@ __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 @@ 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 @@ asmlinkage long sys_sync(void) { - fsync_dev(0); + fsync_dev(NODEV); return 0; } @@ -571,7 +571,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ { lock_kernel(); sync_unlocked_inodes(); - sync_supers(0); + sync_supers(NODEV); unlock_kernel(); for (;;) { diff -urN linux-2.5.2-pre5/fs/devices.c linux/fs/devices.c --- linux-2.5.2-pre5/fs/devices.c Sat Sep 22 20:35:43 2001 +++ linux/fs/devices.c Tue Jan 1 14:04:28 2002 @@ -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 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 @@ 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; } diff -urN linux-2.5.2-pre5/fs/inode.c linux/fs/inode.c --- linux-2.5.2-pre5/fs/inode.c Mon Dec 10 14:13:25 2001 +++ linux/fs/inode.c Tue Jan 1 14:04:28 2002 @@ -382,7 +382,7 @@ /* * 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 @@ 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; diff -urN linux-2.5.2-pre5/fs/isofs/rock.c linux/fs/isofs/rock.c --- linux-2.5.2-pre5/fs/isofs/rock.c Sun Dec 16 12:23:05 2001 +++ linux/fs/isofs/rock.c Tue Jan 1 14:04:28 2002 @@ -297,9 +297,9 @@ * 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; diff -urN linux-2.5.2-pre5/fs/lockd/svclock.c linux/fs/lockd/svclock.c --- linux-2.5.2-pre5/fs/lockd/svclock.c Thu Oct 11 07:52:18 2001 +++ linux/fs/lockd/svclock.c Tue Jan 1 14:04:28 2002 @@ -306,8 +306,9 @@ 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 @@ { 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 @@ { 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 @@ { 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, diff -urN linux-2.5.2-pre5/fs/namei.c linux/fs/namei.c --- linux-2.5.2-pre5/fs/namei.c Fri Nov 30 08:41:52 2001 +++ linux/fs/namei.c Tue Jan 1 14:04:29 2002 @@ -1589,7 +1589,7 @@ 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 @@ 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 @@ 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) diff -urN linux-2.5.2-pre5/fs/nfs/dir.c linux/fs/nfs/dir.c --- linux-2.5.2-pre5/fs/nfs/dir.c Tue Jun 12 11:15:08 2001 +++ linux/fs/nfs/dir.c Tue Jan 1 14:04:29 2002 @@ -643,8 +643,8 @@ 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 @@ 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 @@ 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 @@ { 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 @@ { 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 @@ 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; diff -urN linux-2.5.2-pre5/fs/nfs/file.c linux/fs/nfs/file.c --- linux-2.5.2-pre5/fs/nfs/file.c Tue Jan 1 14:04:25 2002 +++ linux/fs/nfs/file.c Tue Jan 1 14:04:29 2002 @@ -73,7 +73,8 @@ 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 @@ 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 @@ 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); diff -urN linux-2.5.2-pre5/fs/nfs/inode.c linux/fs/nfs/inode.c --- linux-2.5.2-pre5/fs/nfs/inode.c Tue Jan 1 14:04:25 2002 +++ linux/fs/nfs/inode.c Tue Jan 1 14:04:29 2002 @@ -104,7 +104,7 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); diff -urN linux-2.5.2-pre5/fs/nfs/read.c linux/fs/nfs/read.c --- linux-2.5.2-pre5/fs/nfs/read.c Tue Jan 1 14:04:25 2002 +++ linux/fs/nfs/read.c Tue Jan 1 14:04:29 2002 @@ -108,9 +108,10 @@ 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 @@ 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 @@ 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)); diff -urN linux-2.5.2-pre5/fs/nfs/write.c linux/fs/nfs/write.c --- linux-2.5.2-pre5/fs/nfs/write.c Tue Jan 1 14:04:25 2002 +++ linux/fs/nfs/write.c Tue Jan 1 14:04:29 2002 @@ -159,8 +159,9 @@ 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 @@ 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 @@ 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)); diff -urN linux-2.5.2-pre5/fs/nfsd/export.c linux/fs/nfsd/export.c --- linux-2.5.2-pre5/fs/nfsd/export.c Tue Jan 1 14:04:25 2002 +++ linux/fs/nfsd/export.c Tue Jan 1 14:04:29 2002 @@ -50,7 +50,7 @@ #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 @@ 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 = 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); } /* diff -urN linux-2.5.2-pre5/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c --- linux-2.5.2-pre5/fs/nfsd/nfsctl.c Sun Oct 21 10:32:33 2001 +++ linux/fs/nfsd/nfsctl.c Tue Jan 1 14:04:29 2002 @@ -125,7 +125,7 @@ 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 @@ 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) { diff -urN linux-2.5.2-pre5/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- linux-2.5.2-pre5/fs/nfsd/nfsfh.c Wed Oct 3 22:59:22 2001 +++ linux/fs/nfsd/nfsfh.c Tue Jan 1 14:04:29 2002 @@ -424,7 +424,8 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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) { diff -urN linux-2.5.2-pre5/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c --- linux-2.5.2-pre5/fs/nfsd/nfsproc.c Sun Oct 21 10:40:36 2001 +++ linux/fs/nfsd/nfsproc.c Tue Jan 1 14:04:29 2002 @@ -197,7 +197,7 @@ 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 @@ 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 @@ /* 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; } diff -urN linux-2.5.2-pre5/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c --- linux-2.5.2-pre5/fs/nfsd/nfsxdr.c Wed Oct 17 14:16:34 2001 +++ linux/fs/nfsd/nfsxdr.c Tue Jan 1 14:04:29 2002 @@ -149,11 +149,11 @@ } *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; diff -urN linux-2.5.2-pre5/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- linux-2.5.2-pre5/fs/nfsd/vfs.c Fri Oct 5 12:23:53 2001 +++ linux/fs/nfsd/vfs.c Tue Jan 1 14:04:29 2002 @@ -66,7 +66,7 @@ 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 @@ * 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 @@ */ 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 @@ 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; diff -urN linux-2.5.2-pre5/fs/partitions/atari.c linux/fs/partitions/atari.c --- linux-2.5.2-pre5/fs/partitions/atari.c Mon Oct 1 20:03:26 2001 +++ linux/fs/partitions/atari.c Tue Jan 1 14:04:29 2002 @@ -43,7 +43,7 @@ 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; diff -urN linux-2.5.2-pre5/fs/partitions/check.c linux/fs/partitions/check.c --- linux-2.5.2-pre5/fs/partitions/check.c Tue Nov 27 09:23:27 2001 +++ linux/fs/partitions/check.c Tue Jan 1 14:04:29 2002 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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; diff -urN linux-2.5.2-pre5/fs/proc/array.c linux/fs/proc/array.c --- linux-2.5.2-pre5/fs/proc/array.c Tue Jan 1 14:04:25 2002 +++ linux/fs/proc/array.c Tue Jan 1 14:04:29 2002 @@ -555,7 +555,7 @@ 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; diff -urN linux-2.5.2-pre5/fs/super.c linux/fs/super.c --- linux-2.5.2-pre5/fs/super.c Tue Jan 1 14:04:25 2002 +++ linux/fs/super.c Tue Jan 1 14:04:29 2002 @@ -418,7 +418,7 @@ 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 @@ { 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 * s; - if (!dev) + if (kdev_none(dev)) return NULL; while (1) { @@ -540,7 +540,7 @@ { 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 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 @@ 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 @@ return old; } - s->s_dev = dev; + s->s_dev = mk_kdev(0, dev); insert_super(s, type); return s; } @@ -699,7 +699,7 @@ 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)) { diff -urN linux-2.5.2-pre5/include/linux/blk.h linux/include/linux/blk.h --- linux-2.5.2-pre5/include/linux/blk.h Tue Jan 1 14:04:26 2002 +++ linux/include/linux/blk.h Tue Jan 1 14:04:29 2002 @@ -106,14 +106,14 @@ #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 @@ /* 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 @@ #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 @@ #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 @@ 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 @@ 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); diff -urN linux-2.5.2-pre5/include/linux/blkdev.h linux/include/linux/blkdev.h --- linux-2.5.2-pre5/include/linux/blkdev.h Tue Jan 1 14:04:26 2002 +++ linux/include/linux/blkdev.h Tue Jan 1 14:04:29 2002 @@ -371,10 +371,10 @@ 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]; } diff -urN linux-2.5.2-pre5/include/linux/cdrom.h linux/include/linux/cdrom.h --- linux-2.5.2-pre5/include/linux/cdrom.h Sun Dec 16 15:43:25 2001 +++ linux/include/linux/cdrom.h Tue Jan 1 14:04:29 2002 @@ -792,7 +792,7 @@ 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); } diff -urN linux-2.5.2-pre5/include/linux/fs.h linux/include/linux/fs.h --- linux-2.5.2-pre5/include/linux/fs.h Tue Jan 1 14:04:26 2002 +++ linux/include/linux/fs.h Tue Jan 1 14:04:29 2002 @@ -311,7 +311,6 @@ #include #include #include -#include #include #include @@ -502,7 +501,6 @@ 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 @@ #include #include #include -#include #include #include @@ -744,7 +741,6 @@ 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; diff -urN linux-2.5.2-pre5/include/linux/genhd.h linux/include/linux/genhd.h --- linux-2.5.2-pre5/include/linux/genhd.h Sun Dec 16 15:43:25 2001 +++ linux/include/linux/genhd.h Tue Jan 1 14:04:29 2002 @@ -71,13 +71,11 @@ 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 @@ 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 diff -urN linux-2.5.2-pre5/include/linux/ide.h linux/include/linux/ide.h --- linux-2.5.2-pre5/include/linux/ide.h Sun Dec 16 15:45:06 2001 +++ linux/include/linux/ide.h Tue Jan 1 14:04:29 2002 @@ -18,13 +18,13 @@ /* * 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 */ /****************************************************************************** diff -urN linux-2.5.2-pre5/include/linux/kdev_t.h linux/include/linux/kdev_t.h --- linux-2.5.2-pre5/include/linux/kdev_t.h Fri Feb 16 16:06:17 2001 +++ linux/include/linux/kdev_t.h Tue Jan 1 14:04:29 2002 @@ -57,48 +57,84 @@ 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 */ diff -urN linux-2.5.2-pre5/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h --- linux-2.5.2-pre5/include/linux/nfsd/nfsfh.h Sun Dec 16 15:44:19 2001 +++ linux/include/linux/nfsd/nfsfh.h Tue Jan 1 14:04:29 2002 @@ -119,15 +119,37 @@ /* * 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) diff -urN linux-2.5.2-pre5/include/linux/raid/md_k.h linux/include/linux/raid/md_k.h --- linux-2.5.2-pre5/include/linux/raid/md_k.h Tue Jan 1 14:04:26 2002 +++ linux/include/linux/raid/md_k.h Tue Jan 1 14:04:29 2002 @@ -77,9 +77,9 @@ 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 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); diff -urN linux-2.5.2-pre5/include/linux/usb.h linux/include/linux/usb.h --- linux-2.5.2-pre5/include/linux/usb.h Sun Dec 16 15:46:59 2001 +++ linux/include/linux/usb.h Tue Jan 1 14:04:29 2002 @@ -521,7 +521,7 @@ 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 @@ 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 @@ * * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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 @@ #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 @@ 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 @@ 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 @@ /* * 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 @@ * 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 */ diff -urN linux-2.5.2-pre5/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h --- linux-2.5.2-pre5/include/linux/usbdevice_fs.h Sun Dec 16 15:47:13 2001 +++ linux/include/linux/usbdevice_fs.h Tue Jan 1 14:04:29 2002 @@ -150,17 +150,6 @@ #include #include -/* - * 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 */ diff -urN linux-2.5.2-pre5/init/do_mounts.c linux/init/do_mounts.c --- linux-2.5.2-pre5/init/do_mounts.c Tue Jan 1 14:04:26 2002 +++ linux/init/do_mounts.c Tue Jan 1 14:04:29 2002 @@ -1,5 +1,7 @@ #define __KERNEL_SYSCALLS__ #include +#include +#include #include #include #include @@ -7,6 +9,7 @@ #include #include #include +#include #include #include @@ -351,8 +354,8 @@ 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 @@ 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 @@ */ 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 @@ 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); diff -urN linux-2.5.2-pre5/kernel/sched.c linux/kernel/sched.c --- linux-2.5.2-pre5/kernel/sched.c Tue Jan 1 14:04:26 2002 +++ linux/kernel/sched.c Tue Jan 1 14:04:29 2002 @@ -51,25 +51,16 @@ * 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 @@ /* .. 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 @@ 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) { /* @@ -1341,6 +1341,8 @@ for(nr = 0; nr < PIDHASH_SZ; nr++) pidhash[nr] = NULL; + + fill_tslice_map(); init_timervecs(); diff -urN linux-2.5.2-pre5/mm/filemap.c linux/mm/filemap.c --- linux-2.5.2-pre5/mm/filemap.c Sun Dec 16 15:21:24 2001 +++ linux/mm/filemap.c Tue Jan 1 14:04:29 2002 @@ -1132,9 +1132,9 @@ 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, diff -urN linux-2.5.2-pre5/mm/page_io.c linux/mm/page_io.c --- linux-2.5.2-pre5/mm/page_io.c Tue Nov 27 09:23:27 2001 +++ linux/mm/page_io.c Tue Jan 1 14:04:29 2002 @@ -38,7 +38,7 @@ 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 @@ 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; diff -urN linux-2.5.2-pre5/mm/swapfile.c linux/mm/swapfile.c --- linux-2.5.2-pre5/mm/swapfile.c Tue Jan 1 14:04:26 2002 +++ linux/mm/swapfile.c Tue Jan 1 14:04:29 2002 @@ -774,7 +774,7 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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;