summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acorn/block/mfmhd.c77
-rw-r--r--drivers/block/DAC960.c37
-rw-r--r--drivers/block/acsi.c46
-rw-r--r--drivers/block/ataflop.c6
-rw-r--r--drivers/block/blkpg.c66
-rw-r--r--drivers/block/cciss.c37
-rw-r--r--drivers/block/cpqarray.c15
-rw-r--r--drivers/block/floppy.c6
-rw-r--r--drivers/block/genhd.c26
-rw-r--r--drivers/block/ll_rw_blk.c11
-rw-r--r--drivers/block/loop.c4
-rw-r--r--drivers/block/paride/Makefile16
-rw-r--r--drivers/block/paride/aten.c53
-rw-r--r--drivers/block/paride/bpck.c55
-rw-r--r--drivers/block/paride/bpck6.c71
-rw-r--r--drivers/block/paride/comm.c53
-rw-r--r--drivers/block/paride/dstr.c53
-rw-r--r--drivers/block/paride/epat.c54
-rw-r--r--drivers/block/paride/epia.c55
-rw-r--r--drivers/block/paride/fit2.c53
-rw-r--r--drivers/block/paride/fit3.c53
-rw-r--r--drivers/block/paride/friq.c54
-rw-r--r--drivers/block/paride/frpw.c54
-rw-r--r--drivers/block/paride/kbic.c92
-rw-r--r--drivers/block/paride/ktti.c53
-rw-r--r--drivers/block/paride/on20.c53
-rw-r--r--drivers/block/paride/on26.c55
-rw-r--r--drivers/block/paride/paride.c133
-rw-r--r--drivers/block/paride/pcd.c124
-rw-r--r--drivers/block/paride/pd.c251
-rw-r--r--drivers/block/paride/pf.c110
-rw-r--r--drivers/block/paride/pg.c107
-rw-r--r--drivers/block/paride/pt.c116
-rw-r--r--drivers/block/ps2esdi.c67
-rw-r--r--drivers/block/rd.c6
-rw-r--r--drivers/block/umem.c91
-rw-r--r--drivers/block/xd.c64
-rw-r--r--drivers/block/xd.h1
-rw-r--r--drivers/cdrom/cdrom.c5
-rw-r--r--drivers/char/Config.in31
-rw-r--r--drivers/char/Makefile21
-rw-r--r--drivers/char/acpi_serial.c203
-rw-r--r--drivers/char/agp/Config.help88
-rw-r--r--drivers/char/agp/Config.in14
-rw-r--r--drivers/char/agp/Makefile15
-rw-r--r--drivers/char/agp/agp.c1662
-rw-r--r--drivers/char/agp/agp.h344
-rw-r--r--drivers/char/agp/agpgart_be.c5114
-rw-r--r--drivers/char/agp/ali-agp.c265
-rw-r--r--drivers/char/agp/amd-agp.c408
-rw-r--r--drivers/char/agp/frontend.c (renamed from drivers/char/agp/agpgart_fe.c)15
-rw-r--r--drivers/char/agp/hp-agp.c394
-rw-r--r--drivers/char/agp/i460-agp.c595
-rw-r--r--drivers/char/agp/i810-agp.c594
-rw-r--r--drivers/char/agp/i8x0-agp.c726
-rw-r--r--drivers/char/agp/sis-agp.c142
-rw-r--r--drivers/char/agp/sworks-agp.c626
-rw-r--r--drivers/char/agp/via-agp.c151
-rw-r--r--drivers/char/n_tty.c4
-rw-r--r--drivers/char/pcmcia/Config.in1
-rw-r--r--drivers/char/pcmcia/Makefile1
-rw-r--r--drivers/char/pcmcia/serial_cs.c667
-rw-r--r--drivers/char/serial.c6003
-rw-r--r--drivers/char/tty_io.c26
-rw-r--r--drivers/char/tty_ioctl.c4
-rw-r--r--drivers/char/vt.c6
-rw-r--r--drivers/ide/hd.c70
-rw-r--r--drivers/ide/hptraid.c5
-rw-r--r--drivers/ide/ide.c3
-rw-r--r--drivers/ide/ioctl.c13
-rw-r--r--drivers/ide/main.c39
-rw-r--r--drivers/ide/pdcraid.c5
-rw-r--r--drivers/ieee1394/sbp2.c2
-rw-r--r--drivers/ieee1394/sbp2.h2
-rw-r--r--drivers/md/lvm.c11
-rw-r--r--drivers/md/md.c24
-rw-r--r--drivers/message/fusion/mptscsih.c2
-rw-r--r--drivers/message/fusion/mptscsih.h2
-rw-r--r--drivers/message/i2o/i2o_block.c19
-rw-r--r--drivers/message/i2o/i2o_scsi.c2
-rw-r--r--drivers/message/i2o/i2o_scsi.h2
-rw-r--r--drivers/mtd/ftl.c57
-rw-r--r--drivers/mtd/mtdblock.c2
-rw-r--r--drivers/mtd/mtdblock_ro.c2
-rw-r--r--drivers/mtd/nftlcore.c43
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/fc/iph5526.c2
-rw-r--r--drivers/net/fc/iph5526_scsi.h2
-rw-r--r--drivers/s390/block/dasd_ioctl.c17
-rw-r--r--drivers/s390/block/xpram.c8
-rw-r--r--drivers/sbus/char/jsflash.c8
-rw-r--r--drivers/scsi/3w-xxxx.c2
-rw-r--r--drivers/scsi/3w-xxxx.h3
-rw-r--r--drivers/scsi/BusLogic.c4
-rw-r--r--drivers/scsi/BusLogic.h3
-rw-r--r--drivers/scsi/NCR53c406a.c2
-rw-r--r--drivers/scsi/NCR53c406a.h2
-rw-r--r--drivers/scsi/advansys.c2
-rw-r--r--drivers/scsi/advansys.h2
-rw-r--r--drivers/scsi/aha152x.c4
-rw-r--r--drivers/scsi/aha152x.h2
-rw-r--r--drivers/scsi/aha1542.c2
-rw-r--r--drivers/scsi/aha1542.h3
-rw-r--r--drivers/scsi/aha1740.c2
-rw-r--r--drivers/scsi/aha1740.h3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_linux.c4
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_linux_host.h2
-rw-r--r--drivers/scsi/aic7xxx_old.c4
-rw-r--r--drivers/scsi/aic7xxx_old/aic7xxx.h2
-rw-r--r--drivers/scsi/atp870u.c2
-rw-r--r--drivers/scsi/atp870u.h3
-rw-r--r--drivers/scsi/cpqfcTS.h2
-rw-r--r--drivers/scsi/cpqfcTSinit.c2
-rw-r--r--drivers/scsi/dc390.h2
-rw-r--r--drivers/scsi/dpt_i2o.c2
-rw-r--r--drivers/scsi/dpti.h2
-rw-r--r--drivers/scsi/dtc.c4
-rw-r--r--drivers/scsi/dtc.h2
-rw-r--r--drivers/scsi/eata.c4
-rw-r--r--drivers/scsi/eata.h2
-rw-r--r--drivers/scsi/fd_mcs.c5
-rw-r--r--drivers/scsi/fd_mcs.h2
-rw-r--r--drivers/scsi/fdomain.c6
-rw-r--r--drivers/scsi/fdomain.h2
-rw-r--r--drivers/scsi/g_NCR5380.c2
-rw-r--r--drivers/scsi/g_NCR5380.h2
-rw-r--r--drivers/scsi/gdth.c6
-rw-r--r--drivers/scsi/gdth.h81
-rw-r--r--drivers/scsi/hosts.h4
-rw-r--r--drivers/scsi/ibmmca.c2
-rw-r--r--drivers/scsi/ibmmca.h2
-rw-r--r--drivers/scsi/ide-scsi.c2
-rw-r--r--drivers/scsi/imm.c2
-rw-r--r--drivers/scsi/imm.h2
-rw-r--r--drivers/scsi/in2000.c2
-rw-r--r--drivers/scsi/in2000.h2
-rw-r--r--drivers/scsi/ini9100u.c2
-rw-r--r--drivers/scsi/ini9100u.h2
-rw-r--r--drivers/scsi/inia100.c2
-rw-r--r--drivers/scsi/inia100.h2
-rw-r--r--drivers/scsi/ips.c4
-rw-r--r--drivers/scsi/ips.h2
-rw-r--r--drivers/scsi/megaraid.c15
-rw-r--r--drivers/scsi/megaraid.h4
-rw-r--r--drivers/scsi/pas16.c4
-rw-r--r--drivers/scsi/pas16.h2
-rw-r--r--drivers/scsi/pci2000.c2
-rw-r--r--drivers/scsi/pci2000.h3
-rw-r--r--drivers/scsi/pci2220i.c3
-rw-r--r--drivers/scsi/pci2220i.h2
-rw-r--r--drivers/scsi/ppa.c2
-rw-r--r--drivers/scsi/ppa.h2
-rw-r--r--drivers/scsi/psi240i.c2
-rw-r--r--drivers/scsi/psi240i.h3
-rw-r--r--drivers/scsi/qla1280.c2
-rw-r--r--drivers/scsi/qla1280.h2
-rw-r--r--drivers/scsi/qlogicfas.c2
-rw-r--r--drivers/scsi/qlogicfas.h2
-rw-r--r--drivers/scsi/qlogicfc.c2
-rw-r--r--drivers/scsi/qlogicfc.h2
-rw-r--r--drivers/scsi/qlogicisp.c2
-rw-r--r--drivers/scsi/qlogicisp.h2
-rw-r--r--drivers/scsi/scsi_debug.c2
-rw-r--r--drivers/scsi/scsi_debug.h3
-rw-r--r--drivers/scsi/scsi_mid_low_api.txt2
-rw-r--r--drivers/scsi/scsicam.c40
-rw-r--r--drivers/scsi/sd.c50
-rw-r--r--drivers/scsi/sim710.h2
-rw-r--r--drivers/scsi/sym53c416.c2
-rw-r--r--drivers/scsi/sym53c416.h3
-rw-r--r--drivers/scsi/t128.c4
-rw-r--r--drivers/scsi/t128.h2
-rw-r--r--drivers/scsi/tmscsim.c12
-rw-r--r--drivers/scsi/u14-34f.c4
-rw-r--r--drivers/scsi/u14-34f.h2
-rw-r--r--drivers/scsi/ultrastor.c2
-rw-r--r--drivers/scsi/ultrastor.h3
-rw-r--r--drivers/scsi/wd7000.c6
-rw-r--r--drivers/scsi/wd7000.h3
-rw-r--r--drivers/serial/Config.help225
-rw-r--r--drivers/serial/Config.in77
-rw-r--r--drivers/serial/Makefile22
-rw-r--r--drivers/serial/serial_21285.c553
-rw-r--r--drivers/serial/serial_8250.c2015
-rw-r--r--drivers/serial/serial_8250.h60
-rw-r--r--drivers/serial/serial_8250_cs.c719
-rw-r--r--drivers/serial/serial_8250_pci.c1138
-rw-r--r--drivers/serial/serial_8250_pnp.c548
-rw-r--r--drivers/serial/serial_amba.c783
-rw-r--r--drivers/serial/serial_anakin.c546
-rw-r--r--drivers/serial/serial_clps711x.c643
-rw-r--r--drivers/serial/serial_core.c2467
-rw-r--r--drivers/serial/serial_sa1100.c899
-rw-r--r--drivers/serial/serial_uart00.c778
-rw-r--r--drivers/usb/class/audio.c38
-rw-r--r--drivers/usb/class/bluetty.c56
-rw-r--r--drivers/usb/class/cdc-acm.c60
-rw-r--r--drivers/usb/class/printer.c29
-rw-r--r--drivers/usb/class/usb-midi.c36
-rw-r--r--drivers/usb/core/devices.c22
-rw-r--r--drivers/usb/core/devio.c62
-rw-r--r--drivers/usb/core/drivers.c6
-rw-r--r--drivers/usb/core/file.c11
-rw-r--r--drivers/usb/core/hcd.c10
-rw-r--r--drivers/usb/core/hub.c14
-rw-r--r--drivers/usb/core/inode.c38
-rw-r--r--drivers/usb/core/usb.c195
-rw-r--r--drivers/usb/host/Config.in1
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/ehci-hcd.c56
-rw-r--r--drivers/usb/host/hc_simple.c10
-rw-r--r--drivers/usb/host/ohci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-pci.c56
-rw-r--r--drivers/usb/host/ohci-sa1111.c26
-rw-r--r--drivers/usb/host/uhci-debug.c8
-rw-r--r--drivers/usb/host/uhci-hcd.c56
-rw-r--r--drivers/usb/host/usb-ohci-pci.c456
-rw-r--r--drivers/usb/host/usb-ohci-sa1111.c153
-rw-r--r--drivers/usb/host/usb-ohci.c2537
-rw-r--r--drivers/usb/host/usb-ohci.h648
-rw-r--r--drivers/usb/image/hpusbscsi.c8
-rw-r--r--drivers/usb/image/mdc800.c20
-rw-r--r--drivers/usb/image/microtek.c40
-rw-r--r--drivers/usb/image/scanner.c18
-rw-r--r--drivers/usb/input/aiptek.c8
-rw-r--r--drivers/usb/input/hid-core.c8
-rw-r--r--drivers/usb/input/hiddev.c20
-rw-r--r--drivers/usb/input/powermate.c8
-rw-r--r--drivers/usb/input/usbkbd.c8
-rw-r--r--drivers/usb/input/usbmouse.c8
-rw-r--r--drivers/usb/input/wacom.c8
-rw-r--r--drivers/usb/input/xpad.c8
-rw-r--r--drivers/usb/media/dabusb.c20
-rw-r--r--drivers/usb/media/dsbr100.c28
-rw-r--r--drivers/usb/media/ov511.c511
-rw-r--r--drivers/usb/media/ov511.h8
-rw-r--r--drivers/usb/media/pwc-if.c59
-rw-r--r--drivers/usb/media/se401.c26
-rw-r--r--drivers/usb/media/stv680.c32
-rw-r--r--drivers/usb/media/usbvideo.c22
-rw-r--r--drivers/usb/media/vicam.c34
-rw-r--r--drivers/usb/misc/auerswald.c22
-rw-r--r--drivers/usb/misc/brlvger.c26
-rw-r--r--drivers/usb/misc/rio500.c18
-rw-r--r--drivers/usb/misc/tiglusb.c24
-rw-r--r--drivers/usb/misc/uss720.c8
-rw-r--r--drivers/usb/net/catc.c8
-rw-r--r--drivers/usb/net/cdc-ether.c8
-rw-r--r--drivers/usb/net/kaweth.c10
-rw-r--r--drivers/usb/net/pegasus.c8
-rw-r--r--drivers/usb/net/rtl8150.c8
-rw-r--r--drivers/usb/net/usbnet.c120
-rw-r--r--drivers/usb/serial/belkin_sa.c30
-rw-r--r--drivers/usb/serial/cyberjack.c30
-rw-r--r--drivers/usb/serial/digi_acceleport.c84
-rw-r--r--drivers/usb/serial/empeg.c40
-rw-r--r--drivers/usb/serial/ftdi_sio.c72
-rw-r--r--drivers/usb/serial/ipaq.c32
-rw-r--r--drivers/usb/serial/ir-usb.c28
-rw-r--r--drivers/usb/serial/keyspan.c36
-rw-r--r--drivers/usb/serial/keyspan_pda.c74
-rw-r--r--drivers/usb/serial/kl5kusb105.c40
-rw-r--r--drivers/usb/serial/mct_u232.c34
-rw-r--r--drivers/usb/serial/omninet.c28
-rw-r--r--drivers/usb/serial/pl2303.c36
-rw-r--r--drivers/usb/serial/safe_serial.c22
-rw-r--r--drivers/usb/serial/usbserial.c136
-rw-r--r--drivers/usb/serial/visor.c80
-rw-r--r--drivers/usb/serial/whiteheat.c46
-rw-r--r--drivers/usb/storage/scsiglue.c46
-rw-r--r--drivers/usb/storage/usb.c18
-rw-r--r--drivers/usb/usb-skeleton.c20
273 files changed, 19811 insertions, 19508 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index e858842760d3..3348f9765ba6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -8,7 +8,7 @@
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_ACPI) += acpi/
obj-$(CONFIG_PARPORT) += parport/
-obj-y += base/ char/ block/ misc/ net/ media/
+obj-y += base/ serial/ char/ block/ misc/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_IDE) += ide/
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index fd41fe9d58b7..309fc7c4d47d 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -184,8 +184,6 @@ struct mfm_info {
#define NEED_1_RECAL -2
#define NEED_2_RECAL -3
int cylinder;
- unsigned int access_count;
- unsigned int busy;
struct {
char recal;
char report;
@@ -197,7 +195,6 @@ struct mfm_info {
static struct hd_struct mfm[MFM_MAXDRIVES << 6];
static int mfm_sizes[MFM_MAXDRIVES << 6];
-static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open);
/* Stuff from the assembly routines */
extern unsigned int hdc63463_baseaddress; /* Controller base address */
@@ -1195,22 +1192,11 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a
return -EFAULT;
return 0;
- case BLKSECTGET:
- return put_user(max_sectors[major][minor], (long *) arg);
-
case BLKRRPART:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
return mfm_reread_partitions(dev);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKFLSBUF:
- case BLKROSET:
- case BLKROGET:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
default:
return -EINVAL;
}
@@ -1219,24 +1205,8 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a
static int mfm_open(struct inode *inode, struct file *file)
{
int dev = DEVICE_NR(minor(inode->i_rdev));
-
if (dev >= mfm_drives)
return -ENODEV;
-
- while (mfm_info[dev].busy)
- sleep_on (&mfm_wait_open);
-
- mfm_info[dev].access_count++;
- return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-static int mfm_release(struct inode *inode, struct file *file)
-{
- mfm_info[DEVICE_NR(minor(inode->i_rdev))].access_count--;
return 0;
}
@@ -1254,10 +1224,11 @@ void mfm_setup(char *str, int *ints)
* since if there are any non-ADFS partitions on the disk, this won't work!
* Hence, I want to get rid of this...
*/
-void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,
- unsigned long discsize, unsigned int secsize)
+void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
+ unsigned char heads, unsigned int secsize)
{
- int drive = minor(dev) >> 6;
+ int drive = MINOR(bdev->bd_dev) >> 6;
+ unsigned long disksize = bdev->bd_inode->i_size;
if (mfm_info[drive].cylinders == 1) {
mfm_info[drive].sectors = secsptrack;
@@ -1265,7 +1236,7 @@ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,
mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize);
if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) {
- printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6));
+ printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + drive);
/* These values are fairly arbitary, but are there so that if your
* lucky you can pick apart your disc to find out what is going on -
@@ -1295,7 +1266,6 @@ static struct block_device_operations mfm_fops =
{
owner: THIS_MODULE,
open: mfm_open,
- release: mfm_release,
ioctl: mfm_ioctl,
};
@@ -1424,38 +1394,19 @@ int mfm_init (void)
/*
* This routine is called to flush all partitions and partition tables
* for a changed MFM disk, and then re-read the new partition table.
- * If we are revalidating due to an ioctl, we have USAGE == 1.
*/
static int mfm_reread_partitions(kdev_t dev)
{
- unsigned int start, i, maxp, target = DEVICE_NR(minor(dev));
- unsigned long flags;
-
- local_irq_save(flags);
- if (mfm_info[target].busy || mfm_info[target].access_count > 1) {
- local_irq_restore (flags);
- return -EBUSY;
- }
- mfm_info[target].busy = 1;
- local_irq_restore (flags);
-
- maxp = 1 << mfm_gendisk.minor_shift;
- start = target << mfm_gendisk.minor_shift;
-
- for (i = maxp - 1; i >= 0; i--) {
- int minor = start + i;
- invalidate_device (mk_kdev(MAJOR_NR, minor), 1);
- mfm_gendisk.part[minor].start_sect = 0;
- mfm_gendisk.part[minor].nr_sects = 0;
- }
-
+ unsigned int unit = DEVICE_NR(minor(dev));
+ kdev_t device = mk_kdev(MAJOR_NR, unit << mfm_gendisk.minor_shift);
+ int err = dev_lock_part(device);
+ if (err)
+ return err;
+ wipe_partitions(device);
/* Divide by 2, since sectors are 2 times smaller than usual ;-) */
-
- grok_partitions(&mfm_gendisk, target, 1<<6, mfm_info[target].heads *
- mfm_info[target].cylinders * mfm_info[target].sectors / 2);
-
- mfm_info[target].busy = 0;
- wake_up (&mfm_wait_open);
+ grok_partitions(device, mfm_info[unit].heads *
+ mfm_info[unit].cylinders * mfm_info[unit].sectors / 2);
+ dev_unlock_part(device);
return 0;
}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 210449ad1715..dc372aa4dbb1 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -2055,29 +2055,20 @@ static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller)
static void DAC960_RegisterDisk(DAC960_Controller_T *Controller,
int LogicalDriveNumber)
{
- if (Controller->FirmwareType == DAC960_V1_Controller)
- {
+ long size;
+ if (Controller->FirmwareType == DAC960_V1_Controller) {
if (LogicalDriveNumber > Controller->LogicalDriveCount - 1) return;
- register_disk(&Controller->GenericDiskInfo,
- DAC960_KernelDevice(Controller->ControllerNumber,
- LogicalDriveNumber, 0),
- DAC960_MaxPartitions,
- &DAC960_BlockDeviceOperations,
- Controller->V1.LogicalDriveInformation
- [LogicalDriveNumber].LogicalDriveSize);
- }
- else
- {
+ size = Controller->V1.LogicalDriveInformation
+ [LogicalDriveNumber].LogicalDriveSize;
+ } else {
DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
if (LogicalDeviceInfo == NULL) return;
- register_disk(&Controller->GenericDiskInfo,
- DAC960_KernelDevice(Controller->ControllerNumber,
- LogicalDriveNumber, 0),
- DAC960_MaxPartitions,
- &DAC960_BlockDeviceOperations,
- LogicalDeviceInfo->ConfigurableDeviceSize);
- }
+ size = LogicalDeviceInfo->ConfigurableDeviceSize;
+ }
+ register_disk(&Controller->GenericDiskInfo,
+ DAC960_KernelDevice(Controller->ControllerNumber, LogicalDriveNumber, 0),
+ DAC960_MaxPartitions, &DAC960_BlockDeviceOperations, size);
}
@@ -5399,15 +5390,9 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
LogicalDeviceInfo->ConfigurableDeviceSize
/ (Geometry.heads * Geometry.sectors);
}
- Geometry.start = get_start_sect(Inode->i_rdev);
+ Geometry.start = get_start_sect(Inode->i_bdev);
return (copy_to_user(UserGeometry, &Geometry,
sizeof(DiskGeometry_T)) ? -EFAULT : 0);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKFLSBUF:
- case BLKBSZGET:
- case BLKBSZSET:
- return blk_ioctl(Inode->i_bdev, Request, Argument);
case BLKRRPART:
/* Re-Read Partition Table. */
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index c35ef7f77e40..f616f01847b7 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -248,8 +248,6 @@ static int NDevices = 0;
static int acsi_sizes[MAX_DEV<<4] = { 0, };
static struct hd_struct acsi_part[MAX_DEV<<4] = { {0,0}, };
static int access_count[MAX_DEV] = { 0, };
-static char busy[MAX_DEV] = { 0, };
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
static int CurrentNReq;
static int CurrentNSect;
@@ -1107,7 +1105,7 @@ static int acsi_ioctl( struct inode *inode, struct file *file,
put_user( 64, &geo->heads );
put_user( 32, &geo->sectors );
put_user( acsi_info[dev].size >> 11, &geo->cylinders );
- put_user(get_start_sect(inode->i_rdev), &geo->start);
+ put_user(get_start_sect(inode->i_bdev), &geo->start);
return 0;
}
@@ -1118,14 +1116,6 @@ static int acsi_ioctl( struct inode *inode, struct file *file,
put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id );
return 0;
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
case BLKRRPART: /* Re-read partition tables */
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -1161,8 +1151,6 @@ static int acsi_open( struct inode * inode, struct file * filp )
if (device >= NDevices)
return -ENXIO;
aip = &acsi_info[device];
- while (busy[device])
- sleep_on(&busy_wait);
if (access_count[device] == 0 && aip->removable) {
#if 0
@@ -1803,10 +1791,6 @@ void cleanup_module(void)
}
#endif
-#define DEVICE_BUSY busy[device]
-#define USAGE access_count[device]
-#define GENDISK_STRUCT acsi_gendisk
-
/*
* This routine is called to flush all partitions and partition tables
* for a changed scsi disk, and then re-read the new partition table.
@@ -1828,24 +1812,15 @@ void cleanup_module(void)
static int revalidate_acsidisk( int dev, int maxusage )
{
- int device;
- struct gendisk * gdev;
- int res;
- struct acsi_info_struct *aip;
-
- device = DEVICE_NR(minor(dev));
- aip = &acsi_info[device];
- gdev = &GENDISK_STRUCT;
+ int unit = DEVICE_NR(minor(dev));
+ struct acsi_info_struct *aip = &acsi_info[unit];
+ kdev_t device = mk_kdev(MAJOR_NR, unit<<4);
+ int res = dev_lock_part(device);
- cli();
- if (DEVICE_BUSY || USAGE > maxusage) {
- sti();
- return -EBUSY;
- };
- DEVICE_BUSY = 1;
- sti();
+ if (res < 0)
+ return res;
- res = wipe_partitions(dev);
+ res = wipe_partitions(device);
stdma_lock( NULL, NULL );
@@ -1862,10 +1837,9 @@ static int revalidate_acsidisk( int dev, int maxusage )
stdma_release();
if (!res)
- grok_partitions(dev, aip->size);
+ grok_partitions(device, aip->size);
- DEVICE_BUSY = 0;
- wake_up(&busy_wait);
+ dev_unlock_part(device);
return res;
}
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index af8f966f4eb3..04a8ce00c6a7 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1559,12 +1559,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
struct floppy_struct setprm;
device = inode->i_rdev;
- switch (cmd) {
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- return blk_ioctl(inode->i_bdev, cmd, param);
- }
drive = minor (device);
type = drive >> 2;
drive &= 3;
diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c
index 37e244777963..83826af84b6a 100644
--- a/drivers/block/blkpg.c
+++ b/drivers/block/blkpg.c
@@ -69,8 +69,9 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p)
struct gendisk *g;
long long ppstart, pplength;
long pstart, plength;
- int i, drive, first_minor, end_minor, minor;
+ int i;
kdev_t dev = to_kdev_t(bdev->bd_dev);
+ struct hd_struct *part;
/* convert bytes to sectors, check for fit in a hd_struct */
ppstart = (p->start >> 9);
@@ -85,37 +86,32 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p)
g = get_gendisk(dev);
if (!g)
return -ENXIO;
+ part = g->part + minor(dev);
/* existing drive? */
- drive = (minor(dev) >> g->minor_shift);
- first_minor = (drive << g->minor_shift);
- 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))
+ if (bdev != bdev->bd_contains)
return -EINVAL;
if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
return -EINVAL;
/* partition number in use? */
- minor = first_minor + p->pno;
- if (g->part[minor].nr_sects != 0)
+ if (part[p->pno].nr_sects != 0)
return -EBUSY;
/* overlap? */
- for (i=first_minor+1; i<end_minor; i++)
- if (!(pstart+plength <= g->part[i].start_sect ||
- pstart >= g->part[i].start_sect + g->part[i].nr_sects))
+ for (i = 1; i < (1<<g->minor_shift); i++)
+ if (!(pstart+plength <= part[i].start_sect ||
+ pstart >= part[i].start_sect + part[i].nr_sects))
return -EBUSY;
/* all seems OK */
- g->part[minor].start_sect = pstart;
- g->part[minor].nr_sects = plength;
+ part[p->pno].start_sect = pstart;
+ part[p->pno].nr_sects = plength;
if (g->sizes)
- g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
- devfs_register_partitions (g, first_minor, 0);
+ g->sizes[minor(dev)+p->pno] = (plength >> (BLOCK_SIZE_BITS-9));
+ devfs_register_partitions (g, minor(dev), 0);
return 0;
}
@@ -133,33 +129,27 @@ int del_partition(struct block_device *bdev, struct blkpg_partition *p)
{
kdev_t dev = to_kdev_t(bdev->bd_dev);
struct gendisk *g;
- kdev_t devp;
struct block_device *bdevp;
- int drive, first_minor, minor;
+ struct hd_struct *part;
int holder;
/* find the drive major */
g = get_gendisk(dev);
if (!g)
return -ENXIO;
+ part = g->part + minor(dev);
- /* drive and partition number OK? */
- drive = (minor(dev) >> g->minor_shift);
- first_minor = (drive << g->minor_shift);
-
- if (first_minor != minor(dev))
+ if (bdev != bdev->bd_contains)
return -EINVAL;
if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
return -EINVAL;
/* existing drive and partition? */
- minor = first_minor + p->pno;
- if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
+ if (part[p->pno].nr_sects == 0)
return -ENXIO;
/* partition in use? Incomplete check for now. */
- devp = mk_kdev(major(dev), minor);
- bdevp = bdget(kdev_t_to_nr(devp));
+ bdevp = bdget(MKDEV(major(dev), minor(dev) + p->pno));
if (!bdevp)
return -ENOMEM;
if (bd_claim(bdevp, &holder) < 0) {
@@ -171,11 +161,11 @@ int del_partition(struct block_device *bdev, struct blkpg_partition *p)
fsync_bdev(bdevp);
invalidate_bdev(bdevp, 0);
- g->part[minor].start_sect = 0;
- g->part[minor].nr_sects = 0;
+ part[p->pno].start_sect = 0;
+ part[p->pno].nr_sects = 0;
if (g->sizes)
- g->sizes[minor] = 0;
- devfs_register_partitions (g, first_minor, 0);
+ g->sizes[minor(dev) + p->pno] = 0;
+ devfs_register_partitions (g, minor(dev), 0);
bd_release(bdevp);
bdput(bdevp);
@@ -223,10 +213,6 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
int holder;
struct backing_dev_info *bdi;
- intval = block_ioctl(bdev, cmd, arg);
- if (intval != -ENOTTY)
- return intval;
-
switch (cmd) {
case BLKROSET:
if (!capable(CAP_SYS_ADMIN))
@@ -296,14 +282,6 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
case BLKPG:
return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
-
- /*
- * deprecated, use the /proc/iosched interface instead
- */
- case BLKELVGET:
- case BLKELVSET:
- return -ENOTTY;
-
case BLKBSZGET:
/* get the logical block size (cf. BLKSSZGET) */
intval = block_size(bdev);
@@ -330,5 +308,3 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
return -EINVAL;
}
}
-
-EXPORT_SYMBOL(blk_ioctl);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index e06fd274b653..939d70269415 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -440,15 +440,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
case BLKRRPART:
return revalidate_logvol(inode->i_rdev, 1);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKFLSBUF:
- case BLKBSZSET:
- case BLKBSZGET:
- case BLKROSET:
- case BLKROGET:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
case CCISS_GETPCIINFO:
{
cciss_pci_info_struct pciinfo;
@@ -735,6 +726,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
}
/* Borrowed and adapted from sd.c */
+/*
+ * FIXME: we are missing the exclusion with ->open() here - it can happen
+ * just as we are rereading partition tables.
+ */
static int revalidate_logvol(kdev_t dev, int maxusage)
{
int ctlr, target;
@@ -860,18 +855,9 @@ static int deregister_disk(int ctlr, int logvol)
/* invalidate the devices and deregister the disk */
max_p = 1 << gdev->minor_shift;
start = logvol << gdev->minor_shift;
+ wipe_partitions(mk_kdev(MAJOR_NR+ctlr, start));
for (i=max_p-1; i>=0; i--)
- {
- int minor = start+i;
- kdev_t kdev = mk_kdev(MAJOR_NR+ctlr, minor);
- // printk("invalidating( %d %d)\n", ctlr, minor);
- invalidate_device(kdev, 1);
- /* so open will now fail */
- h->sizes[minor] = 0;
- /* so it will no longer appear in /proc/partitions */
- gdev->part[minor].start_sect = 0;
- gdev->part[minor].nr_sects = 0;
- }
+ h->sizes[start + i] = 0;
/* check to see if it was the last disk */
if (logvol == h->highest_lun)
{
@@ -1313,19 +1299,12 @@ static int register_new_disk(kdev_t dev, int ctlr)
hba[ctlr]->drv[logvol].usage_count = 0;
max_p = 1 << gdev->minor_shift;
start = logvol<< gdev->minor_shift;
+ kdev = mk_kdev(MAJOR_NR + ctlr, logvol<< gdev->minor_shift);
- for(i=max_p-1; i>=0; i--) {
- int minor = start+i;
- kdev = mk_kdev(MAJOR_NR + ctlr, minor);
- invalidate_device(kdev, 1);
- gdev->part[minor].start_sect = 0;
- gdev->part[minor].nr_sects = 0;
- }
-
+ wipe_partitions(kdev);
++hba[ctlr]->num_luns;
gdev->nr_real = hba[ctlr]->highest_lun + 1;
/* setup partitions per disk */
- kdev = mk_kdev(MAJOR_NR + ctlr, logvol<< gdev->minor_shift);
grok_partitions(kdev, hba[ctlr]->drv[logvol].nr_blocks);
kfree(ld_buff);
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index fccef1bb792c..31276ef0e87c 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -1116,7 +1116,7 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
put_user(diskinfo[0], &geo->heads);
put_user(diskinfo[1], &geo->sectors);
put_user(diskinfo[2], &geo->cylinders);
- put_user(get_start_sect(inode->i_rdev), &geo->start);
+ put_user(get_start_sect(inode->i_bdev), &geo->start);
return 0;
case IDAGETDRVINFO:
if (copy_to_user(&io->c.drv, &hba[ctlr]->drv[dsk],
@@ -1157,16 +1157,6 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
return(0);
}
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKFLSBUF:
- case BLKBSZSET:
- case BLKBSZGET:
- case BLKROSET:
- case BLKROGET:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
default:
return -EINVAL;
}
@@ -1533,6 +1523,9 @@ static int revalidate_allvol(kdev_t dev)
}
/* Borrowed and adapted from sd.c */
+/*
+ * FIXME: exclusion with ->open()
+ */
static int revalidate_logvol(kdev_t dev, int maxusage)
{
int ctlr, target;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index aff8acff0ef3..fdc6e904464a 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3468,12 +3468,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
const char *outparam; /* parameters passed back to user space */
device = inode->i_rdev;
- switch (cmd) {
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- return blk_ioctl(inode->i_bdev, cmd, param);
- }
type = TYPE(device);
drive = DRIVE(device);
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 7c30fbe37c16..0fc011f610d1 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -117,31 +117,6 @@ get_gendisk(kdev_t dev)
EXPORT_SYMBOL(get_gendisk);
-
-unsigned long
-get_start_sect(kdev_t dev)
-{
- struct gendisk *gp;
-
- gp = get_gendisk(dev);
- if (gp)
- return gp->part[minor(dev)].start_sect;
- return 0;
-}
-
-EXPORT_SYMBOL(get_start_sect);
-
-unsigned long
-get_nr_sects(kdev_t dev)
-{
- struct gendisk *gp;
-
- gp = get_gendisk(dev);
- if (gp)
- return gp->part[minor(dev)].nr_sects;
- return 0;
-}
-
#ifdef CONFIG_PROC_FS
/* iterator */
static void *part_start(struct seq_file *part, loff_t *pos)
@@ -209,7 +184,6 @@ int __init device_init(void)
{
rwlock_init(&gendisk_lock);
blk_dev_init();
- sti();
#ifdef CONFIG_I2O
i2o_init();
#endif
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 48616f94f5ee..c23f57a0ed16 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -1573,16 +1573,10 @@ end_io:
static inline void blk_partition_remap(struct bio *bio)
{
struct block_device *bdev = bio->bi_bdev;
- struct gendisk *g;
-
if (bdev == bdev->bd_contains)
return;
- g = get_gendisk(to_kdev_t(bdev->bd_dev));
- if (!g)
- BUG();
-
- bio->bi_sector += g->part[minor(to_kdev_t((bdev->bd_dev)))].start_sect;
+ bio->bi_sector += bdev->bd_offset;
bio->bi_bdev = bdev->bd_contains;
/* lots of checks are possible */
}
@@ -2047,9 +2041,6 @@ int __init blk_dev_init(void)
#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
hd_init();
#endif
-#if defined(__i386__) /* Do we even need this? */
- outb_p(0xc, 0x3f2);
-#endif
return 0;
};
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 982604ff6bfd..50c1052cae74 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -912,10 +912,6 @@ static int lo_ioctl(struct inode * inode, struct file * file,
}
err = put_user((u64)loop_sizes[lo->lo_number] << 10, (u64*)arg);
break;
- case BLKBSZGET:
- case BLKBSZSET:
- err = blk_ioctl(inode->i_bdev, cmd, arg);
- break;
default:
err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
}
diff --git a/drivers/block/paride/Makefile b/drivers/block/paride/Makefile
index d62c39cb9b55..b1294e64f414 100644
--- a/drivers/block/paride/Makefile
+++ b/drivers/block/paride/Makefile
@@ -5,14 +5,9 @@
# Rewritten to use lists instead of if-statements.
#
-export-objs := paride.o bpck6.o
+export-objs := paride.o
obj-$(CONFIG_PARIDE) += paride.o
-obj-$(CONFIG_PARIDE_PD) += pd.o
-obj-$(CONFIG_PARIDE_PCD) += pcd.o
-obj-$(CONFIG_PARIDE_PF) += pf.o
-obj-$(CONFIG_PARIDE_PT) += pt.o
-obj-$(CONFIG_PARIDE_PG) += pg.o
obj-$(CONFIG_PARIDE_ATEN) += aten.o
obj-$(CONFIG_PARIDE_BPCK) += bpck.o
obj-$(CONFIG_PARIDE_COMM) += comm.o
@@ -20,13 +15,18 @@ obj-$(CONFIG_PARIDE_DSTR) += dstr.o
obj-$(CONFIG_PARIDE_KBIC) += kbic.o
obj-$(CONFIG_PARIDE_EPAT) += epat.o
obj-$(CONFIG_PARIDE_EPIA) += epia.o
-obj-$(CONFIG_PARIDE_FIT2) += fit2.o
-obj-$(CONFIG_PARIDE_FIT3) += fit3.o
obj-$(CONFIG_PARIDE_FRPW) += frpw.o
obj-$(CONFIG_PARIDE_FRIQ) += friq.o
+obj-$(CONFIG_PARIDE_FIT2) += fit2.o
+obj-$(CONFIG_PARIDE_FIT3) += fit3.o
obj-$(CONFIG_PARIDE_ON20) += on20.o
obj-$(CONFIG_PARIDE_ON26) += on26.o
obj-$(CONFIG_PARIDE_KTTI) += ktti.o
obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o
+obj-$(CONFIG_PARIDE_PD) += pd.o
+obj-$(CONFIG_PARIDE_PCD) += pcd.o
+obj-$(CONFIG_PARIDE_PF) += pf.o
+obj-$(CONFIG_PARIDE_PT) += pt.o
+obj-$(CONFIG_PARIDE_PG) += pg.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/block/paride/aten.c b/drivers/block/paride/aten.c
index b22d34da348a..763fc50d7f76 100644
--- a/drivers/block/paride/aten.c
+++ b/drivers/block/paride/aten.c
@@ -18,6 +18,7 @@
#define ATEN_VERSION "1.01"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/wait.h>
@@ -140,35 +141,33 @@ static void aten_release_proto( PIA *pi )
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol aten = {"aten",0,2,2,1,1,
- aten_write_regr,
- aten_read_regr,
- aten_write_block,
- aten_read_block,
- aten_connect,
- aten_disconnect,
- 0,
- 0,
- 0,
- aten_log_adapter,
- aten_init_proto,
- aten_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &aten ) - 1;
+static struct pi_protocol aten = {
+ .name = "aten",
+ .max_mode = 2,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = aten_write_regr,
+ .read_regr = aten_read_regr,
+ .write_block = aten_write_block,
+ .read_block = aten_read_block,
+ .connect = aten_connect,
+ .disconnect = aten_disconnect,
+ .log_adapter = aten_log_adapter,
+ .init_proto = aten_init_proto,
+ .release_proto = aten_release_proto,
+};
+
+static int __init aten_init(void)
+{
+ return pi_register(&aten)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &aten );
+static void __exit aten_exit(void)
+{
+ pi_unregister( &aten );
}
-#endif
-
-/* end of aten.c */
MODULE_LICENSE("GPL");
+module_init(aten_init)
+module_exit(aten_exit)
diff --git a/drivers/block/paride/bpck.c b/drivers/block/paride/bpck.c
index 3e20e6b7054a..b15ff97fe7af 100644
--- a/drivers/block/paride/bpck.c
+++ b/drivers/block/paride/bpck.c
@@ -17,6 +17,7 @@
#define BPCK_VERSION "1.02"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -452,34 +453,36 @@ static void bpck_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol bpck = { "bpck",0,5,2,4,256,
- bpck_write_regr,
- bpck_read_regr,
- bpck_write_block,
- bpck_read_block,
- bpck_connect,
- bpck_disconnect,
- bpck_test_port,
- bpck_probe_unit,
- bpck_test_proto,
- bpck_log_adapter,
- bpck_init_proto,
- bpck_release_proto
- };
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register(&bpck) - 1;
+static struct pi_protocol bpck = {
+ .name = "bpck",
+ .max_mode = 5,
+ .epp_first = 2,
+ .default_delay = 4,
+ .max_units = 255,
+ .write_regr = bpck_write_regr,
+ .read_regr = bpck_read_regr,
+ .write_block = bpck_write_block,
+ .read_block = bpck_read_block,
+ .connect = bpck_connect,
+ .disconnect = bpck_disconnect,
+ .test_port = bpck_test_port,
+ .probe_unit = bpck_probe_unit,
+ .test_proto = bpck_test_proto,
+ .log_adapter = bpck_log_adapter,
+ .init_proto = bpck_init_proto,
+ .release_proto = bpck_release_proto,
+};
+
+static int __init bpck_init(void)
+{
+ return pi_register(&bpck)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister(&bpck);
+static void __exit bpck_exit(void)
+{
+ pi_unregister(&bpck);
}
-#endif
-
-/* end of bpck.c */
MODULE_LICENSE("GPL");
+module_init(bpck_init)
+module_exit(bpck_exit)
diff --git a/drivers/block/paride/bpck6.c b/drivers/block/paride/bpck6.c
index f2febfcfd268..c1fcdd9f4e94 100644
--- a/drivers/block/paride/bpck6.c
+++ b/drivers/block/paride/bpck6.c
@@ -26,6 +26,7 @@ int verbose=0; /* set this to 1 to see debugging messages and whatnot */
#define BACKPACK_VERSION "2.0.2"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -252,65 +253,41 @@ static void bpck6_release_proto(PIA *pi)
kfree((void *)(pi->private));
}
-struct pi_protocol bpck6 = { "bpck6", /* name for proto*/
- 0, /* index into proto table */
- 5, /* max mode =5 */
- 2, /* 2-5 use epp (need 8 ports) */
- 0, /* no delay (not used anyway) */
- 255, /* we can have units up to 255 */
- bpck6_write_regr,
- bpck6_read_regr,
- bpck6_write_block,
- bpck6_read_block,
- bpck6_connect,
- bpck6_disconnect,
- bpck6_test_port,
- bpck6_probe_unit,
- 0,
- bpck6_log_adapter,
- bpck6_init_proto,
- bpck6_release_proto
- };
-
-
-EXPORT_SYMBOL(bpck6_write_regr);
-EXPORT_SYMBOL(bpck6_read_regr);
-EXPORT_SYMBOL(bpck6_write_block);
-EXPORT_SYMBOL(bpck6_read_block);
-EXPORT_SYMBOL(bpck6_connect);
-EXPORT_SYMBOL(bpck6_disconnect);
-EXPORT_SYMBOL(bpck6_test_port);
-EXPORT_SYMBOL(bpck6_probe_unit);
-EXPORT_SYMBOL(bpck6_log_adapter);
-EXPORT_SYMBOL(bpck6_init_proto);
-EXPORT_SYMBOL(bpck6_release_proto);
-
-/*---------------------------MODULE STUFF-----------------------*/
-
-#ifdef MODULE
-/*module information*/
-
-static int init_module(void)
+static struct pi_protocol bpck6 = {
+ .name = "bpck6",
+ .max_mode = 5,
+ .epp_first = 2, /* 2-5 use epp (need 8 ports) */
+ .max_units = 255,
+ .write_regr = bpck6_write_regr,
+ .read_regr = bpck6_read_regr,
+ .write_block = bpck6_write_block,
+ .read_block = bpck6_read_block,
+ .connect = bpck6_connect,
+ .disconnect = bpck6_disconnect,
+ .test_port = bpck6_test_port,
+ .probe_unit = bpck6_probe_unit,
+ .log_adapter = bpck6_log_adapter,
+ .init_proto = bpck6_init_proto,
+ .release_proto = bpck6_release_proto,
+};
+
+static int __init bpck6_init(void)
{
printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n");
printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n");
-
if(verbose)
- {
printk(KERN_DEBUG "bpck6: verbose debug enabled.\n");
- }
-
return pi_register(&bpck6) - 1;
}
-void cleanup_module(void)
+static void __exit bpck6_exit(void)
{
pi_unregister(&bpck6);
}
+MODULE_LICENSE("GPL");
MODULE_AUTHOR("Micro Solutions Inc.");
MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE");
MODULE_PARM(verbose,"i");
-
-#endif
-
+module_init(bpck6_init)
+module_exit(bpck6_exit)
diff --git a/drivers/block/paride/comm.c b/drivers/block/paride/comm.c
index 058a7d68572c..f3010d6fc73b 100644
--- a/drivers/block/paride/comm.c
+++ b/drivers/block/paride/comm.c
@@ -17,6 +17,7 @@
#define COMM_VERSION "1.01"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -196,35 +197,33 @@ static void comm_release_proto(PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol comm = {"comm",0,5,2,1,1,
- comm_write_regr,
- comm_read_regr,
- comm_write_block,
- comm_read_block,
- comm_connect,
- comm_disconnect,
- 0,
- 0,
- 0,
- comm_log_adapter,
- comm_init_proto,
- comm_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &comm ) - 1;
+static struct pi_protocol comm = {
+ .name = "comm",
+ .max_mode = 5,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = comm_write_regr,
+ .read_regr = comm_read_regr,
+ .write_block = comm_write_block,
+ .read_block = comm_read_block,
+ .connect = comm_connect,
+ .disconnect = comm_disconnect,
+ .log_adapter = comm_log_adapter,
+ .init_proto = comm_init_proto,
+ .release_proto = comm_release_proto,
+};
+
+static int __init comm_init(void)
+{
+ return pi_register(&comm)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &comm );
+static void __exit comm_exit(void)
+{
+ pi_unregister(&comm);
}
-#endif
-
-/* end of comm.c */
MODULE_LICENSE("GPL");
+module_init(comm_init)
+module_exit(comm_exit)
diff --git a/drivers/block/paride/dstr.c b/drivers/block/paride/dstr.c
index 438735b6ce10..204fe75df233 100644
--- a/drivers/block/paride/dstr.c
+++ b/drivers/block/paride/dstr.c
@@ -16,6 +16,7 @@
#define DSTR_VERSION "1.01"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -211,35 +212,33 @@ static void dstr_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol dstr = {"dstr",0,5,2,1,1,
- dstr_write_regr,
- dstr_read_regr,
- dstr_write_block,
- dstr_read_block,
- dstr_connect,
- dstr_disconnect,
- 0,
- 0,
- 0,
- dstr_log_adapter,
- dstr_init_proto,
- dstr_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &dstr ) - 1;
+static struct pi_protocol dstr = {
+ .name = "dstr",
+ .max_mode = 5,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = dstr_write_regr,
+ .read_regr = dstr_read_regr,
+ .write_block = dstr_write_block,
+ .read_block = dstr_read_block,
+ .connect = dstr_connect,
+ .disconnect = dstr_disconnect,
+ .log_adapter = dstr_log_adapter,
+ .init_proto = dstr_init_proto,
+ .release_proto = dstr_release_proto,
+};
+
+static int __init dstr_init(void)
+{
+ return pi_register(&dstr)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &dstr );
+static void __exit dstr_exit(void)
+{
+ pi_unregister(&dstr);
}
-#endif
-
-/* end of dstr.c */
MODULE_LICENSE("GPL");
+module_init(dstr_init)
+module_exit(dstr_exit)
diff --git a/drivers/block/paride/epat.c b/drivers/block/paride/epat.c
index 624a5ba32cfd..0a7126756371 100644
--- a/drivers/block/paride/epat.c
+++ b/drivers/block/paride/epat.c
@@ -19,6 +19,7 @@
#define EPAT_VERSION "1.02"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -311,35 +312,34 @@ static void epat_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol epat = {"epat",0,6,3,1,1,
- epat_write_regr,
- epat_read_regr,
- epat_write_block,
- epat_read_block,
- epat_connect,
- epat_disconnect,
- 0,
- 0,
- epat_test_proto,
- epat_log_adapter,
- epat_init_proto,
- epat_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &epat) - 1;
+static struct pi_protocol epat = {
+ .name = "epat",
+ .max_mode = 6,
+ .epp_first = 3,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = epat_write_regr,
+ .read_regr = epat_read_regr,
+ .write_block = epat_write_block,
+ .read_block = epat_read_block,
+ .connect = epat_connect,
+ .disconnect = epat_disconnect,
+ .test_proto = epat_test_proto,
+ .log_adapter = epat_log_adapter,
+ .init_proto = epat_init_proto,
+ .release_proto = epat_release_proto,
+};
+
+static int __init epat_init(void)
+{
+ return pi_register(&epat)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &epat);
+static void __exit epat_exit(void)
+{
+ pi_unregister(&epat);
}
-#endif
-
-/* end of epat.c */
MODULE_LICENSE("GPL");
+module_init(epat_init)
+module_exit(epat_exit)
diff --git a/drivers/block/paride/epia.c b/drivers/block/paride/epia.c
index c27edd64ecc1..c2728af843dd 100644
--- a/drivers/block/paride/epia.c
+++ b/drivers/block/paride/epia.c
@@ -20,6 +20,7 @@
#define EPIA_VERSION "1.02"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -293,36 +294,34 @@ static void epia_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol epia = {"epia",0,6,3,1,1,
- epia_write_regr,
- epia_read_regr,
- epia_write_block,
- epia_read_block,
- epia_connect,
- epia_disconnect,
- 0,
- 0,
- epia_test_proto,
- epia_log_adapter,
- epia_init_proto,
- epia_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &epia ) - 1;
+static struct pi_protocol epia = {
+ .name = "epia",
+ .max_mode = 6,
+ .epp_first = 3,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = epia_write_regr,
+ .read_regr = epia_read_regr,
+ .write_block = epia_write_block,
+ .read_block = epia_read_block,
+ .connect = epia_connect,
+ .disconnect = epia_disconnect,
+ .test_proto = epia_test_proto,
+ .log_adapter = epia_log_adapter,
+ .init_proto = epia_init_proto,
+ .release_proto = epia_release_proto,
+};
+
+static int __init epia_init(void)
+{
+ return pi_register(&epia)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &epia );
+static void __exit epia_exit(void)
+{
+ pi_unregister(&epia);
}
-#endif
-
-/* end of epia.c */
-
MODULE_LICENSE("GPL");
+module_init(epia_init)
+module_exit(epia_exit)
diff --git a/drivers/block/paride/fit2.c b/drivers/block/paride/fit2.c
index 7f45529c80b1..42b2880a82ac 100644
--- a/drivers/block/paride/fit2.c
+++ b/drivers/block/paride/fit2.c
@@ -16,6 +16,7 @@
#define FIT2_VERSION "1.0"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -129,35 +130,33 @@ static void fit2_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol fit2 = {"fit2",0,1,2,1,1,
- fit2_write_regr,
- fit2_read_regr,
- fit2_write_block,
- fit2_read_block,
- fit2_connect,
- fit2_disconnect,
- 0,
- 0,
- 0,
- fit2_log_adapter,
- fit2_init_proto,
- fit2_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &fit2 ) - 1;
+static struct pi_protocol fit2 = {
+ .name = "fit2",
+ .max_mode = 1,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = fit2_write_regr,
+ .read_regr = fit2_read_regr,
+ .write_block = fit2_write_block,
+ .read_block = fit2_read_block,
+ .connect = fit2_connect,
+ .disconnect = fit2_disconnect,
+ .log_adapter = fit2_log_adapter,
+ .init_proto = fit2_init_proto,
+ .release_proto = fit2_release_proto,
+};
+
+static int __init fit2_init(void)
+{
+ return pi_register(&fit2)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &fit2 );
+static void __exit fit2_exit(void)
+{
+ pi_unregister(&fit2);
}
-#endif
-
-/* end of fit2.c */
MODULE_LICENSE("GPL");
+module_init(fit2_init)
+module_exit(fit2_exit)
diff --git a/drivers/block/paride/fit3.c b/drivers/block/paride/fit3.c
index 8b5ad4bd5ad0..4d9286562c3c 100644
--- a/drivers/block/paride/fit3.c
+++ b/drivers/block/paride/fit3.c
@@ -20,6 +20,7 @@
#define FIT3_VERSION "1.0"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -189,35 +190,33 @@ static void fit3_release_proto(PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol fit3 = {"fit3",0,3,2,1,1,
- fit3_write_regr,
- fit3_read_regr,
- fit3_write_block,
- fit3_read_block,
- fit3_connect,
- fit3_disconnect,
- 0,
- 0,
- 0,
- fit3_log_adapter,
- fit3_init_proto,
- fit3_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &fit3 ) - 1;
+static struct pi_protocol fit3 = {
+ .name = "fit3",
+ .max_mode = 3,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = fit3_write_regr,
+ .read_regr = fit3_read_regr,
+ .write_block = fit3_write_block,
+ .read_block = fit3_read_block,
+ .connect = fit3_connect,
+ .disconnect = fit3_disconnect,
+ .log_adapter = fit3_log_adapter,
+ .init_proto = fit3_init_proto,
+ .release_proto = fit3_release_proto,
+};
+
+static int __init fit3_init(void)
+{
+ return pi_register(&fit3)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &fit3 );
+static void __exit fit3_exit(void)
+{
+ pi_unregister(&fit3);
}
-#endif
-
-/* end of fit3.c */
MODULE_LICENSE("GPL");
+module_init(fit3_init)
+module_exit(fit3_exit)
diff --git a/drivers/block/paride/friq.c b/drivers/block/paride/friq.c
index 74b2eaab1c19..10b994a456da 100644
--- a/drivers/block/paride/friq.c
+++ b/drivers/block/paride/friq.c
@@ -28,6 +28,7 @@
#define FRIQ_VERSION "1.01"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -250,35 +251,34 @@ static void friq_release_proto( PIA *pi)
MOD_DEC_USE_COUNT;
}
-struct pi_protocol friq = {"friq",0,5,2,1,1,
- friq_write_regr,
- friq_read_regr,
- friq_write_block,
- friq_read_block,
- friq_connect,
- friq_disconnect,
- 0,
- 0,
- friq_test_proto,
- friq_log_adapter,
- friq_init_proto,
- friq_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &friq ) - 1;
+static struct pi_protocol friq = {
+ .name = "friq",
+ .max_mode = 5,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = friq_write_regr,
+ .read_regr = friq_read_regr,
+ .write_block = friq_write_block,
+ .read_block = friq_read_block,
+ .connect = friq_connect,
+ .disconnect = friq_disconnect,
+ .test_proto = friq_test_proto,
+ .log_adapter = friq_log_adapter,
+ .init_proto = friq_init_proto,
+ .release_proto = friq_release_proto,
+};
+
+static int __init friq_init(void)
+{
+ return pi_register(&friq)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &friq );
+static void __exit friq_exit(void)
+{
+ pi_unregister(&friq);
}
-#endif
-
-/* end of friq.c */
MODULE_LICENSE("GPL");
+module_init(friq_init)
+module_exit(friq_exit)
diff --git a/drivers/block/paride/frpw.c b/drivers/block/paride/frpw.c
index 817004a3f7dc..ee0cad3807a1 100644
--- a/drivers/block/paride/frpw.c
+++ b/drivers/block/paride/frpw.c
@@ -26,6 +26,7 @@
#define FRPW_VERSION "1.03"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -291,35 +292,34 @@ static void frpw_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol frpw = {"frpw",0,6,2,2,1,
- frpw_write_regr,
- frpw_read_regr,
- frpw_write_block,
- frpw_read_block,
- frpw_connect,
- frpw_disconnect,
- 0,
- 0,
- frpw_test_proto,
- frpw_log_adapter,
- frpw_init_proto,
- frpw_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &frpw ) - 1;
+static struct pi_protocol frpw = {
+ .name = "frpw",
+ .max_mode = 6,
+ .epp_first = 2,
+ .default_delay = 2,
+ .max_units = 1,
+ .write_regr = frpw_write_regr,
+ .read_regr = frpw_read_regr,
+ .write_block = frpw_write_block,
+ .read_block = frpw_read_block,
+ .connect = frpw_connect,
+ .disconnect = frpw_disconnect,
+ .test_proto = frpw_test_proto,
+ .log_adapter = frpw_log_adapter,
+ .init_proto = frpw_init_proto,
+ .release_proto = frpw_release_proto,
+};
+
+static int __init frpw_init(void)
+{
+ return pi_register(&frpw)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &frpw );
+static void __exit frpw_exit(void)
+{
+ pi_unregister(&frpw);
}
-#endif
-
-/* end of frpw.c */
MODULE_LICENSE("GPL");
+module_init(frpw_init)
+module_exit(frpw_exit)
diff --git a/drivers/block/paride/kbic.c b/drivers/block/paride/kbic.c
index 2f20c9b0fa4e..f97233b39b7b 100644
--- a/drivers/block/paride/kbic.c
+++ b/drivers/block/paride/kbic.c
@@ -21,6 +21,7 @@
#define KBIC_VERSION "1.01"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -258,56 +259,51 @@ static void kbic_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol k951 = {"k951",0,6,3,1,1,
- kbic_write_regr,
- kbic_read_regr,
- kbic_write_block,
- kbic_read_block,
- k951_connect,
- k951_disconnect,
- 0,
- 0,
- 0,
- k951_log_adapter,
- kbic_init_proto,
- kbic_release_proto
- };
-
-
-struct pi_protocol k971 = {"k971",0,6,3,1,1,
- kbic_write_regr,
- kbic_read_regr,
- kbic_write_block,
- kbic_read_block,
- k971_connect,
- k971_disconnect,
- 0,
- 0,
- 0,
- k971_log_adapter,
- kbic_init_proto,
- kbic_release_proto
- };
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ int s5,s7;
-
- s5 = pi_register(&k951);
- s7 = pi_register(&k971);
-
- return (s5 || s7) - 1;
+static struct pi_protocol k951 = {
+ .name = "k951",
+ .max_mode = 6,
+ .epp_first = 3,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = kbic_write_regr,
+ .read_regr = kbic_read_regr,
+ .write_block = kbic_write_block,
+ .read_block = kbic_read_block,
+ .connect = k951_connect,
+ .disconnect = k951_disconnect,
+ .log_adapter = k951_log_adapter,
+ .init_proto = kbic_init_proto,
+ .release_proto = kbic_release_proto
+};
+
+static struct pi_protocol k971 = {
+ .name = "k971",
+ .max_mode = 6,
+ .epp_first = 3,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = kbic_write_regr,
+ .read_regr = kbic_read_regr,
+ .write_block = kbic_write_block,
+ .read_block = kbic_read_block,
+ .connect = k971_connect,
+ .disconnect = k971_disconnect,
+ .log_adapter = k971_log_adapter,
+ .init_proto = kbic_init_proto,
+ .release_proto = kbic_release_proto
+};
+
+static int __init kbic_init(void)
+{
+ return (pi_register(&k951)||pi_register(&k971))-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &k951 );
- pi_unregister( &k971 );
+static void __exit kbic_exit(void)
+{
+ pi_unregister(&k951);
+ pi_unregister(&k971);
}
-#endif
-
-/* end of kbic.c */
MODULE_LICENSE("GPL");
+module_init(kbic_init)
+module_exit(kbic_exit)
diff --git a/drivers/block/paride/ktti.c b/drivers/block/paride/ktti.c
index 60778192e0c1..bee083b4da9c 100644
--- a/drivers/block/paride/ktti.c
+++ b/drivers/block/paride/ktti.c
@@ -12,6 +12,7 @@
#define KTTI_VERSION "1.0"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -106,35 +107,33 @@ static void ktti_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol ktti = {"ktti",0,1,2,1,1,
- ktti_write_regr,
- ktti_read_regr,
- ktti_write_block,
- ktti_read_block,
- ktti_connect,
- ktti_disconnect,
- 0,
- 0,
- 0,
- ktti_log_adapter,
- ktti_init_proto,
- ktti_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &ktti ) - 1;
+static struct pi_protocol ktti = {
+ .name = "ktti",
+ .max_mode = 1,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = ktti_write_regr,
+ .read_regr = ktti_read_regr,
+ .write_block = ktti_write_block,
+ .read_block = ktti_read_block,
+ .connect = ktti_connect,
+ .disconnect = ktti_disconnect,
+ .log_adapter = ktti_log_adapter,
+ .init_proto = ktti_init_proto,
+ .release_proto = ktti_release_proto,
+};
+
+static int __init ktti_init(void)
+{
+ return pi_register(&ktti)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &ktti );
+static void __exit ktti_exit(void)
+{
+ pi_unregister(&ktti);
}
-#endif
-
-/* end of ktti.c */
MODULE_LICENSE("GPL");
+module_init(ktti_init)
+module_exit(ktti_exit)
diff --git a/drivers/block/paride/on20.c b/drivers/block/paride/on20.c
index b3c8d3d325e0..8528e0212591 100644
--- a/drivers/block/paride/on20.c
+++ b/drivers/block/paride/on20.c
@@ -15,6 +15,7 @@
#define ON20_VERSION "1.01"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -131,35 +132,33 @@ static void on20_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol on20 = {"on20",0,2,2,1,1,
- on20_write_regr,
- on20_read_regr,
- on20_write_block,
- on20_read_block,
- on20_connect,
- on20_disconnect,
- 0,
- 0,
- 0,
- on20_log_adapter,
- on20_init_proto,
- on20_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &on20 ) - 1;
+static struct pi_protocol on20 = {
+ .name = "on20",
+ .max_mode = 2,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = on20_write_regr,
+ .read_regr = on20_read_regr,
+ .write_block = on20_write_block,
+ .read_block = on20_read_block,
+ .connect = on20_connect,
+ .disconnect = on20_disconnect,
+ .log_adapter = on20_log_adapter,
+ .init_proto = on20_init_proto,
+ .release_proto = on20_release_proto,
+};
+
+static int __init on20_init(void)
+{
+ return pi_register(&on20)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &on20 );
+static void __exit on20_exit(void)
+{
+ pi_unregister(&on20);
}
-#endif
-
-/* end of on20.c */
MODULE_LICENSE("GPL");
+module_init(on20_init)
+module_exit(on20_exit)
diff --git a/drivers/block/paride/on26.c b/drivers/block/paride/on26.c
index 0688c6317972..c08111db5a21 100644
--- a/drivers/block/paride/on26.c
+++ b/drivers/block/paride/on26.c
@@ -19,6 +19,7 @@
#define ON26_VERSION "1.04"
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -296,36 +297,34 @@ static void on26_release_proto( PIA *pi)
{ MOD_DEC_USE_COUNT;
}
-struct pi_protocol on26 = {"on26",0,5,2,1,1,
- on26_write_regr,
- on26_read_regr,
- on26_write_block,
- on26_read_block,
- on26_connect,
- on26_disconnect,
- on26_test_port,
- 0,
- 0,
- on26_log_adapter,
- on26_init_proto,
- on26_release_proto
- };
-
-
-#ifdef MODULE
-
-int init_module(void)
-
-{ return pi_register( &on26 ) - 1;
+static struct pi_protocol on26 = {
+ .name = "on26",
+ .max_mode = 5,
+ .epp_first = 2,
+ .default_delay = 1,
+ .max_units = 1,
+ .write_regr = on26_write_regr,
+ .read_regr = on26_read_regr,
+ .write_block = on26_write_block,
+ .read_block = on26_read_block,
+ .connect = on26_connect,
+ .disconnect = on26_disconnect,
+ .test_port = on26_test_port,
+ .log_adapter = on26_log_adapter,
+ .init_proto = on26_init_proto,
+ .release_proto = on26_release_proto,
+};
+
+static int __init on26_init(void)
+{
+ return pi_register(&on26)-1;
}
-void cleanup_module(void)
-
-{ pi_unregister( &on26 );
+static void __exit on26_exit(void)
+{
+ pi_unregister(&on26);
}
-#endif
-
-/* end of on26.c */
-
MODULE_LICENSE("GPL");
+module_init(on26_init)
+module_exit(on26_exit)
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
index e3a6150acff6..18bd7892269c 100644
--- a/drivers/block/paride/paride.c
+++ b/drivers/block/paride/paride.c
@@ -431,136 +431,3 @@ int pi_init(PIA *pi, int autoprobe, int port, int mode,
}
EXPORT_SYMBOL(pi_init);
-
-#ifdef MODULE
-
-int init_module(void)
-
-{
- int k;
- const char *indicate_pp = "";
-#ifdef CONFIG_PARPORT
- indicate_pp = " (parport)";
-#endif
-
- for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0;
-
- printk("paride: version %s installed%s\n",PI_VERSION,indicate_pp);
- return 0;
-}
-
-void cleanup_module(void)
-
-{
-}
-
-#else
-
-void paride_init( void )
-
-{
-
-#ifdef CONFIG_PARIDE_ATEN
- { extern struct pi_protocol aten;
- pi_register(&aten);
- };
-#endif
-#ifdef CONFIG_PARIDE_BPCK
- { extern struct pi_protocol bpck;
- pi_register(&bpck);
- };
-#endif
-#ifdef CONFIG_PARIDE_COMM
- { extern struct pi_protocol comm;
- pi_register(&comm);
- };
-#endif
-#ifdef CONFIG_PARIDE_DSTR
- { extern struct pi_protocol dstr;
- pi_register(&dstr);
- };
-#endif
-#ifdef CONFIG_PARIDE_EPAT
- { extern struct pi_protocol epat;
- pi_register(&epat);
- };
-#endif
-#ifdef CONFIG_PARIDE_EPIA
- { extern struct pi_protocol epia;
- pi_register(&epia);
- };
-#endif
-#ifdef CONFIG_PARIDE_FRPW
- { extern struct pi_protocol frpw;
- pi_register(&frpw);
- };
-#endif
-#ifdef CONFIG_PARIDE_FRIQ
- { extern struct pi_protocol friq;
- pi_register(&friq);
- };
-#endif
-#ifdef CONFIG_PARIDE_FIT2
- { extern struct pi_protocol fit2;
- pi_register(&fit2);
- };
-#endif
-#ifdef CONFIG_PARIDE_FIT3
- { extern struct pi_protocol fit3;
- pi_register(&fit3);
- };
-#endif
-#ifdef CONFIG_PARIDE_KBIC
- { extern struct pi_protocol k951;
- extern struct pi_protocol k971;
- pi_register(&k951);
- pi_register(&k971);
- };
-#endif
-#ifdef CONFIG_PARIDE_KTTI
- { extern struct pi_protocol ktti;
- pi_register(&ktti);
- };
-#endif
-#ifdef CONFIG_PARIDE_ON20
- { extern struct pi_protocol on20;
- pi_register(&on20);
- };
-#endif
-#ifdef CONFIG_PARIDE_ON26
- { extern struct pi_protocol on26;
- pi_register(&on26);
- };
-#endif
-
-#ifdef CONFIG_PARIDE_PD
- { extern int pd_init(void);
- pd_init();
- };
-#endif
-#ifdef CONFIG_PARIDE_PCD
- { extern int pcd_init(void);
- pcd_init();
- };
-#endif
-#ifdef CONFIG_PARIDE_PF
- { extern int pf_init(void);
- pf_init();
- };
-#endif
-#ifdef CONFIG_PARIDE_PT
- { extern int pt_init(void);
- pt_init();
- };
-#endif
-#ifdef CONFIG_PARIDE_PG
- { extern int pg_init(void);
- pg_init();
- };
-#endif
-}
-
-#endif
-
-/* end of paride.c */
-MODULE_LICENSE("GPL");
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index e9839726b20e..25273d4ba1b8 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -137,6 +137,7 @@ static int pcd_drive_count;
/* end of parameters */
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -200,9 +201,6 @@ MODULE_PARM(drive3,"1-6i");
#define IDE_READY 0x40
#define IDE_BUSY 0x80
-int pcd_init(void);
-void cleanup_module( void );
-
static int pcd_open(struct cdrom_device_info *cdi, int purpose);
static void pcd_release(struct cdrom_device_info *cdi);
static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
@@ -327,84 +325,18 @@ static void pcd_init_units( void )
}
}
-int pcd_init (void) /* preliminary initialisation */
-{
- int unit;
-
- if (disable) return -1;
-
- pcd_init_units();
-
- if (pcd_detect()) return -1;
-
- /* get the atapi capabilities page */
- pcd_probe_capabilities();
-
- if (register_blkdev(MAJOR_NR,name,&pcd_bdops)) {
- printk("pcd: unable to get major number %d\n",MAJOR_NR);
- return -1;
- }
-
- for (unit=0;unit<PCD_UNITS;unit++) {
- if (PCD.present) {
- register_cdrom(&PCD.info);
- devfs_plain_cdrom(&PCD.info, &pcd_bdops);
- }
- }
-
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_pcd_request, &pcd_lock);
-
- return 0;
-}
-
static int pcd_open(struct cdrom_device_info *cdi, int purpose)
-
-{ int unit = DEVICE_NR(cdi->dev);
-
- if ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
-
+{
+ int unit = DEVICE_NR(cdi->dev);
+ if ((unit >= PCD_UNITS) || (!PCD.present))
+ return -ENODEV;
return 0;
}
static void pcd_release(struct cdrom_device_info *cdi)
-
{
}
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-int init_module(void)
-
-{ int err;
-
-#ifdef PARIDE_JUMBO
- { extern paride_init();
- paride_init();
- }
-#endif
-
- err = pcd_init();
-
- return err;
-}
-
-void cleanup_module(void)
-
-{ int unit;
-
- for (unit=0;unit<PCD_UNITS;unit++)
- if (PCD.present) {
- pi_release(PI);
- unregister_cdrom(&PCD.info);
- }
-
- unregister_blkdev(MAJOR_NR,name);
-}
-
-#endif
-
#define WR(c,r,v) pi_write_regr(PI,c,r,v)
#define RR(c,r) (pi_read_regr(PI,c,r))
@@ -950,6 +882,50 @@ static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
return 0;
}
-/* end of pcd.c */
+
+static int __init pcd_init(void)
+{
+ int unit;
+
+ if (disable)
+ return -1;
+
+ pcd_init_units();
+
+ if (pcd_detect())
+ return -1;
+
+ /* get the atapi capabilities page */
+ pcd_probe_capabilities();
+
+ if (register_blkdev(MAJOR_NR,name,&pcd_bdops)) {
+ printk("pcd: unable to get major number %d\n",MAJOR_NR);
+ return -1;
+ }
+
+ for (unit=0;unit<PCD_UNITS;unit++) {
+ if (PCD.present) {
+ register_cdrom(&PCD.info);
+ devfs_plain_cdrom(&PCD.info, &pcd_bdops);
+ }
+ }
+
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_pcd_request, &pcd_lock);
+
+ return 0;
+}
+
+static void __exit pcd_exit(void)
+{
+ int unit;
+ for (unit=0;unit<PCD_UNITS;unit++)
+ if (PCD.present) {
+ pi_release(PI);
+ unregister_cdrom(&PCD.info);
+ }
+ unregister_blkdev(MAJOR_NR,name);
+}
MODULE_LICENSE("GPL");
+module_init(pcd_init)
+module_exit(pcd_exit)
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index cb10da16d136..f9b681ac6b86 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -153,16 +153,12 @@ static int pd_drive_count;
/* end of parameters */
+#include <linux/init.h>
#include <linux/module.h>
-#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/cdrom.h> /* for the eject ioctl */
-#include <linux/spinlock.h>
#include <asm/uaccess.h>
@@ -181,8 +177,8 @@ static STT pd_stt[7] = {{"drive0",8,drive0},
{"nice",1,&nice}};
void pd_setup( char *str, int *ints)
-
-{ generic_setup(pd_stt,7,str);
+{
+ generic_setup(pd_stt,7,str);
}
#endif
@@ -199,19 +195,15 @@ MODULE_PARM(drive3,"1-8i");
#include "paride.h"
-#define PD_BITS 4
-
-/* set up defines for blk.h, why don't all drivers do it this way ? */
-
#define MAJOR_NR major
-#define DEVICE_NR(device) (minor(device)>>PD_BITS)
-#define DEVICE_OFF(device)
#include <linux/blk.h>
#include <linux/blkpg.h>
#include "pseudo.h"
+#define PD_BITS 4
+#define DEVICE_NR(device) (minor(device)>>PD_BITS)
#define PD_PARTNS (1<<PD_BITS)
#define PD_DEVS PD_PARTNS*PD_UNITS
@@ -258,11 +250,7 @@ MODULE_PARM(drive3,"1-8i");
#define IDE_IDENTIFY 0xec
#define IDE_EJECT 0xed
-int pd_init(void);
void pd_setup(char * str, int * ints);
-#ifdef MODULE
-void cleanup_module( void );
-#endif
static int pd_open(struct inode *inode, struct file *file);
static void do_pd_request(request_queue_t * q);
static int pd_ioctl(struct inode *inode,struct file *file,
@@ -296,6 +284,7 @@ struct pd_unit {
int heads; /* physical geometry */
int sectors;
int cylinders;
+ int can_lba;
int drive; /* master=0 slave=1 */
int changed; /* Have we seen a disk change ? */
int removable; /* removable media device ? */
@@ -303,7 +292,7 @@ struct pd_unit {
int alt_geom;
int present;
char name[PD_NAMELEN]; /* pda, pdb, etc ... */
- };
+};
struct pd_unit pd[PD_UNITS];
@@ -312,7 +301,6 @@ struct pd_unit pd[PD_UNITS];
#define PD pd[unit]
#define PI PD.pi
-static int pd_valid = 1; /* serialise partition checks */
static char pd_scratch[512]; /* scratch block buffer */
/* the variables below are used mainly in the I/O request engine, which
@@ -379,47 +367,12 @@ void pd_init_units( void )
}
}
-int pd_init (void)
-{
- request_queue_t * q;
-
- if (disable) return -1;
- if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) {
- printk("%s: unable to get major number %d\n",
- name,major);
- return -1;
- }
- q = BLK_DEFAULT_QUEUE(MAJOR_NR);
- blk_init_queue(q, do_pd_request, &pd_lock);
- blk_queue_max_sectors(q, cluster);
-
- pd_gendisk.major = major;
- pd_gendisk.major_name = name;
- add_gendisk(&pd_gendisk);
-
- printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
- name,name,PD_VERSION,major,cluster,nice);
- pd_init_units();
- pd_valid = 0;
- pd_gendisk.nr_real = pd_detect();
- pd_valid = 1;
-
-#ifdef MODULE
- if (!pd_gendisk.nr_real) {
- cleanup_module();
- return -1;
- }
-#endif
- return 0;
-}
-
static int pd_open (struct inode *inode, struct file *file)
+{
+ int unit = DEVICE_NR(inode->i_rdev);
-{ int unit = DEVICE_NR(inode->i_rdev);
-
- if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
-
- wait_event (pd_wait_open, pd_valid);
+ if ((unit >= PD_UNITS) || (!PD.present))
+ return -ENODEV;
PD.access++;
@@ -434,11 +387,8 @@ static int pd_ioctl(struct inode *inode,struct file *file,
unsigned int cmd, unsigned long arg)
{
struct hd_geometry *geo = (struct hd_geometry *) arg;
- int err, unit;
+ int err, unit = DEVICE_NR(inode->i_rdev);
- if (!inode || kdev_none(inode->i_rdev))
- return -EINVAL;
- unit = DEVICE_NR(inode->i_rdev);
if (!PD.present)
return -ENODEV;
@@ -461,50 +411,34 @@ static int pd_ioctl(struct inode *inode,struct file *file,
put_user(PD.heads, (char *) &geo->heads);
put_user(PD.sectors, (char *) &geo->sectors);
}
- put_user(get_start_sect(inode->i_rdev), (long *)&geo->start);
+ put_user(get_start_sect(inode->i_bdev), (long *)&geo->start);
return 0;
case BLKRRPART:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
return pd_revalidate(inode->i_rdev);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
default:
return -EINVAL;
}
}
static int pd_release (struct inode *inode, struct file *file)
+{
+ int unit = DEVICE_NR(inode->i_rdev);
-{ kdev_t devp;
- int unit;
-
- devp = inode->i_rdev;
- unit = DEVICE_NR(devp);
-
- if ((unit >= PD_UNITS) || (PD.access <= 0))
- return -EINVAL;
-
- PD.access--;
-
- if (!PD.access && PD.removable)
+ if (!--PD.access && PD.removable)
pd_doorlock(unit,IDE_DOORUNLOCK);
return 0;
}
static int pd_check_media( kdev_t dev)
-
-{ int r, unit;
-
- unit = DEVICE_NR(dev);
- if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
- if (!PD.removable) return 0;
+{
+ int r, unit = DEVICE_NR(dev);
+ if ((unit >= PD_UNITS) || (!PD.present))
+ return -ENODEV;
+ if (!PD.removable)
+ return 0;
pd_media_check(unit);
r = PD.changed;
PD.changed = 0;
@@ -513,64 +447,26 @@ static int pd_check_media( kdev_t dev)
static int pd_revalidate(kdev_t dev)
{
- int unit, res;
- long flags;
+ int unit = DEVICE_NR(dev);
+ kdev_t device = mk_kdev(MAJOR_NR, unit << PD_BITS);
+ int res;
- unit = DEVICE_NR(dev);
if ((unit >= PD_UNITS) || !PD.present)
return -ENODEV;
- save_flags(flags);
- cli();
- if (PD.access > 1) {
- restore_flags(flags);
- return -EBUSY;
- }
- pd_valid = 0;
- restore_flags(flags);
-
- res = wipe_partitions(dev);
+ res = dev_lock_part(device);
+ if (res < 0)
+ return res;
+ res = wipe_partitions(device);
if (res == 0 && pd_identify(unit))
- grok_partitions(dev, PD.capacity);
+ grok_partitions(device, PD.capacity);
- pd_valid = 1;
- wake_up(&pd_wait_open);
+ dev_unlock_part(device);
return res;
}
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-void cleanup_module(void);
-
-int init_module(void)
-
-{
-
-#ifdef PARIDE_JUMBO
- { extern paride_init();
- paride_init();
- }
-#endif
- return pd_init();
-}
-
-void cleanup_module(void)
-{
- int unit;
-
- devfs_unregister_blkdev(MAJOR_NR, name);
- del_gendisk(&pd_gendisk);
-
- for (unit=0; unit<PD_UNITS; unit++)
- if (PD.present)
- pi_release(PI);
-}
-#endif
-
#define WR(c,r,v) pi_write_regr(PI,c,r,v)
#define RR(c,r) (pi_read_regr(PI,c,r))
@@ -619,7 +515,6 @@ static int pd_wait_for( int unit, int w, char * msg ) /* polled wait */
static void pd_send_command( int unit, int n, int s, int h,
int c0, int c1, int func )
-
{
WR(0,6,DRIVE+h);
WR(0,1,0); /* the IDE task file */
@@ -633,16 +528,20 @@ static void pd_send_command( int unit, int n, int s, int h,
}
static void pd_ide_command( int unit, int func, int block, int count )
-
-/* Don't use this call if the capacity is zero. */
-
-{ int c1, c0, h, s;
-
- s = ( block % PD.sectors) + 1;
- h = ( block / PD.sectors) % PD.heads;
- c0 = ( block / (PD.sectors*PD.heads)) % 256;
- c1 = ( block / (PD.sectors*PD.heads*256));
-
+{
+ int c1, c0, h, s;
+
+ if (PD.can_lba) {
+ s = block & 255;
+ c0 = (block >>= 8) & 255;
+ c1 = (block >>= 8) & 255;
+ h = ((block >>= 8) & 15) + 0x40;
+ } else {
+ s = ( block % PD.sectors) + 1;
+ h = ( block /= PD.sectors) % PD.heads;
+ c0 = ( block /= PD.heads) % 256;
+ c1 = (block >>= 8);
+ }
pd_send_command(unit,count,s,h,c0,c1,func);
}
@@ -742,10 +641,14 @@ static int pd_identify( int unit )
}
pi_read_block(PI,pd_scratch,512);
pi_disconnect(PI);
- PD.sectors = word_val(6);
- PD.heads = word_val(3);
- PD.cylinders = word_val(1);
- PD.capacity = PD.sectors*PD.heads*PD.cylinders;
+ PD.can_lba = pd_scratch[99] & 2;
+ PD.sectors = le16_to_cpu(*(u16*)(pd_scratch+12));
+ PD.heads = le16_to_cpu(*(u16*)(pd_scratch+6));
+ PD.cylinders = le16_to_cpu(*(u16*)(pd_scratch+2));
+ if (PD.can_lba)
+ PD.capacity = le32_to_cpu(*(u32*)(pd_scratch + 120));
+ else
+ PD.capacity = PD.sectors*PD.heads*PD.cylinders;
for(j=0;j<PD_ID_LEN;j++) id[j^1] = pd_scratch[j+PD_ID_OFF];
j = PD_ID_LEN-1;
@@ -763,7 +666,7 @@ static int pd_identify( int unit )
if (PD.capacity) pd_init_dev_parms(unit);
if (!PD.standby) pd_standby_off(unit);
-
+
return 1;
}
@@ -1031,6 +934,50 @@ static void do_pd_write_done( void )
spin_unlock_irqrestore(&pd_lock,saved_flags);
}
-/* end of pd.c */
+static int __init pd_init(void)
+{
+ request_queue_t * q;
+ int unit;
+
+ if (disable) return -1;
+ if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) {
+ printk("%s: unable to get major number %d\n",
+ name,major);
+ return -1;
+ }
+ q = BLK_DEFAULT_QUEUE(MAJOR_NR);
+ blk_init_queue(q, do_pd_request, &pd_lock);
+ blk_queue_max_sectors(q, cluster);
+
+ pd_gendisk.major = major;
+ pd_gendisk.major_name = name;
+ add_gendisk(&pd_gendisk);
+
+ printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
+ name,name,PD_VERSION,major,cluster,nice);
+ pd_init_units();
+ pd_gendisk.nr_real = pd_detect();
+ if (!pd_gendisk.nr_real) {
+ devfs_unregister_blkdev(MAJOR_NR, name);
+ del_gendisk(&pd_gendisk);
+ for (unit=0; unit<PD_UNITS; unit++)
+ if (PD.present)
+ pi_release(PI);
+ return -1;
+ }
+ return 0;
+}
+
+static void __exit pd_exit(void)
+{
+ int unit;
+ devfs_unregister_blkdev(MAJOR_NR, name);
+ del_gendisk(&pd_gendisk);
+ for (unit=0; unit<PD_UNITS; unit++)
+ if (PD.present)
+ pi_release(PI);
+}
MODULE_LICENSE("GPL");
+module_init(pd_init)
+module_exit(pd_exit)
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 578feaadbb38..a117aa6df61a 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -153,11 +153,9 @@ static int pf_drive_count;
#include <linux/module.h>
-#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/cdrom.h>
#include <linux/spinlock.h>
@@ -240,7 +238,6 @@ MODULE_PARM(drive3,"1-7i");
#define ATAPI_READ_10 0x28
#define ATAPI_WRITE_10 0x2a
-int pf_init(void);
#ifdef MODULE
void cleanup_module( void );
#endif
@@ -337,34 +334,6 @@ void pf_init_units( void )
}
}
-int pf_init (void) /* preliminary initialisation */
-
-{ int i;
- request_queue_t * q;
-
- if (disable) return -1;
-
- pf_init_units();
-
- if (pf_detect()) return -1;
- pf_busy = 0;
-
- if (register_blkdev(MAJOR_NR,name,&pf_fops)) {
- printk("pf_init: unable to get major number %d\n",
- major);
- return -1;
- }
- q = BLK_DEFAULT_QUEUE(MAJOR_NR);
- blk_init_queue(q, do_pf_request, &pf_spin_lock);
- blk_queue_max_phys_segments(q, cluster);
- blk_queue_max_hw_segments(q, cluster);
-
- for (i=0;i<PF_UNITS;i++)
- register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &pf_fops, 0);
-
- return 0;
-}
-
static int pf_open (struct inode *inode, struct file *file)
{ int unit = DEVICE_NR(inode->i_rdev);
@@ -423,10 +392,6 @@ static int pf_ioctl(struct inode *inode,struct file *file,
return put_user(PF.capacity,(long *) arg);
case BLKGETSIZE64:
return put_user((u64)PF.capacity << 9,(u64 *)arg);
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- return blk_ioctl(inode->i_bdev, cmd, arg);
default:
return -EINVAL;
}
@@ -458,39 +423,6 @@ static int pf_check_media( kdev_t dev)
{ return 1;
}
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-void cleanup_module(void);
-
-int init_module(void)
-
-{ int err;
-
-#ifdef PARIDE_JUMBO
- { extern paride_init();
- paride_init();
- }
-#endif
-
- err = pf_init();
-
- return err;
-}
-
-void cleanup_module(void)
-
-{ int unit;
-
- unregister_blkdev(MAJOR_NR,name);
-
- for (unit=0;unit<PF_UNITS;unit++)
- if (PF.present) pi_release(PI);
-}
-
-#endif
-
#define WR(c,r,v) pi_write_regr(PI,c,r,v)
#define RR(c,r) (pi_read_regr(PI,c,r))
@@ -1040,6 +972,44 @@ static void do_pf_write_done( void )
spin_unlock_irqrestore(&pf_spin_lock,saved_flags);
}
-/* end of pf.c */
+static int __init pf_init(void) /* preliminary initialisation */
+{
+ int i;
+ request_queue_t * q;
+
+ if (disable)
+ return -1;
+
+ pf_init_units();
+
+ if (pf_detect())
+ return -1;
+ pf_busy = 0;
+
+ if (register_blkdev(MAJOR_NR,name,&pf_fops)) {
+ printk("pf_init: unable to get major number %d\n", major);
+ return -1;
+ }
+ q = BLK_DEFAULT_QUEUE(MAJOR_NR);
+ blk_init_queue(q, do_pf_request, &pf_spin_lock);
+ blk_queue_max_phys_segments(q, cluster);
+ blk_queue_max_hw_segments(q, cluster);
+
+ for (i=0;i<PF_UNITS;i++)
+ register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &pf_fops, 0);
+ return 0;
+}
+
+static void __exit pf_exit(void)
+{
+ int unit;
+ unregister_blkdev(MAJOR_NR,name);
+ for (unit=0;unit<PF_UNITS;unit++)
+ if (PF.present)
+ pi_release(PI);
+}
+
MODULE_LICENSE("GPL");
+module_init(pf_init)
+module_exit(pf_exit)
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 5f5af68fc86c..0a43b4a5d61b 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -162,16 +162,13 @@ static int pg_drive_count;
#include <linux/module.h>
-#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/fs.h>
#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mtio.h>
#include <linux/pg.h>
-#include <linux/wait.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -218,11 +215,6 @@ MODULE_PARM(drive3,"1-6i");
#define ATAPI_IDENTIFY 0x12
-int pg_init(void);
-#ifdef MODULE
-void cleanup_module( void );
-#endif
-
static int pg_open(struct inode *inode, struct file *file);
static int pg_release (struct inode *inode, struct file *file);
static ssize_t pg_read(struct file * filp, char * buf,
@@ -291,64 +283,6 @@ void pg_init_units( void )
static devfs_handle_t devfs_handle;
-int pg_init (void) /* preliminary initialisation */
-
-{ int unit;
-
- if (disable) return -1;
-
- pg_init_units();
-
- if (pg_detect()) return -1;
-
- if (devfs_register_chrdev(major,name,&pg_fops)) {
- printk("pg_init: unable to get major number %d\n",
- major);
- for (unit=0;unit<PG_UNITS;unit++)
- if (PG.present) pi_release(PI);
- return -1;
- }
- devfs_handle = devfs_mk_dir (NULL, "pg", NULL);
- devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
- major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
- &pg_fops, NULL);
- return 0;
-}
-
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-void cleanup_module(void);
-
-int init_module(void)
-
-{ int err;
-
-#ifdef PARIDE_JUMBO
- { extern paride_init();
- paride_init();
- }
-#endif
-
- err = pg_init();
-
- return err;
-}
-
-void cleanup_module(void)
-
-{ int unit;
-
- devfs_unregister (devfs_handle);
- devfs_unregister_chrdev(major,name);
-
- for (unit=0;unit<PG_UNITS;unit++)
- if (PG.present) pi_release(PI);
-}
-
-#endif
-
#define WR(c,r,v) pi_write_regr(PI,c,r,v)
#define RR(c,r) (pi_read_regr(PI,c,r))
@@ -691,6 +625,43 @@ static ssize_t pg_read(struct file * filp, char * buf,
return copy+hs;
}
-/* end of pg.c */
+static int __init pg_init(void)
+{
+ int unit;
+
+ if (disable)
+ return -1;
+
+ pg_init_units();
+
+ if (pg_detect())
+ return -1;
+
+ if (devfs_register_chrdev(major,name,&pg_fops)) {
+ printk("pg_init: unable to get major number %d\n",
+ major);
+ for (unit=0;unit<PG_UNITS;unit++)
+ if (PG.present) pi_release(PI);
+ return -1;
+ }
+ devfs_handle = devfs_mk_dir (NULL, "pg", NULL);
+ devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
+ major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
+ &pg_fops, NULL);
+ return 0;
+}
+
+static void __exit pg_exit(void)
+{
+ int unit;
+
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev(major,name);
+
+ for (unit=0;unit<PG_UNITS;unit++)
+ if (PG.present) pi_release(PI);
+}
MODULE_LICENSE("GPL");
+module_init(pg_init)
+module_exit(pg_exit)
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index ccf3db7b1463..bc987791fd32 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -141,15 +141,12 @@ static int pt_drive_count;
#include <linux/module.h>
-#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/fs.h>
#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mtio.h>
-#include <linux/wait.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -209,11 +206,6 @@ MODULE_PARM(drive3,"1-6i");
#define ATAPI_MODE_SENSE 0x1a
#define ATAPI_LOG_SENSE 0x4d
-int pt_init(void);
-#ifdef MODULE
-void cleanup_module( void );
-#endif
-
static int pt_open(struct inode *inode, struct file *file);
static int pt_ioctl(struct inode *inode,struct file *file,
unsigned int cmd, unsigned long arg);
@@ -291,71 +283,9 @@ void pt_init_units( void )
PT.name[j] = 0;
if (DU[D_PRT]) pt_drive_count++;
}
-}
-
-static devfs_handle_t devfs_handle;
-
-int pt_init (void) /* preliminary initialisation */
-
-{ int unit;
-
- if (disable) return -1;
-
- pt_init_units();
-
- if (pt_detect()) return -1;
-
- if (devfs_register_chrdev(major,name,&pt_fops)) {
- printk("pt_init: unable to get major number %d\n",
- major);
- for (unit=0;unit<PT_UNITS;unit++)
- if (PT.present) pi_release(PI);
- return -1;
- }
-
- devfs_handle = devfs_mk_dir (NULL, "pt", NULL);
- devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
- major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
- &pt_fops, NULL);
- devfs_register_series (devfs_handle, "%un", 4, DEVFS_FL_DEFAULT,
- major, 128, S_IFCHR | S_IRUSR | S_IWUSR,
- &pt_fops, NULL);
- return 0;
}
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-void cleanup_module(void);
-
-int init_module(void)
-
-{ int err;
-
-#ifdef PARIDE_JUMBO
- { extern paride_init();
- paride_init();
- }
-#endif
-
- err = pt_init();
-
- return err;
-}
-
-void cleanup_module(void)
-
-{ int unit;
-
- devfs_unregister (devfs_handle);
- devfs_unregister_chrdev(major,name);
-
- for (unit=0;unit<PT_UNITS;unit++)
- if (PT.present) pi_release(PI);
-}
-
-#endif
+static devfs_handle_t devfs_handle;
#define WR(c,r,v) pi_write_regr(PI,c,r,v)
#define RR(c,r) (pi_read_regr(PI,c,r))
@@ -965,6 +895,46 @@ static ssize_t pt_write(struct file * filp, const char * buf,
return t;
}
-/* end of pt.c */
+static int __init pt_init(void)
+{
+ int unit;
+
+ if (disable)
+ return -1;
+
+ pt_init_units();
+
+ if (pt_detect())
+ return -1;
+
+ if (devfs_register_chrdev(major,name,&pt_fops)) {
+ printk("pt_init: unable to get major number %d\n",
+ major);
+ for (unit=0;unit<PT_UNITS;unit++)
+ if (PT.present) pi_release(PI);
+ return -1;
+ }
+
+ devfs_handle = devfs_mk_dir (NULL, "pt", NULL);
+ devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
+ major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
+ &pt_fops, NULL);
+ devfs_register_series (devfs_handle, "%un", 4, DEVFS_FL_DEFAULT,
+ major, 128, S_IFCHR | S_IRUSR | S_IWUSR,
+ &pt_fops, NULL);
+ return 0;
+}
+
+static void __exit pt_exit(void)
+{
+ int unit;
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev(major,name);
+ for (unit=0;unit<PT_UNITS;unit++)
+ if (PT.present)
+ pi_release(PI);
+}
MODULE_LICENSE("GPL");
+module_init(pt_init)
+module_exit(pt_exit)
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index bd604cee4663..1d734f15cab2 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -93,8 +93,6 @@ static void ps2esdi_geometry_int_handler(u_int);
static int ps2esdi_open(struct inode *inode, struct file *file);
-static int ps2esdi_release(struct inode *inode, struct file *file);
-
static int ps2esdi_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg);
@@ -111,11 +109,8 @@ static void ps2esdi_reset_timer(unsigned long unused);
static u_int dma_arb_level; /* DMA arbitration level */
static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int);
-static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open);
static int no_int_yet;
-static int access_count[MAX_HD];
-static char ps2esdi_valid[MAX_HD];
static int ps2esdi_sizes[MAX_HD << 6];
static int ps2esdi_drives;
static struct hd_struct ps2esdi[MAX_HD << 6];
@@ -152,7 +147,6 @@ static struct block_device_operations ps2esdi_fops =
{
owner: THIS_MODULE,
open: ps2esdi_open,
- release: ps2esdi_release,
ioctl: ps2esdi_ioctl,
};
@@ -441,13 +435,11 @@ static int __init ps2esdi_geninit(void)
}
blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128);
- for (i = 0; i < ps2esdi_drives; i++) {
+ for (i = 0; i < ps2esdi_drives; i++)
register_disk(&ps2esdi_gendisk,mk_kdev(MAJOR_NR,i<<6),1<<6,
&ps2esdi_fops,
ps2esdi_info[i].head * ps2esdi_info[i].sect *
ps2esdi_info[i].cyl);
- ps2esdi_valid[i] = 1;
- }
return 0;
err_out3:
@@ -1083,32 +1075,11 @@ static void dump_cmd_complete_status(u_int int_ret_code)
static int ps2esdi_open(struct inode *inode, struct file *file)
{
int dev = DEVICE_NR(inode->i_rdev);
-
- if (dev < ps2esdi_drives) {
- while (!ps2esdi_valid[dev])
- sleep_on(&ps2esdi_wait_open);
-
- access_count[dev]++;
-
- return (0);
- } else
- return (-ENODEV);
-}
-
-
-
-static int ps2esdi_release(struct inode *inode, struct file *file)
-{
- int dev = DEVICE_NR(inode->i_rdev);
-
- if (dev < ps2esdi_drives) {
- access_count[dev]--;
- }
+ if (dev >= ps2esdi_drives)
+ return -ENODEV;
return 0;
}
-
-
static int ps2esdi_ioctl(struct inode *inode,
struct file *file, u_int cmd, u_long arg)
{
@@ -1125,7 +1096,7 @@ static int ps2esdi_ioctl(struct inode *inode,
put_user(ps2esdi_info[dev].head, (char *) &geometry->heads);
put_user(ps2esdi_info[dev].sect, (char *) &geometry->sectors);
put_user(ps2esdi_info[dev].cyl, (short *) &geometry->cylinders);
- put_user(get_start_sect(inode->i_rdev),
+ put_user(get_start_sect(inode->b_rdev),
(long *) &geometry->start);
return 0;
@@ -1136,16 +1107,6 @@ static int ps2esdi_ioctl(struct inode *inode,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
return (ps2esdi_reread_partitions(inode->i_rdev));
-
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- case BLKBSZGET:
- case BLKBSZSET:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
}
return (-EINVAL);
}
@@ -1155,24 +1116,20 @@ static int ps2esdi_ioctl(struct inode *inode,
static int ps2esdi_reread_partitions(kdev_t dev)
{
int target = DEVICE_NR(dev);
- int res;
+ kdev_t device = mk_kdev(MAJOR_NR, target << 6);
+ int res = dev_lock_part(device);
- cli();
- ps2esdi_valid[target] = (access_count[target] != 1);
- sti();
- if (ps2esdi_valid[target])
- return (-EBUSY);
+ if (res < 0)
+ return res;
- res = wipe_partitions(dev);
+ res = wipe_partitions(device);
if (res == 0)
- grok_partitions(dev, ps2esdi_info[target].head
+ grok_partitions(device, ps2esdi_info[target].head
* ps2esdi_info[target].cyl
* ps2esdi_info[target].sect);
- ps2esdi_valid[target] = 1;
- wake_up(&ps2esdi_wait_open);
-
- return (res);
+ dev_unlock_part(device);
+ return res;
}
static void ps2esdi_reset_timer(unsigned long unused)
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 7b60e75d5584..662020429ba6 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -303,12 +303,6 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
up(&inode->i_bdev->bd_sem);
break;
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKSSZGET:
- error = blk_ioctl(inode->i_bdev, cmd, arg);
}
out:
return error;
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index e046885bb67b..a1575eb830b0 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -65,7 +65,7 @@
#define MM_BLKSIZE 1024 /* 1k blocks */
#define MM_HARDSECT 512 /* 512-byte hardware sectors */
#define MM_SHIFT 6 /* max 64 partitions on 4 cards */
-#define DEVICE_NR(device) (MINOR(device)>>MM_SHIFT)
+#define DEVICE_NR(device) (minor(device)>>MM_SHIFT)
/*
* Version Information
@@ -150,7 +150,6 @@ struct cardinfo {
unsigned long last_change;
} battery[2];
- atomic_t usage;
spinlock_t lock;
int check_batteries;
@@ -813,31 +812,21 @@ static void del_battery_timer(void)
* Note no locks taken out here. In a worst case scenario, we could drop
* a chunk of system memory. But that should never happen, since validation
* happens at open or mount time, when locks are held.
+ *
+ * That's crap, since doing that while some partitions are opened
+ * or mounted will give you really nasty results.
*/
static int mm_revalidate(kdev_t i_rdev)
{
- int i;
-
- int card_number = DEVICE_NR(kdev_val(i_rdev));
- /* first partition, # of partitions */
- int part1 = (card_number << MM_SHIFT) + 1;
- int npart = (1 << MM_SHIFT) -1;
-
- /* first clear old partition information */
- for (i=0; i<npart ;i++) {
- mm_gendisk.sizes[part1+i]=0;
- mm_gendisk.part[part1+i].start_sect = 0;
- mm_gendisk.part[part1+i].nr_sects = 0;
- }
-
- mm_gendisk.part[card_number << MM_SHIFT].nr_sects =
- cards[card_number].mm_size << 1;
-
-
- /* then fill new info */
+ int card_number = DEVICE_NR(i_rdev);
+ kdev_t device = mk_mdev(MAJOR_NR, card_number << MM_SHIFT);
+ int res = dev_lock_part(device);
+ if (res < 0)
+ return res;
+ wipe_partitions(device);
printk(KERN_INFO "mm partition check: (%d)\n", card_number);
- grok_partitions(mk_kdev(major_nr,part1-1),
- mm_gendisk.sizes[card_number<<MM_SHIFT]);
+ grok_partitions(device, cards[card_number].mm_size << 1);
+ dev_unlock_part(device);
return 0;
}
/*
@@ -859,16 +848,6 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned
switch(cmd) {
-
- case BLKGETSIZE:
- /* Return the device size, expressed in sectors */
- err = ! access_ok (VERIFY_WRITE, arg, sizeof(long));
- if (err) return -EFAULT;
- size = mm_gendisk.part[minor].nr_sects;
- if (copy_to_user((long *) arg, &size, sizeof (long)))
- return -EFAULT;
- return 0;
-
case BLKRRPART:
return (mm_revalidate(i->i_rdev));
@@ -883,16 +862,15 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned
size = cards[card_number].mm_size * (1024 / MM_HARDSECT);
geo.heads = 64;
geo.sectors = 32;
- geo.start = mm_gendisk.part[minor].start_sect;
+ geo.start = get_start_sect(inode->i_bdev);
geo.cylinders = size / (geo.heads * geo.sectors);
if (copy_to_user((void *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
-
default:
- return blk_ioctl(i->i_bdev, cmd, arg);
+ return -EINVAL;
}
return -ENOTTY; /* unknown command */
@@ -905,7 +883,7 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned
*/
static int mm_check_change(kdev_t i_rdev)
{
- int card_number = DEVICE_NR(kdev_val(i_rdev));
+ int card_number = DEVICE_NR(i_rdev);
/* struct cardinfo *dev = cards + card_number; */
if (card_number >= num_cards) /* paranoid */
return 0;
@@ -920,38 +898,8 @@ static int mm_check_change(kdev_t i_rdev)
*/
static int mm_open(struct inode *i, struct file *filp)
{
- int num;
- struct cardinfo *card;
-
- num = DEVICE_NR(kdev_val(i->i_rdev));
- if (num >= num_cards)
+ if (DEVICE_NR(i->i_rdev) >= num_cards)
return -ENXIO;
-
- card = cards + num;
-
- atomic_inc(&card->usage);
- MOD_INC_USE_COUNT;
-
- return 0;
-}
-/*
------------------------------------------------------------------------------------
--- mm_do_release
------------------------------------------------------------------------------------
-*/
-static int mm_do_release(struct inode *i, struct file *filp)
-{
- int num;
- struct cardinfo *card;
-
- num = DEVICE_NR(kdev_val(i->i_rdev));
-
- card = cards + num;
-
- if (atomic_dec_and_test(&card->usage))
- invalidate_device(i->i_rdev, 1);
-
- MOD_DEC_USE_COUNT;
return 0;
}
/*
@@ -962,7 +910,6 @@ static int mm_do_release(struct inode *i, struct file *filp)
static struct block_device_operations mm_fops = {
owner: THIS_MODULE,
open: mm_open,
- release: mm_do_release,
ioctl: mm_ioctl,
revalidate: mm_revalidate,
check_media_change: mm_check_change,
@@ -1243,7 +1190,7 @@ static struct pci_driver mm_pci_driver = {
static request_queue_t * mm_queue_proc(kdev_t dev)
{
- int c = DEVICE_NR(kdev_val(dev));
+ int c = DEVICE_NR(dev);
if (c < MM_MAXCARDS)
return &cards[c].queue;
@@ -1293,7 +1240,6 @@ int __init mm_init(void)
blk_dev[MAJOR_NR].queue = mm_queue_proc;
add_gendisk(&mm_gendisk);
- blk_size[MAJOR_NR] = mm_gendisk.sizes;
for (i = 0; i < num_cards; i++) {
register_disk(&mm_gendisk, mk_kdev(MAJOR_NR, i<<MM_SHIFT), MM_SHIFT,
&mm_fops, cards[i].mm_size << 1);
@@ -1325,9 +1271,6 @@ void __exit mm_cleanup(void)
unregister_blkdev(MAJOR_NR, "umem");
- for (i = 0; i < (num_cards << MM_SHIFT); i++)
- invalidate_device (mk_kdev(MAJOR_NR,i), 1);
-
blk_size [MAJOR_NR] = NULL;
/*
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index bca8cd457e0e..a1166a4e1394 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -122,7 +122,7 @@ static unsigned int xd_bases[] __initdata =
};
static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
-static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES];
+static int xd_sizes[XD_MAXDRIVES << 6];
static spinlock_t xd_lock = SPIN_LOCK_UNLOCKED;
@@ -140,12 +140,9 @@ static struct gendisk xd_gendisk = {
static struct block_device_operations xd_fops = {
owner: THIS_MODULE,
open: xd_open,
- release: xd_release,
ioctl: xd_ioctl,
};
static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
-static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open);
-static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
static u_char xd_override __initdata = 0, xd_type __initdata = 0;
static u_short xd_iobase = 0x320;
@@ -244,14 +241,11 @@ static void __init xd_geninit (void)
/* xd_maxsectors depends on controller - so set after detection */
blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), xd_maxsectors);
- for (i = 0; i < xd_drives; i++) {
- xd_valid[i] = 1;
+ for (i = 0; i < xd_drives; i++)
register_disk(&xd_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6,
&xd_fops,
xd_info[i].heads * xd_info[i].cylinders *
xd_info[i].sectors);
- }
-
xd_gendisk.nr_real = xd_drives;
}
@@ -259,17 +253,9 @@ static void __init xd_geninit (void)
static int xd_open (struct inode *inode,struct file *file)
{
int dev = DEVICE_NR(inode->i_rdev);
-
- if (dev < xd_drives) {
- while (!xd_valid[dev])
- sleep_on(&xd_wait_open);
-
- xd_access[dev]++;
-
- return (0);
- }
-
- return -ENXIO;
+ if (dev >= xd_drives)
+ return -ENXIO;
+ return 0;
}
/* do_xd_request: handle an incoming request */
@@ -329,7 +315,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
g.heads = xd_info[dev].heads;
g.sectors = xd_info[dev].sectors;
g.cylinders = xd_info[dev].cylinders;
- g.start = get_start_sect(inode->i_rdev);
+ g.start = get_start_sect(inode->i_bdev);
return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0;
}
case HDIO_SET_DMA:
@@ -351,50 +337,28 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
return -EACCES;
return xd_reread_partitions(inode->i_rdev);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKFLSBUF:
- case BLKROSET:
- case BLKROGET:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
default:
return -EINVAL;
}
}
-/* xd_release: release the device */
-static int xd_release (struct inode *inode, struct file *file)
-{
- int target = DEVICE_NR(inode->i_rdev);
- if (target < xd_drives)
- xd_access[target]--;
- return 0;
-}
-
/* xd_reread_partitions: rereads the partition table from a drive */
static int xd_reread_partitions(kdev_t dev)
{
- int target;
- int res;
+ int target = DEVICE_NR(dev);
+ kdev_t device = mk_kdev(MAJOR_NR, target << 6);
+ int res = dev_lock_part(device);
- target = DEVICE_NR(dev);
-
- cli();
- xd_valid[target] = (xd_access[target] != 1);
- sti();
- if (xd_valid[target])
- return -EBUSY;
+ if (res < 0)
+ return 0;
- res = wipe_partitions(dev);
+ res = wipe_partitions(device);
if (!res)
- grok_partitions(dev, xd_info[target].heads
+ grok_partitions(device, xd_info[target].heads
* xd_info[target].cylinders
* xd_info[target].sectors);
- xd_valid[target] = 1;
- wake_up(&xd_wait_open);
+ dev_unlock_part(device);
return res;
}
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index 7babb59b96d0..3df2d4e98410 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -113,7 +113,6 @@ static void xd_geninit (void);
static int xd_open (struct inode *inode,struct file *file);
static void do_xd_request (request_queue_t * q);
static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
-static int xd_release (struct inode *inode,struct file *file);
static int xd_reread_partitions (kdev_t dev);
static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
static void xd_recalibrate (u_char drive);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 494aa03dc273..7b6dbbee9d95 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1732,11 +1732,6 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
because they fill up the sys log when CD players poll
the drive. */
switch (cmd) {
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- case BLKSSZGET:
- return blk_ioctl(ip->i_bdev, cmd, arg);
case CDROMSUBCHNL: {
struct cdrom_subchnl q;
u_char requested, back;
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index ccce94f8fd26..a2489a9daf9b 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -8,25 +8,6 @@ bool 'Virtual terminal' CONFIG_VT
if [ "$CONFIG_VT" = "y" ]; then
bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE
fi
-tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL
-if [ "$CONFIG_SERIAL" = "y" ]; then
- bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
- if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
- tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
- tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL
- fi
-fi
-if [ "$CONFIG_ACPI" = "y" -a "$CONFIG_IA64" = "y" ]; then
- bool ' Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI
-fi
-dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
-if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
- bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
- bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
- bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ
- bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT
- bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6
-fi
bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
@@ -85,15 +66,9 @@ fi
if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
fi
-if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
- bool 'DC21285 serial port support' CONFIG_SERIAL_21285
- if [ "$CONFIG_SERIAL_21285" = "y" ]; then
- if [ "$CONFIG_OBSOLETE" = "y" ]; then
- bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD
- fi
- bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE
- fi
-fi
+
+source drivers/serial/Config.in
+
bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 07ed55ac10ad..650d9b6eb6de 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -13,20 +13,18 @@ obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := busmouse.o console.o keyboard.o sysrq.o \
- misc.o pty.o random.o selection.o serial.o \
+ misc.o pty.o random.o selection.o \
sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \
ip2main.o
KEYMAP =defkeymap.o
KEYBD =pc_keyb.o
CONSOLE =console.o
-SERIAL =serial.o
ifeq ($(ARCH),s390)
KEYMAP =
KEYBD =
CONSOLE =
- SERIAL =
endif
ifeq ($(ARCH),mips)
@@ -39,7 +37,6 @@ ifeq ($(ARCH),s390x)
KEYMAP =
KEYBD =
CONSOLE =
- SERIAL =
endif
ifeq ($(ARCH),m68k)
@@ -48,7 +45,6 @@ ifeq ($(ARCH),m68k)
else
KEYBD =
endif
- SERIAL =
endif
ifeq ($(ARCH),arm)
@@ -96,15 +92,6 @@ endif
ifeq ($(CONFIG_BAGET_MIPS),y)
KEYBD =
- SERIAL =
-endif
-
-ifeq ($(CONFIG_NINO),y)
- SERIAL =
-endif
-
-ifneq ($(CONFIG_SUN_SERIAL),)
- SERIAL =
endif
ifeq ($(CONFIG_QTRONIX_KEYBOARD),y)
@@ -113,11 +100,7 @@ ifeq ($(CONFIG_QTRONIX_KEYBOARD),y)
endif
obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
-obj-$(CONFIG_SERIAL) += $(SERIAL)
-obj-$(CONFIG_SERIAL_ACPI) += acpi_serial.o
-obj-$(CONFIG_SERIAL_21285) += serial_21285.o
-obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
-obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o
+#obj-$(CONFIG_SERIAL) += $(SERIAL) # Fix for decserial.o
ifndef CONFIG_SUN_KEYBOARD
obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD)
diff --git a/drivers/char/acpi_serial.c b/drivers/char/acpi_serial.c
deleted file mode 100644
index f0c7f188299f..000000000000
--- a/drivers/char/acpi_serial.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * linux/drivers/char/acpi_serial.c
- *
- * Copyright (C) 2000 Hewlett-Packard Co.
- * Copyright (C) 2000 Khalid Aziz <khalid_aziz@hp.com>
- *
- * Detect and initialize the headless console serial port defined in
- * SPCR table and debug serial port defined in DBGP table
- *
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/pm.h>
-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <asm/serial.h>
-#include <asm/io.h>
-#include <linux/acpi_serial.h>
-/*#include <asm/acpi-ext.h>*/
-
-#undef SERIAL_DEBUG_ACPI
-
-/*
- * Query ACPI tables for a debug and a headless console serial
- * port. If found, add them to rs_table[]. A pointer to either SPCR
- * or DBGP table is passed as parameter. This function should be called
- * before serial_console_init() is called to make sure the SPCR serial
- * console will be available for use. IA-64 kernel calls this function
- * from within acpi.c when it encounters SPCR or DBGP tables as it parses
- * the ACPI 2.0 tables during bootup.
- *
- */
-void __init setup_serial_acpi(void *tablep)
-{
- acpi_ser_t *acpi_ser_p;
- struct serial_struct serial_req;
- unsigned long iobase;
- int global_sys_irq;
-
-#ifdef SERIAL_DEBUG_ACPI
- printk("Entering setup_serial_acpi()\n");
-#endif
-
- /* Now get the table */
- if (tablep == NULL) {
- return;
- }
-
- acpi_ser_p = (acpi_ser_t *)tablep;
-
- /*
- * Perform a sanity check on the table. Table should have a
- * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes
- * long.
- */
- if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE,
- ACPI_SIG_LEN) != 0) &&
- (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE,
- ACPI_SIG_LEN) != 0)) {
- return;
- }
- if (acpi_ser_p->length < 52) {
- return;
- }
-
- iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl;
- global_sys_irq = (acpi_ser_p->global_int[3] << 24) |
- (acpi_ser_p->global_int[2] << 16) |
- (acpi_ser_p->global_int[1] << 8) |
- acpi_ser_p->global_int[0];
-
-#ifdef SERIAL_DEBUG_ACPI
- printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p);
- printk(" sig = '%c%c%c%c'\n",
- acpi_ser_p->signature[0],
- acpi_ser_p->signature[1],
- acpi_ser_p->signature[2],
- acpi_ser_p->signature[3]);
- printk(" length = %d\n", acpi_ser_p->length);
- printk(" Rev = %d\n", acpi_ser_p->rev);
- printk(" Interface type = %d\n", acpi_ser_p->intfc_type);
- printk(" Base address = 0x%lX\n", iobase);
- printk(" IRQ = %d\n", acpi_ser_p->irq);
- printk(" Global System Int = %d\n", global_sys_irq);
- printk(" Baud rate = ");
- switch (acpi_ser_p->baud) {
- case ACPI_SERIAL_BAUD_9600:
- printk("9600\n");
- break;
-
- case ACPI_SERIAL_BAUD_19200:
- printk("19200\n");
- break;
-
- case ACPI_SERIAL_BAUD_57600:
- printk("57600\n");
- break;
-
- case ACPI_SERIAL_BAUD_115200:
- printk("115200\n");
- break;
-
- default:
- printk("Huh (%d)\n", acpi_ser_p->baud);
- break;
-
- }
- if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) {
- printk(" PCI serial port:\n");
- printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n",
- acpi_ser_p->pci_bus, acpi_ser_p->pci_dev,
- acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id);
- }
-#endif
-
- /*
- * Now build a serial_req structure to update the entry in
- * rs_table for the headless console port.
- */
- switch (acpi_ser_p->intfc_type) {
- case ACPI_SERIAL_INTFC_16550:
- serial_req.type = PORT_16550;
- serial_req.baud_base = BASE_BAUD;
- break;
-
- case ACPI_SERIAL_INTFC_16450:
- serial_req.type = PORT_16450;
- serial_req.baud_base = BASE_BAUD;
- break;
-
- default:
- serial_req.type = PORT_UNKNOWN;
- break;
- }
- if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE,
- ACPI_SIG_LEN) == 0) {
- serial_req.line = ACPI_SERIAL_CONSOLE_PORT;
- }
- else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE,
- ACPI_SIG_LEN) == 0) {
- serial_req.line = ACPI_SERIAL_DEBUG_PORT;
- }
- /*
- * Check if this is an I/O mapped address or a memory mapped address
- */
- if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) {
- serial_req.port = 0;
- serial_req.port_high = 0;
- serial_req.iomem_base = (void *)ioremap(iobase, 64);
- serial_req.io_type = SERIAL_IO_MEM;
- }
- else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) {
- serial_req.port = (unsigned long) iobase & 0xffffffff;
- serial_req.port_high = (unsigned long)(((u64)iobase) >> 32);
- serial_req.iomem_base = NULL;
- serial_req.io_type = SERIAL_IO_PORT;
- }
- else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) {
- printk("WARNING: No support for PCI serial console\n");
- return;
- }
-
- /*
- * If the table does not have IRQ information, use 0 for IRQ.
- * This will force rs_init() to probe for IRQ.
- */
- if (acpi_ser_p->length < 53) {
- serial_req.irq = 0;
- }
- else {
- serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF |
- ASYNC_AUTO_IRQ;
- if (acpi_ser_p->int_type &
- (ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) {
- serial_req.irq = global_sys_irq;
- }
- else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) {
- serial_req.irq = acpi_ser_p->irq;
- }
- else {
- /*
- * IRQ type not being set would mean UART will
- * run in polling mode. Do not probe for IRQ in
- * that case.
- */
- serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF;
- }
- }
-
- serial_req.xmit_fifo_size = serial_req.custom_divisor = 0;
- serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0;
- serial_req.iomem_reg_shift = 0;
- if (early_serial_setup(&serial_req) < 0) {
- printk("early_serial_setup() for ACPI serial console port failed\n");
- return;
- }
-
-#ifdef SERIAL_DEBUG_ACPI
- printk("Leaving setup_serial_acpi()\n");
-#endif
-}
diff --git a/drivers/char/agp/Config.help b/drivers/char/agp/Config.help
new file mode 100644
index 000000000000..b6083743dad6
--- /dev/null
+++ b/drivers/char/agp/Config.help
@@ -0,0 +1,88 @@
+CONFIG_AGP
+ AGP (Accelerated Graphics Port) is a bus system mainly used to
+ connect graphics cards to the rest of the system.
+
+ If you have an AGP system and you say Y here, it will be possible to
+ use the AGP features of your 3D rendering video card. This code acts
+ as a sort of "AGP driver" for the motherboard's chipset.
+
+ If you need more texture memory than you can get with the AGP GART
+ (theoretically up to 256 MB, but in practice usually 64 or 128 MB
+ due to kernel allocation issues), you could use PCI accesses
+ and have up to a couple gigs of texture space.
+
+ Note that this is the only means to have XFree4/GLX use
+ write-combining with MTRR support on the AGP bus. Without it, OpenGL
+ direct rendering will be a lot slower but still faster than PIO.
+
+ You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+ use GLX or DRI. If unsure, say N.
+
+ This driver is available as a module. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>. The
+ module will be called agpgart.o.
+
+CONFIG_AGP_INTEL
+ This option gives you AGP support for the GLX component of the
+ XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850 and 860 chipsets.
+
+ You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+ use GLX or DRI. If unsure, say N.
+
+CONFIG_AGP_I810
+ This option gives you AGP support for the Xserver on the Intel 810
+ 815 and 830m chipset boards for their on-board integrated graphics. This
+ is required to do any useful video modes with these boards.
+
+CONFIG_AGP_I460
+ This option gives you AGP GART support for the Intel 460GX chipset
+ for IA64 processors.
+
+CONFIG_AGP_VIA
+ This option gives you AGP support for the GLX component of the
+ XFree86 4.x on VIA MPV3/Apollo Pro chipsets.
+
+ You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+ use GLX or DRI. If unsure, say N.
+
+CONFIG_AGP_AMD
+ This option gives you AGP support for the GLX component of the
+ XFree86 4.x on AMD Irongate, 761, and 762 chipsets.
+
+ You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+ use GLX or DRI. If unsure, say N.
+
+CONFIG_AGP_SIS
+ This option gives you AGP support for the GLX component of the "soon
+ to be released" XFree86 4.x on Silicon Integrated Systems [SiS]
+ chipsets.
+
+ Note that 5591/5592 AGP chipsets are NOT supported.
+
+ You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+ use GLX or DRI. If unsure, say N.
+
+CONFIG_AGP_SWORKS
+ Say Y here to support the Serverworks AGP card. See
+ <http://www.serverworks.com/> for product descriptions and images.
+
+CONFIG_AGP_ALI
+ This option gives you AGP support for the GLX component of the
+ XFree86 4.x on the following ALi chipsets. The supported chipsets
+ include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
+ For the ALi-chipset question, ALi suggests you refer to
+ <http://www.ali.com.tw/eng/support/index.shtml>.
+
+ The M1541 chipset can do AGP 1x and 2x, but note that there is an
+ acknowledged incompatibility with Matrox G200 cards. Due to
+ timing issues, this chipset cannot do AGP 2x with the G200.
+ This is a hardware limitation. AGP 1x seems to be fine, though.
+
+ You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+ use GLX or DRI. If unsure, say N.
+
+CONFIG_AGP_HP_ZX1
+ This option gives you AGP GART support for the HP ZX1 chipset
+ for IA64 processors.
+
+
diff --git a/drivers/char/agp/Config.in b/drivers/char/agp/Config.in
new file mode 100644
index 000000000000..91c2fbdf5e4a
--- /dev/null
+++ b/drivers/char/agp/Config.in
@@ -0,0 +1,14 @@
+dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
+if [ "$CONFIG_AGP" != "n" ]; then
+ bool ' Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
+ bool ' Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
+ bool ' VIA chipset support' CONFIG_AGP_VIA
+ bool ' AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
+ bool ' Generic SiS support' CONFIG_AGP_SIS
+ bool ' ALI chipset support' CONFIG_AGP_ALI
+ bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS
+ if [ "$CONFIG_IA64" = "y" ]; then
+ bool ' Intel 460GX support' CONFIG_AGP_I460
+ bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1
+ fi
+fi
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 8c78cba4f66e..940b293804a8 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -3,9 +3,20 @@
# space ioctl interface to use agp memory. It also adds a kernel interface
# that other drivers could use to manipulate agp memory.
-export-objs := agpgart_be.o
+export-objs := agp.o
-agpgart-objs := agpgart_fe.o agpgart_be.o
+agpgart-y := agp.o frontend.o
+
+agpgart-$(CONFIG_AGP_INTEL) += i8x0-agp.o
+agpgart-$(CONFIG_AGP_I810) += i810-agp.o
+agpgart-$(CONFIG_AGP_VIA) += via-agp.o
+agpgart-$(CONFIG_AGP_AMD) += amd-agp.o
+agpgart-$(CONFIG_AGP_SIS) += sis-agp.o
+agpgart-$(CONFIG_AGP_ALI) += ali-agp.o
+agpgart-$(CONFIG_AGP_SWORKS) += sworks-agp.o
+agpgart-$(CONFIG_AGP_I460) += i460-agp.o
+agpgart-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
+agpgart-objs := $(agpgart-y)
obj-$(CONFIG_AGP) += agpgart.o
diff --git a/drivers/char/agp/agp.c b/drivers/char/agp/agp.c
new file mode 100644
index 000000000000..ff0564a4faed
--- /dev/null
+++ b/drivers/char/agp/agp.c
@@ -0,0 +1,1662 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/miscdevice.h>
+#include <linux/pm.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+MODULE_AUTHOR("Jeff Hartmann <jhartmann@precisioninsight.com>");
+MODULE_PARM(agp_try_unsupported, "1i");
+MODULE_LICENSE("GPL and additional rights");
+EXPORT_SYMBOL(agp_free_memory);
+EXPORT_SYMBOL(agp_allocate_memory);
+EXPORT_SYMBOL(agp_copy_info);
+EXPORT_SYMBOL(agp_bind_memory);
+EXPORT_SYMBOL(agp_unbind_memory);
+EXPORT_SYMBOL(agp_enable);
+EXPORT_SYMBOL(agp_backend_acquire);
+EXPORT_SYMBOL(agp_backend_release);
+
+struct agp_bridge_data agp_bridge = { type: NOT_SUPPORTED };
+static int agp_try_unsupported __initdata = 0;
+
+int agp_backend_acquire(void)
+{
+ if (agp_bridge.type == NOT_SUPPORTED)
+ return -EINVAL;
+
+ atomic_inc(&agp_bridge.agp_in_use);
+
+ if (atomic_read(&agp_bridge.agp_in_use) != 1) {
+ atomic_dec(&agp_bridge.agp_in_use);
+ return -EBUSY;
+ }
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+void agp_backend_release(void)
+{
+ if (agp_bridge.type == NOT_SUPPORTED)
+ return;
+
+ atomic_dec(&agp_bridge.agp_in_use);
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Generic routines for handling agp_memory structures -
+ * They use the basic page allocation routines to do the
+ * brunt of the work.
+ */
+
+
+void agp_free_key(int key)
+{
+
+ if (key < 0)
+ return;
+
+ if (key < MAXKEY)
+ clear_bit(key, agp_bridge.key_list);
+}
+
+static int agp_get_key(void)
+{
+ int bit;
+
+ bit = find_first_zero_bit(agp_bridge.key_list, MAXKEY);
+ if (bit < MAXKEY) {
+ set_bit(bit, agp_bridge.key_list);
+ return bit;
+ }
+ return -1;
+}
+
+agp_memory *agp_create_memory(int scratch_pages)
+{
+ agp_memory *new;
+
+ new = kmalloc(sizeof(agp_memory), GFP_KERNEL);
+
+ if (new == NULL)
+ return NULL;
+
+ memset(new, 0, sizeof(agp_memory));
+ new->key = agp_get_key();
+
+ if (new->key < 0) {
+ kfree(new);
+ return NULL;
+ }
+ new->memory = vmalloc(PAGE_SIZE * scratch_pages);
+
+ if (new->memory == NULL) {
+ agp_free_key(new->key);
+ kfree(new);
+ return NULL;
+ }
+ new->num_scratch_pages = scratch_pages;
+ return new;
+}
+
+void agp_free_memory(agp_memory * curr)
+{
+ int i;
+
+ if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL))
+ return;
+
+ if (curr->is_bound == TRUE)
+ agp_unbind_memory(curr);
+
+ if (curr->type != 0) {
+ agp_bridge.free_by_type(curr);
+ return;
+ }
+ if (curr->page_count != 0) {
+ for (i = 0; i < curr->page_count; i++) {
+ curr->memory[i] &= ~(0x00000fff);
+ agp_bridge.agp_destroy_page(phys_to_virt(curr->memory[i]));
+ }
+ }
+ agp_free_key(curr->key);
+ vfree(curr->memory);
+ kfree(curr);
+ MOD_DEC_USE_COUNT;
+}
+
+#define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))
+
+agp_memory *agp_allocate_memory(size_t page_count, u32 type)
+{
+ int scratch_pages;
+ agp_memory *new;
+ int i;
+
+ if (agp_bridge.type == NOT_SUPPORTED)
+ return NULL;
+
+ if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) >
+ agp_bridge.max_memory_agp) {
+ return NULL;
+ }
+
+ if (type != 0) {
+ new = agp_bridge.alloc_by_type(page_count, type);
+ return new;
+ }
+ /* We always increase the module count, since free auto-decrements
+ * it
+ */
+
+ MOD_INC_USE_COUNT;
+
+ scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
+
+ new = agp_create_memory(scratch_pages);
+
+ if (new == NULL) {
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+
+ for (i = 0; i < page_count; i++) {
+ void *addr = agp_bridge.agp_alloc_page();
+
+ if (addr == NULL) {
+ /* Free this structure */
+ agp_free_memory(new);
+ return NULL;
+ }
+ new->memory[i] = agp_bridge.mask_memory(virt_to_phys(addr), type);
+ new->page_count++;
+ }
+
+ flush_agp_mappings();
+
+ return new;
+}
+
+/* End - Generic routines for handling agp_memory structures */
+
+static int agp_return_size(void)
+{
+ int current_size;
+ void *temp;
+
+ temp = agp_bridge.current_size;
+
+ switch (agp_bridge.size_type) {
+ case U8_APER_SIZE:
+ current_size = A_SIZE_8(temp)->size;
+ break;
+ case U16_APER_SIZE:
+ current_size = A_SIZE_16(temp)->size;
+ break;
+ case U32_APER_SIZE:
+ current_size = A_SIZE_32(temp)->size;
+ break;
+ case LVL2_APER_SIZE:
+ current_size = A_SIZE_LVL2(temp)->size;
+ break;
+ case FIXED_APER_SIZE:
+ current_size = A_SIZE_FIX(temp)->size;
+ break;
+ default:
+ current_size = 0;
+ break;
+ }
+
+ return current_size;
+}
+
+/* Routine to copy over information structure */
+
+void agp_copy_info(agp_kern_info * info)
+{
+ unsigned long page_mask = 0;
+ int i;
+
+ memset(info, 0, sizeof(agp_kern_info));
+ if (agp_bridge.type == NOT_SUPPORTED) {
+ info->chipset = agp_bridge.type;
+ return;
+ }
+ info->version.major = agp_bridge.version->major;
+ info->version.minor = agp_bridge.version->minor;
+ info->device = agp_bridge.dev;
+ info->chipset = agp_bridge.type;
+ info->mode = agp_bridge.mode;
+ info->aper_base = agp_bridge.gart_bus_addr;
+ info->aper_size = agp_return_size();
+ info->max_memory = agp_bridge.max_memory_agp;
+ info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
+ info->cant_use_aperture = agp_bridge.cant_use_aperture;
+
+ for(i = 0; i < agp_bridge.num_of_masks; i++)
+ page_mask |= agp_bridge.mask_memory(page_mask, i);
+
+ info->page_mask = ~page_mask;
+}
+
+/* End - Routine to copy over information structure */
+
+/*
+ * Routines for handling swapping of agp_memory into the GATT -
+ * These routines take agp_memory and insert them into the GATT.
+ * They call device specific routines to actually write to the GATT.
+ */
+
+int agp_bind_memory(agp_memory * curr, off_t pg_start)
+{
+ int ret_val;
+
+ if ((agp_bridge.type == NOT_SUPPORTED) ||
+ (curr == NULL) || (curr->is_bound == TRUE)) {
+ return -EINVAL;
+ }
+ if (curr->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ curr->is_flushed = TRUE;
+ }
+ ret_val = agp_bridge.insert_memory(curr, pg_start, curr->type);
+
+ if (ret_val != 0)
+ return ret_val;
+
+ curr->is_bound = TRUE;
+ curr->pg_start = pg_start;
+ return 0;
+}
+
+int agp_unbind_memory(agp_memory * curr)
+{
+ int ret_val;
+
+ if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL))
+ return -EINVAL;
+
+ if (curr->is_bound != TRUE)
+ return -EINVAL;
+
+ ret_val = agp_bridge.remove_memory(curr, curr->pg_start, curr->type);
+
+ if (ret_val != 0)
+ return ret_val;
+
+ curr->is_bound = FALSE;
+ curr->pg_start = 0;
+ return 0;
+}
+
+/* End - Routines for handling swapping of agp_memory into the GATT */
+
+/*
+ * Driver routines - start
+ * Currently this module supports the following chipsets:
+ * i810, i815, 440lx, 440bx, 440gx, i830, i840, i845, i850, i860, via vp3,
+ * via mvp3, via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541,
+ * and generic support for the SiS chipsets.
+ */
+
+/* Generic Agp routines - Start */
+
+void agp_generic_agp_enable(u32 mode)
+{
+ struct pci_dev *device = NULL;
+ u32 command, scratch;
+ u8 cap_ptr;
+
+ pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + 4, &command);
+
+ /*
+ * PASS1: go throu all devices that claim to be
+ * AGP devices and collect their data.
+ */
+
+
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+ if (cap_ptr != 0x00) {
+ /*
+ * Ok, here we have a AGP device. Disable impossible
+ * settings, and adjust the readqueue to the minimum.
+ */
+
+ pci_read_config_dword(device, cap_ptr + 4, &scratch);
+
+ /* adjust RQ depth */
+ command = ((command & ~0xff000000) |
+ min_t(u32, (mode & 0xff000000),
+ min_t(u32, (command & 0xff000000),
+ (scratch & 0xff000000))));
+
+ /* disable SBA if it's not supported */
+ if (!((command & 0x00000200) &&
+ (scratch & 0x00000200) &&
+ (mode & 0x00000200)))
+ command &= ~0x00000200;
+
+ /* disable FW if it's not supported */
+ if (!((command & 0x00000010) &&
+ (scratch & 0x00000010) &&
+ (mode & 0x00000010)))
+ command &= ~0x00000010;
+
+ if (!((command & 4) &&
+ (scratch & 4) &&
+ (mode & 4)))
+ command &= ~0x00000004;
+
+ if (!((command & 2) &&
+ (scratch & 2) &&
+ (mode & 2)))
+ command &= ~0x00000002;
+
+ if (!((command & 1) &&
+ (scratch & 1) &&
+ (mode & 1)))
+ command &= ~0x00000001;
+ }
+ }
+ /*
+ * PASS2: Figure out the 4X/2X/1X setting and enable the
+ * target (our motherboard chipset).
+ */
+
+ if (command & 4)
+ command &= ~3; /* 4X */
+
+ if (command & 2)
+ command &= ~5; /* 2X */
+
+ if (command & 1)
+ command &= ~6; /* 1X */
+
+ command |= 0x00000100;
+
+ pci_write_config_dword(agp_bridge.dev,
+ agp_bridge.capndx + 8,
+ command);
+
+ /*
+ * PASS3: Go throu all AGP devices and update the
+ * command registers.
+ */
+
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+ if (cap_ptr != 0x00)
+ pci_write_config_dword(device, cap_ptr + 8, command);
+ }
+}
+
+int agp_generic_create_gatt_table(void)
+{
+ char *table;
+ char *table_end;
+ int size;
+ int page_order;
+ int num_entries;
+ int i;
+ void *temp;
+ struct page *page;
+
+ /* The generic routines can't handle 2 level gatt's */
+ if (agp_bridge.size_type == LVL2_APER_SIZE) {
+ return -EINVAL;
+ }
+
+ table = NULL;
+ i = agp_bridge.aperture_size_idx;
+ temp = agp_bridge.current_size;
+ size = page_order = num_entries = 0;
+
+ if (agp_bridge.size_type != FIXED_APER_SIZE) {
+ do {
+ switch (agp_bridge.size_type) {
+ case U8_APER_SIZE:
+ size = A_SIZE_8(temp)->size;
+ page_order =
+ A_SIZE_8(temp)->page_order;
+ num_entries =
+ A_SIZE_8(temp)->num_entries;
+ break;
+ case U16_APER_SIZE:
+ size = A_SIZE_16(temp)->size;
+ page_order = A_SIZE_16(temp)->page_order;
+ num_entries = A_SIZE_16(temp)->num_entries;
+ break;
+ case U32_APER_SIZE:
+ size = A_SIZE_32(temp)->size;
+ page_order = A_SIZE_32(temp)->page_order;
+ num_entries = A_SIZE_32(temp)->num_entries;
+ break;
+ /* This case will never really happen. */
+ case FIXED_APER_SIZE:
+ case LVL2_APER_SIZE:
+ default:
+ size = page_order = num_entries = 0;
+ break;
+ }
+
+ table = (char *) __get_free_pages(GFP_KERNEL,
+ page_order);
+
+ if (table == NULL) {
+ i++;
+ switch (agp_bridge.size_type) {
+ case U8_APER_SIZE:
+ agp_bridge.current_size = A_IDX8();
+ break;
+ case U16_APER_SIZE:
+ agp_bridge.current_size = A_IDX16();
+ break;
+ case U32_APER_SIZE:
+ agp_bridge.current_size = A_IDX32();
+ break;
+ /* This case will never really
+ * happen.
+ */
+ case FIXED_APER_SIZE:
+ case LVL2_APER_SIZE:
+ default:
+ agp_bridge.current_size =
+ agp_bridge.current_size;
+ break;
+ }
+ temp = agp_bridge.current_size;
+ } else {
+ agp_bridge.aperture_size_idx = i;
+ }
+ } while ((table == NULL) &&
+ (i < agp_bridge.num_aperture_sizes));
+ } else {
+ size = ((struct aper_size_info_fixed *) temp)->size;
+ page_order = ((struct aper_size_info_fixed *) temp)->page_order;
+ num_entries = ((struct aper_size_info_fixed *) temp)->num_entries;
+ table = (char *) __get_free_pages(GFP_KERNEL, page_order);
+ }
+
+ if (table == NULL)
+ return -ENOMEM;
+
+ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+ for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+ SetPageReserved(page);
+
+ agp_bridge.gatt_table_real = (unsigned long *) table;
+ CACHE_FLUSH();
+ agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
+ (PAGE_SIZE * (1 << page_order)));
+ CACHE_FLUSH();
+
+ if (agp_bridge.gatt_table == NULL) {
+ for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+ ClearPageReserved(page);
+
+ free_pages((unsigned long) table, page_order);
+
+ return -ENOMEM;
+ }
+ agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real);
+
+ for (i = 0; i < num_entries; i++)
+ agp_bridge.gatt_table[i] = (unsigned long) agp_bridge.scratch_page;
+
+ return 0;
+}
+
+int agp_generic_suspend(void)
+{
+ return 0;
+}
+
+void agp_generic_resume(void)
+{
+ return;
+}
+
+int agp_generic_free_gatt_table(void)
+{
+ int page_order;
+ char *table, *table_end;
+ void *temp;
+ struct page *page;
+
+ temp = agp_bridge.current_size;
+
+ switch (agp_bridge.size_type) {
+ case U8_APER_SIZE:
+ page_order = A_SIZE_8(temp)->page_order;
+ break;
+ case U16_APER_SIZE:
+ page_order = A_SIZE_16(temp)->page_order;
+ break;
+ case U32_APER_SIZE:
+ page_order = A_SIZE_32(temp)->page_order;
+ break;
+ case FIXED_APER_SIZE:
+ page_order = A_SIZE_FIX(temp)->page_order;
+ break;
+ case LVL2_APER_SIZE:
+ /* The generic routines can't deal with 2 level gatt's */
+ return -EINVAL;
+ break;
+ default:
+ page_order = 0;
+ break;
+ }
+
+ /* Do not worry about freeing memory, because if this is
+ * called, then all agp memory is deallocated and removed
+ * from the table.
+ */
+
+ iounmap(agp_bridge.gatt_table);
+ table = (char *) agp_bridge.gatt_table_real;
+ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+ for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+ ClearPageReserved(page);
+
+ free_pages((unsigned long) agp_bridge.gatt_table_real, page_order);
+ return 0;
+}
+
+int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+ int i, j, num_entries;
+ void *temp;
+
+ temp = agp_bridge.current_size;
+
+ switch (agp_bridge.size_type) {
+ case U8_APER_SIZE:
+ num_entries = A_SIZE_8(temp)->num_entries;
+ break;
+ case U16_APER_SIZE:
+ num_entries = A_SIZE_16(temp)->num_entries;
+ break;
+ case U32_APER_SIZE:
+ num_entries = A_SIZE_32(temp)->num_entries;
+ break;
+ case FIXED_APER_SIZE:
+ num_entries = A_SIZE_FIX(temp)->num_entries;
+ break;
+ case LVL2_APER_SIZE:
+ /* The generic routines can't deal with 2 level gatt's */
+ return -EINVAL;
+ break;
+ default:
+ num_entries = 0;
+ break;
+ }
+
+ if (type != 0 || mem->type != 0) {
+ /* The generic routines know nothing of memory types */
+ return -EINVAL;
+ }
+
+ if ((pg_start + mem->page_count) > num_entries)
+ return -EINVAL;
+
+ j = pg_start;
+
+ while (j < (pg_start + mem->page_count)) {
+ if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
+ return -EBUSY;
+ }
+ j++;
+ }
+
+ if (mem->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ mem->is_flushed = TRUE;
+ }
+
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
+ agp_bridge.gatt_table[j] = mem->memory[i];
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+ int i;
+
+ if (type != 0 || mem->type != 0) {
+ /* The generic routines know nothing of memory types */
+ return -EINVAL;
+ }
+ for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+ agp_bridge.gatt_table[i] =
+ (unsigned long) agp_bridge.scratch_page;
+ }
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+agp_memory *agp_generic_alloc_by_type(size_t page_count, int type)
+{
+ return NULL;
+}
+
+void agp_generic_free_by_type(agp_memory * curr)
+{
+ if (curr->memory != NULL)
+ vfree(curr->memory);
+
+ agp_free_key(curr->key);
+ kfree(curr);
+}
+
+/*
+ * Basic Page Allocation Routines -
+ * These routines handle page allocation
+ * and by default they reserve the allocated
+ * memory. They also handle incrementing the
+ * current_memory_agp value, Which is checked
+ * against a maximum value.
+ */
+
+void *agp_generic_alloc_page(void)
+{
+ struct page * page;
+
+ page = alloc_page(GFP_KERNEL);
+ if (page == NULL)
+ return 0;
+
+ map_page_into_agp(page);
+
+ get_page(page);
+ SetPageLocked(page);
+ atomic_inc(&agp_bridge.current_memory_agp);
+ return page_address(page);
+}
+
+void agp_generic_destroy_page(void *addr)
+{
+ struct page *page;
+
+ if (addr == NULL)
+ return;
+
+ page = virt_to_page(addr);
+ unmap_page_from_agp(page);
+ put_page(page);
+ unlock_page(page);
+ free_page((unsigned long)addr);
+ atomic_dec(&agp_bridge.current_memory_agp);
+}
+
+/* End Basic Page Allocation Routines */
+
+void agp_enable(u32 mode)
+{
+ if (agp_bridge.type == NOT_SUPPORTED)
+ return;
+ agp_bridge.agp_enable(mode);
+}
+
+/* End - Generic Agp routines */
+
+
+/* per-chipset initialization data.
+ * note -- all chipsets for a single vendor MUST be grouped together
+ */
+static struct {
+ unsigned short device_id; /* first, to make table easier to read */
+ unsigned short vendor_id;
+ enum chipset_type chipset;
+ const char *vendor_name;
+ const char *chipset_name;
+ int (*chipset_setup) (struct pci_dev *pdev);
+} agp_bridge_info[] __initdata = {
+
+#ifdef CONFIG_AGP_ALI
+ {
+ device_id: PCI_DEVICE_ID_AL_M1541_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1541,
+ vendor_name: "Ali",
+ chipset_name: "M1541",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AL_M1621_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1621,
+ vendor_name: "Ali",
+ chipset_name: "M1621",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AL_M1631_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1631,
+ vendor_name: "Ali",
+ chipset_name: "M1631",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AL_M1632_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1632,
+ vendor_name: "Ali",
+ chipset_name: "M1632",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AL_M1641_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1641,
+ vendor_name: "Ali",
+ chipset_name: "M1641",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AL_M1644_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1644,
+ vendor_name: "Ali",
+ chipset_name: "M1644",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AL_M1647_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1647,
+ vendor_name: "Ali",
+ chipset_name: "M1647",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AL_M1651_0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_M1651,
+ vendor_name: "Ali",
+ chipset_name: "M1651",
+ chipset_setup: ali_generic_setup,
+ },
+ {
+ device_id: 0,
+ vendor_id: PCI_VENDOR_ID_AL,
+ chipset: ALI_GENERIC,
+ vendor_name: "Ali",
+ chipset_name: "Generic",
+ chipset_setup: ali_generic_setup,
+ },
+#endif /* CONFIG_AGP_ALI */
+
+#ifdef CONFIG_AGP_AMD
+ {
+ device_id: PCI_DEVICE_ID_AMD_IRONGATE_0,
+ vendor_id: PCI_VENDOR_ID_AMD,
+ chipset: AMD_IRONGATE,
+ vendor_name: "AMD",
+ chipset_name: "Irongate",
+ chipset_setup: amd_irongate_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AMD_761_0,
+ vendor_id: PCI_VENDOR_ID_AMD,
+ chipset: AMD_761,
+ vendor_name: "AMD",
+ chipset_name: "761",
+ chipset_setup: amd_irongate_setup,
+ },
+ {
+ device_id: PCI_DEVICE_ID_AMD_762_0,
+ vendor_id: PCI_VENDOR_ID_AMD,
+ chipset: AMD_762,
+ vendor_name: "AMD",
+ chipset_name: "760MP",
+ chipset_setup: amd_irongate_setup,
+ },
+ {
+ device_id: 0,
+ vendor_id: PCI_VENDOR_ID_AMD,
+ chipset: AMD_GENERIC,
+ vendor_name: "AMD",
+ chipset_name: "Generic",
+ chipset_setup: amd_irongate_setup,
+ },
+#endif /* CONFIG_AGP_AMD */
+
+#ifdef CONFIG_AGP_INTEL
+ {
+ device_id: PCI_DEVICE_ID_INTEL_82443LX_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_LX,
+ vendor_name: "Intel",
+ chipset_name: "440LX",
+ chipset_setup: intel_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_82443BX_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_BX,
+ vendor_name: "Intel",
+ chipset_name: "440BX",
+ chipset_setup: intel_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_82443GX_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_GX,
+ vendor_name: "Intel",
+ chipset_name: "440GX",
+ chipset_setup: intel_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_815_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I815,
+ vendor_name: "Intel",
+ chipset_name: "i815",
+ chipset_setup: intel_815_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_820_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I820,
+ vendor_name: "Intel",
+ chipset_name: "i820",
+ chipset_setup: intel_820_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_820_UP_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I820,
+ vendor_name: "Intel",
+ chipset_name: "i820",
+ chipset_setup: intel_820_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_830_M_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I830_M,
+ vendor_name: "Intel",
+ chipset_name: "i830M",
+ chipset_setup: intel_830mp_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_845_G_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I845_G,
+ vendor_name: "Intel",
+ chipset_name: "i845G",
+ chipset_setup: intel_830mp_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_840_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I840,
+ vendor_name: "Intel",
+ chipset_name: "i840",
+ chipset_setup: intel_840_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_845_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I845,
+ vendor_name: "Intel",
+ chipset_name: "i845",
+ chipset_setup: intel_845_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_850_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I850,
+ vendor_name: "Intel",
+ chipset_name: "i850",
+ chipset_setup: intel_850_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_INTEL_860_0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_I860,
+ vendor_name: "Intel",
+ chipset_name: "i860",
+ chipset_setup: intel_860_setup
+ },
+ {
+ device_id: 0,
+ vendor_id: PCI_VENDOR_ID_INTEL,
+ chipset: INTEL_GENERIC,
+ vendor_name: "Intel",
+ chipset_name: "Generic",
+ chipset_setup: intel_generic_setup
+ },
+
+#endif /* CONFIG_AGP_INTEL */
+
+#ifdef CONFIG_AGP_SIS
+ {
+ device_id: PCI_DEVICE_ID_SI_740,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "740",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_650,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "650",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_645,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "645",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_735,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "735",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_745,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "745",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_730,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "730",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_630,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "630",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_540,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "540",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_620,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "620",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_530,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "530",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_SI_550,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "550",
+ chipset_setup: sis_generic_setup
+ },
+ {
+ device_id: 0,
+ vendor_id: PCI_VENDOR_ID_SI,
+ chipset: SIS_GENERIC,
+ vendor_name: "SiS",
+ chipset_name: "Generic",
+ chipset_setup: sis_generic_setup
+ },
+#endif /* CONFIG_AGP_SIS */
+
+#ifdef CONFIG_AGP_VIA
+ {
+ device_id: PCI_DEVICE_ID_VIA_8501_0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_MVP4,
+ vendor_name: "Via",
+ chipset_name: "MVP4",
+ chipset_setup: via_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_VIA_82C597_0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_VP3,
+ vendor_name: "Via",
+ chipset_name: "VP3",
+ chipset_setup: via_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_VIA_82C598_0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_MVP3,
+ vendor_name: "Via",
+ chipset_name: "MVP3",
+ chipset_setup: via_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_VIA_82C691_0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_APOLLO_PRO,
+ vendor_name: "Via",
+ chipset_name: "Apollo Pro",
+ chipset_setup: via_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_VIA_8371_0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_APOLLO_KX133,
+ vendor_name: "Via",
+ chipset_name: "Apollo Pro KX133",
+ chipset_setup: via_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_VIA_8363_0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_APOLLO_KT133,
+ vendor_name: "Via",
+ chipset_name: "Apollo Pro KT133",
+ chipset_setup: via_generic_setup
+ },
+ {
+ device_id: PCI_DEVICE_ID_VIA_8367_0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_APOLLO_KT133,
+ vendor_name: "Via",
+ chipset_name: "Apollo Pro KT266",
+ chipset_setup: via_generic_setup
+ },
+ {
+ device_id: 0,
+ vendor_id: PCI_VENDOR_ID_VIA,
+ chipset: VIA_GENERIC,
+ vendor_name: "Via",
+ chipset_name: "Generic",
+ chipset_setup: via_generic_setup
+ },
+#endif /* CONFIG_AGP_VIA */
+
+#ifdef CONFIG_AGP_HP_ZX1
+ {
+ device_id: PCI_DEVICE_ID_HP_ZX1_LBA,
+ vendor_id: PCI_VENDOR_ID_HP,
+ chipset: HP_ZX1,
+ vendor_name: "HP",
+ chipset_name: "ZX1",
+ chipset_setup: hp_zx1_setup
+ },
+#endif
+
+ { }, /* dummy final entry, always present */
+};
+
+
+/* scan table above for supported devices */
+static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (agp_bridge_info); i++)
+ if (pdev->vendor == agp_bridge_info[i].vendor_id)
+ break;
+
+ if (i >= ARRAY_SIZE (agp_bridge_info)) {
+ printk (KERN_DEBUG PFX "unsupported bridge\n");
+ return -ENODEV;
+ }
+
+ while ((i < ARRAY_SIZE (agp_bridge_info)) &&
+ (agp_bridge_info[i].vendor_id == pdev->vendor)) {
+ if (pdev->device == agp_bridge_info[i].device_id) {
+#ifdef CONFIG_AGP_ALI
+ if (pdev->device == PCI_DEVICE_ID_AL_M1621_0) {
+ u8 hidden_1621_id;
+
+ pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
+ switch (hidden_1621_id) {
+ case 0x31:
+ agp_bridge_info[i].chipset_name="M1631";
+ break;
+ case 0x32:
+ agp_bridge_info[i].chipset_name="M1632";
+ break;
+ case 0x41:
+ agp_bridge_info[i].chipset_name="M1641";
+ break;
+ case 0x43:
+ break;
+ case 0x47:
+ agp_bridge_info[i].chipset_name="M1647";
+ break;
+ case 0x51:
+ agp_bridge_info[i].chipset_name="M1651";
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+
+ printk (KERN_INFO PFX "Detected %s %s chipset\n",
+ agp_bridge_info[i].vendor_name,
+ agp_bridge_info[i].chipset_name);
+ agp_bridge.type = agp_bridge_info[i].chipset;
+ return agp_bridge_info[i].chipset_setup (pdev);
+ }
+
+ i++;
+ }
+
+ i--; /* point to vendor generic entry (device_id == 0) */
+
+ /* try init anyway, if user requests it AND
+ * there is a 'generic' bridge entry for this vendor */
+ if (agp_try_unsupported && agp_bridge_info[i].device_id == 0) {
+ printk(KERN_WARNING PFX "Trying generic %s routines"
+ " for device id: %04x\n",
+ agp_bridge_info[i].vendor_name, pdev->device);
+ agp_bridge.type = agp_bridge_info[i].chipset;
+ return agp_bridge_info[i].chipset_setup (pdev);
+ }
+
+ printk(KERN_ERR PFX "Unsupported %s chipset (device id: %04x),"
+ " you might want to try agp_try_unsupported=1.\n",
+ agp_bridge_info[i].vendor_name, pdev->device);
+ return -ENODEV;
+}
+
+
+/* Supported Device Scanning routine */
+
+static int __init agp_find_supported_device(struct pci_dev *dev)
+{
+ u8 cap_ptr = 0x00;
+
+ agp_bridge.dev = dev;
+
+ /* Need to test for I810 here */
+#ifdef CONFIG_AGP_I810
+ if (dev->vendor == PCI_VENDOR_ID_INTEL) {
+ struct pci_dev *i810_dev;
+
+ switch (dev->device) {
+ case PCI_DEVICE_ID_INTEL_810_0:
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_810_1,
+ NULL);
+ if (i810_dev == NULL) {
+ printk(KERN_ERR PFX "Detected an Intel i810,"
+ " but could not find the secondary"
+ " device.\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO PFX "Detected an Intel "
+ "i810 Chipset.\n");
+ agp_bridge.type = INTEL_I810;
+ return intel_i810_setup (i810_dev);
+
+ case PCI_DEVICE_ID_INTEL_810_DC100_0:
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_810_DC100_1,
+ NULL);
+ if (i810_dev == NULL) {
+ printk(KERN_ERR PFX "Detected an Intel i810 "
+ "DC100, but could not find the "
+ "secondary device.\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO PFX "Detected an Intel i810 "
+ "DC100 Chipset.\n");
+ agp_bridge.type = INTEL_I810;
+ return intel_i810_setup(i810_dev);
+
+ case PCI_DEVICE_ID_INTEL_810_E_0:
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_810_E_1,
+ NULL);
+ if (i810_dev == NULL) {
+ printk(KERN_ERR PFX "Detected an Intel i810 E"
+ ", but could not find the secondary "
+ "device.\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO PFX "Detected an Intel i810 E "
+ "Chipset.\n");
+ agp_bridge.type = INTEL_I810;
+ return intel_i810_setup(i810_dev);
+
+ case PCI_DEVICE_ID_INTEL_815_0:
+ /* The i815 can operate either as an i810 style
+ * integrated device, or as an AGP4X motherboard.
+ *
+ * This only addresses the first mode:
+ */
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_815_1,
+ NULL);
+ if (i810_dev == NULL) {
+ printk(KERN_ERR PFX "agpgart: Detected an "
+ "Intel i815, but could not find the"
+ " secondary device. Assuming a "
+ "non-integrated video card.\n");
+ break;
+ }
+ printk(KERN_INFO PFX "agpgart: Detected an Intel i815 "
+ "Chipset.\n");
+ agp_bridge.type = INTEL_I810;
+ return intel_i810_setup(i810_dev);
+
+ case PCI_DEVICE_ID_INTEL_845_G_0:
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_845_G_1, NULL);
+ if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_845_G_1, i810_dev);
+ }
+
+ if (i810_dev == NULL) {
+ /*
+ * We probably have a I845MP chipset
+ * with an external graphics
+ * card. It will be initialized later
+ */
+ agp_bridge.type = INTEL_I845_G;
+ break;
+ }
+ printk(KERN_INFO PFX "Detected an Intel "
+ "845G Chipset.\n");
+ agp_bridge.type = INTEL_I810;
+ return intel_i830_setup(i810_dev);
+
+ case PCI_DEVICE_ID_INTEL_830_M_0:
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_830_M_1,
+ NULL);
+ if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
+ i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_830_M_1,
+ i810_dev);
+ }
+
+ if (i810_dev == NULL) {
+ /* Intel 830MP with external graphic card */
+ /* It will be initialized later */
+ agp_bridge.type = INTEL_I830_M;
+ break;
+ }
+ printk(KERN_INFO PFX "Detected an Intel "
+ "830M Chipset.\n");
+ agp_bridge.type = INTEL_I810;
+ return intel_i830_setup(i810_dev);
+ default:
+ break;
+ }
+ }
+#endif /* CONFIG_AGP_I810 */
+
+#ifdef CONFIG_AGP_SWORKS
+ /* Everything is on func 1 here so we are hardcoding function one */
+ if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS) {
+ struct pci_dev *bridge_dev;
+
+ bridge_dev = pci_find_slot ((unsigned int)dev->bus->number,
+ PCI_DEVFN(0, 1));
+ if(bridge_dev == NULL) {
+ printk(KERN_INFO PFX "agpgart: Detected a Serverworks "
+ "Chipset, but could not find the secondary "
+ "device.\n");
+ return -ENODEV;
+ }
+
+ switch (dev->device) {
+ case PCI_DEVICE_ID_SERVERWORKS_HE:
+ agp_bridge.type = SVWRKS_HE;
+ return serverworks_setup(bridge_dev);
+
+ case PCI_DEVICE_ID_SERVERWORKS_LE:
+ case 0x0007:
+ agp_bridge.type = SVWRKS_LE;
+ return serverworks_setup(bridge_dev);
+
+ default:
+ if(agp_try_unsupported) {
+ agp_bridge.type = SVWRKS_GENERIC;
+ return serverworks_setup(bridge_dev);
+ }
+ break;
+ }
+ }
+
+#endif /* CONFIG_AGP_SWORKS */
+
+#ifdef CONFIG_AGP_HP_ZX1
+ if (dev->vendor == PCI_VENDOR_ID_HP) {
+ /* ZX1 LBAs can be either PCI or AGP bridges */
+ if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
+ printk(KERN_INFO PFX "Detected HP ZX1 AGP "
+ "chipset at %s\n", dev->slot_name);
+ agp_bridge.type = HP_ZX1;
+ agp_bridge.dev = dev;
+ return hp_zx1_setup(dev);
+ }
+ return -ENODEV;
+ }
+#endif /* CONFIG_AGP_HP_ZX1 */
+
+ /* find capndx */
+ cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
+ if (cap_ptr == 0x00)
+ return -ENODEV;
+ agp_bridge.capndx = cap_ptr;
+
+ /* Fill in the mode register */
+ pci_read_config_dword(agp_bridge.dev,
+ agp_bridge.capndx + 4,
+ &agp_bridge.mode);
+
+ /* probe for known chipsets */
+ return agp_lookup_host_bridge (dev);
+}
+
+struct agp_max_table {
+ int mem;
+ int agp;
+};
+
+static struct agp_max_table maxes_table[9] __initdata =
+{
+ {0, 0},
+ {32, 4},
+ {64, 28},
+ {128, 96},
+ {256, 204},
+ {512, 440},
+ {1024, 942},
+ {2048, 1920},
+ {4096, 3932}
+};
+
+static int __init agp_find_max (void)
+{
+ long memory, index, result;
+
+ memory = virt_to_phys(high_memory) >> 20;
+ index = 1;
+
+ while ((memory > maxes_table[index].mem) &&
+ (index < 8)) {
+ index++;
+ }
+
+ result = maxes_table[index - 1].agp +
+ ( (memory - maxes_table[index - 1].mem) *
+ (maxes_table[index].agp - maxes_table[index - 1].agp)) /
+ (maxes_table[index].mem - maxes_table[index - 1].mem);
+
+ printk(KERN_INFO PFX "Maximum main memory to use "
+ "for agp memory: %ldM\n", result);
+ result = result << (20 - PAGE_SHIFT);
+ return result;
+}
+
+#define AGPGART_VERSION_MAJOR 0
+#define AGPGART_VERSION_MINOR 99
+
+static struct agp_version agp_current_version =
+{
+ major: AGPGART_VERSION_MAJOR,
+ minor: AGPGART_VERSION_MINOR,
+};
+
+static int __init agp_backend_initialize(struct pci_dev *dev)
+{
+ int size_value, rc, got_gatt=0, got_keylist=0;
+
+ memset(&agp_bridge, 0, sizeof(struct agp_bridge_data));
+ agp_bridge.type = NOT_SUPPORTED;
+ agp_bridge.max_memory_agp = agp_find_max();
+ agp_bridge.version = &agp_current_version;
+
+ rc = agp_find_supported_device(dev);
+ if (rc) {
+ /* not KERN_ERR because error msg should have already printed */
+ printk(KERN_DEBUG PFX "no supported devices found.\n");
+ return rc;
+ }
+
+ if (agp_bridge.needs_scratch_page == TRUE) {
+ void *addr;
+ addr = agp_bridge.agp_alloc_page();
+
+ if (addr == NULL) {
+ printk(KERN_ERR PFX "unable to get memory for "
+ "scratch page.\n");
+ return -ENOMEM;
+ }
+ agp_bridge.scratch_page = virt_to_phys(addr);
+ agp_bridge.scratch_page =
+ agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
+ }
+
+ size_value = agp_bridge.fetch_size();
+
+ if (size_value == 0) {
+ printk(KERN_ERR PFX "unable to determine aperture size.\n");
+ rc = -EINVAL;
+ goto err_out;
+ }
+ if (agp_bridge.create_gatt_table()) {
+ printk(KERN_ERR PFX "unable to get memory for graphics "
+ "translation table.\n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ got_gatt = 1;
+
+ agp_bridge.key_list = vmalloc(PAGE_SIZE * 4);
+ if (agp_bridge.key_list == NULL) {
+ printk(KERN_ERR PFX "error allocating memory for key lists.\n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ got_keylist = 1;
+
+ /* FIXME vmalloc'd memory not guaranteed contiguous */
+ memset(agp_bridge.key_list, 0, PAGE_SIZE * 4);
+
+ if (agp_bridge.configure()) {
+ printk(KERN_ERR PFX "error configuring host chipset.\n");
+ rc = -EINVAL;
+ goto err_out;
+ }
+
+ printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
+ size_value, agp_bridge.gart_bus_addr);
+
+ return 0;
+
+err_out:
+ if (agp_bridge.needs_scratch_page == TRUE) {
+ agp_bridge.scratch_page &= ~(0x00000fff);
+ agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
+ }
+ if (got_gatt)
+ agp_bridge.free_gatt_table();
+ if (got_keylist)
+ vfree(agp_bridge.key_list);
+ return rc;
+}
+
+
+/* cannot be __exit b/c as it could be called from __init code */
+static void agp_backend_cleanup(void)
+{
+ agp_bridge.cleanup();
+ agp_bridge.free_gatt_table();
+ vfree(agp_bridge.key_list);
+
+ if (agp_bridge.needs_scratch_page == TRUE) {
+ agp_bridge.scratch_page &= ~(0x00000fff);
+ agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
+ }
+}
+
+static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data)
+{
+ switch(rq)
+ {
+ case PM_SUSPEND:
+ return agp_bridge.suspend();
+ case PM_RESUME:
+ agp_bridge.resume();
+ return 0;
+ }
+ return 0;
+}
+
+extern int agp_frontend_initialize(void);
+extern void agp_frontend_cleanup(void);
+
+static const drm_agp_t drm_agp = {
+ &agp_free_memory,
+ &agp_allocate_memory,
+ &agp_bind_memory,
+ &agp_unbind_memory,
+ &agp_enable,
+ &agp_backend_acquire,
+ &agp_backend_release,
+ &agp_copy_info
+};
+
+static int agp_probe (struct pci_dev *dev, const struct pci_device_id *ent)
+{
+ int ret_val;
+
+ if (agp_bridge.type != NOT_SUPPORTED) {
+ printk (KERN_DEBUG PFX "Oops, don't init more than one agpgart device.\n");
+ return -ENODEV;
+ }
+
+ ret_val = agp_backend_initialize(dev);
+ if (ret_val) {
+ agp_bridge.type = NOT_SUPPORTED;
+ return ret_val;
+ }
+ ret_val = agp_frontend_initialize();
+ if (ret_val) {
+ agp_bridge.type = NOT_SUPPORTED;
+ agp_backend_cleanup();
+ return ret_val;
+ }
+
+ inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
+
+ pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power);
+ return 0;
+}
+
+static struct pci_device_id agp_pci_table[] __initdata = {
+ {
+ class: (PCI_CLASS_BRIDGE_HOST << 8),
+ class_mask: ~0,
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, agp_pci_table);
+
+static struct pci_driver agp_pci_driver = {
+ name: "agpgart",
+ id_table: agp_pci_table,
+ probe: agp_probe,
+};
+
+static int __init agp_init(void)
+{
+ int ret_val;
+
+ printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Jeff Hartmann\n",
+ AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
+
+ ret_val = pci_module_init(&agp_pci_driver);
+ if (ret_val) {
+ agp_bridge.type = NOT_SUPPORTED;
+ return ret_val;
+ }
+ return 0;
+}
+
+static void __exit agp_cleanup(void)
+{
+ pci_unregister_driver(&agp_pci_driver);
+ if (agp_bridge.type != NOT_SUPPORTED) {
+ pm_unregister_all(agp_power);
+ agp_frontend_cleanup();
+ agp_backend_cleanup();
+ inter_module_unregister("drm_agp");
+ }
+}
+
+module_init(agp_init);
+module_exit(agp_cleanup);
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 94e405104df4..4515f8ee5d2e 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -27,6 +27,67 @@
#ifndef _AGP_BACKEND_PRIV_H
#define _AGP_BACKEND_PRIV_H 1
+#include <asm/agp.h> /* for flush_agp_cache() */
+
+extern struct agp_bridge_data agp_bridge;
+
+/* Generic routines. */
+void agp_generic_agp_enable(u32 mode);
+int agp_generic_create_gatt_table(void);
+int agp_generic_free_gatt_table(void);
+agp_memory *agp_create_memory(int scratch_pages);
+int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type);
+int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, int type);
+agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
+void agp_generic_free_by_type(agp_memory * curr);
+void *agp_generic_alloc_page(void);
+void agp_generic_destroy_page(void *addr);
+int agp_generic_suspend(void);
+void agp_generic_resume(void);
+void agp_free_key(int key);
+
+/* chipset specific init routines. */
+int __init ali_generic_setup (struct pci_dev *pdev);
+int __init amd_irongate_setup (struct pci_dev *pdev);
+int __init hp_zx1_setup (struct pci_dev *pdev);
+int __init intel_i460_setup (struct pci_dev *pdev);
+int __init intel_generic_setup (struct pci_dev *pdev);
+int __init intel_i810_setup(struct pci_dev *i810_dev);
+int __init intel_815_setup(struct pci_dev *pdev);
+int __init intel_i830_setup(struct pci_dev *i830_dev);
+int __init intel_820_setup (struct pci_dev *pdev);
+int __init intel_830mp_setup (struct pci_dev *pdev);
+int __init intel_840_setup (struct pci_dev *pdev);
+int __init intel_845_setup (struct pci_dev *pdev);
+int __init intel_850_setup (struct pci_dev *pdev);
+int __init intel_860_setup (struct pci_dev *pdev);
+int __init serverworks_setup (struct pci_dev *pdev);
+int __init sis_generic_setup (struct pci_dev *pdev);
+int __init via_generic_setup (struct pci_dev *pdev);
+
+#define AGPGART_MODULE_NAME "agpgart"
+#define PFX AGPGART_MODULE_NAME ": "
+
+
+#ifdef CONFIG_SMP
+static void ipi_handler(void *null)
+{
+ flush_agp_cache();
+}
+
+static void __attribute__((unused)) global_cache_flush(void)
+{
+ if (smp_call_function(ipi_handler, NULL, 1, 1) != 0)
+ panic(PFX "timed out waiting for the other CPUs!\n");
+ flush_agp_cache();
+}
+#else
+static void global_cache_flush(void)
+{
+ flush_agp_cache();
+}
+#endif /* !CONFIG_SMP */
+
enum aper_size_type {
U8_APER_SIZE,
U16_APER_SIZE,
@@ -35,55 +96,55 @@ enum aper_size_type {
FIXED_APER_SIZE
};
-typedef struct _gatt_mask {
+struct gatt_mask {
unsigned long mask;
u32 type;
/* totally device specific, for integrated chipsets that
* might have different types of memory masks. For other
* devices this will probably be ignored */
-} gatt_mask;
+};
-typedef struct _aper_size_info_8 {
+struct aper_size_info_8 {
int size;
int num_entries;
int page_order;
u8 size_value;
-} aper_size_info_8;
+};
-typedef struct _aper_size_info_16 {
+struct aper_size_info_16 {
int size;
int num_entries;
int page_order;
u16 size_value;
-} aper_size_info_16;
+};
-typedef struct _aper_size_info_32 {
+struct aper_size_info_32 {
int size;
int num_entries;
int page_order;
u32 size_value;
-} aper_size_info_32;
+};
-typedef struct _aper_size_info_lvl2 {
+struct aper_size_info_lvl2 {
int size;
int num_entries;
u32 size_value;
-} aper_size_info_lvl2;
+};
-typedef struct _aper_size_info_fixed {
+struct aper_size_info_fixed {
int size;
int num_entries;
int page_order;
-} aper_size_info_fixed;
+};
struct agp_bridge_data {
- agp_version *version;
+ struct agp_version *version;
void *aperture_sizes;
void *previous_size;
void *current_size;
void *dev_private_data;
struct pci_dev *dev;
- gatt_mask *masks;
+ struct gatt_mask *masks;
unsigned long *gatt_table;
unsigned long *gatt_table_real;
unsigned long scratch_page;
@@ -125,26 +186,26 @@ struct agp_bridge_data {
};
-#define OUTREG64(mmap, addr, val) __raw_writeq((val), (mmap)+(addr))
-#define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr))
-#define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr))
-#define OUTREG8(mmap, addr, val) __raw_writeb((val), (mmap)+(addr))
+#define OUTREG64(mmap, addr, val) __raw_writeq((val), (mmap)+(addr))
+#define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr))
+#define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr))
+#define OUTREG8(mmap, addr, val) __raw_writeb((val), (mmap)+(addr))
-#define INREG64(mmap, addr) __raw_readq((mmap)+(addr))
-#define INREG32(mmap, addr) __raw_readl((mmap)+(addr))
-#define INREG16(mmap, addr) __raw_readw((mmap)+(addr))
-#define INREG8(mmap, addr) __raw_readb((mmap)+(addr))
+#define INREG64(mmap, addr) __raw_readq((mmap)+(addr))
+#define INREG32(mmap, addr) __raw_readl((mmap)+(addr))
+#define INREG16(mmap, addr) __raw_readw((mmap)+(addr))
+#define INREG8(mmap, addr) __raw_readb((mmap)+(addr))
-#define KB(x) ((x) * 1024)
-#define MB(x) (KB (KB (x)))
-#define GB(x) (MB (KB (x)))
+#define KB(x) ((x) * 1024)
+#define MB(x) (KB (KB (x)))
+#define GB(x) (MB (KB (x)))
#define CACHE_FLUSH agp_bridge.cache_flush
-#define A_SIZE_8(x) ((aper_size_info_8 *) x)
-#define A_SIZE_16(x) ((aper_size_info_16 *) x)
-#define A_SIZE_32(x) ((aper_size_info_32 *) x)
-#define A_SIZE_LVL2(x) ((aper_size_info_lvl2 *) x)
-#define A_SIZE_FIX(x) ((aper_size_info_fixed *) x)
+#define A_SIZE_8(x) ((struct aper_size_info_8 *) x)
+#define A_SIZE_16(x) ((struct aper_size_info_16 *) x)
+#define A_SIZE_32(x) ((struct aper_size_info_32 *) x)
+#define A_SIZE_LVL2(x) ((struct aper_size_info_lvl2 *) x)
+#define A_SIZE_FIX(x) ((struct aper_size_info_fixed *) x)
#define A_IDX8() (A_SIZE_8(agp_bridge.aperture_sizes) + i)
#define A_IDX16() (A_SIZE_16(agp_bridge.aperture_sizes) + i)
#define A_IDX32() (A_SIZE_32(agp_bridge.aperture_sizes) + i)
@@ -152,91 +213,88 @@ struct agp_bridge_data {
#define A_IDXFIX() (A_SIZE_FIX(agp_bridge.aperture_sizes) + i)
#define MAXKEY (4096 * 32)
-#define AGPGART_MODULE_NAME "agpgart"
-#define PFX AGPGART_MODULE_NAME ": "
-
-#define PGE_EMPTY(p) (!(p) || (p) == (unsigned long) agp_bridge.scratch_page)
+#define PGE_EMPTY(p) (!(p) || (p) == (unsigned long) agp_bridge.scratch_page)
#ifndef PCI_DEVICE_ID_VIA_82C691_0
-#define PCI_DEVICE_ID_VIA_82C691_0 0x0691
+#define PCI_DEVICE_ID_VIA_82C691_0 0x0691
#endif
#ifndef PCI_DEVICE_ID_VIA_8371_0
-#define PCI_DEVICE_ID_VIA_8371_0 0x0391
+#define PCI_DEVICE_ID_VIA_8371_0 0x0391
#endif
#ifndef PCI_DEVICE_ID_VIA_8363_0
-#define PCI_DEVICE_ID_VIA_8363_0 0x0305
+#define PCI_DEVICE_ID_VIA_8363_0 0x0305
#endif
#ifndef PCI_DEVICE_ID_VIA_82C694X_0
-#define PCI_DEVICE_ID_VIA_82C694X_0 0x0605
+#define PCI_DEVICE_ID_VIA_82C694X_0 0x0605
#endif
#ifndef PCI_DEVICE_ID_INTEL_810_0
-#define PCI_DEVICE_ID_INTEL_810_0 0x7120
+#define PCI_DEVICE_ID_INTEL_810_0 0x7120
#endif
#ifndef PCI_DEVICE_ID_INTEL_845_G_0
#define PCI_DEVICE_ID_INTEL_845_G_0 0x2560
#endif
#ifndef PCI_DEVICE_ID_INTEL_845_G_1
-#define PCI_DEVICE_ID_INTEL_845_G_1 0x2562
+#define PCI_DEVICE_ID_INTEL_845_G_1 0x2562
#endif
#ifndef PCI_DEVICE_ID_INTEL_830_M_0
#define PCI_DEVICE_ID_INTEL_830_M_0 0x3575
#endif
#ifndef PCI_DEVICE_ID_INTEL_830_M_1
-#define PCI_DEVICE_ID_INTEL_830_M_1 0x3577
+#define PCI_DEVICE_ID_INTEL_830_M_1 0x3577
#endif
#ifndef PCI_DEVICE_ID_INTEL_820_0
-#define PCI_DEVICE_ID_INTEL_820_0 0x2500
+#define PCI_DEVICE_ID_INTEL_820_0 0x2500
#endif
#ifndef PCI_DEVICE_ID_INTEL_820_UP_0
-#define PCI_DEVICE_ID_INTEL_820_UP_0 0x2501
+#define PCI_DEVICE_ID_INTEL_820_UP_0 0x2501
#endif
#ifndef PCI_DEVICE_ID_INTEL_840_0
-#define PCI_DEVICE_ID_INTEL_840_0 0x1a21
+#define PCI_DEVICE_ID_INTEL_840_0 0x1a21
#endif
#ifndef PCI_DEVICE_ID_INTEL_845_0
-#define PCI_DEVICE_ID_INTEL_845_0 0x1a30
+#define PCI_DEVICE_ID_INTEL_845_0 0x1a30
#endif
#ifndef PCI_DEVICE_ID_INTEL_850_0
-#define PCI_DEVICE_ID_INTEL_850_0 0x2530
+#define PCI_DEVICE_ID_INTEL_850_0 0x2530
#endif
#ifndef PCI_DEVICE_ID_INTEL_860_0
-#define PCI_DEVICE_ID_INTEL_860_0 0x2531
+#define PCI_DEVICE_ID_INTEL_860_0 0x2531
#endif
#ifndef PCI_DEVICE_ID_INTEL_810_DC100_0
-#define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122
+#define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122
#endif
#ifndef PCI_DEVICE_ID_INTEL_810_E_0
-#define PCI_DEVICE_ID_INTEL_810_E_0 0x7124
+#define PCI_DEVICE_ID_INTEL_810_E_0 0x7124
#endif
#ifndef PCI_DEVICE_ID_INTEL_82443GX_0
-#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0
+#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0
#endif
#ifndef PCI_DEVICE_ID_INTEL_810_1
-#define PCI_DEVICE_ID_INTEL_810_1 0x7121
+#define PCI_DEVICE_ID_INTEL_810_1 0x7121
#endif
#ifndef PCI_DEVICE_ID_INTEL_810_DC100_1
-#define PCI_DEVICE_ID_INTEL_810_DC100_1 0x7123
+#define PCI_DEVICE_ID_INTEL_810_DC100_1 0x7123
#endif
#ifndef PCI_DEVICE_ID_INTEL_810_E_1
-#define PCI_DEVICE_ID_INTEL_810_E_1 0x7125
+#define PCI_DEVICE_ID_INTEL_810_E_1 0x7125
#endif
#ifndef PCI_DEVICE_ID_INTEL_815_0
-#define PCI_DEVICE_ID_INTEL_815_0 0x1130
+#define PCI_DEVICE_ID_INTEL_815_0 0x1130
#endif
#ifndef PCI_DEVICE_ID_INTEL_815_1
-#define PCI_DEVICE_ID_INTEL_815_1 0x1132
+#define PCI_DEVICE_ID_INTEL_815_1 0x1132
#endif
#ifndef PCI_DEVICE_ID_INTEL_82443GX_1
-#define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1
+#define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1
#endif
#ifndef PCI_DEVICE_ID_INTEL_460GX
-#define PCI_DEVICE_ID_INTEL_460GX 0x84ea
+#define PCI_DEVICE_ID_INTEL_460GX 0x84ea
#endif
#ifndef PCI_DEVICE_ID_AMD_IRONGATE_0
-#define PCI_DEVICE_ID_AMD_IRONGATE_0 0x7006
+#define PCI_DEVICE_ID_AMD_IRONGATE_0 0x7006
#endif
#ifndef PCI_DEVICE_ID_AMD_761_0
-#define PCI_DEVICE_ID_AMD_761_0 0x700e
+#define PCI_DEVICE_ID_AMD_761_0 0x700e
#endif
#ifndef PCI_DEVICE_ID_AMD_762_0
#define PCI_DEVICE_ID_AMD_762_0 0x700C
@@ -270,12 +328,12 @@ struct agp_bridge_data {
#endif
/* intel register */
-#define INTEL_APBASE 0x10
-#define INTEL_APSIZE 0xb4
-#define INTEL_ATTBASE 0xb8
-#define INTEL_AGPCTRL 0xb0
-#define INTEL_NBXCFG 0x50
-#define INTEL_ERRSTS 0x91
+#define INTEL_APBASE 0x10
+#define INTEL_APSIZE 0xb4
+#define INTEL_ATTBASE 0xb8
+#define INTEL_AGPCTRL 0xb0
+#define INTEL_NBXCFG 0x50
+#define INTEL_ERRSTS 0x91
/* Intel 460GX Registers */
#define INTEL_I460_APBASE 0x10
@@ -287,116 +345,120 @@ struct agp_bridge_data {
#define INTEL_I460_GATT_COHERENT (1UL << 25)
/* intel i830 registers */
-#define I830_GMCH_CTRL 0x52
-#define I830_GMCH_ENABLED 0x4
-#define I830_GMCH_MEM_MASK 0x1
-#define I830_GMCH_MEM_64M 0x1
-#define I830_GMCH_MEM_128M 0
-#define I830_GMCH_GMS_MASK 0x70
-#define I830_GMCH_GMS_DISABLED 0x00
-#define I830_GMCH_GMS_LOCAL 0x10
-#define I830_GMCH_GMS_STOLEN_512 0x20
-#define I830_GMCH_GMS_STOLEN_1024 0x30
-#define I830_GMCH_GMS_STOLEN_8192 0x40
-#define I830_RDRAM_CHANNEL_TYPE 0x03010
-#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5)
-#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3)
+#define I830_GMCH_CTRL 0x52
+#define I830_GMCH_ENABLED 0x4
+#define I830_GMCH_MEM_MASK 0x1
+#define I830_GMCH_MEM_64M 0x1
+#define I830_GMCH_MEM_128M 0
+#define I830_GMCH_GMS_MASK 0x70
+#define I830_GMCH_GMS_DISABLED 0x00
+#define I830_GMCH_GMS_LOCAL 0x10
+#define I830_GMCH_GMS_STOLEN_512 0x20
+#define I830_GMCH_GMS_STOLEN_1024 0x30
+#define I830_GMCH_GMS_STOLEN_8192 0x40
+#define I830_RDRAM_CHANNEL_TYPE 0x03010
+#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5)
+#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3)
/* This one is for I830MP w. an external graphic card */
-#define INTEL_I830_ERRSTS 0x92
+#define INTEL_I830_ERRSTS 0x92
+
+/* intel 815 register */
+#define INTEL_815_APCONT 0x51
+#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
/* intel i820 registers */
-#define INTEL_I820_RDCR 0x51
-#define INTEL_I820_ERRSTS 0xc8
+#define INTEL_I820_RDCR 0x51
+#define INTEL_I820_ERRSTS 0xc8
/* intel i840 registers */
-#define INTEL_I840_MCHCFG 0x50
-#define INTEL_I840_ERRSTS 0xc8
+#define INTEL_I840_MCHCFG 0x50
+#define INTEL_I840_ERRSTS 0xc8
/* intel i845 registers */
-#define INTEL_I845_AGPM 0x51
-#define INTEL_I845_ERRSTS 0xc8
+#define INTEL_I845_AGPM 0x51
+#define INTEL_I845_ERRSTS 0xc8
/* intel i850 registers */
-#define INTEL_I850_MCHCFG 0x50
-#define INTEL_I850_ERRSTS 0xc8
+#define INTEL_I850_MCHCFG 0x50
+#define INTEL_I850_ERRSTS 0xc8
/* intel i860 registers */
#define INTEL_I860_MCHCFG 0x50
#define INTEL_I860_ERRSTS 0xc8
/* intel i810 registers */
-#define I810_GMADDR 0x10
-#define I810_MMADDR 0x14
-#define I810_PTE_BASE 0x10000
-#define I810_PTE_MAIN_UNCACHED 0x00000000
-#define I810_PTE_LOCAL 0x00000002
-#define I810_PTE_VALID 0x00000001
-#define I810_SMRAM_MISCC 0x70
-#define I810_GFX_MEM_WIN_SIZE 0x00010000
-#define I810_GFX_MEM_WIN_32M 0x00010000
-#define I810_GMS 0x000000c0
-#define I810_GMS_DISABLE 0x00000000
-#define I810_PGETBL_CTL 0x2020
-#define I810_PGETBL_ENABLED 0x00000001
-#define I810_DRAM_CTL 0x3000
-#define I810_DRAM_ROW_0 0x00000001
-#define I810_DRAM_ROW_0_SDRAM 0x00000001
+#define I810_GMADDR 0x10
+#define I810_MMADDR 0x14
+#define I810_PTE_BASE 0x10000
+#define I810_PTE_MAIN_UNCACHED 0x00000000
+#define I810_PTE_LOCAL 0x00000002
+#define I810_PTE_VALID 0x00000001
+#define I810_SMRAM_MISCC 0x70
+#define I810_GFX_MEM_WIN_SIZE 0x00010000
+#define I810_GFX_MEM_WIN_32M 0x00010000
+#define I810_GMS 0x000000c0
+#define I810_GMS_DISABLE 0x00000000
+#define I810_PGETBL_CTL 0x2020
+#define I810_PGETBL_ENABLED 0x00000001
+#define I810_DRAM_CTL 0x3000
+#define I810_DRAM_ROW_0 0x00000001
+#define I810_DRAM_ROW_0_SDRAM 0x00000001
/* VIA register */
-#define VIA_APBASE 0x10
-#define VIA_GARTCTRL 0x80
-#define VIA_APSIZE 0x84
-#define VIA_ATTBASE 0x88
+#define VIA_APBASE 0x10
+#define VIA_GARTCTRL 0x80
+#define VIA_APSIZE 0x84
+#define VIA_ATTBASE 0x88
/* SiS registers */
-#define SIS_APBASE 0x10
-#define SIS_ATTBASE 0x90
-#define SIS_APSIZE 0x94
-#define SIS_TLBCNTRL 0x97
-#define SIS_TLBFLUSH 0x98
+#define SIS_APBASE 0x10
+#define SIS_ATTBASE 0x90
+#define SIS_APSIZE 0x94
+#define SIS_TLBCNTRL 0x97
+#define SIS_TLBFLUSH 0x98
/* AMD registers */
-#define AMD_APBASE 0x10
-#define AMD_MMBASE 0x14
-#define AMD_APSIZE 0xac
-#define AMD_MODECNTL 0xb0
-#define AMD_MODECNTL2 0xb2
-#define AMD_GARTENABLE 0x02 /* In mmio region (16-bit register) */
-#define AMD_ATTBASE 0x04 /* In mmio region (32-bit register) */
-#define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */
-#define AMD_CACHEENTRY 0x10 /* In mmio region (32-bit register) */
+#define AMD_APBASE 0x10
+#define AMD_MMBASE 0x14
+#define AMD_APSIZE 0xac
+#define AMD_MODECNTL 0xb0
+#define AMD_MODECNTL2 0xb2
+#define AMD_GARTENABLE 0x02 /* In mmio region (16-bit register) */
+#define AMD_ATTBASE 0x04 /* In mmio region (32-bit register) */
+#define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */
+#define AMD_CACHEENTRY 0x10 /* In mmio region (32-bit register) */
/* ALi registers */
-#define ALI_APBASE 0x10
-#define ALI_AGPCTRL 0xb8
-#define ALI_ATTBASE 0xbc
-#define ALI_TLBCTRL 0xc0
-#define ALI_TAGCTRL 0xc4
-#define ALI_CACHE_FLUSH_CTRL 0xD0
+#define ALI_APBASE 0x10
+#define ALI_AGPCTRL 0xb8
+#define ALI_ATTBASE 0xbc
+#define ALI_TLBCTRL 0xc0
+#define ALI_TAGCTRL 0xc4
+#define ALI_CACHE_FLUSH_CTRL 0xD0
#define ALI_CACHE_FLUSH_ADDR_MASK 0xFFFFF000
-#define ALI_CACHE_FLUSH_EN 0x100
+#define ALI_CACHE_FLUSH_EN 0x100
/* Serverworks Registers */
-#define SVWRKS_APSIZE 0x10
-#define SVWRKS_SIZE_MASK 0xfe000000
+#define SVWRKS_APSIZE 0x10
+#define SVWRKS_SIZE_MASK 0xfe000000
-#define SVWRKS_MMBASE 0x14
-#define SVWRKS_CACHING 0x4b
-#define SVWRKS_FEATURE 0x68
+#define SVWRKS_MMBASE 0x14
+#define SVWRKS_CACHING 0x4b
+#define SVWRKS_FEATURE 0x68
/* func 1 registers */
-#define SVWRKS_AGP_ENABLE 0x60
-#define SVWRKS_COMMAND 0x04
+#define SVWRKS_AGP_ENABLE 0x60
+#define SVWRKS_COMMAND 0x04
/* Memory mapped registers */
-#define SVWRKS_GART_CACHE 0x02
-#define SVWRKS_GATTBASE 0x04
-#define SVWRKS_TLBFLUSH 0x10
-#define SVWRKS_POSTFLUSH 0x14
-#define SVWRKS_DIRFLUSH 0x0c
+#define SVWRKS_GART_CACHE 0x02
+#define SVWRKS_GATTBASE 0x04
+#define SVWRKS_TLBFLUSH 0x10
+#define SVWRKS_POSTFLUSH 0x14
+#define SVWRKS_DIRFLUSH 0x0c
/* HP ZX1 SBA registers */
#define HP_ZX1_CTRL 0x200
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
deleted file mode 100644
index 8ba761695215..000000000000
--- a/drivers/char/agp/agpgart_be.c
+++ /dev/null
@@ -1,5114 +0,0 @@
-/*
- * AGPGART module version 0.99
- * Copyright (C) 1999 Jeff Hartmann
- * Copyright (C) 1999 Precision Insight, Inc.
- * Copyright (C) 1999 Xi Graphics, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
- * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * TODO:
- * - Allocate more than order 0 pages to avoid too much linear map splitting.
- */
-#include <linux/config.h>
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/miscdevice.h>
-#include <linux/pm.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/agp.h>
-
-#include <linux/agp_backend.h>
-#include "agp.h"
-
-MODULE_AUTHOR("Jeff Hartmann <jhartmann@precisioninsight.com>");
-MODULE_PARM(agp_try_unsupported, "1i");
-MODULE_LICENSE("GPL and additional rights");
-EXPORT_SYMBOL(agp_free_memory);
-EXPORT_SYMBOL(agp_allocate_memory);
-EXPORT_SYMBOL(agp_copy_info);
-EXPORT_SYMBOL(agp_bind_memory);
-EXPORT_SYMBOL(agp_unbind_memory);
-EXPORT_SYMBOL(agp_enable);
-EXPORT_SYMBOL(agp_backend_acquire);
-EXPORT_SYMBOL(agp_backend_release);
-
-static struct agp_bridge_data agp_bridge;
-static int agp_try_unsupported __initdata = 0;
-
-#ifdef CONFIG_SMP
-static void ipi_handler(void *null)
-{
- flush_agp_cache();
-}
-
-static void smp_flush_cache(void)
-{
- if (smp_call_function(ipi_handler, NULL, 1, 1) != 0)
- panic(PFX "timed out waiting for the other CPUs!\n");
- flush_agp_cache();
-}
-#define global_cache_flush smp_flush_cache
-#else /* CONFIG_SMP */
-static void global_cache_flush(void)
-{
- flush_agp_cache();
-}
-#endif /* !CONFIG_SMP */
-
-int agp_backend_acquire(void)
-{
- if (agp_bridge.type == NOT_SUPPORTED) {
- return -EINVAL;
- }
- atomic_inc(&agp_bridge.agp_in_use);
-
- if (atomic_read(&agp_bridge.agp_in_use) != 1) {
- atomic_dec(&agp_bridge.agp_in_use);
- return -EBUSY;
- }
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-void agp_backend_release(void)
-{
- if (agp_bridge.type == NOT_SUPPORTED) {
- return;
- }
- atomic_dec(&agp_bridge.agp_in_use);
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * Generic routines for handling agp_memory structures -
- * They use the basic page allocation routines to do the
- * brunt of the work.
- */
-
-
-static void agp_free_key(int key)
-{
-
- if (key < 0) {
- return;
- }
- if (key < MAXKEY) {
- clear_bit(key, agp_bridge.key_list);
- }
-}
-
-static int agp_get_key(void)
-{
- int bit;
-
- bit = find_first_zero_bit(agp_bridge.key_list, MAXKEY);
- if (bit < MAXKEY) {
- set_bit(bit, agp_bridge.key_list);
- return bit;
- }
- return -1;
-}
-
-static agp_memory *agp_create_memory(int scratch_pages)
-{
- agp_memory *new;
-
- new = kmalloc(sizeof(agp_memory), GFP_KERNEL);
-
- if (new == NULL) {
- return NULL;
- }
- memset(new, 0, sizeof(agp_memory));
- new->key = agp_get_key();
-
- if (new->key < 0) {
- kfree(new);
- return NULL;
- }
- new->memory = vmalloc(PAGE_SIZE * scratch_pages);
-
- if (new->memory == NULL) {
- agp_free_key(new->key);
- kfree(new);
- return NULL;
- }
- new->num_scratch_pages = scratch_pages;
- return new;
-}
-
-void agp_free_memory(agp_memory * curr)
-{
- int i;
-
- if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL)) {
- return;
- }
- if (curr->is_bound == TRUE) {
- agp_unbind_memory(curr);
- }
- if (curr->type != 0) {
- agp_bridge.free_by_type(curr);
- return;
- }
- if (curr->page_count != 0) {
- for (i = 0; i < curr->page_count; i++) {
- curr->memory[i] &= ~(0x00000fff);
- agp_bridge.agp_destroy_page(phys_to_virt(curr->memory[i]));
- }
- }
- agp_free_key(curr->key);
- vfree(curr->memory);
- kfree(curr);
- MOD_DEC_USE_COUNT;
-}
-
-#define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))
-
-agp_memory *agp_allocate_memory(size_t page_count, u32 type)
-{
- int scratch_pages;
- agp_memory *new;
- int i;
-
- if (agp_bridge.type == NOT_SUPPORTED) {
- return NULL;
- }
- if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) >
- agp_bridge.max_memory_agp) {
- return NULL;
- }
-
- if (type != 0) {
- new = agp_bridge.alloc_by_type(page_count, type);
- return new;
- }
- /* We always increase the module count, since free auto-decrements
- * it
- */
-
- MOD_INC_USE_COUNT;
-
- scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
-
- new = agp_create_memory(scratch_pages);
-
- if (new == NULL) {
- MOD_DEC_USE_COUNT;
- return NULL;
- }
-
- for (i = 0; i < page_count; i++) {
- void *addr = agp_bridge.agp_alloc_page();
-
- if (addr == NULL) {
- /* Free this structure */
- agp_free_memory(new);
- return NULL;
- }
- new->memory[i] =
- agp_bridge.mask_memory(virt_to_phys(addr), type);
- new->page_count++;
- }
-
- flush_agp_mappings();
-
- return new;
-}
-
-/* End - Generic routines for handling agp_memory structures */
-
-static int agp_return_size(void)
-{
- int current_size;
- void *temp;
-
- temp = agp_bridge.current_size;
-
- switch (agp_bridge.size_type) {
- case U8_APER_SIZE:
- current_size = A_SIZE_8(temp)->size;
- break;
- case U16_APER_SIZE:
- current_size = A_SIZE_16(temp)->size;
- break;
- case U32_APER_SIZE:
- current_size = A_SIZE_32(temp)->size;
- break;
- case LVL2_APER_SIZE:
- current_size = A_SIZE_LVL2(temp)->size;
- break;
- case FIXED_APER_SIZE:
- current_size = A_SIZE_FIX(temp)->size;
- break;
- default:
- current_size = 0;
- break;
- }
-
- return current_size;
-}
-
-/* Routine to copy over information structure */
-
-void agp_copy_info(agp_kern_info * info)
-{
- unsigned long page_mask = 0;
- int i;
-
- memset(info, 0, sizeof(agp_kern_info));
- if (agp_bridge.type == NOT_SUPPORTED) {
- info->chipset = agp_bridge.type;
- return;
- }
- info->version.major = agp_bridge.version->major;
- info->version.minor = agp_bridge.version->minor;
- info->device = agp_bridge.dev;
- info->chipset = agp_bridge.type;
- info->mode = agp_bridge.mode;
- info->aper_base = agp_bridge.gart_bus_addr;
- info->aper_size = agp_return_size();
- info->max_memory = agp_bridge.max_memory_agp;
- info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
- info->cant_use_aperture = agp_bridge.cant_use_aperture;
-
- for(i = 0; i < agp_bridge.num_of_masks; i++)
- page_mask |= agp_bridge.mask_memory(page_mask, i);
-
- info->page_mask = ~page_mask;
-}
-
-/* End - Routine to copy over information structure */
-
-/*
- * Routines for handling swapping of agp_memory into the GATT -
- * These routines take agp_memory and insert them into the GATT.
- * They call device specific routines to actually write to the GATT.
- */
-
-int agp_bind_memory(agp_memory * curr, off_t pg_start)
-{
- int ret_val;
-
- if ((agp_bridge.type == NOT_SUPPORTED) ||
- (curr == NULL) || (curr->is_bound == TRUE)) {
- return -EINVAL;
- }
- if (curr->is_flushed == FALSE) {
- CACHE_FLUSH();
- curr->is_flushed = TRUE;
- }
- ret_val = agp_bridge.insert_memory(curr, pg_start, curr->type);
-
- if (ret_val != 0) {
- return ret_val;
- }
- curr->is_bound = TRUE;
- curr->pg_start = pg_start;
- return 0;
-}
-
-int agp_unbind_memory(agp_memory * curr)
-{
- int ret_val;
-
- if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL)) {
- return -EINVAL;
- }
- if (curr->is_bound != TRUE) {
- return -EINVAL;
- }
- ret_val = agp_bridge.remove_memory(curr, curr->pg_start, curr->type);
-
- if (ret_val != 0) {
- return ret_val;
- }
- curr->is_bound = FALSE;
- curr->pg_start = 0;
- return 0;
-}
-
-/* End - Routines for handling swapping of agp_memory into the GATT */
-
-/*
- * Driver routines - start
- * Currently this module supports the following chipsets:
- * i810, i815, 440lx, 440bx, 440gx, i830, i840, i845, i850, i860, via vp3,
- * via mvp3, via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541,
- * and generic support for the SiS chipsets.
- */
-
-/* Generic Agp routines - Start */
-
-static void agp_generic_agp_enable(u32 mode)
-{
- struct pci_dev *device = NULL;
- u32 command, scratch;
- u8 cap_ptr;
-
- pci_read_config_dword(agp_bridge.dev,
- agp_bridge.capndx + 4,
- &command);
-
- /*
- * PASS1: go throu all devices that claim to be
- * AGP devices and collect their data.
- */
-
-
- pci_for_each_dev(device) {
- cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
- if (cap_ptr != 0x00) {
- /*
- * Ok, here we have a AGP device. Disable impossible
- * settings, and adjust the readqueue to the minimum.
- */
-
- pci_read_config_dword(device, cap_ptr + 4, &scratch);
-
- /* adjust RQ depth */
- command =
- ((command & ~0xff000000) |
- min_t(u32, (mode & 0xff000000),
- min_t(u32, (command & 0xff000000),
- (scratch & 0xff000000))));
-
- /* disable SBA if it's not supported */
- if (!((command & 0x00000200) &&
- (scratch & 0x00000200) &&
- (mode & 0x00000200)))
- command &= ~0x00000200;
-
- /* disable FW if it's not supported */
- if (!((command & 0x00000010) &&
- (scratch & 0x00000010) &&
- (mode & 0x00000010)))
- command &= ~0x00000010;
-
- if (!((command & 4) &&
- (scratch & 4) &&
- (mode & 4)))
- command &= ~0x00000004;
-
- if (!((command & 2) &&
- (scratch & 2) &&
- (mode & 2)))
- command &= ~0x00000002;
-
- if (!((command & 1) &&
- (scratch & 1) &&
- (mode & 1)))
- command &= ~0x00000001;
- }
- }
- /*
- * PASS2: Figure out the 4X/2X/1X setting and enable the
- * target (our motherboard chipset).
- */
-
- if (command & 4) {
- command &= ~3; /* 4X */
- }
- if (command & 2) {
- command &= ~5; /* 2X */
- }
- if (command & 1) {
- command &= ~6; /* 1X */
- }
- command |= 0x00000100;
-
- pci_write_config_dword(agp_bridge.dev,
- agp_bridge.capndx + 8,
- command);
-
- /*
- * PASS3: Go throu all AGP devices and update the
- * command registers.
- */
-
- pci_for_each_dev(device) {
- cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
- if (cap_ptr != 0x00)
- pci_write_config_dword(device, cap_ptr + 8, command);
- }
-}
-
-static int agp_generic_create_gatt_table(void)
-{
- char *table;
- char *table_end;
- int size;
- int page_order;
- int num_entries;
- int i;
- void *temp;
- struct page *page;
-
- /* The generic routines can't handle 2 level gatt's */
- if (agp_bridge.size_type == LVL2_APER_SIZE) {
- return -EINVAL;
- }
-
- table = NULL;
- i = agp_bridge.aperture_size_idx;
- temp = agp_bridge.current_size;
- size = page_order = num_entries = 0;
-
- if (agp_bridge.size_type != FIXED_APER_SIZE) {
- do {
- switch (agp_bridge.size_type) {
- case U8_APER_SIZE:
- size = A_SIZE_8(temp)->size;
- page_order =
- A_SIZE_8(temp)->page_order;
- num_entries =
- A_SIZE_8(temp)->num_entries;
- break;
- case U16_APER_SIZE:
- size = A_SIZE_16(temp)->size;
- page_order = A_SIZE_16(temp)->page_order;
- num_entries = A_SIZE_16(temp)->num_entries;
- break;
- case U32_APER_SIZE:
- size = A_SIZE_32(temp)->size;
- page_order = A_SIZE_32(temp)->page_order;
- num_entries = A_SIZE_32(temp)->num_entries;
- break;
- /* This case will never really happen. */
- case FIXED_APER_SIZE:
- case LVL2_APER_SIZE:
- default:
- size = page_order = num_entries = 0;
- break;
- }
-
- table = (char *) __get_free_pages(GFP_KERNEL,
- page_order);
-
- if (table == NULL) {
- i++;
- switch (agp_bridge.size_type) {
- case U8_APER_SIZE:
- agp_bridge.current_size = A_IDX8();
- break;
- case U16_APER_SIZE:
- agp_bridge.current_size = A_IDX16();
- break;
- case U32_APER_SIZE:
- agp_bridge.current_size = A_IDX32();
- break;
- /* This case will never really
- * happen.
- */
- case FIXED_APER_SIZE:
- case LVL2_APER_SIZE:
- default:
- agp_bridge.current_size =
- agp_bridge.current_size;
- break;
- }
- temp = agp_bridge.current_size;
- } else {
- agp_bridge.aperture_size_idx = i;
- }
- } while ((table == NULL) &&
- (i < agp_bridge.num_aperture_sizes));
- } else {
- size = ((aper_size_info_fixed *) temp)->size;
- page_order = ((aper_size_info_fixed *) temp)->page_order;
- num_entries = ((aper_size_info_fixed *) temp)->num_entries;
- table = (char *) __get_free_pages(GFP_KERNEL, page_order);
- }
-
- if (table == NULL) {
- return -ENOMEM;
- }
- table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
-
- for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
- SetPageReserved(page);
-
- agp_bridge.gatt_table_real = (unsigned long *) table;
- CACHE_FLUSH();
- agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
- (PAGE_SIZE * (1 << page_order)));
- CACHE_FLUSH();
-
- if (agp_bridge.gatt_table == NULL) {
- for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
- ClearPageReserved(page);
-
- free_pages((unsigned long) table, page_order);
-
- return -ENOMEM;
- }
- agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real);
-
- for (i = 0; i < num_entries; i++) {
- agp_bridge.gatt_table[i] =
- (unsigned long) agp_bridge.scratch_page;
- }
-
- return 0;
-}
-
-static int agp_generic_suspend(void)
-{
- return 0;
-}
-
-static void agp_generic_resume(void)
-{
- return;
-}
-
-static int agp_generic_free_gatt_table(void)
-{
- int page_order;
- char *table, *table_end;
- void *temp;
- struct page *page;
-
- temp = agp_bridge.current_size;
-
- switch (agp_bridge.size_type) {
- case U8_APER_SIZE:
- page_order = A_SIZE_8(temp)->page_order;
- break;
- case U16_APER_SIZE:
- page_order = A_SIZE_16(temp)->page_order;
- break;
- case U32_APER_SIZE:
- page_order = A_SIZE_32(temp)->page_order;
- break;
- case FIXED_APER_SIZE:
- page_order = A_SIZE_FIX(temp)->page_order;
- break;
- case LVL2_APER_SIZE:
- /* The generic routines can't deal with 2 level gatt's */
- return -EINVAL;
- break;
- default:
- page_order = 0;
- break;
- }
-
- /* Do not worry about freeing memory, because if this is
- * called, then all agp memory is deallocated and removed
- * from the table.
- */
-
- iounmap(agp_bridge.gatt_table);
- table = (char *) agp_bridge.gatt_table_real;
- table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
-
- for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
- ClearPageReserved(page);
-
- free_pages((unsigned long) agp_bridge.gatt_table_real, page_order);
- return 0;
-}
-
-static int agp_generic_insert_memory(agp_memory * mem,
- off_t pg_start, int type)
-{
- int i, j, num_entries;
- void *temp;
-
- temp = agp_bridge.current_size;
-
- switch (agp_bridge.size_type) {
- case U8_APER_SIZE:
- num_entries = A_SIZE_8(temp)->num_entries;
- break;
- case U16_APER_SIZE:
- num_entries = A_SIZE_16(temp)->num_entries;
- break;
- case U32_APER_SIZE:
- num_entries = A_SIZE_32(temp)->num_entries;
- break;
- case FIXED_APER_SIZE:
- num_entries = A_SIZE_FIX(temp)->num_entries;
- break;
- case LVL2_APER_SIZE:
- /* The generic routines can't deal with 2 level gatt's */
- return -EINVAL;
- break;
- default:
- num_entries = 0;
- break;
- }
-
- if (type != 0 || mem->type != 0) {
- /* The generic routines know nothing of memory types */
- return -EINVAL;
- }
- if ((pg_start + mem->page_count) > num_entries) {
- return -EINVAL;
- }
- j = pg_start;
-
- while (j < (pg_start + mem->page_count)) {
- if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
- return -EBUSY;
- }
- j++;
- }
-
- if (mem->is_flushed == FALSE) {
- CACHE_FLUSH();
- mem->is_flushed = TRUE;
- }
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- agp_bridge.gatt_table[j] = mem->memory[i];
- }
-
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static int agp_generic_remove_memory(agp_memory * mem, off_t pg_start,
- int type)
-{
- int i;
-
- if (type != 0 || mem->type != 0) {
- /* The generic routines know nothing of memory types */
- return -EINVAL;
- }
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- agp_bridge.gatt_table[i] =
- (unsigned long) agp_bridge.scratch_page;
- }
-
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static agp_memory *agp_generic_alloc_by_type(size_t page_count, int type)
-{
- return NULL;
-}
-
-static void agp_generic_free_by_type(agp_memory * curr)
-{
- if (curr->memory != NULL) {
- vfree(curr->memory);
- }
- agp_free_key(curr->key);
- kfree(curr);
-}
-
-/*
- * Basic Page Allocation Routines -
- * These routines handle page allocation
- * and by default they reserve the allocated
- * memory. They also handle incrementing the
- * current_memory_agp value, Which is checked
- * against a maximum value.
- */
-
-static void *agp_generic_alloc_page(void)
-{
- struct page * page;
-
- page = alloc_page(GFP_KERNEL);
- if (page == NULL)
- return 0;
-
- map_page_into_agp(page);
-
- get_page(page);
- SetPageLocked(page);
- atomic_inc(&agp_bridge.current_memory_agp);
- return page_address(page);
-}
-
-static void agp_generic_destroy_page(void *addr)
-{
- struct page *page;
-
- if (addr == NULL)
- return;
-
- page = virt_to_page(addr);
- unmap_page_from_agp(page);
- put_page(page);
- unlock_page(page);
- free_page((unsigned long)addr);
- atomic_dec(&agp_bridge.current_memory_agp);
-}
-
-/* End Basic Page Allocation Routines */
-
-void agp_enable(u32 mode)
-{
- if (agp_bridge.type == NOT_SUPPORTED) return;
- agp_bridge.agp_enable(mode);
-}
-
-/* End - Generic Agp routines */
-
-#ifdef CONFIG_AGP_I810
-static aper_size_info_fixed intel_i810_sizes[] =
-{
- {64, 16384, 4},
- /* The 32M mode still requires a 64k gatt */
- {32, 8192, 4}
-};
-
-#define AGP_DCACHE_MEMORY 1
-#define AGP_PHYS_MEMORY 2
-
-static gatt_mask intel_i810_masks[] =
-{
- {I810_PTE_VALID, 0},
- {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY},
- {I810_PTE_VALID, 0}
-};
-
-static struct _intel_i810_private {
- struct pci_dev *i810_dev; /* device one */
- volatile u8 *registers;
- int num_dcache_entries;
-} intel_i810_private;
-
-static int intel_i810_fetch_size(void)
-{
- u32 smram_miscc;
- aper_size_info_fixed *values;
-
- pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc);
- values = A_SIZE_FIX(agp_bridge.aperture_sizes);
-
- if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
- printk(KERN_WARNING PFX "i810 is disabled\n");
- return 0;
- }
- if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + 1);
- agp_bridge.aperture_size_idx = 1;
- return values[1].size;
- } else {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values);
- agp_bridge.aperture_size_idx = 0;
- return values[0].size;
- }
-
- return 0;
-}
-
-static int intel_i810_configure(void)
-{
- aper_size_info_fixed *current_size;
- u32 temp;
- int i;
-
- current_size = A_SIZE_FIX(agp_bridge.current_size);
-
- pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
- temp &= 0xfff80000;
-
- intel_i810_private.registers =
- (volatile u8 *) ioremap(temp, 128 * 4096);
-
- if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL)
- & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
- /* This will need to be dynamically assigned */
- printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n");
- intel_i810_private.num_dcache_entries = 1024;
- }
- pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL,
- agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
- CACHE_FLUSH();
-
- if (agp_bridge.needs_scratch_page == TRUE) {
- for (i = 0; i < current_size->num_entries; i++) {
- OUTREG32(intel_i810_private.registers,
- I810_PTE_BASE + (i * 4),
- agp_bridge.scratch_page);
- }
- }
- return 0;
-}
-
-static void intel_i810_cleanup(void)
-{
- OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0);
- iounmap((void *) intel_i810_private.registers);
-}
-
-static void intel_i810_tlbflush(agp_memory * mem)
-{
- return;
-}
-
-static void intel_i810_agp_enable(u32 mode)
-{
- return;
-}
-
-static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start,
- int type)
-{
- int i, j, num_entries;
- void *temp;
-
- temp = agp_bridge.current_size;
- num_entries = A_SIZE_FIX(temp)->num_entries;
-
- if ((pg_start + mem->page_count) > num_entries) {
- return -EINVAL;
- }
- for (j = pg_start; j < (pg_start + mem->page_count); j++) {
- if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
- return -EBUSY;
- }
- }
-
- if (type != 0 || mem->type != 0) {
- if ((type == AGP_DCACHE_MEMORY) &&
- (mem->type == AGP_DCACHE_MEMORY)) {
- /* special insert */
- CACHE_FLUSH();
- for (i = pg_start;
- i < (pg_start + mem->page_count); i++) {
- OUTREG32(intel_i810_private.registers,
- I810_PTE_BASE + (i * 4),
- (i * 4096) | I810_PTE_LOCAL |
- I810_PTE_VALID);
- }
- CACHE_FLUSH();
- agp_bridge.tlb_flush(mem);
- return 0;
- }
- if((type == AGP_PHYS_MEMORY) &&
- (mem->type == AGP_PHYS_MEMORY)) {
- goto insert;
- }
- return -EINVAL;
- }
-
-insert:
- CACHE_FLUSH();
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- OUTREG32(intel_i810_private.registers,
- I810_PTE_BASE + (j * 4), mem->memory[i]);
- }
- CACHE_FLUSH();
-
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start,
- int type)
-{
- int i;
-
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- OUTREG32(intel_i810_private.registers,
- I810_PTE_BASE + (i * 4),
- agp_bridge.scratch_page);
- }
-
- CACHE_FLUSH();
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
-{
- agp_memory *new;
-
- if (type == AGP_DCACHE_MEMORY) {
- if (pg_count != intel_i810_private.num_dcache_entries) {
- return NULL;
- }
- new = agp_create_memory(1);
-
- if (new == NULL) {
- return NULL;
- }
- new->type = AGP_DCACHE_MEMORY;
- new->page_count = pg_count;
- new->num_scratch_pages = 0;
- vfree(new->memory);
- MOD_INC_USE_COUNT;
- return new;
- }
- if(type == AGP_PHYS_MEMORY) {
- void *addr;
- /* The I810 requires a physical address to program
- * it's mouse pointer into hardware. However the
- * Xserver still writes to it through the agp
- * aperture
- */
- if (pg_count != 1) {
- return NULL;
- }
- new = agp_create_memory(1);
-
- if (new == NULL) {
- return NULL;
- }
- MOD_INC_USE_COUNT;
- addr = agp_bridge.agp_alloc_page();
-
- if (addr == NULL) {
- /* Free this structure */
- agp_free_memory(new);
- return NULL;
- }
- new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type);
- new->page_count = 1;
- new->num_scratch_pages = 1;
- new->type = AGP_PHYS_MEMORY;
- new->physical = virt_to_phys((void *) new->memory[0]);
- return new;
- }
-
- return NULL;
-}
-
-static void intel_i810_free_by_type(agp_memory * curr)
-{
- agp_free_key(curr->key);
- if(curr->type == AGP_PHYS_MEMORY) {
- agp_bridge.agp_destroy_page(
- phys_to_virt(curr->memory[0]));
- vfree(curr->memory);
- }
- kfree(curr);
- MOD_DEC_USE_COUNT;
-}
-
-static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
-{
- /* Type checking must be done elsewhere */
- return addr | agp_bridge.masks[type].mask;
-}
-
-static int __init intel_i810_setup(struct pci_dev *i810_dev)
-{
- intel_i810_private.i810_dev = i810_dev;
-
- agp_bridge.masks = intel_i810_masks;
- agp_bridge.num_of_masks = 2;
- agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
- agp_bridge.size_type = FIXED_APER_SIZE;
- agp_bridge.num_aperture_sizes = 2;
- agp_bridge.dev_private_data = (void *) &intel_i810_private;
- agp_bridge.needs_scratch_page = TRUE;
- agp_bridge.configure = intel_i810_configure;
- agp_bridge.fetch_size = intel_i810_fetch_size;
- agp_bridge.cleanup = intel_i810_cleanup;
- agp_bridge.tlb_flush = intel_i810_tlbflush;
- agp_bridge.mask_memory = intel_i810_mask_memory;
- agp_bridge.agp_enable = intel_i810_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = intel_i810_insert_entries;
- agp_bridge.remove_memory = intel_i810_remove_entries;
- agp_bridge.alloc_by_type = intel_i810_alloc_by_type;
- agp_bridge.free_by_type = intel_i810_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-}
-
-static aper_size_info_fixed intel_i830_sizes[] =
-{
- {128, 32768, 5},
- /* The 64M mode still requires a 128k gatt */
- {64, 16384, 5}
-};
-
-static struct _intel_i830_private {
- struct pci_dev *i830_dev; /* device one */
- volatile u8 *registers;
- int gtt_entries;
-} intel_i830_private;
-
-static void intel_i830_init_gtt_entries(void) {
- u16 gmch_ctrl;
- int gtt_entries;
- u8 rdct;
- static const int ddt[4] = { 0, 16, 32, 64 };
-
- pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
-
- switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
- case I830_GMCH_GMS_STOLEN_512:
- gtt_entries = KB(512);
- printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
- break;
- case I830_GMCH_GMS_STOLEN_1024:
- gtt_entries = MB(1);
- printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
- break;
- case I830_GMCH_GMS_STOLEN_8192:
- gtt_entries = MB(8);
- printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
- break;
- case I830_GMCH_GMS_LOCAL:
- rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE);
- gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]);
- printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1));
- break;
- default:
- printk(KERN_INFO PFX "no video memory detected.\n");
- gtt_entries = 0;
- break;
- }
-
- gtt_entries /= KB(4);
-
- intel_i830_private.gtt_entries = gtt_entries;
-}
-
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(void)
-{
- int page_order;
- aper_size_info_fixed *size;
- int num_entries;
- u32 temp;
-
- size = agp_bridge.current_size;
- page_order = size->page_order;
- num_entries = size->num_entries;
- agp_bridge.gatt_table_real = 0;
-
- pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
- temp &= 0xfff80000;
-
- intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
- if (!intel_i830_private.registers) return (-ENOMEM);
-
- temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000;
- CACHE_FLUSH();
-
- /* we have to call this as early as possible after the MMIO base address is known */
- intel_i830_init_gtt_entries();
-
- agp_bridge.gatt_table = NULL;
-
- agp_bridge.gatt_bus_addr = temp;
-
- return(0);
-}
-
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(void)
-{
- return(0);
-}
-
-static int intel_i830_fetch_size(void)
-{
- u16 gmch_ctrl;
- aper_size_info_fixed *values;
-
- pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
- values = A_SIZE_FIX(agp_bridge.aperture_sizes);
-
- if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
- agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
- agp_bridge.aperture_size_idx = 0;
- return(values[0].size);
- } else {
- agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
- agp_bridge.aperture_size_idx = 1;
- return(values[1].size);
- }
-
- return(0);
-}
-
-static int intel_i830_configure(void)
-{
- aper_size_info_fixed *current_size;
- u32 temp;
- u16 gmch_ctrl;
- int i;
-
- current_size = A_SIZE_FIX(agp_bridge.current_size);
-
- pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
- gmch_ctrl |= I830_GMCH_ENABLED;
- pci_write_config_word(agp_bridge.dev,I830_GMCH_CTRL,gmch_ctrl);
-
- OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
- CACHE_FLUSH();
-
- if (agp_bridge.needs_scratch_page == TRUE)
- for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
- OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
-
- return (0);
-}
-
-static void intel_i830_cleanup(void)
-{
- iounmap((void *) intel_i830_private.registers);
-}
-
-static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type)
-{
- int i,j,num_entries;
- void *temp;
-
- temp = agp_bridge.current_size;
- num_entries = A_SIZE_FIX(temp)->num_entries;
-
- if (pg_start < intel_i830_private.gtt_entries) {
- printk (KERN_DEBUG "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n",
- pg_start,intel_i830_private.gtt_entries);
-
- printk ("Trying to insert into local/stolen memory\n");
- return (-EINVAL);
- }
-
- if ((pg_start + mem->page_count) > num_entries)
- return (-EINVAL);
-
- /* The i830 can't check the GTT for entries since its read only,
- * depend on the caller to make the correct offset decisions.
- */
-
- if ((type != 0 && type != AGP_PHYS_MEMORY) ||
- (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
- return (-EINVAL);
-
- CACHE_FLUSH();
-
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
- OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
-
- CACHE_FLUSH();
-
- agp_bridge.tlb_flush(mem);
-
- return(0);
-}
-
-static int intel_i830_remove_entries(agp_memory *mem,off_t pg_start,int type)
-{
- int i;
-
- CACHE_FLUSH ();
-
- if (pg_start < intel_i830_private.gtt_entries) {
- printk ("Trying to disable local/stolen memory\n");
- return (-EINVAL);
- }
-
- for (i = pg_start; i < (mem->page_count + pg_start); i++)
- OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
-
- CACHE_FLUSH();
-
- agp_bridge.tlb_flush(mem);
-
- return (0);
-}
-
-static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
-{
- agp_memory *nw;
-
- /* always return NULL for now */
- if (type == AGP_DCACHE_MEMORY) return(NULL);
-
- if (type == AGP_PHYS_MEMORY) {
- void *addr;
-
- /* The i830 requires a physical address to program
- * it's mouse pointer into hardware. However the
- * Xserver still writes to it through the agp
- * aperture
- */
-
- if (pg_count != 1) return(NULL);
-
- nw = agp_create_memory(1);
-
- if (nw == NULL) return(NULL);
-
- MOD_INC_USE_COUNT;
- addr = agp_bridge.agp_alloc_page();
- if (addr == NULL) {
- /* free this structure */
- agp_free_memory(nw);
- return(NULL);
- }
-
- nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type);
- nw->page_count = 1;
- nw->num_scratch_pages = 1;
- nw->type = AGP_PHYS_MEMORY;
- nw->physical = virt_to_phys(addr);
- return(nw);
- }
-
- return(NULL);
-}
-
-static int __init intel_i830_setup(struct pci_dev *i830_dev)
-{
- intel_i830_private.i830_dev = i830_dev;
-
- agp_bridge.masks = intel_i810_masks;
- agp_bridge.num_of_masks = 3;
- agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
- agp_bridge.size_type = FIXED_APER_SIZE;
- agp_bridge.num_aperture_sizes = 2;
-
- agp_bridge.dev_private_data = (void *) &intel_i830_private;
- agp_bridge.needs_scratch_page = TRUE;
-
- agp_bridge.configure = intel_i830_configure;
- agp_bridge.fetch_size = intel_i830_fetch_size;
- agp_bridge.cleanup = intel_i830_cleanup;
- agp_bridge.tlb_flush = intel_i810_tlbflush;
- agp_bridge.mask_memory = intel_i810_mask_memory;
- agp_bridge.agp_enable = intel_i810_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
-
- agp_bridge.create_gatt_table = intel_i830_create_gatt_table;
- agp_bridge.free_gatt_table = intel_i830_free_gatt_table;
-
- agp_bridge.insert_memory = intel_i830_insert_entries;
- agp_bridge.remove_memory = intel_i830_remove_entries;
- agp_bridge.alloc_by_type = intel_i830_alloc_by_type;
- agp_bridge.free_by_type = intel_i810_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
-
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return(0);
-}
-
-#endif /* CONFIG_AGP_I810 */
-
-#ifdef CONFIG_AGP_I460
-
-/* BIOS configures the chipset so that one of two apbase registers are used */
-static u8 intel_i460_dynamic_apbase = 0x10;
-
-/* 460 supports multiple GART page sizes, so GART pageshift is dynamic */
-static u8 intel_i460_pageshift = 12;
-static u32 intel_i460_pagesize;
-
-/* Keep track of which is larger, chipset or kernel page size. */
-static u32 intel_i460_cpk = 1;
-
-/* Structure for tracking partial use of 4MB GART pages */
-static u32 **i460_pg_detail = NULL;
-static u32 *i460_pg_count = NULL;
-
-#define I460_CPAGES_PER_KPAGE (PAGE_SIZE >> intel_i460_pageshift)
-#define I460_KPAGES_PER_CPAGE ((1 << intel_i460_pageshift) >> PAGE_SHIFT)
-
-#define I460_SRAM_IO_DISABLE (1 << 4)
-#define I460_BAPBASE_ENABLE (1 << 3)
-#define I460_AGPSIZ_MASK 0x7
-#define I460_4M_PS (1 << 1)
-
-#define log2(x) ffz(~(x))
-
-static inline void intel_i460_read_back (volatile u32 *entry)
-{
- /*
- * The 460 spec says we have to read the last location written to
- * make sure that all writes have taken effect
- */
- *entry;
-}
-
-static int intel_i460_fetch_size(void)
-{
- int i;
- u8 temp;
- aper_size_info_8 *values;
-
- /* Determine the GART page size */
- pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp);
- intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12;
- intel_i460_pagesize = 1UL << intel_i460_pageshift;
-
- values = A_SIZE_8(agp_bridge.aperture_sizes);
-
- pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp);
-
- /* Exit now if the IO drivers for the GART SRAMS are turned off */
- if (temp & I460_SRAM_IO_DISABLE) {
- printk(KERN_ERR PFX "GART SRAMS disabled on 460GX chipset\n");
- printk(KERN_ERR PFX "AGPGART operation not possible\n");
- return 0;
- }
-
- /* Make sure we don't try to create an 2 ^ 23 entry GATT */
- if ((intel_i460_pageshift == 0) && ((temp & I460_AGPSIZ_MASK) == 4)) {
- printk(KERN_ERR PFX "We can't have a 32GB aperture with 4KB GART pages\n");
- return 0;
- }
-
- /* Determine the proper APBASE register */
- if (temp & I460_BAPBASE_ENABLE)
- intel_i460_dynamic_apbase = INTEL_I460_BAPBASE;
- else
- intel_i460_dynamic_apbase = INTEL_I460_APBASE;
-
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- /*
- * Dynamically calculate the proper num_entries and page_order values for
- * the define aperture sizes. Take care not to shift off the end of
- * values[i].size.
- */
- values[i].num_entries = (values[i].size << 8) >> (intel_i460_pageshift - 12);
- values[i].page_order = log2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT);
- }
-
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- /* Neglect control bits when matching up size_value */
- if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) {
- agp_bridge.previous_size = agp_bridge.current_size = (void *) (values + i);
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-/* There isn't anything to do here since 460 has no GART TLB. */
-static void intel_i460_tlb_flush(agp_memory * mem)
-{
- return;
-}
-
-/*
- * This utility function is needed to prevent corruption of the control bits
- * which are stored along with the aperture size in 460's AGPSIZ register
- */
-static void intel_i460_write_agpsiz(u8 size_value)
-{
- u8 temp;
-
- pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp);
- pci_write_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ,
- ((temp & ~I460_AGPSIZ_MASK) | size_value));
-}
-
-static void intel_i460_cleanup(void)
-{
- aper_size_info_8 *previous_size;
-
- previous_size = A_SIZE_8(agp_bridge.previous_size);
- intel_i460_write_agpsiz(previous_size->size_value);
-
- if (intel_i460_cpk == 0) {
- vfree(i460_pg_detail);
- vfree(i460_pg_count);
- }
-}
-
-
-/* Control bits for Out-Of-GART coherency and Burst Write Combining */
-#define I460_GXBCTL_OOG (1UL << 0)
-#define I460_GXBCTL_BWC (1UL << 2)
-
-static int intel_i460_configure(void)
-{
- union {
- u32 small[2];
- u64 large;
- } temp;
- u8 scratch;
- int i;
-
- aper_size_info_8 *current_size;
-
- temp.large = 0;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
- intel_i460_write_agpsiz(current_size->size_value);
-
- /*
- * Do the necessary rigmarole to read all eight bytes of APBASE.
- * This has to be done since the AGP aperture can be above 4GB on
- * 460 based systems.
- */
- pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase, &(temp.small[0]));
- pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase + 4, &(temp.small[1]));
-
- /* Clear BAR control bits */
- agp_bridge.gart_bus_addr = temp.large & ~((1UL << 3) - 1);
-
- pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &scratch);
- pci_write_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL,
- (scratch & 0x02) | I460_GXBCTL_OOG | I460_GXBCTL_BWC);
-
- /*
- * Initialize partial allocation trackers if a GART page is bigger than
- * a kernel page.
- */
- if (I460_CPAGES_PER_KPAGE >= 1) {
- intel_i460_cpk = 1;
- } else {
- intel_i460_cpk = 0;
-
- i460_pg_detail = vmalloc(sizeof(*i460_pg_detail) * current_size->num_entries);
- i460_pg_count = vmalloc(sizeof(*i460_pg_count) * current_size->num_entries);
-
- for (i = 0; i < current_size->num_entries; i++) {
- i460_pg_count[i] = 0;
- i460_pg_detail[i] = NULL;
- }
- }
- return 0;
-}
-
-static int intel_i460_create_gatt_table(void)
-{
- char *table;
- int i;
- int page_order;
- int num_entries;
- void *temp;
-
- /*
- * Load up the fixed address of the GART SRAMS which hold our
- * GATT table.
- */
- table = (char *) __va(INTEL_I460_ATTBASE);
-
- temp = agp_bridge.current_size;
- page_order = A_SIZE_8(temp)->page_order;
- num_entries = A_SIZE_8(temp)->num_entries;
-
- agp_bridge.gatt_table_real = (u32 *) table;
- agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
- (PAGE_SIZE * (1 << page_order)));
- agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real);
-
- for (i = 0; i < num_entries; i++) {
- agp_bridge.gatt_table[i] = 0;
- }
-
- intel_i460_read_back(agp_bridge.gatt_table + i - 1);
- return 0;
-}
-
-static int intel_i460_free_gatt_table(void)
-{
- int num_entries;
- int i;
- void *temp;
-
- temp = agp_bridge.current_size;
-
- num_entries = A_SIZE_8(temp)->num_entries;
-
- for (i = 0; i < num_entries; i++) {
- agp_bridge.gatt_table[i] = 0;
- }
-
- intel_i460_read_back(agp_bridge.gatt_table + i - 1);
-
- iounmap(agp_bridge.gatt_table);
- return 0;
-}
-
-/* These functions are called when PAGE_SIZE exceeds the GART page size */
-
-static int intel_i460_insert_memory_cpk(agp_memory * mem, off_t pg_start, int type)
-{
- int i, j, k, num_entries;
- void *temp;
- unsigned long paddr;
-
- /*
- * The rest of the kernel will compute page offsets in terms of
- * PAGE_SIZE.
- */
- pg_start = I460_CPAGES_PER_KPAGE * pg_start;
-
- temp = agp_bridge.current_size;
- num_entries = A_SIZE_8(temp)->num_entries;
-
- if ((pg_start + I460_CPAGES_PER_KPAGE * mem->page_count) > num_entries) {
- printk(KERN_ERR PFX "Looks like we're out of AGP memory\n");
- return -EINVAL;
- }
-
- j = pg_start;
- while (j < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count)) {
- if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
- return -EBUSY;
- }
- j++;
- }
-
-#if 0
- /* not necessary since 460 GART is operated in coherent mode... */
- if (mem->is_flushed == FALSE) {
- CACHE_FLUSH();
- mem->is_flushed = TRUE;
- }
-#endif
-
- for (i = 0, j = pg_start; i < mem->page_count; i++) {
- paddr = mem->memory[i];
- for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, paddr += intel_i460_pagesize)
- agp_bridge.gatt_table[j] = (u32) agp_bridge.mask_memory(paddr, mem->type);
- }
-
- intel_i460_read_back(agp_bridge.gatt_table + j - 1);
- return 0;
-}
-
-static int intel_i460_remove_memory_cpk(agp_memory * mem, off_t pg_start, int type)
-{
- int i;
-
- pg_start = I460_CPAGES_PER_KPAGE * pg_start;
-
- for (i = pg_start; i < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count); i++)
- agp_bridge.gatt_table[i] = 0;
-
- intel_i460_read_back(agp_bridge.gatt_table + i - 1);
- return 0;
-}
-
-/*
- * These functions are called when the GART page size exceeds PAGE_SIZE.
- *
- * This situation is interesting since AGP memory allocations that are
- * smaller than a single GART page are possible. The structures i460_pg_count
- * and i460_pg_detail track partial allocation of the large GART pages to
- * work around this issue.
- *
- * i460_pg_count[pg_num] tracks the number of kernel pages in use within
- * GART page pg_num. i460_pg_detail[pg_num] is an array containing a
- * psuedo-GART entry for each of the aforementioned kernel pages. The whole
- * of i460_pg_detail is equivalent to a giant GATT with page size equal to
- * that of the kernel.
- */
-
-static void *intel_i460_alloc_large_page(int pg_num)
-{
- int i;
- void *bp, *bp_end;
- struct page *page;
-
- i460_pg_detail[pg_num] = (void *) vmalloc(sizeof(u32) * I460_KPAGES_PER_CPAGE);
- if (i460_pg_detail[pg_num] == NULL) {
- printk(KERN_ERR PFX "Out of memory, we're in trouble...\n");
- return NULL;
- }
-
- for (i = 0; i < I460_KPAGES_PER_CPAGE; i++)
- i460_pg_detail[pg_num][i] = 0;
-
- bp = (void *) __get_free_pages(GFP_KERNEL, intel_i460_pageshift - PAGE_SHIFT);
- if (bp == NULL) {
- printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n");
- return NULL;
- }
-
- bp_end = bp + ((PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT))) - 1);
-
- for (page = virt_to_page(bp); page <= virt_to_page(bp_end); page++) {
- atomic_inc(&agp_bridge.current_memory_agp);
- }
- return bp;
-}
-
-static void intel_i460_free_large_page(int pg_num, unsigned long addr)
-{
- struct page *page;
- void *bp, *bp_end;
-
- bp = (void *) __va(addr);
- bp_end = bp + (PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT)));
-
- vfree(i460_pg_detail[pg_num]);
- i460_pg_detail[pg_num] = NULL;
-
- for (page = virt_to_page(bp); page < virt_to_page(bp_end); page++) {
- atomic_dec(&agp_bridge.current_memory_agp);
- }
-
- free_pages((unsigned long) bp, intel_i460_pageshift - PAGE_SHIFT);
-}
-
-static int intel_i460_insert_memory_kpc(agp_memory * mem, off_t pg_start, int type)
-{
- int i, pg, start_pg, end_pg, start_offset, end_offset, idx;
- int num_entries;
- void *temp;
- unsigned long paddr;
-
- temp = agp_bridge.current_size;
- num_entries = A_SIZE_8(temp)->num_entries;
-
- /* Figure out what pg_start means in terms of our large GART pages */
- start_pg = pg_start / I460_KPAGES_PER_CPAGE;
- start_offset = pg_start % I460_KPAGES_PER_CPAGE;
- end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE;
- end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE;
-
- if (end_pg > num_entries) {
- printk(KERN_ERR PFX "Looks like we're out of AGP memory\n");
- return -EINVAL;
- }
-
- /* Check if the requested region of the aperture is free */
- for (pg = start_pg; pg <= end_pg; pg++) {
- /* Allocate new GART pages if necessary */
- if (i460_pg_detail[pg] == NULL) {
- temp = intel_i460_alloc_large_page(pg);
- if (temp == NULL)
- return -ENOMEM;
- agp_bridge.gatt_table[pg] = agp_bridge.mask_memory((unsigned long) temp,
- 0);
- intel_i460_read_back(agp_bridge.gatt_table + pg);
- }
-
- for (idx = ((pg == start_pg) ? start_offset : 0);
- idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE);
- idx++)
- {
- if (i460_pg_detail[pg][idx] != 0)
- return -EBUSY;
- }
- }
-
-#if 0
- /* not necessary since 460 GART is operated in coherent mode... */
- if (mem->is_flushed == FALSE) {
- CACHE_FLUSH();
- mem->is_flushed = TRUE;
- }
-#endif
-
- for (pg = start_pg, i = 0; pg <= end_pg; pg++) {
- paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]);
- for (idx = ((pg == start_pg) ? start_offset : 0);
- idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE);
- idx++, i++)
- {
- mem->memory[i] = paddr + (idx * PAGE_SIZE);
- i460_pg_detail[pg][idx] = agp_bridge.mask_memory(mem->memory[i],
- mem->type);
- i460_pg_count[pg]++;
- }
- }
-
- return 0;
-}
-
-static int intel_i460_remove_memory_kpc(agp_memory * mem, off_t pg_start, int type)
-{
- int i, pg, start_pg, end_pg, start_offset, end_offset, idx;
- int num_entries;
- void *temp;
- unsigned long paddr;
-
- temp = agp_bridge.current_size;
- num_entries = A_SIZE_8(temp)->num_entries;
-
- /* Figure out what pg_start means in terms of our large GART pages */
- start_pg = pg_start / I460_KPAGES_PER_CPAGE;
- start_offset = pg_start % I460_KPAGES_PER_CPAGE;
- end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE;
- end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE;
-
- for (i = 0, pg = start_pg; pg <= end_pg; pg++) {
- for (idx = ((pg == start_pg) ? start_offset : 0);
- idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE);
- idx++, i++)
- {
- mem->memory[i] = 0;
- i460_pg_detail[pg][idx] = 0;
- i460_pg_count[pg]--;
- }
-
- /* Free GART pages if they are unused */
- if (i460_pg_count[pg] == 0) {
- paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]);
- agp_bridge.gatt_table[pg] = agp_bridge.scratch_page;
- intel_i460_read_back(agp_bridge.gatt_table + pg);
- intel_i460_free_large_page(pg, paddr);
- }
- }
- return 0;
-}
-
-/* Dummy routines to call the approriate {cpk,kpc} function */
-
-static int intel_i460_insert_memory(agp_memory * mem, off_t pg_start, int type)
-{
- if (intel_i460_cpk)
- return intel_i460_insert_memory_cpk(mem, pg_start, type);
- else
- return intel_i460_insert_memory_kpc(mem, pg_start, type);
-}
-
-static int intel_i460_remove_memory(agp_memory * mem, off_t pg_start, int type)
-{
- if (intel_i460_cpk)
- return intel_i460_remove_memory_cpk(mem, pg_start, type);
- else
- return intel_i460_remove_memory_kpc(mem, pg_start, type);
-}
-
-/*
- * If the kernel page size is smaller that the chipset page size, we don't
- * want to allocate memory until we know where it is to be bound in the
- * aperture (a multi-kernel-page alloc might fit inside of an already
- * allocated GART page). Consequently, don't allocate or free anything
- * if i460_cpk (meaning chipset pages per kernel page) isn't set.
- *
- * Let's just hope nobody counts on the allocated AGP memory being there
- * before bind time (I don't think current drivers do)...
- */
-static void * intel_i460_alloc_page(void)
-{
- if (intel_i460_cpk)
- return agp_generic_alloc_page();
-
- /* Returning NULL would cause problems */
- /* AK: really dubious code. */
- return (void *)~0UL;
-}
-
-static void intel_i460_destroy_page(void *page)
-{
- if (intel_i460_cpk)
- agp_generic_destroy_page(page);
-}
-
-static gatt_mask intel_i460_masks[] =
-{
- {
- INTEL_I460_GATT_VALID | INTEL_I460_GATT_COHERENT,
- 0
- }
-};
-
-static unsigned long intel_i460_mask_memory(unsigned long addr, int type)
-{
- /* Make sure the returned address is a valid GATT entry */
- return (agp_bridge.masks[0].mask
- | (((addr & ~((1 << intel_i460_pageshift) - 1)) & 0xffffff000) >> 12));
-}
-
-static unsigned long intel_i460_unmask_memory(unsigned long addr)
-{
- /* Turn a GATT entry into a physical address */
- return ((addr & 0xffffff) << 12);
-}
-
-static aper_size_info_8 intel_i460_sizes[3] =
-{
- /*
- * The 32GB aperture is only available with a 4M GART page size.
- * Due to the dynamic GART page size, we can't figure out page_order
- * or num_entries until runtime.
- */
- {32768, 0, 0, 4},
- {1024, 0, 0, 2},
- {256, 0, 0, 1}
-};
-
-static int __init intel_i460_setup (struct pci_dev *pdev __attribute__((unused)))
-{
- agp_bridge.masks = intel_i460_masks;
- agp_bridge.aperture_sizes = (void *) intel_i460_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 3;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_i460_configure;
- agp_bridge.fetch_size = intel_i460_fetch_size;
- agp_bridge.cleanup = intel_i460_cleanup;
- agp_bridge.tlb_flush = intel_i460_tlb_flush;
- agp_bridge.mask_memory = intel_i460_mask_memory;
- agp_bridge.unmask_memory = intel_i460_unmask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = intel_i460_create_gatt_table;
- agp_bridge.free_gatt_table = intel_i460_free_gatt_table;
- agp_bridge.insert_memory = intel_i460_insert_memory;
- agp_bridge.remove_memory = intel_i460_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = intel_i460_alloc_page;
- agp_bridge.agp_destroy_page = intel_i460_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 1;
- return 0;
-}
-
-#endif /* CONFIG_AGP_I460 */
-
-#ifdef CONFIG_AGP_INTEL
-
-static int intel_fetch_size(void)
-{
- int i;
- u16 temp;
- aper_size_info_16 *values;
-
- pci_read_config_word(agp_bridge.dev, INTEL_APSIZE, &temp);
- values = A_SIZE_16(agp_bridge.aperture_sizes);
-
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- if (temp == values[i].size_value) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + i);
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-
-static int intel_8xx_fetch_size(void)
-{
- int i;
- u8 temp;
- aper_size_info_8 *values;
-
- pci_read_config_byte(agp_bridge.dev, INTEL_APSIZE, &temp);
- values = A_SIZE_8(agp_bridge.aperture_sizes);
-
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- if (temp == values[i].size_value) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + i);
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-static void intel_tlbflush(agp_memory * mem)
-{
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200);
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280);
-}
-
-
-static void intel_8xx_tlbflush(agp_memory * mem)
-{
- u32 temp;
- pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & ~(1 << 7));
- pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp | (1 << 7));
-}
-
-
-static void intel_cleanup(void)
-{
- u16 temp;
- aper_size_info_16 *previous_size;
-
- previous_size = A_SIZE_16(agp_bridge.previous_size);
- pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp);
- pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9));
- pci_write_config_word(agp_bridge.dev, INTEL_APSIZE,
- previous_size->size_value);
-}
-
-
-static void intel_8xx_cleanup(void)
-{
- u16 temp;
- aper_size_info_8 *previous_size;
-
- previous_size = A_SIZE_8(agp_bridge.previous_size);
- pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp);
- pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9));
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- previous_size->size_value);
-}
-
-
-static int intel_configure(void)
-{
- u32 temp;
- u16 temp2;
- aper_size_info_16 *current_size;
-
- current_size = A_SIZE_16(agp_bridge.current_size);
-
- /* aperture size */
- pci_write_config_word(agp_bridge.dev, INTEL_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase - aperture base */
- pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280);
-
- /* paccfg/nbxcfg */
- pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2);
- pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG,
- (temp2 & ~(1 << 10)) | (1 << 9));
- /* clear any possible error conditions */
- pci_write_config_byte(agp_bridge.dev, INTEL_ERRSTS + 1, 7);
- return 0;
-}
-
-static void intel_820_tlbflush(agp_memory * mem)
-{
- return;
-}
-
-static void intel_820_cleanup(void)
-{
- u8 temp;
- aper_size_info_8 *previous_size;
-
- previous_size = A_SIZE_8(agp_bridge.previous_size);
- pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp);
- pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR,
- temp & ~(1 << 1));
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- previous_size->size_value);
-}
-
-
-static int intel_820_configure(void)
-{
- u32 temp;
- u8 temp2;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
-
- /* aperture size */
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase - aperture base */
- pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
-
- /* global enable aperture access */
- /* This flag is not accessed through MCHCFG register as in */
- /* i850 chipset. */
- pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2);
- pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR,
- temp2 | (1 << 1));
- /* clear any possible AGP-related error conditions */
- pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c);
- return 0;
-}
-
-static int intel_840_configure(void)
-{
- u32 temp;
- u16 temp2;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
-
- /* aperture size */
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase - aperture base */
- pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
-
- /* mcgcfg */
- pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2);
- pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG,
- temp2 | (1 << 9));
- /* clear any possible error conditions */
- pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000);
- return 0;
-}
-
-static int intel_845_configure(void)
-{
- u32 temp;
- u8 temp2;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
-
- /* aperture size */
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase - aperture base */
- pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
-
- /* agpm */
- pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2);
- pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM,
- temp2 | (1 << 1));
- /* clear any possible error conditions */
- pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c);
- return 0;
-}
-
-static int intel_850_configure(void)
-{
- u32 temp;
- u16 temp2;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
-
- /* aperture size */
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase - aperture base */
- pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
-
- /* mcgcfg */
- pci_read_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, &temp2);
- pci_write_config_word(agp_bridge.dev, INTEL_I850_MCHCFG,
- temp2 | (1 << 9));
- /* clear any possible AGP-related error conditions */
- pci_write_config_word(agp_bridge.dev, INTEL_I850_ERRSTS, 0x001c);
- return 0;
-}
-
-static int intel_860_configure(void)
-{
- u32 temp;
- u16 temp2;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
-
- /* aperture size */
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase - aperture base */
- pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
-
- /* mcgcfg */
- pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2);
- pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG,
- temp2 | (1 << 9));
- /* clear any possible AGP-related error conditions */
- pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700);
- return 0;
-}
-
-static int intel_830mp_configure(void)
-{
- u32 temp;
- u16 temp2;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
-
- /* aperture size */
- pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
- current_size->size_value);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* attbase - aperture base */
- pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* agpctrl */
- pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
-
- /* gmch */
- pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2);
- pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG,
- temp2 | (1 << 9));
- /* clear any possible AGP-related error conditions */
- pci_write_config_word(agp_bridge.dev, INTEL_I830_ERRSTS, 0x1c);
- return 0;
-}
-
-static unsigned long intel_mask_memory(unsigned long addr, int type)
-{
- /* Memory type is ignored */
-
- return addr | agp_bridge.masks[0].mask;
-}
-
-static void intel_resume(void)
-{
- intel_configure();
-}
-
-/* Setup function */
-static gatt_mask intel_generic_masks[] =
-{
- {0x00000017, 0}
-};
-
-static aper_size_info_8 intel_8xx_sizes[7] =
-{
- {256, 65536, 6, 0},
- {128, 32768, 5, 32},
- {64, 16384, 4, 48},
- {32, 8192, 3, 56},
- {16, 4096, 2, 60},
- {8, 2048, 1, 62},
- {4, 1024, 0, 63}
-};
-
-static aper_size_info_16 intel_generic_sizes[7] =
-{
- {256, 65536, 6, 0},
- {128, 32768, 5, 32},
- {64, 16384, 4, 48},
- {32, 8192, 3, 56},
- {16, 4096, 2, 60},
- {8, 2048, 1, 62},
- {4, 1024, 0, 63}
-};
-
-static aper_size_info_8 intel_830mp_sizes[4] =
-{
- {256, 65536, 6, 0},
- {128, 32768, 5, 32},
- {64, 16384, 4, 48},
- {32, 8192, 3, 56}
-};
-
-static int __init intel_generic_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = intel_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
- agp_bridge.size_type = U16_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_configure;
- agp_bridge.fetch_size = intel_fetch_size;
- agp_bridge.cleanup = intel_cleanup;
- agp_bridge.tlb_flush = intel_tlbflush;
- agp_bridge.mask_memory = intel_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = intel_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-
-static int __init intel_820_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = intel_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_820_configure;
- agp_bridge.fetch_size = intel_8xx_fetch_size;
- agp_bridge.cleanup = intel_820_cleanup;
- agp_bridge.tlb_flush = intel_820_tlbflush;
- agp_bridge.mask_memory = intel_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-static int __init intel_830mp_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = intel_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 4;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_830mp_configure;
- agp_bridge.fetch_size = intel_8xx_fetch_size;
- agp_bridge.cleanup = intel_8xx_cleanup;
- agp_bridge.tlb_flush = intel_8xx_tlbflush;
- agp_bridge.mask_memory = intel_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-static int __init intel_840_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = intel_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_840_configure;
- agp_bridge.fetch_size = intel_8xx_fetch_size;
- agp_bridge.cleanup = intel_8xx_cleanup;
- agp_bridge.tlb_flush = intel_8xx_tlbflush;
- agp_bridge.mask_memory = intel_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-static int __init intel_845_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = intel_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_845_configure;
- agp_bridge.fetch_size = intel_8xx_fetch_size;
- agp_bridge.cleanup = intel_8xx_cleanup;
- agp_bridge.tlb_flush = intel_8xx_tlbflush;
- agp_bridge.mask_memory = intel_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-static int __init intel_850_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = intel_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_850_configure;
- agp_bridge.fetch_size = intel_8xx_fetch_size;
- agp_bridge.cleanup = intel_8xx_cleanup;
- agp_bridge.tlb_flush = intel_8xx_tlbflush;
- agp_bridge.mask_memory = intel_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-static int __init intel_860_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = intel_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = intel_860_configure;
- agp_bridge.fetch_size = intel_8xx_fetch_size;
- agp_bridge.cleanup = intel_8xx_cleanup;
- agp_bridge.tlb_flush = intel_8xx_tlbflush;
- agp_bridge.mask_memory = intel_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-#endif /* CONFIG_AGP_INTEL */
-
-#ifdef CONFIG_AGP_VIA
-
-static int via_fetch_size(void)
-{
- int i;
- u8 temp;
- aper_size_info_8 *values;
-
- values = A_SIZE_8(agp_bridge.aperture_sizes);
- pci_read_config_byte(agp_bridge.dev, VIA_APSIZE, &temp);
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- if (temp == values[i].size_value) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + i);
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-static int via_configure(void)
-{
- u32 temp;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
- /* aperture size */
- pci_write_config_byte(agp_bridge.dev, VIA_APSIZE,
- current_size->size_value);
- /* address to map too */
- pci_read_config_dword(agp_bridge.dev, VIA_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* GART control register */
- pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f);
-
- /* attbase - aperture GATT base */
- pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE,
- (agp_bridge.gatt_bus_addr & 0xfffff000) | 3);
- return 0;
-}
-
-static void via_cleanup(void)
-{
- aper_size_info_8 *previous_size;
-
- previous_size = A_SIZE_8(agp_bridge.previous_size);
- pci_write_config_byte(agp_bridge.dev, VIA_APSIZE,
- previous_size->size_value);
- /* Do not disable by writing 0 to VIA_ATTBASE, it screws things up
- * during reinitialization.
- */
-}
-
-static void via_tlbflush(agp_memory * mem)
-{
- pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000008f);
- pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f);
-}
-
-static unsigned long via_mask_memory(unsigned long addr, int type)
-{
- /* Memory type is ignored */
-
- return addr | agp_bridge.masks[0].mask;
-}
-
-static aper_size_info_8 via_generic_sizes[7] =
-{
- {256, 65536, 6, 0},
- {128, 32768, 5, 128},
- {64, 16384, 4, 192},
- {32, 8192, 3, 224},
- {16, 4096, 2, 240},
- {8, 2048, 1, 248},
- {4, 1024, 0, 252}
-};
-
-static gatt_mask via_generic_masks[] =
-{
- {0x00000000, 0}
-};
-
-static int __init via_generic_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = via_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) via_generic_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = via_configure;
- agp_bridge.fetch_size = via_fetch_size;
- agp_bridge.cleanup = via_cleanup;
- agp_bridge.tlb_flush = via_tlbflush;
- agp_bridge.mask_memory = via_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-#endif /* CONFIG_AGP_VIA */
-
-#ifdef CONFIG_AGP_SIS
-
-static int sis_fetch_size(void)
-{
- u8 temp_size;
- int i;
- aper_size_info_8 *values;
-
- pci_read_config_byte(agp_bridge.dev, SIS_APSIZE, &temp_size);
- values = A_SIZE_8(agp_bridge.aperture_sizes);
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- if ((temp_size == values[i].size_value) ||
- ((temp_size & ~(0x03)) ==
- (values[i].size_value & ~(0x03)))) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + i);
-
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-
-static void sis_tlbflush(agp_memory * mem)
-{
- pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02);
-}
-
-static int sis_configure(void)
-{
- u32 temp;
- aper_size_info_8 *current_size;
-
- current_size = A_SIZE_8(agp_bridge.current_size);
- pci_write_config_byte(agp_bridge.dev, SIS_TLBCNTRL, 0x05);
- pci_read_config_dword(agp_bridge.dev, SIS_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- pci_write_config_dword(agp_bridge.dev, SIS_ATTBASE,
- agp_bridge.gatt_bus_addr);
- pci_write_config_byte(agp_bridge.dev, SIS_APSIZE,
- current_size->size_value);
- return 0;
-}
-
-static void sis_cleanup(void)
-{
- aper_size_info_8 *previous_size;
-
- previous_size = A_SIZE_8(agp_bridge.previous_size);
- pci_write_config_byte(agp_bridge.dev, SIS_APSIZE,
- (previous_size->size_value & ~(0x03)));
-}
-
-static unsigned long sis_mask_memory(unsigned long addr, int type)
-{
- /* Memory type is ignored */
-
- return addr | agp_bridge.masks[0].mask;
-}
-
-static aper_size_info_8 sis_generic_sizes[7] =
-{
- {256, 65536, 6, 99},
- {128, 32768, 5, 83},
- {64, 16384, 4, 67},
- {32, 8192, 3, 51},
- {16, 4096, 2, 35},
- {8, 2048, 1, 19},
- {4, 1024, 0, 3}
-};
-
-static gatt_mask sis_generic_masks[] =
-{
- {0x00000000, 0}
-};
-
-static int __init sis_generic_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = sis_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) sis_generic_sizes;
- agp_bridge.size_type = U8_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = sis_configure;
- agp_bridge.fetch_size = sis_fetch_size;
- agp_bridge.cleanup = sis_cleanup;
- agp_bridge.tlb_flush = sis_tlbflush;
- agp_bridge.mask_memory = sis_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-}
-
-#endif /* CONFIG_AGP_SIS */
-
-#ifdef CONFIG_AGP_AMD
-
-typedef struct _amd_page_map {
- unsigned long *real;
- unsigned long *remapped;
-} amd_page_map;
-
-static struct _amd_irongate_private {
- volatile u8 *registers;
- amd_page_map **gatt_pages;
- int num_tables;
-} amd_irongate_private;
-
-static int amd_create_page_map(amd_page_map *page_map)
-{
- int i;
-
- page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
- if (page_map->real == NULL) {
- return -ENOMEM;
- }
- SetPageReserved(virt_to_page(page_map->real));
- CACHE_FLUSH();
- page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
- PAGE_SIZE);
- if (page_map->remapped == NULL) {
- ClearPageReserved(virt_to_page(page_map->real));
- free_page((unsigned long) page_map->real);
- page_map->real = NULL;
- return -ENOMEM;
- }
- CACHE_FLUSH();
-
- for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
- page_map->remapped[i] = agp_bridge.scratch_page;
- }
-
- return 0;
-}
-
-static void amd_free_page_map(amd_page_map *page_map)
-{
- iounmap(page_map->remapped);
- ClearPageReserved(virt_to_page(page_map->real));
- free_page((unsigned long) page_map->real);
-}
-
-static void amd_free_gatt_pages(void)
-{
- int i;
- amd_page_map **tables;
- amd_page_map *entry;
-
- tables = amd_irongate_private.gatt_pages;
- for(i = 0; i < amd_irongate_private.num_tables; i++) {
- entry = tables[i];
- if (entry != NULL) {
- if (entry->real != NULL) {
- amd_free_page_map(entry);
- }
- kfree(entry);
- }
- }
- kfree(tables);
-}
-
-static int amd_create_gatt_pages(int nr_tables)
-{
- amd_page_map **tables;
- amd_page_map *entry;
- int retval = 0;
- int i;
-
- tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *),
- GFP_KERNEL);
- if (tables == NULL) {
- return -ENOMEM;
- }
- memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1));
- for (i = 0; i < nr_tables; i++) {
- entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL);
- if (entry == NULL) {
- retval = -ENOMEM;
- break;
- }
- memset(entry, 0, sizeof(amd_page_map));
- tables[i] = entry;
- retval = amd_create_page_map(entry);
- if (retval != 0) break;
- }
- amd_irongate_private.num_tables = nr_tables;
- amd_irongate_private.gatt_pages = tables;
-
- if (retval != 0) amd_free_gatt_pages();
-
- return retval;
-}
-
-/* Since we don't need contigious memory we just try
- * to get the gatt table once
- */
-
-#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
-#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
- GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr))
-#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
-#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\
- GET_PAGE_DIR_IDX(addr)]->remapped)
-
-static int amd_create_gatt_table(void)
-{
- aper_size_info_lvl2 *value;
- amd_page_map page_dir;
- unsigned long addr;
- int retval;
- u32 temp;
- int i;
-
- value = A_SIZE_LVL2(agp_bridge.current_size);
- retval = amd_create_page_map(&page_dir);
- if (retval != 0) {
- return retval;
- }
-
- retval = amd_create_gatt_pages(value->num_entries / 1024);
- if (retval != 0) {
- amd_free_page_map(&page_dir);
- return retval;
- }
-
- agp_bridge.gatt_table_real = page_dir.real;
- agp_bridge.gatt_table = page_dir.remapped;
- agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real);
-
- /* Get the address for the gart region.
- * This is a bus address even on the alpha, b/c its
- * used to program the agp master not the cpu
- */
-
- pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp);
- addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- agp_bridge.gart_bus_addr = addr;
-
- /* Calculate the agp offset */
- for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
- page_dir.remapped[GET_PAGE_DIR_OFF(addr)] =
- virt_to_phys(amd_irongate_private.gatt_pages[i]->real);
- page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001;
- }
-
- return 0;
-}
-
-static int amd_free_gatt_table(void)
-{
- amd_page_map page_dir;
-
- page_dir.real = agp_bridge.gatt_table_real;
- page_dir.remapped = agp_bridge.gatt_table;
-
- amd_free_gatt_pages();
- amd_free_page_map(&page_dir);
- return 0;
-}
-
-static int amd_irongate_fetch_size(void)
-{
- int i;
- u32 temp;
- aper_size_info_lvl2 *values;
-
- pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
- temp = (temp & 0x0000000e);
- values = A_SIZE_LVL2(agp_bridge.aperture_sizes);
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- if (temp == values[i].size_value) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + i);
-
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-static int amd_irongate_configure(void)
-{
- aper_size_info_lvl2 *current_size;
- u32 temp;
- u16 enable_reg;
-
- current_size = A_SIZE_LVL2(agp_bridge.current_size);
-
- /* Get the memory mapped registers */
- pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp);
- temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096);
-
- /* Write out the address of the gatt table */
- OUTREG32(amd_irongate_private.registers, AMD_ATTBASE,
- agp_bridge.gatt_bus_addr);
-
- /* Write the Sync register */
- pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80);
-
- /* Set indexing mode */
- pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00);
-
- /* Write the enable register */
- enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
- enable_reg = (enable_reg | 0x0004);
- OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg);
-
- /* Write out the size register */
- pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
- temp = (((temp & ~(0x0000000e)) | current_size->size_value)
- | 0x00000001);
- pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp);
-
- /* Flush the tlb */
- OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
-
- return 0;
-}
-
-static void amd_irongate_cleanup(void)
-{
- aper_size_info_lvl2 *previous_size;
- u32 temp;
- u16 enable_reg;
-
- previous_size = A_SIZE_LVL2(agp_bridge.previous_size);
-
- enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
- enable_reg = (enable_reg & ~(0x0004));
- OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg);
-
- /* Write back the previous size and disable gart translation */
- pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
- temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
- pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp);
- iounmap((void *) amd_irongate_private.registers);
-}
-
-/*
- * This routine could be implemented by taking the addresses
- * written to the GATT, and flushing them individually. However
- * currently it just flushes the whole table. Which is probably
- * more efficent, since agp_memory blocks can be a large number of
- * entries.
- */
-
-static void amd_irongate_tlbflush(agp_memory * temp)
-{
- OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
-}
-
-static unsigned long amd_irongate_mask_memory(unsigned long addr, int type)
-{
- /* Only type 0 is supported by the irongate */
-
- return addr | agp_bridge.masks[0].mask;
-}
-
-static int amd_insert_memory(agp_memory * mem,
- off_t pg_start, int type)
-{
- int i, j, num_entries;
- unsigned long *cur_gatt;
- unsigned long addr;
-
- num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
- if ((pg_start + mem->page_count) > num_entries) {
- return -EINVAL;
- }
-
- j = pg_start;
- while (j < (pg_start + mem->page_count)) {
- addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
- cur_gatt = GET_GATT(addr);
- if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
- return -EBUSY;
- }
- j++;
- }
-
- if (mem->is_flushed == FALSE) {
- CACHE_FLUSH();
- mem->is_flushed = TRUE;
- }
-
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
- cur_gatt = GET_GATT(addr);
- cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
- }
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static int amd_remove_memory(agp_memory * mem, off_t pg_start,
- int type)
-{
- int i;
- unsigned long *cur_gatt;
- unsigned long addr;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr;
- cur_gatt = GET_GATT(addr);
- cur_gatt[GET_GATT_OFF(addr)] =
- (unsigned long) agp_bridge.scratch_page;
- }
-
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static aper_size_info_lvl2 amd_irongate_sizes[7] =
-{
- {2048, 524288, 0x0000000c},
- {1024, 262144, 0x0000000a},
- {512, 131072, 0x00000008},
- {256, 65536, 0x00000006},
- {128, 32768, 0x00000004},
- {64, 16384, 0x00000002},
- {32, 8192, 0x00000000}
-};
-
-static gatt_mask amd_irongate_masks[] =
-{
- {0x00000001, 0}
-};
-
-static int __init amd_irongate_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = amd_irongate_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
- agp_bridge.size_type = LVL2_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = (void *) &amd_irongate_private;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = amd_irongate_configure;
- agp_bridge.fetch_size = amd_irongate_fetch_size;
- agp_bridge.cleanup = amd_irongate_cleanup;
- agp_bridge.tlb_flush = amd_irongate_tlbflush;
- agp_bridge.mask_memory = amd_irongate_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = amd_create_gatt_table;
- agp_bridge.free_gatt_table = amd_free_gatt_table;
- agp_bridge.insert_memory = amd_insert_memory;
- agp_bridge.remove_memory = amd_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-#endif /* CONFIG_AGP_AMD */
-
-#ifdef CONFIG_AGP_ALI
-
-static int ali_fetch_size(void)
-{
- int i;
- u32 temp;
- aper_size_info_32 *values;
-
- pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
- temp &= ~(0xfffffff0);
- values = A_SIZE_32(agp_bridge.aperture_sizes);
-
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- if (temp == values[i].size_value) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + i);
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-static void ali_tlbflush(agp_memory * mem)
-{
- u32 temp;
-
- pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
-// clear tag
- pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL,
- ((temp & 0xfffffff0) | 0x00000001|0x00000002));
-}
-
-static void ali_cleanup(void)
-{
- aper_size_info_32 *previous_size;
- u32 temp;
-
- previous_size = A_SIZE_32(agp_bridge.previous_size);
-
- pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
-// clear tag
- pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL,
- ((temp & 0xffffff00) | 0x00000001|0x00000002));
-
- pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
- pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE,
- ((temp & 0x00000ff0) | previous_size->size_value));
-}
-
-static int ali_configure(void)
-{
- u32 temp;
- aper_size_info_32 *current_size;
-
- current_size = A_SIZE_32(agp_bridge.current_size);
-
- /* aperture size and gatt addr */
- pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
- temp = (((temp & 0x00000ff0) | (agp_bridge.gatt_bus_addr & 0xfffff000))
- | (current_size->size_value & 0xf));
- pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, temp);
-
- /* tlb control */
-
- /*
- * Question: Jeff, ALi's patch deletes this:
- *
- * pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
- * pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
- * ((temp & 0xffffff00) | 0x00000010));
- *
- * and replaces it with the following, which seems to duplicate the
- * next couple of lines below it. I suspect this was an oversight,
- * but you might want to check up on this?
- */
-
- pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* address to map to */
- pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-#if 0
- if (agp_bridge.type == ALI_M1541) {
- u32 nlvm_addr = 0;
-
- switch (current_size->size_value) {
- case 0: break;
- case 1: nlvm_addr = 0x100000;break;
- case 2: nlvm_addr = 0x200000;break;
- case 3: nlvm_addr = 0x400000;break;
- case 4: nlvm_addr = 0x800000;break;
- case 6: nlvm_addr = 0x1000000;break;
- case 7: nlvm_addr = 0x2000000;break;
- case 8: nlvm_addr = 0x4000000;break;
- case 9: nlvm_addr = 0x8000000;break;
- case 10: nlvm_addr = 0x10000000;break;
- default: break;
- }
- nlvm_addr--;
- nlvm_addr&=0xfff00000;
-
- nlvm_addr+= agp_bridge.gart_bus_addr;
- nlvm_addr|=(agp_bridge.gart_bus_addr>>12);
- printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr);
- }
-#endif
-
- pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
- temp &= 0xffffff7f; //enable TLB
- pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, temp);
-
- return 0;
-}
-
-static unsigned long ali_mask_memory(unsigned long addr, int type)
-{
- /* Memory type is ignored */
-
- return addr | agp_bridge.masks[0].mask;
-}
-
-static void ali_cache_flush(void)
-{
- global_cache_flush();
-
- if (agp_bridge.type == ALI_M1541) {
- int i, page_count;
- u32 temp;
-
- page_count = 1 << A_SIZE_32(agp_bridge.current_size)->page_order;
- for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) {
- pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
- (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- (agp_bridge.gatt_bus_addr + i)) |
- ALI_CACHE_FLUSH_EN));
- }
- }
-}
-
-static void *ali_alloc_page(void)
-{
- void *adr = agp_generic_alloc_page();
- unsigned temp;
-
- if (adr == 0)
- return 0;
-
- if (agp_bridge.type == ALI_M1541) {
- pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
- (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_phys(adr)) |
- ALI_CACHE_FLUSH_EN ));
- }
- return adr;
-}
-
-static void ali_destroy_page(void * addr)
-{
- u32 temp;
-
- if (addr == NULL)
- return;
-
- global_cache_flush();
-
- if (agp_bridge.type == ALI_M1541) {
- pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
- pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
- (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_phys(addr)) |
- ALI_CACHE_FLUSH_EN));
- }
-
- agp_generic_destroy_page(addr);
-}
-
-/* Setup function */
-static gatt_mask ali_generic_masks[] =
-{
- {0x00000000, 0}
-};
-
-static aper_size_info_32 ali_generic_sizes[7] =
-{
- {256, 65536, 6, 10},
- {128, 32768, 5, 9},
- {64, 16384, 4, 8},
- {32, 8192, 3, 7},
- {16, 4096, 2, 6},
- {8, 2048, 1, 4},
- {4, 1024, 0, 3}
-};
-
-static int __init ali_generic_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = ali_generic_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) ali_generic_sizes;
- agp_bridge.size_type = U32_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = ali_configure;
- agp_bridge.fetch_size = ali_fetch_size;
- agp_bridge.cleanup = ali_cleanup;
- agp_bridge.tlb_flush = ali_tlbflush;
- agp_bridge.mask_memory = ali_mask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = ali_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = ali_alloc_page;
- agp_bridge.agp_destroy_page = ali_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- return 0;
-
- (void) pdev; /* unused */
-}
-
-#endif /* CONFIG_AGP_ALI */
-
-#ifdef CONFIG_AGP_SWORKS
-typedef struct _serverworks_page_map {
- unsigned long *real;
- unsigned long *remapped;
-} serverworks_page_map;
-
-static struct _serverworks_private {
- struct pci_dev *svrwrks_dev; /* device one */
- volatile u8 *registers;
- serverworks_page_map **gatt_pages;
- int num_tables;
- serverworks_page_map scratch_dir;
-
- int gart_addr_ofs;
- int mm_addr_ofs;
-} serverworks_private;
-
-static int serverworks_create_page_map(serverworks_page_map *page_map)
-{
- int i;
-
- page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
- if (page_map->real == NULL) {
- return -ENOMEM;
- }
- SetPageReserved(virt_to_page(page_map->real));
- CACHE_FLUSH();
- page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
- PAGE_SIZE);
- if (page_map->remapped == NULL) {
- ClearPageReserved(virt_to_page(page_map->real));
- free_page((unsigned long) page_map->real);
- page_map->real = NULL;
- return -ENOMEM;
- }
- CACHE_FLUSH();
-
- for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
- page_map->remapped[i] = agp_bridge.scratch_page;
- }
-
- return 0;
-}
-
-static void serverworks_free_page_map(serverworks_page_map *page_map)
-{
- iounmap(page_map->remapped);
- ClearPageReserved(virt_to_page(page_map->real));
- free_page((unsigned long) page_map->real);
-}
-
-static void serverworks_free_gatt_pages(void)
-{
- int i;
- serverworks_page_map **tables;
- serverworks_page_map *entry;
-
- tables = serverworks_private.gatt_pages;
- for(i = 0; i < serverworks_private.num_tables; i++) {
- entry = tables[i];
- if (entry != NULL) {
- if (entry->real != NULL) {
- serverworks_free_page_map(entry);
- }
- kfree(entry);
- }
- }
- kfree(tables);
-}
-
-static int serverworks_create_gatt_pages(int nr_tables)
-{
- serverworks_page_map **tables;
- serverworks_page_map *entry;
- int retval = 0;
- int i;
-
- tables = kmalloc((nr_tables + 1) * sizeof(serverworks_page_map *),
- GFP_KERNEL);
- if (tables == NULL) {
- return -ENOMEM;
- }
- memset(tables, 0, sizeof(serverworks_page_map *) * (nr_tables + 1));
- for (i = 0; i < nr_tables; i++) {
- entry = kmalloc(sizeof(serverworks_page_map), GFP_KERNEL);
- if (entry == NULL) {
- retval = -ENOMEM;
- break;
- }
- memset(entry, 0, sizeof(serverworks_page_map));
- tables[i] = entry;
- retval = serverworks_create_page_map(entry);
- if (retval != 0) break;
- }
- serverworks_private.num_tables = nr_tables;
- serverworks_private.gatt_pages = tables;
-
- if (retval != 0) serverworks_free_gatt_pages();
-
- return retval;
-}
-
-#define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\
- GET_PAGE_DIR_IDX(addr)]->remapped)
-
-#ifndef GET_PAGE_DIR_OFF
-#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
-#endif
-
-#ifndef GET_PAGE_DIR_IDX
-#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
- GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr))
-#endif
-
-#ifndef GET_GATT_OFF
-#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
-#endif
-
-static int serverworks_create_gatt_table(void)
-{
- aper_size_info_lvl2 *value;
- serverworks_page_map page_dir;
- int retval;
- u32 temp;
- int i;
-
- value = A_SIZE_LVL2(agp_bridge.current_size);
- retval = serverworks_create_page_map(&page_dir);
- if (retval != 0) {
- return retval;
- }
- retval = serverworks_create_page_map(&serverworks_private.scratch_dir);
- if (retval != 0) {
- serverworks_free_page_map(&page_dir);
- return retval;
- }
- /* Create a fake scratch directory */
- for(i = 0; i < 1024; i++) {
- serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge.scratch_page;
- page_dir.remapped[i] =
- virt_to_phys(serverworks_private.scratch_dir.real);
- page_dir.remapped[i] |= 0x00000001;
- }
-
- retval = serverworks_create_gatt_pages(value->num_entries / 1024);
- if (retval != 0) {
- serverworks_free_page_map(&page_dir);
- serverworks_free_page_map(&serverworks_private.scratch_dir);
- return retval;
- }
-
- agp_bridge.gatt_table_real = page_dir.real;
- agp_bridge.gatt_table = page_dir.remapped;
- agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real);
-
- /* Get the address for the gart region.
- * This is a bus address even on the alpha, b/c its
- * used to program the agp master not the cpu
- */
-
- pci_read_config_dword(agp_bridge.dev,
- serverworks_private.gart_addr_ofs,
- &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
- /* Calculate the agp offset */
-
- for(i = 0; i < value->num_entries / 1024; i++) {
- page_dir.remapped[i] =
- virt_to_phys(serverworks_private.gatt_pages[i]->real);
- page_dir.remapped[i] |= 0x00000001;
- }
-
- return 0;
-}
-
-static int serverworks_free_gatt_table(void)
-{
- serverworks_page_map page_dir;
-
- page_dir.real = agp_bridge.gatt_table_real;
- page_dir.remapped = agp_bridge.gatt_table;
-
- serverworks_free_gatt_pages();
- serverworks_free_page_map(&page_dir);
- serverworks_free_page_map(&serverworks_private.scratch_dir);
- return 0;
-}
-
-static int serverworks_fetch_size(void)
-{
- int i;
- u32 temp;
- u32 temp2;
- aper_size_info_lvl2 *values;
-
- values = A_SIZE_LVL2(agp_bridge.aperture_sizes);
- pci_read_config_dword(agp_bridge.dev,
- serverworks_private.gart_addr_ofs,
- &temp);
- pci_write_config_dword(agp_bridge.dev,
- serverworks_private.gart_addr_ofs,
- SVWRKS_SIZE_MASK);
- pci_read_config_dword(agp_bridge.dev,
- serverworks_private.gart_addr_ofs,
- &temp2);
- pci_write_config_dword(agp_bridge.dev,
- serverworks_private.gart_addr_ofs,
- temp);
- temp2 &= SVWRKS_SIZE_MASK;
-
- for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
- if (temp2 == values[i].size_value) {
- agp_bridge.previous_size =
- agp_bridge.current_size = (void *) (values + i);
-
- agp_bridge.aperture_size_idx = i;
- return values[i].size;
- }
- }
-
- return 0;
-}
-
-static int serverworks_configure(void)
-{
- aper_size_info_lvl2 *current_size;
- u32 temp;
- u8 enable_reg;
- u8 cap_ptr;
- u32 cap_id;
- u16 cap_reg;
-
- current_size = A_SIZE_LVL2(agp_bridge.current_size);
-
- /* Get the memory mapped registers */
- pci_read_config_dword(agp_bridge.dev,
- serverworks_private.mm_addr_ofs,
- &temp);
- temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096);
-
- OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a);
-
- OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE,
- agp_bridge.gatt_bus_addr);
-
- cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND);
- cap_reg &= ~0x0007;
- cap_reg |= 0x4;
- OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg);
-
- pci_read_config_byte(serverworks_private.svrwrks_dev,
- SVWRKS_AGP_ENABLE, &enable_reg);
- enable_reg |= 0x1; /* Agp Enable bit */
- pci_write_config_byte(serverworks_private.svrwrks_dev,
- SVWRKS_AGP_ENABLE, enable_reg);
- agp_bridge.tlb_flush(NULL);
-
- pci_read_config_byte(serverworks_private.svrwrks_dev, 0x34, &cap_ptr);
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(serverworks_private.svrwrks_dev,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
- agp_bridge.capndx = cap_ptr;
-
- /* Fill in the mode register */
- pci_read_config_dword(serverworks_private.svrwrks_dev,
- agp_bridge.capndx + 4,
- &agp_bridge.mode);
-
- pci_read_config_byte(agp_bridge.dev,
- SVWRKS_CACHING,
- &enable_reg);
- enable_reg &= ~0x3;
- pci_write_config_byte(agp_bridge.dev,
- SVWRKS_CACHING,
- enable_reg);
-
- pci_read_config_byte(agp_bridge.dev,
- SVWRKS_FEATURE,
- &enable_reg);
- enable_reg |= (1<<6);
- pci_write_config_byte(agp_bridge.dev,
- SVWRKS_FEATURE,
- enable_reg);
-
- return 0;
-}
-
-static void serverworks_cleanup(void)
-{
- iounmap((void *) serverworks_private.registers);
-}
-
-/*
- * This routine could be implemented by taking the addresses
- * written to the GATT, and flushing them individually. However
- * currently it just flushes the whole table. Which is probably
- * more efficent, since agp_memory blocks can be a large number of
- * entries.
- */
-
-static void serverworks_tlbflush(agp_memory * temp)
-{
- unsigned long end;
-
- OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01);
- end = jiffies + 3*HZ;
- while(INREG8(serverworks_private.registers,
- SVWRKS_POSTFLUSH) == 0x01) {
- if((signed)(end - jiffies) <= 0) {
- printk(KERN_ERR "Posted write buffer flush took more"
- "then 3 seconds\n");
- }
- }
- OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001);
- end = jiffies + 3*HZ;
- while(INREG32(serverworks_private.registers,
- SVWRKS_DIRFLUSH) == 0x00000001) {
- if((signed)(end - jiffies) <= 0) {
- printk(KERN_ERR "TLB flush took more"
- "then 3 seconds\n");
- }
- }
-}
-
-static unsigned long serverworks_mask_memory(unsigned long addr, int type)
-{
- /* Only type 0 is supported by the serverworks chipsets */
-
- return addr | agp_bridge.masks[0].mask;
-}
-
-static int serverworks_insert_memory(agp_memory * mem,
- off_t pg_start, int type)
-{
- int i, j, num_entries;
- unsigned long *cur_gatt;
- unsigned long addr;
-
- num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
- if ((pg_start + mem->page_count) > num_entries) {
- return -EINVAL;
- }
-
- j = pg_start;
- while (j < (pg_start + mem->page_count)) {
- addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
- cur_gatt = SVRWRKS_GET_GATT(addr);
- if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
- return -EBUSY;
- }
- j++;
- }
-
- if (mem->is_flushed == FALSE) {
- CACHE_FLUSH();
- mem->is_flushed = TRUE;
- }
-
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
- cur_gatt = SVRWRKS_GET_GATT(addr);
- cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
- }
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static int serverworks_remove_memory(agp_memory * mem, off_t pg_start,
- int type)
-{
- int i;
- unsigned long *cur_gatt;
- unsigned long addr;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
-
- CACHE_FLUSH();
- agp_bridge.tlb_flush(mem);
-
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr;
- cur_gatt = SVRWRKS_GET_GATT(addr);
- cur_gatt[GET_GATT_OFF(addr)] =
- (unsigned long) agp_bridge.scratch_page;
- }
-
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static gatt_mask serverworks_masks[] =
-{
- {0x00000001, 0}
-};
-
-static aper_size_info_lvl2 serverworks_sizes[7] =
-{
- {2048, 524288, 0x80000000},
- {1024, 262144, 0xc0000000},
- {512, 131072, 0xe0000000},
- {256, 65536, 0xf0000000},
- {128, 32768, 0xf8000000},
- {64, 16384, 0xfc000000},
- {32, 8192, 0xfe000000}
-};
-
-static void serverworks_agp_enable(u32 mode)
-{
- struct pci_dev *device = NULL;
- u32 command, scratch, cap_id;
- u8 cap_ptr;
-
- pci_read_config_dword(serverworks_private.svrwrks_dev,
- agp_bridge.capndx + 4,
- &command);
-
- /*
- * PASS1: go throu all devices that claim to be
- * AGP devices and collect their data.
- */
-
-
- pci_for_each_dev(device) {
- cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(device,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
- if (cap_ptr != 0x00) {
- /*
- * Ok, here we have a AGP device. Disable impossible
- * settings, and adjust the readqueue to the minimum.
- */
-
- pci_read_config_dword(device, cap_ptr + 4, &scratch);
-
- /* adjust RQ depth */
- command =
- ((command & ~0xff000000) |
- min_t(u32, (mode & 0xff000000),
- min_t(u32, (command & 0xff000000),
- (scratch & 0xff000000))));
-
- /* disable SBA if it's not supported */
- if (!((command & 0x00000200) &&
- (scratch & 0x00000200) &&
- (mode & 0x00000200)))
- command &= ~0x00000200;
-
- /* disable FW */
- command &= ~0x00000010;
-
- command &= ~0x00000008;
-
- if (!((command & 4) &&
- (scratch & 4) &&
- (mode & 4)))
- command &= ~0x00000004;
-
- if (!((command & 2) &&
- (scratch & 2) &&
- (mode & 2)))
- command &= ~0x00000002;
-
- if (!((command & 1) &&
- (scratch & 1) &&
- (mode & 1)))
- command &= ~0x00000001;
- }
- }
- /*
- * PASS2: Figure out the 4X/2X/1X setting and enable the
- * target (our motherboard chipset).
- */
-
- if (command & 4) {
- command &= ~3; /* 4X */
- }
- if (command & 2) {
- command &= ~5; /* 2X */
- }
- if (command & 1) {
- command &= ~6; /* 1X */
- }
- command |= 0x00000100;
-
- pci_write_config_dword(serverworks_private.svrwrks_dev,
- agp_bridge.capndx + 8,
- command);
-
- /*
- * PASS3: Go throu all AGP devices and update the
- * command registers.
- */
-
- pci_for_each_dev(device) {
- cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
- if (cap_ptr != 0x00)
- pci_write_config_dword(device, cap_ptr + 8, command);
- }
-}
-
-static int __init serverworks_setup (struct pci_dev *pdev)
-{
- u32 temp;
- u32 temp2;
-
- serverworks_private.svrwrks_dev = pdev;
-
- agp_bridge.masks = serverworks_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.aperture_sizes = (void *) serverworks_sizes;
- agp_bridge.size_type = LVL2_APER_SIZE;
- agp_bridge.num_aperture_sizes = 7;
- agp_bridge.dev_private_data = (void *) &serverworks_private;
- agp_bridge.needs_scratch_page = TRUE;
- agp_bridge.configure = serverworks_configure;
- agp_bridge.fetch_size = serverworks_fetch_size;
- agp_bridge.cleanup = serverworks_cleanup;
- agp_bridge.tlb_flush = serverworks_tlbflush;
- agp_bridge.mask_memory = serverworks_mask_memory;
- agp_bridge.agp_enable = serverworks_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = serverworks_create_gatt_table;
- agp_bridge.free_gatt_table = serverworks_free_gatt_table;
- agp_bridge.insert_memory = serverworks_insert_memory;
- agp_bridge.remove_memory = serverworks_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.suspend = agp_generic_suspend;
- agp_bridge.resume = agp_generic_resume;
- agp_bridge.cant_use_aperture = 0;
-
- pci_read_config_dword(agp_bridge.dev,
- SVWRKS_APSIZE,
- &temp);
-
- serverworks_private.gart_addr_ofs = 0x10;
-
- if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- pci_read_config_dword(agp_bridge.dev,
- SVWRKS_APSIZE + 4,
- &temp2);
- if(temp2 != 0) {
- printk("Detected 64 bit aperture address, but top "
- "bits are not zero. Disabling agp\n");
- return -ENODEV;
- }
- serverworks_private.mm_addr_ofs = 0x18;
- } else {
- serverworks_private.mm_addr_ofs = 0x14;
- }
-
- pci_read_config_dword(agp_bridge.dev,
- serverworks_private.mm_addr_ofs,
- &temp);
- if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- pci_read_config_dword(agp_bridge.dev,
- serverworks_private.mm_addr_ofs + 4,
- &temp2);
- if(temp2 != 0) {
- printk("Detected 64 bit MMIO address, but top "
- "bits are not zero. Disabling agp\n");
- return -ENODEV;
- }
- }
-
- return 0;
-}
-
-#endif /* CONFIG_AGP_SWORKS */
-
-#ifdef CONFIG_AGP_HP_ZX1
-
-#ifndef log2
-#define log2(x) ffz(~(x))
-#endif
-
-#define HP_ZX1_IOVA_BASE GB(1UL)
-#define HP_ZX1_IOVA_SIZE GB(1UL)
-#define HP_ZX1_GART_SIZE (HP_ZX1_IOVA_SIZE / 2)
-#define HP_ZX1_SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL
-
-#define HP_ZX1_PDIR_VALID_BIT 0x8000000000000000UL
-#define HP_ZX1_IOVA_TO_PDIR(va) ((va - hp_private.iova_base) >> \
- hp_private.io_tlb_shift)
-
-static aper_size_info_fixed hp_zx1_sizes[] =
-{
- {0, 0, 0}, /* filled in by hp_zx1_fetch_size() */
-};
-
-static gatt_mask hp_zx1_masks[] =
-{
- {HP_ZX1_PDIR_VALID_BIT, 0}
-};
-
-static struct _hp_private {
- struct pci_dev *ioc;
- volatile u8 *registers;
- u64 *io_pdir; // PDIR for entire IOVA
- u64 *gatt; // PDIR just for GART (subset of above)
- u64 gatt_entries;
- u64 iova_base;
- u64 gart_base;
- u64 gart_size;
- u64 io_pdir_size;
- int io_pdir_owner; // do we own it, or share it with sba_iommu?
- int io_page_size;
- int io_tlb_shift;
- int io_tlb_ps; // IOC ps config
- int io_pages_per_kpage;
-} hp_private;
-
-static int __init hp_zx1_ioc_shared(void)
-{
- struct _hp_private *hp = &hp_private;
-
- printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n");
-
- /*
- * IOC already configured by sba_iommu module; just use
- * its setup. We assume:
- * - IOVA space is 1Gb in size
- * - first 512Mb is IOMMU, second 512Mb is GART
- */
- hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG);
- switch (hp->io_tlb_ps) {
- case 0: hp->io_tlb_shift = 12; break;
- case 1: hp->io_tlb_shift = 13; break;
- case 2: hp->io_tlb_shift = 14; break;
- case 3: hp->io_tlb_shift = 16; break;
- default:
- printk(KERN_ERR PFX "Invalid IOTLB page size "
- "configuration 0x%x\n", hp->io_tlb_ps);
- hp->gatt = 0;
- hp->gatt_entries = 0;
- return -ENODEV;
- }
- hp->io_page_size = 1 << hp->io_tlb_shift;
- hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
-
- hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1;
- hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE;
-
- hp->gart_size = HP_ZX1_GART_SIZE;
- hp->gatt_entries = hp->gart_size / hp->io_page_size;
-
- hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE));
- hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
-
- if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
- hp->gatt = 0;
- hp->gatt_entries = 0;
- printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
- "GART disabled\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int __init hp_zx1_ioc_owner(u8 ioc_rev)
-{
- struct _hp_private *hp = &hp_private;
-
- printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n");
-
- /*
- * Select an IOV page size no larger than system page size.
- */
- if (PAGE_SIZE >= KB(64)) {
- hp->io_tlb_shift = 16;
- hp->io_tlb_ps = 3;
- } else if (PAGE_SIZE >= KB(16)) {
- hp->io_tlb_shift = 14;
- hp->io_tlb_ps = 2;
- } else if (PAGE_SIZE >= KB(8)) {
- hp->io_tlb_shift = 13;
- hp->io_tlb_ps = 1;
- } else {
- hp->io_tlb_shift = 12;
- hp->io_tlb_ps = 0;
- }
- hp->io_page_size = 1 << hp->io_tlb_shift;
- hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
-
- hp->iova_base = HP_ZX1_IOVA_BASE;
- hp->gart_size = HP_ZX1_GART_SIZE;
- hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size;
-
- hp->gatt_entries = hp->gart_size / hp->io_page_size;
- hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64);
-
- return 0;
-}
-
-static int __init hp_zx1_ioc_init(void)
-{
- struct _hp_private *hp = &hp_private;
- struct pci_dev *ioc;
- int i;
- u8 ioc_rev;
-
- ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL);
- if (!ioc) {
- printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n");
- return -ENODEV;
- }
- hp->ioc = ioc;
-
- pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev);
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
- hp->registers = (u8 *) ioremap(pci_resource_start(ioc,
- i),
- pci_resource_len(ioc, i));
- break;
- }
- }
- if (!hp->registers) {
- printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
-
- return -ENODEV;
- }
-
- /*
- * If the IOTLB is currently disabled, we can take it over.
- * Otherwise, we have to share with sba_iommu.
- */
- hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0;
-
- if (hp->io_pdir_owner)
- return hp_zx1_ioc_owner(ioc_rev);
-
- return hp_zx1_ioc_shared();
-}
-
-static int hp_zx1_fetch_size(void)
-{
- int size;
-
- size = hp_private.gart_size / MB(1);
- hp_zx1_sizes[0].size = size;
- agp_bridge.current_size = (void *) &hp_zx1_sizes[0];
- return size;
-}
-
-static int hp_zx1_configure(void)
-{
- struct _hp_private *hp = &hp_private;
-
- agp_bridge.gart_bus_addr = hp->gart_base;
- agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP);
- pci_read_config_dword(agp_bridge.dev,
- agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode);
-
- if (hp->io_pdir_owner) {
- OUTREG64(hp->registers, HP_ZX1_PDIR_BASE,
- virt_to_phys(hp->io_pdir));
- OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps);
- OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1));
- OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1);
- OUTREG64(hp->registers, HP_ZX1_PCOM,
- hp->iova_base | log2(HP_ZX1_IOVA_SIZE));
- INREG64(hp->registers, HP_ZX1_PCOM);
- }
-
- return 0;
-}
-
-static void hp_zx1_cleanup(void)
-{
- struct _hp_private *hp = &hp_private;
-
- if (hp->io_pdir_owner)
- OUTREG64(hp->registers, HP_ZX1_IBASE, 0);
- iounmap((void *) hp->registers);
-}
-
-static void hp_zx1_tlbflush(agp_memory * mem)
-{
- struct _hp_private *hp = &hp_private;
-
- OUTREG64(hp->registers, HP_ZX1_PCOM,
- hp->gart_base | log2(hp->gart_size));
- INREG64(hp->registers, HP_ZX1_PCOM);
-}
-
-static int hp_zx1_create_gatt_table(void)
-{
- struct _hp_private *hp = &hp_private;
- int i;
-
- if (hp->io_pdir_owner) {
- hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL,
- get_order(hp->io_pdir_size));
- if (!hp->io_pdir) {
- printk(KERN_ERR PFX "Couldn't allocate contiguous "
- "memory for I/O PDIR\n");
- hp->gatt = 0;
- hp->gatt_entries = 0;
- return -ENOMEM;
- }
- memset(hp->io_pdir, 0, hp->io_pdir_size);
-
- hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
- }
-
- for (i = 0; i < hp->gatt_entries; i++) {
- hp->gatt[i] = (unsigned long) agp_bridge.scratch_page;
- }
-
- return 0;
-}
-
-static int hp_zx1_free_gatt_table(void)
-{
- struct _hp_private *hp = &hp_private;
-
- if (hp->io_pdir_owner)
- free_pages((unsigned long) hp->io_pdir,
- get_order(hp->io_pdir_size));
- else
- hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE;
- return 0;
-}
-
-static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type)
-{
- struct _hp_private *hp = &hp_private;
- int i, k;
- off_t j, io_pg_start;
- int io_pg_count;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
-
- io_pg_start = hp->io_pages_per_kpage * pg_start;
- io_pg_count = hp->io_pages_per_kpage * mem->page_count;
- if ((io_pg_start + io_pg_count) > hp->gatt_entries) {
- return -EINVAL;
- }
-
- j = io_pg_start;
- while (j < (io_pg_start + io_pg_count)) {
- if (hp->gatt[j]) {
- return -EBUSY;
- }
- j++;
- }
-
- if (mem->is_flushed == FALSE) {
- CACHE_FLUSH();
- mem->is_flushed = TRUE;
- }
-
- for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
- unsigned long paddr;
-
- paddr = mem->memory[i];
- for (k = 0;
- k < hp->io_pages_per_kpage;
- k++, j++, paddr += hp->io_page_size) {
- hp->gatt[j] = agp_bridge.mask_memory(paddr, type);
- }
- }
-
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type)
-{
- struct _hp_private *hp = &hp_private;
- int i, io_pg_start, io_pg_count;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
-
- io_pg_start = hp->io_pages_per_kpage * pg_start;
- io_pg_count = hp->io_pages_per_kpage * mem->page_count;
- for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
- hp->gatt[i] = agp_bridge.scratch_page;
- }
-
- agp_bridge.tlb_flush(mem);
- return 0;
-}
-
-static unsigned long hp_zx1_mask_memory(unsigned long addr, int type)
-{
- return HP_ZX1_PDIR_VALID_BIT | addr;
-}
-
-static unsigned long hp_zx1_unmask_memory(unsigned long addr)
-{
- return addr & ~(HP_ZX1_PDIR_VALID_BIT);
-}
-
-static int __init hp_zx1_setup (struct pci_dev *pdev)
-{
- agp_bridge.masks = hp_zx1_masks;
- agp_bridge.num_of_masks = 1;
- agp_bridge.dev_private_data = NULL;
- agp_bridge.size_type = FIXED_APER_SIZE;
- agp_bridge.needs_scratch_page = FALSE;
- agp_bridge.configure = hp_zx1_configure;
- agp_bridge.fetch_size = hp_zx1_fetch_size;
- agp_bridge.cleanup = hp_zx1_cleanup;
- agp_bridge.tlb_flush = hp_zx1_tlbflush;
- agp_bridge.mask_memory = hp_zx1_mask_memory;
- agp_bridge.unmask_memory = hp_zx1_unmask_memory;
- agp_bridge.agp_enable = agp_generic_agp_enable;
- agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = hp_zx1_create_gatt_table;
- agp_bridge.free_gatt_table = hp_zx1_free_gatt_table;
- agp_bridge.insert_memory = hp_zx1_insert_memory;
- agp_bridge.remove_memory = hp_zx1_remove_memory;
- agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
- agp_bridge.free_by_type = agp_generic_free_by_type;
- agp_bridge.agp_alloc_page = agp_generic_alloc_page;
- agp_bridge.agp_destroy_page = agp_generic_destroy_page;
- agp_bridge.cant_use_aperture = 1;
-
- return hp_zx1_ioc_init();
-
- (void) pdev; /* unused */
-}
-
-#endif /* CONFIG_AGP_HP_ZX1 */
-
-/* per-chipset initialization data.
- * note -- all chipsets for a single vendor MUST be grouped together
- */
-static struct {
- unsigned short device_id; /* first, to make table easier to read */
- unsigned short vendor_id;
- enum chipset_type chipset;
- const char *vendor_name;
- const char *chipset_name;
- int (*chipset_setup) (struct pci_dev *pdev);
-} agp_bridge_info[] __initdata = {
-
-#ifdef CONFIG_AGP_ALI
- { PCI_DEVICE_ID_AL_M1541_0,
- PCI_VENDOR_ID_AL,
- ALI_M1541,
- "Ali",
- "M1541",
- ali_generic_setup },
- { PCI_DEVICE_ID_AL_M1621_0,
- PCI_VENDOR_ID_AL,
- ALI_M1621,
- "Ali",
- "M1621",
- ali_generic_setup },
- { PCI_DEVICE_ID_AL_M1631_0,
- PCI_VENDOR_ID_AL,
- ALI_M1631,
- "Ali",
- "M1631",
- ali_generic_setup },
- { PCI_DEVICE_ID_AL_M1632_0,
- PCI_VENDOR_ID_AL,
- ALI_M1632,
- "Ali",
- "M1632",
- ali_generic_setup },
- { PCI_DEVICE_ID_AL_M1641_0,
- PCI_VENDOR_ID_AL,
- ALI_M1641,
- "Ali",
- "M1641",
- ali_generic_setup },
- { PCI_DEVICE_ID_AL_M1644_0,
- PCI_VENDOR_ID_AL,
- ALI_M1644,
- "Ali",
- "M1644",
- ali_generic_setup },
- { PCI_DEVICE_ID_AL_M1647_0,
- PCI_VENDOR_ID_AL,
- ALI_M1647,
- "Ali",
- "M1647",
- ali_generic_setup },
- { PCI_DEVICE_ID_AL_M1651_0,
- PCI_VENDOR_ID_AL,
- ALI_M1651,
- "Ali",
- "M1651",
- ali_generic_setup },
- { 0,
- PCI_VENDOR_ID_AL,
- ALI_GENERIC,
- "Ali",
- "Generic",
- ali_generic_setup },
-#endif /* CONFIG_AGP_ALI */
-
-#ifdef CONFIG_AGP_AMD
- { PCI_DEVICE_ID_AMD_IRONGATE_0,
- PCI_VENDOR_ID_AMD,
- AMD_IRONGATE,
- "AMD",
- "Irongate",
- amd_irongate_setup },
- { PCI_DEVICE_ID_AMD_761_0,
- PCI_VENDOR_ID_AMD,
- AMD_761,
- "AMD",
- "761",
- amd_irongate_setup },
- { PCI_DEVICE_ID_AMD_762_0,
- PCI_VENDOR_ID_AMD,
- AMD_762,
- "AMD",
- "760MP",
- amd_irongate_setup },
- { 0,
- PCI_VENDOR_ID_AMD,
- AMD_GENERIC,
- "AMD",
- "Generic",
- amd_irongate_setup },
-#endif /* CONFIG_AGP_AMD */
-
-#ifdef CONFIG_AGP_INTEL
- { PCI_DEVICE_ID_INTEL_82443LX_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_LX,
- "Intel",
- "440LX",
- intel_generic_setup },
- { PCI_DEVICE_ID_INTEL_82443BX_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_BX,
- "Intel",
- "440BX",
- intel_generic_setup },
- { PCI_DEVICE_ID_INTEL_82443GX_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_GX,
- "Intel",
- "440GX",
- intel_generic_setup },
- { PCI_DEVICE_ID_INTEL_815_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I815,
- "Intel",
- "i815",
- intel_generic_setup },
- { PCI_DEVICE_ID_INTEL_820_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I820,
- "Intel",
- "i820",
- intel_820_setup },
- { PCI_DEVICE_ID_INTEL_820_UP_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I820,
- "Intel",
- "i820",
- intel_820_setup },
- { PCI_DEVICE_ID_INTEL_830_M_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I830_M,
- "Intel",
- "i830M",
- intel_830mp_setup },
- { PCI_DEVICE_ID_INTEL_845_G_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I845_G,
- "Intel",
- "i845G",
- intel_830mp_setup },
- { PCI_DEVICE_ID_INTEL_840_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I840,
- "Intel",
- "i840",
- intel_840_setup },
- { PCI_DEVICE_ID_INTEL_845_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I845,
- "Intel",
- "i845",
- intel_845_setup },
- { PCI_DEVICE_ID_INTEL_850_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I850,
- "Intel",
- "i850",
-intel_850_setup },
- { PCI_DEVICE_ID_INTEL_860_0,
- PCI_VENDOR_ID_INTEL,
- INTEL_I860,
- "Intel",
- "i860",
- intel_860_setup },
- { 0,
- PCI_VENDOR_ID_INTEL,
- INTEL_GENERIC,
- "Intel",
- "Generic",
- intel_generic_setup },
-
-#endif /* CONFIG_AGP_INTEL */
-
-#ifdef CONFIG_AGP_SIS
- { PCI_DEVICE_ID_SI_740,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "740",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_650,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "650",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_645,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "645",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_735,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "735",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_730,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "730",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_630,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "630",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_540,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "540",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_620,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "620",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_530,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "530",
- sis_generic_setup },
- { PCI_DEVICE_ID_SI_550,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "550",
- sis_generic_setup },
- { 0,
- PCI_VENDOR_ID_SI,
- SIS_GENERIC,
- "SiS",
- "Generic",
- sis_generic_setup },
-#endif /* CONFIG_AGP_SIS */
-
-#ifdef CONFIG_AGP_VIA
- { PCI_DEVICE_ID_VIA_8501_0,
- PCI_VENDOR_ID_VIA,
- VIA_MVP4,
- "Via",
- "MVP4",
- via_generic_setup },
- { PCI_DEVICE_ID_VIA_82C597_0,
- PCI_VENDOR_ID_VIA,
- VIA_VP3,
- "Via",
- "VP3",
- via_generic_setup },
- { PCI_DEVICE_ID_VIA_82C598_0,
- PCI_VENDOR_ID_VIA,
- VIA_MVP3,
- "Via",
- "MVP3",
- via_generic_setup },
- { PCI_DEVICE_ID_VIA_82C691_0,
- PCI_VENDOR_ID_VIA,
- VIA_APOLLO_PRO,
- "Via",
- "Apollo Pro",
- via_generic_setup },
- { PCI_DEVICE_ID_VIA_8371_0,
- PCI_VENDOR_ID_VIA,
- VIA_APOLLO_KX133,
- "Via",
- "Apollo Pro KX133",
- via_generic_setup },
- { PCI_DEVICE_ID_VIA_8363_0,
- PCI_VENDOR_ID_VIA,
- VIA_APOLLO_KT133,
- "Via",
- "Apollo Pro KT133",
- via_generic_setup },
- { PCI_DEVICE_ID_VIA_8367_0,
- PCI_VENDOR_ID_VIA,
- VIA_APOLLO_KT133,
- "Via",
- "Apollo Pro KT266",
- via_generic_setup },
- { 0,
- PCI_VENDOR_ID_VIA,
- VIA_GENERIC,
- "Via",
- "Generic",
- via_generic_setup },
-#endif /* CONFIG_AGP_VIA */
-
-#ifdef CONFIG_AGP_HP_ZX1
- { PCI_DEVICE_ID_HP_ZX1_LBA,
- PCI_VENDOR_ID_HP,
- HP_ZX1,
- "HP",
- "ZX1",
- hp_zx1_setup },
-#endif
-
- { 0, }, /* dummy final entry, always present */
-};
-
-
-/* scan table above for supported devices */
-static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE (agp_bridge_info); i++)
- if (pdev->vendor == agp_bridge_info[i].vendor_id)
- break;
-
- if (i >= ARRAY_SIZE (agp_bridge_info)) {
- printk (KERN_DEBUG PFX "unsupported bridge\n");
- return -ENODEV;
- }
-
- while ((i < ARRAY_SIZE (agp_bridge_info)) &&
- (agp_bridge_info[i].vendor_id == pdev->vendor)) {
- if (pdev->device == agp_bridge_info[i].device_id) {
-#ifdef CONFIG_AGP_ALI
- if (pdev->device == PCI_DEVICE_ID_AL_M1621_0) {
- u8 hidden_1621_id;
-
- pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
- switch (hidden_1621_id) {
- case 0x31:
- agp_bridge_info[i].chipset_name="M1631";
- break;
- case 0x32:
- agp_bridge_info[i].chipset_name="M1632";
- break;
- case 0x41:
- agp_bridge_info[i].chipset_name="M1641";
- break;
- case 0x43:
- break;
- case 0x47:
- agp_bridge_info[i].chipset_name="M1647";
- break;
- case 0x51:
- agp_bridge_info[i].chipset_name="M1651";
- break;
- default:
- break;
- }
- }
-#endif
-
- printk (KERN_INFO PFX "Detected %s %s chipset\n",
- agp_bridge_info[i].vendor_name,
- agp_bridge_info[i].chipset_name);
- agp_bridge.type = agp_bridge_info[i].chipset;
- return agp_bridge_info[i].chipset_setup (pdev);
- }
-
- i++;
- }
-
- i--; /* point to vendor generic entry (device_id == 0) */
-
- /* try init anyway, if user requests it AND
- * there is a 'generic' bridge entry for this vendor */
- if (agp_try_unsupported && agp_bridge_info[i].device_id == 0) {
- printk(KERN_WARNING PFX "Trying generic %s routines"
- " for device id: %04x\n",
- agp_bridge_info[i].vendor_name, pdev->device);
- agp_bridge.type = agp_bridge_info[i].chipset;
- return agp_bridge_info[i].chipset_setup (pdev);
- }
-
- printk(KERN_ERR PFX "Unsupported %s chipset (device id: %04x),"
- " you might want to try agp_try_unsupported=1.\n",
- agp_bridge_info[i].vendor_name, pdev->device);
- return -ENODEV;
-}
-
-
-/* Supported Device Scanning routine */
-
-static int __init agp_find_supported_device(void)
-{
- struct pci_dev *dev = NULL;
- u8 cap_ptr = 0x00;
-
- if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL)
- return -ENODEV;
-
- agp_bridge.dev = dev;
-
- /* Need to test for I810 here */
-#ifdef CONFIG_AGP_I810
- if (dev->vendor == PCI_VENDOR_ID_INTEL) {
- struct pci_dev *i810_dev;
-
- switch (dev->device) {
- case PCI_DEVICE_ID_INTEL_810_0:
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_810_1,
- NULL);
- if (i810_dev == NULL) {
- printk(KERN_ERR PFX "Detected an Intel i810,"
- " but could not find the secondary"
- " device.\n");
- return -ENODEV;
- }
- printk(KERN_INFO PFX "Detected an Intel "
- "i810 Chipset.\n");
- agp_bridge.type = INTEL_I810;
- return intel_i810_setup (i810_dev);
-
- case PCI_DEVICE_ID_INTEL_810_DC100_0:
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_810_DC100_1,
- NULL);
- if (i810_dev == NULL) {
- printk(KERN_ERR PFX "Detected an Intel i810 "
- "DC100, but could not find the "
- "secondary device.\n");
- return -ENODEV;
- }
- printk(KERN_INFO PFX "Detected an Intel i810 "
- "DC100 Chipset.\n");
- agp_bridge.type = INTEL_I810;
- return intel_i810_setup(i810_dev);
-
- case PCI_DEVICE_ID_INTEL_810_E_0:
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_810_E_1,
- NULL);
- if (i810_dev == NULL) {
- printk(KERN_ERR PFX "Detected an Intel i810 E"
- ", but could not find the secondary "
- "device.\n");
- return -ENODEV;
- }
- printk(KERN_INFO PFX "Detected an Intel i810 E "
- "Chipset.\n");
- agp_bridge.type = INTEL_I810;
- return intel_i810_setup(i810_dev);
-
- case PCI_DEVICE_ID_INTEL_815_0:
- /* The i815 can operate either as an i810 style
- * integrated device, or as an AGP4X motherboard.
- *
- * This only addresses the first mode:
- */
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_815_1,
- NULL);
- if (i810_dev == NULL) {
- printk(KERN_ERR PFX "agpgart: Detected an "
- "Intel i815, but could not find the"
- " secondary device. Assuming a "
- "non-integrated video card.\n");
- break;
- }
- printk(KERN_INFO PFX "agpgart: Detected an Intel i815 "
- "Chipset.\n");
- agp_bridge.type = INTEL_I810;
- return intel_i810_setup(i810_dev);
-
- case PCI_DEVICE_ID_INTEL_845_G_0:
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_845_G_1, NULL);
- if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_845_G_1, i810_dev);
- }
-
- if (i810_dev == NULL) {
- /*
- * We probably have a I845MP chipset
- * with an external graphics
- * card. It will be initialized later
- */
- agp_bridge.type = INTEL_I845_G;
- break;
- }
- printk(KERN_INFO PFX "Detected an Intel "
- "845G Chipset.\n");
- agp_bridge.type = INTEL_I810;
- return intel_i830_setup(i810_dev);
-
- case PCI_DEVICE_ID_INTEL_830_M_0:
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_830_M_1,
- NULL);
- if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
- i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_830_M_1,
- i810_dev);
- }
-
- if (i810_dev == NULL) {
- /* Intel 830MP with external graphic card */
- /* It will be initialized later */
- agp_bridge.type = INTEL_I830_M;
- break;
- }
- printk(KERN_INFO PFX "Detected an Intel "
- "830M Chipset.\n");
- agp_bridge.type = INTEL_I810;
- return intel_i830_setup(i810_dev);
- default:
- break;
- }
- }
-#endif /* CONFIG_AGP_I810 */
-
-#ifdef CONFIG_AGP_SWORKS
- /* Everything is on func 1 here so we are hardcoding function one */
- if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS) {
- struct pci_dev *bridge_dev;
-
- bridge_dev = pci_find_slot ((unsigned int)dev->bus->number,
- PCI_DEVFN(0, 1));
- if(bridge_dev == NULL) {
- printk(KERN_INFO PFX "agpgart: Detected a Serverworks "
- "Chipset, but could not find the secondary "
- "device.\n");
- return -ENODEV;
- }
-
- switch (dev->device) {
- case PCI_DEVICE_ID_SERVERWORKS_HE:
- agp_bridge.type = SVWRKS_HE;
- return serverworks_setup(bridge_dev);
-
- case PCI_DEVICE_ID_SERVERWORKS_LE:
- case 0x0007:
- agp_bridge.type = SVWRKS_LE;
- return serverworks_setup(bridge_dev);
-
- default:
- if(agp_try_unsupported) {
- agp_bridge.type = SVWRKS_GENERIC;
- return serverworks_setup(bridge_dev);
- }
- break;
- }
- }
-
-#endif /* CONFIG_AGP_SWORKS */
-
-#ifdef CONFIG_AGP_HP_ZX1
- if (dev->vendor == PCI_VENDOR_ID_HP) {
- do {
- /* ZX1 LBAs can be either PCI or AGP bridges */
- if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
- printk(KERN_INFO PFX "Detected HP ZX1 AGP "
- "chipset at %s\n", dev->slot_name);
- agp_bridge.type = HP_ZX1;
- agp_bridge.dev = dev;
- return hp_zx1_setup(dev);
- }
- dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev);
- } while (dev);
- return -ENODEV;
- }
-#endif /* CONFIG_AGP_HP_ZX1 */
-
- /* find capndx */
- cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
- if (cap_ptr == 0x00)
- return -ENODEV;
- agp_bridge.capndx = cap_ptr;
-
- /* Fill in the mode register */
- pci_read_config_dword(agp_bridge.dev,
- agp_bridge.capndx + 4,
- &agp_bridge.mode);
-
- /* probe for known chipsets */
- return agp_lookup_host_bridge (dev);
-}
-
-struct agp_max_table {
- int mem;
- int agp;
-};
-
-static struct agp_max_table maxes_table[9] __initdata =
-{
- {0, 0},
- {32, 4},
- {64, 28},
- {128, 96},
- {256, 204},
- {512, 440},
- {1024, 942},
- {2048, 1920},
- {4096, 3932}
-};
-
-static int __init agp_find_max (void)
-{
- long memory, index, result;
-
- memory = virt_to_phys(high_memory) >> 20;
- index = 1;
-
- while ((memory > maxes_table[index].mem) &&
- (index < 8)) {
- index++;
- }
-
- result = maxes_table[index - 1].agp +
- ( (memory - maxes_table[index - 1].mem) *
- (maxes_table[index].agp - maxes_table[index - 1].agp)) /
- (maxes_table[index].mem - maxes_table[index - 1].mem);
-
- printk(KERN_INFO PFX "Maximum main memory to use "
- "for agp memory: %ldM\n", result);
- result = result << (20 - PAGE_SHIFT);
- return result;
-}
-
-#define AGPGART_VERSION_MAJOR 0
-#define AGPGART_VERSION_MINOR 99
-
-static agp_version agp_current_version =
-{
- AGPGART_VERSION_MAJOR,
- AGPGART_VERSION_MINOR
-};
-
-static int __init agp_backend_initialize(void)
-{
- int size_value, rc, got_gatt=0, got_keylist=0;
-
- memset(&agp_bridge, 0, sizeof(struct agp_bridge_data));
- agp_bridge.type = NOT_SUPPORTED;
- agp_bridge.max_memory_agp = agp_find_max();
- agp_bridge.version = &agp_current_version;
-
- rc = agp_find_supported_device();
- if (rc) {
- /* not KERN_ERR because error msg should have already printed */
- printk(KERN_DEBUG PFX "no supported devices found.\n");
- return rc;
- }
-
- if (agp_bridge.needs_scratch_page == TRUE) {
- void *addr;
- addr = agp_bridge.agp_alloc_page();
-
- if (addr == NULL) {
- printk(KERN_ERR PFX "unable to get memory for "
- "scratch page.\n");
- return -ENOMEM;
- }
- agp_bridge.scratch_page = virt_to_phys(addr);
- agp_bridge.scratch_page =
- agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
- }
-
- size_value = agp_bridge.fetch_size();
-
- if (size_value == 0) {
- printk(KERN_ERR PFX "unable to determine aperture size.\n");
- rc = -EINVAL;
- goto err_out;
- }
- if (agp_bridge.create_gatt_table()) {
- printk(KERN_ERR PFX "unable to get memory for graphics "
- "translation table.\n");
- rc = -ENOMEM;
- goto err_out;
- }
- got_gatt = 1;
-
- agp_bridge.key_list = vmalloc(PAGE_SIZE * 4);
- if (agp_bridge.key_list == NULL) {
- printk(KERN_ERR PFX "error allocating memory for key lists.\n");
- rc = -ENOMEM;
- goto err_out;
- }
- got_keylist = 1;
-
- /* FIXME vmalloc'd memory not guaranteed contiguous */
- memset(agp_bridge.key_list, 0, PAGE_SIZE * 4);
-
- if (agp_bridge.configure()) {
- printk(KERN_ERR PFX "error configuring host chipset.\n");
- rc = -EINVAL;
- goto err_out;
- }
-
- printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
- size_value, agp_bridge.gart_bus_addr);
-
- return 0;
-
-err_out:
- if (agp_bridge.needs_scratch_page == TRUE) {
- agp_bridge.scratch_page &= ~(0x00000fff);
- agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
- }
- if (got_gatt)
- agp_bridge.free_gatt_table();
- if (got_keylist)
- vfree(agp_bridge.key_list);
- return rc;
-}
-
-
-/* cannot be __exit b/c as it could be called from __init code */
-static void agp_backend_cleanup(void)
-{
- agp_bridge.cleanup();
- agp_bridge.free_gatt_table();
- vfree(agp_bridge.key_list);
-
- if (agp_bridge.needs_scratch_page == TRUE) {
- agp_bridge.scratch_page &= ~(0x00000fff);
- agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
- }
-}
-
-static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data)
-{
- switch(rq)
- {
- case PM_SUSPEND:
- return agp_bridge.suspend();
- case PM_RESUME:
- agp_bridge.resume();
- return 0;
- }
- return 0;
-}
-
-extern int agp_frontend_initialize(void);
-extern void agp_frontend_cleanup(void);
-
-static const drm_agp_t drm_agp = {
- &agp_free_memory,
- &agp_allocate_memory,
- &agp_bind_memory,
- &agp_unbind_memory,
- &agp_enable,
- &agp_backend_acquire,
- &agp_backend_release,
- &agp_copy_info
-};
-
-static int __init agp_init(void)
-{
- int ret_val;
-
- printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Jeff Hartmann\n",
- AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
-
- ret_val = agp_backend_initialize();
- if (ret_val) {
- agp_bridge.type = NOT_SUPPORTED;
- return ret_val;
- }
- ret_val = agp_frontend_initialize();
- if (ret_val) {
- agp_bridge.type = NOT_SUPPORTED;
- agp_backend_cleanup();
- return ret_val;
- }
-
- inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
-
- pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power);
- return 0;
-}
-
-static void __exit agp_cleanup(void)
-{
- pm_unregister_all(agp_power);
- agp_frontend_cleanup();
- agp_backend_cleanup();
- inter_module_unregister("drm_agp");
-}
-
-module_init(agp_init);
-module_exit(agp_cleanup);
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
new file mode 100644
index 000000000000..e60ca2a30fd3
--- /dev/null
+++ b/drivers/char/agp/ali-agp.c
@@ -0,0 +1,265 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+static int ali_fetch_size(void)
+{
+ int i;
+ u32 temp;
+ struct aper_size_info_32 *values;
+
+ pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
+ temp &= ~(0xfffffff0);
+ values = A_SIZE_32(agp_bridge.aperture_sizes);
+
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ if (temp == values[i].size_value) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + i);
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+
+ return 0;
+}
+
+static void ali_tlbflush(agp_memory * mem)
+{
+ u32 temp;
+
+ pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+// clear tag
+ pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL,
+ ((temp & 0xfffffff0) | 0x00000001|0x00000002));
+}
+
+static void ali_cleanup(void)
+{
+ struct aper_size_info_32 *previous_size;
+ u32 temp;
+
+ previous_size = A_SIZE_32(agp_bridge.previous_size);
+
+ pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+// clear tag
+ pci_write_config_dword(agp_bridge.dev, ALI_TAGCTRL,
+ ((temp & 0xffffff00) | 0x00000001|0x00000002));
+
+ pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
+ pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE,
+ ((temp & 0x00000ff0) | previous_size->size_value));
+}
+
+static int ali_configure(void)
+{
+ u32 temp;
+ struct aper_size_info_32 *current_size;
+
+ current_size = A_SIZE_32(agp_bridge.current_size);
+
+ /* aperture size and gatt addr */
+ pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
+ temp = (((temp & 0x00000ff0) | (agp_bridge.gatt_bus_addr & 0xfffff000))
+ | (current_size->size_value & 0xf));
+ pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, temp);
+
+ /* tlb control */
+
+ /*
+ * Question: Jeff, ALi's patch deletes this:
+ *
+ * pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+ * pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
+ * ((temp & 0xffffff00) | 0x00000010));
+ *
+ * and replaces it with the following, which seems to duplicate the
+ * next couple of lines below it. I suspect this was an oversight,
+ * but you might want to check up on this?
+ */
+
+ pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+#if 0
+ if (agp_bridge.type == ALI_M1541) {
+ u32 nlvm_addr = 0;
+
+ switch (current_size->size_value) {
+ case 0: break;
+ case 1: nlvm_addr = 0x100000;break;
+ case 2: nlvm_addr = 0x200000;break;
+ case 3: nlvm_addr = 0x400000;break;
+ case 4: nlvm_addr = 0x800000;break;
+ case 6: nlvm_addr = 0x1000000;break;
+ case 7: nlvm_addr = 0x2000000;break;
+ case 8: nlvm_addr = 0x4000000;break;
+ case 9: nlvm_addr = 0x8000000;break;
+ case 10: nlvm_addr = 0x10000000;break;
+ default: break;
+ }
+ nlvm_addr--;
+ nlvm_addr&=0xfff00000;
+
+ nlvm_addr+= agp_bridge.gart_bus_addr;
+ nlvm_addr|=(agp_bridge.gart_bus_addr>>12);
+ printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr);
+ }
+#endif
+
+ pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+ temp &= 0xffffff7f; //enable TLB
+ pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, temp);
+
+ return 0;
+}
+
+static unsigned long ali_mask_memory(unsigned long addr, int type)
+{
+ /* Memory type is ignored */
+
+ return addr | agp_bridge.masks[0].mask;
+}
+
+static void ali_cache_flush(void)
+{
+ global_cache_flush();
+
+ if (agp_bridge.type == ALI_M1541) {
+ int i, page_count;
+ u32 temp;
+
+ page_count = 1 << A_SIZE_32(agp_bridge.current_size)->page_order;
+ for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) {
+ pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
+ pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
+ (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+ (agp_bridge.gatt_bus_addr + i)) |
+ ALI_CACHE_FLUSH_EN));
+ }
+ }
+}
+
+static void *ali_alloc_page(void)
+{
+ void *adr = agp_generic_alloc_page();
+ u32 temp;
+
+ if (adr == 0)
+ return 0;
+
+ if (agp_bridge.type == ALI_M1541) {
+ pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
+ pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
+ (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+ virt_to_phys(adr)) |
+ ALI_CACHE_FLUSH_EN ));
+ }
+ return adr;
+}
+
+static void ali_destroy_page(void * addr)
+{
+ u32 temp;
+
+ if (addr == NULL)
+ return;
+
+ global_cache_flush();
+
+ if (agp_bridge.type == ALI_M1541) {
+ pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
+ pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
+ (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+ virt_to_phys(addr)) |
+ ALI_CACHE_FLUSH_EN));
+ }
+
+ agp_generic_destroy_page(addr);
+}
+
+/* Setup function */
+static struct gatt_mask ali_generic_masks[] =
+{
+ {mask: 0x00000000, type: 0}
+};
+
+static struct aper_size_info_32 ali_generic_sizes[7] =
+{
+ {256, 65536, 6, 10},
+ {128, 32768, 5, 9},
+ {64, 16384, 4, 8},
+ {32, 8192, 3, 7},
+ {16, 4096, 2, 6},
+ {8, 2048, 1, 4},
+ {4, 1024, 0, 3}
+};
+
+int __init ali_generic_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = ali_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) ali_generic_sizes;
+ agp_bridge.size_type = U32_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = ali_configure;
+ agp_bridge.fetch_size = ali_fetch_size;
+ agp_bridge.cleanup = ali_cleanup;
+ agp_bridge.tlb_flush = ali_tlbflush;
+ agp_bridge.mask_memory = ali_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = ali_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = ali_alloc_page;
+ agp_bridge.agp_destroy_page = ali_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
diff --git a/drivers/char/agp/amd-agp.c b/drivers/char/agp/amd-agp.c
new file mode 100644
index 000000000000..9fc81a0011e6
--- /dev/null
+++ b/drivers/char/agp/amd-agp.c
@@ -0,0 +1,408 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+struct amd_page_map {
+ unsigned long *real;
+ unsigned long *remapped;
+};
+
+static struct _amd_irongate_private {
+ volatile u8 *registers;
+ struct amd_page_map **gatt_pages;
+ int num_tables;
+} amd_irongate_private;
+
+static int amd_create_page_map(struct amd_page_map *page_map)
+{
+ int i;
+
+ page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
+ if (page_map->real == NULL) {
+ return -ENOMEM;
+ }
+ SetPageReserved(virt_to_page(page_map->real));
+ CACHE_FLUSH();
+ page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
+ PAGE_SIZE);
+ if (page_map->remapped == NULL) {
+ ClearPageReserved(virt_to_page(page_map->real));
+ free_page((unsigned long) page_map->real);
+ page_map->real = NULL;
+ return -ENOMEM;
+ }
+ CACHE_FLUSH();
+
+ for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
+ page_map->remapped[i] = agp_bridge.scratch_page;
+ }
+
+ return 0;
+}
+
+static void amd_free_page_map(struct amd_page_map *page_map)
+{
+ iounmap(page_map->remapped);
+ ClearPageReserved(virt_to_page(page_map->real));
+ free_page((unsigned long) page_map->real);
+}
+
+static void amd_free_gatt_pages(void)
+{
+ int i;
+ struct amd_page_map **tables;
+ struct amd_page_map *entry;
+
+ tables = amd_irongate_private.gatt_pages;
+ for(i = 0; i < amd_irongate_private.num_tables; i++) {
+ entry = tables[i];
+ if (entry != NULL) {
+ if (entry->real != NULL) {
+ amd_free_page_map(entry);
+ }
+ kfree(entry);
+ }
+ }
+ kfree(tables);
+}
+
+static int amd_create_gatt_pages(int nr_tables)
+{
+ struct amd_page_map **tables;
+ struct amd_page_map *entry;
+ int retval = 0;
+ int i;
+
+ tables = kmalloc((nr_tables + 1) * sizeof(struct amd_page_map *),
+ GFP_KERNEL);
+ if (tables == NULL) {
+ return -ENOMEM;
+ }
+ memset(tables, 0, sizeof(struct amd_page_map *) * (nr_tables + 1));
+ for (i = 0; i < nr_tables; i++) {
+ entry = kmalloc(sizeof(struct amd_page_map), GFP_KERNEL);
+ if (entry == NULL) {
+ retval = -ENOMEM;
+ break;
+ }
+ memset(entry, 0, sizeof(struct amd_page_map));
+ tables[i] = entry;
+ retval = amd_create_page_map(entry);
+ if (retval != 0) break;
+ }
+ amd_irongate_private.num_tables = nr_tables;
+ amd_irongate_private.gatt_pages = tables;
+
+ if (retval != 0) amd_free_gatt_pages();
+
+ return retval;
+}
+
+/* Since we don't need contigious memory we just try
+ * to get the gatt table once
+ */
+
+#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
+#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
+ GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr))
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
+#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\
+ GET_PAGE_DIR_IDX(addr)]->remapped)
+
+static int amd_create_gatt_table(void)
+{
+ struct aper_size_info_lvl2 *value;
+ struct amd_page_map page_dir;
+ unsigned long addr;
+ int retval;
+ u32 temp;
+ int i;
+
+ value = A_SIZE_LVL2(agp_bridge.current_size);
+ retval = amd_create_page_map(&page_dir);
+ if (retval != 0) {
+ return retval;
+ }
+
+ retval = amd_create_gatt_pages(value->num_entries / 1024);
+ if (retval != 0) {
+ amd_free_page_map(&page_dir);
+ return retval;
+ }
+
+ agp_bridge.gatt_table_real = page_dir.real;
+ agp_bridge.gatt_table = page_dir.remapped;
+ agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real);
+
+ /* Get the address for the gart region.
+ * This is a bus address even on the alpha, b/c its
+ * used to program the agp master not the cpu
+ */
+
+ pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp);
+ addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge.gart_bus_addr = addr;
+
+ /* Calculate the agp offset */
+ for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
+ page_dir.remapped[GET_PAGE_DIR_OFF(addr)] =
+ virt_to_phys(amd_irongate_private.gatt_pages[i]->real);
+ page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001;
+ }
+
+ return 0;
+}
+
+static int amd_free_gatt_table(void)
+{
+ struct amd_page_map page_dir;
+
+ page_dir.real = agp_bridge.gatt_table_real;
+ page_dir.remapped = agp_bridge.gatt_table;
+
+ amd_free_gatt_pages();
+ amd_free_page_map(&page_dir);
+ return 0;
+}
+
+static int amd_irongate_fetch_size(void)
+{
+ int i;
+ u32 temp;
+ struct aper_size_info_lvl2 *values;
+
+ pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
+ temp = (temp & 0x0000000e);
+ values = A_SIZE_LVL2(agp_bridge.aperture_sizes);
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ if (temp == values[i].size_value) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + i);
+
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+
+ return 0;
+}
+
+static int amd_irongate_configure(void)
+{
+ struct aper_size_info_lvl2 *current_size;
+ u32 temp;
+ u16 enable_reg;
+
+ current_size = A_SIZE_LVL2(agp_bridge.current_size);
+
+ /* Get the memory mapped registers */
+ pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp);
+ temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096);
+
+ /* Write out the address of the gatt table */
+ OUTREG32(amd_irongate_private.registers, AMD_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* Write the Sync register */
+ pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80);
+
+ /* Set indexing mode */
+ pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00);
+
+ /* Write the enable register */
+ enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
+ enable_reg = (enable_reg | 0x0004);
+ OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg);
+
+ /* Write out the size register */
+ pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
+ temp = (((temp & ~(0x0000000e)) | current_size->size_value)
+ | 0x00000001);
+ pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp);
+
+ /* Flush the tlb */
+ OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
+
+ return 0;
+}
+
+static void amd_irongate_cleanup(void)
+{
+ struct aper_size_info_lvl2 *previous_size;
+ u32 temp;
+ u16 enable_reg;
+
+ previous_size = A_SIZE_LVL2(agp_bridge.previous_size);
+
+ enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
+ enable_reg = (enable_reg & ~(0x0004));
+ OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg);
+
+ /* Write back the previous size and disable gart translation */
+ pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
+ temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
+ pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp);
+ iounmap((void *) amd_irongate_private.registers);
+}
+
+/*
+ * This routine could be implemented by taking the addresses
+ * written to the GATT, and flushing them individually. However
+ * currently it just flushes the whole table. Which is probably
+ * more efficent, since agp_memory blocks can be a large number of
+ * entries.
+ */
+
+static void amd_irongate_tlbflush(agp_memory * temp)
+{
+ OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
+}
+
+static unsigned long amd_irongate_mask_memory(unsigned long addr, int type)
+{
+ /* Only type 0 is supported by the irongate */
+
+ return addr | agp_bridge.masks[0].mask;
+}
+
+static int amd_insert_memory(agp_memory * mem,
+ off_t pg_start, int type)
+{
+ int i, j, num_entries;
+ unsigned long *cur_gatt;
+ unsigned long addr;
+
+ num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+ if ((pg_start + mem->page_count) > num_entries) {
+ return -EINVAL;
+ }
+
+ j = pg_start;
+ while (j < (pg_start + mem->page_count)) {
+ addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = GET_GATT(addr);
+ if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
+ return -EBUSY;
+ }
+ j++;
+ }
+
+ if (mem->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ mem->is_flushed = TRUE;
+ }
+
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = GET_GATT(addr);
+ cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+ }
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static int amd_remove_memory(agp_memory * mem, off_t pg_start,
+ int type)
+{
+ int i;
+ unsigned long *cur_gatt;
+ unsigned long addr;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+ for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+ addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = GET_GATT(addr);
+ cur_gatt[GET_GATT_OFF(addr)] =
+ (unsigned long) agp_bridge.scratch_page;
+ }
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static struct aper_size_info_lvl2 amd_irongate_sizes[7] =
+{
+ {2048, 524288, 0x0000000c},
+ {1024, 262144, 0x0000000a},
+ {512, 131072, 0x00000008},
+ {256, 65536, 0x00000006},
+ {128, 32768, 0x00000004},
+ {64, 16384, 0x00000002},
+ {32, 8192, 0x00000000}
+};
+
+static struct gatt_mask amd_irongate_masks[] =
+{
+ {mask: 0x00000001, type: 0}
+};
+
+int __init amd_irongate_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = amd_irongate_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
+ agp_bridge.size_type = LVL2_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = (void *) &amd_irongate_private;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = amd_irongate_configure;
+ agp_bridge.fetch_size = amd_irongate_fetch_size;
+ agp_bridge.cleanup = amd_irongate_cleanup;
+ agp_bridge.tlb_flush = amd_irongate_tlbflush;
+ agp_bridge.mask_memory = amd_irongate_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = amd_create_gatt_table;
+ agp_bridge.free_gatt_table = amd_free_gatt_table;
+ agp_bridge.insert_memory = amd_insert_memory;
+ agp_bridge.remove_memory = amd_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
diff --git a/drivers/char/agp/agpgart_fe.c b/drivers/char/agp/frontend.c
index e603a9e5f1e8..a2e0a5ee1b42 100644
--- a/drivers/char/agp/agpgart_fe.c
+++ b/drivers/char/agp/frontend.c
@@ -24,29 +24,16 @@
*
*/
-#define __NO_VERSION__
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
+#include <linux/mman.h>
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/pagemap.h>
#include <linux/miscdevice.h>
#include <linux/agp_backend.h>
#include <linux/agpgart.h>
-#include <linux/smp_lock.h>
-#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/mman.h>
#include "agp.h"
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
new file mode 100644
index 000000000000..6798e967d386
--- /dev/null
+++ b/drivers/char/agp/hp-agp.c
@@ -0,0 +1,394 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+
+#ifndef log2
+#define log2(x) ffz(~(x))
+#endif
+
+#define HP_ZX1_IOVA_BASE GB(1UL)
+#define HP_ZX1_IOVA_SIZE GB(1UL)
+#define HP_ZX1_GART_SIZE (HP_ZX1_IOVA_SIZE / 2)
+#define HP_ZX1_SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL
+
+#define HP_ZX1_PDIR_VALID_BIT 0x8000000000000000UL
+#define HP_ZX1_IOVA_TO_PDIR(va) ((va - hp_private.iova_base) >> \
+ hp_private.io_tlb_shift)
+
+static struct aper_size_info_fixed hp_zx1_sizes[] =
+{
+ {0, 0, 0}, /* filled in by hp_zx1_fetch_size() */
+};
+
+static struct gatt_mask hp_zx1_masks[] =
+{
+ {mask: HP_ZX1_PDIR_VALID_BIT, type: 0}
+};
+
+static struct _hp_private {
+ struct pci_dev *ioc;
+ volatile u8 *registers;
+ u64 *io_pdir; // PDIR for entire IOVA
+ u64 *gatt; // PDIR just for GART (subset of above)
+ u64 gatt_entries;
+ u64 iova_base;
+ u64 gart_base;
+ u64 gart_size;
+ u64 io_pdir_size;
+ int io_pdir_owner; // do we own it, or share it with sba_iommu?
+ int io_page_size;
+ int io_tlb_shift;
+ int io_tlb_ps; // IOC ps config
+ int io_pages_per_kpage;
+} hp_private;
+
+static int __init hp_zx1_ioc_shared(void)
+{
+ struct _hp_private *hp = &hp_private;
+
+ printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n");
+
+ /*
+ * IOC already configured by sba_iommu module; just use
+ * its setup. We assume:
+ * - IOVA space is 1Gb in size
+ * - first 512Mb is IOMMU, second 512Mb is GART
+ */
+ hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG);
+ switch (hp->io_tlb_ps) {
+ case 0: hp->io_tlb_shift = 12; break;
+ case 1: hp->io_tlb_shift = 13; break;
+ case 2: hp->io_tlb_shift = 14; break;
+ case 3: hp->io_tlb_shift = 16; break;
+ default:
+ printk(KERN_ERR PFX "Invalid IOTLB page size "
+ "configuration 0x%x\n", hp->io_tlb_ps);
+ hp->gatt = 0;
+ hp->gatt_entries = 0;
+ return -ENODEV;
+ }
+ hp->io_page_size = 1 << hp->io_tlb_shift;
+ hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+ hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1;
+ hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE;
+
+ hp->gart_size = HP_ZX1_GART_SIZE;
+ hp->gatt_entries = hp->gart_size / hp->io_page_size;
+
+ hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE));
+ hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+
+ if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
+ hp->gatt = 0;
+ hp->gatt_entries = 0;
+ printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
+ "GART disabled\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int __init hp_zx1_ioc_owner(u8 ioc_rev)
+{
+ struct _hp_private *hp = &hp_private;
+
+ printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n");
+
+ /*
+ * Select an IOV page size no larger than system page size.
+ */
+ if (PAGE_SIZE >= KB(64)) {
+ hp->io_tlb_shift = 16;
+ hp->io_tlb_ps = 3;
+ } else if (PAGE_SIZE >= KB(16)) {
+ hp->io_tlb_shift = 14;
+ hp->io_tlb_ps = 2;
+ } else if (PAGE_SIZE >= KB(8)) {
+ hp->io_tlb_shift = 13;
+ hp->io_tlb_ps = 1;
+ } else {
+ hp->io_tlb_shift = 12;
+ hp->io_tlb_ps = 0;
+ }
+ hp->io_page_size = 1 << hp->io_tlb_shift;
+ hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+ hp->iova_base = HP_ZX1_IOVA_BASE;
+ hp->gart_size = HP_ZX1_GART_SIZE;
+ hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size;
+
+ hp->gatt_entries = hp->gart_size / hp->io_page_size;
+ hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64);
+
+ return 0;
+}
+
+static int __init hp_zx1_ioc_init(void)
+{
+ struct _hp_private *hp = &hp_private;
+ struct pci_dev *ioc;
+ int i;
+ u8 ioc_rev;
+
+ ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL);
+ if (!ioc) {
+ printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n");
+ return -ENODEV;
+ }
+ hp->ioc = ioc;
+
+ pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev);
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
+ hp->registers = (u8 *) ioremap(pci_resource_start(ioc,
+ i),
+ pci_resource_len(ioc, i));
+ break;
+ }
+ }
+ if (!hp->registers) {
+ printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
+
+ return -ENODEV;
+ }
+
+ /*
+ * If the IOTLB is currently disabled, we can take it over.
+ * Otherwise, we have to share with sba_iommu.
+ */
+ hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0;
+
+ if (hp->io_pdir_owner)
+ return hp_zx1_ioc_owner(ioc_rev);
+
+ return hp_zx1_ioc_shared();
+}
+
+static int hp_zx1_fetch_size(void)
+{
+ int size;
+
+ size = hp_private.gart_size / MB(1);
+ hp_zx1_sizes[0].size = size;
+ agp_bridge.current_size = (void *) &hp_zx1_sizes[0];
+ return size;
+}
+
+static int hp_zx1_configure(void)
+{
+ struct _hp_private *hp = &hp_private;
+
+ agp_bridge.gart_bus_addr = hp->gart_base;
+ agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP);
+ pci_read_config_dword(agp_bridge.dev,
+ agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode);
+
+ if (hp->io_pdir_owner) {
+ OUTREG64(hp->registers, HP_ZX1_PDIR_BASE,
+ virt_to_phys(hp->io_pdir));
+ OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps);
+ OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1));
+ OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1);
+ OUTREG64(hp->registers, HP_ZX1_PCOM,
+ hp->iova_base | log2(HP_ZX1_IOVA_SIZE));
+ INREG64(hp->registers, HP_ZX1_PCOM);
+ }
+
+ return 0;
+}
+
+static void hp_zx1_cleanup(void)
+{
+ struct _hp_private *hp = &hp_private;
+
+ if (hp->io_pdir_owner)
+ OUTREG64(hp->registers, HP_ZX1_IBASE, 0);
+ iounmap((void *) hp->registers);
+}
+
+static void hp_zx1_tlbflush(agp_memory * mem)
+{
+ struct _hp_private *hp = &hp_private;
+
+ OUTREG64(hp->registers, HP_ZX1_PCOM,
+ hp->gart_base | log2(hp->gart_size));
+ INREG64(hp->registers, HP_ZX1_PCOM);
+}
+
+static int hp_zx1_create_gatt_table(void)
+{
+ struct _hp_private *hp = &hp_private;
+ int i;
+
+ if (hp->io_pdir_owner) {
+ hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL,
+ get_order(hp->io_pdir_size));
+ if (!hp->io_pdir) {
+ printk(KERN_ERR PFX "Couldn't allocate contiguous "
+ "memory for I/O PDIR\n");
+ hp->gatt = 0;
+ hp->gatt_entries = 0;
+ return -ENOMEM;
+ }
+ memset(hp->io_pdir, 0, hp->io_pdir_size);
+
+ hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+ }
+
+ for (i = 0; i < hp->gatt_entries; i++) {
+ hp->gatt[i] = (unsigned long) agp_bridge.scratch_page;
+ }
+
+ return 0;
+}
+
+static int hp_zx1_free_gatt_table(void)
+{
+ struct _hp_private *hp = &hp_private;
+
+ if (hp->io_pdir_owner)
+ free_pages((unsigned long) hp->io_pdir,
+ get_order(hp->io_pdir_size));
+ else
+ hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE;
+ return 0;
+}
+
+static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+ struct _hp_private *hp = &hp_private;
+ int i, k;
+ off_t j, io_pg_start;
+ int io_pg_count;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+
+ io_pg_start = hp->io_pages_per_kpage * pg_start;
+ io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+ if ((io_pg_start + io_pg_count) > hp->gatt_entries) {
+ return -EINVAL;
+ }
+
+ j = io_pg_start;
+ while (j < (io_pg_start + io_pg_count)) {
+ if (hp->gatt[j]) {
+ return -EBUSY;
+ }
+ j++;
+ }
+
+ if (mem->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ mem->is_flushed = TRUE;
+ }
+
+ for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+ unsigned long paddr;
+
+ paddr = mem->memory[i];
+ for (k = 0;
+ k < hp->io_pages_per_kpage;
+ k++, j++, paddr += hp->io_page_size) {
+ hp->gatt[j] = agp_bridge.mask_memory(paddr, type);
+ }
+ }
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+ struct _hp_private *hp = &hp_private;
+ int i, io_pg_start, io_pg_count;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+
+ io_pg_start = hp->io_pages_per_kpage * pg_start;
+ io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+ for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+ hp->gatt[i] = agp_bridge.scratch_page;
+ }
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static unsigned long hp_zx1_mask_memory(unsigned long addr, int type)
+{
+ return HP_ZX1_PDIR_VALID_BIT | addr;
+}
+
+static unsigned long hp_zx1_unmask_memory(unsigned long addr)
+{
+ return addr & ~(HP_ZX1_PDIR_VALID_BIT);
+}
+
+int __init hp_zx1_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = hp_zx1_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.size_type = FIXED_APER_SIZE;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = hp_zx1_configure;
+ agp_bridge.fetch_size = hp_zx1_fetch_size;
+ agp_bridge.cleanup = hp_zx1_cleanup;
+ agp_bridge.tlb_flush = hp_zx1_tlbflush;
+ agp_bridge.mask_memory = hp_zx1_mask_memory;
+ agp_bridge.unmask_memory = hp_zx1_unmask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = hp_zx1_create_gatt_table;
+ agp_bridge.free_gatt_table = hp_zx1_free_gatt_table;
+ agp_bridge.insert_memory = hp_zx1_insert_memory;
+ agp_bridge.remove_memory = hp_zx1_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.cant_use_aperture = 1;
+
+ return hp_zx1_ioc_init();
+
+ (void) pdev; /* unused */
+}
+
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
new file mode 100644
index 000000000000..e09f3974ae40
--- /dev/null
+++ b/drivers/char/agp/i460-agp.c
@@ -0,0 +1,595 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+/* BIOS configures the chipset so that one of two apbase registers are used */
+static u8 intel_i460_dynamic_apbase = 0x10;
+
+/* 460 supports multiple GART page sizes, so GART pageshift is dynamic */
+static u8 intel_i460_pageshift = 12;
+static u32 intel_i460_pagesize;
+
+/* Keep track of which is larger, chipset or kernel page size. */
+static u32 intel_i460_cpk = 1;
+
+/* Structure for tracking partial use of 4MB GART pages */
+static u32 **i460_pg_detail = NULL;
+static u32 *i460_pg_count = NULL;
+
+#define I460_CPAGES_PER_KPAGE (PAGE_SIZE >> intel_i460_pageshift)
+#define I460_KPAGES_PER_CPAGE ((1 << intel_i460_pageshift) >> PAGE_SHIFT)
+
+#define I460_SRAM_IO_DISABLE (1 << 4)
+#define I460_BAPBASE_ENABLE (1 << 3)
+#define I460_AGPSIZ_MASK 0x7
+#define I460_4M_PS (1 << 1)
+
+#define log2(x) ffz(~(x))
+
+static inline void intel_i460_read_back (volatile u32 *entry)
+{
+ /*
+ * The 460 spec says we have to read the last location written to
+ * make sure that all writes have taken effect
+ */
+ *entry;
+}
+
+static int intel_i460_fetch_size(void)
+{
+ int i;
+ u8 temp;
+ struct aper_size_info_8 *values;
+
+ /* Determine the GART page size */
+ pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &temp);
+ intel_i460_pageshift = (temp & I460_4M_PS) ? 22 : 12;
+ intel_i460_pagesize = 1UL << intel_i460_pageshift;
+
+ values = A_SIZE_8(agp_bridge.aperture_sizes);
+
+ pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp);
+
+ /* Exit now if the IO drivers for the GART SRAMS are turned off */
+ if (temp & I460_SRAM_IO_DISABLE) {
+ printk(KERN_ERR PFX "GART SRAMS disabled on 460GX chipset\n");
+ printk(KERN_ERR PFX "AGPGART operation not possible\n");
+ return 0;
+ }
+
+ /* Make sure we don't try to create an 2 ^ 23 entry GATT */
+ if ((intel_i460_pageshift == 0) && ((temp & I460_AGPSIZ_MASK) == 4)) {
+ printk(KERN_ERR PFX "We can't have a 32GB aperture with 4KB GART pages\n");
+ return 0;
+ }
+
+ /* Determine the proper APBASE register */
+ if (temp & I460_BAPBASE_ENABLE)
+ intel_i460_dynamic_apbase = INTEL_I460_BAPBASE;
+ else
+ intel_i460_dynamic_apbase = INTEL_I460_APBASE;
+
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ /*
+ * Dynamically calculate the proper num_entries and page_order values for
+ * the define aperture sizes. Take care not to shift off the end of
+ * values[i].size.
+ */
+ values[i].num_entries = (values[i].size << 8) >> (intel_i460_pageshift - 12);
+ values[i].page_order = log2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT);
+ }
+
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ /* Neglect control bits when matching up size_value */
+ if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) {
+ agp_bridge.previous_size = agp_bridge.current_size = (void *) (values + i);
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+
+ return 0;
+}
+
+/* There isn't anything to do here since 460 has no GART TLB. */
+static void intel_i460_tlb_flush(agp_memory * mem)
+{
+ return;
+}
+
+/*
+ * This utility function is needed to prevent corruption of the control bits
+ * which are stored along with the aperture size in 460's AGPSIZ register
+ */
+static void intel_i460_write_agpsiz(u8 size_value)
+{
+ u8 temp;
+
+ pci_read_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ, &temp);
+ pci_write_config_byte(agp_bridge.dev, INTEL_I460_AGPSIZ,
+ ((temp & ~I460_AGPSIZ_MASK) | size_value));
+}
+
+static void intel_i460_cleanup(void)
+{
+ struct aper_size_info_8 *previous_size;
+
+ previous_size = A_SIZE_8(agp_bridge.previous_size);
+ intel_i460_write_agpsiz(previous_size->size_value);
+
+ if (intel_i460_cpk == 0) {
+ vfree(i460_pg_detail);
+ vfree(i460_pg_count);
+ }
+}
+
+
+/* Control bits for Out-Of-GART coherency and Burst Write Combining */
+#define I460_GXBCTL_OOG (1UL << 0)
+#define I460_GXBCTL_BWC (1UL << 2)
+
+static int intel_i460_configure(void)
+{
+ union {
+ u32 small[2];
+ u64 large;
+ } temp;
+ u8 scratch;
+ int i;
+
+ struct aper_size_info_8 *current_size;
+
+ temp.large = 0;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+ intel_i460_write_agpsiz(current_size->size_value);
+
+ /*
+ * Do the necessary rigmarole to read all eight bytes of APBASE.
+ * This has to be done since the AGP aperture can be above 4GB on
+ * 460 based systems.
+ */
+ pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase, &(temp.small[0]));
+ pci_read_config_dword(agp_bridge.dev, intel_i460_dynamic_apbase + 4, &(temp.small[1]));
+
+ /* Clear BAR control bits */
+ agp_bridge.gart_bus_addr = temp.large & ~((1UL << 3) - 1);
+
+ pci_read_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL, &scratch);
+ pci_write_config_byte(agp_bridge.dev, INTEL_I460_GXBCTL,
+ (scratch & 0x02) | I460_GXBCTL_OOG | I460_GXBCTL_BWC);
+
+ /*
+ * Initialize partial allocation trackers if a GART page is bigger than
+ * a kernel page.
+ */
+ if (I460_CPAGES_PER_KPAGE >= 1) {
+ intel_i460_cpk = 1;
+ } else {
+ intel_i460_cpk = 0;
+
+ i460_pg_detail = vmalloc(sizeof(*i460_pg_detail) * current_size->num_entries);
+ i460_pg_count = vmalloc(sizeof(*i460_pg_count) * current_size->num_entries);
+
+ for (i = 0; i < current_size->num_entries; i++) {
+ i460_pg_count[i] = 0;
+ i460_pg_detail[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+static int intel_i460_create_gatt_table(void)
+{
+ char *table;
+ int i;
+ int page_order;
+ int num_entries;
+ void *temp;
+
+ /*
+ * Load up the fixed address of the GART SRAMS which hold our
+ * GATT table.
+ */
+ table = (char *) __va(INTEL_I460_ATTBASE);
+
+ temp = agp_bridge.current_size;
+ page_order = A_SIZE_8(temp)->page_order;
+ num_entries = A_SIZE_8(temp)->num_entries;
+
+ agp_bridge.gatt_table_real = (u32 *) table;
+ agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
+ (PAGE_SIZE * (1 << page_order)));
+ agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real);
+
+ for (i = 0; i < num_entries; i++) {
+ agp_bridge.gatt_table[i] = 0;
+ }
+
+ intel_i460_read_back(agp_bridge.gatt_table + i - 1);
+ return 0;
+}
+
+static int intel_i460_free_gatt_table(void)
+{
+ int num_entries;
+ int i;
+ void *temp;
+
+ temp = agp_bridge.current_size;
+
+ num_entries = A_SIZE_8(temp)->num_entries;
+
+ for (i = 0; i < num_entries; i++) {
+ agp_bridge.gatt_table[i] = 0;
+ }
+
+ intel_i460_read_back(agp_bridge.gatt_table + i - 1);
+
+ iounmap(agp_bridge.gatt_table);
+ return 0;
+}
+
+/* These functions are called when PAGE_SIZE exceeds the GART page size */
+
+static int intel_i460_insert_memory_cpk(agp_memory * mem, off_t pg_start, int type)
+{
+ int i, j, k, num_entries;
+ void *temp;
+ unsigned long paddr;
+
+ /*
+ * The rest of the kernel will compute page offsets in terms of
+ * PAGE_SIZE.
+ */
+ pg_start = I460_CPAGES_PER_KPAGE * pg_start;
+
+ temp = agp_bridge.current_size;
+ num_entries = A_SIZE_8(temp)->num_entries;
+
+ if ((pg_start + I460_CPAGES_PER_KPAGE * mem->page_count) > num_entries) {
+ printk(KERN_ERR PFX "Looks like we're out of AGP memory\n");
+ return -EINVAL;
+ }
+
+ j = pg_start;
+ while (j < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count)) {
+ if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
+ return -EBUSY;
+ }
+ j++;
+ }
+
+#if 0
+ /* not necessary since 460 GART is operated in coherent mode... */
+ if (mem->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ mem->is_flushed = TRUE;
+ }
+#endif
+
+ for (i = 0, j = pg_start; i < mem->page_count; i++) {
+ paddr = mem->memory[i];
+ for (k = 0; k < I460_CPAGES_PER_KPAGE; k++, j++, paddr += intel_i460_pagesize)
+ agp_bridge.gatt_table[j] = (u32) agp_bridge.mask_memory(paddr, mem->type);
+ }
+
+ intel_i460_read_back(agp_bridge.gatt_table + j - 1);
+ return 0;
+}
+
+static int intel_i460_remove_memory_cpk(agp_memory * mem, off_t pg_start, int type)
+{
+ int i;
+
+ pg_start = I460_CPAGES_PER_KPAGE * pg_start;
+
+ for (i = pg_start; i < (pg_start + I460_CPAGES_PER_KPAGE * mem->page_count); i++)
+ agp_bridge.gatt_table[i] = 0;
+
+ intel_i460_read_back(agp_bridge.gatt_table + i - 1);
+ return 0;
+}
+
+/*
+ * These functions are called when the GART page size exceeds PAGE_SIZE.
+ *
+ * This situation is interesting since AGP memory allocations that are
+ * smaller than a single GART page are possible. The structures i460_pg_count
+ * and i460_pg_detail track partial allocation of the large GART pages to
+ * work around this issue.
+ *
+ * i460_pg_count[pg_num] tracks the number of kernel pages in use within
+ * GART page pg_num. i460_pg_detail[pg_num] is an array containing a
+ * psuedo-GART entry for each of the aforementioned kernel pages. The whole
+ * of i460_pg_detail is equivalent to a giant GATT with page size equal to
+ * that of the kernel.
+ */
+
+static void *intel_i460_alloc_large_page(int pg_num)
+{
+ int i;
+ void *bp, *bp_end;
+ struct page *page;
+
+ i460_pg_detail[pg_num] = (void *) vmalloc(sizeof(u32) * I460_KPAGES_PER_CPAGE);
+ if (i460_pg_detail[pg_num] == NULL) {
+ printk(KERN_ERR PFX "Out of memory, we're in trouble...\n");
+ return NULL;
+ }
+
+ for (i = 0; i < I460_KPAGES_PER_CPAGE; i++)
+ i460_pg_detail[pg_num][i] = 0;
+
+ bp = (void *) __get_free_pages(GFP_KERNEL, intel_i460_pageshift - PAGE_SHIFT);
+ if (bp == NULL) {
+ printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n");
+ return NULL;
+ }
+
+ bp_end = bp + ((PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT))) - 1);
+
+ for (page = virt_to_page(bp); page <= virt_to_page(bp_end); page++) {
+ atomic_inc(&agp_bridge.current_memory_agp);
+ }
+ return bp;
+}
+
+static void intel_i460_free_large_page(int pg_num, unsigned long addr)
+{
+ struct page *page;
+ void *bp, *bp_end;
+
+ bp = (void *) __va(addr);
+ bp_end = bp + (PAGE_SIZE * (1 << (intel_i460_pageshift - PAGE_SHIFT)));
+
+ vfree(i460_pg_detail[pg_num]);
+ i460_pg_detail[pg_num] = NULL;
+
+ for (page = virt_to_page(bp); page < virt_to_page(bp_end); page++) {
+ atomic_dec(&agp_bridge.current_memory_agp);
+ }
+
+ free_pages((unsigned long) bp, intel_i460_pageshift - PAGE_SHIFT);
+}
+
+static int intel_i460_insert_memory_kpc(agp_memory * mem, off_t pg_start, int type)
+{
+ int i, pg, start_pg, end_pg, start_offset, end_offset, idx;
+ int num_entries;
+ void *temp;
+ unsigned long paddr;
+
+ temp = agp_bridge.current_size;
+ num_entries = A_SIZE_8(temp)->num_entries;
+
+ /* Figure out what pg_start means in terms of our large GART pages */
+ start_pg = pg_start / I460_KPAGES_PER_CPAGE;
+ start_offset = pg_start % I460_KPAGES_PER_CPAGE;
+ end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE;
+ end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE;
+
+ if (end_pg > num_entries) {
+ printk(KERN_ERR PFX "Looks like we're out of AGP memory\n");
+ return -EINVAL;
+ }
+
+ /* Check if the requested region of the aperture is free */
+ for (pg = start_pg; pg <= end_pg; pg++) {
+ /* Allocate new GART pages if necessary */
+ if (i460_pg_detail[pg] == NULL) {
+ temp = intel_i460_alloc_large_page(pg);
+ if (temp == NULL)
+ return -ENOMEM;
+ agp_bridge.gatt_table[pg] = agp_bridge.mask_memory((unsigned long) temp,
+ 0);
+ intel_i460_read_back(agp_bridge.gatt_table + pg);
+ }
+
+ for (idx = ((pg == start_pg) ? start_offset : 0);
+ idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE);
+ idx++)
+ {
+ if (i460_pg_detail[pg][idx] != 0)
+ return -EBUSY;
+ }
+ }
+
+#if 0
+ /* not necessary since 460 GART is operated in coherent mode... */
+ if (mem->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ mem->is_flushed = TRUE;
+ }
+#endif
+
+ for (pg = start_pg, i = 0; pg <= end_pg; pg++) {
+ paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]);
+ for (idx = ((pg == start_pg) ? start_offset : 0);
+ idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE);
+ idx++, i++)
+ {
+ mem->memory[i] = paddr + (idx * PAGE_SIZE);
+ i460_pg_detail[pg][idx] = agp_bridge.mask_memory(mem->memory[i],
+ mem->type);
+ i460_pg_count[pg]++;
+ }
+ }
+
+ return 0;
+}
+
+static int intel_i460_remove_memory_kpc(agp_memory * mem, off_t pg_start, int type)
+{
+ int i, pg, start_pg, end_pg, start_offset, end_offset, idx;
+ int num_entries;
+ void *temp;
+ unsigned long paddr;
+
+ temp = agp_bridge.current_size;
+ num_entries = A_SIZE_8(temp)->num_entries;
+
+ /* Figure out what pg_start means in terms of our large GART pages */
+ start_pg = pg_start / I460_KPAGES_PER_CPAGE;
+ start_offset = pg_start % I460_KPAGES_PER_CPAGE;
+ end_pg = (pg_start + mem->page_count - 1) / I460_KPAGES_PER_CPAGE;
+ end_offset = (pg_start + mem->page_count - 1) % I460_KPAGES_PER_CPAGE;
+
+ for (i = 0, pg = start_pg; pg <= end_pg; pg++) {
+ for (idx = ((pg == start_pg) ? start_offset : 0);
+ idx < ((pg == end_pg) ? (end_offset + 1) : I460_KPAGES_PER_CPAGE);
+ idx++, i++)
+ {
+ mem->memory[i] = 0;
+ i460_pg_detail[pg][idx] = 0;
+ i460_pg_count[pg]--;
+ }
+
+ /* Free GART pages if they are unused */
+ if (i460_pg_count[pg] == 0) {
+ paddr = agp_bridge.unmask_memory(agp_bridge.gatt_table[pg]);
+ agp_bridge.gatt_table[pg] = agp_bridge.scratch_page;
+ intel_i460_read_back(agp_bridge.gatt_table + pg);
+ intel_i460_free_large_page(pg, paddr);
+ }
+ }
+ return 0;
+}
+
+/* Dummy routines to call the approriate {cpk,kpc} function */
+
+static int intel_i460_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+ if (intel_i460_cpk)
+ return intel_i460_insert_memory_cpk(mem, pg_start, type);
+ else
+ return intel_i460_insert_memory_kpc(mem, pg_start, type);
+}
+
+static int intel_i460_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+ if (intel_i460_cpk)
+ return intel_i460_remove_memory_cpk(mem, pg_start, type);
+ else
+ return intel_i460_remove_memory_kpc(mem, pg_start, type);
+}
+
+/*
+ * If the kernel page size is smaller that the chipset page size, we don't
+ * want to allocate memory until we know where it is to be bound in the
+ * aperture (a multi-kernel-page alloc might fit inside of an already
+ * allocated GART page). Consequently, don't allocate or free anything
+ * if i460_cpk (meaning chipset pages per kernel page) isn't set.
+ *
+ * Let's just hope nobody counts on the allocated AGP memory being there
+ * before bind time (I don't think current drivers do)...
+ */
+static void * intel_i460_alloc_page(void)
+{
+ if (intel_i460_cpk)
+ return agp_generic_alloc_page();
+
+ /* Returning NULL would cause problems */
+ /* AK: really dubious code. */
+ return (void *)~0UL;
+}
+
+static void intel_i460_destroy_page(void *page)
+{
+ if (intel_i460_cpk)
+ agp_generic_destroy_page(page);
+}
+
+static struct gatt_mask intel_i460_masks[] =
+{
+ {
+ mask: INTEL_I460_GATT_VALID | INTEL_I460_GATT_COHERENT,
+ type: 0
+ }
+};
+
+static unsigned long intel_i460_mask_memory(unsigned long addr, int type)
+{
+ /* Make sure the returned address is a valid GATT entry */
+ return (agp_bridge.masks[0].mask
+ | (((addr & ~((1 << intel_i460_pageshift) - 1)) & 0xffffff000) >> 12));
+}
+
+static unsigned long intel_i460_unmask_memory(unsigned long addr)
+{
+ /* Turn a GATT entry into a physical address */
+ return ((addr & 0xffffff) << 12);
+}
+
+static struct aper_size_info_8 intel_i460_sizes[3] =
+{
+ /*
+ * The 32GB aperture is only available with a 4M GART page size.
+ * Due to the dynamic GART page size, we can't figure out page_order
+ * or num_entries until runtime.
+ */
+ {32768, 0, 0, 4},
+ {1024, 0, 0, 2},
+ {256, 0, 0, 1}
+};
+
+int __init intel_i460_setup (struct pci_dev *pdev __attribute__((unused)))
+{
+ agp_bridge.masks = intel_i460_masks;
+ agp_bridge.aperture_sizes = (void *) intel_i460_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 3;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_i460_configure;
+ agp_bridge.fetch_size = intel_i460_fetch_size;
+ agp_bridge.cleanup = intel_i460_cleanup;
+ agp_bridge.tlb_flush = intel_i460_tlb_flush;
+ agp_bridge.mask_memory = intel_i460_mask_memory;
+ agp_bridge.unmask_memory = intel_i460_unmask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = intel_i460_create_gatt_table;
+ agp_bridge.free_gatt_table = intel_i460_free_gatt_table;
+ agp_bridge.insert_memory = intel_i460_insert_memory;
+ agp_bridge.remove_memory = intel_i460_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = intel_i460_alloc_page;
+ agp_bridge.agp_destroy_page = intel_i460_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 1;
+ return 0;
+}
+
diff --git a/drivers/char/agp/i810-agp.c b/drivers/char/agp/i810-agp.c
new file mode 100644
index 000000000000..77d721dfad9c
--- /dev/null
+++ b/drivers/char/agp/i810-agp.c
@@ -0,0 +1,594 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+static struct aper_size_info_fixed intel_i810_sizes[] =
+{
+ {64, 16384, 4},
+ /* The 32M mode still requires a 64k gatt */
+ {32, 8192, 4}
+};
+
+#define AGP_DCACHE_MEMORY 1
+#define AGP_PHYS_MEMORY 2
+
+static struct gatt_mask intel_i810_masks[] =
+{
+ {mask: I810_PTE_VALID, type: 0},
+ {mask: (I810_PTE_VALID | I810_PTE_LOCAL), type: AGP_DCACHE_MEMORY},
+ {mask: I810_PTE_VALID, type: 0}
+};
+
+static struct _intel_i810_private {
+ struct pci_dev *i810_dev; /* device one */
+ volatile u8 *registers;
+ int num_dcache_entries;
+} intel_i810_private;
+
+static int intel_i810_fetch_size(void)
+{
+ u32 smram_miscc;
+ struct aper_size_info_fixed *values;
+
+ pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc);
+ values = A_SIZE_FIX(agp_bridge.aperture_sizes);
+
+ if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
+ printk(KERN_WARNING PFX "i810 is disabled\n");
+ return 0;
+ }
+ if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + 1);
+ agp_bridge.aperture_size_idx = 1;
+ return values[1].size;
+ } else {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values);
+ agp_bridge.aperture_size_idx = 0;
+ return values[0].size;
+ }
+
+ return 0;
+}
+
+static int intel_i810_configure(void)
+{
+ struct aper_size_info_fixed *current_size;
+ u32 temp;
+ int i;
+
+ current_size = A_SIZE_FIX(agp_bridge.current_size);
+
+ pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
+ temp &= 0xfff80000;
+
+ intel_i810_private.registers =
+ (volatile u8 *) ioremap(temp, 128 * 4096);
+
+ if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL)
+ & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
+ /* This will need to be dynamically assigned */
+ printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n");
+ intel_i810_private.num_dcache_entries = 1024;
+ }
+ pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL,
+ agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
+ CACHE_FLUSH();
+
+ if (agp_bridge.needs_scratch_page == TRUE) {
+ for (i = 0; i < current_size->num_entries; i++) {
+ OUTREG32(intel_i810_private.registers,
+ I810_PTE_BASE + (i * 4),
+ agp_bridge.scratch_page);
+ }
+ }
+ return 0;
+}
+
+static void intel_i810_cleanup(void)
+{
+ OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0);
+ iounmap((void *) intel_i810_private.registers);
+}
+
+static void intel_i810_tlbflush(agp_memory * mem)
+{
+ return;
+}
+
+static void intel_i810_agp_enable(u32 mode)
+{
+ return;
+}
+
+static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start,
+ int type)
+{
+ int i, j, num_entries;
+ void *temp;
+
+ temp = agp_bridge.current_size;
+ num_entries = A_SIZE_FIX(temp)->num_entries;
+
+ if ((pg_start + mem->page_count) > num_entries) {
+ return -EINVAL;
+ }
+ for (j = pg_start; j < (pg_start + mem->page_count); j++) {
+ if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
+ return -EBUSY;
+ }
+ }
+
+ if (type != 0 || mem->type != 0) {
+ if ((type == AGP_DCACHE_MEMORY) &&
+ (mem->type == AGP_DCACHE_MEMORY)) {
+ /* special insert */
+ CACHE_FLUSH();
+ for (i = pg_start;
+ i < (pg_start + mem->page_count); i++) {
+ OUTREG32(intel_i810_private.registers,
+ I810_PTE_BASE + (i * 4),
+ (i * 4096) | I810_PTE_LOCAL |
+ I810_PTE_VALID);
+ }
+ CACHE_FLUSH();
+ agp_bridge.tlb_flush(mem);
+ return 0;
+ }
+ if((type == AGP_PHYS_MEMORY) &&
+ (mem->type == AGP_PHYS_MEMORY)) {
+ goto insert;
+ }
+ return -EINVAL;
+ }
+
+insert:
+ CACHE_FLUSH();
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ OUTREG32(intel_i810_private.registers,
+ I810_PTE_BASE + (j * 4), mem->memory[i]);
+ }
+ CACHE_FLUSH();
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start,
+ int type)
+{
+ int i;
+
+ for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+ OUTREG32(intel_i810_private.registers,
+ I810_PTE_BASE + (i * 4),
+ agp_bridge.scratch_page);
+ }
+
+ CACHE_FLUSH();
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
+{
+ agp_memory *new;
+
+ if (type == AGP_DCACHE_MEMORY) {
+ if (pg_count != intel_i810_private.num_dcache_entries) {
+ return NULL;
+ }
+ new = agp_create_memory(1);
+
+ if (new == NULL) {
+ return NULL;
+ }
+ new->type = AGP_DCACHE_MEMORY;
+ new->page_count = pg_count;
+ new->num_scratch_pages = 0;
+ vfree(new->memory);
+ MOD_INC_USE_COUNT;
+ return new;
+ }
+ if(type == AGP_PHYS_MEMORY) {
+ void *addr;
+ /* The I810 requires a physical address to program
+ * it's mouse pointer into hardware. However the
+ * Xserver still writes to it through the agp
+ * aperture
+ */
+ if (pg_count != 1) {
+ return NULL;
+ }
+ new = agp_create_memory(1);
+
+ if (new == NULL) {
+ return NULL;
+ }
+ MOD_INC_USE_COUNT;
+ addr = agp_bridge.agp_alloc_page();
+
+ if (addr == NULL) {
+ /* Free this structure */
+ agp_free_memory(new);
+ return NULL;
+ }
+ new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type);
+ new->page_count = 1;
+ new->num_scratch_pages = 1;
+ new->type = AGP_PHYS_MEMORY;
+ new->physical = virt_to_phys((void *) new->memory[0]);
+ return new;
+ }
+
+ return NULL;
+}
+
+static void intel_i810_free_by_type(agp_memory * curr)
+{
+ agp_free_key(curr->key);
+ if(curr->type == AGP_PHYS_MEMORY) {
+ agp_bridge.agp_destroy_page(
+ phys_to_virt(curr->memory[0]));
+ vfree(curr->memory);
+ }
+ kfree(curr);
+ MOD_DEC_USE_COUNT;
+}
+
+static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
+{
+ /* Type checking must be done elsewhere */
+ return addr | agp_bridge.masks[type].mask;
+}
+
+int __init intel_i810_setup(struct pci_dev *i810_dev)
+{
+ intel_i810_private.i810_dev = i810_dev;
+
+ agp_bridge.masks = intel_i810_masks;
+ agp_bridge.num_of_masks = 2;
+ agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
+ agp_bridge.size_type = FIXED_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 2;
+ agp_bridge.dev_private_data = (void *) &intel_i810_private;
+ agp_bridge.needs_scratch_page = TRUE;
+ agp_bridge.configure = intel_i810_configure;
+ agp_bridge.fetch_size = intel_i810_fetch_size;
+ agp_bridge.cleanup = intel_i810_cleanup;
+ agp_bridge.tlb_flush = intel_i810_tlbflush;
+ agp_bridge.mask_memory = intel_i810_mask_memory;
+ agp_bridge.agp_enable = intel_i810_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = intel_i810_insert_entries;
+ agp_bridge.remove_memory = intel_i810_remove_entries;
+ agp_bridge.alloc_by_type = intel_i810_alloc_by_type;
+ agp_bridge.free_by_type = intel_i810_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+}
+
+static struct aper_size_info_fixed intel_i830_sizes[] =
+{
+ {128, 32768, 5},
+ /* The 64M mode still requires a 128k gatt */
+ {64, 16384, 5}
+};
+
+static struct _intel_i830_private {
+ struct pci_dev *i830_dev; /* device one */
+ volatile u8 *registers;
+ int gtt_entries;
+} intel_i830_private;
+
+static void intel_i830_init_gtt_entries(void)
+{
+ u16 gmch_ctrl;
+ int gtt_entries;
+ u8 rdct;
+ static const int ddt[4] = { 0, 16, 32, 64 };
+
+ pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
+
+ switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ case I830_GMCH_GMS_STOLEN_512:
+ gtt_entries = KB(512) - KB(132);
+ printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
+ break;
+ case I830_GMCH_GMS_STOLEN_1024:
+ gtt_entries = MB(1) - KB(132);
+ printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
+ break;
+ case I830_GMCH_GMS_STOLEN_8192:
+ gtt_entries = MB(8) - KB(132);
+ printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
+ break;
+ case I830_GMCH_GMS_LOCAL:
+ rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE);
+ gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]);
+ printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1));
+ break;
+ default:
+ printk(KERN_INFO PFX "no video memory detected.\n");
+ gtt_entries = 0;
+ break;
+ }
+
+ gtt_entries /= KB(4);
+
+ intel_i830_private.gtt_entries = gtt_entries;
+}
+
+/* The intel i830 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i830_create_gatt_table(void)
+{
+ int page_order;
+ struct aper_size_info_fixed *size;
+ int num_entries;
+ u32 temp;
+
+ size = agp_bridge.current_size;
+ page_order = size->page_order;
+ num_entries = size->num_entries;
+ agp_bridge.gatt_table_real = 0;
+
+ pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
+ temp &= 0xfff80000;
+
+ intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
+ if (!intel_i830_private.registers) return (-ENOMEM);
+
+ temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000;
+ CACHE_FLUSH();
+
+ /* we have to call this as early as possible after the MMIO base address is known */
+ intel_i830_init_gtt_entries();
+
+ agp_bridge.gatt_table = NULL;
+
+ agp_bridge.gatt_bus_addr = temp;
+
+ return(0);
+}
+
+/* Return the gatt table to a sane state. Use the top of stolen
+ * memory for the GTT.
+ */
+static int intel_i830_free_gatt_table(void)
+{
+ return(0);
+}
+
+static int intel_i830_fetch_size(void)
+{
+ u16 gmch_ctrl;
+ struct aper_size_info_fixed *values;
+
+ pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
+ values = A_SIZE_FIX(agp_bridge.aperture_sizes);
+
+ if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
+ agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
+ agp_bridge.aperture_size_idx = 0;
+ return(values[0].size);
+ } else {
+ agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
+ agp_bridge.aperture_size_idx = 1;
+ return(values[1].size);
+ }
+
+ return(0);
+}
+
+static int intel_i830_configure(void)
+{
+ struct aper_size_info_fixed *current_size;
+ u32 temp;
+ u16 gmch_ctrl;
+ int i;
+
+ current_size = A_SIZE_FIX(agp_bridge.current_size);
+
+ pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
+ gmch_ctrl |= I830_GMCH_ENABLED;
+ pci_write_config_word(agp_bridge.dev,I830_GMCH_CTRL,gmch_ctrl);
+
+ OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
+ CACHE_FLUSH();
+
+ if (agp_bridge.needs_scratch_page == TRUE)
+ for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
+ OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+
+ return (0);
+}
+
+static void intel_i830_cleanup(void)
+{
+ iounmap((void *) intel_i830_private.registers);
+}
+
+static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type)
+{
+ int i,j,num_entries;
+ void *temp;
+
+ temp = agp_bridge.current_size;
+ num_entries = A_SIZE_FIX(temp)->num_entries;
+
+ if (pg_start < intel_i830_private.gtt_entries) {
+ printk (KERN_DEBUG "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n",
+ pg_start,intel_i830_private.gtt_entries);
+
+ printk ("Trying to insert into local/stolen memory\n");
+ return (-EINVAL);
+ }
+
+ if ((pg_start + mem->page_count) > num_entries)
+ return (-EINVAL);
+
+ /* The i830 can't check the GTT for entries since its read only,
+ * depend on the caller to make the correct offset decisions.
+ */
+
+ if ((type != 0 && type != AGP_PHYS_MEMORY) ||
+ (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
+ return (-EINVAL);
+
+ CACHE_FLUSH();
+
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
+ OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
+
+ CACHE_FLUSH();
+
+ agp_bridge.tlb_flush(mem);
+
+ return(0);
+}
+
+static int intel_i830_remove_entries(agp_memory *mem,off_t pg_start,int type)
+{
+ int i;
+
+ CACHE_FLUSH ();
+
+ if (pg_start < intel_i830_private.gtt_entries) {
+ printk ("Trying to disable local/stolen memory\n");
+ return (-EINVAL);
+ }
+
+ for (i = pg_start; i < (mem->page_count + pg_start); i++)
+ OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+
+ CACHE_FLUSH();
+
+ agp_bridge.tlb_flush(mem);
+
+ return (0);
+}
+
+static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
+{
+ agp_memory *nw;
+
+ /* always return NULL for now */
+ if (type == AGP_DCACHE_MEMORY) return(NULL);
+
+ if (type == AGP_PHYS_MEMORY) {
+ void *addr;
+
+ /* The i830 requires a physical address to program
+ * it's mouse pointer into hardware. However the
+ * Xserver still writes to it through the agp
+ * aperture
+ */
+
+ if (pg_count != 1) return(NULL);
+
+ nw = agp_create_memory(1);
+
+ if (nw == NULL) return(NULL);
+
+ MOD_INC_USE_COUNT;
+ addr = agp_bridge.agp_alloc_page();
+ if (addr == NULL) {
+ /* free this structure */
+ agp_free_memory(nw);
+ return(NULL);
+ }
+
+ nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type);
+ nw->page_count = 1;
+ nw->num_scratch_pages = 1;
+ nw->type = AGP_PHYS_MEMORY;
+ nw->physical = virt_to_phys(addr);
+ return(nw);
+ }
+
+ return(NULL);
+}
+
+int __init intel_i830_setup(struct pci_dev *i830_dev)
+{
+ intel_i830_private.i830_dev = i830_dev;
+
+ agp_bridge.masks = intel_i810_masks;
+ agp_bridge.num_of_masks = 3;
+ agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
+ agp_bridge.size_type = FIXED_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 2;
+
+ agp_bridge.dev_private_data = (void *) &intel_i830_private;
+ agp_bridge.needs_scratch_page = TRUE;
+
+ agp_bridge.configure = intel_i830_configure;
+ agp_bridge.fetch_size = intel_i830_fetch_size;
+ agp_bridge.cleanup = intel_i830_cleanup;
+ agp_bridge.tlb_flush = intel_i810_tlbflush;
+ agp_bridge.mask_memory = intel_i810_mask_memory;
+ agp_bridge.agp_enable = intel_i810_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+
+ agp_bridge.create_gatt_table = intel_i830_create_gatt_table;
+ agp_bridge.free_gatt_table = intel_i830_free_gatt_table;
+
+ agp_bridge.insert_memory = intel_i830_insert_entries;
+ agp_bridge.remove_memory = intel_i830_remove_entries;
+ agp_bridge.alloc_by_type = intel_i830_alloc_by_type;
+ agp_bridge.free_by_type = intel_i810_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return(0);
+}
+
diff --git a/drivers/char/agp/i8x0-agp.c b/drivers/char/agp/i8x0-agp.c
new file mode 100644
index 000000000000..bf1daf0a69dd
--- /dev/null
+++ b/drivers/char/agp/i8x0-agp.c
@@ -0,0 +1,726 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+
+static int intel_fetch_size(void)
+{
+ int i;
+ u16 temp;
+ struct aper_size_info_16 *values;
+
+ pci_read_config_word(agp_bridge.dev, INTEL_APSIZE, &temp);
+ values = A_SIZE_16(agp_bridge.aperture_sizes);
+
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ if (temp == values[i].size_value) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + i);
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+
+ return 0;
+}
+
+static int intel_8xx_fetch_size(void)
+{
+ int i;
+ u8 temp;
+ struct aper_size_info_8 *values;
+
+ pci_read_config_byte(agp_bridge.dev, INTEL_APSIZE, &temp);
+
+ /* Intel 815 chipsets have a _weird_ APSIZE register with only
+ * one non-reserved bit, so mask the others out ... */
+ if (agp_bridge.type == INTEL_I815)
+ temp &= (1 << 3);
+
+ values = A_SIZE_8(agp_bridge.aperture_sizes);
+
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ if (temp == values[i].size_value) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + i);
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+ return 0;
+}
+
+
+static void intel_tlbflush(agp_memory * mem)
+{
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200);
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280);
+}
+
+
+static void intel_8xx_tlbflush(agp_memory * mem)
+{
+ u32 temp;
+ pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp);
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & ~(1 << 7));
+ pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp);
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp | (1 << 7));
+}
+
+
+static void intel_cleanup(void)
+{
+ u16 temp;
+ struct aper_size_info_16 *previous_size;
+
+ previous_size = A_SIZE_16(agp_bridge.previous_size);
+ pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp);
+ pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9));
+ pci_write_config_word(agp_bridge.dev, INTEL_APSIZE,
+ previous_size->size_value);
+}
+
+
+static void intel_8xx_cleanup(void)
+{
+ u16 temp;
+ struct aper_size_info_8 *previous_size;
+
+ previous_size = A_SIZE_8(agp_bridge.previous_size);
+ pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp);
+ pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9));
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ previous_size->size_value);
+}
+
+
+static int intel_configure(void)
+{
+ u32 temp;
+ u16 temp2;
+ struct aper_size_info_16 *current_size;
+
+ current_size = A_SIZE_16(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_word(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280);
+
+ /* paccfg/nbxcfg */
+ pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2);
+ pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG,
+ (temp2 & ~(1 << 10)) | (1 << 9));
+ /* clear any possible error conditions */
+ pci_write_config_byte(agp_bridge.dev, INTEL_ERRSTS + 1, 7);
+ return 0;
+}
+
+static int intel_815_configure(void)
+{
+ u32 temp, addr;
+ u8 temp2;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ /* the Intel 815 chipset spec. says that bits 29-31 in the
+ * ATTBASE register are reserved -> try not to write them */
+ if (agp_bridge.gatt_bus_addr & INTEL_815_ATTBASE_MASK)
+ panic("gatt bus addr too high");
+ pci_read_config_dword(agp_bridge.dev, INTEL_ATTBASE, &addr);
+ addr &= INTEL_815_ATTBASE_MASK;
+ addr |= agp_bridge.gatt_bus_addr;
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* apcont */
+ pci_read_config_byte(agp_bridge.dev, INTEL_815_APCONT, &temp2);
+ pci_write_config_byte(agp_bridge.dev, INTEL_815_APCONT, temp2 | (1 << 1));
+
+ /* clear any possible error conditions */
+ /* Oddness : this chipset seems to have no ERRSTS register ! */
+ return 0;
+}
+
+static void intel_820_tlbflush(agp_memory * mem)
+{
+ return;
+}
+
+static void intel_820_cleanup(void)
+{
+ u8 temp;
+ struct aper_size_info_8 *previous_size;
+
+ previous_size = A_SIZE_8(agp_bridge.previous_size);
+ pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp);
+ pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR,
+ temp & ~(1 << 1));
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ previous_size->size_value);
+}
+
+
+static int intel_820_configure(void)
+{
+ u32 temp;
+ u8 temp2;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* global enable aperture access */
+ /* This flag is not accessed through MCHCFG register as in */
+ /* i850 chipset. */
+ pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2);
+ pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR,
+ temp2 | (1 << 1));
+ /* clear any possible AGP-related error conditions */
+ pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c);
+ return 0;
+}
+
+static int intel_840_configure(void)
+{
+ u32 temp;
+ u16 temp2;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* mcgcfg */
+ pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2);
+ pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG,
+ temp2 | (1 << 9));
+ /* clear any possible error conditions */
+ pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000);
+ return 0;
+}
+
+static int intel_845_configure(void)
+{
+ u32 temp;
+ u8 temp2;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* agpm */
+ pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2);
+ pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM,
+ temp2 | (1 << 1));
+ /* clear any possible error conditions */
+ pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c);
+ return 0;
+}
+
+static int intel_850_configure(void)
+{
+ u32 temp;
+ u16 temp2;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* mcgcfg */
+ pci_read_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, &temp2);
+ pci_write_config_word(agp_bridge.dev, INTEL_I850_MCHCFG,
+ temp2 | (1 << 9));
+ /* clear any possible AGP-related error conditions */
+ pci_write_config_word(agp_bridge.dev, INTEL_I850_ERRSTS, 0x001c);
+ return 0;
+}
+
+static int intel_860_configure(void)
+{
+ u32 temp;
+ u16 temp2;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* mcgcfg */
+ pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2);
+ pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG,
+ temp2 | (1 << 9));
+ /* clear any possible AGP-related error conditions */
+ pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700);
+ return 0;
+}
+
+static int intel_830mp_configure(void)
+{
+ u32 temp;
+ u16 temp2;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* gmch */
+ pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2);
+ pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG,
+ temp2 | (1 << 9));
+ /* clear any possible AGP-related error conditions */
+ pci_write_config_word(agp_bridge.dev, INTEL_I830_ERRSTS, 0x1c);
+ return 0;
+}
+
+static unsigned long intel_mask_memory(unsigned long addr, int type)
+{
+ /* Memory type is ignored */
+
+ return addr | agp_bridge.masks[0].mask;
+}
+
+static void intel_resume(void)
+{
+ intel_configure();
+}
+
+/* Setup function */
+static struct gatt_mask intel_generic_masks[] =
+{
+ {mask: 0x00000017, type: 0}
+};
+
+static struct aper_size_info_8 intel_815_sizes[2] =
+{
+ {64, 16384, 4, 0},
+ {32, 8192, 3, 8},
+};
+
+static struct aper_size_info_8 intel_8xx_sizes[7] =
+{
+ {256, 65536, 6, 0},
+ {128, 32768, 5, 32},
+ {64, 16384, 4, 48},
+ {32, 8192, 3, 56},
+ {16, 4096, 2, 60},
+ {8, 2048, 1, 62},
+ {4, 1024, 0, 63}
+};
+
+static struct aper_size_info_16 intel_generic_sizes[7] =
+{
+ {256, 65536, 6, 0},
+ {128, 32768, 5, 32},
+ {64, 16384, 4, 48},
+ {32, 8192, 3, 56},
+ {16, 4096, 2, 60},
+ {8, 2048, 1, 62},
+ {4, 1024, 0, 63}
+};
+
+static struct aper_size_info_8 intel_830mp_sizes[4] =
+{
+ {256, 65536, 6, 0},
+ {128, 32768, 5, 32},
+ {64, 16384, 4, 48},
+ {32, 8192, 3, 56}
+};
+
+int __init intel_generic_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
+ agp_bridge.size_type = U16_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_configure;
+ agp_bridge.fetch_size = intel_fetch_size;
+ agp_bridge.cleanup = intel_cleanup;
+ agp_bridge.tlb_flush = intel_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = intel_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
+int __init intel_815_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_815_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 2;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_815_configure;
+ agp_bridge.fetch_size = intel_8xx_fetch_size;
+ agp_bridge.cleanup = intel_8xx_cleanup;
+ agp_bridge.tlb_flush = intel_8xx_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+}
+
+
+int __init intel_820_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_820_configure;
+ agp_bridge.fetch_size = intel_8xx_fetch_size;
+ agp_bridge.cleanup = intel_820_cleanup;
+ agp_bridge.tlb_flush = intel_820_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
+int __init intel_830mp_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 4;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_830mp_configure;
+ agp_bridge.fetch_size = intel_8xx_fetch_size;
+ agp_bridge.cleanup = intel_8xx_cleanup;
+ agp_bridge.tlb_flush = intel_8xx_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
+int __init intel_840_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_840_configure;
+ agp_bridge.fetch_size = intel_8xx_fetch_size;
+ agp_bridge.cleanup = intel_8xx_cleanup;
+ agp_bridge.tlb_flush = intel_8xx_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
+int __init intel_845_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_845_configure;
+ agp_bridge.fetch_size = intel_8xx_fetch_size;
+ agp_bridge.cleanup = intel_8xx_cleanup;
+ agp_bridge.tlb_flush = intel_8xx_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
+int __init intel_850_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_850_configure;
+ agp_bridge.fetch_size = intel_8xx_fetch_size;
+ agp_bridge.cleanup = intel_8xx_cleanup;
+ agp_bridge.tlb_flush = intel_8xx_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
+int __init intel_860_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_860_configure;
+ agp_bridge.fetch_size = intel_8xx_fetch_size;
+ agp_bridge.cleanup = intel_8xx_cleanup;
+ agp_bridge.tlb_flush = intel_8xx_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
new file mode 100644
index 000000000000..841c32a40267
--- /dev/null
+++ b/drivers/char/agp/sis-agp.c
@@ -0,0 +1,142 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+static int sis_fetch_size(void)
+{
+ u8 temp_size;
+ int i;
+ struct aper_size_info_8 *values;
+
+ pci_read_config_byte(agp_bridge.dev, SIS_APSIZE, &temp_size);
+ values = A_SIZE_8(agp_bridge.aperture_sizes);
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ if ((temp_size == values[i].size_value) ||
+ ((temp_size & ~(0x03)) ==
+ (values[i].size_value & ~(0x03)))) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + i);
+
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+
+ return 0;
+}
+
+
+static void sis_tlbflush(agp_memory * mem)
+{
+ pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02);
+}
+
+static int sis_configure(void)
+{
+ u32 temp;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+ pci_write_config_byte(agp_bridge.dev, SIS_TLBCNTRL, 0x05);
+ pci_read_config_dword(agp_bridge.dev, SIS_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(agp_bridge.dev, SIS_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+ pci_write_config_byte(agp_bridge.dev, SIS_APSIZE,
+ current_size->size_value);
+ return 0;
+}
+
+static void sis_cleanup(void)
+{
+ struct aper_size_info_8 *previous_size;
+
+ previous_size = A_SIZE_8(agp_bridge.previous_size);
+ pci_write_config_byte(agp_bridge.dev, SIS_APSIZE,
+ (previous_size->size_value & ~(0x03)));
+}
+
+static unsigned long sis_mask_memory(unsigned long addr, int type)
+{
+ /* Memory type is ignored */
+
+ return addr | agp_bridge.masks[0].mask;
+}
+
+static struct aper_size_info_8 sis_generic_sizes[7] =
+{
+ {256, 65536, 6, 99},
+ {128, 32768, 5, 83},
+ {64, 16384, 4, 67},
+ {32, 8192, 3, 51},
+ {16, 4096, 2, 35},
+ {8, 2048, 1, 19},
+ {4, 1024, 0, 3}
+};
+
+static struct gatt_mask sis_generic_masks[] =
+{
+ {mask: 0x00000000, type: 0}
+};
+
+int __init sis_generic_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = sis_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) sis_generic_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = sis_configure;
+ agp_bridge.fetch_size = sis_fetch_size;
+ agp_bridge.cleanup = sis_cleanup;
+ agp_bridge.tlb_flush = sis_tlbflush;
+ agp_bridge.mask_memory = sis_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+}
+
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
new file mode 100644
index 000000000000..ad9e4c46cc52
--- /dev/null
+++ b/drivers/char/agp/sworks-agp.c
@@ -0,0 +1,626 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+struct serverworks_page_map {
+ unsigned long *real;
+ unsigned long *remapped;
+};
+
+static struct _serverworks_private {
+ struct pci_dev *svrwrks_dev; /* device one */
+ volatile u8 *registers;
+ struct serverworks_page_map **gatt_pages;
+ int num_tables;
+ struct serverworks_page_map scratch_dir;
+
+ int gart_addr_ofs;
+ int mm_addr_ofs;
+} serverworks_private;
+
+static int serverworks_create_page_map(struct serverworks_page_map *page_map)
+{
+ int i;
+
+ page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
+ if (page_map->real == NULL) {
+ return -ENOMEM;
+ }
+ SetPageReserved(virt_to_page(page_map->real));
+ CACHE_FLUSH();
+ page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
+ PAGE_SIZE);
+ if (page_map->remapped == NULL) {
+ ClearPageReserved(virt_to_page(page_map->real));
+ free_page((unsigned long) page_map->real);
+ page_map->real = NULL;
+ return -ENOMEM;
+ }
+ CACHE_FLUSH();
+
+ for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
+ page_map->remapped[i] = agp_bridge.scratch_page;
+ }
+
+ return 0;
+}
+
+static void serverworks_free_page_map(struct serverworks_page_map *page_map)
+{
+ iounmap(page_map->remapped);
+ ClearPageReserved(virt_to_page(page_map->real));
+ free_page((unsigned long) page_map->real);
+}
+
+static void serverworks_free_gatt_pages(void)
+{
+ int i;
+ struct serverworks_page_map **tables;
+ struct serverworks_page_map *entry;
+
+ tables = serverworks_private.gatt_pages;
+ for(i = 0; i < serverworks_private.num_tables; i++) {
+ entry = tables[i];
+ if (entry != NULL) {
+ if (entry->real != NULL) {
+ serverworks_free_page_map(entry);
+ }
+ kfree(entry);
+ }
+ }
+ kfree(tables);
+}
+
+static int serverworks_create_gatt_pages(int nr_tables)
+{
+ struct serverworks_page_map **tables;
+ struct serverworks_page_map *entry;
+ int retval = 0;
+ int i;
+
+ tables = kmalloc((nr_tables + 1) * sizeof(struct serverworks_page_map *),
+ GFP_KERNEL);
+ if (tables == NULL) {
+ return -ENOMEM;
+ }
+ memset(tables, 0, sizeof(struct serverworks_page_map *) * (nr_tables + 1));
+ for (i = 0; i < nr_tables; i++) {
+ entry = kmalloc(sizeof(struct serverworks_page_map), GFP_KERNEL);
+ if (entry == NULL) {
+ retval = -ENOMEM;
+ break;
+ }
+ memset(entry, 0, sizeof(struct serverworks_page_map));
+ tables[i] = entry;
+ retval = serverworks_create_page_map(entry);
+ if (retval != 0) break;
+ }
+ serverworks_private.num_tables = nr_tables;
+ serverworks_private.gatt_pages = tables;
+
+ if (retval != 0) serverworks_free_gatt_pages();
+
+ return retval;
+}
+
+#define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\
+ GET_PAGE_DIR_IDX(addr)]->remapped)
+
+#ifndef GET_PAGE_DIR_OFF
+#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
+#endif
+
+#ifndef GET_PAGE_DIR_IDX
+#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
+ GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr))
+#endif
+
+#ifndef GET_GATT_OFF
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
+#endif
+
+static int serverworks_create_gatt_table(void)
+{
+ struct aper_size_info_lvl2 *value;
+ struct serverworks_page_map page_dir;
+ int retval;
+ u32 temp;
+ int i;
+
+ value = A_SIZE_LVL2(agp_bridge.current_size);
+ retval = serverworks_create_page_map(&page_dir);
+ if (retval != 0) {
+ return retval;
+ }
+ retval = serverworks_create_page_map(&serverworks_private.scratch_dir);
+ if (retval != 0) {
+ serverworks_free_page_map(&page_dir);
+ return retval;
+ }
+ /* Create a fake scratch directory */
+ for(i = 0; i < 1024; i++) {
+ serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge.scratch_page;
+ page_dir.remapped[i] =
+ virt_to_phys(serverworks_private.scratch_dir.real);
+ page_dir.remapped[i] |= 0x00000001;
+ }
+
+ retval = serverworks_create_gatt_pages(value->num_entries / 1024);
+ if (retval != 0) {
+ serverworks_free_page_map(&page_dir);
+ serverworks_free_page_map(&serverworks_private.scratch_dir);
+ return retval;
+ }
+
+ agp_bridge.gatt_table_real = page_dir.real;
+ agp_bridge.gatt_table = page_dir.remapped;
+ agp_bridge.gatt_bus_addr = virt_to_phys(page_dir.real);
+
+ /* Get the address for the gart region.
+ * This is a bus address even on the alpha, b/c its
+ * used to program the agp master not the cpu
+ */
+
+ pci_read_config_dword(agp_bridge.dev,
+ serverworks_private.gart_addr_ofs,
+ &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* Calculate the agp offset */
+
+ for(i = 0; i < value->num_entries / 1024; i++) {
+ page_dir.remapped[i] =
+ virt_to_phys(serverworks_private.gatt_pages[i]->real);
+ page_dir.remapped[i] |= 0x00000001;
+ }
+
+ return 0;
+}
+
+static int serverworks_free_gatt_table(void)
+{
+ struct serverworks_page_map page_dir;
+
+ page_dir.real = agp_bridge.gatt_table_real;
+ page_dir.remapped = agp_bridge.gatt_table;
+
+ serverworks_free_gatt_pages();
+ serverworks_free_page_map(&page_dir);
+ serverworks_free_page_map(&serverworks_private.scratch_dir);
+ return 0;
+}
+
+static int serverworks_fetch_size(void)
+{
+ int i;
+ u32 temp;
+ u32 temp2;
+ struct aper_size_info_lvl2 *values;
+
+ values = A_SIZE_LVL2(agp_bridge.aperture_sizes);
+ pci_read_config_dword(agp_bridge.dev,
+ serverworks_private.gart_addr_ofs,
+ &temp);
+ pci_write_config_dword(agp_bridge.dev,
+ serverworks_private.gart_addr_ofs,
+ SVWRKS_SIZE_MASK);
+ pci_read_config_dword(agp_bridge.dev,
+ serverworks_private.gart_addr_ofs,
+ &temp2);
+ pci_write_config_dword(agp_bridge.dev,
+ serverworks_private.gart_addr_ofs,
+ temp);
+ temp2 &= SVWRKS_SIZE_MASK;
+
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ if (temp2 == values[i].size_value) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + i);
+
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+
+ return 0;
+}
+
+static int serverworks_configure(void)
+{
+ struct aper_size_info_lvl2 *current_size;
+ u32 temp;
+ u8 enable_reg;
+ u8 cap_ptr;
+ u32 cap_id;
+ u16 cap_reg;
+
+ current_size = A_SIZE_LVL2(agp_bridge.current_size);
+
+ /* Get the memory mapped registers */
+ pci_read_config_dword(agp_bridge.dev,
+ serverworks_private.mm_addr_ofs,
+ &temp);
+ temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096);
+
+ OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a);
+
+ OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND);
+ cap_reg &= ~0x0007;
+ cap_reg |= 0x4;
+ OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg);
+
+ pci_read_config_byte(serverworks_private.svrwrks_dev,
+ SVWRKS_AGP_ENABLE, &enable_reg);
+ enable_reg |= 0x1; /* Agp Enable bit */
+ pci_write_config_byte(serverworks_private.svrwrks_dev,
+ SVWRKS_AGP_ENABLE, enable_reg);
+ agp_bridge.tlb_flush(NULL);
+
+ pci_read_config_byte(serverworks_private.svrwrks_dev, 0x34, &cap_ptr);
+ if (cap_ptr != 0x00) {
+ do {
+ pci_read_config_dword(serverworks_private.svrwrks_dev,
+ cap_ptr, &cap_id);
+
+ if ((cap_id & 0xff) != 0x02)
+ cap_ptr = (cap_id >> 8) & 0xff;
+ }
+ while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
+ }
+ agp_bridge.capndx = cap_ptr;
+
+ /* Fill in the mode register */
+ pci_read_config_dword(serverworks_private.svrwrks_dev,
+ agp_bridge.capndx + 4,
+ &agp_bridge.mode);
+
+ pci_read_config_byte(agp_bridge.dev,
+ SVWRKS_CACHING,
+ &enable_reg);
+ enable_reg &= ~0x3;
+ pci_write_config_byte(agp_bridge.dev,
+ SVWRKS_CACHING,
+ enable_reg);
+
+ pci_read_config_byte(agp_bridge.dev,
+ SVWRKS_FEATURE,
+ &enable_reg);
+ enable_reg |= (1<<6);
+ pci_write_config_byte(agp_bridge.dev,
+ SVWRKS_FEATURE,
+ enable_reg);
+
+ return 0;
+}
+
+static void serverworks_cleanup(void)
+{
+ iounmap((void *) serverworks_private.registers);
+}
+
+/*
+ * This routine could be implemented by taking the addresses
+ * written to the GATT, and flushing them individually. However
+ * currently it just flushes the whole table. Which is probably
+ * more efficent, since agp_memory blocks can be a large number of
+ * entries.
+ */
+
+static void serverworks_tlbflush(agp_memory * temp)
+{
+ unsigned long end;
+
+ OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01);
+ end = jiffies + 3*HZ;
+ while(INREG8(serverworks_private.registers,
+ SVWRKS_POSTFLUSH) == 0x01) {
+ if((signed)(end - jiffies) <= 0) {
+ printk(KERN_ERR "Posted write buffer flush took more"
+ "then 3 seconds\n");
+ }
+ }
+ OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001);
+ end = jiffies + 3*HZ;
+ while(INREG32(serverworks_private.registers,
+ SVWRKS_DIRFLUSH) == 0x00000001) {
+ if((signed)(end - jiffies) <= 0) {
+ printk(KERN_ERR "TLB flush took more"
+ "then 3 seconds\n");
+ }
+ }
+}
+
+static unsigned long serverworks_mask_memory(unsigned long addr, int type)
+{
+ /* Only type 0 is supported by the serverworks chipsets */
+
+ return addr | agp_bridge.masks[0].mask;
+}
+
+static int serverworks_insert_memory(agp_memory * mem,
+ off_t pg_start, int type)
+{
+ int i, j, num_entries;
+ unsigned long *cur_gatt;
+ unsigned long addr;
+
+ num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+ if ((pg_start + mem->page_count) > num_entries) {
+ return -EINVAL;
+ }
+
+ j = pg_start;
+ while (j < (pg_start + mem->page_count)) {
+ addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = SVRWRKS_GET_GATT(addr);
+ if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
+ return -EBUSY;
+ }
+ j++;
+ }
+
+ if (mem->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ mem->is_flushed = TRUE;
+ }
+
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = SVRWRKS_GET_GATT(addr);
+ cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+ }
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static int serverworks_remove_memory(agp_memory * mem, off_t pg_start,
+ int type)
+{
+ int i;
+ unsigned long *cur_gatt;
+ unsigned long addr;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+
+ CACHE_FLUSH();
+ agp_bridge.tlb_flush(mem);
+
+ for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+ addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = SVRWRKS_GET_GATT(addr);
+ cur_gatt[GET_GATT_OFF(addr)] =
+ (unsigned long) agp_bridge.scratch_page;
+ }
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static struct gatt_mask serverworks_masks[] =
+{
+ {mask: 0x00000001, type: 0}
+};
+
+static struct aper_size_info_lvl2 serverworks_sizes[7] =
+{
+ {2048, 524288, 0x80000000},
+ {1024, 262144, 0xc0000000},
+ {512, 131072, 0xe0000000},
+ {256, 65536, 0xf0000000},
+ {128, 32768, 0xf8000000},
+ {64, 16384, 0xfc000000},
+ {32, 8192, 0xfe000000}
+};
+
+static void serverworks_agp_enable(u32 mode)
+{
+ struct pci_dev *device = NULL;
+ u32 command, scratch, cap_id;
+ u8 cap_ptr;
+
+ pci_read_config_dword(serverworks_private.svrwrks_dev,
+ agp_bridge.capndx + 4,
+ &command);
+
+ /*
+ * PASS1: go throu all devices that claim to be
+ * AGP devices and collect their data.
+ */
+
+
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+ if (cap_ptr != 0x00) {
+ do {
+ pci_read_config_dword(device,
+ cap_ptr, &cap_id);
+
+ if ((cap_id & 0xff) != 0x02)
+ cap_ptr = (cap_id >> 8) & 0xff;
+ }
+ while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
+ }
+ if (cap_ptr != 0x00) {
+ /*
+ * Ok, here we have a AGP device. Disable impossible
+ * settings, and adjust the readqueue to the minimum.
+ */
+
+ pci_read_config_dword(device, cap_ptr + 4, &scratch);
+
+ /* adjust RQ depth */
+ command =
+ ((command & ~0xff000000) |
+ min_t(u32, (mode & 0xff000000),
+ min_t(u32, (command & 0xff000000),
+ (scratch & 0xff000000))));
+
+ /* disable SBA if it's not supported */
+ if (!((command & 0x00000200) &&
+ (scratch & 0x00000200) &&
+ (mode & 0x00000200)))
+ command &= ~0x00000200;
+
+ /* disable FW */
+ command &= ~0x00000010;
+
+ command &= ~0x00000008;
+
+ if (!((command & 4) &&
+ (scratch & 4) &&
+ (mode & 4)))
+ command &= ~0x00000004;
+
+ if (!((command & 2) &&
+ (scratch & 2) &&
+ (mode & 2)))
+ command &= ~0x00000002;
+
+ if (!((command & 1) &&
+ (scratch & 1) &&
+ (mode & 1)))
+ command &= ~0x00000001;
+ }
+ }
+ /*
+ * PASS2: Figure out the 4X/2X/1X setting and enable the
+ * target (our motherboard chipset).
+ */
+
+ if (command & 4) {
+ command &= ~3; /* 4X */
+ }
+ if (command & 2) {
+ command &= ~5; /* 2X */
+ }
+ if (command & 1) {
+ command &= ~6; /* 1X */
+ }
+ command |= 0x00000100;
+
+ pci_write_config_dword(serverworks_private.svrwrks_dev,
+ agp_bridge.capndx + 8,
+ command);
+
+ /*
+ * PASS3: Go throu all AGP devices and update the
+ * command registers.
+ */
+
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+ if (cap_ptr != 0x00)
+ pci_write_config_dword(device, cap_ptr + 8, command);
+ }
+}
+
+int __init serverworks_setup (struct pci_dev *pdev)
+{
+ u32 temp;
+ u32 temp2;
+
+ serverworks_private.svrwrks_dev = pdev;
+
+ agp_bridge.masks = serverworks_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) serverworks_sizes;
+ agp_bridge.size_type = LVL2_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = (void *) &serverworks_private;
+ agp_bridge.needs_scratch_page = TRUE;
+ agp_bridge.configure = serverworks_configure;
+ agp_bridge.fetch_size = serverworks_fetch_size;
+ agp_bridge.cleanup = serverworks_cleanup;
+ agp_bridge.tlb_flush = serverworks_tlbflush;
+ agp_bridge.mask_memory = serverworks_mask_memory;
+ agp_bridge.agp_enable = serverworks_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = serverworks_create_gatt_table;
+ agp_bridge.free_gatt_table = serverworks_free_gatt_table;
+ agp_bridge.insert_memory = serverworks_insert_memory;
+ agp_bridge.remove_memory = serverworks_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ pci_read_config_dword(agp_bridge.dev,
+ SVWRKS_APSIZE,
+ &temp);
+
+ serverworks_private.gart_addr_ofs = 0x10;
+
+ if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ pci_read_config_dword(agp_bridge.dev,
+ SVWRKS_APSIZE + 4,
+ &temp2);
+ if(temp2 != 0) {
+ printk("Detected 64 bit aperture address, but top "
+ "bits are not zero. Disabling agp\n");
+ return -ENODEV;
+ }
+ serverworks_private.mm_addr_ofs = 0x18;
+ } else {
+ serverworks_private.mm_addr_ofs = 0x14;
+ }
+
+ pci_read_config_dword(agp_bridge.dev,
+ serverworks_private.mm_addr_ofs,
+ &temp);
+ if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ pci_read_config_dword(agp_bridge.dev,
+ serverworks_private.mm_addr_ofs + 4,
+ &temp2);
+ if(temp2 != 0) {
+ printk("Detected 64 bit MMIO address, but top "
+ "bits are not zero. Disabling agp\n");
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
new file mode 100644
index 000000000000..5facf9f64062
--- /dev/null
+++ b/drivers/char/agp/via-agp.c
@@ -0,0 +1,151 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * TODO:
+ * - Allocate more than order 0 pages to avoid too much linear map splitting.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+
+static int via_fetch_size(void)
+{
+ int i;
+ u8 temp;
+ struct aper_size_info_8 *values;
+
+ values = A_SIZE_8(agp_bridge.aperture_sizes);
+ pci_read_config_byte(agp_bridge.dev, VIA_APSIZE, &temp);
+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+ if (temp == values[i].size_value) {
+ agp_bridge.previous_size =
+ agp_bridge.current_size = (void *) (values + i);
+ agp_bridge.aperture_size_idx = i;
+ return values[i].size;
+ }
+ }
+
+ return 0;
+}
+
+static int via_configure(void)
+{
+ u32 temp;
+ struct aper_size_info_8 *current_size;
+
+ current_size = A_SIZE_8(agp_bridge.current_size);
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, VIA_APSIZE,
+ current_size->size_value);
+ /* address to map too */
+ pci_read_config_dword(agp_bridge.dev, VIA_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* GART control register */
+ pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f);
+
+ /* attbase - aperture GATT base */
+ pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE,
+ (agp_bridge.gatt_bus_addr & 0xfffff000) | 3);
+ return 0;
+}
+
+static void via_cleanup(void)
+{
+ struct aper_size_info_8 *previous_size;
+
+ previous_size = A_SIZE_8(agp_bridge.previous_size);
+ pci_write_config_byte(agp_bridge.dev, VIA_APSIZE,
+ previous_size->size_value);
+ /* Do not disable by writing 0 to VIA_ATTBASE, it screws things up
+ * during reinitialization.
+ */
+}
+
+static void via_tlbflush(agp_memory * mem)
+{
+ pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000008f);
+ pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f);
+}
+
+static unsigned long via_mask_memory(unsigned long addr, int type)
+{
+ /* Memory type is ignored */
+
+ return addr | agp_bridge.masks[0].mask;
+}
+
+static struct aper_size_info_8 via_generic_sizes[7] =
+{
+ {256, 65536, 6, 0},
+ {128, 32768, 5, 128},
+ {64, 16384, 4, 192},
+ {32, 8192, 3, 224},
+ {16, 4096, 2, 240},
+ {8, 2048, 1, 248},
+ {4, 1024, 0, 252}
+};
+
+static struct gatt_mask via_generic_masks[] =
+{
+ {mask: 0x00000000, type: 0}
+};
+
+int __init via_generic_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = via_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) via_generic_sizes;
+ agp_bridge.size_type = U8_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = via_configure;
+ agp_bridge.fetch_size = via_fetch_size;
+ agp_bridge.cleanup = via_cleanup;
+ agp_bridge.tlb_flush = via_tlbflush;
+ agp_bridge.mask_memory = via_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index d748d499da60..7cf8fb5cfcb5 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -807,7 +807,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
I_PARMRK(tty)) {
- cli();
+ __cli(); // FIXME: is this safe?
memset(tty->process_char_map, 0, 256/8);
if (I_IGNCR(tty) || I_ICRNL(tty))
@@ -843,7 +843,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
set_bit(SUSP_CHAR(tty), tty->process_char_map);
}
clear_bit(__DISABLED_CHAR, tty->process_char_map);
- sti();
+ __sti(); // FIXME: is this safe?
tty->raw = 0;
tty->real_raw = 0;
} else {
diff --git a/drivers/char/pcmcia/Config.in b/drivers/char/pcmcia/Config.in
index 5905bd307d97..e44fa2a25ec8 100644
--- a/drivers/char/pcmcia/Config.in
+++ b/drivers/char/pcmcia/Config.in
@@ -5,7 +5,6 @@
mainmenu_option next_comment
comment 'PCMCIA character devices'
-dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA $CONFIG_SERIAL
dep_tristate 'SyncLink PC Card support' CONFIG_SYNCLINK_CS $CONFIG_PCMCIA
endmenu
diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile
index 0b499b55814b..a1db3f706121 100644
--- a/drivers/char/pcmcia/Makefile
+++ b/drivers/char/pcmcia/Makefile
@@ -4,7 +4,6 @@
# Makefile for the Linux PCMCIA char device drivers.
#
-obj-$(CONFIG_PCMCIA_SERIAL_CS) += serial_cs.o
obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/char/pcmcia/serial_cs.c b/drivers/char/pcmcia/serial_cs.c
deleted file mode 100644
index 892f2c832a9e..000000000000
--- a/drivers/char/pcmcia/serial_cs.c
+++ /dev/null
@@ -1,667 +0,0 @@
-/*======================================================================
-
- A driver for PCMCIA serial devices
-
- serial_cs.c 1.123 2000/08/24 18:46:38
-
- The contents of this file are subject to the Mozilla Public
- License Version 1.1 (the "License"); you may not use this file
- except in compliance with the License. You may obtain a copy of
- the License at http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS
- IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- implied. See the License for the specific language governing
- rights and limitations under the License.
-
- The initial developer of the original code is David A. Hinds
- <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-
- Alternatively, the contents of this file may be used under the
- terms of the GNU General Public License version 2 (the "GPL"), in which
- case the provisions of the GPL are applicable instead of the
- above. If you wish to allow the use of your version of this file
- only under the terms of the GPL and not to allow others to use
- your version of this file under the MPL, indicate your decision
- by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the MPL or the GPL.
-
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
-static int irq_list[4] = { -1 };
-
-/* Enable the speaker? */
-static int do_sound = 1;
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(do_sound, "i");
-
-/*====================================================================*/
-
-/* Table of multi-port card ID's */
-
-typedef struct {
- u_short manfid;
- u_short prodid;
- int multi; /* 1 = multifunction, > 1 = # ports */
-} multi_id_t;
-
-static multi_id_t multi_id[] = {
- { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
- { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
- { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
- { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
-};
-#define MULTI_COUNT (sizeof(multi_id)/sizeof(multi_id_t))
-
-typedef struct serial_info_t {
- dev_link_t link;
- int ndev;
- int multi;
- int slave;
- int manfid;
- dev_node_t node[4];
- int line[4];
-} serial_info_t;
-
-static void serial_config(dev_link_t *link);
-static void serial_release(u_long arg);
-static int serial_event(event_t event, int priority,
- event_callback_args_t *args);
-
-static dev_info_t dev_info = "serial_cs";
-
-static dev_link_t *serial_attach(void);
-static void serial_detach(dev_link_t *);
-
-static dev_link_t *dev_list = NULL;
-
-/*====================================================================*/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
- error_info_t err = { func, ret };
- CardServices(ReportError, handle, &err);
-}
-
-/*======================================================================
-
- serial_attach() creates an "instance" of the driver, allocating
- local data structures for one device. The device is registered
- with Card Services.
-
-======================================================================*/
-
-static dev_link_t *serial_attach(void)
-{
- serial_info_t *info;
- client_reg_t client_reg;
- dev_link_t *link;
- int i, ret;
-
- DEBUG(0, "serial_attach()\n");
-
- /* Create new serial device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) return NULL;
- memset(info, 0, sizeof(*info));
- link = &info->link; link->priv = info;
-
- link->release.function = &serial_release;
- link->release.data = (u_long)link;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 8;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
- link->irq.IRQInfo2 = irq_mask;
- else
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
- link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Vcc = 50;
- if (do_sound) {
- link->conf.Attributes |= CONF_ENABLE_SPKR;
- link->conf.Status = CCSR_AUDIO_ENA;
- }
- link->conf.IntType = INT_MEMORY_AND_IO;
-
- /* Register with Card Services */
- link->next = dev_list;
- dev_list = link;
- client_reg.dev_info = &dev_info;
- client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &serial_event;
- client_reg.Version = 0x0210;
- client_reg.event_callback_args.client_data = link;
- ret = CardServices(RegisterClient, &link->handle, &client_reg);
- if (ret != CS_SUCCESS) {
- cs_error(link->handle, RegisterClient, ret);
- serial_detach(link);
- return NULL;
- }
-
- return link;
-} /* serial_attach */
-
-/*======================================================================
-
- This deletes a driver "instance". The device is de-registered
- with Card Services. If it has been released, all local data
- structures are freed. Otherwise, the structures will be freed
- when the device is released.
-
-======================================================================*/
-
-static void serial_detach(dev_link_t *link)
-{
- serial_info_t *info = link->priv;
- dev_link_t **linkp;
- int ret;
-
- DEBUG(0, "serial_detach(0x%p)\n", link);
-
- /* Locate device structure */
- for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
- if (*linkp == link) break;
- if (*linkp == NULL)
- return;
-
- del_timer(&link->release);
- if (link->state & DEV_CONFIG)
- serial_release((u_long)link);
-
- if (link->handle) {
- ret = CardServices(DeregisterClient, link->handle);
- if (ret != CS_SUCCESS)
- cs_error(link->handle, DeregisterClient, ret);
- }
-
- /* Unlink device structure, free bits */
- *linkp = link->next;
- kfree(info);
-
-} /* serial_detach */
-
-/*====================================================================*/
-
-static int setup_serial(serial_info_t *info, ioaddr_t port, int irq)
-{
- struct serial_struct serial;
- int line;
-
- memset(&serial, 0, sizeof(serial));
- serial.port = port;
- serial.irq = irq;
- serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
- line = register_serial(&serial);
- if (line < 0) {
- printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
- " irq %d failed\n", (u_long)serial.port, serial.irq);
- return -1;
- }
-
- info->line[info->ndev] = line;
- sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
- info->node[info->ndev].major = TTY_MAJOR;
- info->node[info->ndev].minor = 0x40+line;
- if (info->ndev > 0)
- info->node[info->ndev-1].next = &info->node[info->ndev];
- info->ndev++;
-
- return 0;
-}
-
-/*====================================================================*/
-
-static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
- cisparse_t *parse)
-{
- int i;
- i = CardServices(fn, handle, tuple);
- if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS;
- i = CardServices(GetTupleData, handle, tuple);
- if (i != CS_SUCCESS) return i;
- return CardServices(ParseTuple, handle, tuple, parse);
-}
-
-#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-
-/*====================================================================*/
-
-static int simple_config(dev_link_t *link)
-{
- static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
- client_handle_t handle = link->handle;
- serial_info_t *info = link->priv;
- tuple_t tuple;
- u_char buf[256];
- cisparse_t parse;
- cistpl_cftable_entry_t *cf = &parse.cftable_entry;
- config_info_t config;
- int i, j, try;
-
- /* If the card is already configured, look up the port and irq */
- i = CardServices(GetConfigurationInfo, handle, &config);
- if ((i == CS_SUCCESS) &&
- (config.Attributes & CONF_VALID_CLIENT)) {
- ioaddr_t port = 0;
- if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
- port = config.BasePort2;
- info->slave = 1;
- } else if ((info->manfid == MANFID_OSITECH) &&
- (config.NumPorts1 == 0x40)) {
- port = config.BasePort1 + 0x28;
- info->slave = 1;
- }
- if (info->slave)
- return setup_serial(info, port, config.AssignedIRQ);
- }
- link->conf.Vcc = config.Vcc;
-
- /* First pass: look for a config entry that looks normal. */
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
- tuple.Attributes = 0;
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- /* Two tries: without IO aliases, then with aliases */
- for (try = 0; try < 2; try++) {
- i = first_tuple(handle, &tuple, &parse);
- while (i != CS_NO_MORE_ITEMS) {
- if (i != CS_SUCCESS) goto next_entry;
- if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM))
- link->conf.Vpp1 = link->conf.Vpp2 =
- cf->vpp1.param[CISTPL_POWER_VNOM]/10000;
- if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
- (cf->io.win[0].base != 0)) {
- link->conf.ConfigIndex = cf->index;
- link->io.BasePort1 = cf->io.win[0].base;
- link->io.IOAddrLines = (try == 0) ?
- 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
- i = CardServices(RequestIO, link->handle, &link->io);
- if (i == CS_SUCCESS) goto found_port;
- }
- next_entry:
- i = next_tuple(handle, &tuple, &parse);
- }
- }
-
- /* Second pass: try to find an entry that isn't picky about
- its base address, then try to grab any standard serial port
- address, and finally try to get any free port. */
- i = first_tuple(handle, &tuple, &parse);
- while (i != CS_NO_MORE_ITEMS) {
- if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
- ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
- link->conf.ConfigIndex = cf->index;
- for (j = 0; j < 5; j++) {
- link->io.BasePort1 = base[j];
- link->io.IOAddrLines = base[j] ? 16 : 3;
- i = CardServices(RequestIO, link->handle,
- &link->io);
- if (i == CS_SUCCESS) goto found_port;
- }
- }
- i = next_tuple(handle, &tuple, &parse);
- }
-
-found_port:
- if (i != CS_SUCCESS) {
- printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n");
- cs_error(link->handle, RequestIO, i);
- return -1;
- }
-
- i = CardServices(RequestIRQ, link->handle, &link->irq);
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIRQ, i);
- link->irq.AssignedIRQ = 0;
- }
- if (info->multi && (info->manfid == MANFID_3COM))
- link->conf.ConfigIndex &= ~(0x08);
- i = CardServices(RequestConfiguration, link->handle, &link->conf);
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestConfiguration, i);
- return -1;
- }
-
- return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
-}
-
-static int multi_config(dev_link_t *link)
-{
- client_handle_t handle = link->handle;
- serial_info_t *info = link->priv;
- tuple_t tuple;
- u_char buf[256];
- cisparse_t parse;
- cistpl_cftable_entry_t *cf = &parse.cftable_entry;
- int i, base2 = 0;
-
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
- tuple.Attributes = 0;
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
- /* First, look for a generic full-sized window */
- link->io.NumPorts1 = info->multi * 8;
- i = first_tuple(handle, &tuple, &parse);
- while (i != CS_NO_MORE_ITEMS) {
- /* The quad port cards have bad CIS's, so just look for a
- window larger than 8 ports and assume it will be right */
- if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
- (cf->io.win[0].len > 8)) {
- link->conf.ConfigIndex = cf->index;
- link->io.BasePort1 = cf->io.win[0].base;
- link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
- i = CardServices(RequestIO, link->handle, &link->io);
- base2 = link->io.BasePort1 + 8;
- if (i == CS_SUCCESS) break;
- }
- i = next_tuple(handle, &tuple, &parse);
- }
-
- /* If that didn't work, look for two windows */
- if (i != CS_SUCCESS) {
- link->io.NumPorts1 = link->io.NumPorts2 = 8;
- info->multi = 2;
- i = first_tuple(handle, &tuple, &parse);
- while (i != CS_NO_MORE_ITEMS) {
- if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
- link->conf.ConfigIndex = cf->index;
- link->io.BasePort1 = cf->io.win[0].base;
- link->io.BasePort2 = cf->io.win[1].base;
- link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
- i = CardServices(RequestIO, link->handle, &link->io);
- base2 = link->io.BasePort2;
- if (i == CS_SUCCESS) break;
- }
- i = next_tuple(handle, &tuple, &parse);
- }
- }
-
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIO, i);
- return -1;
- }
-
- i = CardServices(RequestIRQ, link->handle, &link->irq);
- if (i != CS_SUCCESS) {
- printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n");
- cs_error(link->handle, RequestIRQ, i);
- link->irq.AssignedIRQ = 0;
- }
- /* Socket Dual IO: this enables irq's for second port */
- if (info->multi && (info->manfid == MANFID_SOCKET)) {
- link->conf.Present |= PRESENT_EXT_STATUS;
- link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
- }
- i = CardServices(RequestConfiguration, link->handle, &link->conf);
- if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestConfiguration, i);
- return -1;
- }
-
- setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
- /* The Nokia cards are not really multiport cards */
- if (info->manfid == MANFID_NOKIA)
- return 0;
- for (i = 0; i < info->multi-1; i++)
- setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
-
- return 0;
-}
-
-/*======================================================================
-
- serial_config() is scheduled to run after a CARD_INSERTION event
- is received, to configure the PCMCIA socket, and to make the
- serial device available to the system.
-
-======================================================================*/
-
-#define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
-
-void serial_config(dev_link_t *link)
-{
- client_handle_t handle = link->handle;
- serial_info_t *info = link->priv;
- tuple_t tuple;
- u_short buf[128];
- cisparse_t parse;
- cistpl_cftable_entry_t *cf = &parse.cftable_entry;
- int i, last_ret, last_fn;
-
- DEBUG(0, "serial_config(0x%p)\n", link);
-
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
- tuple.Attributes = 0;
- /* Get configuration register information */
- tuple.DesiredTuple = CISTPL_CONFIG;
- last_ret = first_tuple(handle, &tuple, &parse);
- if (last_ret != CS_SUCCESS) {
- last_fn = ParseTuple;
- goto cs_failed;
- }
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
-
- /* Configure card */
- link->state |= DEV_CONFIG;
-
- /* Is this a compliant multifunction card? */
- tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
- tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
- info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
-
- /* Is this a multiport card? */
- tuple.DesiredTuple = CISTPL_MANFID;
- if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
- info->manfid = le16_to_cpu(buf[0]);
- for (i = 0; i < MULTI_COUNT; i++)
- if ((info->manfid == multi_id[i].manfid) &&
- (le16_to_cpu(buf[1]) == multi_id[i].prodid))
- break;
- if (i < MULTI_COUNT)
- info->multi = multi_id[i].multi;
- }
-
- /* Another check for dual-serial cards: look for either serial or
- multifunction cards that ask for appropriate IO port ranges */
- tuple.DesiredTuple = CISTPL_FUNCID;
- if ((info->multi == 0) &&
- ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) ||
- (parse.funcid.func == CISTPL_FUNCID_MULTI) ||
- (parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
- if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
- info->multi = cf->io.win[0].len >> 3;
- if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
- (cf->io.win[1].len == 8))
- info->multi = 2;
- }
- }
-
- if (info->multi > 1)
- multi_config(link);
- else
- simple_config(link);
-
- if (info->ndev == 0)
- goto failed;
-
- if (info->manfid == MANFID_IBM) {
- conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
- CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
- reg.Action = CS_WRITE;
- reg.Value = reg.Value | 1;
- CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
- }
-
- link->dev = &info->node[0];
- link->state &= ~DEV_CONFIG_PENDING;
- return;
-
-cs_failed:
- cs_error(link->handle, last_fn, last_ret);
-failed:
- serial_release((u_long)link);
-
-} /* serial_config */
-
-/*======================================================================
-
- After a card is removed, serial_release() will unregister the net
- device, and release the PCMCIA configuration.
-
-======================================================================*/
-
-void serial_release(u_long arg)
-{
- dev_link_t *link = (dev_link_t *)arg;
- serial_info_t *info = link->priv;
- int i;
-
- DEBUG(0, "serial_release(0x%p)\n", link);
-
- for (i = 0; i < info->ndev; i++) {
- unregister_serial(info->line[i]);
- }
- link->dev = NULL;
-
- if (!info->slave) {
- CardServices(ReleaseConfiguration, link->handle);
- CardServices(ReleaseIO, link->handle, &link->io);
- CardServices(ReleaseIRQ, link->handle, &link->irq);
- }
-
- link->state &= ~DEV_CONFIG;
-
-} /* serial_release */
-
-/*======================================================================
-
- The card status event handler. Mostly, this schedules other
- stuff to run after an event is received. A CARD_REMOVAL event
- also sets some flags to discourage the serial drivers from
- talking to the ports.
-
-======================================================================*/
-
-static int serial_event(event_t event, int priority,
- event_callback_args_t *args)
-{
- dev_link_t *link = args->client_data;
- serial_info_t *info = link->priv;
-
- DEBUG(1, "serial_event(0x%06x)\n", event);
-
- switch (event) {
- case CS_EVENT_CARD_REMOVAL:
- link->state &= ~DEV_PRESENT;
- if (link->state & DEV_CONFIG)
- mod_timer(&link->release, jiffies + HZ/20);
- break;
- case CS_EVENT_CARD_INSERTION:
- link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
- serial_config(link);
- break;
- case CS_EVENT_PM_SUSPEND:
- link->state |= DEV_SUSPEND;
- /* Fall through... */
- case CS_EVENT_RESET_PHYSICAL:
- if ((link->state & DEV_CONFIG) && !info->slave)
- CardServices(ReleaseConfiguration, link->handle);
- break;
- case CS_EVENT_PM_RESUME:
- link->state &= ~DEV_SUSPEND;
- /* Fall through... */
- case CS_EVENT_CARD_RESET:
- if (DEV_OK(link) && !info->slave)
- CardServices(RequestConfiguration, link->handle, &link->conf);
- break;
- }
- return 0;
-} /* serial_event */
-
-/*====================================================================*/
-
-static int __init init_serial_cs(void)
-{
- servinfo_t serv;
- DEBUG(0, "%s\n", version);
- CardServices(GetCardServicesInfo, &serv);
- if (serv.Revision != CS_RELEASE_CODE) {
- printk(KERN_NOTICE "serial_cs: Card Services release "
- "does not match!\n");
- return -1;
- }
- register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
- return 0;
-}
-
-static void __exit exit_serial_cs(void)
-{
- DEBUG(0, "serial_cs: unloading\n");
- unregister_pccard_driver(&dev_info);
- while (dev_list != NULL)
- serial_detach(dev_list);
-}
-
-module_init(init_serial_cs);
-module_exit(exit_serial_cs);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
deleted file mode 100644
index c3cd00f3caea..000000000000
--- a/drivers/char/serial.c
+++ /dev/null
@@ -1,6003 +0,0 @@
-/*
- * linux/drivers/char/serial.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
- * 1998, 1999 Theodore Ts'o
- *
- * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
- * much more extensible to support other serial cards based on the
- * 16450/16550A UART's. Added support for the AST FourPort and the
- * Accent Async board.
- *
- * set_serial_info fixed to set the flags, custom divisor, and uart
- * type fields. Fix suggested by Michael K. Johnson 12/12/92.
- *
- * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
- *
- * 03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
- *
- * rs_set_termios fixed to look also for changes of the input
- * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
- * Bernd Anhäupl 05/17/96.
- *
- * 1/97: Extended dumb serial ports are a config option now.
- * Saves 4k. Michael A. Griffith <grif@acm.org>
- *
- * 8/97: Fix bug in rs_set_termios with RTS
- * Stanislav V. Voronyi <stas@uanet.kharkov.ua>
- *
- * 3/98: Change the IRQ detection, use of probe_irq_o*(),
- * suppress TIOCSERGWILD and TIOCSERSWILD
- * Etienne Lorrain <etienne.lorrain@ibm.net>
- *
- * 4/98: Added changes to support the ARM architecture proposed by
- * Russell King
- *
- * 5/99: Updated to include support for the XR16C850 and ST16C654
- * uarts. Stuart MacDonald <stuartm@connecttech.com>
- *
- * 8/99: Generalized PCI support added. Theodore Ts'o
- *
- * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a
- * few races on freeing buffers too.
- * Alan Modra <alan@linuxcare.com>
- *
- * 5/00: Support for the RSA-DV II/S card added.
- * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
- *
- * 6/00: Remove old-style timer, use timer_list
- * Andrew Morton <andrewm@uow.edu.au>
- *
- * 7/00: Support Timedia/Sunix/Exsys PCI cards
- *
- * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * 10/00: add in optional software flow control for serial console.
- * Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o)
- *
- */
-
-static char *serial_version = "5.05c";
-static char *serial_revdate = "2001-07-08";
-
-/*
- * Serial driver configuration section. Here are the various options:
- *
- * CONFIG_HUB6
- * Enables support for the venerable Bell Technologies
- * HUB6 card.
- *
- * CONFIG_SERIAL_MANY_PORTS
- * Enables support for ports beyond the standard, stupid
- * COM 1/2/3/4.
- *
- * CONFIG_SERIAL_MULTIPORT
- * Enables support for special multiport board support.
- *
- * CONFIG_SERIAL_SHARE_IRQ
- * Enables support for multiple serial ports on one IRQ
- *
- * CONFIG_SERIAL_DETECT_IRQ
- * Enable the autodetection of IRQ on standart ports
- *
- * SERIAL_PARANOIA_CHECK
- * Check the magic number for the async_structure where
- * ever possible.
- *
- * CONFIG_SERIAL_ACPI
- * Enable support for serial console port and serial
- * debug port as defined by the SPCR and DBGP tables in
- * ACPI 2.0.
- */
-
-#include <linux/config.h>
-#include <linux/version.h>
-
-#undef SERIAL_PARANOIA_CHECK
-#define CONFIG_SERIAL_NOPAUSE_IO
-#define SERIAL_DO_RESTART
-
-#if 0
-/* These defines are normally controlled by the autoconf.h */
-#define CONFIG_SERIAL_MANY_PORTS
-#define CONFIG_SERIAL_SHARE_IRQ
-#define CONFIG_SERIAL_DETECT_IRQ
-#define CONFIG_SERIAL_MULTIPORT
-#define CONFIG_HUB6
-#endif
-
-#ifdef CONFIG_PCI
-#define ENABLE_SERIAL_PCI
-#ifndef CONFIG_SERIAL_SHARE_IRQ
-#define CONFIG_SERIAL_SHARE_IRQ
-#endif
-#ifndef CONFIG_SERIAL_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS
-#endif
-#endif
-
-#ifdef CONFIG_SERIAL_ACPI
-#define ENABLE_SERIAL_ACPI
-#endif
-
-
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-#undef SERIAL_DEBUG_PCI
-#undef SERIAL_DEBUG_AUTOCONF
-
-/* Sanity checks */
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-#ifndef CONFIG_SERIAL_SHARE_IRQ
-#define CONFIG_SERIAL_SHARE_IRQ
-#endif
-#endif
-
-#ifdef CONFIG_HUB6
-#ifndef CONFIG_SERIAL_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS
-#endif
-#ifndef CONFIG_SERIAL_SHARE_IRQ
-#define CONFIG_SERIAL_SHARE_IRQ
-#endif
-#endif
-
-#ifdef MODULE
-#undef CONFIG_SERIAL_CONSOLE
-#endif
-
-#define CONFIG_SERIAL_RSA
-
-#define RS_STROBE_TIME (10*HZ)
-#define RS_ISR_PASS_LIMIT 256
-
-#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
-#define SERIAL_INLINE
-#endif
-
-/*
- * End of serial driver configuration section.
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#ifdef LOCAL_HEADERS
-#include "serial_local.h"
-#else
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-#define LOCAL_VERSTRING ""
-#endif
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#if (LINUX_VERSION_CODE >= 131343)
-#include <linux/init.h>
-#endif
-#if (LINUX_VERSION_CODE >= 131336)
-#include <asm/uaccess.h>
-#endif
-#include <linux/delay.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#endif
-#ifdef ENABLE_SERIAL_PCI
-#include <linux/pci.h>
-#endif
-
-#include <linux/isapnp.h>
-#ifdef __ISAPNP__
-#ifndef ENABLE_SERIAL_PNP
-#define ENABLE_SERIAL_PNP
-#endif
-#endif
-
-#ifdef CONFIG_MAGIC_SYSRQ
-#include <linux/sysrq.h>
-#endif
-
-/*
- * All of the compatibilty code so we can compile serial.c against
- * older kernels is hidden in serial_compat.h
- */
-#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
-#include "serial_compat.h"
-#endif
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/bitops.h>
-
-#ifdef CONFIG_MAC_SERIAL
-#define SERIAL_DEV_OFFSET 2
-#else
-#define SERIAL_DEV_OFFSET 0
-#endif
-
-#ifdef SERIAL_INLINE
-#define _INLINE_ inline
-#else
-#define _INLINE_
-#endif
-
-static char *serial_name = "Serial driver";
-
-static DECLARE_TASK_QUEUE(tq_serial);
-
-static struct tty_driver serial_driver, callout_driver;
-static int serial_refcount;
-
-static struct timer_list serial_timer;
-
-/* serial subtype definitions */
-#ifndef SERIAL_TYPE_NORMAL
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
-#endif
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * IRQ_timeout - How long the timeout should be for each IRQ
- * should be after the IRQ has been active.
- */
-
-static struct async_struct *IRQ_ports[NR_IRQS];
-#ifdef CONFIG_SERIAL_MULTIPORT
-static struct rs_multiport_struct rs_multiport[NR_IRQS];
-#endif
-static int IRQ_timeout[NR_IRQS];
-#ifdef CONFIG_SERIAL_CONSOLE
-static struct console sercons;
-static int lsr_break_flag;
-#endif
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-static unsigned long break_pressed; /* break, really ... */
-#endif
-
-static unsigned detect_uart_irq (struct serial_state * state);
-static void autoconfig(struct serial_state * state);
-static void change_speed(struct async_struct *info, struct termios *old);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-/*
- * Here we define the default xmit fifo size used for each type of
- * UART
- */
-static struct serial_uart_config uart_config[] = {
- { "unknown", 1, 0 },
- { "8250", 1, 0 },
- { "16450", 1, 0 },
- { "16550", 1, 0 },
- { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
- { "cirrus", 1, 0 }, /* usurped by cyclades.c */
- { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
- { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
- UART_STARTECH },
- { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
- { "Startech", 1, 0}, /* usurped by cyclades.c */
- { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
- { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
- UART_STARTECH },
- { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
- UART_STARTECH },
- { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
- { 0, 0}
-};
-
-#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
-
-#define PORT_RSA_MAX 4
-static int probe_rsa[PORT_RSA_MAX];
-static int force_rsa[PORT_RSA_MAX];
-
-MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
-MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
-MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
-MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
-#endif /* CONFIG_SERIAL_RSA */
-
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
- SERIAL_PORT_DFNS /* Defined in serial.h */
-};
-
-#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
-
-#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
-#define NR_PCI_BOARDS 8
-
-static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
-
-#ifndef IS_PCI_REGION_IOPORT
-#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
- IORESOURCE_IO)
-#endif
-#ifndef IS_PCI_REGION_IOMEM
-#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
- IORESOURCE_MEM)
-#endif
-#ifndef PCI_IRQ_RESOURCE
-#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
-#endif
-#ifndef pci_get_subvendor
-#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
-#define pci_get_subdevice(dev) ((dev)->subsystem_device)
-#endif
-#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
-
-#ifndef PREPARE_FUNC
-#define PREPARE_FUNC(dev) (dev->prepare)
-#define ACTIVATE_FUNC(dev) (dev->activate)
-#define DEACTIVATE_FUNC(dev) (dev->deactivate)
-#endif
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-
-static struct tty_struct *serial_table[NR_PORTS];
-static struct termios *serial_termios[NR_PORTS];
-static struct termios *serial_termios_locked[NR_PORTS];
-
-
-#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
-#else
-#define DBG_CNT(s)
-#endif
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-#ifdef DECLARE_MUTEX
-static DECLARE_MUTEX(tmp_buf_sem);
-#else
-static struct semaphore tmp_buf_sem = MUTEX;
-#endif
-
-
-static inline int serial_paranoia_check(struct async_struct *info,
- kdev_t device, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct (%s) in %s\n";
- static const char *badinfo =
- "Warning: null async_struct for (%s) in %s\n";
-
- if (!info) {
- printk(badinfo, kdevname(device), routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, kdevname(device), routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
-{
- switch (info->io_type) {
-#ifdef CONFIG_HUB6
- case SERIAL_IO_HUB6:
- outb(info->hub6 - 1 + offset, info->port);
- return inb(info->port+1);
-#endif
- case SERIAL_IO_MEM:
- return readb((unsigned long) info->iomem_base +
- (offset<<info->iomem_reg_shift));
-#ifdef CONFIG_SERIAL_GSC
- case SERIAL_IO_GSC:
- return gsc_readb(info->iomem_base + offset);
-#endif
- default:
- return inb(info->port + offset);
- }
-}
-
-static _INLINE_ void serial_out(struct async_struct *info, int offset,
- int value)
-{
- switch (info->io_type) {
-#ifdef CONFIG_HUB6
- case SERIAL_IO_HUB6:
- outb(info->hub6 - 1 + offset, info->port);
- outb(value, info->port+1);
- break;
-#endif
- case SERIAL_IO_MEM:
- writeb(value, (unsigned long) info->iomem_base +
- (offset<<info->iomem_reg_shift));
- break;
-#ifdef CONFIG_SERIAL_GSC
- case SERIAL_IO_GSC:
- gsc_writeb(value, info->iomem_base + offset);
- break;
-#endif
- default:
- outb(value, info->port+offset);
- }
-}
-
-/*
- * We used to support using pause I/O for certain machines. We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(info, offset) serial_in(info, offset)
-#define serial_outp(info, offset, value) serial_out(info, offset, value)
-
-
-/*
- * For the 16C950
- */
-void serial_icr_write(struct async_struct *info, int offset, int value)
-{
- serial_out(info, UART_SCR, offset);
- serial_out(info, UART_ICR, value);
-}
-
-unsigned int serial_icr_read(struct async_struct *info, int offset)
-{
- int value;
-
- serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD);
- serial_out(info, UART_SCR, offset);
- value = serial_in(info, UART_ICR);
- serial_icr_write(info, UART_ACR, info->ACR);
- return value;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_stop"))
- return;
-
- save_flags(flags); cli();
- if (info->IER & UART_IER_THRI) {
- info->IER &= ~UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
- if (info->state->type == PORT_16C950) {
- info->ACR |= UART_ACR_TXDIS;
- serial_icr_write(info, UART_ACR, info->ACR);
- }
- restore_flags(flags);
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_start"))
- return;
-
- save_flags(flags); cli();
- if (info->xmit.head != info->xmit.tail
- && info->xmit.buf
- && !(info->IER & UART_IER_THRI)) {
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
- if (info->state->type == PORT_16C950) {
- info->ACR &= ~UART_ACR_TXDIS;
- serial_icr_write(info, UART_ACR, info->ACR);
- }
- restore_flags(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off. People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible. After you are done making modifications, it is not a bad
- * idea to do:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static _INLINE_ void rs_sched_event(struct async_struct *info,
- int event)
-{
- info->event |= 1 << event;
- queue_task(&info->tqueue, &tq_serial);
- mark_bh(SERIAL_BH);
-}
-
-static _INLINE_ void receive_chars(struct async_struct *info,
- int *status, struct pt_regs * regs)
-{
- struct tty_struct *tty = info->tty;
- unsigned char ch;
- struct async_icount *icount;
- int max_count = 256;
-
- icount = &info->state->icount;
- do {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- tty->flip.tqueue.routine((void *) tty);
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- return; // if TTY_DONT_FLIP is set
- }
- ch = serial_inp(info, UART_RX);
- *tty->flip.char_buf_ptr = ch;
- icount->rx++;
-
-#ifdef SERIAL_DEBUG_INTR
- printk("DR%02x:%02x...", ch, *status);
-#endif
- *tty->flip.flag_buf_ptr = 0;
- if (*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE)) {
- /*
- * For statistics only
- */
- if (*status & UART_LSR_BI) {
- *status &= ~(UART_LSR_FE | UART_LSR_PE);
- icount->brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
- if (info->line == sercons.index) {
- if (!break_pressed) {
- break_pressed = jiffies;
- goto ignore_char;
- }
- break_pressed = 0;
- }
-#endif
- if (info->flags & ASYNC_SAK)
- do_SAK(tty);
- } else if (*status & UART_LSR_PE)
- icount->parity++;
- else if (*status & UART_LSR_FE)
- icount->frame++;
- if (*status & UART_LSR_OE)
- icount->overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- *status &= info->read_status_mask;
-
-#ifdef CONFIG_SERIAL_CONSOLE
- if (info->line == sercons.index) {
- /* Recover the break flag from console xmit */
- *status |= lsr_break_flag;
- lsr_break_flag = 0;
- }
-#endif
- if (*status & (UART_LSR_BI)) {
-#ifdef SERIAL_DEBUG_INTR
- printk("handling break....");
-#endif
- *tty->flip.flag_buf_ptr = TTY_BREAK;
- } else if (*status & UART_LSR_PE)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
- else if (*status & UART_LSR_FE)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
- }
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
- if (break_pressed && info->line == sercons.index) {
- if (ch != 0 &&
- time_before(jiffies, break_pressed + HZ*5)) {
- handle_sysrq(ch, regs, NULL);
- break_pressed = 0;
- goto ignore_char;
- }
- break_pressed = 0;
- }
-#endif
- if ((*status & info->ignore_status_mask) == 0) {
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- }
- if ((*status & UART_LSR_OE) &&
- (tty->flip.count < TTY_FLIPBUF_SIZE)) {
- /*
- * Overrun is special, since it's reported
- * immediately, and doesn't affect the current
- * character
- */
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- }
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
- ignore_char:
-#endif
- *status = serial_inp(info, UART_LSR);
- } while ((*status & UART_LSR_DR) && (max_count-- > 0));
-#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
- tty_flip_buffer_push(tty);
-#else
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
-#endif
-}
-
-static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
-{
- int count;
-
- if (info->x_char) {
- serial_outp(info, UART_TX, info->x_char);
- info->state->icount.tx++;
- info->x_char = 0;
- if (intr_done)
- *intr_done = 0;
- return;
- }
- if (info->xmit.head == info->xmit.tail
- || info->tty->stopped
- || info->tty->hw_stopped) {
- info->IER &= ~UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- return;
- }
-
- count = info->xmit_fifo_size;
- do {
- serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
- info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
- info->state->icount.tx++;
- if (info->xmit.head == info->xmit.tail)
- break;
- } while (--count > 0);
-
- if (CIRC_CNT(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-#ifdef SERIAL_DEBUG_INTR
- printk("THRE...");
-#endif
- if (intr_done)
- *intr_done = 0;
-
- if (info->xmit.head == info->xmit.tail) {
- info->IER &= ~UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
-}
-
-static _INLINE_ void check_modem_status(struct async_struct *info)
-{
- int status;
- struct async_icount *icount;
-
- status = serial_in(info, UART_MSR);
-
- if (status & UART_MSR_ANY_DELTA) {
- icount = &info->state->icount;
- /* update input line counters */
- if (status & UART_MSR_TERI)
- icount->rng++;
- if (status & UART_MSR_DDSR)
- icount->dsr++;
- if (status & UART_MSR_DDCD) {
- icount->dcd++;
-#ifdef CONFIG_HARD_PPS
- if ((info->flags & ASYNC_HARDPPS_CD) &&
- (status & UART_MSR_DCD))
- hardpps();
-#endif
- }
- if (status & UART_MSR_DCTS)
- icount->cts++;
- wake_up_interruptible(&info->delta_msr_wait);
- }
-
- if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
- printk("ttys%d CD now %s...", info->line,
- (status & UART_MSR_DCD) ? "on" : "off");
-#endif
- if (status & UART_MSR_DCD)
- wake_up_interruptible(&info->open_wait);
- else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_CALLOUT_NOHUP))) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("doing serial hangup...");
-#endif
- if (info->tty)
- tty_hangup(info->tty);
- }
- }
- if (info->flags & ASYNC_CTS_FLOW) {
- if (info->tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
- printk("CTS tx start...");
-#endif
- info->tty->hw_stopped = 0;
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
- return;
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
- printk("CTS tx stop...");
-#endif
- info->tty->hw_stopped = 1;
- info->IER &= ~UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
- }
- }
-}
-
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-/*
- * This is the serial driver's generic interrupt routine
- */
-static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
- int status;
- struct async_struct * info;
- int pass_counter = 0;
- struct async_struct *end_mark = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
- int first_multi = 0;
- struct rs_multiport_struct *multi;
-#endif
-
-#ifdef SERIAL_DEBUG_INTR
- printk("rs_interrupt(%d)...", irq);
-#endif
-
- info = IRQ_ports[irq];
- if (!info)
- return;
-
-#ifdef CONFIG_SERIAL_MULTIPORT
- multi = &rs_multiport[irq];
- if (multi->port_monitor)
- first_multi = inb(multi->port_monitor);
-#endif
-
- do {
- if (!info->tty ||
- (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
- if (!end_mark)
- end_mark = info;
- goto next;
- }
-#ifdef SERIAL_DEBUG_INTR
- printk("IIR = %x...", serial_in(info, UART_IIR));
-#endif
- end_mark = 0;
-
- info->last_active = jiffies;
-
- status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
- printk("status = %x...", status);
-#endif
- if (status & UART_LSR_DR)
- receive_chars(info, &status, regs);
- check_modem_status(info);
- if (status & UART_LSR_THRE)
- transmit_chars(info, 0);
-
- next:
- info = info->next_port;
- if (!info) {
- info = IRQ_ports[irq];
- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
- printk("rs loop break\n");
-#endif
- break; /* Prevent infinite loops */
- }
- continue;
- }
- } while (end_mark != info);
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (multi->port_monitor)
- printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
- info->state->irq, first_multi,
- inb(multi->port_monitor));
-#endif
-#ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
-#endif
-}
-#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
-
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
-{
- int status;
- int pass_counter = 0;
- struct async_struct * info;
-#ifdef CONFIG_SERIAL_MULTIPORT
- int first_multi = 0;
- struct rs_multiport_struct *multi;
-#endif
-
-#ifdef SERIAL_DEBUG_INTR
- printk("rs_interrupt_single(%d)...", irq);
-#endif
-
- info = IRQ_ports[irq];
- if (!info || !info->tty)
- return;
-
-#ifdef CONFIG_SERIAL_MULTIPORT
- multi = &rs_multiport[irq];
- if (multi->port_monitor)
- first_multi = inb(multi->port_monitor);
-#endif
-
- do {
- status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
- printk("status = %x...", status);
-#endif
- if (status & UART_LSR_DR)
- receive_chars(info, &status, regs);
- check_modem_status(info);
- if (status & UART_LSR_THRE)
- transmit_chars(info, 0);
- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
- printk("rs_single loop break.\n");
-#endif
- break;
- }
-#ifdef SERIAL_DEBUG_INTR
- printk("IIR = %x...", serial_in(info, UART_IIR));
-#endif
- } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
- info->last_active = jiffies;
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (multi->port_monitor)
- printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
- info->state->irq, first_multi,
- inb(multi->port_monitor));
-#endif
-#ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
-#endif
-}
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-/*
- * This is the serial driver's for multiport boards
- */
-static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
-{
- int status;
- struct async_struct * info;
- int pass_counter = 0;
- int first_multi= 0;
- struct rs_multiport_struct *multi;
-
-#ifdef SERIAL_DEBUG_INTR
- printk("rs_interrupt_multi(%d)...", irq);
-#endif
-
- info = IRQ_ports[irq];
- if (!info)
- return;
- multi = &rs_multiport[irq];
- if (!multi->port1) {
- /* Should never happen */
- printk("rs_interrupt_multi: NULL port1!\n");
- return;
- }
- if (multi->port_monitor)
- first_multi = inb(multi->port_monitor);
-
- while (1) {
- if (!info->tty ||
- (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
- goto next;
-
- info->last_active = jiffies;
-
- status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
- printk("status = %x...", status);
-#endif
- if (status & UART_LSR_DR)
- receive_chars(info, &status, regs);
- check_modem_status(info);
- if (status & UART_LSR_THRE)
- transmit_chars(info, 0);
-
- next:
- info = info->next_port;
- if (info)
- continue;
-
- info = IRQ_ports[irq];
- /*
- * The user was a bonehead, and misconfigured their
- * multiport info. Rather than lock up the kernel
- * in an infinite loop, if we loop too many times,
- * print a message and break out of the loop.
- */
- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
- printk("Misconfigured multiport serial info "
- "for irq %d. Breaking out irq loop\n", irq);
- break;
- }
- if (multi->port_monitor)
- printk("rs port monitor irq %d: 0x%x, 0x%x\n",
- info->state->irq, first_multi,
- inb(multi->port_monitor));
- if ((inb(multi->port1) & multi->mask1) != multi->match1)
- continue;
- if (!multi->port2)
- break;
- if ((inb(multi->port2) & multi->mask2) != multi->match2)
- continue;
- if (!multi->port3)
- break;
- if ((inb(multi->port3) & multi->mask3) != multi->match3)
- continue;
- if (!multi->port4)
- break;
- if ((inb(multi->port4) & multi->mask4) != multi->match4)
- continue;
- break;
- }
-#ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
-#endif
-}
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-static void do_serial_bh(void)
-{
- run_task_queue(&tq_serial);
-}
-
-static void do_softint(void *private_)
-{
- struct async_struct *info = (struct async_struct *) private_;
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- wake_up_interruptible(&tty->write_wait);
-#ifdef SERIAL_HAVE_POLL_WAIT
- wake_up_interruptible(&tty->poll_wait);
-#endif
- }
-}
-
-/*
- * This subroutine is called when the RS_TIMER goes off. It is used
- * by the serial driver to handle ports that do not have an interrupt
- * (irq=0). This doesn't work very well for 16450's, but gives barely
- * passable results for a 16550A. (Although at the expense of much
- * CPU overhead).
- */
-static void rs_timer(unsigned long dummy)
-{
- static unsigned long last_strobe;
- struct async_struct *info;
- unsigned int i;
- unsigned long flags;
-
- if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
- for (i=0; i < NR_IRQS; i++) {
- info = IRQ_ports[i];
- if (!info)
- continue;
- save_flags(flags); cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- if (info->next_port) {
- do {
- serial_out(info, UART_IER, 0);
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- info = info->next_port;
- } while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (rs_multiport[i].port1)
- rs_interrupt_multi(i, NULL, NULL);
- else
-#endif
- rs_interrupt(i, NULL, NULL);
- } else
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
- rs_interrupt_single(i, NULL, NULL);
- restore_flags(flags);
- }
- }
- last_strobe = jiffies;
- mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
-
- if (IRQ_ports[0]) {
- save_flags(flags); cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- rs_interrupt(0, NULL, NULL);
-#else
- rs_interrupt_single(0, NULL, NULL);
-#endif
- restore_flags(flags);
-
- mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
- }
-}
-
-/*
- * ---------------------------------------------------------------
- * Low level utility subroutines for the serial driver: routines to
- * figure out the appropriate timeout for an interrupt chain, routines
- * to initialize and startup a serial port, and routines to shutdown a
- * serial port. Useful stuff like that.
- * ---------------------------------------------------------------
- */
-
-/*
- * This routine figures out the correct timeout for a particular IRQ.
- * It uses the smallest timeout of all of the serial ports in a
- * particular interrupt chain. Now only used for IRQ 0....
- */
-static void figure_IRQ_timeout(int irq)
-{
- struct async_struct *info;
- int timeout = 60*HZ; /* 60 seconds === a long time :-) */
-
- info = IRQ_ports[irq];
- if (!info) {
- IRQ_timeout[irq] = 60*HZ;
- return;
- }
- while (info) {
- if (info->timeout < timeout)
- timeout = info->timeout;
- info = info->next_port;
- }
- if (!irq)
- timeout = timeout / 2;
- IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;
-}
-
-#ifdef CONFIG_SERIAL_RSA
-/* Attempts to turn on the RSA FIFO. Returns zero on failure */
-static int enable_rsa(struct async_struct *info)
-{
- unsigned char mode;
- int result;
- unsigned long flags;
-
- save_flags(flags); cli();
- mode = serial_inp(info, UART_RSA_MSR);
- result = mode & UART_RSA_MSR_FIFO;
-
- if (!result) {
- serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
- mode = serial_inp(info, UART_RSA_MSR);
- result = mode & UART_RSA_MSR_FIFO;
- }
-
- restore_flags(flags);
- return result;
-}
-
-/* Attempts to turn off the RSA FIFO. Returns zero on failure */
-static int disable_rsa(struct async_struct *info)
-{
- unsigned char mode;
- int result;
- unsigned long flags;
-
- save_flags(flags); cli();
- mode = serial_inp(info, UART_RSA_MSR);
- result = !(mode & UART_RSA_MSR_FIFO);
-
- if (!result) {
- serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
- mode = serial_inp(info, UART_RSA_MSR);
- result = !(mode & UART_RSA_MSR_FIFO);
- }
-
- restore_flags(flags);
- return result;
-}
-#endif /* CONFIG_SERIAL_RSA */
-
-static int startup(struct async_struct * info)
-{
- unsigned long flags;
- int retval=0;
- void (*handler)(int, void *, struct pt_regs *);
- struct serial_state *state= info->state;
- unsigned long page;
-#ifdef CONFIG_SERIAL_MANY_PORTS
- unsigned short ICP;
-#endif
-
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
-
- save_flags(flags); cli();
-
- if (info->flags & ASYNC_INITIALIZED) {
- free_page(page);
- goto errout;
- }
-
- if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- free_page(page);
- goto errout;
- }
- if (info->xmit.buf)
- free_page(page);
- else
- info->xmit.buf = (unsigned char *) page;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
- if (uart_config[state->type].flags & UART_STARTECH) {
- /* Wake up UART */
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, UART_EFR_ECB);
- /*
- * Turn off LCR == 0xBF so we actually set the IER
- * register on the XR16C850
- */
- serial_outp(info, UART_LCR, 0);
- serial_outp(info, UART_IER, 0);
- /*
- * Now reset LCR so we can turn off the ECB bit
- */
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, 0);
- /*
- * For a XR16C850, we need to set the trigger levels
- */
- if (state->type == PORT_16850) {
- serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
- UART_FCTR_RX);
- serial_outp(info, UART_TRG, UART_TRG_96);
- serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
- UART_FCTR_TX);
- serial_outp(info, UART_TRG, UART_TRG_96);
- }
- serial_outp(info, UART_LCR, 0);
- }
-
- if (state->type == PORT_16750) {
- /* Wake up UART */
- serial_outp(info, UART_IER, 0);
- }
-
- if (state->type == PORT_16C950) {
- /* Wake up and initialize UART */
- info->ACR = 0;
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, UART_EFR_ECB);
- serial_outp(info, UART_IER, 0);
- serial_outp(info, UART_LCR, 0);
- serial_icr_write(info, UART_CSR, 0); /* Reset the UART */
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, UART_EFR_ECB);
- serial_outp(info, UART_LCR, 0);
- }
-
-#ifdef CONFIG_SERIAL_RSA
- /*
- * If this is an RSA port, see if we can kick it up to the
- * higher speed clock.
- */
- if (state->type == PORT_RSA) {
- if (state->baud_base != SERIAL_RSA_BAUD_BASE &&
- enable_rsa(info))
- state->baud_base = SERIAL_RSA_BAUD_BASE;
- if (state->baud_base == SERIAL_RSA_BAUD_BASE)
- serial_outp(info, UART_RSA_FRR, 0);
- }
-#endif
-
- /*
- * Clear the FIFO buffers and disable them
- * (they will be reenabled in change_speed())
- */
- if (uart_config[state->type].flags & UART_CLEAR_FIFO) {
- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT));
- serial_outp(info, UART_FCR, 0);
- }
-
- /*
- * Clear the interrupt registers.
- */
- (void) serial_inp(info, UART_LSR);
- (void) serial_inp(info, UART_RX);
- (void) serial_inp(info, UART_IIR);
- (void) serial_inp(info, UART_MSR);
-
- /*
- * At this point there's no way the LSR could still be 0xFF;
- * if it is, then bail out, because there's likely no UART
- * here.
- */
- if (!(info->flags & ASYNC_BUGGY_UART) &&
- (serial_inp(info, UART_LSR) == 0xff)) {
- printk("ttyS%d: LSR safety check engaged!\n", state->line);
- if (capable(CAP_SYS_ADMIN)) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- } else
- retval = -ENODEV;
- goto errout;
- }
-
- /*
- * Allocate the IRQ if necessary
- */
- if (state->irq && (!IRQ_ports[state->irq] ||
- !IRQ_ports[state->irq]->next_port)) {
- if (IRQ_ports[state->irq]) {
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- free_irq(state->irq, &IRQ_ports[state->irq]);
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (rs_multiport[state->irq].port1)
- handler = rs_interrupt_multi;
- else
-#endif
- handler = rs_interrupt;
-#else
- retval = -EBUSY;
- goto errout;
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
- } else
- handler = rs_interrupt_single;
-
- retval = request_irq(state->irq, handler, SA_SHIRQ,
- "serial", &IRQ_ports[state->irq]);
- if (retval) {
- if (capable(CAP_SYS_ADMIN)) {
- if (info->tty)
- set_bit(TTY_IO_ERROR,
- &info->tty->flags);
- retval = 0;
- }
- goto errout;
- }
- }
-
- /*
- * Insert serial port into IRQ chain.
- */
- info->prev_port = 0;
- info->next_port = IRQ_ports[state->irq];
- if (info->next_port)
- info->next_port->prev_port = info;
- IRQ_ports[state->irq] = info;
- figure_IRQ_timeout(state->irq);
-
- /*
- * Now, initialize the UART
- */
- serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
-
- info->MCR = 0;
- if (info->tty->termios->c_cflag & CBAUD)
- info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- if (state->irq == 0)
- info->MCR |= UART_MCR_OUT1;
- } else
-#endif
- {
- if (state->irq != 0)
- info->MCR |= UART_MCR_OUT2;
- }
- info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
- serial_outp(info, UART_MCR, info->MCR);
-
- /*
- * Finally, enable interrupts
- */
- info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
- serial_outp(info, UART_IER, info->IER); /* enable interrupts */
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- /* Enable interrupts on the AST Fourport board */
- ICP = (info->port & 0xFE0) | 0x01F;
- outb_p(0x80, ICP);
- (void) inb_p(ICP);
- }
-#endif
-
- /*
- * And clear the interrupt registers again for luck.
- */
- (void)serial_inp(info, UART_LSR);
- (void)serial_inp(info, UART_RX);
- (void)serial_inp(info, UART_IIR);
- (void)serial_inp(info, UART_MSR);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit.head = info->xmit.tail = 0;
-
- /*
- * Set up serial timers...
- */
- mod_timer(&serial_timer, jiffies + 2*HZ/100);
-
- /*
- * Set up the tty->alt_speed kludge
- */
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
- if (info->tty) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->tty->alt_speed = 57600;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- info->tty->alt_speed = 115200;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- info->tty->alt_speed = 230400;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->tty->alt_speed = 460800;
- }
-#endif
-
- /*
- * and set the speed of the serial port
- */
- change_speed(info, 0);
-
- info->flags |= ASYNC_INITIALIZED;
- restore_flags(flags);
- return 0;
-
-errout:
- restore_flags(flags);
- return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct async_struct * info)
-{
- unsigned long flags;
- struct serial_state *state;
- int retval;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
-
- state = info->state;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d (irq %d)....", info->line,
- state->irq);
-#endif
-
- save_flags(flags); cli(); /* Disable interrupts */
-
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
- * here so the queue might never be waken up
- */
- wake_up_interruptible(&info->delta_msr_wait);
-
- /*
- * First unlink the serial port from the IRQ chain...
- */
- if (info->next_port)
- info->next_port->prev_port = info->prev_port;
- if (info->prev_port)
- info->prev_port->next_port = info->next_port;
- else
- IRQ_ports[state->irq] = info->next_port;
- figure_IRQ_timeout(state->irq);
-
- /*
- * Free the IRQ, if necessary
- */
- if (state->irq && (!IRQ_ports[state->irq] ||
- !IRQ_ports[state->irq]->next_port)) {
- if (IRQ_ports[state->irq]) {
- free_irq(state->irq, &IRQ_ports[state->irq]);
- retval = request_irq(state->irq, rs_interrupt_single,
- SA_SHIRQ, "serial",
- &IRQ_ports[state->irq]);
-
- if (retval)
- printk("serial shutdown: request_irq: error %d"
- " Couldn't reacquire IRQ.\n", retval);
- } else
- free_irq(state->irq, &IRQ_ports[state->irq]);
- }
-
- if (info->xmit.buf) {
- unsigned long pg = (unsigned long) info->xmit.buf;
- info->xmit.buf = 0;
- free_page(pg);
- }
-
- info->IER = 0;
- serial_outp(info, UART_IER, 0x00); /* disable all intrs */
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- /* reset interrupts on the AST Fourport board */
- (void) inb((info->port & 0xFE0) | 0x01F);
- info->MCR |= UART_MCR_OUT1;
- } else
-#endif
- info->MCR &= ~UART_MCR_OUT2;
- info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
-
- /* disable break condition */
- serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
-
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
- info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
- serial_outp(info, UART_MCR, info->MCR);
-
- /* disable FIFO's */
- serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT));
- serial_outp(info, UART_FCR, 0);
-
-#ifdef CONFIG_SERIAL_RSA
- /*
- * Reset the RSA board back to 115kbps compat mode.
- */
- if ((state->type == PORT_RSA) &&
- (state->baud_base == SERIAL_RSA_BAUD_BASE &&
- disable_rsa(info)))
- state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
-#endif
-
-
- (void)serial_in(info, UART_RX); /* read data port to reset things */
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- if (uart_config[info->state->type].flags & UART_STARTECH) {
- /* Arrange to enter sleep mode */
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, UART_EFR_ECB);
- serial_outp(info, UART_LCR, 0);
- serial_outp(info, UART_IER, UART_IERX_SLEEP);
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR, 0);
- serial_outp(info, UART_LCR, 0);
- }
- if (info->state->type == PORT_16750) {
- /* Arrange to enter sleep mode */
- serial_outp(info, UART_IER, UART_IERX_SLEEP);
- }
- info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
-}
-
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300,
- 600, 1200, 1800, 2400, 4800, 9600, 19200,
- 38400, 57600, 115200, 230400, 460800, 0 };
-
-static int tty_get_baud_rate(struct tty_struct *tty)
-{
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- unsigned int cflag, i;
-
- cflag = tty->termios->c_cflag;
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 2)
- tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (i == 15) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- i += 1;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- i += 2;
- }
- return baud_table[i];
-}
-#endif
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct async_struct *info,
- struct termios *old_termios)
-{
- int quot = 0, baud_base, baud;
- unsigned cflag, cval, fcr = 0;
- int bits;
- unsigned long flags;
-
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
- if (!CONFIGURED_SERIAL_PORT(info))
- return;
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: cval = 0x00; bits = 7; break;
- case CS6: cval = 0x01; bits = 8; break;
- case CS7: cval = 0x02; bits = 9; break;
- case CS8: cval = 0x03; bits = 10; break;
- /* Never happens, but GCC is too dumb to figure it out */
- default: cval = 0x00; bits = 7; break;
- }
- if (cflag & CSTOPB) {
- cval |= 0x04;
- bits++;
- }
- if (cflag & PARENB) {
- cval |= UART_LCR_PARITY;
- bits++;
- }
- if (!(cflag & PARODD))
- cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
- if (cflag & CMSPAR)
- cval |= UART_LCR_SPAR;
-#endif
-
- /* Determine divisor based on baud rate */
- baud = tty_get_baud_rate(info->tty);
- if (!baud)
- baud = 9600; /* B0 transition handled in rs_set_termios */
-#ifdef CONFIG_SERIAL_RSA
- if ((info->state->type == PORT_RSA) &&
- (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
- enable_rsa(info))
- info->state->baud_base = SERIAL_RSA_BAUD_BASE;
-#endif
- baud_base = info->state->baud_base;
- if (info->state->type == PORT_16C950) {
- if (baud <= baud_base)
- serial_icr_write(info, UART_TCR, 0);
- else if (baud <= 2*baud_base) {
- serial_icr_write(info, UART_TCR, 0x8);
- baud_base = baud_base * 2;
- } else if (baud <= 4*baud_base) {
- serial_icr_write(info, UART_TCR, 0x4);
- baud_base = baud_base * 4;
- } else
- serial_icr_write(info, UART_TCR, 0);
- }
- if (baud == 38400 &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
- quot = info->state->custom_divisor;
- else {
- if (baud == 134)
- /* Special case since 134 is really 134.5 */
- quot = (2*baud_base / 269);
- else if (baud)
- quot = baud_base / baud;
- }
- /* If the quotient is zero refuse the change */
- if (!quot && old_termios) {
- info->tty->termios->c_cflag &= ~CBAUD;
- info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
- baud = tty_get_baud_rate(info->tty);
- if (!baud)
- baud = 9600;
- if (baud == 38400 &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
- quot = info->state->custom_divisor;
- else {
- if (baud == 134)
- /* Special case since 134 is really 134.5 */
- quot = (2*baud_base / 269);
- else if (baud)
- quot = baud_base / baud;
- }
- }
- /* As a last resort, if the quotient is zero, default to 9600 bps */
- if (!quot)
- quot = baud_base / 9600;
- /*
- * Work around a bug in the Oxford Semiconductor 952 rev B
- * chip which causes it to seriously miscalculate baud rates
- * when DLL is 0.
- */
- if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
- (info->state->revision == 0x5201))
- quot++;
-
- info->quot = quot;
- info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
- info->timeout += HZ/50; /* Add .02 seconds of slop */
-
- /* Set up FIFO's */
- if (uart_config[info->state->type].flags & UART_USE_FIFO) {
- if ((info->state->baud_base / quot) < 2400)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-#ifdef CONFIG_SERIAL_RSA
- else if (info->state->type == PORT_RSA)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
-#endif
- else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
- }
- if (info->state->type == PORT_16750)
- fcr |= UART_FCR7_64BYTE;
-
- /* CTS flow control flag and modem status interrupts */
- info->IER &= ~UART_IER_MSI;
- if (info->flags & ASYNC_HARDPPS_CD)
- info->IER |= UART_IER_MSI;
- if (cflag & CRTSCTS) {
- info->flags |= ASYNC_CTS_FLOW;
- info->IER |= UART_IER_MSI;
- } else
- info->flags &= ~ASYNC_CTS_FLOW;
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else {
- info->flags |= ASYNC_CHECK_CD;
- info->IER |= UART_IER_MSI;
- }
- serial_out(info, UART_IER, info->IER);
-
- /*
- * Set up parity check flag
- */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
- info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (I_INPCK(info->tty))
- info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
- info->read_status_mask |= UART_LSR_BI;
-
- /*
- * Characters to ignore
- */
- info->ignore_status_mask = 0;
- if (I_IGNPAR(info->tty))
- info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
- if (I_IGNBRK(info->tty)) {
- info->ignore_status_mask |= UART_LSR_BI;
- /*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
- */
- if (I_IGNPAR(info->tty))
- info->ignore_status_mask |= UART_LSR_OE;
- }
- /*
- * !!! ignore all characters if CREAD is not set
- */
- if ((cflag & CREAD) == 0)
- info->ignore_status_mask |= UART_LSR_DR;
- save_flags(flags); cli();
- if (uart_config[info->state->type].flags & UART_STARTECH) {
- serial_outp(info, UART_LCR, 0xBF);
- serial_outp(info, UART_EFR,
- (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
- }
- serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
- serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */
- if (info->state->type == PORT_16750)
- serial_outp(info, UART_FCR, fcr); /* set fcr */
- serial_outp(info, UART_LCR, cval); /* reset DLAB */
- info->LCR = cval; /* Save LCR */
- if (info->state->type != PORT_16750) {
- if (fcr & UART_FCR_ENABLE_FIFO) {
- /* emulated UARTs (Lucent Venus 167x) need two steps */
- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
- }
- serial_outp(info, UART_FCR, fcr); /* set fcr */
- }
- restore_flags(flags);
-}
-
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_put_char"))
- return;
-
- if (!tty || !info->xmit.buf)
- return;
-
- save_flags(flags); cli();
- if (CIRC_SPACE(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE) == 0) {
- restore_flags(flags);
- return;
- }
-
- info->xmit.buf[info->xmit.head] = ch;
- info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
- restore_flags(flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
- return;
-
- if (info->xmit.head == info->xmit.tail
- || tty->stopped
- || tty->hw_stopped
- || !info->xmit.buf)
- return;
-
- save_flags(flags); cli();
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- restore_flags(flags);
-}
-
-static int rs_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
-{
- int c, ret = 0;
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit.buf || !tmp_buf)
- return 0;
-
- save_flags(flags);
- if (from_user) {
- down(&tmp_buf_sem);
- while (1) {
- int c1;
- c = CIRC_SPACE_TO_END(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE);
- if (count < c)
- c = count;
- if (c <= 0)
- break;
-
- c -= copy_from_user(tmp_buf, buf, c);
- if (!c) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- cli();
- c1 = CIRC_SPACE_TO_END(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE);
- if (c1 < c)
- c = c1;
- memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
- info->xmit.head = ((info->xmit.head + c) &
- (SERIAL_XMIT_SIZE-1));
- restore_flags(flags);
- buf += c;
- count -= c;
- ret += c;
- }
- up(&tmp_buf_sem);
- } else {
- cli();
- while (1) {
- c = CIRC_SPACE_TO_END(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE);
- if (count < c)
- c = count;
- if (c <= 0) {
- break;
- }
- memcpy(info->xmit.buf + info->xmit.head, buf, c);
- info->xmit.head = ((info->xmit.head + c) &
- (SERIAL_XMIT_SIZE-1));
- buf += c;
- count -= c;
- ret += c;
- }
- restore_flags(flags);
- }
- if (info->xmit.head != info->xmit.tail
- && !tty->stopped
- && !tty->hw_stopped
- && !(info->IER & UART_IER_THRI)) {
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
- return ret;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->device, "rs_write_room"))
- return 0;
- return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
- return 0;
- return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
- return;
- save_flags(flags); cli();
- info->xmit.head = info->xmit.tail = 0;
- restore_flags(flags);
- wake_up_interruptible(&tty->write_wait);
-#ifdef SERIAL_HAVE_POLL_WAIT
- wake_up_interruptible(&tty->poll_wait);
-#endif
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void rs_send_xchar(struct tty_struct *tty, char ch)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->device, "rs_send_char"))
- return;
-
- info->x_char = ch;
- if (ch) {
- /* Make sure transmit interrupts are on */
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->device, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty))
- rs_send_xchar(tty, STOP_CHAR(tty));
-
- if (tty->termios->c_cflag & CRTSCTS)
- info->MCR &= ~UART_MCR_RTS;
-
- save_flags(flags); cli();
- serial_out(info, UART_MCR, info->MCR);
- restore_flags(flags);
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- rs_send_xchar(tty, START_CHAR(tty));
- }
- if (tty->termios->c_cflag & CRTSCTS)
- info->MCR |= UART_MCR_RTS;
- save_flags(flags); cli();
- serial_out(info, UART_MCR, info->MCR);
- restore_flags(flags);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct async_struct * info,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
- struct serial_state *state = info->state;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = state->type;
- tmp.line = state->line;
- tmp.port = state->port;
- if (HIGH_BITS_OFFSET)
- tmp.port_high = state->port >> HIGH_BITS_OFFSET;
- else
- tmp.port_high = 0;
- tmp.irq = state->irq;
- tmp.flags = state->flags;
- tmp.xmit_fifo_size = state->xmit_fifo_size;
- tmp.baud_base = state->baud_base;
- tmp.close_delay = state->close_delay;
- tmp.closing_wait = state->closing_wait;
- tmp.custom_divisor = state->custom_divisor;
- tmp.hub6 = state->hub6;
- tmp.io_type = state->io_type;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int set_serial_info(struct async_struct * info,
- struct serial_struct * new_info)
-{
- struct serial_struct new_serial;
- struct serial_state old_state, *state;
- unsigned int i,change_irq,change_port;
- int retval = 0;
- unsigned long new_port;
-
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- state = info->state;
- old_state = *state;
-
- new_port = new_serial.port;
- if (HIGH_BITS_OFFSET)
- new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
-
- change_irq = new_serial.irq != state->irq;
- change_port = (new_port != ((int) state->port)) ||
- (new_serial.hub6 != state->hub6);
-
- if (!capable(CAP_SYS_ADMIN)) {
- if (change_irq || change_port ||
- (new_serial.baud_base != state->baud_base) ||
- (new_serial.type != state->type) ||
- (new_serial.close_delay != state->close_delay) ||
- (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
- (state->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- state->flags = ((state->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- state->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- new_serial.irq = irq_cannonicalize(new_serial.irq);
-
- if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
- (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
- (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
- (new_serial.type == PORT_STARTECH)) {
- return -EINVAL;
- }
-
- if ((new_serial.type != state->type) ||
- (new_serial.xmit_fifo_size <= 0))
- new_serial.xmit_fifo_size =
- uart_config[new_serial.type].dfl_xmit_fifo_size;
-
- /* Make sure address is not already in use */
- if (new_serial.type) {
- for (i = 0 ; i < NR_PORTS; i++)
- if ((state != &rs_table[i]) &&
- (rs_table[i].port == new_port) &&
- rs_table[i].type)
- return -EADDRINUSE;
- }
-
- if ((change_port || change_irq) && (state->count > 1))
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- state->baud_base = new_serial.baud_base;
- state->flags = ((state->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
- (info->flags & ASYNC_INTERNAL_FLAGS));
- state->custom_divisor = new_serial.custom_divisor;
- state->close_delay = new_serial.close_delay * HZ/100;
- state->closing_wait = new_serial.closing_wait * HZ/100;
-#if (LINUX_VERSION_CODE > 0x20100)
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-#endif
- info->xmit_fifo_size = state->xmit_fifo_size =
- new_serial.xmit_fifo_size;
-
- if ((state->type != PORT_UNKNOWN) && state->port) {
-#ifdef CONFIG_SERIAL_RSA
- if (old_state.type == PORT_RSA)
- release_region(state->port + UART_RSA_BASE, 16);
- else
-#endif
- release_region(state->port,8);
- }
- state->type = new_serial.type;
- if (change_port || change_irq) {
- /*
- * We need to shutdown the serial port at the old
- * port/irq combination.
- */
- shutdown(info);
- state->irq = new_serial.irq;
- info->port = state->port = new_port;
- info->hub6 = state->hub6 = new_serial.hub6;
- if (info->hub6)
- info->io_type = state->io_type = SERIAL_IO_HUB6;
- else if (info->io_type == SERIAL_IO_HUB6)
- info->io_type = state->io_type = SERIAL_IO_PORT;
- }
- if ((state->type != PORT_UNKNOWN) && state->port) {
-#ifdef CONFIG_SERIAL_RSA
- if (state->type == PORT_RSA)
- request_region(state->port + UART_RSA_BASE,
- 16, "serial_rsa(set)");
- else
-#endif
- request_region(state->port,8,"serial(set)");
- }
-
-
-check_and_exit:
- if (!state->port || !state->type)
- return 0;
- if (info->flags & ASYNC_INITIALIZED) {
- if (((old_state.flags & ASYNC_SPD_MASK) !=
- (state->flags & ASYNC_SPD_MASK)) ||
- (old_state.custom_divisor != state->custom_divisor)) {
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->tty->alt_speed = 57600;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- info->tty->alt_speed = 115200;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- info->tty->alt_speed = 230400;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->tty->alt_speed = 460800;
-#endif
- change_speed(info, 0);
- }
- } else
- retval = startup(info);
- return retval;
-}
-
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct async_struct * info, unsigned int *value)
-{
- unsigned char status;
- unsigned int result;
- unsigned long flags;
-
- save_flags(flags); cli();
- status = serial_in(info, UART_LSR);
- restore_flags(flags);
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-
- /*
- * If we're about to load something into the transmit
- * register, we'll pretend the transmitter isn't empty to
- * avoid a race condition (depending on when the transmit
- * interrupt happens).
- */
- if (info->x_char ||
- ((CIRC_CNT(info->xmit.head, info->xmit.tail,
- SERIAL_XMIT_SIZE) > 0) &&
- !info->tty->stopped && !info->tty->hw_stopped))
- result &= ~TIOCSER_TEMT;
-
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
- return 0;
-}
-
-
-static int get_modem_info(struct async_struct * info, unsigned int *value)
-{
- unsigned char control, status;
- unsigned int result;
- unsigned long flags;
-
- control = info->MCR;
- save_flags(flags); cli();
- status = serial_in(info, UART_MSR);
- restore_flags(flags);
- result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-#ifdef TIOCM_OUT1
- | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
- | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
-#endif
- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
- return 0;
-}
-
-static int set_modem_info(struct async_struct * info, unsigned int cmd,
- unsigned int *value)
-{
- unsigned int arg;
- unsigned long flags;
-
- if (copy_from_user(&arg, value, sizeof(int)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS)
- info->MCR |= UART_MCR_RTS;
- if (arg & TIOCM_DTR)
- info->MCR |= UART_MCR_DTR;
-#ifdef TIOCM_OUT1
- if (arg & TIOCM_OUT1)
- info->MCR |= UART_MCR_OUT1;
- if (arg & TIOCM_OUT2)
- info->MCR |= UART_MCR_OUT2;
-#endif
- if (arg & TIOCM_LOOP)
- info->MCR |= UART_MCR_LOOP;
- break;
- case TIOCMBIC:
- if (arg & TIOCM_RTS)
- info->MCR &= ~UART_MCR_RTS;
- if (arg & TIOCM_DTR)
- info->MCR &= ~UART_MCR_DTR;
-#ifdef TIOCM_OUT1
- if (arg & TIOCM_OUT1)
- info->MCR &= ~UART_MCR_OUT1;
- if (arg & TIOCM_OUT2)
- info->MCR &= ~UART_MCR_OUT2;
-#endif
- if (arg & TIOCM_LOOP)
- info->MCR &= ~UART_MCR_LOOP;
- break;
- case TIOCMSET:
- info->MCR = ((info->MCR & ~(UART_MCR_RTS |
-#ifdef TIOCM_OUT1
- UART_MCR_OUT1 |
- UART_MCR_OUT2 |
-#endif
- UART_MCR_LOOP |
- UART_MCR_DTR))
- | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-#ifdef TIOCM_OUT1
- | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
- | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
-#endif
- | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
- | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
- break;
- default:
- return -EINVAL;
- }
- save_flags(flags); cli();
- info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
- serial_out(info, UART_MCR, info->MCR);
- restore_flags(flags);
- return 0;
-}
-
-static int do_autoconfig(struct async_struct * info)
-{
- int irq, retval;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (info->state->count > 1)
- return -EBUSY;
-
- shutdown(info);
-
- autoconfig(info->state);
- if ((info->state->flags & ASYNC_AUTO_IRQ) &&
- (info->state->port != 0 || info->state->iomem_base != 0) &&
- (info->state->type != PORT_UNKNOWN)) {
- irq = detect_uart_irq(info->state);
- if (irq > 0)
- info->state->irq = irq;
- }
-
- retval = startup(info);
- if (retval)
- return retval;
- return 0;
-}
-
-/*
- * rs_break() --- routine which turns the break handling on or off
- */
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static void send_break( struct async_struct * info, int duration)
-{
- if (!CONFIGURED_SERIAL_PORT(info))
- return;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + duration;
- cli();
- info->LCR |= UART_LCR_SBC;
- serial_out(info, UART_LCR, info->LCR);
- schedule();
- info->LCR &= ~UART_LCR_SBC;
- serial_out(info, UART_LCR, info->LCR);
- sti();
-}
-#else
-static void rs_break(struct tty_struct *tty, int break_state)
-{
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_break"))
- return;
-
- if (!CONFIGURED_SERIAL_PORT(info))
- return;
- save_flags(flags); cli();
- if (break_state == -1)
- info->LCR |= UART_LCR_SBC;
- else
- info->LCR &= ~UART_LCR_SBC;
- serial_out(info, UART_LCR, info->LCR);
- restore_flags(flags);
-}
-#endif
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-static int get_multiport_struct(struct async_struct * info,
- struct serial_multiport_struct *retinfo)
-{
- struct serial_multiport_struct ret;
- struct rs_multiport_struct *multi;
-
- multi = &rs_multiport[info->state->irq];
-
- ret.port_monitor = multi->port_monitor;
-
- ret.port1 = multi->port1;
- ret.mask1 = multi->mask1;
- ret.match1 = multi->match1;
-
- ret.port2 = multi->port2;
- ret.mask2 = multi->mask2;
- ret.match2 = multi->match2;
-
- ret.port3 = multi->port3;
- ret.mask3 = multi->mask3;
- ret.match3 = multi->match3;
-
- ret.port4 = multi->port4;
- ret.mask4 = multi->mask4;
- ret.match4 = multi->match4;
-
- ret.irq = info->state->irq;
-
- if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int set_multiport_struct(struct async_struct * info,
- struct serial_multiport_struct *in_multi)
-{
- struct serial_multiport_struct new_multi;
- struct rs_multiport_struct *multi;
- struct serial_state *state;
- int was_multi, now_multi;
- int retval;
- void (*handler)(int, void *, struct pt_regs *);
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- state = info->state;
-
- if (copy_from_user(&new_multi, in_multi,
- sizeof(struct serial_multiport_struct)))
- return -EFAULT;
-
- if (new_multi.irq != state->irq || state->irq == 0 ||
- !IRQ_ports[state->irq])
- return -EINVAL;
-
- multi = &rs_multiport[state->irq];
- was_multi = (multi->port1 != 0);
-
- multi->port_monitor = new_multi.port_monitor;
-
- if (multi->port1)
- release_region(multi->port1,1);
- multi->port1 = new_multi.port1;
- multi->mask1 = new_multi.mask1;
- multi->match1 = new_multi.match1;
- if (multi->port1)
- request_region(multi->port1,1,"serial(multiport1)");
-
- if (multi->port2)
- release_region(multi->port2,1);
- multi->port2 = new_multi.port2;
- multi->mask2 = new_multi.mask2;
- multi->match2 = new_multi.match2;
- if (multi->port2)
- request_region(multi->port2,1,"serial(multiport2)");
-
- if (multi->port3)
- release_region(multi->port3,1);
- multi->port3 = new_multi.port3;
- multi->mask3 = new_multi.mask3;
- multi->match3 = new_multi.match3;
- if (multi->port3)
- request_region(multi->port3,1,"serial(multiport3)");
-
- if (multi->port4)
- release_region(multi->port4,1);
- multi->port4 = new_multi.port4;
- multi->mask4 = new_multi.mask4;
- multi->match4 = new_multi.match4;
- if (multi->port4)
- request_region(multi->port4,1,"serial(multiport4)");
-
- now_multi = (multi->port1 != 0);
-
- if (IRQ_ports[state->irq]->next_port &&
- (was_multi != now_multi)) {
- free_irq(state->irq, &IRQ_ports[state->irq]);
- if (now_multi)
- handler = rs_interrupt_multi;
- else
- handler = rs_interrupt;
-
- retval = request_irq(state->irq, handler, SA_SHIRQ,
- "serial", &IRQ_ports[state->irq]);
- if (retval) {
- printk("Couldn't reallocate serial interrupt "
- "driver!!\n");
- }
- }
- return 0;
-}
-#endif
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- struct async_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct icount;
- unsigned long flags;
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- int retval, tmp;
-#endif
-
- if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- if (!arg) {
- send_break(info, HZ/4); /* 1/4 second */
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
- if (signal_pending(current))
- return -EINTR;
- return 0;
- case TIOCGSOFTCAR:
- tmp = C_CLOCAL(tty) ? 1 : 0;
- if (copy_to_user((void *)arg, &tmp, sizeof(int)))
- return -EFAULT;
- return 0;
- case TIOCSSOFTCAR:
- if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
- return -EFAULT;
-
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (tmp ? CLOCAL : 0));
- return 0;
-#endif
- case TIOCMGET:
- return get_modem_info(info, (unsigned int *) arg);
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- return set_modem_info(info, cmd, (unsigned int *) arg);
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSERCONFIG:
- return do_autoconfig(info);
-
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
-
- case TIOCSERGSTRUCT:
- if (copy_to_user((struct async_struct *) arg,
- info, sizeof(struct async_struct)))
- return -EFAULT;
- return 0;
-
-#ifdef CONFIG_SERIAL_MULTIPORT
- case TIOCSERGETMULTI:
- return get_multiport_struct(info,
- (struct serial_multiport_struct *) arg);
- case TIOCSERSETMULTI:
- return set_multiport_struct(info,
- (struct serial_multiport_struct *) arg);
-#endif
-
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
- case TIOCMIWAIT:
- save_flags(flags); cli();
- /* note the counters on entry */
- cprev = info->state->icount;
- restore_flags(flags);
- /* Force modem status interrupts on */
- info->IER |= UART_IER_MSI;
- serial_out(info, UART_IER, info->IER);
- while (1) {
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- save_flags(flags); cli();
- cnow = info->state->icount; /* atomic copy */
- restore_flags(flags);
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
-
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
- case TIOCGICOUNT:
- save_flags(flags); cli();
- cnow = info->state->icount;
- restore_flags(flags);
- icount.cts = cnow.cts;
- icount.dsr = cnow.dsr;
- icount.rng = cnow.rng;
- icount.dcd = cnow.dcd;
- icount.rx = cnow.rx;
- icount.tx = cnow.tx;
- icount.frame = cnow.frame;
- icount.overrun = cnow.overrun;
- icount.parity = cnow.parity;
- icount.brk = cnow.brk;
- icount.buf_overrun = cnow.buf_overrun;
-
- if (copy_to_user((void *)arg, &icount, sizeof(icount)))
- return -EFAULT;
- return 0;
- case TIOCSERGWILD:
- case TIOCSERSWILD:
- /* "setserial -W" is called in Debian boot */
- printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
- struct async_struct *info = (struct async_struct *)tty->driver_data;
- unsigned long flags;
- unsigned int cflag = tty->termios->c_cflag;
-
- if ( (cflag == old_termios->c_cflag)
- && ( RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
-
- change_speed(info, old_termios);
-
- /* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) &&
- !(cflag & CBAUD)) {
- info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
- save_flags(flags); cli();
- serial_out(info, UART_MCR, info->MCR);
- restore_flags(flags);
- }
-
- /* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- (cflag & CBAUD)) {
- info->MCR |= UART_MCR_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
- info->MCR |= UART_MCR_RTS;
- }
- save_flags(flags); cli();
- serial_out(info, UART_MCR, info->MCR);
- restore_flags(flags);
- }
-
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- rs_start(tty);
- }
-
-#if 0
- /*
- * No need to wake up processes in open wait, since they
- * sample the CLOCAL flag once, and don't recheck it.
- * XXX It's not clear whether the current behavior is correct
- * or not. Hence, this may change.....
- */
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&info->open_wait);
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- struct serial_state *state;
- unsigned long flags;
-
- if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
- return;
-
- state = info->state;
-
- save_flags(flags); cli();
-
- if (tty_hung_up_p(filp)) {
- DBG_CNT("before DEC-hung");
- MOD_DEC_USE_COUNT;
- restore_flags(flags);
- return;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
- if ((tty->count == 1) && (state->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. state->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("rs_close: bad serial port count; tty->count is 1, "
- "state->count is %d\n", state->count);
- state->count = 1;
- }
- if (--state->count < 0) {
- printk("rs_close: bad serial port count for ttys%d: %d\n",
- info->line, state->count);
- state->count = 0;
- }
- if (state->count) {
- DBG_CNT("before DEC-2");
- MOD_DEC_USE_COUNT;
- restore_flags(flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
- restore_flags(flags);
- /*
- * Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
- if (info->flags & ASYNC_NORMAL_ACTIVE)
- info->state->normal_termios = *tty->termios;
- if (info->flags & ASYNC_CALLOUT_ACTIVE)
- info->state->callout_termios = *tty->termios;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- info->IER &= ~UART_IER_RLSI;
- info->read_status_mask &= ~UART_LSR_DR;
- if (info->flags & ASYNC_INITIALIZED) {
- serial_out(info, UART_IER, info->IER);
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- rs_wait_until_sent(tty, info->timeout);
- }
- shutdown(info);
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- tty->closing = 0;
- info->event = 0;
- info->tty = 0;
- if (info->blocked_open) {
- if (info->close_delay) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(info->close_delay);
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
- ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- unsigned long orig_jiffies, char_time;
- int lsr;
-
- if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
- return;
-
- if (info->state->type == PORT_UNKNOWN)
- return;
-
- if (info->xmit_fifo_size == 0)
- return; /* Just in case.... */
-
- orig_jiffies = jiffies;
- /*
- * Set the check interval to be 1/5 of the estimated time to
- * send a single character, and make it at least 1. The check
- * interval should also be less than the timeout.
- *
- * Note: we have to use pretty tight timings here to satisfy
- * the NIST-PCTS.
- */
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
- char_time = char_time / 5;
- if (char_time == 0)
- char_time = 1;
- if (timeout && timeout < char_time)
- char_time = timeout;
- /*
- * If the transmitter hasn't cleared in twice the approximate
- * amount of time to send the entire FIFO, it probably won't
- * ever clear. This assumes the UART isn't doing flow
- * control, which is currently the case. Hence, if it ever
- * takes longer than info->timeout, this is probably due to a
- * UART bug of some kind. So, we clamp the timeout parameter at
- * 2*info->timeout.
- */
- if (!timeout || timeout > 2*info->timeout)
- timeout = 2*info->timeout;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
-#endif
- while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(char_time);
- if (signal_pending(current))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
- }
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
- struct async_struct * info = (struct async_struct *)tty->driver_data;
- struct serial_state *state = info->state;
-
- if (serial_paranoia_check(info, tty->device, "rs_hangup"))
- return;
-
- state = info->state;
-
- rs_flush_buffer(tty);
- if (info->flags & ASYNC_CLOSING)
- return;
- shutdown(info);
- info->event = 0;
- state->count = 0;
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
- info->tty = 0;
- wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct async_struct *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct serial_state *state = info->state;
- int retval;
- int do_clocal = 0, extra_count = 0;
- unsigned long flags;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- return ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If this is a callout device, then just make sure the normal
- * device isn't being used.
- */
- if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
- if (info->flags & ASYNC_NORMAL_ACTIVE)
- return -EBUSY;
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_SESSION_LOCKOUT) &&
- (info->session != current->session))
- return -EBUSY;
- if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_PGRP_LOCKOUT) &&
- (info->pgrp != current->pgrp))
- return -EBUSY;
- info->flags |= ASYNC_CALLOUT_ACTIVE;
- return 0;
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- if (info->flags & ASYNC_CALLOUT_ACTIVE)
- return -EBUSY;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- if (info->flags & ASYNC_CALLOUT_ACTIVE) {
- if (state->normal_termios.c_cflag & CLOCAL)
- do_clocal = 1;
- } else {
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
- }
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, state->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
- state->line, state->count);
-#endif
- save_flags(flags); cli();
- if (!tty_hung_up_p(filp)) {
- extra_count = 1;
- state->count--;
- }
- restore_flags(flags);
- info->blocked_open++;
- while (1) {
- save_flags(flags); cli();
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (tty->termios->c_cflag & CBAUD))
- serial_out(info, UART_MCR,
- serial_inp(info, UART_MCR) |
- (UART_MCR_DTR | UART_MCR_RTS));
- restore_flags(flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- !(info->flags & ASYNC_CLOSING) &&
- (do_clocal || (serial_in(info, UART_MSR) &
- UART_MSR_DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttys%d, count = %d\n",
- info->line, state->count);
-#endif
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->open_wait, &wait);
- if (extra_count)
- state->count++;
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
- info->line, state->count);
-#endif
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
-static int get_async_struct(int line, struct async_struct **ret_info)
-{
- struct async_struct *info;
- struct serial_state *sstate;
-
- sstate = rs_table + line;
- sstate->count++;
- info = sstate->info;
-
- /*
- * If the async_struct is already allocated, do the fastpath.
- */
- if (info)
- goto out;
-
- info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
- if (!info) {
- sstate->count--;
- return -ENOMEM;
- }
-
- memset(info, 0, sizeof(struct async_struct));
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- info->magic = SERIAL_MAGIC;
- info->port = sstate->port;
- info->hub6 = sstate->hub6;
- info->flags = sstate->flags;
- info->xmit_fifo_size = sstate->xmit_fifo_size;
- info->state = sstate;
- info->line = line;
- info->iomem_base = sstate->iomem_base;
- info->iomem_reg_shift = sstate->iomem_reg_shift;
- info->io_type = sstate->io_type;
- info->tqueue.routine = do_softint;
- info->tqueue.data = info;
-
- if (sstate->info) {
- kfree(info);
- info = sstate->info;
- } else {
- sstate->info = info;
- }
-
-out:
- /*
- * If this is the first open, copy over some timeouts.
- */
- if (sstate->count == 1) {
- info->closing_wait = sstate->closing_wait;
- }
- *ret_info = info;
- return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_open(struct tty_struct *tty, struct file * filp)
-{
- struct async_struct *info;
- int retval, line;
- unsigned long page;
-
- MOD_INC_USE_COUNT;
- line = minor(tty->device) - tty->driver.minor_start;
- if ((line < 0) || (line >= NR_PORTS)) {
- MOD_DEC_USE_COUNT;
- return -ENODEV;
- }
- retval = get_async_struct(line, &info);
- if (retval) {
- MOD_DEC_USE_COUNT;
- return retval;
- }
- tty->driver_data = info;
- info->tty = tty;
- if (serial_paranoia_check(info, tty->device, "rs_open")) {
- MOD_DEC_USE_COUNT;
- return -ENODEV;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
- info->state->count);
-#endif
-#if (LINUX_VERSION_CODE > 0x20100)
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-#endif
-
- /*
- * This relies on lock_kernel() stuff so wants tidying for 2.5
- */
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page) {
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
- }
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
-
- /*
- * If the port is the middle of closing, bail out now
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
- MOD_DEC_USE_COUNT;
-#ifdef SERIAL_DO_RESTART
- return ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval) {
- MOD_DEC_USE_COUNT;
- return retval;
- }
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open returning after block_til_ready with %d\n",
- retval);
-#endif
- MOD_DEC_USE_COUNT;
- return retval;
- }
-
- if ((info->state->count == 1) &&
- (info->flags & ASYNC_SPLIT_TERMIOS)) {
- if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->state->normal_termios;
- else
- *tty->termios = info->state->callout_termios;
- change_speed(info, 0);
- }
-#ifdef CONFIG_SERIAL_CONSOLE
- if (sercons.cflag && sercons.index == line) {
- tty->termios->c_cflag = sercons.cflag;
- sercons.cflag = 0;
- change_speed(info, 0);
- }
-#endif
- info->session = current->session;
- info->pgrp = current->pgrp;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open ttys%d successful...", info->line);
-#endif
- return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-static inline int line_info(char *buf, struct serial_state *state)
-{
- struct async_struct *info = state->info, scr_info;
- char stat_buf[30], control, status;
- int ret;
- unsigned long flags;
-
- ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
- state->line, uart_config[state->type].name,
- state->port, state->irq);
-
- if (!state->port || (state->type == PORT_UNKNOWN)) {
- ret += sprintf(buf+ret, "\n");
- return ret;
- }
-
- /*
- * Figure out the current RS-232 lines
- */
- if (!info) {
- info = &scr_info; /* This is just for serial_{in,out} */
-
- info->magic = SERIAL_MAGIC;
- info->port = state->port;
- info->flags = state->flags;
- info->hub6 = state->hub6;
- info->io_type = state->io_type;
- info->iomem_base = state->iomem_base;
- info->iomem_reg_shift = state->iomem_reg_shift;
- info->quot = 0;
- info->tty = 0;
- }
- save_flags(flags); cli();
- status = serial_in(info, UART_MSR);
- control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
- restore_flags(flags);
-
- stat_buf[0] = 0;
- stat_buf[1] = 0;
- if (control & UART_MCR_RTS)
- strcat(stat_buf, "|RTS");
- if (status & UART_MSR_CTS)
- strcat(stat_buf, "|CTS");
- if (control & UART_MCR_DTR)
- strcat(stat_buf, "|DTR");
- if (status & UART_MSR_DSR)
- strcat(stat_buf, "|DSR");
- if (status & UART_MSR_DCD)
- strcat(stat_buf, "|CD");
- if (status & UART_MSR_RI)
- strcat(stat_buf, "|RI");
-
- if (info->quot) {
- ret += sprintf(buf+ret, " baud:%d",
- state->baud_base / info->quot);
- }
-
- ret += sprintf(buf+ret, " tx:%d rx:%d",
- state->icount.tx, state->icount.rx);
-
- if (state->icount.frame)
- ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
-
- if (state->icount.parity)
- ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
-
- if (state->icount.brk)
- ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
-
- if (state->icount.overrun)
- ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
-
- /*
- * Last thing is the RS-232 status lines
- */
- ret += sprintf(buf+ret, " %s\n", stat_buf+1);
- return ret;
-}
-
-int rs_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int i, len = 0, l;
- off_t begin = 0;
-
- len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n",
- serial_version, LOCAL_VERSTRING, serial_revdate);
- for (i = 0; i < NR_PORTS && len < 4000; i++) {
- l = line_info(page + len, &rs_table[i]);
- len += l;
- if (len+begin > off+count)
- goto done;
- if (len+begin < off) {
- begin += len;
- len = 0;
- }
- }
- *eof = 1;
-done:
- if (off >= len+begin)
- return 0;
- *start = page + (off-begin);
- return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static char serial_options[] __initdata =
-#ifdef CONFIG_HUB6
- " HUB-6"
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
- " MANY_PORTS"
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_MULTIPORT
- " MULTIPORT"
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- " SHARE_IRQ"
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_DETECT_IRQ
- " DETECT_IRQ"
-#define SERIAL_OPT
-#endif
-#ifdef ENABLE_SERIAL_PCI
- " SERIAL_PCI"
-#define SERIAL_OPT
-#endif
-#ifdef ENABLE_SERIAL_PNP
- " ISAPNP"
-#define SERIAL_OPT
-#endif
-#ifdef ENABLE_SERIAL_ACPI
- " SERIAL_ACPI"
-#define SERIAL_OPT
-#endif
-#ifdef SERIAL_OPT
- " enabled\n";
-#else
- " no serial options enabled\n";
-#endif
-#undef SERIAL_OPT
-
-static _INLINE_ void show_serial_version(void)
-{
- printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
- serial_version, LOCAL_VERSTRING, serial_revdate,
- serial_options);
-}
-
-/*
- * This routine detect the IRQ of a serial port by clearing OUT2 when
- * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
- * each time, as long as no other device permanently request the IRQ.
- * If no IRQ is detected, or multiple IRQ appear, this function returns 0.
- * The variable "state" and the field "state->port" should not be null.
- */
-static unsigned detect_uart_irq (struct serial_state * state)
-{
- int irq;
- unsigned long irqs;
- unsigned char save_mcr, save_ier;
- struct async_struct scr_info; /* serial_{in,out} because HUB6 */
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
- unsigned char save_ICP=0; /* no warning */
- unsigned short ICP=0;
-
- if (state->flags & ASYNC_FOURPORT) {
- ICP = (state->port & 0xFE0) | 0x01F;
- save_ICP = inb_p(ICP);
- outb_p(0x80, ICP);
- (void) inb_p(ICP);
- }
-#endif
- scr_info.magic = SERIAL_MAGIC;
- scr_info.state = state;
- scr_info.port = state->port;
- scr_info.flags = state->flags;
-#ifdef CONFIG_HUB6
- scr_info.hub6 = state->hub6;
-#endif
- scr_info.io_type = state->io_type;
- scr_info.iomem_base = state->iomem_base;
- scr_info.iomem_reg_shift = state->iomem_reg_shift;
-
- /* forget possible initially masked and pending IRQ */
- probe_irq_off(probe_irq_on());
- save_mcr = serial_inp(&scr_info, UART_MCR);
- save_ier = serial_inp(&scr_info, UART_IER);
- serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
-
- irqs = probe_irq_on();
- serial_outp(&scr_info, UART_MCR, 0);
- udelay (10);
- if (state->flags & ASYNC_FOURPORT) {
- serial_outp(&scr_info, UART_MCR,
- UART_MCR_DTR | UART_MCR_RTS);
- } else {
- serial_outp(&scr_info, UART_MCR,
- UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
- }
- serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */
- (void)serial_inp(&scr_info, UART_LSR);
- (void)serial_inp(&scr_info, UART_RX);
- (void)serial_inp(&scr_info, UART_IIR);
- (void)serial_inp(&scr_info, UART_MSR);
- serial_outp(&scr_info, UART_TX, 0xFF);
- udelay (20);
- irq = probe_irq_off(irqs);
-
- serial_outp(&scr_info, UART_MCR, save_mcr);
- serial_outp(&scr_info, UART_IER, save_ier);
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (state->flags & ASYNC_FOURPORT)
- outb_p(save_ICP, ICP);
-#endif
- return (irq > 0)? irq : 0;
-}
-
-/*
- * This is a quickie test to see how big the FIFO is.
- * It doesn't work at all the time, more's the pity.
- */
-static int size_fifo(struct async_struct *info)
-{
- unsigned char old_fcr, old_mcr, old_dll, old_dlm;
- int count;
-
- old_fcr = serial_inp(info, UART_FCR);
- old_mcr = serial_inp(info, UART_MCR);
- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_outp(info, UART_MCR, UART_MCR_LOOP);
- serial_outp(info, UART_LCR, UART_LCR_DLAB);
- old_dll = serial_inp(info, UART_DLL);
- old_dlm = serial_inp(info, UART_DLM);
- serial_outp(info, UART_DLL, 0x01);
- serial_outp(info, UART_DLM, 0x00);
- serial_outp(info, UART_LCR, 0x03);
- for (count = 0; count < 256; count++)
- serial_outp(info, UART_TX, count);
- mdelay(20);
- for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) &&
- (count < 256); count++)
- serial_inp(info, UART_RX);
- serial_outp(info, UART_FCR, old_fcr);
- serial_outp(info, UART_MCR, old_mcr);
- serial_outp(info, UART_LCR, UART_LCR_DLAB);
- serial_outp(info, UART_DLL, old_dll);
- serial_outp(info, UART_DLM, old_dlm);
-
- return count;
-}
-
-/*
- * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
- * When this function is called we know it is at least a StarTech
- * 16650 V2, but it might be one of several StarTech UARTs, or one of
- * its clones. (We treat the broken original StarTech 16650 V1 as a
- * 16550, and why not? Startech doesn't seem to even acknowledge its
- * existence.)
- *
- * What evil have men's minds wrought...
- */
-static void autoconfig_startech_uarts(struct async_struct *info,
- struct serial_state *state,
- unsigned long flags)
-{
- unsigned char scratch, scratch2, scratch3, scratch4;
-
- /*
- * First we check to see if it's an Oxford Semiconductor UART.
- *
- * If we have to do this here because some non-National
- * Semiconductor clone chips lock up if you try writing to the
- * LSR register (which serial_icr_read does)
- */
- if (state->type == PORT_16550A) {
- /*
- * EFR [4] must be set else this test fails
- *
- * This shouldn't be necessary, but Mike Hudson
- * (Exoray@isys.ca) claims that it's needed for 952
- * dual UART's (which are not recommended for new designs).
- */
- info->ACR = 0;
- serial_out(info, UART_LCR, 0xBF);
- serial_out(info, UART_EFR, 0x10);
- serial_out(info, UART_LCR, 0x00);
- /* Check for Oxford Semiconductor 16C950 */
- scratch = serial_icr_read(info, UART_ID1);
- scratch2 = serial_icr_read(info, UART_ID2);
- scratch3 = serial_icr_read(info, UART_ID3);
-
- if (scratch == 0x16 && scratch2 == 0xC9 &&
- (scratch3 == 0x50 || scratch3 == 0x52 ||
- scratch3 == 0x54)) {
- state->type = PORT_16C950;
- state->revision = serial_icr_read(info, UART_REV) |
- (scratch3 << 8);
- return;
- }
- }
-
- /*
- * We check for a XR16C850 by setting DLL and DLM to 0, and
- * then reading back DLL and DLM. If DLM reads back 0x10,
- * then the UART is a XR16C850 and the DLL contains the chip
- * revision. If DLM reads back 0x14, then the UART is a
- * XR16C854.
- *
- */
-
- /* Save the DLL and DLM */
-
- serial_outp(info, UART_LCR, UART_LCR_DLAB);
- scratch3 = serial_inp(info, UART_DLL);
- scratch4 = serial_inp(info, UART_DLM);
-
- serial_outp(info, UART_DLL, 0);
- serial_outp(info, UART_DLM, 0);
- scratch2 = serial_inp(info, UART_DLL);
- scratch = serial_inp(info, UART_DLM);
- serial_outp(info, UART_LCR, 0);
-
- if (scratch == 0x10 || scratch == 0x14) {
- if (scratch == 0x10)
- state->revision = scratch2;
- state->type = PORT_16850;
- return;
- }
-
- /* Restore the DLL and DLM */
-
- serial_outp(info, UART_LCR, UART_LCR_DLAB);
- serial_outp(info, UART_DLL, scratch3);
- serial_outp(info, UART_DLM, scratch4);
- serial_outp(info, UART_LCR, 0);
- /*
- * We distinguish between the '654 and the '650 by counting
- * how many bytes are in the FIFO. I'm using this for now,
- * since that's the technique that was sent to me in the
- * serial driver update, but I'm not convinced this works.
- * I've had problems doing this in the past. -TYT
- */
- if (size_fifo(info) == 64)
- state->type = PORT_16654;
- else
- state->type = PORT_16650V2;
-}
-
-/*
- * This routine is called by rs_init() to initialize a specific serial
- * port. It determines what type of UART chip this serial port is
- * using: 8250, 16450, 16550, 16550A. The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
- */
-static void autoconfig(struct serial_state * state)
-{
- unsigned char status1, status2, scratch, scratch2, scratch3;
- unsigned char save_lcr, save_mcr;
- struct async_struct *info, scr_info;
- unsigned long flags;
-
- state->type = PORT_UNKNOWN;
-
-#ifdef SERIAL_DEBUG_AUTOCONF
- printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
- state->port, (unsigned) state->iomem_base);
-#endif
-
- if (!CONFIGURED_SERIAL_PORT(state))
- return;
-
- info = &scr_info; /* This is just for serial_{in,out} */
-
- info->magic = SERIAL_MAGIC;
- info->state = state;
- info->port = state->port;
- info->flags = state->flags;
-#ifdef CONFIG_HUB6
- info->hub6 = state->hub6;
-#endif
- info->io_type = state->io_type;
- info->iomem_base = state->iomem_base;
- info->iomem_reg_shift = state->iomem_reg_shift;
-
- save_flags(flags); cli();
-
- if (!(state->flags & ASYNC_BUGGY_UART) &&
- !state->iomem_base) {
- /*
- * Do a simple existence test first; if we fail this,
- * there's no point trying anything else.
- *
- * 0x80 is used as a nonsense port to prevent against
- * false positives due to ISA bus float. The
- * assumption is that 0x80 is a non-existent port;
- * which should be safe since include/asm/io.h also
- * makes this assumption.
- */
- scratch = serial_inp(info, UART_IER);
- serial_outp(info, UART_IER, 0);
-#ifdef __i386__
- outb(0xff, 0x080);
-#endif
- scratch2 = serial_inp(info, UART_IER);
- serial_outp(info, UART_IER, 0x0F);
-#ifdef __i386__
- outb(0, 0x080);
-#endif
- scratch3 = serial_inp(info, UART_IER);
- serial_outp(info, UART_IER, scratch);
- if (scratch2 || scratch3 != 0x0F) {
-#ifdef SERIAL_DEBUG_AUTOCONF
- printk("serial: ttyS%d: simple autoconfig failed "
- "(%02x, %02x)\n", state->line,
- scratch2, scratch3);
-#endif
- restore_flags(flags);
- return; /* We failed; there's nothing here */
- }
- }
-
- save_mcr = serial_in(info, UART_MCR);
- save_lcr = serial_in(info, UART_LCR);
-
- /*
- * Check to see if a UART is really there. Certain broken
- * internal modems based on the Rockwell chipset fail this
- * test, because they apparently don't implement the loopback
- * test mode. So this test is skipped on the COM 1 through
- * COM 4 ports. This *should* be safe, since no board
- * manufacturer would be stupid enough to design a board
- * that conflicts with COM 1-4 --- we hope!
- */
- if (!(state->flags & ASYNC_SKIP_TEST)) {
- serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
- status1 = serial_inp(info, UART_MSR) & 0xF0;
- serial_outp(info, UART_MCR, save_mcr);
- if (status1 != 0x90) {
-#ifdef SERIAL_DEBUG_AUTOCONF
- printk("serial: ttyS%d: no UART loopback failed\n",
- state->line);
-#endif
- restore_flags(flags);
- return;
- }
- }
- serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
- serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
- serial_outp(info, UART_LCR, 0);
- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
- scratch = serial_in(info, UART_IIR) >> 6;
- switch (scratch) {
- case 0:
- state->type = PORT_16450;
- break;
- case 1:
- state->type = PORT_UNKNOWN;
- break;
- case 2:
- state->type = PORT_16550;
- break;
- case 3:
- state->type = PORT_16550A;
- break;
- }
- if (state->type == PORT_16550A) {
- /* Check for Startech UART's */
- serial_outp(info, UART_LCR, UART_LCR_DLAB);
- if (serial_in(info, UART_EFR) == 0) {
- state->type = PORT_16650;
- } else {
- serial_outp(info, UART_LCR, 0xBF);
- if (serial_in(info, UART_EFR) == 0)
- autoconfig_startech_uarts(info, state, flags);
- }
- }
- if (state->type == PORT_16550A) {
- /* Check for TI 16750 */
- serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB);
- serial_outp(info, UART_FCR,
- UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
- scratch = serial_in(info, UART_IIR) >> 5;
- if (scratch == 7) {
- /*
- * If this is a 16750, and not a cheap UART
- * clone, then it should only go into 64 byte
- * mode if the UART_FCR7_64BYTE bit was set
- * while UART_LCR_DLAB was latched.
- */
- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(info, UART_LCR, 0);
- serial_outp(info, UART_FCR,
- UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
- scratch = serial_in(info, UART_IIR) >> 5;
- if (scratch == 6)
- state->type = PORT_16750;
- }
- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
- }
-#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
- if (state->type == PORT_16550A) {
- int i;
-
- for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
- if (!probe_rsa[i] && !force_rsa[i])
- break;
- if (((probe_rsa[i] != state->port) ||
- check_region(state->port + UART_RSA_BASE, 16)) &&
- (force_rsa[i] != state->port))
- continue;
- if (!enable_rsa(info))
- continue;
- state->type = PORT_RSA;
- state->baud_base = SERIAL_RSA_BAUD_BASE;
- break;
- }
- }
-#endif
- serial_outp(info, UART_LCR, save_lcr);
- if (state->type == PORT_16450) {
- scratch = serial_in(info, UART_SCR);
- serial_outp(info, UART_SCR, 0xa5);
- status1 = serial_in(info, UART_SCR);
- serial_outp(info, UART_SCR, 0x5a);
- status2 = serial_in(info, UART_SCR);
- serial_outp(info, UART_SCR, scratch);
-
- if ((status1 != 0xa5) || (status2 != 0x5a))
- state->type = PORT_8250;
- }
- state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
-
- if (state->type == PORT_UNKNOWN) {
- restore_flags(flags);
- return;
- }
-
- if (info->port) {
-#ifdef CONFIG_SERIAL_RSA
- if (state->type == PORT_RSA)
- request_region(info->port + UART_RSA_BASE, 16,
- "serial_rsa(auto)");
- else
-#endif
- request_region(info->port,8,"serial(auto)");
- }
-
- /*
- * Reset the UART.
- */
-#ifdef CONFIG_SERIAL_RSA
- if (state->type == PORT_RSA)
- serial_outp(info, UART_RSA_FRR, 0);
-#endif
- serial_outp(info, UART_MCR, save_mcr);
- serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT));
- serial_outp(info, UART_FCR, 0);
- (void)serial_in(info, UART_RX);
- serial_outp(info, UART_IER, 0);
-
- restore_flags(flags);
-}
-
-int register_serial(struct serial_struct *req);
-void unregister_serial(int line);
-
-#if (LINUX_VERSION_CODE > 0x20100)
-EXPORT_SYMBOL(register_serial);
-EXPORT_SYMBOL(unregister_serial);
-#else
-static struct symbol_table serial_syms = {
-#include <linux/symtab_begin.h>
- X(register_serial),
- X(unregister_serial),
-#include <linux/symtab_end.h>
-};
-#endif
-
-
-#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
-
-static void __devinit printk_pnp_dev_id(unsigned short vendor,
- unsigned short device)
-{
- printk("%c%c%c%x%x%x%x",
- 'A' + ((vendor >> 2) & 0x3f) - 1,
- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
- 'A' + ((vendor >> 8) & 0x1f) - 1,
- (device >> 4) & 0x0f,
- device & 0x0f,
- (device >> 12) & 0x0f,
- (device >> 8) & 0x0f);
-}
-
-static _INLINE_ int get_pci_port(struct pci_dev *dev,
- struct pci_board *board,
- struct serial_struct *req,
- int idx)
-{
- unsigned long port;
- int base_idx;
- int max_port;
- int offset;
-
- base_idx = SPCI_FL_GET_BASE(board->flags);
- if (board->flags & SPCI_FL_BASE_TABLE)
- base_idx += idx;
-
- if (board->flags & SPCI_FL_REGION_SZ_CAP) {
- max_port = pci_resource_len(dev, base_idx) / 8;
- if (idx >= max_port)
- return 1;
- }
-
- offset = board->first_uart_offset;
-
- /* Timedia/SUNIX uses a mixture of BARs and offsets */
- /* Ugh, this is ugly as all hell --- TYT */
- if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */
- switch(idx) {
- case 0: base_idx=0;
- break;
- case 1: base_idx=0; offset=8;
- break;
- case 2: base_idx=1;
- break;
- case 3: base_idx=1; offset=8;
- break;
- case 4: /* BAR 2*/
- case 5: /* BAR 3 */
- case 6: /* BAR 4*/
- case 7: base_idx=idx-2; /* BAR 5*/
- }
-
- /* Some Titan cards are also a little weird */
- if (dev->vendor == PCI_VENDOR_ID_TITAN &&
- (dev->device == PCI_DEVICE_ID_TITAN_400L ||
- dev->device == PCI_DEVICE_ID_TITAN_800L)) {
- switch (idx) {
- case 0: base_idx = 1;
- break;
- case 1: base_idx = 2;
- break;
- default:
- base_idx = 4;
- offset = 8 * (idx - 2);
- }
-
- }
-
- port = pci_resource_start(dev, base_idx) + offset;
-
- if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
- port += idx * (board->uart_offset ? board->uart_offset : 8);
-
- if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
- req->port = port;
- if (HIGH_BITS_OFFSET)
- req->port_high = port >> HIGH_BITS_OFFSET;
- else
- req->port_high = 0;
- return 0;
- }
- req->io_type = SERIAL_IO_MEM;
- req->iomem_base = ioremap(port, board->uart_offset);
- req->iomem_reg_shift = board->reg_shift;
- req->port = 0;
- return 0;
-}
-
-static _INLINE_ int get_pci_irq(struct pci_dev *dev,
- struct pci_board *board,
- int idx)
-{
- int base_idx;
-
- if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
- return dev->irq;
-
- base_idx = SPCI_FL_GET_IRQBASE(board->flags);
- if (board->flags & SPCI_FL_IRQ_TABLE)
- base_idx += idx;
-
- return PCI_IRQ_RESOURCE(dev, base_idx);
-}
-
-/*
- * Common enabler code shared by both PCI and ISAPNP probes
- */
-static void __devinit start_pci_pnp_board(struct pci_dev *dev,
- struct pci_board *board)
-{
- int k, line;
- struct serial_struct serial_req;
- int base_baud;
-
- if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
- printk("serial: PNP device '");
- printk_pnp_dev_id(dev->vendor, dev->device);
- printk("' prepare failed\n");
- return;
- }
-
- if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
- printk("serial: PNP device '");
- printk_pnp_dev_id(dev->vendor, dev->device);
- printk("' activate failed\n");
- return;
- }
-
- /*
- * Run the initialization function, if any
- */
- if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
- return;
-
- /*
- * Register the serial board in the array if we need to
- * shutdown the board on a module unload or card removal
- */
- if (DEACTIVATE_FUNC(dev) || board->init_fn) {
- for (k=0; k < NR_PCI_BOARDS; k++)
- if (serial_pci_board[k].dev == 0)
- break;
- if (k >= NR_PCI_BOARDS)
- return;
- serial_pci_board[k].board = *board;
- serial_pci_board[k].dev = dev;
- }
-
- base_baud = board->base_baud;
- if (!base_baud)
- base_baud = BASE_BAUD;
- memset(&serial_req, 0, sizeof(serial_req));
-
- for (k=0; k < board->num_ports; k++) {
- serial_req.irq = get_pci_irq(dev, board, k);
- if (get_pci_port(dev, board, &serial_req, k))
- break;
- serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
-#ifdef SERIAL_DEBUG_PCI
- printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
- serial_req.port, serial_req.irq, serial_req.io_type);
-#endif
- line = register_serial(&serial_req);
- if (line < 0)
- break;
- rs_table[line].baud_base = base_baud;
- rs_table[line].dev = dev;
- }
-}
-#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
-
-#ifdef ENABLE_SERIAL_PCI
-/*
- * Some PCI serial cards using the PLX 9050 PCI interface chip require
- * that the card interrupt be explicitly enabled or disabled. This
- * seems to be mainly needed on card using the PLX which also use I/O
- * mapped memory.
- */
-static int __devinit
-pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
-{
- u8 data, *p, irq_config;
- int pci_config;
-
- irq_config = 0x41;
- pci_config = PCI_COMMAND_MEMORY;
- if (dev->vendor == PCI_VENDOR_ID_PANACOM)
- irq_config = 0x43;
- if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
- (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) {
- /*
- * As the megawolf cards have the int pins active
- * high, and have 2 UART chips, both ints must be
- * enabled on the 9050. Also, the UARTS are set in
- * 16450 mode by default, so we have to enable the
- * 16C950 'enhanced' mode so that we can use the deep
- * FIFOs
- */
- irq_config = 0x5b;
- pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
- }
-
- pci_read_config_byte(dev, PCI_COMMAND, &data);
-
- if (enable)
- pci_write_config_byte(dev, PCI_COMMAND,
- data | pci_config);
-
- /* enable/disable interrupts */
- p = ioremap(pci_resource_start(dev, 0), 0x80);
- writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
- iounmap(p);
-
- if (!enable)
- pci_write_config_byte(dev, PCI_COMMAND,
- data & ~pci_config);
- return 0;
-}
-
-
-/*
- * SIIG serial cards have an PCI interface chip which also controls
- * the UART clocking frequency. Each UART can be clocked independently
- * (except cards equiped with 4 UARTs) and initial clocking settings
- * are stored in the EEPROM chip. It can cause problems because this
- * version of serial driver doesn't support differently clocked UART's
- * on single PCI card. To prevent this, initialization functions set
- * high frequency clocking for all UART's on given card. It is safe (I
- * hope) because it doesn't touch EEPROM settings to prevent conflicts
- * with other OSes (like M$ DOS).
- *
- * SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999
- *
- * There is two family of SIIG serial cards with different PCI
- * interface chip and different configuration methods:
- * - 10x cards have control registers in IO and/or memory space;
- * - 20x cards have control registers in standard PCI configuration space.
- */
-
-#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
-#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
-
-static int __devinit
-pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
-{
- u16 data, *p;
-
- if (!enable) return 0;
-
- p = ioremap(pci_resource_start(dev, 0), 0x80);
-
- switch (dev->device & 0xfff8) {
- case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
- data = 0xffdf;
- break;
- case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
- data = 0xf7ff;
- break;
- default: /* 1S1P, 4S */
- data = 0xfffb;
- break;
- }
-
- writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
- iounmap(p);
- return 0;
-}
-
-#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
-#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
-
-static int __devinit
-pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
-{
- u8 data;
-
- if (!enable) return 0;
-
- /* Change clock frequency for the first UART. */
- pci_read_config_byte(dev, 0x6f, &data);
- pci_write_config_byte(dev, 0x6f, data & 0xef);
-
- /* If this card has 2 UART, we have to do the same with second UART. */
- if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
- ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
- pci_read_config_byte(dev, 0x73, &data);
- pci_write_config_byte(dev, 0x73, data & 0xef);
- }
- return 0;
-}
-
-/* Added for EKF Intel i960 serial boards */
-static int __devinit
-pci_inteli960ni_fn(struct pci_dev *dev,
- struct pci_board *board,
- int enable)
-{
- unsigned long oldval;
-
- if (!(pci_get_subdevice(dev) & 0x1000))
- return(-1);
-
- if (!enable) /* is there something to deinit? */
- return(0);
-
-#ifdef SERIAL_DEBUG_PCI
- printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n",
- (unsigned long) board->subdevice);
-#endif
- /* is firmware started? */
- pci_read_config_dword(dev, 0x44, (void*) &oldval);
- if (oldval == 0x00001000L) { /* RESET value */
- printk(KERN_DEBUG "Local i960 firmware missing");
- return(-1);
- }
- return(0);
-}
-
-/*
- * Timedia has an explosion of boards, and to avoid the PCI table from
- * growing *huge*, we use this function to collapse some 70 entries
- * in the PCI table into one, for sanity's and compactness's sake.
- */
-static unsigned short timedia_single_port[] = {
- 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 };
-static unsigned short timedia_dual_port[] = {
- 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
- 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
- 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
- 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
- 0xD079, 0 };
-static unsigned short timedia_quad_port[] = {
- 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
- 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
- 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
- 0xB157, 0 };
-static unsigned short timedia_eight_port[] = {
- 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
- 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 };
-static struct timedia_struct {
- int num;
- unsigned short *ids;
-} timedia_data[] = {
- { 1, timedia_single_port },
- { 2, timedia_dual_port },
- { 4, timedia_quad_port },
- { 8, timedia_eight_port },
- { 0, 0 }
-};
-
-static int __devinit
-pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
-{
- int i, j;
- unsigned short *ids;
-
- if (!enable)
- return 0;
-
- for (i=0; timedia_data[i].num; i++) {
- ids = timedia_data[i].ids;
- for (j=0; ids[j]; j++) {
- if (pci_get_subdevice(dev) == ids[j]) {
- board->num_ports = timedia_data[i].num;
- return 0;
- }
- }
- }
- return 0;
-}
-
-static int __devinit
-pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
-{
- __set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/10);
- return 0;
-}
-
-/*
- * This is the configuration table for all of the PCI serial boards
- * which we support. It is directly indexed by the pci_board_num_t enum
- * value, which is encoded in the pci_device_id PCI probe table's
- * driver_data member.
- */
-enum pci_board_num_t {
- pbn_b0_1_115200,
- pbn_default = 0,
-
- pbn_b0_2_115200,
- pbn_b0_4_115200,
-
- pbn_b0_1_921600,
- pbn_b0_2_921600,
- pbn_b0_4_921600,
-
- pbn_b0_bt_1_115200,
- pbn_b0_bt_2_115200,
- pbn_b0_bt_1_460800,
- pbn_b0_bt_2_460800,
-
- pbn_b1_1_115200,
- pbn_b1_2_115200,
- pbn_b1_4_115200,
- pbn_b1_8_115200,
-
- pbn_b1_2_921600,
- pbn_b1_4_921600,
- pbn_b1_8_921600,
-
- pbn_b1_2_1382400,
- pbn_b1_4_1382400,
- pbn_b1_8_1382400,
-
- pbn_b2_8_115200,
- pbn_b2_4_460800,
- pbn_b2_8_460800,
- pbn_b2_16_460800,
- pbn_b2_4_921600,
- pbn_b2_8_921600,
-
- pbn_b2_bt_1_115200,
- pbn_b2_bt_2_115200,
- pbn_b2_bt_4_115200,
- pbn_b2_bt_2_921600,
-
- pbn_panacom,
- pbn_panacom2,
- pbn_panacom4,
- pbn_plx_romulus,
- pbn_oxsemi,
- pbn_timedia,
- pbn_intel_i960,
- pbn_sgi_ioc3,
-#ifdef CONFIG_DDB5074
- pbn_nec_nile4,
-#endif
-#if 0
- pbn_dci_pccom8,
-#endif
- pbn_xircom_combo,
-
- pbn_siig10x_0,
- pbn_siig10x_1,
- pbn_siig10x_2,
- pbn_siig10x_4,
- pbn_siig20x_0,
- pbn_siig20x_2,
- pbn_siig20x_4,
-
- pbn_computone_4,
- pbn_computone_6,
- pbn_computone_8,
-};
-
-static struct pci_board pci_boards[] __devinitdata = {
- /*
- * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
- * Offset to get to next UART's registers,
- * Register shift to use for memory-mapped I/O,
- * Initialization function, first UART offset
- */
-
- /* Generic serial board, pbn_b0_1_115200, pbn_default */
- { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200,
- pbn_default */
-
- { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */
- { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */
-
- { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */
- { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */
- { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */
-
- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
-
- { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */
- { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */
- { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */
- { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */
-
- { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */
- { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */
- { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */
-
- { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */
- { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */
- { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */
-
- { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */
- { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */
- { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */
- { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */
- { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */
- { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */
-
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
-
- { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */
- 0x400, 7, pci_plx9050_fn },
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */
- 0x400, 7, pci_plx9050_fn },
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */
- 0x400, 7, pci_plx9050_fn },
- { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */
- 0x20, 2, pci_plx9050_fn, 0x03 },
- /* This board uses the size of PCI Base region 0 to
- * signal now many ports are available */
- { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
- { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */
- 0, 0, pci_timedia_fn },
- /* EKF addition for i960 Boards form EKF with serial port */
- { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */
- 8<<2, 2, pci_inteli960ni_fn, 0x10000},
- { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */
- 1, 458333, 0, 0, 0, 0x20178 },
-#ifdef CONFIG_DDB5074
- /*
- * NEC Vrc-5074 (Nile 4) builtin UART.
- * Conditionally compiled in since this is a motherboard device.
- */
- { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */
- 64, 3, NULL, 0x300 },
-#endif
-#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ /* pbn_dci_pccom8 */
- { SPCI_FL_BASE3, 8, 115200, 8 },
-#endif
- { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */
- 0, 0, pci_xircom_fn },
-
- { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */
- 0, 0, pci_siig10x_fn },
- { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */
- 0, 0, pci_siig10x_fn },
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */
- 0, 0, pci_siig10x_fn },
- { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */
- 0, 0, pci_siig10x_fn },
- { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */
- 0, 0, pci_siig20x_fn },
- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */
- 0, 0, pci_siig20x_fn },
- { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */
- 0, 0, pci_siig20x_fn },
-
- { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */
- 0x40, 2, NULL, 0x200 },
- { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */
- 0x40, 2, NULL, 0x200 },
- { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */
- 0x40, 2, NULL, 0x200 },
-};
-
-/*
- * Given a complete unknown PCI device, try to use some heuristics to
- * guess what the configuration might be, based on the pitiful PCI
- * serial specs. Returns 0 on success, 1 on failure.
- */
-static int __devinit serial_pci_guess_board(struct pci_dev *dev,
- struct pci_board *board)
-{
- int num_iomem = 0, num_port = 0, first_port = -1;
- int i;
-
- /*
- * If it is not a communications device or the programming
- * interface is greater than 6, give up.
- *
- * (Should we try to make guesses for multiport serial devices
- * later?)
- */
- if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
- ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
- (dev->class & 0xff) > 6)
- return 1;
-
- for (i=0; i < 6; i++) {
- if (IS_PCI_REGION_IOPORT(dev, i)) {
- num_port++;
- if (first_port == -1)
- first_port = i;
- }
- if (IS_PCI_REGION_IOMEM(dev, i))
- num_iomem++;
- }
-
- /*
- * If there is 1 or 0 iomem regions, and exactly one port, use
- * it.
- */
- if (num_iomem <= 1 && num_port == 1) {
- board->flags = first_port;
- return 0;
- }
- return 1;
-}
-
-static int __devinit serial_init_one(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- struct pci_board *board, tmp;
- int rc;
-
- board = &pci_boards[ent->driver_data];
-
- rc = pci_enable_device(dev);
- if (rc) return rc;
-
- if (ent->driver_data == pbn_default &&
- serial_pci_guess_board(dev, board))
- return -ENODEV;
- else if (serial_pci_guess_board(dev, &tmp) == 0) {
- printk(KERN_INFO "Redundant entry in serial pci_table. "
- "Please send the output of\n"
- "lspci -vv, this message (%04x,%04x,%04x,%04x)\n"
- "and the manufacturer and name of "
- "serial board or modem board\n"
- "to serial-pci-info@lists.sourceforge.net.\n",
- dev->vendor, dev->device,
- pci_get_subvendor(dev), pci_get_subdevice(dev));
- }
-
- start_pci_pnp_board(dev, board);
-
- return 0;
-}
-
-static void __devexit serial_remove_one(struct pci_dev *dev)
-{
- int i;
-
- /*
- * Iterate through all of the ports finding those that belong
- * to this PCI device.
- */
- for(i = 0; i < NR_PORTS; i++) {
- if (rs_table[i].dev != dev)
- continue;
- unregister_serial(i);
- rs_table[i].dev = 0;
- }
- /*
- * Now execute any board-specific shutdown procedure
- */
- for (i=0; i < NR_PCI_BOARDS; i++) {
- struct pci_board_inst *brd = &serial_pci_board[i];
-
- if (serial_pci_board[i].dev != dev)
- continue;
- if (brd->board.init_fn)
- (brd->board.init_fn)(brd->dev, &brd->board, 0);
- if (DEACTIVATE_FUNC(brd->dev))
- (DEACTIVATE_FUNC(brd->dev))(brd->dev);
- serial_pci_board[i].dev = 0;
- }
-}
-
-
-static struct pci_device_id serial_pci_tbl[] __devinitdata = {
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
- pbn_b1_8_1382400 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
- pbn_b1_4_1382400 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
- pbn_b1_2_1382400 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
- pbn_b1_8_1382400 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
- pbn_b1_4_1382400 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
- pbn_b1_2_1382400 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
- pbn_b1_8_921600 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
- pbn_b1_8_921600 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
- pbn_b1_4_921600 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
- pbn_b1_4_921600 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
- pbn_b1_2_921600 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
- pbn_b1_8_921600 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
- pbn_b1_8_921600 },
- { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
- pbn_b1_4_921600 },
-
- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_1_115200 },
- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_2_115200 },
- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_4_115200 },
- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_2_115200 },
- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_4_115200 },
- { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_8_115200 },
-
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_2_115200 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_2_921600 },
- /* VScom SPCOM800, from sl@s.pl */
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_8_921600 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_4_921600 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_KEYSPAN,
- PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
- pbn_panacom },
- { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_panacom4 },
- { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_panacom2 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
- pbn_b2_4_460800 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
- pbn_b2_8_460800 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
- pbn_b2_16_460800 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_CHASE_PCIFAST,
- PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
- pbn_b2_16_460800 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_CHASE_PCIRAS,
- PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
- pbn_b2_4_460800 },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_CHASE_PCIRAS,
- PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
- pbn_b2_8_460800 },
- /* Megawolf Romulus PCI Serial Card, from Mike Hudson */
- /* (Exoray@isys.ca) */
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
- 0x10b5, 0x106a, 0, 0,
- pbn_plx_romulus },
- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b1_4_115200 },
- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b1_2_115200 },
- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b1_8_115200 },
- { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b1_8_115200 },
- { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
- PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0,
- pbn_b0_4_921600 },
- { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_4_115200 },
- { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_2_115200 },
-
- /* Digitan DS560-558, from jimd@esoft.com */
- { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b1_1_115200 },
-
- /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
- { PCI_VENDOR_ID_USR, 0x1008,
- PCI_ANY_ID, PCI_ANY_ID, },
-
- /* Titan Electronic cards */
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_2_921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_4_921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_4_921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE1, 1, 921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
- /* The 400L and 800L have a custom hack in get_pci_port */
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE_TABLE, 4, 921600 },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
- PCI_ANY_ID, PCI_ANY_ID,
- SPCI_FL_BASE_TABLE, 8, 921600 },
-
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_1 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_1 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_1 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_4 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_4 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig10x_4 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_0 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_2 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_4 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_4 },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_siig20x_4 },
-
- /* Computone devices submitted by Doug McNash dmcnash@computone.com */
- { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
- PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
- 0, 0, pbn_computone_4 },
- { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
- PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
- 0, 0, pbn_computone_8 },
- { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
- PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
- 0, 0, pbn_computone_6 },
-
- { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
- { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
- PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
-
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_2_115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_2_115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_2_115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_2_460800 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_2_460800 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_2_460800 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_1_115200 },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_bt_1_460800 },
-
- /* RAStel 2 port modem, gerg@moreton.com.au */
- { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_2_115200 },
-
- /* EKF addition for i960 Boards form EKF with serial port */
- { PCI_VENDOR_ID_INTEL, 0x1960,
- 0xE4BF, PCI_ANY_ID, 0, 0,
- pbn_intel_i960 },
-
- /* Xircom Cardbus/Ethernet combos */
- { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_xircom_combo },
-
- /*
- * Untested PCI modems, sent in from various folks...
- */
-
- /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
- { PCI_VENDOR_ID_ROCKWELL, 0x1004,
- 0x1048, 0x1500, 0, 0,
- pbn_b1_1_115200 },
-
- { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
- 0xFF00, 0, 0, 0,
- pbn_sgi_ioc3 },
-
-#ifdef CONFIG_DDB5074
- /*
- * NEC Vrc-5074 (Nile 4) builtin UART.
- * Conditionally compiled in since this is a motherboard device.
- */
- { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_nec_nile4 },
-#endif
-
-#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */
- { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_dci_pccom8 },
-#endif
-
- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
-
-static struct pci_driver serial_pci_driver = {
- name: "serial",
- probe: serial_init_one,
- remove: __devexit_p(serial_remove_one),
- id_table: serial_pci_tbl,
-};
-
-
-/*
- * Query PCI space for known serial boards
- * If found, add them to the PCI device space in rs_table[]
- *
- * Accept a maximum of eight boards
- *
- */
-static void __devinit probe_serial_pci(void)
-{
-#ifdef SERIAL_DEBUG_PCI
- printk(KERN_DEBUG "Entered probe_serial_pci()\n");
-#endif
-
- /* Register call PCI serial devices. Null out
- * the driver name upon failure, as a signal
- * not to attempt to unregister the driver later
- */
- if (pci_module_init (&serial_pci_driver) != 0)
- serial_pci_driver.name = "";
-
-#ifdef SERIAL_DEBUG_PCI
- printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
-#endif
- return;
-}
-
-#endif /* ENABLE_SERIAL_PCI */
-
-#ifdef ENABLE_SERIAL_PNP
-
-struct pnp_board {
- unsigned short vendor;
- unsigned short device;
-};
-
-static struct pnp_board pnp_devices[] __devinitdata = {
- /* Archtek America Corp. */
- /* Archtek SmartLink Modem 3334BT Plug & Play */
- { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
- /* Anchor Datacomm BV */
- /* SXPro 144 External Data Fax Modem Plug & Play */
- { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) },
- /* SXPro 288 External Data Fax Modem Plug & Play */
- { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) },
- /* Rockwell 56K ACF II Fax+Data+Voice Modem */
- { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) },
- /* AZT3005 PnP SOUND DEVICE */
- { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) },
- /* Best Data Products Inc. Smart One 336F PnP Modem */
- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
- /* Boca Research */
- /* Boca Complete Ofc Communicator 14.4 Data-FAX */
- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
- /* Boca Research 33,600 ACF Modem */
- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) },
- /* Boca 33.6 Kbps Internal FD34FSVD */
- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) },
- /* Boca 33.6 Kbps Internal FD34FSVD */
- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
- /* Best Data Products Inc. Smart One 336F PnP Modem */
- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
- /* Computer Peripherals Inc */
- /* EuroViVa CommCenter-33.6 SP PnP */
- { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) },
- /* Creative Labs */
- /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
- { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) },
- /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
- { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) },
- /* Creative */
- /* Creative Modem Blaster Flash56 DI5601-1 */
- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) },
- /* Creative Modem Blaster V.90 DI5660 */
- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) },
- /* FUJITSU */
- /* Fujitsu 33600 PnP-I2 R Plug & Play */
- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) },
- /* Fujitsu FMV-FX431 Plug & Play */
- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) },
- /* Fujitsu 33600 PnP-I4 R Plug & Play */
- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) },
- /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) },
- /* Archtek America Corp. */
- /* Archtek SmartLink Modem 3334BT Plug & Play */
- { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) },
- /* Hayes */
- /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) },
- /* Hayes Optima 336 V.34 + FAX + Voice PnP */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) },
- /* Hayes Optima 336B V.34 + FAX + Voice PnP */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) },
- /* Hayes Accura 56K Ext Fax Modem PnP */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) },
- /* Hayes Accura 56K Ext Fax Modem PnP */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) },
- /* Hayes Accura 56K Fax Modem PnP */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) },
- /* Hayes 288, V.34 + FAX */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) },
- /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) },
- /* IBM */
- /* IBM Thinkpad 701 Internal Modem Voice */
- { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) },
- /* Intertex */
- /* Intertex 28k8 33k6 Voice EXT PnP */
- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) },
- /* Intertex 33k6 56k Voice EXT PnP */
- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) },
- /* Intertex 28k8 33k6 Voice SP EXT PnP */
- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) },
- /* Intertex 33k6 56k Voice SP EXT PnP */
- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) },
- /* Intertex 28k8 33k6 Voice SP INT PnP */
- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) },
- /* Intertex 28k8 33k6 Voice SP EXT PnP */
- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) },
- /* Intertex 33k6 56k Voice SP EXT PnP */
- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) },
- /* Kortex International */
- /* KORTEX 28800 Externe PnP */
- { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) },
- /* KXPro 33.6 Vocal ASVD PnP */
- { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) },
- /* Lasat */
- /* LASAT Internet 33600 PnP */
- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) },
- /* Lasat Safire 560 PnP */
- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) },
- /* Lasat Safire 336 PnP */
- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) },
- /* Microcom, Inc. */
- /* Microcom TravelPorte FAST V.34 Plug & Play */
- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) },
- /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) },
- /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) },
- /* Microcom DeskPorte 28.8P Plug & Play */
- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) },
- /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
- /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
- /* Microcom DeskPorte 28.8S Internal Plug & Play */
- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) },
- /* Motorola */
- /* Motorola BitSURFR Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) },
- /* Motorola TA210 Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) },
- /* Motorola HMTA 200 (ISDN) Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) },
- /* Motorola BitSURFR Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) },
- /* Motorola Lifestyle 28.8 Internal */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) },
- /* Motorola V.3400 Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) },
- /* Motorola Lifestyle 28.8 V.34 Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) },
- /* Motorola Power 28.8 V.34 Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) },
- /* Motorola ModemSURFR External 28.8 Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) },
- /* Motorola Premier 33.6 Desktop Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) },
- /* Motorola VoiceSURFR 56K External PnP */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) },
- /* Motorola ModemSURFR 56K External PnP */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) },
- /* Motorola ModemSURFR 56K Internal PnP */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) },
- /* Motorola ModemSURFR Internal 28.8 Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) },
- /* Motorola Premier 33.6 Internal Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) },
- /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) },
- /* Motorola VoiceSURFR 56K Internal PnP */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) },
- /* Com 1 */
- /* Deskline K56 Phone System PnP */
- { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) },
- /* PC Rider K56 Phone System PnP */
- { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) },
- /* Pace 56 Voice Internal Plug & Play Modem */
- { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) },
- /* Generic */
- /* Generic standard PC COM port */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
- /* Generic 16550A-compatible COM port */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
- /* Compaq 14400 Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) },
- /* Compaq 2400/9600 Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) },
- /* Dial-Up Networking Serial Cable between 2 PCs */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) },
- /* Dial-Up Networking Parallel Cable between 2 PCs */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) },
- /* Standard 9600 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) },
- /* Standard 14400 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) },
- /* Standard 28800 bps Modem*/
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) },
- /* Standard Modem*/
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) },
- /* Standard 9600 bps Modem*/
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) },
- /* Standard 14400 bps Modem*/
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) },
- /* Standard 28800 bps Modem*/
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) },
- /* Standard Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) },
- /* Standard 9600 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) },
- /* Standard 14400 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) },
- /* Standard 28800 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) },
- /* Standard Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) },
- /* Standard 9600 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) },
- /* Standard 14400 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) },
- /* Standard 28800 bps Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) },
- /* Standard Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) },
- /* Standard PCMCIA Card Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) },
- /* Rockwell */
- /* Modular Technology */
- /* Rockwell 33.6 DPF Internal PnP */
- /* Modular Technology 33.6 Internal PnP */
- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) },
- /* Kortex International */
- /* KORTEX 14400 Externe PnP */
- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) },
- /* Viking Components, Inc */
- /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) },
- /* Rockwell */
- /* British Telecom */
- /* Modular Technology */
- /* Rockwell 33.6 DPF External PnP */
- /* BT Prologue 33.6 External PnP */
- /* Modular Technology 33.6 External PnP */
- { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) },
- /* Viking 56K FAX INT */
- { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) },
- /* SupraExpress 28.8 Data/Fax PnP modem */
- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) },
- /* SupraExpress 33.6 Data/Fax PnP modem */
- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) },
- /* SupraExpress 33.6 Data/Fax PnP modem */
- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) },
- /* SupraExpress 33.6 Data/Fax PnP modem */
- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) },
- /* Phoebe Micro */
- /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
- { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) },
- /* Archtek America Corp. */
- /* Archtek SmartLink Modem 3334BT Plug & Play */
- { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
- /* 3Com Corp. */
- /* Gateway Telepath IIvi 33.6 */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) },
- /* Sportster Vi 14.4 PnP FAX Voicemail */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) },
- /* U.S. Robotics 33.6K Voice INT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) },
- /* U.S. Robotics 33.6K Voice EXT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) },
- /* U.S. Robotics 33.6K Voice INT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) },
- /* U.S. Robotics 56K Voice INT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) },
- /* U.S. Robotics 56K Voice EXT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) },
- /* U.S. Robotics 56K FAX INT */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) },
- /* U.S. Robotics 56K Voice INT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) },
- /* U.S. Robotics 56K Voice EXT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) },
- /* U.S. Robotics 56K Voice INT PnP */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) },
- /* U.S. Robotics 56K Message */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) },
- /* U.S. Robotics 56K FAX EXT PnP*/
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) },
- /* U.S. Robotics 56K FAX INT PnP*/
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) },
- /* U.S. Robotics 56K Voice EXT PnP*/
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) },
- /* U.S. Robotics 56K Voice INT PnP*/
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) },
- { 0, }
-};
-
-static void inline avoid_irq_share(struct pci_dev *dev)
-{
- int i;
- unsigned long map = 0x1FF8;
- struct serial_state *state = rs_table;
- struct isapnp_irq *irq;
- struct isapnp_resources *res = dev->sysdata;
-
- for (i = 0; i < NR_PORTS; i++) {
- if (state->type != PORT_UNKNOWN)
- clear_bit(state->irq, &map);
- state++;
- }
-
- for ( ; res; res = res->alt)
- for(irq = res->irq; irq; irq = irq->next)
- irq->map = map;
-}
-
-static char *modem_names[] __devinitdata = {
- "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
- "56K", "56k", "K56", "33.6", "28.8", "14.4",
- "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
- "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
-};
-
-static int __devinit check_name(char *name)
-{
- char **tmp = modem_names;
-
- while (*tmp) {
- if (strstr(name, *tmp))
- return 1;
- tmp++;
- }
- return 0;
-}
-
-static int inline check_compatible_id(struct pci_dev *dev)
-{
- int i;
- for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
- if ((dev->vendor_compatible[i] ==
- ISAPNP_VENDOR('P', 'N', 'P')) &&
- (swab16(dev->device_compatible[i]) >= 0xc000) &&
- (swab16(dev->device_compatible[i]) <= 0xdfff))
- return 0;
- return 1;
-}
-
-/*
- * Given a complete unknown ISA PnP device, try to use some heuristics to
- * detect modems. Currently use such heuristic set:
- * - dev->name or dev->bus->name must contain "modem" substring;
- * - device must have only one IO region (8 byte long) with base adress
- * 0x2e8, 0x3e8, 0x2f8 or 0x3f8.
- *
- * Such detection looks very ugly, but can detect at least some of numerous
- * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
- * table.
- */
-static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
- struct pci_board *board)
-{
- struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
- struct isapnp_resources *resa;
-
- if (!(check_name(dev->name) || check_name(dev->bus->name)) &&
- !(check_compatible_id(dev)))
- return 1;
-
- if (!res || res->next)
- return 1;
-
- for (resa = res->alt; resa; resa = resa->alt) {
- struct isapnp_port *port;
- for (port = res->port; port; port = port->next)
- if ((port->size == 8) &&
- ((port->min == 0x2f8) ||
- (port->min == 0x3f8) ||
- (port->min == 0x2e8) ||
- (port->min == 0x3e8)))
- return 0;
- }
-
- return 1;
-}
-
-static void __devinit probe_serial_pnp(void)
-{
- struct pci_dev *dev = NULL;
- struct pnp_board *pnp_board;
- struct pci_board board;
-
-#ifdef SERIAL_DEBUG_PNP
- printk("Entered probe_serial_pnp()\n");
-#endif
- if (!isapnp_present()) {
-#ifdef SERIAL_DEBUG_PNP
- printk("Leaving probe_serial_pnp() (no isapnp)\n");
-#endif
- return;
- }
-
- isapnp_for_each_dev(dev) {
- if (dev->active)
- continue;
-
- memset(&board, 0, sizeof(board));
- board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT;
- board.num_ports = 1;
- board.base_baud = 115200;
-
- for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++)
- if ((dev->vendor == pnp_board->vendor) &&
- (dev->device == pnp_board->device))
- break;
-
- if (pnp_board->vendor) {
- /* Special case that's more efficient to hardcode */
- if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
- pnp_board->device == ISAPNP_DEVICE(0x1021)))
- board.flags |= SPCI_FL_NO_SHIRQ;
- } else {
- if (serial_pnp_guess_board(dev, &board))
- continue;
- }
-
- if (board.flags & SPCI_FL_NO_SHIRQ)
- avoid_irq_share(dev);
- start_pci_pnp_board(dev, &board);
- }
-
-#ifdef SERIAL_DEBUG_PNP
- printk("Leaving probe_serial_pnp() (probe finished)\n");
-#endif
- return;
-}
-
-#endif /* ENABLE_SERIAL_PNP */
-
-/*
- * The serial driver boot-time initialization code!
- */
-static int __init rs_init(void)
-{
- int i;
- struct serial_state * state;
-
- init_bh(SERIAL_BH, do_serial_bh);
- init_timer(&serial_timer);
- serial_timer.function = rs_timer;
- mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
-
- for (i = 0; i < NR_IRQS; i++) {
- IRQ_ports[i] = 0;
- IRQ_timeout[i] = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
- memset(&rs_multiport[i], 0,
- sizeof(struct rs_multiport_struct));
-#endif
- }
-#ifdef CONFIG_SERIAL_CONSOLE
- /*
- * The interrupt of the serial console port
- * can't be shared.
- */
- if (sercons.flags & CON_CONSDEV) {
- for(i = 0; i < NR_PORTS; i++)
- if (i != sercons.index &&
- rs_table[i].irq == rs_table[sercons.index].irq)
- rs_table[i].irq = 0;
- }
-#endif
- show_serial_version();
-
- /* Initialize the tty_driver structure */
-
- memset(&serial_driver, 0, sizeof(struct tty_driver));
- serial_driver.magic = TTY_DRIVER_MAGIC;
-#if (LINUX_VERSION_CODE > 0x20100)
- serial_driver.driver_name = "serial";
-#endif
-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
- serial_driver.name = "tts/%d";
-#else
- serial_driver.name = "ttyS";
-#endif
- serial_driver.major = TTY_MAJOR;
- serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
- serial_driver.num = NR_PORTS;
- serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver.subtype = SERIAL_TYPE_NORMAL;
- serial_driver.init_termios = tty_std_termios;
- serial_driver.init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
- serial_driver.refcount = &serial_refcount;
- serial_driver.table = serial_table;
- serial_driver.termios = serial_termios;
- serial_driver.termios_locked = serial_termios_locked;
-
- serial_driver.open = rs_open;
- serial_driver.close = rs_close;
- serial_driver.write = rs_write;
- serial_driver.put_char = rs_put_char;
- serial_driver.flush_chars = rs_flush_chars;
- serial_driver.write_room = rs_write_room;
- serial_driver.chars_in_buffer = rs_chars_in_buffer;
- serial_driver.flush_buffer = rs_flush_buffer;
- serial_driver.ioctl = rs_ioctl;
- serial_driver.throttle = rs_throttle;
- serial_driver.unthrottle = rs_unthrottle;
- serial_driver.set_termios = rs_set_termios;
- serial_driver.stop = rs_stop;
- serial_driver.start = rs_start;
- serial_driver.hangup = rs_hangup;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
- serial_driver.break_ctl = rs_break;
-#endif
-#if (LINUX_VERSION_CODE >= 131343)
- serial_driver.send_xchar = rs_send_xchar;
- serial_driver.wait_until_sent = rs_wait_until_sent;
- serial_driver.read_proc = rs_read_proc;
-#endif
-
- /*
- * The callout device is just like normal device except for
- * major number and the subtype code.
- */
- callout_driver = serial_driver;
-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
- callout_driver.name = "cua/%d";
-#else
- callout_driver.name = "cua";
-#endif
- callout_driver.major = TTYAUX_MAJOR;
- callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-#if (LINUX_VERSION_CODE >= 131343)
- callout_driver.read_proc = 0;
- callout_driver.proc_entry = 0;
-#endif
-
- if (tty_register_driver(&serial_driver))
- panic("Couldn't register serial driver\n");
- if (tty_register_driver(&callout_driver))
- panic("Couldn't register callout driver\n");
-
- for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
- state->magic = SSTATE_MAGIC;
- state->line = i;
- state->type = PORT_UNKNOWN;
- state->custom_divisor = 0;
- state->close_delay = 5*HZ/10;
- state->closing_wait = 30*HZ;
- state->callout_termios = callout_driver.init_termios;
- state->normal_termios = serial_driver.init_termios;
- state->icount.cts = state->icount.dsr =
- state->icount.rng = state->icount.dcd = 0;
- state->icount.rx = state->icount.tx = 0;
- state->icount.frame = state->icount.parity = 0;
- state->icount.overrun = state->icount.brk = 0;
- state->irq = irq_cannonicalize(state->irq);
- if (state->hub6)
- state->io_type = SERIAL_IO_HUB6;
- if (state->port && check_region(state->port,8))
- continue;
-#ifdef CONFIG_MCA
- if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
- continue;
-#endif
- if (state->flags & ASYNC_BOOT_AUTOCONF)
- autoconfig(state);
- }
- for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
- if (state->type == PORT_UNKNOWN)
- continue;
- if ( (state->flags & ASYNC_BOOT_AUTOCONF)
- && (state->flags & ASYNC_AUTO_IRQ)
- && (state->port != 0 || state->iomem_base != 0))
- state->irq = detect_uart_irq(state);
- if (state->io_type == SERIAL_IO_MEM) {
- printk(KERN_INFO"ttyS%02d%s at 0x%px (irq = %d) is a %s\n",
- state->line + SERIAL_DEV_OFFSET,
- (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
- state->iomem_base, state->irq,
- uart_config[state->type].name);
- }
- else {
- printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
- state->line + SERIAL_DEV_OFFSET,
- (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
- state->port, state->irq,
- uart_config[state->type].name);
- }
- tty_register_devfs(&serial_driver, 0,
- serial_driver.minor_start + state->line);
- tty_register_devfs(&callout_driver, 0,
- callout_driver.minor_start + state->line);
- }
-#ifdef ENABLE_SERIAL_PCI
- probe_serial_pci();
-#endif
-#ifdef ENABLE_SERIAL_PNP
- probe_serial_pnp();
-#endif
- return 0;
-}
-
-/*
- * This is for use by architectures that know their serial console
- * attributes only at run time. Not to be invoked after rs_init().
- */
-int __init early_serial_setup(struct serial_struct *req)
-{
- int i = req->line;
-
- if (i >= NR_IRQS)
- return(-ENOENT);
- rs_table[i].magic = 0;
- rs_table[i].baud_base = req->baud_base;
- rs_table[i].port = req->port;
- if (HIGH_BITS_OFFSET)
- rs_table[i].port += (unsigned long) req->port_high <<
- HIGH_BITS_OFFSET;
- rs_table[i].irq = req->irq;
- rs_table[i].flags = req->flags;
- rs_table[i].close_delay = req->close_delay;
- rs_table[i].io_type = req->io_type;
- rs_table[i].hub6 = req->hub6;
- rs_table[i].iomem_base = req->iomem_base;
- rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
- rs_table[i].type = req->type;
- rs_table[i].xmit_fifo_size = req->xmit_fifo_size;
- rs_table[i].custom_divisor = req->custom_divisor;
- rs_table[i].closing_wait = req->closing_wait;
- return(0);
-}
-
-/*
- * register_serial and unregister_serial allows for 16x50 serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-
-/**
- * register_serial - configure a 16x50 serial port at runtime
- * @req: request structure
- *
- * Configure the serial port specified by the request. If the
- * port exists and is in use an error is returned. If the port
- * is not currently in the table it is added.
- *
- * The port is then probed and if neccessary the IRQ is autodetected
- * If this fails an error is returned.
- *
- * On success the port is ready to use and the line number is returned.
- */
-
-int register_serial(struct serial_struct *req)
-{
- int i;
- unsigned long flags;
- struct serial_state *state;
- struct async_struct *info;
- unsigned long port;
-
- port = req->port;
- if (HIGH_BITS_OFFSET)
- port += (unsigned long) req->port_high << HIGH_BITS_OFFSET;
-
- save_flags(flags); cli();
- for (i = 0; i < NR_PORTS; i++) {
- if ((rs_table[i].port == port) &&
- (rs_table[i].iomem_base == req->iomem_base))
- break;
- }
-#ifdef __i386__
- if (i == NR_PORTS) {
- for (i = 4; i < NR_PORTS; i++)
- if ((rs_table[i].type == PORT_UNKNOWN) &&
- (rs_table[i].count == 0))
- break;
- }
-#endif
- if (i == NR_PORTS) {
- for (i = 0; i < NR_PORTS; i++)
- if ((rs_table[i].type == PORT_UNKNOWN) &&
- (rs_table[i].count == 0))
- break;
- }
- if (i == NR_PORTS) {
- restore_flags(flags);
- return -1;
- }
- state = &rs_table[i];
- if (rs_table[i].count) {
- restore_flags(flags);
- printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
- "device already open\n", i, port, req->irq);
- return -1;
- }
- state->irq = req->irq;
- state->port = port;
- state->flags = req->flags;
- state->io_type = req->io_type;
- state->iomem_base = req->iomem_base;
- state->iomem_reg_shift = req->iomem_reg_shift;
- if (req->baud_base)
- state->baud_base = req->baud_base;
- if ((info = state->info) != NULL) {
- info->port = port;
- info->flags = req->flags;
- info->io_type = req->io_type;
- info->iomem_base = req->iomem_base;
- info->iomem_reg_shift = req->iomem_reg_shift;
- }
- autoconfig(state);
- if (state->type == PORT_UNKNOWN) {
- restore_flags(flags);
- printk("register_serial(): autoconfig failed\n");
- return -1;
- }
- restore_flags(flags);
-
- if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
- state->irq = detect_uart_irq(state);
-
- printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
- state->line + SERIAL_DEV_OFFSET,
- state->iomem_base ? "iomem" : "port",
- state->iomem_base ? (unsigned long)state->iomem_base :
- state->port, state->irq, uart_config[state->type].name);
- tty_register_devfs(&serial_driver, 0,
- serial_driver.minor_start + state->line);
- tty_register_devfs(&callout_driver, 0,
- callout_driver.minor_start + state->line);
- return state->line + SERIAL_DEV_OFFSET;
-}
-
-/**
- * unregister_serial - deconfigure a 16x50 serial port
- * @line: line to deconfigure
- *
- * The port specified is deconfigured and its resources are freed. Any
- * user of the port is disconnected as if carrier was dropped. Line is
- * the port number returned by register_serial().
- */
-
-void unregister_serial(int line)
-{
- unsigned long flags;
- struct serial_state *state = &rs_table[line];
-
- save_flags(flags); cli();
- if (state->info && state->info->tty)
- tty_hangup(state->info->tty);
- state->type = PORT_UNKNOWN;
- printk(KERN_INFO "ttyS%02d unloaded\n", state->line);
- /* These will be hidden, because they are devices that will no longer
- * be available to the system. (ie, PCMCIA modems, once ejected)
- */
- tty_unregister_devfs(&serial_driver,
- serial_driver.minor_start + state->line);
- tty_unregister_devfs(&callout_driver,
- callout_driver.minor_start + state->line);
- restore_flags(flags);
-}
-
-static void __exit rs_fini(void)
-{
- unsigned long flags;
- int e1, e2;
- int i;
- struct async_struct *info;
-
- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- del_timer_sync(&serial_timer);
- save_flags(flags); cli();
- remove_bh(SERIAL_BH);
- if ((e1 = tty_unregister_driver(&serial_driver)))
- printk("serial: failed to unregister serial driver (%d)\n",
- e1);
- if ((e2 = tty_unregister_driver(&callout_driver)))
- printk("serial: failed to unregister callout driver (%d)\n",
- e2);
- restore_flags(flags);
-
- for (i = 0; i < NR_PORTS; i++) {
- if ((info = rs_table[i].info)) {
- rs_table[i].info = NULL;
- kfree(info);
- }
- if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
-#ifdef CONFIG_SERIAL_RSA
- if (rs_table[i].type == PORT_RSA)
- release_region(rs_table[i].port +
- UART_RSA_BASE, 16);
- else
-#endif
- release_region(rs_table[i].port, 8);
- }
-#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
- if (rs_table[i].iomem_base)
- iounmap(rs_table[i].iomem_base);
-#endif
- }
-#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
- for (i=0; i < NR_PCI_BOARDS; i++) {
- struct pci_board_inst *brd = &serial_pci_board[i];
-
- if (serial_pci_board[i].dev == 0)
- continue;
- if (brd->board.init_fn)
- (brd->board.init_fn)(brd->dev, &brd->board, 0);
- if (DEACTIVATE_FUNC(brd->dev))
- (DEACTIVATE_FUNC(brd->dev))(brd->dev);
- }
-#endif
- if (tmp_buf) {
- unsigned long pg = (unsigned long) tmp_buf;
- tmp_buf = NULL;
- free_page(pg);
- }
-
-#ifdef ENABLE_SERIAL_PCI
- if (serial_pci_driver.name[0])
- pci_unregister_driver (&serial_pci_driver);
-#endif
-}
-
-module_init(rs_init);
-module_exit(rs_fini);
-MODULE_DESCRIPTION("Standard/generic (dumb) serial driver");
-MODULE_AUTHOR("Theodore Ts'o <tytso@mit.edu>");
-MODULE_LICENSE("GPL");
-
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-static struct async_struct async_sercons;
-
-/*
- * Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct async_struct *info)
-{
- unsigned int status, tmout = 1000000;
-
- do {
- status = serial_in(info, UART_LSR);
-
- if (status & UART_LSR_BI)
- lsr_break_flag = UART_LSR_BI;
-
- if (--tmout == 0)
- break;
- } while((status & BOTH_EMPTY) != BOTH_EMPTY);
-
- /* Wait for flow control if necessary */
- if (info->flags & ASYNC_CONS_FLOW) {
- tmout = 1000000;
- while (--tmout &&
- ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
- }
-}
-
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- * The console must be locked when we get here.
- */
-static void serial_console_write(struct console *co, const char *s,
- unsigned count)
-{
- static struct async_struct *info = &async_sercons;
- int ier;
- unsigned i;
-
- /*
- * First save the IER then disable the interrupts
- */
- ier = serial_in(info, UART_IER);
- serial_out(info, UART_IER, 0x00);
-
- /*
- * Now, do each character
- */
- for (i = 0; i < count; i++, s++) {
- wait_for_xmitr(info);
-
- /*
- * Send the character out.
- * If a LF, also do CR...
- */
- serial_out(info, UART_TX, *s);
- if (*s == 10) {
- wait_for_xmitr(info);
- serial_out(info, UART_TX, 13);
- }
- }
-
- /*
- * Finally, Wait for transmitter & holding register to empty
- * and restore the IER
- */
- wait_for_xmitr(info);
- serial_out(info, UART_IER, ier);
-}
-
-static kdev_t serial_console_device(struct console *c)
-{
- return mk_kdev(TTY_MAJOR, 64 + c->index);
-}
-
-/*
- * Setup initial baud/bits/parity/flow control. We do two things here:
- * - construct a cflag setting for the first rs_open()
- * - initialize the serial port
- * Return non-zero if we didn't find a serial port.
- */
-static int __init serial_console_setup(struct console *co, char *options)
-{
- static struct async_struct *info;
- struct serial_state *state;
- unsigned cval;
- int baud = 9600;
- int bits = 8;
- int parity = 'n';
- int doflow = 0;
- int cflag = CREAD | HUPCL | CLOCAL;
- int quot = 0;
- char *s;
-
- if (options) {
- baud = simple_strtoul(options, NULL, 10);
- s = options;
- while(*s >= '0' && *s <= '9')
- s++;
- if (*s) parity = *s++;
- if (*s) bits = *s++ - '0';
- if (*s) doflow = (*s++ == 'r');
- }
-
- /*
- * Now construct a cflag setting.
- */
- switch(baud) {
- case 1200:
- cflag |= B1200;
- break;
- case 2400:
- cflag |= B2400;
- break;
- case 4800:
- cflag |= B4800;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 38400:
- cflag |= B38400;
- break;
- case 57600:
- cflag |= B57600;
- break;
- case 115200:
- cflag |= B115200;
- break;
- case 9600:
- default:
- cflag |= B9600;
- /*
- * Set this to a sane value to prevent a divide error
- */
- baud = 9600;
- break;
- }
- switch(bits) {
- case 7:
- cflag |= CS7;
- break;
- default:
- case 8:
- cflag |= CS8;
- break;
- }
- switch(parity) {
- case 'o': case 'O':
- cflag |= PARODD;
- break;
- case 'e': case 'E':
- cflag |= PARENB;
- break;
- }
- co->cflag = cflag;
-
- /*
- * Divisor, bytesize and parity
- */
- state = rs_table + co->index;
- if (doflow)
- state->flags |= ASYNC_CONS_FLOW;
- info = &async_sercons;
- info->magic = SERIAL_MAGIC;
- info->state = state;
- info->port = state->port;
- info->flags = state->flags;
-#ifdef CONFIG_HUB6
- info->hub6 = state->hub6;
-#endif
- info->io_type = state->io_type;
- info->iomem_base = state->iomem_base;
- info->iomem_reg_shift = state->iomem_reg_shift;
- quot = state->baud_base / baud;
- cval = cflag & (CSIZE | CSTOPB);
-#if defined(__powerpc__) || defined(__alpha__)
- cval >>= 8;
-#else /* !__powerpc__ && !__alpha__ */
- cval >>= 4;
-#endif /* !__powerpc__ && !__alpha__ */
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- /*
- * Disable UART interrupts, set DTR and RTS high
- * and set speed.
- */
- serial_out(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
- serial_out(info, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */
- serial_out(info, UART_LCR, cval); /* reset DLAB */
- serial_out(info, UART_IER, 0);
- serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
-
- /*
- * If we read 0xff from the LSR, there is no UART here.
- */
- if (serial_in(info, UART_LSR) == 0xff)
- return -1;
-
- return 0;
-}
-
-static struct console sercons = {
- name: "ttyS",
- write: serial_console_write,
- device: serial_console_device,
- setup: serial_console_setup,
- flags: CON_PRINTBUFFER,
- index: -1,
-};
-
-/*
- * Register console.
- */
-void __init serial_console_init(void)
-{
- register_console(&sercons);
-}
-#endif
-
-/*
- Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
- End:
-*/
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 6789e5ecf6b5..ce8b07ccc5f4 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -150,8 +150,7 @@ extern void con3215_init(void);
extern void tty3215_init(void);
extern void tub3270_con_init(void);
extern void tub3270_init(void);
-extern void rs285_console_init(void);
-extern void sa1100_rs_console_init(void);
+extern void uart_console_init(void);
extern void sgi_serial_console_init(void);
extern void sci_console_init(void);
extern void tx3912_console_init(void);
@@ -456,11 +455,12 @@ void do_tty_hangup(void *data)
}
file_list_unlock();
- /* FIXME! What are the locking issues here? This may me overdoing things.. */
+ /* FIXME! What are the locking issues here? This may me overdoing things..
+ * this question is especially important now that we've removed the irqlock. */
{
unsigned long flags;
- save_flags(flags); cli();
+ __save_flags(flags); __cli(); // FIXME: is this safe?
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
if (tty->driver.flush_buffer)
@@ -468,7 +468,7 @@ void do_tty_hangup(void *data)
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
- restore_flags(flags);
+ __restore_flags(flags); // FIXME: is this safe?
}
wake_up_interruptible(&tty->write_wait);
@@ -1900,7 +1900,7 @@ static void flush_to_ldisc(void *private_)
fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
tty->flip.buf_num = 0;
- save_flags(flags); cli();
+ __save_flags(flags); __cli(); // FIXME: is this safe?
tty->flip.char_buf_ptr = tty->flip.char_buf;
tty->flip.flag_buf_ptr = tty->flip.flag_buf;
} else {
@@ -1908,13 +1908,13 @@ static void flush_to_ldisc(void *private_)
fp = tty->flip.flag_buf;
tty->flip.buf_num = 1;
- save_flags(flags); cli();
+ __save_flags(flags); __cli(); // FIXME: is this safe?
tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
}
count = tty->flip.count;
tty->flip.count = 0;
- restore_flags(flags);
+ __restore_flags(flags); // FIXME: is this safe?
tty->ldisc.receive_buf(tty, cp, fp, count);
}
@@ -2220,18 +2220,12 @@ void __init console_init(void)
#ifdef CONFIG_STDIO_CONSOLE
stdio_console_init();
#endif
-#ifdef CONFIG_SERIAL_21285_CONSOLE
- rs285_console_init();
-#endif
-#ifdef CONFIG_SERIAL_SA1100_CONSOLE
- sa1100_rs_console_init();
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+ uart_console_init();
#endif
#ifdef CONFIG_ARC_CONSOLE
arc_console_init();
#endif
-#ifdef CONFIG_SERIAL_AMBA_CONSOLE
- ambauart_console_init();
-#endif
#ifdef CONFIG_SERIAL_TX3912_CONSOLE
tx3912_console_init();
#endif
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 6fe1ef20e409..68662c975de4 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -97,7 +97,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
int canon_change;
struct termios old_termios = *tty->termios;
- cli();
+ __cli(); // FIXME: is this safe?
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
@@ -107,7 +107,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
tty->canon_data = 0;
tty->erasing = 0;
}
- sti();
+ __sti(); // FIXME: is this safe?
if (canon_change && !L_ICANON(tty) && tty->read_cnt)
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->read_wait);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index e59c0cef09e7..87a0b5904263 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -113,8 +113,8 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
if (hz > 20 && hz < 32767)
count = 1193180 / hz;
- save_flags(flags);
- cli();
+ __save_flags(flags); // FIXME: is this safe?
+ __cli();
del_timer(&sound_timer);
if (count) {
/* enable counter 2 */
@@ -131,7 +131,7 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
}
} else
kd_nosound(0);
- restore_flags(flags);
+ __restore_flags(flags);
return;
}
diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c
index a34945a2382f..f5fb26632eb2 100644
--- a/drivers/ide/hd.c
+++ b/drivers/ide/hd.c
@@ -83,9 +83,6 @@ static void bad_rw_intr(void);
static char recalibrate[MAX_HD];
static char special_op[MAX_HD];
-static int access_count[MAX_HD];
-static char busy[MAX_HD];
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
static int reset;
static int hd_error;
@@ -644,7 +641,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
g.heads = hd_info[dev].head;
g.sectors = hd_info[dev].sect;
g.cylinders = hd_info[dev].cyl;
- g.start = get_start_sect(inode->i_rdev);
+ g.start = get_start_sect(inode->i_bdev);
return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
}
@@ -653,14 +650,6 @@ static int hd_ioctl(struct inode * inode, struct file * file,
return -EACCES;
return revalidate_hddisk(inode->i_rdev, 1);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
default:
return -EINVAL;
}
@@ -668,14 +657,9 @@ static int hd_ioctl(struct inode * inode, struct file * file,
static int hd_open(struct inode * inode, struct file * filp)
{
- int target;
- target = DEVICE_NR(inode->i_rdev);
-
+ int target = DEVICE_NR(inode->i_rdev);
if (target >= NR_HD)
return -ENODEV;
- while (busy[target])
- sleep_on(&busy_wait);
- access_count[target]++;
return 0;
}
@@ -683,12 +667,6 @@ static int hd_open(struct inode * inode, struct file * filp)
* Releasing a block device means we sync() it, so that it can safely
* be forgotten about...
*/
-static int hd_release(struct inode * inode, struct file * file)
-{
- int target = DEVICE_NR(inode->i_rdev);
- access_count[target]--;
- return 0;
-}
extern struct block_device_operations hd_fops;
@@ -715,7 +693,6 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct block_device_operations hd_fops = {
.open = hd_open,
- .release = hd_release,
.ioctl = hd_ioctl,
};
@@ -854,13 +831,9 @@ int __init hd_init(void)
return 0;
}
-#define DEVICE_BUSY busy[target]
-#define USAGE access_count[target]
#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
/* We assume that the BIOS parameters do not change, so the disk capacity
will not change */
-#undef MAYBE_REINIT
-#define GENDISK_STRUCT hd_gendisk
/*
* This routine is called to flush all partitions and partition tables
@@ -872,36 +845,15 @@ int __init hd_init(void)
*/
static int revalidate_hddisk(kdev_t dev, int maxusage)
{
- int target;
- struct gendisk * gdev;
- int res;
- long flags;
-
- target = DEVICE_NR(dev);
- gdev = &GENDISK_STRUCT;
-
- save_flags(flags);
- cli();
- if (DEVICE_BUSY || USAGE > maxusage) {
- restore_flags(flags);
- return -EBUSY;
- }
- DEVICE_BUSY = 1;
- restore_flags(flags);
-
- res = wipe_partitions(dev);
- if (res)
- goto leave;
-
-#ifdef MAYBE_REINIT
- MAYBE_REINIT;
-#endif
-
- grok_partitions(dev, CAPACITY);
-
-leave:
- DEVICE_BUSY = 0;
- wake_up(&busy_wait);
+ int target = DEVICE_NR(dev);
+ kdev_t device = mk_kdev(MAJOR_NR, target << 6);
+ int res = dev_lock_part(device);
+ if (res < 0)
+ return res;
+ res = wipe_partitions(device);
+ if (!res)
+ grok_partitions(device, CAPACITY);
+ dev_unlock_part(device);
return res;
}
diff --git a/drivers/ide/hptraid.c b/drivers/ide/hptraid.c
index 9e8e07b35a2f..43b45c6e06eb 100644
--- a/drivers/ide/hptraid.c
+++ b/drivers/ide/hptraid.c
@@ -122,11 +122,6 @@ static int hptraid_ioctl(struct inode *inode, struct file *file,
return 0;
}
- case BLKROSET:
- case BLKROGET:
- case BLKSSZGET:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
default:
return -EINVAL;
};
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index a83f8e7ee6d6..ce566e1b0645 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1105,9 +1105,6 @@ static int ide_open(struct inode * inode, struct file * filp)
if (drive->driver == NULL)
ide_driver_module();
- while (drive->busy)
- sleep_on(&drive->wqueue);
-
++drive->usage;
if (ata_ops(drive) && ata_ops(drive)->open)
return ata_ops(drive)->open(inode, filp, drive);
diff --git a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c
index 1c86cbc9c177..003b743b4772 100644
--- a/drivers/ide/ioctl.c
+++ b/drivers/ide/ioctl.c
@@ -343,19 +343,6 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
case BLKRRPART: /* Re-read partition tables */
return ata_revalidate(inode->i_rdev);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- case BLKSSZGET:
- case BLKPG:
- case BLKELVGET:
- case BLKELVSET:
- case BLKBSZGET:
- case BLKBSZSET:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
/* Now check whatever this particular ioctl has a device type
* specific implementation.
*/
diff --git a/drivers/ide/main.c b/drivers/ide/main.c
index 24cc8bc9a75e..6c09337f334f 100644
--- a/drivers/ide/main.c
+++ b/drivers/ide/main.c
@@ -249,28 +249,22 @@ struct ata_device *get_info_ptr(kdev_t i_rdev)
*/
int ata_revalidate(kdev_t i_rdev)
{
+ kdev_t device = mk_kdev(major(i_rdev), minor(i_rdev) & ~PARTN_MASK);
struct ata_device *drive;
- unsigned long flags;
int res;
- if ((drive = get_info_ptr(i_rdev)) == NULL)
+ if ((drive = get_info_ptr(device)) == NULL)
return -ENODEV;
- /* FIXME: The locking here doesn't make the slightest sense! */
- spin_lock_irqsave(&ide_lock, flags);
-
- if (drive->busy || (drive->usage > 1)) {
- spin_unlock_irqrestore(&ide_lock, flags);
-
- return -EBUSY;
- }
-
- drive->busy = 1;
MOD_INC_USE_COUNT;
- spin_unlock_irqrestore(&ide_lock, flags);
+ res = dev_lock_part(device);
+ if (res < 0) {
+ MOD_DEC_USE_COUNT;
+ return res;
+ }
- res = wipe_partitions(i_rdev);
+ res = wipe_partitions(device);
if (!res) {
if (ata_ops(drive) && ata_ops(drive)->revalidate) {
ata_get(ata_ops(drive));
@@ -281,14 +275,11 @@ int ata_revalidate(kdev_t i_rdev)
ata_ops(drive)->revalidate(drive);
ata_put(ata_ops(drive));
} else
- grok_partitions(i_rdev, ata_capacity(drive));
+ grok_partitions(device, ata_capacity(drive));
}
- drive->busy = 0;
- wake_up(&drive->wqueue);
-
+ dev_unlock_part(device);
MOD_DEC_USE_COUNT;
-
return res;
}
@@ -1091,18 +1082,18 @@ int ide_unregister_subdriver(struct ata_device *drive)
{
unsigned long flags;
- save_flags(flags); /* all CPUs */
- cli(); /* all CPUs */
+ __save_flags(flags); // FIXME: is this safe?
+ __cli();
#if 0
if (__MOD_IN_USE(ata_ops(drive)->owner)) {
- restore_flags(flags);
+ __restore_flags(flags); // FIXME: is this safe?
return 1;
}
#endif
if (drive->usage || drive->busy || !ata_ops(drive)) {
- restore_flags(flags); /* all CPUs */
+ __restore_flags(flags); // FIXME: is this safe?
return 1;
}
@@ -1111,7 +1102,7 @@ int ide_unregister_subdriver(struct ata_device *drive)
#endif
drive->driver = NULL;
- restore_flags(flags); /* all CPUs */
+ __restore_flags(flags); // FIXME: is this safe?
return 0;
}
diff --git a/drivers/ide/pdcraid.c b/drivers/ide/pdcraid.c
index 4d6f81507582..d1bd67ba7f45 100644
--- a/drivers/ide/pdcraid.c
+++ b/drivers/ide/pdcraid.c
@@ -152,11 +152,6 @@ static int pdcraid_ioctl(struct inode *inode, struct file *file,
return 0;
}
- case BLKROSET:
- case BLKROGET:
- case BLKSSZGET:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
default:
printk("Invalid ioctl \n");
return -EINVAL;
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 3338ed620e69..3a0244704002 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -3097,7 +3097,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
/*
* Called by scsi stack to get bios parameters (used by fdisk, and at boot).
*/
-static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[])
+static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[])
{
int heads, sectors, cylinders;
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index 7d6da4a61dd5..12e6dde4944b 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -542,7 +542,7 @@ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id
static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
static const char *sbp2scsi_info (struct Scsi_Host *host);
void sbp2scsi_setup(char *str, int *ints);
-static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
+static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]);
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt);
static int sbp2scsi_reset (Scsi_Cmnd *SCpnt);
static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
diff --git a/drivers/md/lvm.c b/drivers/md/lvm.c
index c44a1b8a74b2..ab05b01ee4ce 100644
--- a/drivers/md/lvm.c
+++ b/drivers/md/lvm.c
@@ -872,17 +872,6 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
break;
-
- case BLKFLSBUF:
- /* flush buffer cache */
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-
- P_IOCTL("BLKFLSBUF\n");
-
- fsync_bdev(inode->i_bdev);
- invalidate_buffers(inode->i_rdev);
- break;
-
case HDIO_GETGEO:
/* get disk geometry */
P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 549063948426..d08613aea3bb 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2241,28 +2241,6 @@ static int md_ioctl(struct inode *inode, struct file *file,
autostart_arrays();
goto done;
#endif
-
- case BLKGETSIZE: /* Return device size */
- if (!arg) {
- err = -EINVAL;
- MD_BUG();
- goto abort;
- }
- err = put_user(md_hd_struct[minor].nr_sects,
- (unsigned long *) arg);
- goto done;
-
- case BLKGETSIZE64: /* Return device size */
- err = put_user((u64)md_hd_struct[minor].nr_sects << 9,
- (u64 *) arg);
- goto done;
-
- case BLKFLSBUF:
- case BLKBSZGET:
- case BLKBSZSET:
- err = blk_ioctl(inode->i_bdev, cmd, arg);
- goto abort;
-
default:;
}
@@ -2386,7 +2364,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
(short *) &loc->cylinders);
if (err)
goto abort_unlock;
- err = put_user (get_start_sect(dev),
+ err = put_user (get_start_sect(inode->i_bdev),
(long *) &loc->start);
goto done_unlock;
}
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 8d03a096d507..5c049fb8dfdd 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -3576,7 +3576,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
*/
int
-mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+mptscsih_bios_param(Disk * disk, struct block_device *dev, int *ip)
{
int size;
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index c26ec0fe1845..b0c55517d1e6 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -201,7 +201,7 @@ extern int x_scsi_host_reset(Scsi_Cmnd *);
extern int x_scsi_old_abort(Scsi_Cmnd *);
extern int x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
#endif
-extern int x_scsi_bios_param(Disk *, kdev_t, int *);
+extern int x_scsi_bios_param(Disk *, struct block_device *, int *);
extern void x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
extern void x_scsi_taskmgmt_bh(void *);
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index bf11c559d43f..b82610655b49 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -1050,13 +1050,7 @@ static int do_i2ob_revalidate(kdev_t dev, int maxu)
return -EBUSY;
}
- for( i = 15; i>=0 ; i--)
- {
- int m = minor+i;
- invalidate_device(mk_kdev(MAJOR_NR, m), 1);
- i2ob_gendisk.part[m].start_sect = 0;
- i2ob_gendisk.part[m].nr_sects = 0;
- }
+ wipe_partitions(mk_kdev(MAJOR_NR, minor), 1);
/*
* Do a physical check and then reconfigure
@@ -1089,7 +1083,7 @@ static int i2ob_ioctl(struct inode *inode, struct file *file,
int u = minor(inode->i_rdev) & 0xF0;
i2o_block_biosparam(i2ob_sizes[u]<<1,
&g.cylinders, &g.heads, &g.sectors);
- g.start = get_start_sect(inode->i_rdev);
+ g.start = get_start_sect(inode->i_bdev);
return copy_to_user((void *)arg, &g, sizeof(g))
? -EFAULT : 0;
}
@@ -1099,14 +1093,6 @@ static int i2ob_ioctl(struct inode *inode, struct file *file,
return -EACCES;
return do_i2ob_revalidate(inode->i_rdev,1);
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKFLSBUF:
- case BLKROSET:
- case BLKROGET:
- case BLKPG:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
default:
return -EINVAL;
}
@@ -1815,7 +1801,6 @@ int i2o_block_init(void)
* Now fill in the boiler plate
*/
- blk_size[MAJOR_NR] = i2ob_sizes;
blk_dev[MAJOR_NR].queue = i2ob_get_queue;
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request);
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index a25603a79897..1c119e8a44ce 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -902,7 +902,7 @@ int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
* This is anyones guess quite frankly.
*/
-int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip)
+int i2o_scsi_bios_param(Disk * disk, struct block_device *dev, int *ip)
{
int size;
diff --git a/drivers/message/i2o/i2o_scsi.h b/drivers/message/i2o/i2o_scsi.h
index c62d2849b118..1979284f10c6 100644
--- a/drivers/message/i2o/i2o_scsi.h
+++ b/drivers/message/i2o/i2o_scsi.h
@@ -20,7 +20,7 @@ extern int i2o_scsi_command(Scsi_Cmnd *);
extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
extern int i2o_scsi_abort(Scsi_Cmnd *);
extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
-extern int i2o_scsi_bios_param(Disk *, kdev_t, int *);
+extern int i2o_scsi_bios_param(Disk *, struct block_device *, int *);
extern void i2o_scsi_setup(char *str, int *ints);
extern int i2o_scsi_release(struct Scsi_Host *host);
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index de201fdea95e..c68d10d829f9 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -880,9 +880,6 @@ static release_t ftl_close(struct inode *inode, struct file *file)
DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
- /* Flush all writes */
- invalidate_device(inode->i_rdev, 1);
-
/* Wait for any pending erase operations to complete */
if (part->mtd->sync)
part->mtd->sync(part->mtd);
@@ -1126,22 +1123,11 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
put_user(1, (char *)&geo->heads);
put_user(8, (char *)&geo->sectors);
put_user((sect>>3), (short *)&geo->cylinders);
- put_user(get_start_sect(inode->i_rdev), (u_long *)&geo->start);
- break;
- case BLKGETSIZE:
- ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
- break;
- case BLKGETSIZE64:
- ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
+ put_user(get_start_sect(inode->i_bdev), (u_long *)&geo->start);
break;
case BLKRRPART:
ret = ftl_reread_partitions(inode->i_rdev);
break;
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- ret = blk_ioctl(inode->i_bdev, cmd, arg);
- break;
default:
ret = -EINVAL;
}
@@ -1157,25 +1143,20 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
static int ftl_reread_partitions(kdev_t dev)
{
- int minor = minor(dev);
- partition_t *part = myparts[minor >> 4];
- int res;
-
- DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
- if ((atomic_read(&part->open) > 1)) {
- return -EBUSY;
- }
-
- res = wipe_partitions(dev);
- if (res)
- goto leave;
-
- scan_header(part);
-
- register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
- &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
-
- return res;
+ int minor = minor(dev);
+ partition_t *part = myparts[minor >> 4];
+ kdev_t device = mk_kdev(MAJOR_NR, minor & ~15);
+ int res = dev_lock_part(device);
+ if (rec < 0)
+ return res;
+ res = wipe_partitions(device);
+ if (!res) {
+ scan_header(part);
+ grok_partitions(device,
+ le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
+ }
+ dev_unlock_part(device);
+ return res;
}
/*======================================================================
@@ -1285,13 +1266,13 @@ static void ftl_notify_add(struct mtd_info *mtd)
partition->mtd = mtd;
- if ((scan_header(partition) == 0) &&
- (build_maps(partition) == 0)) {
-
+ if ((scan_header(partition) == 0) && (build_maps(partition) == 0)) {
partition->state = FTL_FORMATTED;
atomic_set(&partition->open, 0);
myparts[device] = partition;
- ftl_reread_partitions(device << 4);
+ register_disk(&ftl_gendisk, mk_kdev(MAJOR_NR, device << 4),
+ MAX_PART, &ftl_blk_fops,
+ le32_to_cpu(partition->header.FormattedSize)/SECTOR_SIZE);
#ifdef PCMCIA_DEBUG
printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
le32_to_cpu(partition->header.FormattedSize) >> 10);
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 56535e9a41e9..928ebe405251 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -354,8 +354,6 @@ static release_t mtdblock_release(struct inode *inode, struct file *file)
if (inode == NULL)
release_return(-ENODEV);
- invalidate_device(inode->i_rdev, 1);
-
dev = minor(inode->i_rdev);
mtdblk = mtdblks[dev];
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index 4939a5cb8145..72482560b696 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -76,8 +76,6 @@ static release_t mtdblock_release(struct inode *inode, struct file *file)
if (inode == NULL)
release_return(-ENODEV);
- invalidate_device(inode->i_rdev, 1);
-
dev = minor(inode->i_rdev);
mtd = __get_mtd_device(NULL, dev);
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index bbe20a1721b3..f54e17f14540 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -115,7 +115,6 @@ static void NFTL_setup(struct mtd_info *mtd)
#endif
/* linux stuff */
- nftl->usecount = 0;
nftl->cylinders = 1024;
nftl->heads = 16;
@@ -153,8 +152,9 @@ static void NFTL_setup(struct mtd_info *mtd)
#if LINUX_VERSION_CODE < 0x20328
resetup_one_dev(&nftl_gendisk, firstfree);
#else
- grok_partitions(mk_kdev(MAJOR_NR,firstfree<<NFTL_PARTN_BITS),
- nftl->nr_sects);
+ register_disk(&nftl_gendisk,
+ mk_kdev(MAJOR_NR,firstfree<<NFTL_PARTN_BITS),
+ 1<<NFTL_PARTN_BITS, &nftl_fops, nftl->nr_sects);
#endif
}
@@ -787,7 +787,7 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd
g.heads = nftl->heads;
g.sectors = nftl->sectors;
g.cylinders = nftl->cylinders;
- g.start = get_start_sect(inode->i_rdev);
+ g.start = get_start_sect(inode->i_bdev);
return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
}
case BLKFLSBUF:
@@ -800,29 +800,18 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd
case BLKRRPART:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- if (nftl->usecount > 1) return -EBUSY;
- /*
- * We have to flush all buffers and invalidate caches,
- * or we won't be able to re-use the partitions,
- * if there was a change and we don't want to reboot
- */
- res = wipe_partitions(inode->i_rdev);
+ {
+ kdev_t device = mk_kdev(MAJOR_NR,
+ minor(inode->i_rdev) & -(1<<NFTL_PARTN_BITS));
+ res = dev_lock_part(device);
+ if (res < 0)
+ return res;
+ res = wipe_partitions(device);
if (!res)
- grok_partitions(inode->i_rdev, nftl->nr_sects);
-
+ grok_partitions(device, nftl->nr_sects);
+ dev_unlock_part(device);
+ }
return res;
-
-#if (LINUX_VERSION_CODE < 0x20303)
- RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */
-#else
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKSSZGET:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-#endif
-
default:
return -EINVAL;
}
@@ -955,7 +944,6 @@ static int nftl_open(struct inode *ip, struct file *fp)
return -EROFS;
#endif /* !CONFIG_NFTL_RW */
- thisNFTL->usecount++;
if (!get_mtd_device(thisNFTL->mtd, -1))
return /* -E'SBUGGEREDOFF */ -ENXIO;
@@ -970,11 +958,8 @@ static int nftl_release(struct inode *inode, struct file *fp)
DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
- invalidate_device(inode->i_rdev, 1);
-
if (thisNFTL->mtd->sync)
thisNFTL->mtd->sync(thisNFTL->mtd);
- thisNFTL->usecount--;
put_mtd_device(thisNFTL->mtd);
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index cd6524d58341..485a0a319a98 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1354,7 +1354,7 @@ static void speedo_tx_timeout(struct net_device *dev)
udelay(10);
/* Disable interrupts. */
outw(SCBMaskAll, ioaddr + SCBCmd);
- synchronize_irq();
+ synchronize_irq(dev->irq);
speedo_tx_buffer_gc(dev);
/* Free as much as possible.
It helps to recover from a hang because of out-of-memory.
diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
index 0819ccc93818..771762a06bed 100644
--- a/drivers/net/fc/iph5526.c
+++ b/drivers/net/fc/iph5526.c
@@ -3891,7 +3891,7 @@ struct pci_dev *pdev = NULL;
}
-int iph5526_biosparam(Disk * disk, kdev_t n, int ip[])
+int iph5526_biosparam(Disk * disk, struct block_device *n, int ip[])
{
int size = disk->capacity;
ip[0] = 64;
diff --git a/drivers/net/fc/iph5526_scsi.h b/drivers/net/fc/iph5526_scsi.h
index 18221157ba29..a0224c6a0925 100644
--- a/drivers/net/fc/iph5526_scsi.h
+++ b/drivers/net/fc/iph5526_scsi.h
@@ -25,7 +25,7 @@ int iph5526_queuecommand(Scsi_Cmnd *Cmnd, void (*done) (Scsi_Cmnd *));
int iph5526_release(struct Scsi_Host *host);
int iph5526_abort(Scsi_Cmnd *Cmnd);
const char *iph5526_info(struct Scsi_Host *host);
-int iph5526_biosparam(Disk * disk, kdev_t n, int ip[]);
+int iph5526_biosparam(Disk * disk, struct block_device *n, int ip[]);
#endif
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index ca62073e1009..beea10ab977d 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -447,11 +447,6 @@ static int dasd_ioctl_set_ro(void *inp, int no, long args)
return 0;
}
-static int dasd_ioctl_blkioctl(void *inp, int no, long args)
-{
- return blk_ioctl(((struct inode *) inp)->i_bdev, no, args);
-}
-
/*
* Return device size in number of sectors.
*/
@@ -517,12 +512,12 @@ static int dasd_ioctl_rr_partition(void *inp, int no, long args)
static int dasd_ioctl_getgeo(void *inp, int no, long args)
{
struct hd_geometry geo = { 0, };
+ struct inode *inode = inp;
dasd_devmap_t *devmap;
dasd_device_t *device;
- kdev_t kdev;
+ kdev_t kdev = inode->i_rdev;
int rc;
- kdev = ((struct inode *) inp)->i_rdev;
devmap = dasd_devmap_from_kdev(kdev);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
@@ -532,7 +527,7 @@ static int dasd_ioctl_getgeo(void *inp, int no, long args)
if (device != NULL && device->discipline != NULL &&
device->discipline->fill_geometry != NULL) {
device->discipline->fill_geometry(device, &geo);
- geo.start = get_start_sect(kdev);
+ geo.start = get_start_sect(inode->i_bdev);
if (copy_to_user((struct hd_geometry *) args, &geo,
sizeof (struct hd_geometry)))
rc = -EFAULT;
@@ -554,16 +549,10 @@ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] =
{ BIODASDINFO2, dasd_ioctl_information },
{ BIODASDPRRD, dasd_ioctl_read_profile },
{ BIODASDPRRST, dasd_ioctl_reset_profile },
- { BLKELVGET, dasd_ioctl_blkioctl },
- { BLKELVSET, dasd_ioctl_blkioctl },
- { BLKFLSBUF, dasd_ioctl_blkioctl },
{ BLKGETSIZE, dasd_ioctl_blkgetsize },
{ BLKGETSIZE64, dasd_ioctl_blkgetsize64 },
- { BLKPG, dasd_ioctl_blkioctl },
- { BLKROGET, dasd_ioctl_blkioctl },
{ BLKROSET, dasd_ioctl_set_ro },
{ BLKRRPART, dasd_ioctl_rr_partition },
- { BLKSSZGET, dasd_ioctl_blkioctl },
{ DASDAPIVER, dasd_ioctl_api_version },
{ HDIO_GETGEO, dasd_ioctl_getgeo },
{ -1, NULL }
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index be899c77943a..3985f4274eac 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -342,14 +342,6 @@ static int xpram_ioctl (struct inode *inode, struct file *filp,
if (idx >= xpram_devs)
return -ENODEV;
switch (cmd) {
- case BLKGETSIZE:
- /* Return the device size, expressed in sectors */
- return put_user(xpram_sizes[idx] << 1, (unsigned long *) arg);
- case BLKGETSIZE64:
- /* Return the device size, expressed in bytes */
- return put_user((u64) xpram_sizes[idx] << 10, (u64 *) arg);
- case BLKFLSBUF:
- return blk_ioctl(((struct inode *) inode)->i_bdev, cmd, arg);
case BLKRRPART:
/* re-read partition table: can't do it */
return -EINVAL;
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index a2c58e179445..c7d5306043c6 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -464,14 +464,6 @@ static int jsfd_ioctl(struct inode *inode, struct file *file,
case BLKGETSIZE64:
return put_user(jsfd_bytesizes[dev], (u64 *) arg);
-#if 0
- case BLKROSET:
- case BLKROGET:
- case BLKSSZGET:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-#endif
-
- /* case BLKFLSBUF: */ /* Program, then read, what happens? Stale? */
default: ;
}
return -ENOTTY;
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 87b883e6107f..3e71b678fb64 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -2084,7 +2084,7 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev)
} /* End tw_reset_sequence() */
/* This funciton returns unit geometry in cylinders/heads/sectors */
-int tw_scsi_biosparam(Disk *disk, kdev_t dev, int geom[])
+int tw_scsi_biosparam(Disk *disk, struct block_device *dev, int geom[])
{
int heads, sectors, cylinders;
TW_Device_Extension *tw_dev;
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 4dce8ea588e0..3f96e3753da3 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -56,7 +56,6 @@
#include <linux/version.h>
#include <linux/types.h>
-#include <linux/kdev_t.h>
/* AEN strings */
static char *tw_aen_string[] = {
@@ -445,7 +444,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds);
int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id);
int tw_reset_device_extension(TW_Device_Extension *tw_dev);
int tw_reset_sequence(TW_Device_Extension *tw_dev);
-int tw_scsi_biosparam(Disk *disk, kdev_t dev, int geom[]);
+int tw_scsi_biosparam(Disk *disk, struct block_device *dev, int geom[]);
int tw_scsi_detect(Scsi_Host_Template *tw_host);
int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt);
int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt);
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index e7e9dcab1884..08ba8fba4876 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -4110,7 +4110,7 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
the BIOS, and a warning may be displayed.
*/
-int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
+int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, struct block_device *bdev,
int *Parameters)
{
BusLogic_HostAdapter_T *HostAdapter =
@@ -4138,7 +4138,7 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
}
DiskParameters->Cylinders =
Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
- buf = scsi_bios_ptable(Device);
+ buf = scsi_bios_ptable(bdev);
if (buf == NULL) return 0;
/*
If the boot sector partition table flag is valid, search for a partition
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index e415cbc9a67d..44822851a138 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -34,7 +34,6 @@
of the Linux Kernel and SCSI Subsystem.
*/
-typedef kdev_t KernelDevice_T;
typedef unsigned long ProcessorFlags_T;
typedef struct pt_regs Registers_T;
typedef struct partition PartitionTable_T;
@@ -58,7 +57,7 @@ extern int BusLogic_QueueCommand(SCSI_Command_T *,
void (*CompletionRoutine)(SCSI_Command_T *));
extern int BusLogic_AbortCommand(SCSI_Command_T *);
extern int BusLogic_ResetCommand(SCSI_Command_T *, unsigned int);
-extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *);
+extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, struct block_device *, int *);
extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index bffa89fb0d43..119869ca0e8e 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -760,7 +760,7 @@ NCR53c406a_reset(Scsi_Cmnd *SCpnt, unsigned int ignored){
}
int
-NCR53c406a_biosparm(Scsi_Disk *disk, kdev_t dev, int* info_array){
+NCR53c406a_biosparm(Scsi_Disk *disk, struct block_device *dev, int* info_array){
int size;
DEB(printk("NCR53c406a_biosparm called\n"));
diff --git a/drivers/scsi/NCR53c406a.h b/drivers/scsi/NCR53c406a.h
index 0ef6c67ba6a7..b056a9367f8b 100644
--- a/drivers/scsi/NCR53c406a.h
+++ b/drivers/scsi/NCR53c406a.h
@@ -50,7 +50,7 @@ int NCR53c406a_command(Scsi_Cmnd *);
int NCR53c406a_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c406a_abort(Scsi_Cmnd *);
int NCR53c406a_reset(Scsi_Cmnd *, unsigned int);
-int NCR53c406a_biosparm(Disk *, kdev_t, int []);
+int NCR53c406a_biosparm(Disk *, struct block_device *, int []);
#endif /* _NCR53C406A_H */
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 107fae08cb44..ace0da2c55c0 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -6114,7 +6114,7 @@ advansys_reset(Scsi_Cmnd *scp)
* ip[2]: cylinders
*/
int
-advansys_biosparam(Disk *dp, kdev_t dep, int ip[])
+advansys_biosparam(Disk *dp, struct block_device *dep, int ip[])
{
asc_board_t *boardp;
diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
index 22cdadd55f2f..756e5c64cc78 100644
--- a/drivers/scsi/advansys.h
+++ b/drivers/scsi/advansys.h
@@ -52,7 +52,7 @@ int advansys_release(struct Scsi_Host *);
const char *advansys_info(struct Scsi_Host *);
int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int advansys_reset(Scsi_Cmnd *);
-int advansys_biosparam(Disk *, kdev_t, int[]);
+int advansys_biosparam(Disk *, struct block_device *, int[]);
#ifdef CONFIG_PROC_FS
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
extern struct proc_dir_entry proc_scsi_advansys;
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 4a9a9cfb93f5..7f353ce582d9 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -1830,7 +1830,7 @@ int aha152x_host_reset(Scsi_Cmnd * SCpnt)
* Return the "logical geometry"
*
*/
-int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
+int aha152x_biosparam(Scsi_Disk * disk, struct block_device *bdev, int *info_array)
{
struct Scsi_Host *shpnt = disk->device->host;
@@ -1844,7 +1844,7 @@ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
int info[3];
/* try to figure out the geometry from the partition table */
- if (scsicam_bios_param(disk, dev, info) < 0 ||
+ if (scsicam_bios_param(disk, bdev, info) < 0 ||
!((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
if (EXT_TRANS) {
printk(KERN_NOTICE
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
index d0a7126ccf7d..0bd6c02ff796 100644
--- a/drivers/scsi/aha152x.h
+++ b/drivers/scsi/aha152x.h
@@ -20,7 +20,7 @@ int aha152x_release(struct Scsi_Host *shpnt);
int aha152x_device_reset(Scsi_Cmnd *);
int aha152x_bus_reset(Scsi_Cmnd *);
int aha152x_host_reset(Scsi_Cmnd *);
-int aha152x_biosparam(Disk *, kdev_t, int*);
+int aha152x_biosparam(Disk *, struct block_device *, int*);
int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
/* number of queueable commands
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index ad1af6379ffb..96712452a8fa 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -1783,7 +1783,7 @@ fail:
#include "sd.h"
-static int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
+static int aha1542_biosparam(Scsi_Disk * disk, struct block_device *dev, int *ip)
{
int translation_algorithm;
int size = disk->capacity;
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
index a15fff3b2fd2..4808317841f6 100644
--- a/drivers/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -32,7 +32,6 @@
*/
#include <linux/types.h>
-#include <linux/kdev_t.h>
/* I/O Port interface 4.2 */
/* READ */
@@ -141,7 +140,7 @@ static int aha1542_host_reset(Scsi_Cmnd * SCpnt);
static int aha1542_old_abort(Scsi_Cmnd * SCpnt);
static int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
#endif
-static int aha1542_biosparam(Disk *, kdev_t, int*);
+static int aha1542_biosparam(Disk *, struct block_device *, int*);
#define AHA1542_MAILBOXES 8
#define AHA1542_SCATTER 16
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index ad043e6020c8..de1e23c9fbb7 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -590,7 +590,7 @@ int aha1740_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
return SCSI_RESET_PUNT;
}
-int aha1740_biosparam(Disk * disk, kdev_t dev, int* ip)
+int aha1740_biosparam(Disk * disk, struct block_device *dev, int* ip)
{
int size = disk->capacity;
int extended = HOSTDATA(disk->device->host)->translation;
diff --git a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h
index 036effaa4e17..9a4410976961 100644
--- a/drivers/scsi/aha1740.h
+++ b/drivers/scsi/aha1740.h
@@ -11,7 +11,6 @@
*/
#include <linux/types.h>
-#include <linux/kdev_t.h>
/* Eisa Enhanced mode operation - slot locating and addressing */
#define MINEISA 1 /* I don't have an EISA Spec to know these ranges, so I */
@@ -158,7 +157,7 @@ int aha1740_command(Scsi_Cmnd *);
int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int aha1740_abort(Scsi_Cmnd *);
int aha1740_reset(Scsi_Cmnd *, unsigned int);
-int aha1740_biosparam(Disk *, kdev_t, int*);
+int aha1740_biosparam(Disk *, struct block_device *, int*);
int aha1740_proc_info(char *buffer, char **start, off_t offset,
int length, int hostno, int inout);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
index a5ed9dac061a..ffcbb4aa09e0 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c
@@ -2722,7 +2722,7 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd)
* Return the disk geometry for the given SCSI device.
*/
int
-ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
+ahc_linux_biosparam(Disk *disk, struct block_device *bdev, int geom[])
{
int heads;
int sectors;
@@ -2733,7 +2733,7 @@ ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
unsigned char *buf;
ahc = *((struct ahc_softc **)disk->device->host->hostdata);
- buf = scsi_bios_ptable(dev);
+ buf = scsi_bios_ptable(bdev);
if (buf) {
ret = scsi_partsize(buf, disk->capacity,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
index 491b0eb49872..4c3735f5a392 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
@@ -47,7 +47,7 @@ int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
int ahc_linux_detect(Scsi_Host_Template *);
int ahc_linux_release(struct Scsi_Host *);
const char *ahc_linux_info(struct Scsi_Host *);
-int ahc_linux_biosparam(Disk *, kdev_t, int[]);
+int ahc_linux_biosparam(Disk *, struct block_device *, int[]);
int ahc_linux_bus_reset(Scsi_Cmnd *);
int ahc_linux_dev_reset(Scsi_Cmnd *);
int ahc_linux_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index ae927a405e08..acf88a76fca0 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -11719,14 +11719,14 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
* Return the disk geometry for the given SCSI device.
*-F*************************************************************************/
int
-aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
+aic7xxx_biosparam(Disk *disk, struct block_device *bdev, int geom[])
{
int heads, sectors, cylinders, ret;
struct aic7xxx_host *p;
unsigned char *buf;
p = (struct aic7xxx_host *) disk->device->host->hostdata;
- buf = scsi_bios_ptable(dev);
+ buf = scsi_bios_ptable(bdev);
if ( buf )
{
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h
index ce397e38d5e8..ac1d78b8602f 100644
--- a/drivers/scsi/aic7xxx_old/aic7xxx.h
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.h
@@ -58,7 +58,7 @@
}
extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
+extern int aic7xxx_biosparam(Disk *, struct block_device *, int[]);
extern int aic7xxx_detect(Scsi_Host_Template *);
extern int aic7xxx_command(Scsi_Cmnd *);
extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 5ba17a3bc2ff..6f64a4466d71 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -2835,7 +2835,7 @@ stop_output:
#include "sd.h"
-int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
+int atp870u_biosparam(Scsi_Disk * disk, struct block_device *dev, int *ip)
{
int heads, sectors, cylinders;
diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
index cda1a387ca67..ab61bf99891e 100644
--- a/drivers/scsi/atp870u.h
+++ b/drivers/scsi/atp870u.h
@@ -11,7 +11,6 @@
*/
#include <linux/types.h>
-#include <linux/kdev_t.h>
/* I/O Port */
@@ -23,7 +22,7 @@ int atp870u_command(Scsi_Cmnd *);
int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int atp870u_abort(Scsi_Cmnd *);
int atp870u_reset(Scsi_Cmnd *, unsigned int);
-int atp870u_biosparam(Disk *, kdev_t, int *);
+int atp870u_biosparam(Disk *, struct block_device *, int *);
int atp870u_release(struct Scsi_Host *);
void send_s870(unsigned char);
diff --git a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h
index 529171e82b9a..a91b3ca51a99 100644
--- a/drivers/scsi/cpqfcTS.h
+++ b/drivers/scsi/cpqfcTS.h
@@ -12,7 +12,7 @@ extern int cpqfcTS_abort(Scsi_Cmnd *);
extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
-extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]);
+extern int cpqfcTS_biosparam(Disk *, struct block_device *, int[]);
extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
// note: since Tachyon TS supports an extended scatter/gather
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
index f38e377207c7..dbac6cde86d9 100644
--- a/drivers/scsi/cpqfcTSinit.c
+++ b/drivers/scsi/cpqfcTSinit.c
@@ -1625,7 +1625,7 @@ int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
(from hosts.h)
*/
-int cpqfcTS_biosparam(Disk *disk, kdev_t n, int ip[])
+int cpqfcTS_biosparam(Disk *disk, struct block_device *n, int ip[])
{
int size = disk->capacity;
diff --git a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h
index 02fe82eaf1db..be436bf43d83 100644
--- a/drivers/scsi/dc390.h
+++ b/drivers/scsi/dc390.h
@@ -39,7 +39,7 @@ extern int DC390_detect(Scsi_Host_Template *psht);
extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
extern int DC390_abort(Scsi_Cmnd *cmd);
extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags);
-extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]);
+extern int DC390_bios_param(Disk *disk, struct block_device *dev, int geom[]);
#ifdef MODULE
static int DC390_release(struct Scsi_Host *);
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index e20cfea59b60..f063b5dc1738 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -453,7 +453,7 @@ static int adpt_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
return adpt_scsi_to_i2o(pHba, cmd, pDev);
}
-static int adpt_bios_param(Disk* disk, kdev_t dev, int geom[])
+static int adpt_bios_param(Disk* disk, struct block_device *dev, int geom[])
{
int heads=-1;
int sectors=-1;
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 670afcc2c070..dfff119adc2b 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -45,7 +45,7 @@ static int adpt_reset(Scsi_Cmnd* cmd);
static int adpt_release(struct Scsi_Host *host);
static const char *adpt_info(struct Scsi_Host *pSHost);
-static int adpt_bios_param(Disk * disk, kdev_t dev, int geom[]);
+static int adpt_bios_param(Disk * disk, struct block_device *dev, int geom[]);
static int adpt_bus_reset(Scsi_Cmnd* cmd);
static int adpt_device_reset(Scsi_Cmnd* cmd);
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 910effea59b4..2fa2cd414363 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -295,7 +295,7 @@ int __init dtc_detect(Scsi_Host_Template * tpnt){
}
/*
- * Function : int dtc_biosparam(Disk * disk, kdev_t dev, int *ip)
+ * Function : int dtc_biosparam(Disk * disk, struct block_device *dev, int *ip)
*
* Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
* the specified device / size.
@@ -314,7 +314,7 @@ int __init dtc_detect(Scsi_Host_Template * tpnt){
* and matching the H_C_S coordinates to what DOS uses.
*/
-int dtc_biosparam(Disk * disk, kdev_t dev, int * ip)
+int dtc_biosparam(Disk * disk, struct block_device *dev, int * ip)
{
int size = disk->capacity;
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index 73616ed085c0..f5ce0c95df3e 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -30,7 +30,7 @@
#ifndef ASM
int dtc_abort(Scsi_Cmnd *);
-int dtc_biosparam(Disk *, kdev_t, int*);
+int dtc_biosparam(Disk *, struct block_device *, int*);
int dtc_detect(Scsi_Host_Template *);
int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int dtc_reset(Scsi_Cmnd *, unsigned int reset_flags);
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index cc73354accc6..9690e38bed42 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1803,10 +1803,10 @@ int eata2x_reset(Scsi_Cmnd *SCarg) {
return do_reset(SCarg);
}
-int eata2x_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
+int eata2x_biosparam(Disk *disk, struct block_device *bdev, int *dkinfo) {
int size = disk->capacity;
- if (ext_tran || (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+ if (ext_tran || (scsicam_bios_param(disk, bdev, dkinfo) < 0)) {
dkinfo[0] = 255;
dkinfo[1] = 63;
dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index f1c5e5b84b91..56f00bf01c7b 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -11,7 +11,7 @@ int eata2x_release(struct Scsi_Host *);
int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *);
-int eata2x_biosparam(Disk *, kdev_t, int *);
+int eata2x_biosparam(Disk *, struct block_device *, int *);
#define EATA_VERSION "7.22.00"
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index c41d92c3f08e..271ce78aa14f 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -1383,9 +1383,8 @@ int fd_mcs_reset( Scsi_Cmnd *SCpnt, unsigned int reset_flags )
#include "sd.h"
#include <scsi/scsi_ioctl.h>
-int fd_mcs_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array )
+int fd_mcs_biosparam( Scsi_Disk *disk, struct block_device *bdev, int *info_array )
{
- int drive;
unsigned char buf[512 + sizeof( int ) * 2];
int size = disk->capacity;
int *sizes = (int *)buf;
@@ -1394,8 +1393,6 @@ int fd_mcs_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array )
int retcode;
/* BIOS >= 3.4 for MCA cards */
- drive = MINOR(dev) / 16;
-
/* This algorithm was provided by Future Domain (much thanks!). */
sizes[0] = 0; /* zero bytes out */
diff --git a/drivers/scsi/fd_mcs.h b/drivers/scsi/fd_mcs.h
index 1841d5c28661..fb490c906afc 100644
--- a/drivers/scsi/fd_mcs.h
+++ b/drivers/scsi/fd_mcs.h
@@ -28,7 +28,7 @@ extern int fd_mcs_command( Scsi_Cmnd * );
extern int fd_mcs_abort( Scsi_Cmnd * );
extern int fd_mcs_reset( Scsi_Cmnd *, unsigned int );
extern int fd_mcs_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
-extern int fd_mcs_biosparam( Disk *, kdev_t, int * );
+extern int fd_mcs_biosparam( Disk *, struct block_device *, int * );
extern int fd_mcs_proc_info( char *, char **, off_t, int, int, int );
extern const char *fd_mcs_info(struct Scsi_Host *);
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index c853eabf386f..6fdd13a4c1a4 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -1874,7 +1874,7 @@ int fdomain_16x0_reset( Scsi_Cmnd *SCpnt, unsigned int ignored )
#include "sd.h"
#include <scsi/scsi_ioctl.h>
-int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array )
+int fdomain_16x0_biosparam( Scsi_Disk *disk, struct block_device *bdev, int *info_array )
{
int drive;
unsigned char buf[512 + sizeof (Scsi_Ioctl_Command)];
@@ -1933,11 +1933,11 @@ int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array )
0x0a bytes long. Heads are one less than we need to report.
*/
- if (major(dev) != SCSI_DISK0_MAJOR) {
+ if (MAJOR(bdev->bd_dev) != SCSI_DISK0_MAJOR) {
printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks");
return 0;
}
- drive = minor(dev) >> 4;
+ drive = MINOR(bdev->bd_dev) >> 4;
if (bios_major == 2) {
switch (Quantum) {
diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
index a85539af125b..cc1f8babadaa 100644
--- a/drivers/scsi/fdomain.h
+++ b/drivers/scsi/fdomain.h
@@ -31,7 +31,7 @@ int fdomain_16x0_abort( Scsi_Cmnd * );
const char *fdomain_16x0_info( struct Scsi_Host * );
int fdomain_16x0_reset( Scsi_Cmnd *, unsigned int );
int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
-int fdomain_16x0_biosparam( Disk *, kdev_t, int * );
+int fdomain_16x0_biosparam( Disk *, struct block_device *, int * );
int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
int length, int hostno, int inout );
int fdomain_16x0_release( struct Scsi_Host *shpnt );
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index ae4136b29491..8789580496b6 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -512,7 +512,7 @@ int generic_NCR5380_release_resources(struct Scsi_Host *instance)
* Locks: none
*/
-int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
+int generic_NCR5380_biosparam(Disk * disk, struct block_device *dev, int *ip)
{
int size = disk->capacity;
ip[0] = 64;
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index 3ab55b6f7bcd..0d07adaa8e9f 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -53,7 +53,7 @@ int notyet_generic_proc_info (char *buffer ,char **start, off_t offset,
int length, int hostno, int inout);
const char* generic_NCR5380_info(struct Scsi_Host *);
#ifdef BIOSPARAM
-int generic_NCR5380_biosparam(Disk *, kdev_t, int *);
+int generic_NCR5380_biosparam(Disk *, struct block_device *, int *);
#endif
int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 8508b693f316..2cb9f5d75851 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4512,11 +4512,7 @@ int gdth_eh_host_reset(Scsi_Cmnd *scp)
}
#endif
-#if LINUX_VERSION_CODE >= 0x010300
-int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
-#else
-int gdth_bios_param(Disk *disk,int dev,int *ip)
-#endif
+int gdth_bios_param(Disk *disk,struct block_device *bdev,int *ip)
{
unchar b, t;
int hanum;
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 1b34a881014a..67355b74b832 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -1031,8 +1031,7 @@ int gdth_reset(Scsi_Cmnd *);
#endif
const char *gdth_info(struct Scsi_Host *);
-#if LINUX_VERSION_CODE >= 0x020322
-int gdth_bios_param(Disk *,kdev_t,int *);
+int gdth_bios_param(Disk *,struct block_device *,int *);
int gdth_proc_info(char *,char **,off_t,int,int,int);
int gdth_eh_abort(Scsi_Cmnd *scp);
int gdth_eh_device_reset(Scsi_Cmnd *scp);
@@ -1061,83 +1060,5 @@ int gdth_eh_host_reset(Scsi_Cmnd *scp);
unchecked_isa_dma: 1, \
use_clustering: ENABLE_CLUSTERING }
-#elif LINUX_VERSION_CODE >= 0x02015F
-int gdth_bios_param(Disk *,kdev_t,int *);
-extern struct proc_dir_entry proc_scsi_gdth;
-int gdth_proc_info(char *,char **,off_t,int,int,int);
-int gdth_eh_abort(Scsi_Cmnd *scp);
-int gdth_eh_device_reset(Scsi_Cmnd *scp);
-int gdth_eh_bus_reset(Scsi_Cmnd *scp);
-int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#define GDTH { proc_dir: &proc_scsi_gdth, \
- proc_info: gdth_proc_info, \
- name: "GDT SCSI Disk Array Controller",\
- detect: gdth_detect, \
- release: gdth_release, \
- info: gdth_info, \
- command: NULL, \
- queuecommand: gdth_queuecommand, \
- eh_abort_handler: gdth_eh_abort, \
- eh_device_reset_handler: gdth_eh_device_reset, \
- eh_bus_reset_handler: gdth_eh_bus_reset, \
- eh_host_reset_handler: gdth_eh_host_reset, \
- abort: gdth_abort, \
- reset: gdth_reset, \
- bios_param: gdth_bios_param, \
- can_queue: GDTH_MAXCMDS, \
- this_id: -1, \
- sg_tablesize: GDTH_MAXSG, \
- cmd_per_lun: GDTH_MAXC_P_L, \
- present: 0, \
- unchecked_isa_dma: 1, \
- use_clustering: ENABLE_CLUSTERING }
-
-#elif LINUX_VERSION_CODE >= 0x010300
-int gdth_bios_param(Disk *,kdev_t,int *);
-extern struct proc_dir_entry proc_scsi_gdth;
-int gdth_proc_info(char *,char **,off_t,int,int,int);
-#define GDTH { NULL, NULL, \
- &proc_scsi_gdth, \
- gdth_proc_info, \
- "GDT SCSI Disk Array Controller", \
- gdth_detect, \
- gdth_release, \
- gdth_info, \
- NULL, \
- gdth_queuecommand, \
- gdth_abort, \
- gdth_reset, \
- NULL, \
- gdth_bios_param, \
- GDTH_MAXCMDS, \
- -1, \
- GDTH_MAXSG, \
- GDTH_MAXC_P_L, \
- 0, \
- 1, \
- ENABLE_CLUSTERING}
-
-#else
-int gdth_bios_param(Disk *,int,int *);
-#define GDTH { NULL, NULL, \
- "GDT SCSI Disk Array Controller", \
- gdth_detect, \
- gdth_release, \
- gdth_info, \
- NULL, \
- gdth_queuecommand, \
- gdth_abort, \
- gdth_reset, \
- NULL, \
- gdth_bios_param, \
- GDTH_MAXCMDS, \
- -1, \
- GDTH_MAXSG, \
- GDTH_MAXC_P_L, \
- 0, \
- 1, \
- ENABLE_CLUSTERING}
-#endif
-
#endif
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index f338366ff443..4d7f25dda311 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -210,9 +210,9 @@ typedef struct SHT
* This function determines the bios parameters for a given
* harddisk. These tend to be numbers that are made up by
* the host adapter. Parameters:
- * size, device number, list (heads, sectors, cylinders)
+ * size, device, list (heads, sectors, cylinders)
*/
- int (* bios_param)(Disk *, kdev_t, int []);
+ int (* bios_param)(Disk *, struct block_device *, int []);
/*
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 1b034e4e4e7f..09d809bae4c8 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -2382,7 +2382,7 @@ int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags)
return SCSI_RESET_SUCCESS;
}
-int ibmmca_biosparam (Disk * disk, kdev_t dev, int *info)
+int ibmmca_biosparam (Disk * disk, struct block_device *dev, int *info)
{
info[0] = 64;
info[1] = 32;
diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
index fa3ec5458576..d8df93cd0ec3 100644
--- a/drivers/scsi/ibmmca.h
+++ b/drivers/scsi/ibmmca.h
@@ -17,7 +17,7 @@ extern int ibmmca_command (Scsi_Cmnd *);
extern int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
extern int ibmmca_abort (Scsi_Cmnd *);
extern int ibmmca_reset (Scsi_Cmnd *, unsigned int);
-extern int ibmmca_biosparam (Disk *, kdev_t, int *);
+extern int ibmmca_biosparam (Disk *, struct block_device *, int *);
/*structure for /proc filesystem */
extern struct proc_dir_entry proc_scsi_ibmmca;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 6cb967d14650..f05c5f37b1ed 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -711,7 +711,7 @@ static int idescsi_device_reset(Scsi_Cmnd *cmd)
return SUCCESS;
}
-static int idescsi_bios(Disk *disk, kdev_t dev, int *parm)
+static int idescsi_bios(Disk *disk, struct block_device *dev, int *parm)
{
idescsi_scsi_t *scsi = idescsi_private(disk->device->host);
struct ata_device *drive = scsi->drive;
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 161cf9799a40..a23e04a157f1 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -1117,7 +1117,7 @@ int imm_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
* be done in sd.c. Even if it gets fixed there, this will still
* work.
*/
-int imm_biosparam(Disk * disk, kdev_t dev, int ip[])
+int imm_biosparam(Disk * disk, struct block_device *dev, int ip[])
{
ip[0] = 0x40;
ip[1] = 0x20;
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
index ab3c8a71c369..ac28d5063c4d 100644
--- a/drivers/scsi/imm.h
+++ b/drivers/scsi/imm.h
@@ -162,7 +162,7 @@ int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int imm_abort(Scsi_Cmnd *);
int imm_reset(Scsi_Cmnd *);
int imm_proc_info(char *, char **, off_t, int, int, int);
-int imm_biosparam(Disk *, kdev_t, int *);
+int imm_biosparam(Disk *, struct block_device *, int *);
#define IMM { proc_name: "imm", \
proc_info: imm_proc_info, \
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 5659858c18d9..83fe01110ce0 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2158,7 +2158,7 @@ char buf[32];
* supposed to do...
*/
-int in2000_biosparam(Disk *disk, kdev_t dev, int *iinfo)
+int in2000_biosparam(Disk *disk, struct block_device *dev, int *iinfo)
{
int size;
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
index 4f12b8fd5e94..f29f4de0bd94 100644
--- a/drivers/scsi/in2000.h
+++ b/drivers/scsi/in2000.h
@@ -402,7 +402,7 @@ int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int in2000_abort(Scsi_Cmnd *);
void in2000_setup(char *, int *) in2000__INIT;
int in2000_proc_info(char *, char **, off_t, int, int, int);
-int in2000_biosparam(struct scsi_disk *, kdev_t, int *);
+int in2000_biosparam(struct scsi_disk *, struct block_device *, int *);
int in2000_reset(Scsi_Cmnd *, unsigned int);
diff --git a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c
index c6c53caf11d3..dd252714d421 100644
--- a/drivers/scsi/ini9100u.c
+++ b/drivers/scsi/ini9100u.c
@@ -583,7 +583,7 @@ int i91u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
/*
* Return the "logical geometry"
*/
-int i91u_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
+int i91u_biosparam(Scsi_Disk * disk, struct block_device *dev, int *info_array)
{
HCS *pHcb; /* Point to Host adapter control block */
TCS *pTcb;
diff --git a/drivers/scsi/ini9100u.h b/drivers/scsi/ini9100u.h
index 557518771e40..a8e88f538f97 100644
--- a/drivers/scsi/ini9100u.h
+++ b/drivers/scsi/ini9100u.h
@@ -84,7 +84,7 @@ extern int i91u_command(Scsi_Cmnd *);
extern int i91u_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
extern int i91u_abort(Scsi_Cmnd *);
extern int i91u_reset(Scsi_Cmnd *, unsigned int);
-extern int i91u_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */
+extern int i91u_biosparam(Scsi_Disk *, struct block_device *, int *);
#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03g"
diff --git a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c
index f4685153398f..e5dc661cc491 100644
--- a/drivers/scsi/inia100.c
+++ b/drivers/scsi/inia100.c
@@ -653,7 +653,7 @@ void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
-int inia100_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
+int inia100_biosparam(Scsi_Disk * disk, struct block_device *dev, int *info_array)
{
ORC_HCS *pHcb; /* Point to Host adapter control block */
ORC_TCS *pTcb;
diff --git a/drivers/scsi/inia100.h b/drivers/scsi/inia100.h
index 786b28329aa9..431c8adfff09 100644
--- a/drivers/scsi/inia100.h
+++ b/drivers/scsi/inia100.h
@@ -83,7 +83,7 @@ extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
extern int inia100_abort(Scsi_Cmnd *);
extern int inia100_reset(Scsi_Cmnd *, unsigned int);
-extern int inia100_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */
+extern int inia100_biosparam(Scsi_Disk *, struct block_device *, int *);
#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02c"
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index be8f9cee7e88..3d22bcaf7072 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -437,7 +437,7 @@ int ips_release(struct Scsi_Host *);
int ips_eh_abort(Scsi_Cmnd *);
int ips_eh_reset(Scsi_Cmnd *);
int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
-int ips_biosparam(Disk *, kdev_t, int *);
+int ips_biosparam(Disk *, struct block_device *, int *);
const char * ips_info(struct Scsi_Host *);
void do_ipsintr(int, void *, struct pt_regs *);
static int ips_hainit(ips_ha_t *);
@@ -1853,7 +1853,7 @@ ips_queue(Scsi_Cmnd *SC, void (*done) (Scsi_Cmnd *)) {
/* */
/****************************************************************************/
int
-ips_biosparam(Disk *disk, kdev_t dev, int geom[]) {
+ips_biosparam(Disk *disk, struct block_device *dev, int geom[]) {
ips_ha_t *ha;
int heads;
int sectors;
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index febbd953eb00..9cc112d362e6 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -56,7 +56,7 @@
extern int ips_eh_abort(Scsi_Cmnd *);
extern int ips_eh_reset(Scsi_Cmnd *);
extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
- extern int ips_biosparam(Disk *, kdev_t, int *);
+ extern int ips_biosparam(Disk *, struct block_device *, int *);
extern const char * ips_info(struct Scsi_Host *);
extern void do_ips(int, void *, struct pt_regs *);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index ea23cc09fba7..7d2bf583126f 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4218,13 +4218,13 @@ static void mega_create_proc_entry (int index, struct proc_dir_entry *parent)
* Return the disk geometry for a particular disk
* Input:
* Disk *disk - Disk geometry
- * kdev_t dev - Device node
+ * struct block_device *dev - Device node
* int *geom - Returns geometry fields
* geom[0] = heads
* geom[1] = sectors
* geom[2] = cylinders
*-------------------------------------------------------------*/
-int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
+int megaraid_biosparam (Disk * disk, struct block_device *bdev, int *geom)
{
int heads, sectors, cylinders;
mega_host_config *megaCfg;
@@ -4251,7 +4251,7 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
geom[2] = cylinders;
}
else {
- if( mega_partsize(disk, dev, geom) == 0 ) return 0;
+ if( mega_partsize(disk, bdev, geom) == 0 ) return 0;
printk(KERN_WARNING
"megaraid: invalid partition on this disk on channel %d\n",
@@ -4279,7 +4279,7 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
}
/*
- * Function : static int mega_partsize(Disk * disk, kdev_t dev, int *geom)
+ * Function : static int mega_partsize(Disk * disk, struct block_device *bdev, int *geom)
*
* Purpose : to determine the BIOS mapping used to create the partition
* table, storing the results (cyls, hds, and secs) in geom
@@ -4289,7 +4289,7 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
* Returns : -1 on failure, 0 on success.
*/
static int
-mega_partsize(Disk * disk, kdev_t dev, int *geom)
+mega_partsize(Disk * disk, struct block_device *bdev, int *geom)
{
struct partition *p, *largest = NULL;
int i, largest_cyl;
@@ -4297,7 +4297,7 @@ mega_partsize(Disk * disk, kdev_t dev, int *geom)
int capacity = disk->capacity;
unsigned char *buf;
- if (!(buf = scsi_bios_ptable(dev)))
+ if (!(buf = scsi_bios_ptable(bdev)))
return -1;
if( *(unsigned short *)(buf + 64) == 0xAA55 ) {
@@ -4534,7 +4534,6 @@ static int megadev_ioctl (struct inode *inode, struct file *filep,
unsigned int cmd, unsigned long arg)
{
int adapno;
- kdev_t dev;
u32 inlen;
struct uioctl_t ioc;
char *kvaddr = NULL;
@@ -4561,8 +4560,6 @@ static int megadev_ioctl (struct inode *inode, struct file *filep,
if (!inode)
return -EINVAL;
- dev = inode->i_rdev;
-
if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC)
return (-EINVAL);
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index c7f011222769..746252eb44c9 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -950,7 +950,7 @@ int megaraid_command (Scsi_Cmnd *);
int megaraid_abort (Scsi_Cmnd *);
int megaraid_reset (Scsi_Cmnd *, unsigned int);
int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-int megaraid_biosparam (Disk *, kdev_t, int *);
+int megaraid_biosparam (Disk *, struct block_device *, int *);
int megaraid_proc_info (char *buffer, char **start, off_t offset,
int length, int hostno, int inout);
@@ -998,7 +998,7 @@ static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *,
static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *,
mega_scb *, Scsi_Cmnd *);
static void mega_enum_raid_scsi(mega_host_config *);
-static int mega_partsize(Disk *, kdev_t, int *);
+static int mega_partsize(Disk *, struct block_device *, int *);
static void mega_get_boot_ldrv(mega_host_config *);
static int mega_get_lun(mega_host_config *, Scsi_Cmnd *);
static int mega_support_random_del(mega_host_config *);
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 339287d6238e..5c347dc8edea 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -486,7 +486,7 @@ int __init pas16_detect(Scsi_Host_Template * tpnt)
}
/*
- * Function : int pas16_biosparam(Disk *disk, kdev_t dev, int *ip)
+ * Function : int pas16_biosparam(Disk *disk, struct block_device *dev, int *ip)
*
* Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
* the specified device / size.
@@ -505,7 +505,7 @@ int __init pas16_detect(Scsi_Host_Template * tpnt)
* and matching the H_C_S coordinates to what DOS uses.
*/
-int pas16_biosparam(Disk * disk, kdev_t dev, int * ip)
+int pas16_biosparam(Disk * disk, struct block_device *dev, int * ip)
{
int size = disk->capacity;
ip[0] = 64;
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index 543a4cfc502f..e16e94bb312a 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -115,7 +115,7 @@
#ifndef ASM
int pas16_abort(Scsi_Cmnd *);
-int pas16_biosparam(Disk *, kdev_t, int*);
+int pas16_biosparam(Disk *, struct block_device *, int*);
int pas16_detect(Scsi_Host_Template *);
int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int pas16_reset(Scsi_Cmnd *, unsigned int);
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
index 0e86e7362f90..1b840371057b 100644
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -830,7 +830,7 @@ int Pci2000_Release (struct Scsi_Host *pshost)
* Returns: zero.
*
****************************************************************/
-int Pci2000_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
+int Pci2000_BiosParam (Scsi_Disk *disk, struct block_device *dev, int geom[])
{
PADAPTER2000 padapter;
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
index fe990d4e93d0..dd5882c7091a 100644
--- a/drivers/scsi/pci2000.h
+++ b/drivers/scsi/pci2000.h
@@ -22,7 +22,6 @@
#define _PCI2000_H
#include <linux/types.h>
-#include <linux/kdev_t.h>
#ifndef PSI_EIDE_SCSIOP
#define PSI_EIDE_SCSIOP 1
@@ -194,7 +193,7 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
int Pci2000_Abort (Scsi_Cmnd *SCpnt);
int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
int Pci2000_Release (struct Scsi_Host *pshost);
-int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
+int Pci2000_BiosParam (Disk *disk, struct block_device *dev, int geom[]);
#ifndef NULL
#define NULL 0
diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
index 77f007e9d85a..4c0cb5f6df45 100644
--- a/drivers/scsi/pci2220i.c
+++ b/drivers/scsi/pci2220i.c
@@ -49,7 +49,6 @@
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
-#include <linux/kdev_t.h>
#include <linux/blk.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
@@ -2903,7 +2902,7 @@ int Pci2220i_Release (struct Scsi_Host *pshost)
* Returns: zero.
*
****************************************************************/
-int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
+int Pci2220i_BiosParam (Scsi_Disk *disk, struct block_device *dev, int geom[])
{
POUR_DEVICE pdev;
diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h
index e7aad4d958e6..d34b3a0acea3 100644
--- a/drivers/scsi/pci2220i.h
+++ b/drivers/scsi/pci2220i.h
@@ -33,7 +33,7 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
int Pci2220i_Abort (Scsi_Cmnd *SCpnt);
int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
int Pci2220i_Release (struct Scsi_Host *pshost);
-int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
+int Pci2220i_BiosParam (Disk *disk, struct block_device *dev, int geom[]);
#ifndef NULL
#define NULL 0
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index f0618cd93f6b..dd4d0544e18f 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -998,7 +998,7 @@ int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
* be done in sd.c. Even if it gets fixed there, this will still
* work.
*/
-int ppa_biosparam(Disk * disk, kdev_t dev, int ip[])
+int ppa_biosparam(Disk * disk, struct block_device *dev, int ip[])
{
ip[0] = 0x40;
ip[1] = 0x20;
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index 7479092b906e..b789f94734b6 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -170,7 +170,7 @@ int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int ppa_abort(Scsi_Cmnd *);
int ppa_reset(Scsi_Cmnd *);
int ppa_proc_info(char *, char **, off_t, int, int, int);
-int ppa_biosparam(Disk *, kdev_t, int *);
+int ppa_biosparam(Disk *, struct block_device *, int *);
#define PPA { proc_name: "ppa", \
proc_info: ppa_proc_info, \
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
index 8ea40aab26cc..cfb7f3f7ae5e 100644
--- a/drivers/scsi/psi240i.c
+++ b/drivers/scsi/psi240i.c
@@ -703,7 +703,7 @@ int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
* Returns: zero.
*
****************************************************************/
-int Psi240i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
+int Psi240i_BiosParam (Scsi_Disk *disk, struct block_device *dev, int geom[])
{
POUR_DEVICE pdev;
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
index d41a5298a805..904c3870b3b9 100644
--- a/drivers/scsi/psi240i.h
+++ b/drivers/scsi/psi240i.h
@@ -28,7 +28,6 @@
#define _PSI240I_H
#include <linux/types.h>
-#include <linux/kdev_t.h>
#ifndef PSI_EIDE_SCSIOP
#define PSI_EIDE_SCSIOP 1
@@ -315,7 +314,7 @@ int Psi240i_Command (Scsi_Cmnd *SCpnt);
int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
int Psi240i_Abort (Scsi_Cmnd *SCpnt);
int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
-int Psi240i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
+int Psi240i_BiosParam (Disk *disk, struct block_device * dev, int geom[]);
#ifndef NULL
#define NULL 0
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 9debb242fe73..7930540f1bb6 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -1699,7 +1699,7 @@ qla1280_reset(Scsi_Cmnd * cmd, unsigned int flags)
* Return the disk geometry for the given SCSI device.
**************************************************************************/
int
-qla1280_biosparam(Disk * disk, kdev_t dev, int geom[])
+qla1280_biosparam(Disk * disk, struct block_device *dev, int geom[])
{
int heads, sectors, cylinders;
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
index 76b60c6e3d73..b8b90c170ee2 100644
--- a/drivers/scsi/qla1280.h
+++ b/drivers/scsi/qla1280.h
@@ -1313,7 +1313,7 @@ int qla1280_release(struct Scsi_Host *);
int qla1280_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int qla1280_abort(Scsi_Cmnd *);
int qla1280_reset(Scsi_Cmnd *, unsigned int);
-int qla1280_biosparam(Disk *, kdev_t, int[]);
+int qla1280_biosparam(Disk *, struct block_device *, int[]);
void qla1280_intr_handler(int, void *, struct pt_regs *);
void qla1280_setup(char *s, int *dummy);
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 6fdb00edcfac..dc589a0a5f32 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -651,7 +651,7 @@ host->proc_name = "qlogicfas";
/*----------------------------------------------------------------*/
/* return bios parameters */
-int qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[])
+int qlogicfas_biosparam(Disk * disk, struct block_device *dev, int ip[])
{
/* This should mimic the DOS Qlogic driver's behavior exactly */
ip[0] = 0x40;
diff --git a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h
index 78129c4d0769..cca31ef3df58 100644
--- a/drivers/scsi/qlogicfas.h
+++ b/drivers/scsi/qlogicfas.h
@@ -7,7 +7,7 @@ int qlogicfas_command(Scsi_Cmnd *);
int qlogicfas_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int qlogicfas_abort(Scsi_Cmnd *);
int qlogicfas_reset(Scsi_Cmnd *, unsigned int);
-int qlogicfas_biosparam(Disk *, kdev_t, int[]);
+int qlogicfas_biosparam(Disk *, struct block_device *, int[]);
#ifndef NULL
#define NULL (0)
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
index 32627b9e3c05..6ae15e45a619 100644
--- a/drivers/scsi/qlogicfc.c
+++ b/drivers/scsi/qlogicfc.c
@@ -1800,7 +1800,7 @@ int isp2x00_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags)
}
-int isp2x00_biosparam(Disk * disk, kdev_t n, int ip[])
+int isp2x00_biosparam(Disk * disk, struct block_device *n, int ip[])
{
int size = disk->capacity;
diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h
index d8831ccb2328..e67e9f5af274 100644
--- a/drivers/scsi/qlogicfc.h
+++ b/drivers/scsi/qlogicfc.h
@@ -75,7 +75,7 @@ const char * isp2x00_info(struct Scsi_Host *);
int isp2x00_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int isp2x00_abort(Scsi_Cmnd *);
int isp2x00_reset(Scsi_Cmnd *, unsigned int);
-int isp2x00_biosparam(Disk *, kdev_t, int[]);
+int isp2x00_biosparam(Disk *, struct block_device *, int[]);
#ifndef NULL
#define NULL (0)
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
index edfa513d9614..4d233ac5d9b0 100644
--- a/drivers/scsi/qlogicisp.c
+++ b/drivers/scsi/qlogicisp.c
@@ -1240,7 +1240,7 @@ int isp1020_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
}
-int isp1020_biosparam(Disk *disk, kdev_t n, int ip[])
+int isp1020_biosparam(Disk *disk, struct block_device *n, int ip[])
{
int size = disk->capacity;
diff --git a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h
index 85940ed2f6ae..724d807dfd72 100644
--- a/drivers/scsi/qlogicisp.h
+++ b/drivers/scsi/qlogicisp.h
@@ -64,7 +64,7 @@ const char * isp1020_info(struct Scsi_Host *);
int isp1020_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int isp1020_abort(Scsi_Cmnd *);
int isp1020_reset(Scsi_Cmnd *, unsigned int);
-int isp1020_biosparam(Disk *, kdev_t, int[]);
+int isp1020_biosparam(Disk *, struct block_device *, int[]);
#ifndef NULL
#define NULL (0)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 058688349f5d..4f7ae5c4fc34 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1008,7 +1008,7 @@ static int scsi_debug_abort(Scsi_Cmnd * SCpnt)
#endif
}
-static int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
+static int scsi_debug_biosparam(Disk * disk, struct block_device *dev, int *info)
{
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: biosparam\n");
diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
index d1eb11c93fd6..92290b6158d5 100644
--- a/drivers/scsi/scsi_debug.h
+++ b/drivers/scsi/scsi_debug.h
@@ -1,13 +1,12 @@
#ifndef _SCSI_DEBUG_H
#include <linux/types.h>
-#include <linux/kdev_t.h>
static int scsi_debug_detect(Scsi_Host_Template *);
/* static int scsi_debug_command(Scsi_Cmnd *); */
static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
static int scsi_debug_abort(Scsi_Cmnd *);
-static int scsi_debug_biosparam(Disk *, kdev_t, int[]);
+static int scsi_debug_biosparam(Disk *, struct block_device *, int[]);
static int scsi_debug_bus_reset(Scsi_Cmnd *);
static int scsi_debug_device_reset(Scsi_Cmnd *);
static int scsi_debug_host_reset(Scsi_Cmnd *);
diff --git a/drivers/scsi/scsi_mid_low_api.txt b/drivers/scsi/scsi_mid_low_api.txt
index 8af86db6d3f2..fbde06519c97 100644
--- a/drivers/scsi/scsi_mid_low_api.txt
+++ b/drivers/scsi/scsi_mid_low_api.txt
@@ -85,7 +85,7 @@ The interface functions are listed below in alphabetical order.
* pre-initialized with made up values just in case this function
* doesn't output anything.
**/
- int bios_param(Scsi_Disk * sdkp, kdev_t dev, int params[3]);
+ int bios_param(Scsi_Disk * sdkp, struct block_device *bdev, int params[3]);
/**
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index 7559b235eba3..db6ca281c59e 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -26,39 +26,25 @@
static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
unsigned int *secs);
-unsigned char *scsi_bios_ptable(kdev_t dev)
+unsigned char *scsi_bios_ptable(struct block_device *dev)
{
- struct block_device *bdev;
unsigned char *res = kmalloc(66, GFP_KERNEL);
- kdev_t rdev = mk_kdev(major(dev), minor(dev) & ~0x0f);
-
if (res) {
- struct buffer_head *bh;
- int err;
-
- bdev = bdget(kdev_t_to_nr(rdev));
- if (!bdev)
- goto fail;
- err = blkdev_get(bdev, FMODE_READ, 0, BDEV_FILE);
- if (err)
- goto fail;
- bh = __bread(bdev, 0, block_size(bdev));
- if (!bh)
- goto fail2;
- memcpy(res, bh->b_data + 0x1be, 66);
- brelse(bh);
- blkdev_put(bdev, BDEV_FILE);
+ struct block_device *bdev = dev->bd_contains;
+ struct buffer_head *bh = __bread(bdev, 0, block_size(bdev));
+ if (bh) {
+ memcpy(res, bh->b_data + 0x1be, 66);
+ brelse(bh);
+ } else {
+ kfree(res);
+ res = NULL;
+ }
}
return res;
-fail2:
- blkdev_put(bdev, BDEV_FILE);
-fail:
- kfree(res);
- return NULL;
}
/*
- * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip)
+ * Function : int scsicam_bios_param (Disk *disk, struct block_device *bdev, int *ip)
*
* Purpose : to determine the BIOS mapping used for a drive in a
* SCSI-CAM system, storing the results in ip as required
@@ -69,13 +55,13 @@ fail:
*/
int scsicam_bios_param(Disk * disk, /* SCSI disk */
- kdev_t dev, /* Device major, minor */
+ struct block_device *bdev,
int *ip /* Heads, sectors, cylinders in that order */ )
{
int ret_code;
int size = disk->capacity;
unsigned long temp_cyl;
- unsigned char *p = scsi_bios_ptable(dev);
+ unsigned char *p = scsi_bios_ptable(bdev);
if (!p)
return -1;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index fd92ed1924f1..f6dd5107974d 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -233,33 +233,20 @@ static int sd_ioctl(struct inode * inode, struct file * filp,
or driver values */
if(host->hostt->bios_param != NULL)
- host->hostt->bios_param(sdkp, dev,
+ host->hostt->bios_param(sdkp, inode->i_bdev,
&diskinfo[0]);
else
- scsicam_bios_param(sdkp, dev, &diskinfo[0]);
+ scsicam_bios_param(sdkp, inode->i_bdev, &diskinfo[0]);
if (put_user(diskinfo[0], &loc->heads) ||
put_user(diskinfo[1], &loc->sectors) ||
put_user(diskinfo[2], &loc->cylinders) ||
put_user((unsigned)
- get_start_sect(inode->i_rdev),
+ get_start_sect(inode->i_bdev),
(unsigned long *) &loc->start))
return -EFAULT;
return 0;
}
- case BLKGETSIZE:
- case BLKGETSIZE64:
- case BLKROSET:
- case BLKROGET:
- case BLKFLSBUF:
- case BLKSSZGET:
- case BLKPG:
- case BLKELVGET:
- case BLKELVSET:
- case BLKBSZGET:
- case BLKBSZSET:
- return blk_ioctl(inode->i_bdev, cmd, arg);
-
case BLKRRPART: /* Re-read partition tables */
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -507,16 +494,6 @@ static int sd_open(struct inode *inode, struct file *filp)
if (!scsi_block_when_processing_errors(sdp))
return -ENXIO;
/*
- * Make sure that only one process can do a check_change_disk at
- * one time. This is also used to lock out further access when
- * the partition table is being re-read.
- */
-
- while (sdp->busy) {
- barrier();
- cpu_relax();
- }
- /*
* The following code can sleep.
* Module unloading must be prevented
*/
@@ -527,9 +504,7 @@ static int sd_open(struct inode *inode, struct file *filp)
sdp->access_count++;
if (sdp->removable) {
- sdp->allow_revalidate = 1;
check_disk_change(inode->i_rdev);
- sdp->allow_revalidate = 0;
/*
* If the drive is empty, just let the open fail.
@@ -1464,9 +1439,10 @@ static int sd_attach(Scsi_Device * sdp)
int revalidate_scsidisk(kdev_t dev, int maxusage)
{
int dsk_nr = DEVICE_NR(dev);
- int res;
Scsi_Disk * sdkp;
Scsi_Device * sdp;
+ kdev_t device = mk_kdev(major(dev), minor(dev) & ~15);
+ int res;
SCSI_LOG_HLQUEUE(3, printk("revalidate_scsidisk: dsk_nr=%d\n",
DEVICE_NR(dev)));
@@ -1474,24 +1450,20 @@ int revalidate_scsidisk(kdev_t dev, int maxusage)
if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
return -ENODEV;
- if (sdp->busy || ((sdp->allow_revalidate == 0) &&
- (sdp->access_count > maxusage))) {
- printk(KERN_WARNING "Device busy for revalidation "
- "(access_count=%d)\n", sdp->access_count);
- return -EBUSY;
- }
- sdp->busy = 1;
+ res = dev_lock_part(device);
+ if (res < 0)
+ return res;
- res = wipe_partitions(dev);
+ res = wipe_partitions(device);
if (res)
goto leave;
sd_init_onedisk(sdkp, dsk_nr);
- grok_partitions(dev, sdkp->capacity);
+ grok_partitions(device, sdkp->capacity);
leave:
- sdp->busy = 0;
+ dev_unlock_part(device);
return res;
}
diff --git a/drivers/scsi/sim710.h b/drivers/scsi/sim710.h
index 2fd837fea8a2..7cd2ff5558d7 100644
--- a/drivers/scsi/sim710.h
+++ b/drivers/scsi/sim710.h
@@ -14,7 +14,7 @@ int sim710_abort(Scsi_Cmnd * SCpnt);
int sim710_bus_reset(Scsi_Cmnd * SCpnt);
int sim710_dev_reset(Scsi_Cmnd * SCpnt);
int sim710_host_reset(Scsi_Cmnd * SCpnt);
-int sim710_biosparam(Disk *, kdev_t, int*);
+int sim710_biosparam(Disk *, struct block_device *, int*);
#ifdef MODULE
int sim710_release(struct Scsi_Host *);
#else
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 2ad532933c49..e32c05b5ddc4 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -828,7 +828,7 @@ static int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
return SCSI_RESET_PENDING;
}
-static int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
+static int sym53c416_bios_param(Disk *disk, struct block_device *dev, int *ip)
{
int size;
diff --git a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h
index 8124b1c78d28..0ecf3917626a 100644
--- a/drivers/scsi/sym53c416.h
+++ b/drivers/scsi/sym53c416.h
@@ -27,7 +27,6 @@
#endif
#include <linux/types.h>
-#include <linux/kdev_t.h>
#define SYM53C416_SCSI_ID 7
@@ -37,7 +36,7 @@ static int sym53c416_command(Scsi_Cmnd *);
static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
static int sym53c416_abort(Scsi_Cmnd *);
static int sym53c416_reset(Scsi_Cmnd *, unsigned int);
-static int sym53c416_bios_param(Disk *, kdev_t, int *);
+static int sym53c416_bios_param(Disk *, struct block_device *, int *);
static void sym53c416_setup(char *str, int *ints);
#define SYM53C416 { \
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index a803b1ab9474..4bd494a01a1c 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -279,7 +279,7 @@ int __init t128_detect(Scsi_Host_Template * tpnt){
}
/*
- * Function : int t128_biosparam(Disk * disk, kdev_t dev, int *ip)
+ * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip)
*
* Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
* the specified device / size.
@@ -298,7 +298,7 @@ int __init t128_detect(Scsi_Host_Template * tpnt){
* and matching the H_C_S coordinates to what DOS uses.
*/
-int t128_biosparam(Disk * disk, kdev_t dev, int * ip)
+int t128_biosparam(Disk * disk, struct block_device *dev, int * ip)
{
int size = disk->capacity;
ip[0] = 64;
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index f315160773ef..e07449e524ab 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -92,7 +92,7 @@
#ifndef ASM
int t128_abort(Scsi_Cmnd *);
-int t128_biosparam(Disk *, kdev_t, int*);
+int t128_biosparam(Disk *, struct block_device *, int*);
int t128_detect(Scsi_Host_Template *);
int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int t128_reset(Scsi_Cmnd *, unsigned int reset_flags);
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index dac2c059d02b..e9bd6a72ffbc 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -1439,7 +1439,7 @@ static int partsize(unsigned char *buf, unsigned long capacity,
* Note:
* In contrary to other externally callable funcs (DC390_), we don't lock
***********************************************************************/
-int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
+int DC390_bios_param (Disk *disk, struct block_device *bdev, int geom[])
{
int heads, sectors, cylinders;
PACB pACB = (PACB) disk->device->host->hostdata;
@@ -1447,7 +1447,7 @@ int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
int size = disk->capacity;
unsigned char *buf;
- if ((buf = scsi_bios_ptable(devno)))
+ if ((buf = scsi_bios_ptable(bdev)))
{
/* try to infer mapping from partition table */
ret_code = partsize (buf, (unsigned long) size, (unsigned int *) geom + 2,
@@ -1475,9 +1475,9 @@ int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
return (0);
}
#else
-int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
+int DC390_bios_param (Disk *disk, struct block_device *bdev, int geom[])
{
- return scsicam_bios_param (disk, devno, geom);
+ return scsicam_bios_param (disk, bdev, geom);
};
#endif
@@ -2525,8 +2525,8 @@ else if (!p1) goto ok2
if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; \
else if (!p1) goto ok2
-#define SEARCH3(buffer, pos, &p0, var, txt, max, scale, ign) \
-if (dc390_search (&buffer, &pos, p0, &var, txt, max, scale, ign)) goto einv2; \
+#define SEARCH3(buffer, pos, p0, var, txt, max, scale, ign) \
+if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, ign)) goto einv2; \
else if (!p1) goto ok2
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 6de097b8368b..993109521385 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1452,7 +1452,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg) {
return do_reset(SCarg);
}
-int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
+int u14_34f_biosparam(Disk *disk, struct block_device *bdev, int *dkinfo) {
unsigned int j = 0;
int size = disk->capacity;
@@ -1460,7 +1460,7 @@ int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
dkinfo[1] = HD(j)->sectors;
dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
- if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+ if (ext_tran && (scsicam_bios_param(disk, bdev, dkinfo) < 0)) {
dkinfo[0] = 255;
dkinfo[1] = 63;
dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h
index c5dfe2d80f55..fe8fe7830a1a 100644
--- a/drivers/scsi/u14-34f.h
+++ b/drivers/scsi/u14-34f.h
@@ -11,7 +11,7 @@ int u14_34f_release(struct Scsi_Host *);
int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int u14_34f_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *);
-int u14_34f_biosparam(Disk *, kdev_t, int *);
+int u14_34f_biosparam(Disk *, struct block_device *, int *);
#define U14_34F_VERSION "7.22.00"
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 1a042201b07a..1876d52a86ab 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -1020,7 +1020,7 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
}
-int ultrastor_biosparam(Disk * disk, kdev_t dev, int * dkinfo)
+int ultrastor_biosparam(Disk * disk, struct block_device *dev, int * dkinfo)
{
int size = disk->capacity;
unsigned int s = config.heads * config.sectors;
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index ffe57ec18b80..4dcb9def40fd 100644
--- a/drivers/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -12,14 +12,13 @@
#ifndef _ULTRASTOR_H
#define _ULTRASTOR_H
-#include <linux/kdev_t.h>
int ultrastor_detect(Scsi_Host_Template *);
const char *ultrastor_info(struct Scsi_Host * shpnt);
int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int ultrastor_abort(Scsi_Cmnd *);
int ultrastor_reset(Scsi_Cmnd *, unsigned int);
-int ultrastor_biosparam(Disk *, kdev_t, int *);
+int ultrastor_biosparam(Disk *, struct block_device *, int *);
#define ULTRASTOR_14F_MAX_SG 16
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 3e1bafa68cb1..97c891fb9f03 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1706,9 +1706,9 @@ int wd7000_reset (Scsi_Cmnd *SCpnt, unsigned int unused)
/*
* This was borrowed directly from aha1542.c. (Zaga)
*/
-int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
+int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip)
{
- dprintk("wd7000_biosparam: dev=%s, size=%d, ", kdevname(dev),
+ dprintk("wd7000_biosparam: dev=%s, size=%d, ", bdevname(bdev),
disk->capacity);
/*
@@ -1727,7 +1727,7 @@ int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
/*
* try to figure out the geometry from the partition table
*/
- if ((scsicam_bios_param (disk, dev, info) < 0) ||
+ if ((scsicam_bios_param (disk, bdev, info) < 0) ||
!(((info[0] == 64) && (info[1] == 32)) ||
((info[0] == 255) && (info[1] == 63)))) {
printk ("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n"
diff --git a/drivers/scsi/wd7000.h b/drivers/scsi/wd7000.h
index c90e07f787f0..a9570edcffce 100644
--- a/drivers/scsi/wd7000.h
+++ b/drivers/scsi/wd7000.h
@@ -12,7 +12,6 @@
*/
#include <linux/types.h>
-#include <linux/kdev_t.h>
int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host);
int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout);
@@ -21,7 +20,7 @@ int wd7000_command (Scsi_Cmnd *);
int wd7000_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int wd7000_abort (Scsi_Cmnd *);
int wd7000_reset (Scsi_Cmnd *, unsigned int);
-int wd7000_biosparam (Disk *, kdev_t, int *);
+int wd7000_biosparam (Disk *, struct block_device *, int *);
#ifndef NULL
#define NULL 0L
diff --git a/drivers/serial/Config.help b/drivers/serial/Config.help
new file mode 100644
index 000000000000..c9f938fbb513
--- /dev/null
+++ b/drivers/serial/Config.help
@@ -0,0 +1,225 @@
+# $Id: Config.help,v 1.5 2002/07/06 17:16:24 rmk Exp $
+
+CONFIG_SERIAL_8250
+ This selects whether you want to include the driver for the standard
+ serial ports. The standard answer is Y. People who might say N
+ here are those that are setting up dedicated Ethernet WWW/FTP
+ servers, or users that have one of the various bus mice instead of a
+ serial mouse and don't intend to use their machine's standard serial
+ port for anything. (Note that the Cyclades and Stallion multi
+ serial port drivers do not need this driver built in for them to
+ work.)
+
+ If you want to compile this driver as a module, say M here and read
+ <file:Documentation/modules.txt>. The module will be called
+ serial.o.
+ [WARNING: Do not compile this driver as a module if you are using
+ non-standard serial ports, since the configuration information will
+ be lost when the driver is unloaded. This limitation may be lifted
+ in the future.]
+
+ BTW1: If you have a mouseman serial mouse which is not recognized by
+ the X window system, try running gpm first.
+
+ BTW2: If you intend to use a software modem (also called Winmodem)
+ under Linux, forget it. These modems are crippled and require
+ proprietary drivers which are only available under Windows.
+
+ Most people will say Y or M here, so that they can use serial mice,
+ modems and similar devices connecting to the standard serial ports.
+
+CONFIG_SERIAL_8250_CONSOLE
+ If you say Y here, it will be possible to use a serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode). This could be useful if some terminal or printer is connected
+ to that serial port.
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyS1". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+ If you don't have a VGA card installed and you say Y here, the
+ kernel will automatically use the first serial line, /dev/ttyS0, as
+ system console.
+
+ If unsure, say N.
+
+CONFIG_SERIAL_8250_CS
+ Say Y here to enable support for 16-bit PCMCIA serial devices,
+ including serial port cards, modems, and the modem functions of
+ multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
+ credit-card size devices often used with laptops.)
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called serial_cs.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+ If unsure, say N.
+
+CONFIG_SERIAL_8250_EXTENDED
+ If you wish to use any non-standard features of the standard "dumb"
+ driver, say Y here. This includes HUB6 support, shared serial
+ interrupts, special multiport support, support for more than the
+ four COM 1/2/3/4 boards, etc.
+
+ Note that the answer to this question won't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about serial driver options. If unsure, say N.
+
+CONFIG_SERIAL_8250_MANY_PORTS
+ Say Y here if you have dumb serial boards other than the four
+ standard COM 1/2/3/4 ports. This may happen if you have an AST
+ FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
+ from <http://www.linuxdoc.org/docs.html#howto>), or other custom
+ serial port hardware which acts similar to standard serial port
+ hardware. If you only use the standard COM 1/2/3/4 ports, you can
+ say N here to save some memory. You can also say Y if you have an
+ "intelligent" multiport card such as Cyclades, Digiboards, etc.
+
+CONFIG_SERIAL_8250_SHARE_IRQ
+ Some serial boards have hardware support which allows multiple dumb
+ serial ports on the same board to share a single IRQ. To enable
+ support for this in the serial driver, say Y here.
+
+CONFIG_SERIAL_8250_DETECT_IRQ
+ Say Y here if you want the kernel to try to guess which IRQ
+ to use for your serial port.
+
+ This is considered unsafe; it is far better to configure the IRQ in
+ a boot script using the setserial command.
+
+ If unsure, say N.
+
+CONFIG_SERIAL_8250_MULTIPORT
+ Some multiport serial ports have special ports which are used to
+ signal when there are any serial ports on the board which need
+ servicing. Say Y here to enable the serial driver to take advantage
+ of those special I/O ports.
+
+CONFIG_SERIAL_8250_RSA
+ ::: To be written :::
+
+CONFIG_ATOMWIDE_SERIAL
+ If you have an Atomwide Serial card for an Acorn system, say Y to
+ this option. The driver can handle 1, 2, or 3 port cards.
+ If unsure, say N.
+
+CONFIG_DUALSP_SERIAL
+ If you have the Serial Port's dual serial card for an Acorn system,
+ say Y to this option. If unsure, say N.
+
+CONFIG_SERIAL_ANAKIN
+ ::: To be written :::
+CONFIG_SERIAL_ANAKIN_CONSOLE
+ ::: To be written :::
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyAN0". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+CONFIG_ANAKIN_DEFAULT_BAUDRATE
+ ::: To be written :::
+
+CONFIG_SERIAL_AMBA
+ This selects the ARM(R) AMBA(R) PrimeCell UART. If you have an
+ Integrator platform, say Y or M here.
+
+ If unsure, say N.
+
+CONFIG_SERIAL_AMBA_CONSOLE
+ Say Y here if you wish to use an AMBA PrimeCell UART as the system
+ console (the system console is the device which receives all kernel
+ messages and warnings and which allows logins in single user mode).
+
+ Even if you say Y here, the currently visible framebuffer console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyAM0". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+CONFIG_SERIAL_CLPS711X
+ ::: To be written :::
+
+CONFIG_SERIAL_CLPS711X_CONSOLE
+ ::: To be written :::
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyCL1". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+CONFIG_SERIAL_CLPS711X_OLD_NAME
+ ::: To be written :::
+
+CONFIG_SERIAL_21285
+ If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
+ PCI bridge you can enable its onboard serial port by enabling this
+ option.
+
+CONFIG_SERIAL_21285_OLD
+ Use the old /dev/ttyS name, major 4 minor 64. This is obsolete
+ and will be removed during later 2.5 development.
+
+CONFIG_SERIAL_21285_CONSOLE
+ If you have enabled the serial port on the 21285 footbridge you can
+ make it the console by answering Y to this option.
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyFB". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+CONFIG_SERIAL_UART00
+ Say Y here if you want to use the hard logic uart on Excalibur. This
+ driver also supports soft logic implentations of this uart core.
+
+CONFIG_SERIAL_UART00_CONSOLE
+ Say Y here if you want to support a serial console on an Excalibur
+ hard logic uart or uart00 IP core.
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyS1". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+CONFIG_SERIAL_SA1100
+ If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
+ can enable its onboard serial port by enabling this option.
+ Please read <file:Documentation/arm/SA1100/serial_UART> for further
+ info.
+
+CONFIG_SERIAL_SA1100_CONSOLE
+ If you have enabled the serial port on the SA1100/SA1110 StrongARM
+ CPU you can make it the console by answering Y to this option.
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttySA0". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+#CONFIG_SERIAL_L7200
+# If you have a LinkUp Systems L7200 board you can enable its two
+# onboard serial ports by enabling this option. The device numbers
+# are major ID 4 with minor 64 and 65 respectively.
+#
+#CONFIG_SERIAL_L7200_CONSOLE
+# If you have enabled the serial ports on the L7200 development board
+# you can make the first serial port the console by answering Y to
+# this option.
+
diff --git a/drivers/serial/Config.in b/drivers/serial/Config.in
new file mode 100644
index 000000000000..7783775e9420
--- /dev/null
+++ b/drivers/serial/Config.in
@@ -0,0 +1,77 @@
+#
+# Serial device configuration
+#
+# $Id: Config.in,v 1.15 2002/07/06 17:16:24 rmk Exp $
+#
+mainmenu_option next_comment
+comment 'Serial drivers'
+
+#
+# The new 8250/16550 serial drivers
+dep_tristate '8250/16550 and compatible serial support (EXPERIMENTAL)' CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL
+dep_bool ' Console on 8250/16550 and compatible serial port (EXPERIMENTAL)' CONFIG_SERIAL_8250_CONSOLE $CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL
+dep_tristate ' 8250/16550 PCMCIA device support' CONFIG_SERIAL_8250_CS $CONFIG_PCMCIA $CONFIG_SERIAL_8250
+
+dep_mbool 'Extended 8250/16550 serial driver options' CONFIG_SERIAL_8250_EXTENDED $CONFIG_SERIAL_8250
+dep_bool ' Support more than 4 serial ports' CONFIG_SERIAL_8250_MANY_PORTS $CONFIG_SERIAL_8250_EXTENDED
+dep_bool ' Support for sharing serial interrupts' CONFIG_SERIAL_8250_SHARE_IRQ $CONFIG_SERIAL_8250_EXTENDED
+dep_bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_8250_DETECT_IRQ $CONFIG_SERIAL_8250_EXTENDED
+dep_bool ' Support special multiport boards' CONFIG_SERIAL_8250_MULTIPORT $CONFIG_SERIAL_8250_EXTENDED
+dep_bool ' Support RSA serial ports' CONFIG_SERIAL_8250_RSA $CONFIG_SERIAL_8250_EXTENDED
+
+comment 'Non-8250 serial port support'
+
+if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate 'Acorn Atomwide 16550 serial port support' CONFIG_ATOMWIDE_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250
+ dep_tristate 'Acorn Dual 16550 serial port support' CONFIG_DUALSP_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250
+ dep_bool 'Anakin serial port support' CONFIG_SERIAL_ANAKIN $CONFIG_ARCH_ANAKIN
+ dep_bool ' Console on Anakin serial port' CONFIG_SERIAL_ANAKIN_CONSOLE $CONFIG_SERIAL_ANAKIN
+ if [ "$CONFIG_SERIAL_ANAKIN" = "y" ]; then
+ int ' Default Anakin serial baudrate' CONFIG_ANAKIN_DEFAULT_BAUDRATE 9600
+ fi
+
+ dep_tristate 'ARM AMBA serial port support' CONFIG_SERIAL_AMBA $CONFIG_ARCH_INTEGRATOR
+ dep_bool ' Support for console on AMBA serial port' CONFIG_SERIAL_AMBA_CONSOLE $CONFIG_SERIAL_AMBA
+ if [ "$CONFIG_SERIAL_AMBA" = "y" ]; then
+ define_bool CONFIG_SERIAL_INTEGRATOR y
+ fi
+
+ dep_tristate 'CLPS711X serial port support' CONFIG_SERIAL_CLPS711X $CONFIG_ARCH_CLPS711X
+ dep_bool ' Support for console on CLPS711X serial port' CONFIG_SERIAL_CLPS711X_CONSOLE $CONFIG_SERIAL_CLPS711X
+ dep_bool ' Use the old 2.4 names for CLPS711X serial port' CONFIG_SERIAL_CLPS711X_OLD_NAME $CONFIG_SERIAL_CLPS711X
+
+ dep_tristate 'DC21285 serial port support' CONFIG_SERIAL_21285 $CONFIG_FOOTBRIDGE
+ dep_bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD $CONFIG_SERIAL_21285 $CONFIG_OBSOLETE
+ dep_bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE $CONFIG_SERIAL_21285
+
+ dep_bool 'Excalibur serial port (uart00) support' CONFIG_SERIAL_UART00 $CONFIG_ARCH_CAMELOT
+ dep_bool ' Support for console on Excalibur serial port' CONFIG_SERIAL_UART00_CONSOLE $CONFIG_SERIAL_UART00
+
+ dep_bool 'SA1100 serial port support' CONFIG_SERIAL_SA1100 $CONFIG_ARCH_SA1100
+ dep_bool ' Console on SA1100 serial port' CONFIG_SERIAL_SA1100_CONSOLE $CONFIG_SERIAL_SA1100
+fi
+
+if [ "$CONFIG_SERIAL_AMBA" = "y" -o "$CONFIG_SERIAL_CLPS711X" = "y" -o \
+ "$CONFIG_SERIAL_21285" = "y" -o "$CONFIG_SERIAL_SA1100" = "y" -o \
+ "$CONFIG_SERIAL_ANAKIN" = "y" -o "$CONFIG_SERIAL_UART00" = "y" -o \
+ "$CONFIG_SERIAL_8250" = "y" -o "$CONFIG_SERIAL_ROCKETPORT" = "y" ]; then
+ define_bool CONFIG_SERIAL_CORE y
+else
+ if [ "$CONFIG_SERIAL_AMBA" = "m" -o "$CONFIG_SERIAL_CLPS711X" = "m" -o \
+ "$CONFIG_SERIAL_21285" = "m" -o "$CONFIG_SERIAL_SA1100" = "m" -o \
+ "$CONFIG_SERIAL_ANAKIN" = "m" -o "$CONFIG_SERIAL_UART00" = "m" -o \
+ "$CONFIG_SERIAL_8250" = "m" -o "$CONFIG_SERIAL_ROCKETPORT" = "m" ]; then
+ define_bool CONFIG_SERIAL_CORE m
+ fi
+fi
+if [ "$CONFIG_SERIAL_AMBA_CONSOLE" = "y" -o \
+ "$CONFIG_SERIAL_CLPS711X_CONSOLE" = "y" -o \
+ "$CONFIG_SERIAL_21285_CONSOLE" = "y" -o \
+ "$CONFIG_SERIAL_SA1100_CONSOLE" = "y" -o \
+ "$CONFIG_SERIAL_ANAKIN_CONSOLE" = "y" -o \
+ "$CONFIG_SERIAL_UART00_CONSOLE" = "y" -o \
+ "$CONFIG_SERIAL_8250_CONSOLE" = "y" ]; then
+ define_bool CONFIG_SERIAL_CORE_CONSOLE y
+fi
+
+endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
new file mode 100644
index 000000000000..613e9d9b7cef
--- /dev/null
+++ b/drivers/serial/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the kernel serial device drivers.
+#
+# $Id: Makefile,v 1.7 2002/07/06 17:16:24 rmk Exp $
+#
+
+export-objs := serial_core.o serial_8250.o
+
+serial-8250-y :=
+serial-8250-$(CONFIG_PCI) += serial_8250_pci.o
+serial-8250-$(CONFIG_ISAPNP) += serial_8250_pnp.o
+obj-$(CONFIG_SERIAL_CORE) += serial_core.o
+obj-$(CONFIG_SERIAL_21285) += serial_21285.o
+obj-$(CONFIG_SERIAL_8250) += serial_8250.o $(serial-8250-y)
+obj-$(CONFIG_SERIAL_8250_CS) += serial_8250_cs.o
+obj-$(CONFIG_SERIAL_ANAKIN) += serial_anakin.o
+obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o
+obj-$(CONFIG_SERIAL_CLPS711X) += serial_clps711x.o
+obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
+obj-$(CONFIG_SERIAL_UART00) += serial_uart00.o
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/serial/serial_21285.c b/drivers/serial/serial_21285.c
new file mode 100644
index 000000000000..0b63b3a7deb6
--- /dev/null
+++ b/drivers/serial/serial_21285.c
@@ -0,0 +1,553 @@
+/*
+ * linux/drivers/char/serial_21285.c
+ *
+ * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
+ *
+ * Based on drivers/char/serial.c
+ *
+ * $Id: serial_21285.c,v 1.32 2002/07/21 08:57:55 rmk Exp $
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/hardware/dec21285.h>
+#include <asm/hardware.h>
+
+#define BAUD_BASE (mem_fclk_21285/64)
+
+#define SERIAL_21285_NAME "ttyFB"
+#define SERIAL_21285_MAJOR 204
+#define SERIAL_21285_MINOR 4
+
+#define RXSTAT_DUMMY_READ 0x80000000
+#define RXSTAT_FRAME (1 << 0)
+#define RXSTAT_PARITY (1 << 1)
+#define RXSTAT_OVERRUN (1 << 2)
+#define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
+
+#define H_UBRLCR_BREAK (1 << 0)
+#define H_UBRLCR_PARENB (1 << 1)
+#define H_UBRLCR_PAREVN (1 << 2)
+#define H_UBRLCR_STOPB (1 << 3)
+#define H_UBRLCR_FIFO (1 << 4)
+
+static const char serial21285_name[] = "Footbridge UART";
+
+#define tx_enabled(port) ((port)->unused[0])
+#define rx_enabled(port) ((port)->unused[1])
+
+/*
+ * The documented expression for selecting the divisor is:
+ * BAUD_BASE / baud - 1
+ * However, typically BAUD_BASE is not divisible by baud, so
+ * we want to select the divisor that gives us the minimum
+ * error. Therefore, we want:
+ * int(BAUD_BASE / baud - 0.5) ->
+ * int(BAUD_BASE / baud - (baud >> 1) / baud) ->
+ * int((BAUD_BASE - (baud >> 1)) / baud)
+ */
+
+static void __serial21285_stop_tx(struct uart_port *port)
+{
+ if (tx_enabled(port)) {
+ disable_irq(IRQ_CONTX);
+ tx_enabled(port) = 0;
+ }
+}
+
+static void
+serial21285_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ __serial21285_stop_tx(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+serial21285_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tx_enabled(port)) {
+ enable_irq(IRQ_CONTX);
+ tx_enabled(port) = 1;
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void serial21285_stop_rx(struct uart_port *port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (rx_enabled(port)) {
+ disable_irq(IRQ_CONRX);
+ rx_enabled(port) = 0;
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void serial21285_enable_ms(struct uart_port *port)
+{
+}
+
+static void serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty = port->info->tty;
+ unsigned int status, ch, rxs, max_count = 256;
+
+ status = *CSR_UARTFLG;
+ while (!(status & 0x10) && max_count--) {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty->flip.tqueue.routine((void *)tty);
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+ return;
+ }
+ }
+
+ ch = *CSR_UARTDR;
+
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = TTY_NORMAL;
+ port->icount.rx++;
+
+ rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
+ if (rxs & RXSTAT_ANYERR) {
+ if (rxs & RXSTAT_PARITY)
+ port->icount.parity++;
+ else if (rxs & RXSTAT_FRAME)
+ port->icount.frame++;
+ if (rxs & RXSTAT_OVERRUN)
+ port->icount.overrun++;
+
+ rxs &= port->read_status_mask;
+
+ if (rxs & RXSTAT_PARITY)
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ else if (rxs & RXSTAT_FRAME)
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ }
+
+ if ((rxs & port->ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((rxs & RXSTAT_OVERRUN) &&
+ tty->flip.count < TTY_FLIPBUF_SIZE) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character.
+ */
+ *tty->flip.char_buf_ptr++ = 0;
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ tty->flip.count++;
+ }
+ status = *CSR_UARTFLG;
+ }
+ tty_flip_buffer_push(tty);
+}
+
+static void serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = dev_id;
+ struct circ_buf *xmit = &port->info->xmit;
+ int count = 256;
+
+ if (port->x_char) {
+ *CSR_UARTDR = port->x_char;
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ __serial21285_stop_tx(port);
+ return;
+ }
+
+ do {
+ *CSR_UARTDR = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0 && !(*CSR_UARTFLG & 0x20));
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(port, EVT_WRITE_WAKEUP);
+
+ if (uart_circ_empty(xmit))
+ __serial21285_stop_tx(port);
+}
+
+static unsigned int serial21285_tx_empty(struct uart_port *port)
+{
+ return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
+}
+
+/* no modem control lines */
+static unsigned int serial21285_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void serial21285_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+ unsigned int h_lcr;
+
+ spin_lock_irqsave(&port->lock, flags);
+ h_lcr = *CSR_H_UBRLCR;
+ if (break_state)
+ h_lcr |= H_UBRLCR_BREAK;
+ else
+ h_lcr &= ~H_UBRLCR_BREAK;
+ *CSR_H_UBRLCR = h_lcr;
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int serial21285_startup(struct uart_port *port)
+{
+ int ret;
+
+ tx_enabled(port) = 1;
+ rx_enabled(port) = 1;
+
+ ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
+ serial21285_name, port);
+ if (ret == 0) {
+ ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
+ serial21285_name, port);
+ if (ret)
+ free_irq(IRQ_CONRX, port);
+ }
+
+ return ret;
+}
+
+static void serial21285_shutdown(struct uart_port *port)
+{
+ free_irq(IRQ_CONTX, port);
+ free_irq(IRQ_CONRX, port);
+}
+
+static void
+serial21285_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+ unsigned int h_lcr;
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ h_lcr = 0x00;
+ break;
+ case CS6:
+ h_lcr = 0x20;
+ break;
+ case CS7:
+ h_lcr = 0x40;
+ break;
+ default: /* CS8 */
+ h_lcr = 0x60;
+ break;
+ }
+
+ if (cflag & CSTOPB)
+ h_lcr |= H_UBRLCR_STOPB;
+ if (cflag & PARENB) {
+ h_lcr |= H_UBRLCR_PARENB;
+ if (!(cflag & PARODD))
+ h_lcr |= H_UBRLCR_PAREVN;
+ }
+
+ if (port->fifosize)
+ h_lcr |= H_UBRLCR_FIFO;
+
+ port->read_status_mask = RXSTAT_OVERRUN;
+ if (iflag & INPCK)
+ port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
+ if (iflag & IGNBRK && iflag & IGNPAR)
+ port->ignore_status_mask |= RXSTAT_OVERRUN;
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if ((cflag & CREAD) == 0)
+ port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+
+ quot -= 1;
+
+ *CSR_UARTCON = 0;
+ *CSR_L_UBRLCR = quot & 0xff;
+ *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
+ *CSR_H_UBRLCR = h_lcr;
+ *CSR_UARTCON = 1;
+}
+
+static const char *serial21285_type(struct uart_port *port)
+{
+ return port->type == PORT_21285 ? "DC21285" : NULL;
+}
+
+static void serial21285_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, 32);
+}
+
+static int serial21285_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, 32, serial21285_name)
+ != NULL ? 0 : -EBUSY;
+}
+
+static void serial21285_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
+ port->type = PORT_21285;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
+ ret = -EINVAL;
+ if (ser->irq != NO_IRQ)
+ ret = -EINVAL;
+ if (ser->baud_base != port->uartclk / 16)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops serial21285_ops = {
+ tx_empty: serial21285_tx_empty,
+ get_mctrl: serial21285_get_mctrl,
+ set_mctrl: serial21285_set_mctrl,
+ stop_tx: serial21285_stop_tx,
+ start_tx: serial21285_start_tx,
+ stop_rx: serial21285_stop_rx,
+ enable_ms: serial21285_enable_ms,
+ break_ctl: serial21285_break_ctl,
+ startup: serial21285_startup,
+ shutdown: serial21285_shutdown,
+ change_speed: serial21285_change_speed,
+ type: serial21285_type,
+ release_port: serial21285_release_port,
+ request_port: serial21285_request_port,
+ config_port: serial21285_config_port,
+ verify_port: serial21285_verify_port,
+};
+
+static struct uart_port serial21285_port = {
+ membase: 0,
+ mapbase: 0x42000160,
+ iotype: SERIAL_IO_MEM,
+ irq: NO_IRQ,
+ uartclk: 0,
+ fifosize: 16,
+ ops: &serial21285_ops,
+ flags: ASYNC_BOOT_AUTOCONF,
+};
+
+static void serial21285_setup_ports(void)
+{
+ serial21285_port.uartclk = mem_fclk_21285 / 4;
+}
+
+#ifdef CONFIG_SERIAL_21285_CONSOLE
+
+static void
+serial21285_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ while (*CSR_UARTFLG & 0x20)
+ barrier();
+ *CSR_UARTDR = s[i];
+ if (s[i] == '\n') {
+ while (*CSR_UARTFLG & 0x20)
+ barrier();
+ *CSR_UARTDR = '\r';
+ }
+ }
+}
+
+static kdev_t serial21285_console_device(struct console *c)
+{
+ return mk_kdev(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
+}
+
+static void __init
+serial21285_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ if (*CSR_UARTCON == 1) {
+ unsigned int tmp;
+
+ tmp = *CSR_H_UBRLCR;
+ switch (tmp & 0x60) {
+ case 0x00:
+ *bits = 5;
+ break;
+ case 0x20:
+ *bits = 6;
+ break;
+ case 0x40:
+ *bits = 7;
+ break;
+ default:
+ case 0x60:
+ *bits = 8;
+ break;
+ }
+
+ if (tmp & H_UBRLCR_PARENB) {
+ *parity = 'o';
+ if (tmp & H_UBRLCR_PAREVN)
+ *parity = 'e';
+ }
+
+ tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
+
+ *baud = port->uartclk / (16 * (tmp + 1));
+ }
+}
+
+static int __init serial21285_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port = &serial21285_port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (machine_is_personal_server())
+ baud = 57600;
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ serial21285_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+#ifdef CONFIG_SERIAL_21285_OLD
+static struct console serial21285_old_cons =
+{
+ name: SERIAL_21285_OLD_NAME,
+ write: serial21285_console_write,
+ device: serial21285_console_device,
+ setup: serial21285_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+#endif
+
+static struct console serial21285_console =
+{
+ name: SERIAL_21285_NAME,
+ write: serial21285_console_write,
+ device: serial21285_console_device,
+ setup: serial21285_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void __init rs285_console_init(void)
+{
+ serial21285_setup_ports();
+ register_console(&serial21285_console);
+}
+
+#define SERIAL_21285_CONSOLE &serial21285_console
+#else
+#define SERIAL_21285_CONSOLE NULL
+#endif
+
+static struct uart_driver serial21285_reg = {
+ owner: THIS_MODULE,
+ driver_name: "ttyFB",
+#ifdef CONFIG_DEVFS_FS
+ dev_name: "ttyFB%d",
+#else
+ dev_name: "ttyFB",
+#endif
+ major: SERIAL_21285_MAJOR,
+ minor: SERIAL_21285_MINOR,
+ nr: 1,
+ cons: SERIAL_21285_CONSOLE,
+};
+
+static int __init serial21285_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: 21285 driver $Revision: 1.32 $\n");
+
+ serial21285_setup_ports();
+
+ ret = uart_register_driver(&serial21285_reg);
+ if (ret == 0)
+ uart_add_one_port(&serial21285_reg, &serial21285_port);
+
+ return ret;
+}
+
+static void __exit serial21285_exit(void)
+{
+ uart_remove_one_port(&serial21285_reg, &serial21285_port);
+ uart_unregister_driver(&serial21285_reg);
+}
+
+module_init(serial21285_init);
+module_exit(serial21285_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.32 $");
diff --git a/drivers/serial/serial_8250.c b/drivers/serial/serial_8250.c
new file mode 100644
index 000000000000..b763e3faa3de
--- /dev/null
+++ b/drivers/serial/serial_8250.c
@@ -0,0 +1,2015 @@
+/*
+ * linux/drivers/char/serial_8250.c
+ *
+ * Driver for 8250/16550-type serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2001 Russell King.
+ *
+ * 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.
+ *
+ * $Id: serial_8250.c,v 1.80 2002/07/21 08:57:55 rmk Exp $
+ *
+ * A note about mapbase / membase
+ *
+ * mapbase is the physical address of the IO port. Currently, we don't
+ * support this very well, and it may well be dropped from this driver
+ * in future. As such, mapbase should be NULL.
+ *
+ * membase is an 'ioremapped' cookie. This is compatible with the old
+ * serial.c driver, and is currently the preferred form.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial_reg.h>
+#include <linux/serialP.h>
+#include <linux/delay.h>
+#include <linux/kmod.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include "serial_8250.h"
+
+/*
+ * Configuration:
+ * share_irqs - whether we pass SA_SHIRQ to request_irq(). This option
+ * is unsafe when used on edge-triggered interrupts.
+ */
+unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
+
+/*
+ * Debugging.
+ */
+#if 0
+#define DEBUG_AUTOCONF(fmt...) printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...) do { } while (0)
+#endif
+
+#if 0
+#define DEBUG_INTR(fmt...) printk(fmt)
+#else
+#define DEBUG_INTR(fmt...) do { } while (0)
+#endif
+
+#define PASS_LIMIT 256
+
+/*
+ * We default to IRQ0 for the "no irq" hack. Some
+ * machine types want others as well - they're free
+ * to redefine this in their header file.
+ */
+#define is_real_interrupt(irq) ((irq) != 0)
+
+/*
+ * This converts from our new CONFIG_ symbols to the symbols
+ * that asm/serial.h expects. You _NEED_ to comment out the
+ * linux/config.h include contained inside asm/serial.h for
+ * this to work.
+ */
+#undef CONFIG_SERIAL_MANY_PORTS
+#undef CONFIG_SERIAL_DETECT_IRQ
+#undef CONFIG_SERIAL_MULTIPORT
+#undef CONFIG_HUB6
+
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ 1
+#endif
+#ifdef CONFIG_SERIAL_8250_MULTIPORT
+#define CONFIG_SERIAL_MULTIPORT 1
+#endif
+
+/*
+ * HUB6 is always on. This will be removed once the header
+ * files have been cleaned.
+ */
+#define CONFIG_HUB6 1
+#define CONFIG_SERIAL_MANY_PORTS 1
+
+#include <asm/serial.h>
+
+static struct old_serial_port old_serial_port[] = {
+ SERIAL_PORT_DFNS /* defined in asm/serial.h */
+};
+
+#define UART_NR ARRAY_SIZE(old_serial_port)
+
+#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
+
+#define PORT_RSA_MAX 4
+static int probe_rsa[PORT_RSA_MAX];
+static int force_rsa[PORT_RSA_MAX];
+#endif /* CONFIG_SERIAL_8250_RSA */
+
+struct uart_8250_port {
+ struct uart_port port;
+ struct timer_list timer; /* "no irq" timer */
+ struct list_head list; /* ports on this IRQ */
+ unsigned char acr;
+ unsigned char ier;
+ unsigned char rev;
+ unsigned char lcr;
+ unsigned int lsr_break_flag;
+
+ /*
+ * We provide a per-port pm hook.
+ */
+ void (*pm)(struct uart_port *port,
+ unsigned int state, unsigned int old);
+};
+
+struct irq_info {
+ spinlock_t lock;
+ struct list_head *head;
+};
+
+static struct irq_info irq_lists[NR_IRQS];
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
+ { "unknown", 1, 0 },
+ { "8250", 1, 0 },
+ { "16450", 1, 0 },
+ { "16550", 1, 0 },
+ { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
+ { "Cirrus", 1, 0 },
+ { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
+ { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+ { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO },
+ { "Startech", 1, 0 },
+ { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO },
+ { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+ { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+ { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }
+};
+
+static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
+{
+ offset <<= up->port.regshift;
+
+ switch (up->port.iotype) {
+ case SERIAL_IO_HUB6:
+ outb(up->port.hub6 - 1 + offset, up->port.iobase);
+ return inb(up->port.iobase + 1);
+
+ case SERIAL_IO_MEM:
+ return readb(up->port.membase + offset);
+
+ default:
+ return inb(up->port.iobase + offset);
+ }
+}
+
+static _INLINE_ void
+serial_out(struct uart_8250_port *up, int offset, int value)
+{
+ offset <<= up->port.regshift;
+
+ switch (up->port.iotype) {
+ case SERIAL_IO_HUB6:
+ outb(up->port.hub6 - 1 + offset, up->port.iobase);
+ outb(value, up->port.iobase + 1);
+ break;
+
+ case SERIAL_IO_MEM:
+ writeb(value, up->port.membase + offset);
+ break;
+
+ default:
+ outb(value, up->port.iobase + offset);
+ }
+}
+
+/*
+ * We used to support using pause I/O for certain machines. We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(up, offset) serial_in(up, offset)
+#define serial_outp(up, offset, value) serial_out(up, offset, value)
+
+
+/*
+ * For the 16C950
+ */
+static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
+{
+ serial_out(up, UART_SCR, offset);
+ serial_out(up, UART_ICR, value);
+}
+
+static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
+{
+ unsigned int value;
+
+ serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
+ serial_out(up, UART_SCR, offset);
+ value = serial_in(up, UART_ICR);
+ serial_icr_write(up, UART_ACR, up->acr);
+
+ return value;
+}
+
+#ifdef CONFIG_SERIAL_8250_RSA
+/*
+ * Attempts to turn on the RSA FIFO. Returns zero on failure.
+ * We set the port uart clock rate if we succeed.
+ */
+static int __enable_rsa(struct uart_8250_port *up)
+{
+ unsigned char mode;
+ int result;
+
+ mode = serial_inp(up, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+
+ if (!result) {
+ serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+ mode = serial_inp(up, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+ }
+
+ if (result)
+ up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
+
+ return result;
+}
+
+static void enable_rsa(struct uart_8250_port *up)
+{
+ if (up->port.type == PORT_RSA) {
+ if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
+ spin_lock_irq(&up->port.lock);
+ __enable_rsa(up);
+ spin_unlock_irq(&up->port.lock);
+ }
+ if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
+ serial_outp(up, UART_RSA_FRR, 0);
+ }
+}
+
+/*
+ * Attempts to turn off the RSA FIFO. Returns zero on failure.
+ * It is unknown why interrupts were disabled in here. However,
+ * the caller is expected to preserve this behaviour by grabbing
+ * the spinlock before calling this function.
+ */
+static void disable_rsa(struct uart_8250_port *up)
+{
+ unsigned char mode;
+ int result;
+
+ if (up->port.type == PORT_RSA &&
+ up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
+ spin_lock_irq(&up->port.lock);
+
+ mode = serial_inp(up, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+
+ if (!result) {
+ serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+ mode = serial_inp(up, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+ }
+
+ if (result)
+ up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
+ spin_unlock_irq(&up->port.lock);
+ }
+}
+#endif /* CONFIG_SERIAL_8250_RSA */
+
+/*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct uart_8250_port *up)
+{
+ unsigned char old_fcr, old_mcr, old_dll, old_dlm;
+ int count;
+
+ old_fcr = serial_inp(up, UART_FCR);
+ old_mcr = serial_inp(up, UART_MCR);
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ serial_outp(up, UART_MCR, UART_MCR_LOOP);
+ serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ old_dll = serial_inp(up, UART_DLL);
+ old_dlm = serial_inp(up, UART_DLM);
+ serial_outp(up, UART_DLL, 0x01);
+ serial_outp(up, UART_DLM, 0x00);
+ serial_outp(up, UART_LCR, 0x03);
+ for (count = 0; count < 256; count++)
+ serial_outp(up, UART_TX, count);
+ mdelay(20);/* FIXME - schedule_timeout */
+ for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&
+ (count < 256); count++)
+ serial_inp(up, UART_RX);
+ serial_outp(up, UART_FCR, old_fcr);
+ serial_outp(up, UART_MCR, old_mcr);
+ serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_outp(up, UART_DLL, old_dll);
+ serial_outp(up, UART_DLM, old_dlm);
+
+ return count;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
+ * When this function is called we know it is at least a StarTech
+ * 16650 V2, but it might be one of several StarTech UARTs, or one of
+ * its clones. (We treat the broken original StarTech 16650 V1 as a
+ * 16550, and why not? Startech doesn't seem to even acknowledge its
+ * existence.)
+ *
+ * What evil have men's minds wrought...
+ */
+static void
+autoconfig_startech_uarts(struct uart_8250_port *up)
+{
+ unsigned char scratch, scratch2, scratch3, scratch4;
+
+ /*
+ * First we check to see if it's an Oxford Semiconductor UART.
+ *
+ * If we have to do this here because some non-National
+ * Semiconductor clone chips lock up if you try writing to the
+ * LSR register (which serial_icr_read does)
+ */
+ if (up->port.type == PORT_16550A) {
+ /*
+ * EFR [4] must be set else this test fails
+ *
+ * This shouldn't be necessary, but Mike Hudson
+ * (Exoray@isys.ca) claims that it's needed for 952
+ * dual UART's (which are not recommended for new designs).
+ */
+ up->acr = 0;
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, 0x10);
+ serial_out(up, UART_LCR, 0x00);
+ /* Check for Oxford Semiconductor 16C950 */
+ scratch = serial_icr_read(up, UART_ID1);
+ scratch2 = serial_icr_read(up, UART_ID2);
+ scratch3 = serial_icr_read(up, UART_ID3);
+
+ if (scratch == 0x16 && scratch2 == 0xC9 &&
+ (scratch3 == 0x50 || scratch3 == 0x52 ||
+ scratch3 == 0x54)) {
+ up->port.type = PORT_16C950;
+ up->rev = serial_icr_read(up, UART_REV) |
+ (scratch3 << 8);
+ return;
+ }
+ }
+
+ /*
+ * We check for a XR16C850 by setting DLL and DLM to 0, and then
+ * reading back DLL and DLM. The chip type depends on the DLM
+ * value read back:
+ * 0x10 - XR16C850 and the DLL contains the chip revision.
+ * 0x12 - XR16C2850.
+ * 0x14 - XR16C854.
+ */
+
+ /* Save the DLL and DLM */
+
+ serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ scratch3 = serial_inp(up, UART_DLL);
+ scratch4 = serial_inp(up, UART_DLM);
+
+ serial_outp(up, UART_DLL, 0);
+ serial_outp(up, UART_DLM, 0);
+ scratch2 = serial_inp(up, UART_DLL);
+ scratch = serial_inp(up, UART_DLM);
+ serial_outp(up, UART_LCR, 0);
+
+ if (scratch == 0x10 || scratch == 0x12 || scratch == 0x14) {
+ if (scratch == 0x10)
+ up->rev = scratch2;
+ up->port.type = PORT_16850;
+ return;
+ }
+
+ /* Restore the DLL and DLM */
+
+ serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_outp(up, UART_DLL, scratch3);
+ serial_outp(up, UART_DLM, scratch4);
+ serial_outp(up, UART_LCR, 0);
+
+ /*
+ * We distinguish between the '654 and the '650 by counting
+ * how many bytes are in the FIFO. I'm using this for now,
+ * since that's the technique that was sent to me in the
+ * serial driver update, but I'm not convinced this works.
+ * I've had problems doing this in the past. -TYT
+ */
+ if (size_fifo(up) == 64)
+ up->port.type = PORT_16654;
+ else
+ up->port.type = PORT_16650V2;
+}
+
+/*
+ * This routine is called by rs_init() to initialize a specific serial
+ * port. It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A. The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+{
+ unsigned char status1, status2, scratch, scratch2, scratch3;
+ unsigned char save_lcr, save_mcr;
+ unsigned long flags;
+
+ DEBUG_AUTOCONF("Testing ttyS%d (0x%04x, 0x%08lx)...\n",
+ up->port.line, up->port.iobase, up->port.membase);
+
+ if (!up->port.iobase && !up->port.membase)
+ return;
+
+ /*
+ * We really do need global IRQs disabled here - we're going to
+ * be frobbing the chips IRQ enable register to see if it exists.
+ */
+ spin_lock_irqsave(&up->port.lock, flags);
+// save_flags(flags); cli();
+
+ if (!(up->port.flags & ASYNC_BUGGY_UART)) {
+ /*
+ * Do a simple existence test first; if we fail this,
+ * there's no point trying anything else.
+ *
+ * 0x80 is used as a nonsense port to prevent against
+ * false positives due to ISA bus float. The
+ * assumption is that 0x80 is a non-existent port;
+ * which should be safe since include/asm/io.h also
+ * makes this assumption.
+ */
+ scratch = serial_inp(up, UART_IER);
+ serial_outp(up, UART_IER, 0);
+#ifdef __i386__
+ outb(0xff, 0x080);
+#endif
+ scratch2 = serial_inp(up, UART_IER);
+ serial_outp(up, UART_IER, 0x0F);
+#ifdef __i386__
+ outb(0, 0x080);
+#endif
+ scratch3 = serial_inp(up, UART_IER);
+ serial_outp(up, UART_IER, scratch);
+ if (scratch2 != 0 || scratch3 != 0x0F) {
+ /*
+ * We failed; there's nothing here
+ */
+ DEBUG_AUTOCONF("serial: ttyS%d: simple autoconfig "
+ "failed (%02x, %02x)\n",
+ up->port.line, scratch2, scratch3);
+ goto out;
+ }
+ }
+
+ save_mcr = serial_in(up, UART_MCR);
+ save_lcr = serial_in(up, UART_LCR);
+
+ /*
+ * Check to see if a UART is really there. Certain broken
+ * internal modems based on the Rockwell chipset fail this
+ * test, because they apparently don't implement the loopback
+ * test mode. So this test is skipped on the COM 1 through
+ * COM 4 ports. This *should* be safe, since no board
+ * manufacturer would be stupid enough to design a board
+ * that conflicts with COM 1-4 --- we hope!
+ */
+ if (!(up->port.flags & ASYNC_SKIP_TEST)) {
+ serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+ status1 = serial_inp(up, UART_MSR) & 0xF0;
+ serial_outp(up, UART_MCR, save_mcr);
+ if (status1 != 0x90) {
+ DEBUG_AUTOCONF("serial: ttyS%d: no UART loopback "
+ "failed\n", up->port.line);
+ goto out;
+ }
+ }
+ serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */
+ serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */
+ serial_outp(up, UART_LCR, 0);
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ scratch = serial_in(up, UART_IIR) >> 6;
+ switch (scratch) {
+ case 0:
+ up->port.type = PORT_16450;
+ break;
+ case 1:
+ up->port.type = PORT_UNKNOWN;
+ break;
+ case 2:
+ up->port.type = PORT_16550;
+ break;
+ case 3:
+ up->port.type = PORT_16550A;
+ break;
+ }
+ if (up->port.type == PORT_16550A) {
+ /* Check for Startech UART's */
+ serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ if (serial_in(up, UART_EFR) == 0) {
+ up->port.type = PORT_16650;
+ } else {
+ serial_outp(up, UART_LCR, 0xBF);
+ if (serial_in(up, UART_EFR) == 0)
+ autoconfig_startech_uarts(up);
+ }
+ }
+ if (up->port.type == PORT_16550A) {
+ /* Check for TI 16750 */
+ serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
+ serial_outp(up, UART_FCR,
+ UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+ scratch = serial_in(up, UART_IIR) >> 5;
+ if (scratch == 7) {
+ /*
+ * If this is a 16750, and not a cheap UART
+ * clone, then it should only go into 64 byte
+ * mode if the UART_FCR7_64BYTE bit was set
+ * while UART_LCR_DLAB was latched.
+ */
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_outp(up, UART_LCR, 0);
+ serial_outp(up, UART_FCR,
+ UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+ scratch = serial_in(up, UART_IIR) >> 5;
+ if (scratch == 6)
+ up->port.type = PORT_16750;
+ }
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ }
+#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
+ /*
+ * Only probe for RSA ports if we got the region.
+ */
+ if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
+ int i;
+
+ for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
+ if (!probe_rsa[i] && !force_rsa[i])
+ break;
+ if (((probe_rsa[i] != up->port.iobase) ||
+ check_region(up->port.iobase + UART_RSA_BASE, 16)) &&
+ (force_rsa[i] != up->port.iobase))
+ continue;
+ if (__enable_rsa(up)) {
+ up->port.type = PORT_RSA;
+ break;
+ }
+ }
+ }
+#endif
+ serial_outp(up, UART_LCR, save_lcr);
+ if (up->port.type == PORT_16450) {
+ scratch = serial_in(up, UART_SCR);
+ serial_outp(up, UART_SCR, 0xa5);
+ status1 = serial_in(up, UART_SCR);
+ serial_outp(up, UART_SCR, 0x5a);
+ status2 = serial_in(up, UART_SCR);
+ serial_outp(up, UART_SCR, scratch);
+
+ if ((status1 != 0xa5) || (status2 != 0x5a))
+ up->port.type = PORT_8250;
+ }
+
+ up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+
+ if (up->port.type == PORT_UNKNOWN)
+ goto out;
+
+ /*
+ * Reset the UART.
+ */
+#ifdef CONFIG_SERIAL_8250_RSA
+ if (up->port.type == PORT_RSA)
+ serial_outp(up, UART_RSA_FRR, 0);
+#endif
+ serial_outp(up, UART_MCR, save_mcr);
+ serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT));
+ serial_outp(up, UART_FCR, 0);
+ (void)serial_in(up, UART_RX);
+ serial_outp(up, UART_IER, 0);
+
+ out:
+ spin_unlock_irqrestore(&up->port.lock, flags);
+// restore_flags(flags);
+#ifdef CONFIG_SERIAL_8250_RSA
+ if (up->port.iobase && up->port.type == PORT_RSA) {
+ release_region(up->port.iobase, 8);
+ request_region(up->port.iobase + UART_RSA_BASE, 16,
+ "serial_rsa");
+ }
+#endif
+}
+
+static void autoconfig_irq(struct uart_8250_port *up)
+{
+ unsigned char save_mcr, save_ier;
+ unsigned char save_ICP = 0;
+ unsigned int ICP = 0;
+ unsigned long irqs;
+ int irq;
+
+ if (up->port.flags & ASYNC_FOURPORT) {
+ ICP = (up->port.iobase & 0xfe0) | 0x1f;
+ save_ICP = inb_p(ICP);
+ outb_p(0x80, ICP);
+ (void) inb_p(ICP);
+ }
+
+ /* forget possible initially masked and pending IRQ */
+ probe_irq_off(probe_irq_on());
+ save_mcr = serial_inp(up, UART_MCR);
+ save_ier = serial_inp(up, UART_IER);
+ serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+
+ irqs = probe_irq_on();
+ serial_outp(up, UART_MCR, 0);
+ udelay (10);
+ if (up->port.flags & ASYNC_FOURPORT) {
+ serial_outp(up, UART_MCR,
+ UART_MCR_DTR | UART_MCR_RTS);
+ } else {
+ serial_outp(up, UART_MCR,
+ UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+ }
+ serial_outp(up, UART_IER, 0x0f); /* enable all intrs */
+ (void)serial_inp(up, UART_LSR);
+ (void)serial_inp(up, UART_RX);
+ (void)serial_inp(up, UART_IIR);
+ (void)serial_inp(up, UART_MSR);
+ serial_outp(up, UART_TX, 0xFF);
+ udelay (20);
+ irq = probe_irq_off(irqs);
+
+ serial_outp(up, UART_MCR, save_mcr);
+ serial_outp(up, UART_IER, save_ier);
+
+ if (up->port.flags & ASYNC_FOURPORT)
+ outb_p(save_ICP, ICP);
+
+ up->port.irq = (irq > 0) ? irq : 0;
+}
+
+static void __serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+ if (up->ier & UART_IER_THRI) {
+ up->ier &= ~UART_IER_THRI;
+ serial_out(up, UART_IER, up->ier);
+ }
+ if (up->port.type == PORT_16C950 && tty_stop) {
+ up->acr |= UART_ACR_TXDIS;
+ serial_icr_write(up, UART_ACR, up->acr);
+ }
+}
+
+static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ __serial8250_stop_tx(port, tty_stop);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+ if (!(up->ier & UART_IER_THRI)) {
+ up->ier |= UART_IER_THRI;
+ serial_out(up, UART_IER, up->ier);
+ }
+ /*
+ * We only do this from uart_start
+ */
+ if (tty_start && up->port.type == PORT_16C950) {
+ up->acr &= ~UART_ACR_TXDIS;
+ serial_icr_write(up, UART_ACR, up->acr);
+ }
+}
+
+static void serial8250_stop_rx(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ up->ier &= ~UART_IER_RLSI;
+ up->port.read_status_mask &= ~UART_LSR_DR;
+ serial_out(up, UART_IER, up->ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void serial8250_enable_ms(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ up->ier |= UART_IER_MSI;
+ serial_out(up, UART_IER, up->ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static _INLINE_ void
+receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
+{
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned char ch;
+ int max_count = 256;
+
+ do {
+ if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+ tty->flip.tqueue.routine((void *)tty);
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ return; // if TTY_DONT_FLIP is set
+ }
+ ch = serial_inp(up, UART_RX);
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = TTY_NORMAL;
+ up->port.icount.rx++;
+
+ if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+ UART_LSR_FE | UART_LSR_OE))) {
+ /*
+ * For statistics only
+ */
+ if (*status & UART_LSR_BI) {
+ *status &= ~(UART_LSR_FE | UART_LSR_PE);
+ up->port.icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(&up->port))
+ goto ignore_char;
+ } else if (*status & UART_LSR_PE)
+ up->port.icount.parity++;
+ else if (*status & UART_LSR_FE)
+ up->port.icount.frame++;
+ if (*status & UART_LSR_OE)
+ up->port.icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ingored.
+ */
+ *status &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ if (up->port.line == up->port.cons->index) {
+ /* Recover the break flag from console xmit */
+ *status |= up->lsr_break_flag;
+ up->lsr_break_flag = 0;
+ }
+#endif
+ if (*status & UART_LSR_BI) {
+ DEBUG_INTR("handling break....");
+ *tty->flip.flag_buf_ptr = TTY_BREAK;
+ } else if (*status & UART_LSR_PE)
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ else if (*status & UART_LSR_FE)
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ }
+ if (uart_handle_sysrq_char(&up->port, ch, regs))
+ goto ignore_char;
+ if ((*status & up->port.ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((*status & UART_LSR_OE) &&
+ tty->flip.count < TTY_FLIPBUF_SIZE) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character.
+ */
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ ignore_char:
+ *status = serial_inp(up, UART_LSR);
+ } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+ tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void transmit_chars(struct uart_8250_port *up)
+{
+ struct circ_buf *xmit = &up->port.info->xmit;
+ int count;
+
+ if (up->port.x_char) {
+ serial_outp(up, UART_TX, up->port.x_char);
+ up->port.icount.tx++;
+ up->port.x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ __serial8250_stop_tx(&up->port, 0);
+ return;
+ }
+
+ count = up->port.fifosize;
+ do {
+ serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ up->port.icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(&up->port, EVT_WRITE_WAKEUP);
+
+ DEBUG_INTR("THRE...");
+
+ if (uart_circ_empty(xmit))
+ __serial8250_stop_tx(&up->port, 0);
+}
+
+static _INLINE_ void check_modem_status(struct uart_8250_port *up)
+{
+ int status;
+
+ status = serial_in(up, UART_MSR);
+
+ if ((status & UART_MSR_ANY_DELTA) == 0)
+ return;
+
+ if (status & UART_MSR_TERI)
+ up->port.icount.rng++;
+ if (status & UART_MSR_DDSR)
+ up->port.icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+ if (status & UART_MSR_DCTS)
+ uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+ wake_up_interruptible(&up->port.info->delta_msr_wait);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static inline void
+serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
+{
+ unsigned int status = serial_inp(up, UART_LSR);
+
+ DEBUG_INTR("status = %x...", status);
+
+ if (status & UART_LSR_DR)
+ receive_chars(up, &status, regs);
+ check_modem_status(up);
+ if (status & UART_LSR_THRE)
+ transmit_chars(up);
+}
+
+/*
+ * This is the serial driver's interrupt routine.
+ *
+ * Arjan thinks the old way was overly complex, so it got simplified.
+ * Alan disagrees, saying that need the complexity to handle the weird
+ * nature of ISA shared interrupts. (This is a special exception.)
+ *
+ * In order to handle ISA shared interrupts properly, we need to check
+ * that all ports have been serviced, and therefore the ISA interrupt
+ * line has been de-asserted.
+ *
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+static void serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct irq_info *i = dev_id;
+ struct list_head *l, *end = NULL;
+ int pass_counter = 0;
+
+ DEBUG_INTR("serial8250_interrupt(%d)...", irq);
+
+ spin_lock(&i->lock);
+
+ l = i->head;
+ do {
+ struct uart_8250_port *up;
+ unsigned int iir;
+
+ up = list_entry(l, struct uart_8250_port, list);
+
+ iir = serial_in(up, UART_IIR);
+ if (!(iir & UART_IIR_NO_INT)) {
+ spin_lock(&up->port.lock);
+ serial8250_handle_port(up, regs);
+ spin_unlock(&up->port.lock);
+
+ end = NULL;
+ } else if (end == NULL)
+ end = l;
+
+ l = l->next;
+
+ if (l == i->head && pass_counter++ > PASS_LIMIT) {
+ /* If we hit this, we're dead. */
+ printk(KERN_ERR "serial8250: too much work for "
+ "irq%d\n", irq);
+ break;
+ }
+ } while (l != end);
+
+ spin_unlock(&i->lock);
+
+ DEBUG_INTR("end.\n");
+}
+
+/*
+ * To support ISA shared interrupts, we need to have one interrupt
+ * handler that ensures that the IRQ line has been deasserted
+ * before returning. Failing to do this will result in the IRQ
+ * line being stuck active, and, since ISA irqs are edge triggered,
+ * no more IRQs will be seen.
+ */
+static int serial_link_irq_chain(struct uart_8250_port *up)
+{
+ struct irq_info *i = irq_lists + up->port.irq;
+ int ret, irq_flags = share_irqs ? SA_SHIRQ : 0;
+
+ spin_lock_irq(&i->lock);
+
+ if (i->head) {
+ list_add(&up->list, i->head);
+ spin_unlock_irq(&i->lock);
+
+ ret = 0;
+ } else {
+ INIT_LIST_HEAD(&up->list);
+ i->head = &up->list;
+ spin_unlock_irq(&i->lock);
+
+ ret = request_irq(up->port.irq, serial8250_interrupt,
+ irq_flags, "serial", i);
+ }
+
+ return ret;
+}
+
+static void serial_unlink_irq_chain(struct uart_8250_port *up)
+{
+ struct irq_info *i = irq_lists + up->port.irq;
+
+ BUG_ON(i->head == NULL);
+
+ if (list_empty(i->head))
+ free_irq(up->port.irq, i);
+
+ spin_lock_irq(&i->lock);
+
+ if (!list_empty(i->head)) {
+ if (i->head == &up->list)
+ i->head = i->head->next;
+ list_del(&up->list);
+ } else {
+ BUG_ON(i->head != &up->list);
+ i->head = NULL;
+ }
+
+ spin_unlock_irq(&i->lock);
+}
+
+/*
+ * This function is used to handle ports that do not have an
+ * interrupt. This doesn't work very well for 16450's, but gives
+ * barely passable results for a 16550A. (Although at the expense
+ * of much CPU overhead).
+ */
+static void serial8250_timeout(unsigned long data)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)data;
+ unsigned int timeout;
+ unsigned int iir;
+
+ iir = serial_in(up, UART_IIR);
+ if (!(iir & UART_IIR_NO_INT)) {
+ spin_lock(&up->port.lock);
+ serial8250_handle_port(up, NULL);
+ spin_unlock(&up->port.lock);
+ }
+
+ timeout = up->port.timeout;
+ timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+ mod_timer(&up->timer, jiffies + timeout);
+}
+
+static unsigned int serial8250_tx_empty(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+ unsigned int ret;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ return ret;
+}
+
+static unsigned int serial8250_get_mctrl(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+ unsigned char status;
+ unsigned int ret;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ status = serial_in(up, UART_MSR);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ ret = 0;
+ if (status & UART_MSR_DCD)
+ ret |= TIOCM_CAR;
+ if (status & UART_MSR_RI)
+ ret |= TIOCM_RNG;
+ if (status & UART_MSR_DSR)
+ ret |= TIOCM_DSR;
+ if (status & UART_MSR_CTS)
+ ret |= TIOCM_CTS;
+ return ret;
+}
+
+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned char mcr = ALPHA_KLUDGE_MCR;
+
+ if (mctrl & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (mctrl & TIOCM_DTR)
+ mcr |= UART_MCR_DTR;
+ if (mctrl & TIOCM_OUT1)
+ mcr |= UART_MCR_OUT1;
+ if (mctrl & TIOCM_OUT2)
+ mcr |= UART_MCR_OUT2;
+ if (mctrl & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+
+ serial_out(up, UART_MCR, mcr);
+}
+
+static void serial8250_break_ctl(struct uart_port *port, int break_state)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ if (break_state == -1)
+ up->lcr |= UART_LCR_SBC;
+ else
+ up->lcr &= ~UART_LCR_SBC;
+ serial_out(up, UART_LCR, up->lcr);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int serial8250_startup(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+ int retval;
+
+ if (up->port.type == PORT_16C950) {
+ /* Wake up and initialize UART */
+ up->acr = 0;
+ serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_EFR, UART_EFR_ECB);
+ serial_outp(up, UART_IER, 0);
+ serial_outp(up, UART_LCR, 0);
+ serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
+ serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_EFR, UART_EFR_ECB);
+ serial_outp(up, UART_LCR, 0);
+ }
+
+#ifdef CONFIG_SERIAL_8250_RSA
+ /*
+ * If this is an RSA port, see if we can kick it up to the
+ * higher speed clock.
+ */
+ enable_rsa(up);
+#endif
+
+ /*
+ * Clear the FIFO buffers and disable them.
+ * (they will be reeanbled in change_speed())
+ */
+ if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ serial_outp(up, UART_FCR, 0);
+ }
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) serial_inp(up, UART_LSR);
+ (void) serial_inp(up, UART_RX);
+ (void) serial_inp(up, UART_IIR);
+ (void) serial_inp(up, UART_MSR);
+
+ /*
+ * At this point, there's no way the LSR could still be 0xff;
+ * if it is, then bail out, because there's likely no UART
+ * here.
+ */
+ if (!(up->port.flags & ASYNC_BUGGY_UART) &&
+ (serial_inp(up, UART_LSR) == 0xff)) {
+ printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+ return -ENODEV;
+ }
+
+ /*
+ * If the "interrupt" for this port doesn't correspond with any
+ * hardware interrupt, we use a timer-based system. The original
+ * driver used to do this with IRQ0.
+ */
+ if (!is_real_interrupt(up->port.irq)) {
+ unsigned int timeout = up->port.timeout;
+
+ timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+
+ up->timer.data = (unsigned long)up;
+ mod_timer(&up->timer, jiffies + timeout);
+ } else {
+ retval = serial_link_irq_chain(up);
+ if (retval)
+ return retval;
+ }
+
+ /*
+ * Now, initialize the UART
+ */
+ serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ if (up->port.flags & ASYNC_FOURPORT) {
+ if (!is_real_interrupt(up->port.irq))
+ up->port.mctrl |= TIOCM_OUT1;
+ } else
+ /*
+ * Most PC uarts need OUT2 raised to enable interrupts.
+ */
+ if (is_real_interrupt(up->port.irq))
+ up->port.mctrl |= TIOCM_OUT2;
+
+ serial8250_set_mctrl(&up->port, up->port.mctrl);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ /*
+ * Finally, enable interrupts. Note: Modem status interrupts
+ * are set via change_speed(), which will be occuring imminently
+ * anyway, so we don't enable them here.
+ */
+ up->ier = UART_IER_RLSI | UART_IER_RDI;
+ serial_outp(up, UART_IER, up->ier);
+
+ if (up->port.flags & ASYNC_FOURPORT) {
+ unsigned int icp;
+ /*
+ * Enable interrupts on the AST Fourport board
+ */
+ icp = (up->port.iobase & 0xfe0) | 0x01f;
+ outb_p(0x80, icp);
+ (void) inb_p(icp);
+ }
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ (void) serial_inp(up, UART_LSR);
+ (void) serial_inp(up, UART_RX);
+ (void) serial_inp(up, UART_IIR);
+ (void) serial_inp(up, UART_MSR);
+
+ return 0;
+}
+
+static void serial8250_shutdown(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+
+ /*
+ * Disable interrupts from this port
+ */
+ up->ier = 0;
+ serial_outp(up, UART_IER, 0);
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ if (up->port.flags & ASYNC_FOURPORT) {
+ /* reset interrupts on the AST Fourport board */
+ inb((up->port.iobase & 0xfe0) | 0x1f);
+ up->port.mctrl |= TIOCM_OUT1;
+ } else
+ up->port.mctrl &= ~TIOCM_OUT2;
+
+ serial8250_set_mctrl(&up->port, up->port.mctrl);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ /*
+ * Disable break condition and FIFOs
+ */
+ serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT);
+ serial_outp(up, UART_FCR, 0);
+
+#ifdef CONFIG_SERIAL_8250_RSA
+ /*
+ * Reset the RSA board back to 115kbps compat mode.
+ */
+ disable_rsa(up);
+#endif
+
+ /*
+ * Read data port to reset things, and then unlink from
+ * the IRQ chain.
+ */
+ (void) serial_in(up, UART_RX);
+
+ if (!is_real_interrupt(up->port.irq))
+ del_timer_sync(&up->timer);
+ else
+ serial_unlink_irq_chain(up);
+}
+
+static void
+serial8250_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned char cval, fcr = 0;
+ unsigned long flags;
+
+ printk("+++ change_speed port %p cflag %08x quot %d\n", port, cflag, quot);
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ cval = 0x00;
+ break;
+ case CS6:
+ cval = 0x01;
+ break;
+ case CS7:
+ cval = 0x02;
+ break;
+ default:
+ case CS8:
+ cval = 0x03;
+ break;
+ }
+
+ if (cflag & CSTOPB)
+ cval |= 0x04;
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+ if (cflag & CMSPAR)
+ cval |= UART_LCR_SPAR;
+#endif
+
+ /*
+ * Work around a bug in the Oxford Semiconductor 952 rev B
+ * chip which causes it to seriously miscalculate baud rates
+ * when DLL is 0.
+ */
+ if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
+ up->rev == 0x5201)
+ quot ++;
+
+ if (uart_config[up->port.type].flags & UART_USE_FIFO) {
+ if ((up->port.uartclk / quot) < (2400 * 16))
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_8250_RSA
+ else if (up->port.type == PORT_RSA)
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
+ else
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+ }
+ if (up->port.type == PORT_16750)
+ fcr |= UART_FCR7_64BYTE;
+
+ up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (iflag & IGNPAR)
+ up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (iflag & (BRKINT | PARMRK))
+ up->port.read_status_mask |= UART_LSR_BI;
+
+ /*
+ * Characteres to ignore
+ */
+ up->port.ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ if (iflag & IGNBRK) {
+ up->port.ignore_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ up->port.ignore_status_mask |= UART_LSR_OE;
+ }
+
+ /*
+ * ignore all characters if CREAD is not set
+ */
+ if ((cflag & CREAD) == 0)
+ up->port.ignore_status_mask |= UART_LSR_DR;
+
+ /*
+ * CTS flow control flag and modem status interrupts
+ */
+ up->ier &= ~UART_IER_MSI;
+ if (UART_ENABLE_MS(&up->port, cflag))
+ up->ier |= UART_IER_MSI;
+
+ /*
+ * Ok, we're now changing the port state. Do it with
+ * interrupts disabled.
+ */
+ spin_lock_irqsave(&up->port.lock, flags);
+ serial_out(up, UART_IER, up->ier);
+
+ if (uart_config[up->port.type].flags & UART_STARTECH) {
+ serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
+ }
+ serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+ serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
+ serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
+ if (up->port.type == PORT_16750)
+ serial_outp(up, UART_FCR, fcr); /* set fcr */
+ serial_outp(up, UART_LCR, cval); /* reset DLAB */
+ up->lcr = cval; /* Save LCR */
+ if (up->port.type != PORT_16750) {
+ if (fcr & UART_FCR_ENABLE_FIFO) {
+ /* emulated UARTs (Lucent Venus 167x) need two steps */
+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ }
+ serial_outp(up, UART_FCR, fcr); /* set fcr */
+ }
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial8250_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ if (state) {
+ /* sleep */
+ if (uart_config[up->port.type].flags & UART_STARTECH) {
+ /* Arrange to enter sleep mode */
+ serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_EFR, UART_EFR_ECB);
+ serial_outp(up, UART_LCR, 0);
+ serial_outp(up, UART_IER, UART_IERX_SLEEP);
+ serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_EFR, 0);
+ serial_outp(up, UART_LCR, 0);
+ }
+ if (up->port.type == PORT_16750) {
+ /* Arrange to enter sleep mode */
+ serial_outp(up, UART_IER, UART_IERX_SLEEP);
+ }
+
+ if (up->pm)
+ up->pm(port, state, oldstate);
+ } else {
+ /* wake */
+ if (uart_config[up->port.type].flags & UART_STARTECH) {
+ /* Wake up UART */
+ serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_EFR, UART_EFR_ECB);
+ /*
+ * Turn off LCR == 0xBF so we actually set the IER
+ * register on the XR16C850
+ */
+ serial_outp(up, UART_LCR, 0);
+ serial_outp(up, UART_IER, 0);
+ /*
+ * Now reset LCR so we can turn off the ECB bit
+ */
+ serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_EFR, 0);
+ /*
+ * For a XR16C850, we need to set the trigger levels
+ */
+ if (up->port.type == PORT_16850) {
+ unsigned char fctr;
+
+ fctr = serial_inp(up, UART_FCTR) &
+ ~(UART_FCTR_RX | UART_FCTR_TX);
+ serial_outp(up, UART_FCTR, fctr |
+ UART_FCTR_TRGD |
+ UART_FCTR_RX);
+ serial_outp(up, UART_TRG, UART_TRG_96);
+ serial_outp(up, UART_FCTR, fctr |
+ UART_FCTR_TRGD |
+ UART_FCTR_TX);
+ serial_outp(up, UART_TRG, UART_TRG_96);
+ }
+ serial_outp(up, UART_LCR, 0);
+ }
+
+ if (up->port.type == PORT_16750) {
+ /* Wake up UART */
+ serial_outp(up, UART_IER, 0);
+ }
+
+ if (up->pm)
+ up->pm(port, state, oldstate);
+ }
+}
+
+/*
+ * Resource handling. This is complicated by the fact that resources
+ * depend on the port type. Maybe we should be claiming the standard
+ * 8250 ports, and then trying to get other resources as necessary?
+ */
+static int
+serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res)
+{
+ unsigned int size = 8 << up->port.regshift;
+ int ret = 0;
+
+ switch (up->port.iotype) {
+ case SERIAL_IO_MEM:
+ if (up->port.mapbase) {
+ *res = request_mem_region(up->port.mapbase, size, "serial");
+ if (!*res)
+ ret = -EBUSY;
+ }
+ break;
+
+ case SERIAL_IO_HUB6:
+ case SERIAL_IO_PORT:
+ *res = request_region(up->port.iobase, size, "serial");
+ if (!*res)
+ ret = -EBUSY;
+ break;
+ }
+ return ret;
+}
+
+static int
+serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res)
+{
+ unsigned int size = 8 << up->port.regshift;
+ unsigned long start;
+ int ret = 0;
+
+ switch (up->port.iotype) {
+ case SERIAL_IO_MEM:
+ if (up->port.mapbase) {
+ start = up->port.mapbase;
+ start += UART_RSA_BASE << up->port.regshift;
+ *res = request_mem_region(start, size, "serial-rsa");
+ if (!*res)
+ ret = -EBUSY;
+ }
+ break;
+
+ case SERIAL_IO_HUB6:
+ case SERIAL_IO_PORT:
+ start = up->port.iobase;
+ start += UART_RSA_BASE << up->port.regshift;
+ *res = request_region(start, size, "serial-rsa");
+ if (!*res)
+ ret = -EBUSY;
+ break;
+ }
+
+ return ret;
+}
+
+static void serial8250_release_port(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long start, offset = 0, size = 0;
+
+ if (up->port.type == PORT_RSA) {
+ offset = UART_RSA_BASE << up->port.regshift;
+ size = 8;
+ }
+
+ size <<= up->port.regshift;
+
+ switch (up->port.iotype) {
+ case SERIAL_IO_MEM:
+ if (up->port.mapbase) {
+ /*
+ * Unmap the area.
+ */
+ iounmap(up->port.membase);
+ up->port.membase = NULL;
+
+ start = up->port.mapbase;
+
+ if (size)
+ release_mem_region(start + offset, size);
+ release_mem_region(start, 8 << up->port.regshift);
+ }
+ break;
+
+ case SERIAL_IO_HUB6:
+ case SERIAL_IO_PORT:
+ start = up->port.iobase;
+
+ if (size)
+ release_region(start + offset, size);
+ release_region(start + offset, 8 << up->port.regshift);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int serial8250_request_port(struct uart_port *port)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct resource *res = NULL, *res_rsa = NULL;
+ int ret = -EBUSY;
+
+ if (up->port.type == PORT_RSA) {
+ ret = serial8250_request_rsa_resource(up, &res_rsa);
+ if (ret)
+ return ret;
+ }
+
+ ret = serial8250_request_std_resource(up, &res);
+
+ /*
+ * If we have a mapbase, then request that as well.
+ */
+ if (res != NULL && up->port.iotype == SERIAL_IO_MEM &&
+ up->port.mapbase) {
+ int size = res->end - res->start + 1;
+
+ up->port.membase = ioremap(up->port.mapbase, size);
+ if (!up->port.membase)
+ ret = -ENOMEM;
+ }
+
+ if (ret) {
+ if (res_rsa)
+ release_resource(res_rsa);
+ if (res)
+ release_resource(res);
+ }
+ return ret;
+}
+
+static void serial8250_config_port(struct uart_port *port, int flags)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ struct resource *res_std = NULL, *res_rsa = NULL;
+ int probeflags = PROBE_ANY;
+ int ret;
+
+#ifdef CONFIG_MCA
+ /*
+ * Don't probe for MCA ports on non-MCA machines.
+ */
+ if (up->port.flags & ASYNC_BOOT_ONLYMCA && !MCA_bus)
+ return;
+#endif
+
+ /*
+ * Find the region that we can probe for. This in turn
+ * tells us whether we can probe for the type of port.
+ */
+ ret = serial8250_request_std_resource(up, &res_std);
+ if (ret)
+ return;
+
+ ret = serial8250_request_rsa_resource(up, &res_rsa);
+ if (ret)
+ probeflags &= ~PROBE_RSA;
+
+ if (flags & UART_CONFIG_TYPE)
+ autoconfig(up, probeflags);
+ if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
+ autoconfig_irq(up);
+
+ /*
+ * If the port wasn't an RSA port, release the resource.
+ */
+ if (up->port.type != PORT_RSA && res_rsa)
+ release_resource(res_rsa);
+
+ if (up->port.type == PORT_UNKNOWN)
+ release_resource(res_std);
+}
+
+static int
+serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if (ser->irq >= NR_IRQS || ser->irq < 0 ||
+ ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+ ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS ||
+ ser->type == PORT_STARTECH)
+ return -EINVAL;
+ return 0;
+}
+
+static const char *
+serial8250_type(struct uart_port *port)
+{
+ int type = port->type;
+
+ if (type >= ARRAY_SIZE(uart_config))
+ type = 0;
+ return uart_config[type].name;
+}
+
+static struct uart_ops serial8250_pops = {
+ tx_empty: serial8250_tx_empty,
+ set_mctrl: serial8250_set_mctrl,
+ get_mctrl: serial8250_get_mctrl,
+ stop_tx: serial8250_stop_tx,
+ start_tx: serial8250_start_tx,
+ stop_rx: serial8250_stop_rx,
+ enable_ms: serial8250_enable_ms,
+ break_ctl: serial8250_break_ctl,
+ startup: serial8250_startup,
+ shutdown: serial8250_shutdown,
+ change_speed: serial8250_change_speed,
+ pm: serial8250_pm,
+ type: serial8250_type,
+ release_port: serial8250_release_port,
+ request_port: serial8250_request_port,
+ config_port: serial8250_config_port,
+ verify_port: serial8250_verify_port,
+};
+
+static struct uart_8250_port serial8250_ports[UART_NR];
+
+static void __init serial8250_isa_init_ports(void)
+{
+ static int first = 1;
+ int i;
+
+ if (!first)
+ return;
+ first = 0;
+
+ for (i = 0; i < ARRAY_SIZE(old_serial_port); i++) {
+ serial8250_ports[i].port.iobase = old_serial_port[i].port;
+ serial8250_ports[i].port.irq = irq_cannonicalize(old_serial_port[i].irq);
+ serial8250_ports[i].port.uartclk = old_serial_port[i].base_baud * 16;
+ serial8250_ports[i].port.flags = old_serial_port[i].flags;
+ serial8250_ports[i].port.ops = &serial8250_pops;
+ }
+}
+
+static void __init serial8250_register_ports(struct uart_driver *drv)
+{
+ int i;
+
+ serial8250_isa_init_ports();
+
+ for (i = 0; i < UART_NR; i++) {
+ serial8250_ports[i].port.line = i;
+ serial8250_ports[i].port.ops = &serial8250_pops;
+ init_timer(&serial8250_ports[i].timer);
+ serial8250_ports[i].timer.function = serial8250_timeout;
+ uart_add_one_port(drv, &serial8250_ports[i].port);
+ }
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ * Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_8250_port *up)
+{
+ unsigned int status, tmout = 10000;
+
+ /* Wait up to 10ms for the character(s) to be sent. */
+ do {
+ status = serial_in(up, UART_LSR);
+
+ if (status & UART_LSR_BI)
+ up->lsr_break_flag = UART_LSR_BI;
+
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+ /* Wait up to 1s for flow control if necessary */
+ if (up->port.flags & ASYNC_CONS_FLOW) {
+ tmout = 1000000;
+ while (--tmout &&
+ ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+ udelay(1);
+ }
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ *
+ * The console_lock must be held when we get here.
+ */
+static void
+serial8250_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_8250_port *up = &serial8250_ports[co->index];
+ unsigned int ier;
+ int i;
+
+ /*
+ * First save the UER then disable the interrupts
+ */
+ ier = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++, s++) {
+ wait_for_xmitr(up);
+
+ /*
+ * Send the character out.
+ * If a LF, also do CR...
+ */
+ serial_out(up, UART_TX, *s);
+ if (*s == 10) {
+ wait_for_xmitr(up);
+ serial_out(up, UART_TX, 13);
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the IER
+ */
+ wait_for_xmitr(up);
+ serial_out(up, UART_IER, ier);
+}
+
+static kdev_t serial8250_console_device(struct console *co)
+{
+ return mk_kdev(TTY_MAJOR, 64 + co->index);
+}
+
+static int __init serial8250_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >= UART_NR)
+ co->index = 0;
+ port = &serial8250_ports[co->index].port;
+ printk("+++ index %d port %p iobase %x\n", co->index, port, port->iobase);
+
+ /*
+ * Temporary fix.
+ */
+ spin_lock_init(&port->lock);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ printk("+++ baud %d bits %d parity %c flow %c\n", baud, parity, bits, flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console serial8250_console = {
+ name: "ttyS",
+ write: serial8250_console_write,
+ device: serial8250_console_device,
+ setup: serial8250_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void __init serial8250_console_init(void)
+{
+ serial8250_isa_init_ports();
+ register_console(&serial8250_console);
+}
+
+#define SERIAL8250_CONSOLE &serial8250_console
+#else
+#define SERIAL8250_CONSOLE NULL
+#endif
+
+static struct uart_driver serial8250_reg = {
+ owner: THIS_MODULE,
+ driver_name: "serial",
+#ifdef CONFIG_DEVFS_FS
+ dev_name: "tts/%d",
+#else
+ dev_name: "ttyS",
+#endif
+ major: TTY_MAJOR,
+ minor: 64,
+ nr: UART_NR,
+ cons: SERIAL8250_CONSOLE,
+};
+
+/*
+ * register_serial and unregister_serial allows for 16x50 serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+
+static int __register_serial(struct serial_struct *req, int line)
+{
+ struct uart_port port;
+
+ port.iobase = req->port;
+ port.membase = req->iomem_base;
+ port.irq = req->irq;
+ port.uartclk = req->baud_base * 16;
+ port.fifosize = req->xmit_fifo_size;
+ port.regshift = req->iomem_reg_shift;
+ port.iotype = req->io_type;
+ port.flags = req->flags | ASYNC_BOOT_AUTOCONF;
+ port.line = line;
+
+ if (HIGH_BITS_OFFSET)
+ port.iobase |= req->port_high << HIGH_BITS_OFFSET;
+
+ /*
+ * If a clock rate wasn't specified by the low level
+ * driver, then default to the standard clock rate.
+ */
+ if (port.uartclk == 0)
+ port.uartclk = BASE_BAUD * 16;
+
+ return uart_register_port(&serial8250_reg, &port);
+}
+
+/**
+ * register_serial - configure a 16x50 serial port at runtime
+ * @req: request structure
+ *
+ * Configure the serial port specified by the request. If the
+ * port exists and is in use an error is returned. If the port
+ * is not currently in the table it is added.
+ *
+ * The port is then probed and if neccessary the IRQ is autodetected
+ * If this fails an error is returned.
+ *
+ * On success the port is ready to use and the line number is returned.
+ */
+int register_serial(struct serial_struct *req)
+{
+ return __register_serial(req, -1);
+}
+
+int __init early_serial_setup(struct serial_struct *req)
+{
+ __register_serial(req, req->line);
+ return 0;
+}
+
+/**
+ * unregister_serial - remove a 16x50 serial port at runtime
+ * @line: serial line number
+ *
+ * Remove one serial port. This may be called from interrupt
+ * context.
+ */
+void unregister_serial(int line)
+{
+ uart_unregister_port(&serial8250_reg, line);
+}
+
+/*
+ * This is for ISAPNP only.
+ */
+void serial8250_get_irq_map(unsigned int *map)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ if (serial8250_ports[i].port.type != PORT_UNKNOWN &&
+ serial8250_ports[i].port.irq < 16)
+ *map |= 1 << serial8250_ports[i].port.irq;
+ }
+}
+
+static int __init serial8250_init(void)
+{
+ int ret, i;
+
+ printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.80 $ "
+ "IRQ sharing %sabled\n", share_irqs ? "en" : "dis");
+
+ for (i = 0; i < NR_IRQS; i++)
+ spin_lock_init(&irq_lists[i].lock);
+
+ ret = uart_register_driver(&serial8250_reg);
+ if (ret)
+ return ret;
+
+ serial8250_register_ports(&serial8250_reg);
+ return 0;
+}
+
+static void __exit serial8250_exit(void)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++)
+ uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
+
+ uart_unregister_driver(&serial8250_reg);
+}
+
+module_init(serial8250_init);
+module_exit(serial8250_exit);
+
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
+EXPORT_SYMBOL(serial8250_get_irq_map);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.80 $");
+
+MODULE_PARM(share_irqs, "i");
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
+ " (unsafe)");
+
+#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
+MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
+MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
+#endif
diff --git a/drivers/serial/serial_8250.h b/drivers/serial/serial_8250.h
new file mode 100644
index 000000000000..1002d1d3d693
--- /dev/null
+++ b/drivers/serial/serial_8250.h
@@ -0,0 +1,60 @@
+/*
+ * linux/drivers/char/serial_8250.h
+ *
+ * Driver for 8250/16550-type serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2001 Russell King.
+ *
+ * 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.
+ *
+ * $Id: serial_8250.h,v 1.7 2002/07/06 16:24:46 rmk Exp $
+ */
+
+#include <linux/config.h>
+
+struct serial8250_probe {
+ struct module *owner;
+ int (*pci_init_one)(struct pci_dev *dev);
+ void (*pci_remove_one)(struct pci_dev *dev);
+ void (*pnp_init)(void);
+};
+
+int serial8250_register_probe(struct serial8250_probe *probe);
+void serial8250_unregister_probe(struct serial8250_probe *probe);
+void serial8250_get_irq_map(unsigned int *map);
+
+struct old_serial_port {
+ unsigned int uart;
+ unsigned int base_baud;
+ unsigned int port;
+ unsigned int irq;
+ unsigned int flags;
+};
+
+#undef SERIAL_DEBUG_PCI
+
+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
+#define SERIAL_INLINE
+#endif
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#else
+#define _INLINE_
+#endif
+
+#define PROBE_RSA (1 << 0)
+#define PROBE_ANY (~0)
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
+#define SERIAL8250_SHARE_IRQS 1
+#else
+#define SERIAL8250_SHARE_IRQS 0
+#endif
diff --git a/drivers/serial/serial_8250_cs.c b/drivers/serial/serial_8250_cs.c
new file mode 100644
index 000000000000..216612335008
--- /dev/null
+++ b/drivers/serial/serial_8250_cs.c
@@ -0,0 +1,719 @@
+/*======================================================================
+
+ A driver for PCMCIA serial devices
+
+ serial_cs.c 1.123 2000/08/24 18:46:38
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU General Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/tqueue.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version = "serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* Enable the speaker? */
+static int do_sound = 1;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(do_sound, "i");
+
+/*====================================================================*/
+
+/* Table of multi-port card ID's */
+
+struct multi_id {
+ u_short manfid;
+ u_short prodid;
+ int multi; /* 1 = multifunction, > 1 = # ports */
+};
+
+static struct multi_id multi_id[] = {
+ { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
+ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
+ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+ { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
+ { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
+ { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
+ { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
+};
+#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
+
+typedef struct serial_info {
+ dev_link_t link;
+ int ndev;
+ int multi;
+ int slave;
+ int manfid;
+ dev_node_t node[4];
+ int line[4];
+ struct tq_struct remove;
+} serial_info_t;
+
+static void serial_config(dev_link_t * link);
+static int serial_event(event_t event, int priority,
+ event_callback_args_t * args);
+
+static dev_info_t dev_info = "serial_cs";
+
+static dev_link_t *serial_attach(void);
+static void serial_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void
+cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+ After a card is removed, do_serial_release() will unregister
+ the serial device(s), and release the PCMCIA configuration.
+
+======================================================================*/
+
+/*
+ * This always runs in process context.
+ */
+static void do_serial_release(void *arg)
+{
+ struct serial_info *info = arg;
+ int i;
+
+ DEBUG(0, "serial_release(0x%p)\n", &info->link);
+
+ /*
+ * Recheck to see if the device is still configured.
+ */
+ if (info->link.state & DEV_CONFIG) {
+ for (i = 0; i < info->ndev; i++)
+ unregister_serial(info->line[i]);
+
+ info->link.dev = NULL;
+
+ if (!info->slave) {
+ CardServices(ReleaseConfiguration, info->link.handle);
+ CardServices(ReleaseIO, info->link.handle, &info->link.io);
+ CardServices(ReleaseIRQ, info->link.handle, &info->link.irq);
+ }
+
+ info->link.state &= ~DEV_CONFIG;
+ }
+}
+
+/*
+ * This may be called from IRQ context.
+ */
+static void serial_remove(dev_link_t *link)
+{
+ struct serial_info *info = link->priv;
+
+ link->state &= ~DEV_PRESENT;
+
+ /*
+ * FIXME: Since the card has probably been removed,
+ * we should call into the serial layer and hang up
+ * the ports on the card immediately.
+ */
+
+ if (link->state & DEV_CONFIG)
+ schedule_task(&info->remove);
+}
+
+/*======================================================================
+
+ serial_attach() creates an "instance" of the driver, allocating
+ local data structures for one device. The device is registered
+ with Card Services.
+
+======================================================================*/
+
+static dev_link_t *serial_attach(void)
+{
+ serial_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "serial_attach()\n");
+
+ /* Create new serial device */
+ info = kmalloc(sizeof (*info), GFP_KERNEL);
+ if (!info)
+ return NULL;
+ memset(info, 0, sizeof (*info));
+ link = &info->link;
+ link->priv = info;
+
+ INIT_TQUEUE(&info->remove, do_serial_release, info);
+
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.NumPorts1 = 8;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ if (do_sound) {
+ link->conf.Attributes |= CONF_ENABLE_SPKR;
+ link->conf.Status = CCSR_AUDIO_ENA;
+ }
+ link->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &serial_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(link->handle, RegisterClient, ret);
+ serial_detach(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/*======================================================================
+
+ This deletes a driver "instance". The device is de-registered
+ with Card Services. If it has been released, all local data
+ structures are freed. Otherwise, the structures will be freed
+ when the device is released.
+
+======================================================================*/
+
+static void serial_detach(dev_link_t * link)
+{
+ serial_info_t *info = link->priv;
+ dev_link_t **linkp;
+ int ret;
+
+ DEBUG(0, "serial_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link)
+ break;
+ if (*linkp == NULL)
+ return;
+
+ /*
+ * Ensure any outstanding scheduled tasks are completed.
+ */
+ flush_scheduled_tasks();
+
+ /*
+ * Ensure that the ports have been released.
+ */
+ do_serial_release(info);
+
+ if (link->handle) {
+ ret = CardServices(DeregisterClient, link->handle);
+ if (ret != CS_SUCCESS)
+ cs_error(link->handle, DeregisterClient, ret);
+ }
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ kfree(info);
+}
+
+/*====================================================================*/
+
+static int setup_serial(serial_info_t * info, ioaddr_t port, int irq)
+{
+ struct serial_struct serial;
+ int line;
+
+ memset(&serial, 0, sizeof (serial));
+ serial.port = port;
+ serial.irq = irq;
+ serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+ line = register_serial(&serial);
+ if (line < 0) {
+ printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
+ " irq %d failed\n", (u_long) serial.port, serial.irq);
+ return -1;
+ }
+
+ info->line[info->ndev] = line;
+ sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
+ info->node[info->ndev].major = TTY_MAJOR;
+ info->node[info->ndev].minor = 0x40 + line;
+ if (info->ndev > 0)
+ info->node[info->ndev - 1].next = &info->node[info->ndev];
+ info->ndev++;
+
+ return 0;
+}
+
+/*====================================================================*/
+
+static int
+get_tuple(int fn, client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
+{
+ int i;
+ i = CardServices(fn, handle, tuple);
+ if (i != CS_SUCCESS)
+ return CS_NO_MORE_ITEMS;
+ i = CardServices(GetTupleData, handle, tuple);
+ if (i != CS_SUCCESS)
+ return i;
+ return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+/*====================================================================*/
+
+static int simple_config(dev_link_t * link)
+{
+ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+ client_handle_t handle = link->handle;
+ serial_info_t *info = link->priv;
+ tuple_t tuple;
+ u_char buf[256];
+ cisparse_t parse;
+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ config_info_t config;
+ int i, j, try;
+
+ /* If the card is already configured, look up the port and irq */
+ i = CardServices(GetConfigurationInfo, handle, &config);
+ if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
+ ioaddr_t port = 0;
+ if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
+ port = config.BasePort2;
+ info->slave = 1;
+ } else if ((info->manfid == MANFID_OSITECH) &&
+ (config.NumPorts1 == 0x40)) {
+ port = config.BasePort1 + 0x28;
+ info->slave = 1;
+ }
+ if (info->slave)
+ return setup_serial(info, port, config.AssignedIRQ);
+ }
+ link->conf.Vcc = config.Vcc;
+
+ /* First pass: look for a config entry that looks normal. */
+ tuple.TupleData = (cisdata_t *) buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ /* Two tries: without IO aliases, then with aliases */
+ for (try = 0; try < 2; try++) {
+ i = first_tuple(handle, &tuple, &parse);
+ while (i != CS_NO_MORE_ITEMS) {
+ if (i != CS_SUCCESS)
+ goto next_entry;
+ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+ (cf->io.win[0].base != 0)) {
+ link->conf.ConfigIndex = cf->index;
+ link->io.BasePort1 = cf->io.win[0].base;
+ link->io.IOAddrLines = (try == 0) ?
+ 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+ i =
+ CardServices(RequestIO, link->handle,
+ &link->io);
+ if (i == CS_SUCCESS)
+ goto found_port;
+ }
+ next_entry:
+ i = next_tuple(handle, &tuple, &parse);
+ }
+ }
+
+ /* Second pass: try to find an entry that isn't picky about
+ its base address, then try to grab any standard serial port
+ address, and finally try to get any free port. */
+ i = first_tuple(handle, &tuple, &parse);
+ while (i != CS_NO_MORE_ITEMS) {
+ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
+ ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+ link->conf.ConfigIndex = cf->index;
+ for (j = 0; j < 5; j++) {
+ link->io.BasePort1 = base[j];
+ link->io.IOAddrLines = base[j] ? 16 : 3;
+ i = CardServices(RequestIO, link->handle,
+ &link->io);
+ if (i == CS_SUCCESS)
+ goto found_port;
+ }
+ }
+ i = next_tuple(handle, &tuple, &parse);
+ }
+
+ found_port:
+ if (i != CS_SUCCESS) {
+ printk(KERN_NOTICE
+ "serial_cs: no usable port range found, giving up\n");
+ cs_error(link->handle, RequestIO, i);
+ return -1;
+ }
+
+ i = CardServices(RequestIRQ, link->handle, &link->irq);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestIRQ, i);
+ link->irq.AssignedIRQ = 0;
+ }
+ if (info->multi && (info->manfid == MANFID_3COM))
+ link->conf.ConfigIndex &= ~(0x08);
+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestConfiguration, i);
+ return -1;
+ }
+
+ return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+}
+
+static int multi_config(dev_link_t * link)
+{
+ client_handle_t handle = link->handle;
+ serial_info_t *info = link->priv;
+ tuple_t tuple;
+ u_char buf[256];
+ cisparse_t parse;
+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ int i, base2 = 0;
+
+ tuple.TupleData = (cisdata_t *) buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+ /* First, look for a generic full-sized window */
+ link->io.NumPorts1 = info->multi * 8;
+ i = first_tuple(handle, &tuple, &parse);
+ while (i != CS_NO_MORE_ITEMS) {
+ /* The quad port cards have bad CIS's, so just look for a
+ window larger than 8 ports and assume it will be right */
+ if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
+ (cf->io.win[0].len > 8)) {
+ link->conf.ConfigIndex = cf->index;
+ link->io.BasePort1 = cf->io.win[0].base;
+ link->io.IOAddrLines =
+ cf->io.flags & CISTPL_IO_LINES_MASK;
+ i = CardServices(RequestIO, link->handle, &link->io);
+ base2 = link->io.BasePort1 + 8;
+ if (i == CS_SUCCESS)
+ break;
+ }
+ i = next_tuple(handle, &tuple, &parse);
+ }
+
+ /* If that didn't work, look for two windows */
+ if (i != CS_SUCCESS) {
+ link->io.NumPorts1 = link->io.NumPorts2 = 8;
+ info->multi = 2;
+ i = first_tuple(handle, &tuple, &parse);
+ while (i != CS_NO_MORE_ITEMS) {
+ if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
+ link->conf.ConfigIndex = cf->index;
+ link->io.BasePort1 = cf->io.win[0].base;
+ link->io.BasePort2 = cf->io.win[1].base;
+ link->io.IOAddrLines =
+ cf->io.flags & CISTPL_IO_LINES_MASK;
+ i =
+ CardServices(RequestIO, link->handle,
+ &link->io);
+ base2 = link->io.BasePort2;
+ if (i == CS_SUCCESS)
+ break;
+ }
+ i = next_tuple(handle, &tuple, &parse);
+ }
+ }
+
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestIO, i);
+ return -1;
+ }
+
+ i = CardServices(RequestIRQ, link->handle, &link->irq);
+ if (i != CS_SUCCESS) {
+ printk(KERN_NOTICE
+ "serial_cs: no usable port range found, giving up\n");
+ cs_error(link->handle, RequestIRQ, i);
+ link->irq.AssignedIRQ = 0;
+ }
+ /* Socket Dual IO: this enables irq's for second port */
+ if (info->multi && (info->manfid == MANFID_SOCKET)) {
+ link->conf.Present |= PRESENT_EXT_STATUS;
+ link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
+ }
+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestConfiguration, i);
+ return -1;
+ }
+
+ setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+ /* The Nokia cards are not really multiport cards */
+ if (info->manfid == MANFID_NOKIA)
+ return 0;
+ for (i = 0; i < info->multi - 1; i++)
+ setup_serial(info, base2 + (8 * i), link->irq.AssignedIRQ);
+
+ return 0;
+}
+
+/*======================================================================
+
+ serial_config() is scheduled to run after a CARD_INSERTION event
+ is received, to configure the PCMCIA socket, and to make the
+ serial device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+void serial_config(dev_link_t * link)
+{
+ client_handle_t handle = link->handle;
+ serial_info_t *info = link->priv;
+ tuple_t tuple;
+ u_short buf[128];
+ cisparse_t parse;
+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ int i, last_ret, last_fn;
+
+ DEBUG(0, "serial_config(0x%p)\n", link);
+
+ tuple.TupleData = (cisdata_t *) buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ /* Get configuration register information */
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ last_ret = first_tuple(handle, &tuple, &parse);
+ if (last_ret != CS_SUCCESS) {
+ last_fn = ParseTuple;
+ goto cs_failed;
+ }
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ /* Is this a compliant multifunction card? */
+ tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+ tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
+ info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
+
+ /* Is this a multiport card? */
+ tuple.DesiredTuple = CISTPL_MANFID;
+ if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+ info->manfid = le16_to_cpu(buf[0]);
+ for (i = 0; i < MULTI_COUNT; i++)
+ if ((info->manfid == multi_id[i].manfid) &&
+ (le16_to_cpu(buf[1]) == multi_id[i].prodid))
+ break;
+ if (i < MULTI_COUNT)
+ info->multi = multi_id[i].multi;
+ }
+
+ /* Another check for dual-serial cards: look for either serial or
+ multifunction cards that ask for appropriate IO port ranges */
+ tuple.DesiredTuple = CISTPL_FUNCID;
+ if ((info->multi == 0) &&
+ ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) ||
+ (parse.funcid.func == CISTPL_FUNCID_MULTI) ||
+ (parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+ if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
+ info->multi = cf->io.win[0].len >> 3;
+ if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
+ (cf->io.win[1].len == 8))
+ info->multi = 2;
+ }
+ }
+
+ if (info->multi > 1)
+ multi_config(link);
+ else
+ simple_config(link);
+
+ if (info->ndev == 0)
+ goto failed;
+
+ if (info->manfid == MANFID_IBM) {
+ conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
+ CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
+ reg.Action = CS_WRITE;
+ reg.Value = reg.Value | 1;
+ CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
+ }
+
+ link->dev = &info->node[0];
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ failed:
+ do_serial_release(info);
+}
+
+/*======================================================================
+
+ The card status event handler. Mostly, this schedules other
+ stuff to run after an event is received. A CARD_REMOVAL event
+ also sets some flags to discourage the serial drivers from
+ talking to the ports.
+
+======================================================================*/
+
+static int
+serial_event(event_t event, int priority, event_callback_args_t * args)
+{
+ dev_link_t *link = args->client_data;
+ serial_info_t *info = link->priv;
+
+ DEBUG(1, "serial_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ serial_remove(link);
+ break;
+
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ serial_config(link);
+ break;
+
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if ((link->state & DEV_CONFIG) && !info->slave)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (DEV_OK(link) && !info->slave)
+ CardServices(RequestConfiguration, link->handle,
+ &link->conf);
+ break;
+ }
+ return 0;
+}
+
+/*====================================================================*/
+
+static int __init init_serial_cs(void)
+{
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "serial_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
+ return 0;
+}
+
+static void __exit exit_serial_cs(void)
+{
+ DEBUG(0, "serial_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ serial_detach(dev_list);
+}
+
+module_init(init_serial_cs);
+module_exit(exit_serial_cs);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_8250_pci.c b/drivers/serial/serial_8250_pci.c
new file mode 100644
index 000000000000..5b20507bbbc8
--- /dev/null
+++ b/drivers/serial/serial_8250_pci.c
@@ -0,0 +1,1138 @@
+/*
+ * linux/drivers/char/serial_8250_pci.c
+ *
+ * Probe module for 8250/16550-type PCI serial ports.
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ * 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.
+ *
+ * $Id: serial_8250_pci.c,v 1.18 2002/03/10 22:32:08 rmk Exp $
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/serial.h>
+
+/* 2.4.6 compatibility cruft - to be removed with the old serial.c code */
+#define pci_board __pci_board
+#include <linux/serialP.h>
+#undef pci_board
+
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/serial.h>
+
+#include "serial_8250.h"
+
+
+#ifndef IS_PCI_REGION_IOPORT
+#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
+ IORESOURCE_IO)
+#endif
+#ifndef IS_PCI_REGION_IOMEM
+#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
+ IORESOURCE_MEM)
+#endif
+#ifndef PCI_IRQ_RESOURCE
+#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
+#endif
+
+#ifndef pci_get_subvendor
+#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
+#define pci_get_subdevice(dev) ((dev)->subsystem_device)
+#endif
+
+struct serial_private {
+ unsigned int nr;
+ struct pci_board *board;
+ int line[0];
+};
+
+struct pci_board {
+ int flags;
+ int num_ports;
+ int base_baud;
+ int uart_offset;
+ int reg_shift;
+ int (*init_fn)(struct pci_dev *dev, struct pci_board *board,
+ int enable);
+ int first_uart_offset;
+};
+
+static int
+get_pci_port(struct pci_dev *dev, struct pci_board *board,
+ struct serial_struct *req, int idx)
+{
+ unsigned long port;
+ int base_idx;
+ int max_port;
+ int offset;
+
+ base_idx = SPCI_FL_GET_BASE(board->flags);
+ if (board->flags & SPCI_FL_BASE_TABLE)
+ base_idx += idx;
+
+ if (board->flags & SPCI_FL_REGION_SZ_CAP) {
+ max_port = pci_resource_len(dev, base_idx) / 8;
+ if (idx >= max_port)
+ return 1;
+ }
+
+ offset = board->first_uart_offset;
+
+ /*
+ * Timedia/SUNIX uses a mixture of BARs and offsets
+ * Ugh, this is ugly as all hell --- TYT
+ */
+ if (dev->vendor == PCI_VENDOR_ID_TIMEDIA)
+ switch(idx) {
+ case 0:
+ base_idx = 0;
+ break;
+ case 1:
+ base_idx = 0;
+ offset = 8;
+ break;
+ case 2:
+ base_idx = 1;
+ break;
+ case 3:
+ base_idx = 1;
+ offset = 8;
+ break;
+ case 4: /* BAR 2 */
+ case 5: /* BAR 3 */
+ case 6: /* BAR 4 */
+ case 7: /* BAR 5 */
+ base_idx = idx - 2;
+ }
+
+ /* AFAVLAB uses a different mixture of BARs and offsets */
+ /* Not that ugly ;) -- HW */
+ if (dev->vendor == PCI_VENDOR_ID_AFAVLAB && idx >= 4) {
+ base_idx = 4;
+ offset = (idx - 4) * 8;
+ }
+
+ /* Some Titan cards are also a little weird */
+ if (dev->vendor == PCI_VENDOR_ID_TITAN &&
+ (dev->device == PCI_DEVICE_ID_TITAN_400L ||
+ dev->device == PCI_DEVICE_ID_TITAN_800L)) {
+ switch (idx) {
+ case 0: base_idx = 1;
+ break;
+ case 1: base_idx = 2;
+ break;
+ default:
+ base_idx = 4;
+ offset = 8 * (idx - 2);
+ }
+ }
+
+ port = pci_resource_start(dev, base_idx) + offset;
+
+ if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
+ port += idx * (board->uart_offset ? board->uart_offset : 8);
+
+ if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
+ req->port = port;
+ if (HIGH_BITS_OFFSET)
+ req->port_high = port >> HIGH_BITS_OFFSET;
+ else
+ req->port_high = 0;
+ return 0;
+ }
+ req->io_type = SERIAL_IO_MEM;
+ req->iomem_base = ioremap(port, board->uart_offset);
+ if (req->iomem_base == NULL)
+ return -ENOMEM;
+ req->iomem_reg_shift = board->reg_shift;
+ req->port = 0;
+ return 0;
+}
+
+static _INLINE_ int
+get_pci_irq(struct pci_dev *dev, struct pci_board *board, int idx)
+{
+ int base_idx;
+
+ if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
+ return dev->irq;
+
+ base_idx = SPCI_FL_GET_IRQBASE(board->flags);
+ if (board->flags & SPCI_FL_IRQ_TABLE)
+ base_idx += idx;
+
+ return PCI_IRQ_RESOURCE(dev, base_idx);
+}
+
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled. This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int __devinit
+pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ u8 *p, irq_config = 0;
+
+ if (enable) {
+ irq_config = 0x41;
+ if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+ irq_config = 0x43;
+ if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+ (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) {
+ /*
+ * As the megawolf cards have the int pins active
+ * high, and have 2 UART chips, both ints must be
+ * enabled on the 9050. Also, the UARTS are set in
+ * 16450 mode by default, so we have to enable the
+ * 16C950 'enhanced' mode so that we can use the
+ * deep FIFOs
+ */
+ irq_config = 0x5b;
+ }
+ }
+
+ /*
+ * enable/disable interrupts
+ */
+ p = ioremap(pci_resource_start(dev, 0), 0x80);
+ if (p == NULL)
+ return -ENOMEM;
+ writel(irq_config, (unsigned long)p + 0x4c);
+
+ /*
+ * Read the register back to ensure that it took effect.
+ */
+ readl((unsigned long)p + 0x4c);
+ iounmap(p);
+
+ return 0;
+}
+
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equiped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ * SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999
+ *
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ * - 10x cards have control registers in IO and/or memory space;
+ * - 20x cards have control registers in standard PCI configuration space.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+static int __devinit
+pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ u16 data, *p;
+
+ if (!enable)
+ return 0;
+
+ switch (dev->device & 0xfff8) {
+ case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
+ data = 0xffdf;
+ break;
+ case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
+ data = 0xf7ff;
+ break;
+ default: /* 1S1P, 4S */
+ data = 0xfffb;
+ break;
+ }
+
+ p = ioremap(pci_resource_start(dev, 0), 0x80);
+ if (p == NULL)
+ return -ENOMEM;
+
+ writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
+ iounmap(p);
+ return 0;
+}
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+static int __devinit
+pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ u8 data;
+
+ if (!enable)
+ return 0;
+
+ /* Change clock frequency for the first UART. */
+ pci_read_config_byte(dev, 0x6f, &data);
+ pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+ /* If this card has 2 UART, we have to do the same with second UART. */
+ if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+ ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+ pci_read_config_byte(dev, 0x73, &data);
+ pci_write_config_byte(dev, 0x73, data & 0xef);
+ }
+ return 0;
+}
+
+/* Added for EKF Intel i960 serial boards */
+static int __devinit
+pci_inteli960ni_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ unsigned long oldval;
+
+ if (!(pci_get_subdevice(dev) & 0x1000))
+ return -ENODEV;
+
+ if (!enable) /* is there something to deinit? */
+ return 0;
+
+ /* is firmware started? */
+ pci_read_config_dword(dev, 0x44, (void*) &oldval);
+ if (oldval == 0x00001000L) { /* RESET value */
+ printk(KERN_DEBUG "Local i960 firmware missing");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/*
+ * Timedia has an explosion of boards, and to avoid the PCI table from
+ * growing *huge*, we use this function to collapse some 70 entries
+ * in the PCI table into one, for sanity's and compactness's sake.
+ */
+static unsigned short timedia_single_port[] = {
+ 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
+};
+
+static unsigned short timedia_dual_port[] = {
+ 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
+ 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
+ 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
+ 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
+ 0xD079, 0
+};
+
+static unsigned short timedia_quad_port[] = {
+ 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
+ 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
+ 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
+ 0xB157, 0
+};
+
+static unsigned short timedia_eight_port[] = {
+ 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
+ 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
+};
+
+static struct timedia_struct {
+ int num;
+ unsigned short *ids;
+} timedia_data[] = {
+ { 1, timedia_single_port },
+ { 2, timedia_dual_port },
+ { 4, timedia_quad_port },
+ { 8, timedia_eight_port },
+ { 0, 0 }
+};
+
+static int __devinit
+pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ int i, j;
+ unsigned short *ids;
+
+ if (!enable)
+ return 0;
+
+ for (i = 0; timedia_data[i].num; i++) {
+ ids = timedia_data[i].ids;
+ for (j = 0; ids[j]; j++) {
+ if (pci_get_subdevice(dev) == ids[j]) {
+ board->num_ports = timedia_data[i].num;
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static int __devinit
+pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+ return 0;
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support. It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ */
+enum pci_board_num_t {
+ pbn_b0_1_115200,
+ pbn_default = 0,
+
+ pbn_b0_2_115200,
+ pbn_b0_4_115200,
+
+ pbn_b0_1_921600,
+ pbn_b0_2_921600,
+ pbn_b0_4_921600,
+
+ pbn_b0_bt_1_115200,
+ pbn_b0_bt_2_115200,
+ pbn_b0_bt_8_115200,
+ pbn_b0_bt_1_460800,
+ pbn_b0_bt_2_460800,
+
+ pbn_b1_1_115200,
+ pbn_b1_2_115200,
+ pbn_b1_4_115200,
+ pbn_b1_8_115200,
+
+ pbn_b1_2_921600,
+ pbn_b1_4_921600,
+ pbn_b1_8_921600,
+
+ pbn_b1_2_1382400,
+ pbn_b1_4_1382400,
+ pbn_b1_8_1382400,
+
+ pbn_b2_8_115200,
+ pbn_b2_4_460800,
+ pbn_b2_8_460800,
+ pbn_b2_16_460800,
+ pbn_b2_4_921600,
+ pbn_b2_8_921600,
+
+ pbn_b2_bt_1_115200,
+ pbn_b2_bt_2_115200,
+ pbn_b2_bt_4_115200,
+ pbn_b2_bt_2_921600,
+
+ pbn_panacom,
+ pbn_panacom2,
+ pbn_panacom4,
+ pbn_plx_romulus,
+ pbn_oxsemi,
+ pbn_timedia,
+ pbn_intel_i960,
+ pbn_sgi_ioc3,
+ pbn_nec_nile4,
+
+ pbn_dci_pccom4,
+ pbn_dci_pccom8,
+
+ pbn_xircom_combo,
+
+ pbn_siig10x_0,
+ pbn_siig10x_1,
+ pbn_siig10x_2,
+ pbn_siig10x_4,
+ pbn_siig20x_0,
+ pbn_siig20x_2,
+ pbn_siig20x_4,
+
+ pbn_computone_4,
+ pbn_computone_6,
+ pbn_computone_8,
+};
+
+static struct pci_board pci_boards[] __devinitdata = {
+ /*
+ * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
+ * Offset to get to next UART's registers,
+ * Register shift to use for memory-mapped I/O,
+ * Initialization function, first UART offset
+ */
+
+ /* Generic serial board, pbn_b0_1_115200, pbn_default */
+ { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200,
+ pbn_default */
+
+ { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */
+ { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */
+
+ { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */
+ { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */
+ { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */
+
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 8, 115200 }, /* pbn_b0_bt_8_115200 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
+
+ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */
+ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */
+ { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */
+ { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */
+
+ { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */
+ { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */
+ { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */
+
+ { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */
+ { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */
+ { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */
+
+ { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */
+ { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */
+ { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */
+ { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */
+ { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */
+ { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */
+
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
+
+ { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */
+ 0x400, 7, pci_plx9050_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */
+ 0x400, 7, pci_plx9050_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */
+ 0x400, 7, pci_plx9050_fn },
+ { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */
+ 0x20, 2, pci_plx9050_fn, 0x03 },
+ /* This board uses the size of PCI Base region 0 to
+ * signal now many ports are available */
+ { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
+ { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */
+ 0, 0, pci_timedia_fn },
+ /* EKF addition for i960 Boards form EKF with serial port */
+ { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */
+ 8<<2, 2, pci_inteli960ni_fn, 0x10000},
+ { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */
+ 1, 458333, 0, 0, 0, 0x20178 },
+
+ /*
+ * NEC Vrc-5074 (Nile 4) builtin UART.
+ */
+ { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */
+ 64, 3, NULL, 0x300 },
+
+ { SPCI_FL_BASE3, 4, 115200, 8 }, /* pbn_dci_pccom4 */
+ { SPCI_FL_BASE3, 8, 115200, 8 }, /* pbn_dci_pccom8 */
+
+ { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */
+ 0, 0, pci_xircom_fn },
+
+ { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */
+ 0, 0, pci_siig10x_fn },
+ { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */
+ 0, 0, pci_siig20x_fn },
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */
+ 0, 0, pci_siig20x_fn },
+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */
+ 0, 0, pci_siig20x_fn },
+
+ { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */
+ 0x40, 2, NULL, 0x200 },
+ { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */
+ 0x40, 2, NULL, 0x200 },
+ { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */
+ 0x40, 2, NULL, 0x200 },
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs. Returns 0 on success, 1 on failure.
+ */
+static int __devinit
+serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board)
+{
+ int num_iomem = 0, num_port = 0, first_port = -1;
+ int i;
+
+ /*
+ * If it is not a communications device or the programming
+ * interface is greater than 6, give up.
+ *
+ * (Should we try to make guesses for multiport serial devices
+ * later?)
+ */
+ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+ ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+ (dev->class & 0xff) > 6)
+ return 1;
+
+ for (i = 0; i < 6; i++) {
+ if (IS_PCI_REGION_IOPORT(dev, i)) {
+ num_port++;
+ if (first_port == -1)
+ first_port = i;
+ }
+ if (IS_PCI_REGION_IOMEM(dev, i))
+ num_iomem++;
+ }
+
+ /*
+ * If there is 1 or 0 iomem regions, and exactly one port, use
+ * it.
+ */
+ if (num_iomem <= 1 && num_port == 1) {
+ board->flags = first_port;
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return an error code to refuse.
+ *
+ * serial_struct is 60 bytes.
+ */
+static int __devinit pci_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+ struct serial_private *priv;
+ struct pci_board *board, tmp;
+ struct serial_struct serial_req;
+ int base_baud, rc, k;
+
+ if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
+ printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
+ ent->driver_data);
+ return -EINVAL;
+ }
+
+ board = &pci_boards[ent->driver_data];
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ if (ent->driver_data == pbn_default &&
+ serial_pci_guess_board(dev, board))
+ return -ENODEV;
+ else if (serial_pci_guess_board(dev, &tmp) == 0) {
+ printk(KERN_INFO "Redundant entry in serial pci_table. "
+ "Please send the output of\n"
+ "lspci -vv, this message (%d,%d,%d,%d)\n"
+ "and the manufacturer and name of "
+ "serial board or modem board\n"
+ "to serial-pci-info@lists.sourceforge.net.\n",
+ dev->vendor, dev->device,
+ pci_get_subvendor(dev), pci_get_subdevice(dev));
+ }
+
+ priv = kmalloc(sizeof(struct serial_private) +
+ sizeof(unsigned int) * board->num_ports,
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /*
+ * Run the initialization function, if any
+ */
+ if (board->init_fn) {
+ rc = board->init_fn(dev, board, 1);
+ if (rc != 0) {
+ kfree(priv);
+ return rc;
+ }
+ }
+
+ base_baud = board->base_baud;
+ if (!base_baud)
+ base_baud = BASE_BAUD;
+ memset(&serial_req, 0, sizeof(serial_req));
+ for (k = 0; k < board->num_ports; k++) {
+ serial_req.irq = get_pci_irq(dev, board, k);
+ if (get_pci_port(dev, board, &serial_req, k))
+ break;
+#ifdef SERIAL_DEBUG_PCI
+ printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
+ serial_req.port, serial_req.irq, serial_req.io_type);
+#endif
+ serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
+ serial_req.baud_base = base_baud;
+
+ priv->line[k] = register_serial(&serial_req);
+ if (priv->line[k] < 0)
+ break;
+ }
+
+ priv->board = board;
+ priv->nr = k;
+
+ pci_set_drvdata(dev, priv);
+
+ return 0;
+}
+
+static void __devexit pci_remove_one(struct pci_dev *dev)
+{
+ struct serial_private *priv = pci_get_drvdata(dev);
+ int i;
+
+ pci_set_drvdata(dev, NULL);
+
+ if (priv) {
+ for (i = 0; i < priv->nr; i++)
+ unregister_serial(priv->line[i]);
+
+ priv->board->init_fn(dev, priv->board, 0);
+
+ pci_disable_device(dev);
+
+ kfree(priv);
+ }
+}
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+ pbn_b1_2_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+ pbn_b1_4_921600 },
+
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_1_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_115200 },
+
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ /* VScom SPCOM800, from sl@s.pl */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_KEYSPAN,
+ PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+ pbn_panacom },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom4 },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom2 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
+ pbn_b2_4_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
+ pbn_b2_8_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
+ pbn_b2_16_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
+ pbn_b2_16_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
+ pbn_b2_4_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
+ pbn_b2_8_460800 },
+ /* Megawolf Romulus PCI Serial Card, from Mike Hudson */
+ /* (Exoray@isys.ca) */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+ 0x10b5, 0x106a, 0, 0,
+ pbn_plx_romulus },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_115200 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_115200 },
+
+ /* Digitan DS560-558, from jimd@esoft.com */
+ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_115200 },
+
+ /* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+ { PCI_VENDOR_ID_USR, 0x1008,
+ PCI_ANY_ID, PCI_ANY_ID, },
+
+ /* Titan Electronic cards */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE1, 1, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
+ /* The 400L and 800L have a custom hack in get_pci_port */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE_TABLE, 4, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE_TABLE, 8, 921600 },
+
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_1 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_1 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_1 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_4 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_4 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig10x_4 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_0 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_2 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_4 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_4 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_siig20x_4 },
+
+ /* Computone devices submitted by Doug McNash dmcnash@computone.com */
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+ 0, 0, pbn_computone_4 },
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+ 0, 0, pbn_computone_8 },
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+ 0, 0, pbn_computone_6 },
+
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
+ { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+ PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
+
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ /* AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org> */
+ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_115200 },
+
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_460800 },
+
+ /* RAStel 2 port modem, gerg@moreton.com.au */
+ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+
+ /* EKF addition for i960 Boards form EKF with serial port */
+ { PCI_VENDOR_ID_INTEL, 0x1960,
+ 0xE4BF, PCI_ANY_ID, 0, 0,
+ pbn_intel_i960 },
+
+ /* Xircom Cardbus/Ethernet combos */
+ { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_xircom_combo },
+
+ /*
+ * Untested PCI modems, sent in from various folks...
+ */
+
+ /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
+ { PCI_VENDOR_ID_ROCKWELL, 0x1004,
+ 0x1048, 0x1500, 0, 0,
+ pbn_b1_1_115200 },
+
+ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+ 0xFF00, 0, 0, 0,
+ pbn_sgi_ioc3 },
+
+ /*
+ * NEC Vrc-5074 (Nile 4) builtin UART.
+ */
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_nec_nile4 },
+
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_dci_pccom4 },
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_dci_pccom8 },
+
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8,
+ 0xffff00, },
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MODEM << 8,
+ 0xffff00, },
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
+ 0xffff00, },
+ { 0, }
+};
+
+#ifndef __devexit_p
+#if defined(MODULE) || defined(CONFIG_HOTPLUG)
+#define __devexit_p(x) x
+#else
+#define __devexit_p(x) NULL
+#endif
+#endif
+
+static struct pci_driver serial_pci_driver = {
+ name: "serial",
+ probe: pci_init_one,
+ remove: __devexit_p(pci_remove_one),
+ id_table: serial_pci_tbl,
+};
+
+static int __init serial8250_pci_init(void)
+{
+ return pci_module_init(&serial_pci_driver);
+}
+
+static void __exit serial8250_pci_exit(void)
+{
+ pci_unregister_driver(&serial_pci_driver);
+}
+
+module_init(serial8250_pci_init);
+module_exit(serial8250_pci_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
diff --git a/drivers/serial/serial_8250_pnp.c b/drivers/serial/serial_8250_pnp.c
new file mode 100644
index 000000000000..37159599913f
--- /dev/null
+++ b/drivers/serial/serial_8250_pnp.c
@@ -0,0 +1,548 @@
+/*
+ * linux/drivers/char/serial_8250_pnp.c
+ *
+ * Probe module for 8250/16550-type ISAPNP serial ports.
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ * 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.
+ *
+ * $Id: serial_8250_pnp.c,v 1.9 2002/02/18 19:20:29 rmk Exp $
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/serial.h>
+
+#include "serial_8250.h"
+
+struct pnpbios_device_id
+{
+ char id[8];
+ unsigned long driver_data;
+};
+
+static const struct pnpbios_device_id pnp_dev_table[] = {
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { "AAC000F", 0 },
+ /* Anchor Datacomm BV */
+ /* SXPro 144 External Data Fax Modem Plug & Play */
+ { "ADC0001", 0 },
+ /* SXPro 288 External Data Fax Modem Plug & Play */
+ { "ADC0002", 0 },
+ /* Rockwell 56K ACF II Fax+Data+Voice Modem */
+ { "AKY1021", SPCI_FL_NO_SHIRQ },
+ /* AZT3005 PnP SOUND DEVICE */
+ { "AZT4001", 0 },
+ /* Best Data Products Inc. Smart One 336F PnP Modem */
+ { "BDP3336", 0 },
+ /* Boca Research */
+ /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+ { "BRI0A49", 0 },
+ /* Boca Research 33,600 ACF Modem */
+ { "BRI1400", 0 },
+ /* Boca 33.6 Kbps Internal FD34FSVD */
+ { "BRI3400", 0 },
+ /* Boca 33.6 Kbps Internal FD34FSVD */
+ { "BRI0A49", 0 },
+ /* Best Data Products Inc. Smart One 336F PnP Modem */
+ { "BDP3336", 0 },
+ /* Computer Peripherals Inc */
+ /* EuroViVa CommCenter-33.6 SP PnP */
+ { "CPI4050", 0 },
+ /* Creative Labs */
+ /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+ { "CTL3001", 0 },
+ /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+ { "CTL3011", 0 },
+ /* Creative */
+ /* Creative Modem Blaster Flash56 DI5601-1 */
+ { "DMB1032", 0 },
+ /* Creative Modem Blaster V.90 DI5660 */
+ { "DMB2001", 0 },
+ /* FUJITSU */
+ /* Fujitsu 33600 PnP-I2 R Plug & Play */
+ { "FUJ0202", 0 },
+ /* Fujitsu FMV-FX431 Plug & Play */
+ { "FUJ0205", 0 },
+ /* Fujitsu 33600 PnP-I4 R Plug & Play */
+ { "FUJ0206", 0 },
+ /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+ { "FUJ0209", 0 },
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { "GVC000F", 0 },
+ /* Hayes */
+ /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+ { "HAY0001", 0 },
+ /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+ { "HAY000C", 0 },
+ /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+ { "HAY000D", 0 },
+ /* Hayes Accura 56K Ext Fax Modem PnP */
+ { "HAY5670", 0 },
+ /* Hayes Accura 56K Ext Fax Modem PnP */
+ { "HAY5674", 0 },
+ /* Hayes Accura 56K Fax Modem PnP */
+ { "HAY5675", 0 },
+ /* Hayes 288, V.34 + FAX */
+ { "HAYF000", 0 },
+ /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+ { "HAYF001", 0 },
+ /* IBM */
+ /* IBM Thinkpad 701 Internal Modem Voice */
+ { "IBM0033", 0 },
+ /* Intertex */
+ /* Intertex 28k8 33k6 Voice EXT PnP */
+ { "IXDC801", 0 },
+ /* Intertex 33k6 56k Voice EXT PnP */
+ { "IXDC901", 0 },
+ /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ { "IXDD801", 0 },
+ /* Intertex 33k6 56k Voice SP EXT PnP */
+ { "IXDD901", 0 },
+ /* Intertex 28k8 33k6 Voice SP INT PnP */
+ { "IXDF401", 0 },
+ /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ { "IXDF801", 0 },
+ /* Intertex 33k6 56k Voice SP EXT PnP */
+ { "IXDF901", 0 },
+ /* Kortex International */
+ /* KORTEX 28800 Externe PnP */
+ { "KOR4522", 0 },
+ /* KXPro 33.6 Vocal ASVD PnP */
+ { "KORF661", 0 },
+ /* Lasat */
+ /* LASAT Internet 33600 PnP */
+ { "LAS4040", 0 },
+ /* Lasat Safire 560 PnP */
+ { "LAS4540", 0 },
+ /* Lasat Safire 336 PnP */
+ { "LAS5440", 0 },
+ /* Microcom, Inc. */
+ /* Microcom TravelPorte FAST V.34 Plug & Play */
+ { "MNP0281", 0 },
+ /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+ { "MNP0336", 0 },
+ /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+ { "MNP0339", 0 },
+ /* Microcom DeskPorte 28.8P Plug & Play */
+ { "MNP0342", 0 },
+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ { "MNP0500", 0 },
+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ { "MNP0501", 0 },
+ /* Microcom DeskPorte 28.8S Internal Plug & Play */
+ { "MNP0502", 0 },
+ /* Motorola */
+ /* Motorola BitSURFR Plug & Play */
+ { "MOT1105", 0 },
+ /* Motorola TA210 Plug & Play */
+ { "MOT1111", 0 },
+ /* Motorola HMTA 200 (ISDN) Plug & Play */
+ { "MOT1114", 0 },
+ /* Motorola BitSURFR Plug & Play */
+ { "MOT1115", 0 },
+ /* Motorola Lifestyle 28.8 Internal */
+ { "MOT1190", 0 },
+ /* Motorola V.3400 Plug & Play */
+ { "MOT1501", 0 },
+ /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+ { "MOT1502", 0 },
+ /* Motorola Power 28.8 V.34 Plug & Play */
+ { "MOT1505", 0 },
+ /* Motorola ModemSURFR External 28.8 Plug & Play */
+ { "MOT1509", 0 },
+ /* Motorola Premier 33.6 Desktop Plug & Play */
+ { "MOT150A", 0 },
+ /* Motorola VoiceSURFR 56K External PnP */
+ { "MOT150F", 0 },
+ /* Motorola ModemSURFR 56K External PnP */
+ { "MOT1510", 0 },
+ /* Motorola ModemSURFR 56K Internal PnP */
+ { "MOT1550", 0 },
+ /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+ { "MOT1560", 0 },
+ /* Motorola Premier 33.6 Internal Plug & Play */
+ { "MOT1580", 0 },
+ /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+ { "MOT15B0", 0 },
+ /* Motorola VoiceSURFR 56K Internal PnP */
+ { "MOT15F0", 0 },
+ /* Com 1 */
+ /* Deskline K56 Phone System PnP */
+ { "MVX00A1", 0 },
+ /* PC Rider K56 Phone System PnP */
+ { "MVX00F2", 0 },
+ /* Pace 56 Voice Internal Plug & Play Modem */
+ { "PMC2430", 0 },
+ /* Generic */
+ /* Generic standard PC COM port */
+ { "PNP0500", 0 },
+ /* Generic 16550A-compatible COM port */
+ { "PNP0501", 0 },
+ /* Compaq 14400 Modem */
+ { "PNPC000", 0 },
+ /* Compaq 2400/9600 Modem */
+ { "PNPC001", 0 },
+ /* Dial-Up Networking Serial Cable between 2 PCs */
+ { "PNPC031", 0 },
+ /* Dial-Up Networking Parallel Cable between 2 PCs */
+ { "PNPC032", 0 },
+ /* Standard 9600 bps Modem */
+ { "PNPC100", 0 },
+ /* Standard 14400 bps Modem */
+ { "PNPC101", 0 },
+ /* Standard 28800 bps Modem*/
+ { "PNPC102", 0 },
+ /* Standard Modem*/
+ { "PNPC103", 0 },
+ /* Standard 9600 bps Modem*/
+ { "PNPC104", 0 },
+ /* Standard 14400 bps Modem*/
+ { "PNPC105", 0 },
+ /* Standard 28800 bps Modem*/
+ { "PNPC106", 0 },
+ /* Standard Modem */
+ { "PNPC107", 0 },
+ /* Standard 9600 bps Modem */
+ { "PNPC108", 0 },
+ /* Standard 14400 bps Modem */
+ { "PNPC109", 0 },
+ /* Standard 28800 bps Modem */
+ { "PNPC10A", 0 },
+ /* Standard Modem */
+ { "PNPC10B", 0 },
+ /* Standard 9600 bps Modem */
+ { "PNPC10C", 0 },
+ /* Standard 14400 bps Modem */
+ { "PNPC10D", 0 },
+ /* Standard 28800 bps Modem */
+ { "PNPC10E", 0 },
+ /* Standard Modem */
+ { "PNPC10F", 0 },
+ /* Standard PCMCIA Card Modem */
+ { "PNP2000", 0 },
+ /* Rockwell */
+ /* Modular Technology */
+ /* Rockwell 33.6 DPF Internal PnP */
+ /* Modular Technology 33.6 Internal PnP */
+ { "ROK0030", 0 },
+ /* Kortex International */
+ /* KORTEX 14400 Externe PnP */
+ { "ROK0100", 0 },
+ /* Viking Components, Inc */
+ /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+ { "ROK4920", 0 },
+ /* Rockwell */
+ /* British Telecom */
+ /* Modular Technology */
+ /* Rockwell 33.6 DPF External PnP */
+ /* BT Prologue 33.6 External PnP */
+ /* Modular Technology 33.6 External PnP */
+ { "RSS00A0", 0 },
+ /* Viking 56K FAX INT */
+ { "RSS0262", 0 },
+ /* SupraExpress 28.8 Data/Fax PnP modem */
+ { "SUP1310", 0 },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { "SUP1421", 0 },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { "SUP1590", 0 },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { "SUP1760", 0 },
+ /* Phoebe Micro */
+ /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+ { "TEX0011", 0 },
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { "UAC000F", 0 },
+ /* 3Com Corp. */
+ /* Gateway Telepath IIvi 33.6 */
+ { "USR0000", 0 },
+ /* Sportster Vi 14.4 PnP FAX Voicemail */
+ { "USR0004", 0 },
+ /* U.S. Robotics 33.6K Voice INT PnP */
+ { "USR0006", 0 },
+ /* U.S. Robotics 33.6K Voice EXT PnP */
+ { "USR0007", 0 },
+ /* U.S. Robotics 33.6K Voice INT PnP */
+ { "USR2002", 0 },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { "USR2070", 0 },
+ /* U.S. Robotics 56K Voice EXT PnP */
+ { "USR2080", 0 },
+ /* U.S. Robotics 56K FAX INT */
+ { "USR3031", 0 },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { "USR3070", 0 },
+ /* U.S. Robotics 56K Voice EXT PnP */
+ { "USR3080", 0 },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { "USR3090", 0 },
+ /* U.S. Robotics 56K Message */
+ { "USR9100", 0 },
+ /* U.S. Robotics 56K FAX EXT PnP*/
+ { "USR9160", 0 },
+ /* U.S. Robotics 56K FAX INT PnP*/
+ { "USR9170", 0 },
+ /* U.S. Robotics 56K Voice EXT PnP*/
+ { "USR9180", 0 },
+ /* U.S. Robotics 56K Voice INT PnP*/
+ { "USR9190", 0 },
+ { "", 0 }
+};
+
+static void inline avoid_irq_share(struct pci_dev *dev)
+{
+ unsigned int map = 0x1FF8;
+ struct isapnp_irq *irq;
+ struct isapnp_resources *res = dev->sysdata;
+
+ serial8250_get_irq_map(&map);
+
+ for ( ; res; res = res->alt)
+ for (irq = res->irq; irq; irq = irq->next)
+ irq->map = map;
+}
+
+static char *modem_names[] __devinitdata = {
+ "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+ "56K", "56k", "K56", "33.6", "28.8", "14.4",
+ "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+ "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
+};
+
+static int __devinit check_name(char *name)
+{
+ char **tmp;
+
+ for (tmp = modem_names; *tmp; tmp++)
+ if (strstr(name, *tmp))
+ return 1;
+
+ return 0;
+}
+
+static int inline check_compatible_id(struct pci_dev *dev)
+{
+ int i;
+ for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
+ if ((dev->vendor_compatible[i] ==
+ ISAPNP_VENDOR('P', 'N', 'P')) &&
+ (swab16(dev->device_compatible[i]) >= 0xc000) &&
+ (swab16(dev->device_compatible[i]) <= 0xdfff))
+ return 0;
+ return 1;
+}
+
+/*
+ * Given a complete unknown ISA PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ * - dev->name or dev->bus->name must contain "modem" substring;
+ * - device must have only one IO region (8 byte long) with base adress
+ * 0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int serial_pnp_guess_board(struct pci_dev *dev, int *flags)
+{
+ struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
+ struct isapnp_resources *resa;
+
+ if (!(check_name(dev->name) || check_name(dev->bus->name)) &&
+ !(check_compatible_id(dev)))
+ return -ENODEV;
+
+ if (!res || res->next)
+ return -ENODEV;
+
+ for (resa = res->alt; resa; resa = resa->alt) {
+ struct isapnp_port *port;
+ for (port = res->port; port; port = port->next)
+ if ((port->size == 8) &&
+ ((port->min == 0x2f8) ||
+ (port->min == 0x3f8) ||
+ (port->min == 0x2e8) ||
+ (port->min == 0x3e8)))
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int
+pnp_init_one(struct pci_dev *dev, const struct pnpbios_device_id *ent,
+ char *slot_name)
+{
+ struct serial_struct serial_req;
+ int ret, line, flags = ent ? ent->driver_data : 0;
+
+ if (!ent) {
+ ret = serial_pnp_guess_board(dev, &flags);
+ if (ret)
+ return ret;
+ }
+
+ if (dev->prepare(dev) < 0) {
+ printk("serial: PNP device '%s' prepare failed\n",
+ slot_name);
+ return -ENODEV;
+ }
+
+ if (dev->active)
+ return -ENODEV;
+
+ if (flags & SPCI_FL_NO_SHIRQ)
+ avoid_irq_share(dev);
+
+ if (dev->activate(dev) < 0) {
+ printk("serial: PNP device '%s' activate failed\n",
+ slot_name);
+ return -ENODEV;
+ }
+
+ memset(&serial_req, 0, sizeof(serial_req));
+ serial_req.irq = dev->irq_resource[0].start;
+ serial_req.port = pci_resource_start(dev, 0);
+ if (HIGH_BITS_OFFSET)
+ serial_req.port = pci_resource_start(dev, 0) >> HIGH_BITS_OFFSET;
+
+#ifdef SERIAL_DEBUG_PNP
+ printk("Setup PNP port: port %x, irq %d, type %d\n",
+ serial_req.port, serial_req.irq, serial_req.io_type);
+#endif
+
+ serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
+ serial_req.baud_base = 115200;
+ line = register_serial(&serial_req);
+
+ if (line >= 0) {
+ pci_set_drvdata(dev, (void *)(line + 1));
+
+ /*
+ * Public health warning: remove this once the 2.5
+ * pnpbios_module_init() stuff is incorporated.
+ */
+ dev->driver = (void *)pnp_dev_table;
+ } else
+ dev->deactivate(dev);
+
+ return line >= 0 ? 0 : -ENODEV;
+}
+
+static void pnp_remove_one(struct pci_dev *dev)
+{
+ int line = (int)pci_get_drvdata(dev);
+
+ if (line) {
+ pci_set_drvdata(dev, NULL);
+
+ unregister_serial(line - 1);
+
+ dev->deactivate(dev);
+ }
+}
+
+static char hex[] = "0123456789ABCDEF";
+
+/*
+ * This function should vanish when 2.5 comes around and
+ * we have pnpbios_module_init()
+ */
+static int pnp_init(void)
+{
+ const struct pnpbios_device_id *id;
+ struct pci_dev *dev = NULL;
+ int nr = 0, rc = -ENODEV;
+
+#ifdef SERIAL_DEBUG_PNP
+ printk("Entered probe_serial_pnp()\n");
+#endif
+
+ isapnp_for_each_dev(dev) {
+ char slot_name[8];
+ u32 pnpid;
+
+ if (dev->active)
+ continue;
+
+ pnpid = dev->vendor << 16 | dev->device;
+ pnpid = cpu_to_le32(pnpid);
+
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+ slot_name[0] = CHAR(pnpid, 26);
+ slot_name[1] = CHAR(pnpid, 21);
+ slot_name[2] = CHAR(pnpid, 16);
+ slot_name[3] = HEX(pnpid, 12);
+ slot_name[4] = HEX(pnpid, 8);
+ slot_name[5] = HEX(pnpid, 4);
+ slot_name[6] = HEX(pnpid, 0);
+ slot_name[7] = '\0';
+
+ for (id = pnp_dev_table; id->id[0]; id++)
+ if (memcmp(id->id, slot_name, 7) == 0)
+ break;
+
+ if (id->id[0])
+ rc = pnp_init_one(dev, id, slot_name);
+ else
+ rc = pnp_init_one(dev, NULL, slot_name);
+
+ if (rc == 0)
+ nr++;
+ }
+
+#ifdef SERIAL_DEBUG_PNP
+ printk("Leaving probe_serial_pnp() (probe finished)\n");
+#endif
+
+ return nr == 0 ? rc : 0;
+}
+
+static int __init serial8250_pnp_init(void)
+{
+ if (!isapnp_present()) {
+#ifdef SERIAL_DEBUG_PNP
+ printk("Leaving probe_serial_pnp() (no isapnp)\n");
+#endif
+ return -ENODEV;
+ }
+ return pnp_init();
+}
+
+static void __exit serial8250_pnp_exit(void)
+{
+ struct pci_dev *dev = NULL;
+
+ isapnp_for_each_dev(dev) {
+ if (dev->driver != (void *)pnp_dev_table)
+ continue;
+ pnp_remove_one(dev);
+ }
+}
+
+module_init(serial8250_pnp_init);
+module_exit(serial8250_pnp_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 PNPBIOS serial probe module");
+MODULE_DEVICE_TABLE(pnpbios, pnp_dev_table);
diff --git a/drivers/serial/serial_amba.c b/drivers/serial/serial_amba.c
new file mode 100644
index 000000000000..016f717c7242
--- /dev/null
+++ b/drivers/serial/serial_amba.c
@@ -0,0 +1,783 @@
+/*
+ * linux/drivers/char/serial_amba.c
+ *
+ * Driver for AMBA serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright 1999 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: serial_amba.c,v 1.35 2002/07/21 08:57:55 rmk Exp $
+ *
+ * This is a generic driver for ARM AMBA-type serial ports. They
+ * have a lot of 16550-like features, but are not register compatable.
+ * Note that although they do have CTS, DCD and DSR inputs, they do
+ * not have an RI input, nor do they have DTR or RTS outputs. If
+ * required, these have to be supplied via some other means (eg, GPIO)
+ * and hooked into this driver.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include <asm/hardware/serial_amba.h>
+
+#define UART_NR 2
+
+#define SERIAL_AMBA_MAJOR 204
+#define SERIAL_AMBA_MINOR 16
+#define SERIAL_AMBA_NR UART_NR
+
+#define AMBA_ISR_PASS_LIMIT 256
+
+/*
+ * Access macros for the AMBA UARTs
+ */
+#define UART_GET_INT_STATUS(p) readb((p)->membase + AMBA_UARTIIR)
+#define UART_PUT_ICR(p, c) writel((c), (p)->membase + AMBA_UARTICR)
+#define UART_GET_FR(p) readb((p)->membase + AMBA_UARTFR)
+#define UART_GET_CHAR(p) readb((p)->membase + AMBA_UARTDR)
+#define UART_PUT_CHAR(p, c) writel((c), (p)->membase + AMBA_UARTDR)
+#define UART_GET_RSR(p) readb((p)->membase + AMBA_UARTRSR)
+#define UART_GET_CR(p) readb((p)->membase + AMBA_UARTCR)
+#define UART_PUT_CR(p,c) writel((c), (p)->membase + AMBA_UARTCR)
+#define UART_GET_LCRL(p) readb((p)->membase + AMBA_UARTLCR_L)
+#define UART_PUT_LCRL(p,c) writel((c), (p)->membase + AMBA_UARTLCR_L)
+#define UART_GET_LCRM(p) readb((p)->membase + AMBA_UARTLCR_M)
+#define UART_PUT_LCRM(p,c) writel((c), (p)->membase + AMBA_UARTLCR_M)
+#define UART_GET_LCRH(p) readb((p)->membase + AMBA_UARTLCR_H)
+#define UART_PUT_LCRH(p,c) writel((c), (p)->membase + AMBA_UARTLCR_H)
+#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0)
+#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0)
+#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0)
+
+#define UART_DUMMY_RSR_RX 256
+#define UART_PORT_SIZE 64
+
+/*
+ * On the Integrator platform, the port RTS and DTR are provided by
+ * bits in the following SC_CTRLS register bits:
+ * RTS DTR
+ * UART0 7 6
+ * UART1 5 4
+ */
+#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
+#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_amba_port {
+ struct uart_port port;
+ unsigned int dtr_mask;
+ unsigned int rts_mask;
+ unsigned int old_status;
+};
+
+static void __ambauart_stop_tx(struct uart_port *port)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CR(port);
+ cr &= ~AMBA_UARTCR_TIE;
+ UART_PUT_CR(port, cr);
+}
+
+static void ambauart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ __ambauart_stop_tx(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void ambauart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CR(port);
+ cr |= AMBA_UARTCR_TIE;
+ UART_PUT_CR(port, cr);
+}
+
+static void ambauart_stop_rx(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int cr;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cr = UART_GET_CR(port);
+ cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE);
+ UART_PUT_CR(port, cr);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void ambauart_enable_ms(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int cr;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cr = UART_GET_CR(port);
+ cr |= AMBA_UARTCR_MSIE;
+ UART_PUT_CR(port, cr);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+#ifdef SUPPORT_SYSRQ
+ambauart_rx_chars(struct uart_port *port, struct pt_regs *regs)
+#else
+ambauart_rx_chars(struct uart_port *port)
+#endif
+{
+ struct tty_struct *tty = port->info->tty;
+ unsigned int status, ch, rsr, max_count = 256;
+
+ status = UART_GET_FR(port);
+ while (UART_RX_DATA(status) && max_count--) {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty->flip.tqueue.routine((void *)tty);
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+ return;
+ }
+ }
+
+ ch = UART_GET_CHAR(port);
+
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = TTY_NORMAL;
+ port->icount.rx++;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
+ if (rsr & AMBA_UARTRSR_ANY) {
+ if (rsr & AMBA_UARTRSR_BE) {
+ rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE);
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ goto ignore_char;
+ } else if (rsr & AMBA_UARTRSR_PE)
+ port->icount.parity++;
+ else if (rsr & AMBA_UARTRSR_FE)
+ port->icount.frame++;
+ if (rsr & AMBA_UARTRSR_OE)
+ port->icount.overrun++;
+
+ rsr &= port->read_status_mask;
+
+ if (rsr & AMBA_UARTRSR_BE)
+ *tty->flip.flag_buf_ptr = TTY_BREAK;
+ else if (rsr & AMBA_UARTRSR_PE)
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ else if (rsr & AMBA_UARTRSR_FE)
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, ch, regs))
+ goto ignore_char;
+
+ if ((rsr & port->ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((rsr & AMBA_UARTRSR_OE) &&
+ tty->flip.count < TTY_FLIPBUF_SIZE) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ *tty->flip.char_buf_ptr++ = 0;
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ tty->flip.count++;
+ }
+ ignore_char:
+ status = UART_GET_FR(port);
+ }
+ tty_flip_buffer_push(tty);
+ return;
+}
+
+static void ambauart_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+ int count;
+
+ if (port->x_char) {
+ UART_PUT_CHAR(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ __ambauart_stop_tx(port);
+ return;
+ }
+
+ count = port->fifosize >> 1;
+ do {
+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(port, EVT_WRITE_WAKEUP);
+
+ if (uart_circ_empty(xmit))
+ __ambauart_stop_tx(port);
+}
+
+static void ambauart_modem_status(struct uart_port *port)
+{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ unsigned int status, delta;
+
+ UART_PUT_ICR(&uap->port, 0);
+
+ status = UART_GET_FR(&uap->port) & AMBA_UARTFR_MODEM_ANY;
+
+ delta = status ^ uap->old_status;
+ uap->old_status = status;
+
+ if (!delta)
+ return;
+
+ if (delta & AMBA_UARTFR_DCD)
+ uart_handle_dcd_change(&uap->port, status & AMBA_UARTFR_DCD);
+
+ if (delta & AMBA_UARTFR_DSR)
+ uap->port.icount.dsr++;
+
+ if (delta & AMBA_UARTFR_CTS)
+ uart_handle_cts_change(&uap->port, status & AMBA_UARTFR_CTS);
+
+ wake_up_interruptible(&uap->port.info->delta_msr_wait);
+}
+
+static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = dev_id;
+ unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+
+ status = UART_GET_INT_STATUS(port);
+ do {
+ if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS))
+#ifdef SUPPORT_SYSRQ
+ ambauart_rx_chars(port, regs);
+#else
+ ambauart_rx_chars(port);
+#endif
+ if (status & AMBA_UARTIIR_MIS)
+ ambauart_modem_status(port);
+ if (status & AMBA_UARTIIR_TIS)
+ ambauart_tx_chars(port);
+
+ if (pass_counter-- == 0)
+ break;
+
+ status = UART_GET_INT_STATUS(port);
+ } while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS |
+ AMBA_UARTIIR_TIS));
+}
+
+static unsigned int ambauart_tx_empty(struct uart_port *port)
+{
+ return UART_GET_FR(port) & AMBA_UARTFR_BUSY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int ambauart_get_mctrl(struct uart_port *port)
+{
+ unsigned int result = 0;
+ unsigned int status;
+
+ status = UART_GET_FR(port);
+ if (status & AMBA_UARTFR_DCD)
+ result |= TIOCM_CAR;
+ if (status & AMBA_UARTFR_DSR)
+ result |= TIOCM_DSR;
+ if (status & AMBA_UARTFR_CTS)
+ result |= TIOCM_CTS;
+
+ return result;
+}
+
+static void ambauart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ unsigned int ctrls = 0, ctrlc = 0;
+
+ if (mctrl & TIOCM_RTS)
+ ctrlc |= uap->rts_mask;
+ else
+ ctrls |= uap->rts_mask;
+
+ if (mctrl & TIOCM_DTR)
+ ctrlc |= uap->dtr_mask;
+ else
+ ctrls |= uap->dtr_mask;
+
+ __raw_writel(ctrls, SC_CTRLS);
+ __raw_writel(ctrlc, SC_CTRLC);
+}
+
+static void ambauart_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+ unsigned int lcr_h;
+
+ spin_lock_irqsave(&port->lock, flags);
+ lcr_h = UART_GET_LCRH(port);
+ if (break_state == -1)
+ lcr_h |= AMBA_UARTLCR_H_BRK;
+ else
+ lcr_h &= ~AMBA_UARTLCR_H_BRK;
+ UART_PUT_LCRH(port, lcr_h);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int ambauart_startup(struct uart_port *port)
+{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ int retval;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(port->irq, ambauart_int, 0, "amba", port);
+ if (retval)
+ return retval;
+
+ /*
+ * initialise the old status of the modem signals
+ */
+ uap->old_status = UART_GET_FR(port) & AMBA_UARTFR_MODEM_ANY;
+
+ /*
+ * Finally, enable interrupts
+ */
+ UART_PUT_CR(port, AMBA_UARTCR_UARTEN | AMBA_UARTCR_RIE |
+ AMBA_UARTCR_RTIE);
+
+ return 0;
+}
+
+static void ambauart_shutdown(struct uart_port *port)
+{
+ /*
+ * Free the interrupt
+ */
+ free_irq(port->irq, port);
+
+ /*
+ * disable all interrupts, disable the port
+ */
+ UART_PUT_CR(port, 0);
+
+ /* disable break condition and fifos */
+ UART_PUT_LCRH(port, UART_GET_LCRH(port) &
+ ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN));
+}
+
+static void
+ambauart_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+ unsigned int lcr_h, old_cr;
+ unsigned long flags;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ lcr_h = AMBA_UARTLCR_H_WLEN_5;
+ break;
+ case CS6:
+ lcr_h = AMBA_UARTLCR_H_WLEN_6;
+ break;
+ case CS7:
+ lcr_h = AMBA_UARTLCR_H_WLEN_7;
+ break;
+ default: // CS8
+ lcr_h = AMBA_UARTLCR_H_WLEN_8;
+ break;
+ }
+ if (cflag & CSTOPB)
+ lcr_h |= AMBA_UARTLCR_H_STP2;
+ if (cflag & PARENB) {
+ lcr_h |= AMBA_UARTLCR_H_PEN;
+ if (!(cflag & PARODD))
+ lcr_h |= AMBA_UARTLCR_H_EPS;
+ }
+ if (port->fifosize > 1)
+ lcr_h |= AMBA_UARTLCR_H_FEN;
+
+ port->read_status_mask = AMBA_UARTRSR_OE;
+ if (iflag & INPCK)
+ port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
+ if (iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= AMBA_UARTRSR_BE;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
+ if (iflag & IGNBRK) {
+ port->ignore_status_mask |= AMBA_UARTRSR_BE;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= AMBA_UARTRSR_OE;
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if ((cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+ /* first, disable everything */
+ spin_lock_irqsave(&port->lock, flags);
+ old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE;
+
+ if (UART_ENABLE_MS(port, cflag))
+ old_cr |= AMBA_UARTCR_MSIE;
+
+ UART_PUT_CR(port, 0);
+
+ /* Set baud rate */
+ quot -= 1;
+ UART_PUT_LCRM(port, ((quot & 0xf00) >> 8));
+ UART_PUT_LCRL(port, (quot & 0xff));
+
+ /*
+ * ----------v----------v----------v----------v-----
+ * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+ * ----------^----------^----------^----------^-----
+ */
+ UART_PUT_LCRH(port, lcr_h);
+ UART_PUT_CR(port, old_cr);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ambauart_type(struct uart_port *port)
+{
+ return port->type == PORT_AMBA ? "AMBA" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void ambauart_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int ambauart_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_amba")
+ != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void ambauart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_AMBA;
+ ambauart_request_port(port);
+ }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int ambauart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops amba_pops = {
+ tx_empty: ambauart_tx_empty,
+ set_mctrl: ambauart_set_mctrl,
+ get_mctrl: ambauart_get_mctrl,
+ stop_tx: ambauart_stop_tx,
+ start_tx: ambauart_start_tx,
+ stop_rx: ambauart_stop_rx,
+ enable_ms: ambauart_enable_ms,
+ break_ctl: ambauart_break_ctl,
+ startup: ambauart_startup,
+ shutdown: ambauart_shutdown,
+ change_speed: ambauart_change_speed,
+ type: ambauart_type,
+ release_port: ambauart_release_port,
+ request_port: ambauart_request_port,
+ config_port: ambauart_config_port,
+ verify_port: ambauart_verify_port,
+};
+
+static struct uart_amba_port amba_ports[UART_NR] = {
+ {
+ port: {
+ membase: (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
+ mapbase: INTEGRATOR_UART0_BASE,
+ iotype: SERIAL_IO_MEM,
+ irq: IRQ_UARTINT0,
+ uartclk: 14745600,
+ fifosize: 16,
+ ops: &amba_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ line: 0,
+ },
+ dtr_mask: 1 << 5,
+ rts_mask: 1 << 4,
+ },
+ {
+ port: {
+ membase: (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
+ mapbase: INTEGRATOR_UART1_BASE,
+ iotype: SERIAL_IO_MEM,
+ irq: IRQ_UARTINT1,
+ uartclk: 14745600,
+ fifosize: 16,
+ ops: &amba_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ line: 1,
+ },
+ dtr_mask: 1 << 7,
+ rts_mask: 1 << 6,
+ }
+};
+
+#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+
+static void
+ambauart_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &amba_ports[co->index].port;
+ unsigned int status, old_cr;
+ int i;
+
+ /*
+ * First save the CR then disable the interrupts
+ */
+ old_cr = UART_GET_CR(port);
+ UART_PUT_CR(port, AMBA_UARTCR_UARTEN);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ do {
+ status = UART_GET_FR(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CHAR(port, s[i]);
+ if (s[i] == '\n') {
+ do {
+ status = UART_GET_FR(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CHAR(port, '\r');
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the TCR
+ */
+ do {
+ status = UART_GET_FR(port);
+ } while (status & AMBA_UARTFR_BUSY);
+ UART_PUT_CR(port, old_cr);
+}
+
+static kdev_t ambauart_console_device(struct console *co)
+{
+ return mk_kdev(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + co->index);
+}
+
+static void __init
+ambauart_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ if (UART_GET_CR(port) & AMBA_UARTCR_UARTEN) {
+ unsigned int lcr_h, quot;
+ lcr_h = UART_GET_LCRH(port);
+
+ *parity = 'n';
+ if (lcr_h & AMBA_UARTLCR_H_PEN) {
+ if (lcr_h & AMBA_UARTLCR_H_EPS)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ if ((lcr_h & 0x60) == AMBA_UARTLCR_H_WLEN_7)
+ *bits = 7;
+ else
+ *bits = 8;
+
+ quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8;
+ *baud = port->uartclk / (16 * (quot + 1));
+ }
+}
+
+static int __init ambauart_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 38400;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >= UART_NR)
+ co->index = 0;
+ port = &amba_ports[co->index].port;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ ambauart_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console amba_console = {
+ name: "ttyAM",
+ write: ambauart_console_write,
+ device: ambauart_console_device,
+ setup: ambauart_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void __init ambauart_console_init(void)
+{
+ register_console(&amba_console);
+}
+
+#define AMBA_CONSOLE &amba_console
+#else
+#define AMBA_CONSOLE NULL
+#endif
+
+static struct uart_driver amba_reg = {
+ owner: THIS_MODULE,
+ driver_name: "ttyAM",
+#ifdef CONFIG_DEVFS_FS
+ dev_name: "ttyAM%d",
+#else
+ dev_name: "ttyAM",
+#endif
+ major: SERIAL_AMBA_MAJOR,
+ minor: SERIAL_AMBA_MINOR,
+ nr: UART_NR,
+ cons: AMBA_CONSOLE,
+};
+
+static int __init ambauart_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: AMBA driver $Revision: 1.35 $\n");
+
+ ret = uart_register_driver(&amba_reg);
+ if (ret == 0) {
+ int i;
+
+ for (i = 0; i < UART_NR; i++)
+ uart_add_one_port(&amba_reg, &amba_ports[i].port);
+ }
+ return ret;
+}
+
+static void __exit ambauart_exit(void)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++)
+ uart_remove_one_port(&amba_reg, &amba_ports[i].port);
+
+ uart_unregister_driver(&amba_reg);
+}
+
+module_init(ambauart_init);
+module_exit(ambauart_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.35 $");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_anakin.c b/drivers/serial/serial_anakin.c
new file mode 100644
index 000000000000..f9ee4c2bb2a4
--- /dev/null
+++ b/drivers/serial/serial_anakin.c
@@ -0,0 +1,546 @@
+/*
+ * linux/drivers/char/serial_anakin.c
+ *
+ * Based on driver for AMBA serial ports, by ARM Limited,
+ * Deep Blue Solutions Ltd., Linus Torvalds and Theodore Ts'o.
+ *
+ * Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
+ *
+ * Copyright (C) 2001 Blue Mug, Inc. for Acunia N.V.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Changelog:
+ * 20-Apr-2001 TTC Created
+ * 05-May-2001 W/TTC Updated for serial_core.c
+ * 27-Jun-2001 jonm Minor changes; add mctrl support, switch to
+ * SA_INTERRUPT. Works reliably now. No longer requires
+ * changes to the serial_core API.
+ *
+ * $Id: serial_anakin.c,v 1.27 2002/07/20 17:10:03 rmk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include <linux/serial_core.h>
+
+#include <asm/arch/serial_reg.h>
+
+#define UART_NR 5
+
+#define SERIAL_ANAKIN_NAME "ttyAN"
+#define SERIAL_ANAKIN_MAJOR 204
+#define SERIAL_ANAKIN_MINOR 32
+
+static unsigned int txenable[NR_IRQS]; /* Software interrupt register */
+
+static inline unsigned int
+anakin_in(struct uart_port *port, unsigned int offset)
+{
+ return __raw_readl(port->base + offset);
+}
+
+static inline void
+anakin_out(struct uart_port *port, unsigned int offset, unsigned int value)
+{
+ __raw_writel(value, port->base + offset);
+}
+
+static void
+anakin_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ txenable[port->irq] = 0;
+}
+
+static inline void
+anakin_transmit_buffer(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ while (!(anakin_in(port, 0x10) & TXEMPTY));
+ anakin_out(port, 0x14, xmit->buf[xmit->tail]);
+ anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+ port->icount.tx++;
+
+ if (uart_circ_empty(xmit))
+ anakin_stop_tx(port, 0);
+}
+
+static inline void
+anakin_transmit_x_char(struct uart_port *port)
+{
+ anakin_out(port, 0x14, port->x_char);
+ anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
+ port->icount.tx++;
+ port->x_char = 0;
+}
+
+static void
+anakin_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ unsigned int flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ // is it this... or below
+ if (!txenable[port->irq]) {
+ txenable[port->irq] = TXENABLE;
+
+ if ((anakin_in(port, 0x10) & TXEMPTY)) {
+ anakin_transmit_buffer(port);
+ }
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+anakin_stop_rx(struct uart_port *port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ while (anakin_in(port, 0x10) & RXRELEASE)
+ anakin_in(port, 0x14);
+ anakin_out(port, 0x18, anakin_in(port, 0x18) | BLOCKRX);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+anakin_enable_ms(struct uart_port *port)
+{
+}
+
+static inline void
+anakin_rx_chars(struct uart_port *port)
+{
+ unsigned int ch;
+ struct tty_struct *tty = port->info->tty;
+
+ if (!(anakin_in(port, 0x10) & RXRELEASE))
+ return;
+
+ ch = anakin_in(port, 0x14) & 0xff;
+
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ *tty->flip.char_buf_ptr++ = ch;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ port->icount.rx++;
+ tty->flip.count++;
+ }
+ tty_flip_buffer_push(tty);
+}
+
+static inline void
+anakin_overrun_chars(struct uart_port *port)
+{
+ unsigned int ch;
+
+ ch = anakin_in(port, 0x14);
+ port->icount.overrun++;
+}
+
+static inline void
+anakin_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ if (port->x_char) {
+ anakin_transmit_x_char(port);
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ anakin_stop_tx(port, 0);
+ return;
+ }
+
+ anakin_transmit_buffer(port);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(port, EVT_WRITE_WAKEUP);
+}
+
+static void
+anakin_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int status;
+ struct uart_port *port = dev_id;
+
+ status = anakin_in(port, 0x1c);
+
+ if (status & RX)
+ anakin_rx_chars(port);
+
+ if (status & OVERRUN)
+ anakin_overrun_chars(port);
+
+ if (txenable[port->irq] && (status & TX))
+ anakin_tx_chars(port);
+}
+
+static unsigned int
+anakin_tx_empty(struct uart_port *port)
+{
+ return anakin_in(port, 0x10) & TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int
+anakin_get_mctrl(struct uart_port *port)
+{
+ unsigned int status = 0;
+
+ status |= (anakin_in(port, 0x10) & CTS ? TIOCM_CTS : 0);
+ status |= (anakin_in(port, 0x18) & DCD ? TIOCM_CAR : 0);
+ status |= (anakin_in(port, 0x18) & DTR ? TIOCM_DTR : 0);
+ status |= (anakin_in(port, 0x18) & RTS ? TIOCM_RTS : 0);
+
+ return status;
+}
+
+static void
+anakin_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned int status;
+
+ status = anakin_in(port, 0x18);
+
+ if (mctrl & TIOCM_RTS)
+ status |= RTS;
+ else
+ status &= ~RTS;
+
+ if (mctrl & TIOCM_CAR)
+ status |= DCD;
+ else
+ status &= ~DCD;
+
+ anakin_out(port, 0x18, status);
+}
+
+static void
+anakin_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+ unsigned int status;
+
+ spin_lock_irqsave(&port->lock, flags);
+ status = anakin_in(port, 0x20);
+
+ if (break_state == -1)
+ status |= SETBREAK;
+ else
+ status &= ~SETBREAK;
+
+ anakin_out(port, 0x20, status);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int anakin_startup(struct uart_port *port)
+{
+ int retval;
+ unsigned int read,write;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(port->irq, anakin_int, SA_INTERRUPT,
+ "serial_anakin", port);
+ if (retval)
+ return retval;
+
+ /*
+ * initialise the old status of the modem signals
+ */
+ port->old_status = 0;
+
+ /*
+ * Finally, disable IRQ and softIRQs for first byte)
+ */
+ txenable[port->irq] = 0;
+ read = anakin_in(port, 0x18);
+ write = (read & ~(RTS | DTR | BLOCKRX)) | IRQENABLE;
+ anakin_out(port, 0x18, write);
+
+ return 0;
+}
+
+static void anakin_shutdown(struct uart_port *port)
+{
+ /*
+ * Free the interrupt
+ */
+ free_irq(port->irq, port);
+
+ /*
+ * disable all interrupts, disable the port
+ */
+ anakin_out(port, 0x18, anakin_in(port, 0x18) & ~IRQENABLE);
+}
+
+static void
+anakin_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+ unsigned int flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ while (!(anakin_in(port, 0x10) & TXEMPTY));
+ anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER)
+ | (quot << 3));
+
+ //parity always set to none
+ anakin_out(port, 0x18, anakin_in(port, 0x18) & ~PARITY);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *anakin_type(struct port *port)
+{
+ return port->type == PORT_ANAKIN ? "ANAKIN" : NULL;
+}
+
+static struct uart_ops anakin_pops = {
+ tx_empty: anakin_tx_empty,
+ set_mctrl: anakin_set_mctrl,
+ get_mctrl: anakin_get_mctrl,
+ stop_tx: anakin_stop_tx,
+ start_tx: anakin_start_tx,
+ stop_rx: anakin_stop_rx,
+ enable_ms: anakin_enable_ms,
+ break_ctl: anakin_break_ctl,
+ startup: anakin_startup,
+ shutdown: anakin_shutdown,
+ change_speed: anakin_change_speed,
+ type: anakin_type,
+};
+
+static struct uart_port anakin_ports[UART_NR] = {
+ {
+ base: IO_BASE + UART0,
+ irq: IRQ_UART0,
+ uartclk: 3686400,
+ fifosize: 0,
+ ops: &anakin_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ line: 0,
+ },
+ {
+ base: IO_BASE + UART1,
+ irq: IRQ_UART1,
+ uartclk: 3686400,
+ fifosize: 0,
+ ops: &anakin_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ line: 1,
+ },
+ {
+ base: IO_BASE + UART2,
+ irq: IRQ_UART2,
+ uartclk: 3686400,
+ fifosize: 0,
+ ops: &anakin_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ line: 2,
+ },
+ {
+ base: IO_BASE + UART3,
+ irq: IRQ_UART3,
+ uartclk: 3686400,
+ fifosize: 0,
+ ops: &anakin_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ line: 3,
+ },
+ {
+ base: IO_BASE + UART4,
+ irq: IRQ_UART4,
+ uartclk: 3686400,
+ fifosize: 0,
+ ops: &anakin_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ line: 4,
+ },
+};
+
+
+#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE
+
+static void
+anakin_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &anakin_ports[co->index];
+ unsigned int flags, status, i;
+
+ /*
+ * First save the status then disable the interrupts
+ */
+ local_irq_save(flags);
+ status = anakin_in(port, 0x18);
+ anakin_out(port, 0x18, status & ~IRQENABLE);
+ local_irq_restore(flags);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++, s++) {
+ while (!(anakin_in(port, 0x10) & TXEMPTY));
+
+ /*
+ * Send the character out.
+ * If a LF, also do CR...
+ */
+ anakin_out(port, 0x14, *s);
+ anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
+
+ if (*s == 10) {
+ while (!(anakin_in(port, 0x10) & TXEMPTY));
+ anakin_out(port, 0x14, 13);
+ anakin_out(port, 0x18, anakin_in(port, 0x18)
+ | SENDREQUEST);
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the interrupts
+ */
+ while (!(anakin_in(port, 0x10) & TXEMPTY));
+
+ if (status & IRQENABLE) {
+ local_irq_save(flags);
+ anakin_out(port, 0x18, anakin_in(port, 0x18) | IRQENABLE);
+ local_irq_restore(flags);
+ }
+}
+
+static kdev_t
+anakin_console_device(struct console *co)
+{
+ return mk_kdev(SERIAL_ANAKIN_MAJOR, SERIAL_ANAKIN_MINOR + co->index);
+}
+
+/*
+ * Read the current UART setup.
+ */
+static void __init
+anakin_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+{
+ int paritycode;
+
+ *baud = GETBAUD (anakin_in(port, 0x10) & PRESCALER);
+ paritycode = GETPARITY(anakin_in(port, 0x18) & PARITY);
+ switch (paritycode) {
+ case NONEPARITY: *parity = 'n'; break;
+ case ODDPARITY: *parity = 'o'; break;
+ case EVENPARITY: *parity = 'e'; break;
+ }
+ *bits = 8;
+}
+
+static int __init
+anakin_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = CONFIG_ANAKIN_DEFAULT_BAUDRATE;
+ int bits = 8;
+ int parity = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >= UART_NR)
+ co->index = 0;
+ port = &anakin_ports[co->index];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits);
+ else
+ anakin_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits);
+}
+
+static struct console anakin_console = {
+ name: SERIAL_ANAKIN_NAME,
+ write: anakin_console_write,
+ device: anakin_console_device,
+ setup: anakin_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void __init
+anakin_console_init(void)
+{
+ register_console(&anakin_console);
+}
+
+#define ANAKIN_CONSOLE &anakin_console
+#else
+#define ANAKIN_CONSOLE NULL
+#endif
+
+static struct uart_register anakin_reg = {
+ driver_name: SERIAL_ANAKIN_NAME,
+ dev_name: SERIAL_ANAKIN_NAME,
+ major: SERIAL_ANAKIN_MAJOR,
+ minor: SERIAL_ANAKIN_MINOR,
+ nr: UART_NR,
+ cons: ANAKIN_CONSOLE,
+};
+
+static int __init
+anakin_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: Anakin driver $Revision: 1.27 $\n");
+
+ ret = uart_register_driver(&anakin_reg);
+ if (ret == 0) {
+ int i;
+
+ for (i = 0; i < UART_NR; i++)
+ uart_add_one_port(&anakin_reg, &anakin_ports[i]);
+ }
+ return ret;
+}
+
+__initcall(anakin_init);
+
+MODULE_DESCRIPTION("Anakin serial driver");
+MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");
+MODULE_SUPPORTED_DEVICE("ttyAN");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff --git a/drivers/serial/serial_clps711x.c b/drivers/serial/serial_clps711x.c
new file mode 100644
index 000000000000..500b9a2b9f51
--- /dev/null
+++ b/drivers/serial/serial_clps711x.c
@@ -0,0 +1,643 @@
+/*
+ * linux/drivers/char/serial_clps711x.c
+ *
+ * Driver for CLPS711x serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright 1999 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: serial_clps711x.c,v 1.38 2002/07/21 08:57:55 rmk Exp $
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/spinlock.h>
+
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include <asm/hardware/clps7111.h>
+
+#define UART_NR 2
+
+#ifndef CONFIG_SERIAL_CLPS711X_OLD_NAME
+#define SERIAL_CLPS711X_NAME "ttyCL"
+#define SERIAL_CLPS711X_MAJOR 204
+#define SERIAL_CLPS711X_MINOR 40
+#define SERIAL_CLPS711X_NR UART_NR
+
+#else
+#warning The old names/device number for this driver if compatabity is needed
+#define SERIAL_CLPS711X_NAME "ttyAM"
+#define SERIAL_CLPS711X_MAJOR 204
+#define SERIAL_CLPS711X_MINOR 16
+#define SERIAL_CLPS711X_NR UART_NR
+
+#endif
+
+/*
+ * We use the relevant SYSCON register as a base address for these ports.
+ */
+#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1)
+#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1)
+#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1)
+#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1)
+
+#define TX_IRQ(port) ((port)->irq)
+#define RX_IRQ(port) ((port)->irq + 1)
+
+#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
+
+#define tx_enabled(port) ((port)->unused[0])
+
+static void
+__clps711xuart_stop_tx(struct uart_port *port)
+{
+ if (tx_enabled(port)) {
+ disable_irq(TX_IRQ(port));
+ tx_enabled(port) = 0;
+ }
+}
+
+static void
+clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ __clps711xuart_stop_tx(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+clps711xuart_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tx_enabled(port)) {
+ enable_irq(TX_IRQ(port));
+ tx_enabled(port) = 1;
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void clps711xuart_stop_rx(struct uart_port *port)
+{
+ disable_irq(RX_IRQ(port));
+}
+
+static void clps711xuart_enable_ms(struct uart_port *port)
+{
+}
+
+static void clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty = port->info->tty;
+ unsigned int status, ch, flg, ignored = 0;
+
+ status = clps_readl(SYSFLG(port));
+ while (!(status & SYSFLG_URXFE)) {
+ ch = clps_readl(UARTDR(port));
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ port->icount.rx++;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ if (ch & UART_ANY_ERR)
+ goto handle_error;
+
+ if (uart_handle_sysrq_char(port, ch, regs))
+ goto ignore_char;
+
+ error_return:
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ ignore_char:
+ status = clps_readl(SYSFLG(port));
+ }
+ out:
+ tty_flip_buffer_push(tty);
+ return;
+
+ handle_error:
+ if (ch & UARTDR_PARERR)
+ port->icount.parity++;
+ else if (ch & UARTDR_FRMERR)
+ port->icount.frame++;
+ if (ch & UARTDR_OVERR)
+ port->icount.overrun++;
+
+ if (ch & port->ignore_status_mask) {
+ if (++ignored > 100)
+ goto out;
+ goto ignore_char;
+ }
+ ch &= port->read_status_mask;
+
+ if (ch & UARTDR_PARERR)
+ flg = TTY_PARITY;
+ else if (ch & UARTDR_FRMERR)
+ flg = TTY_FRAME;
+
+ if (ch & UARTDR_OVERR) {
+ /*
+ * CHECK: does overrun affect the current character?
+ * ASSUMPTION: it does not.
+ */
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ ch = 0;
+ flg = TTY_OVERRUN;
+ }
+#ifdef SUPPORT_SYSRQ
+ port->sysrq = 0;
+#endif
+ goto error_return;
+}
+
+static void clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = dev_id;
+ struct circ_buf *xmit = &port->info->xmit;
+ int count;
+
+ if (port->x_char) {
+ clps_writel(port->x_char, UARTDR(port));
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ __clps711xuart_stop_tx(port);
+ return;
+ }
+
+ count = port->fifosize >> 1;
+ do {
+ clps_writel(xmit->buf[xmit->tail], UARTDR(port));
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(port, EVT_WRITE_WAKEUP);
+
+ if (uart_circ_empty(xmit))
+ __clps711xuart_stop_tx(port);
+}
+
+static unsigned int clps711xuart_tx_empty(struct uart_port *port)
+{
+ unsigned int status = clps_readl(SYSFLG(port));
+ return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
+{
+ unsigned int port_addr;
+ unsigned int result = 0;
+ unsigned int status;
+
+ port_addr = SYSFLG(port);
+ if (port_addr == SYSFLG1) {
+ status = clps_readl(SYSFLG1);
+ if (status & SYSFLG1_DCD)
+ result |= TIOCM_CAR;
+ if (status & SYSFLG1_DSR)
+ result |= TIOCM_DSR;
+ if (status & SYSFLG1_CTS)
+ result |= TIOCM_CTS;
+ }
+
+ return result;
+}
+
+static void
+clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+ unsigned int ubrlcr;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ubrlcr = clps_readl(UBRLCR(port));
+ if (break_state == -1)
+ ubrlcr |= UBRLCR_BREAK;
+ else
+ ubrlcr &= ~UBRLCR_BREAK;
+ clps_writel(ubrlcr, UBRLCR(port));
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int clps711xuart_startup(struct uart_port *port)
+{
+ unsigned int syscon;
+ int retval;
+
+ tx_enabled(port) = 1;
+
+ /*
+ * Allocate the IRQs
+ */
+ retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
+ "clps711xuart_tx", port);
+ if (retval)
+ return retval;
+
+ retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
+ "clps711xuart_rx", port);
+ if (retval) {
+ free_irq(TX_IRQ(port), port);
+ return retval;
+ }
+
+ /*
+ * enable the port
+ */
+ syscon = clps_readl(SYSCON(port));
+ syscon |= SYSCON_UARTEN;
+ clps_writel(syscon, SYSCON(port));
+
+ return 0;
+}
+
+static void clps711xuart_shutdown(struct uart_port *port)
+{
+ unsigned int ubrlcr, syscon;
+
+ /*
+ * Free the interrupt
+ */
+ free_irq(TX_IRQ(port), port); /* TX interrupt */
+ free_irq(RX_IRQ(port), port); /* RX interrupt */
+
+ /*
+ * disable the port
+ */
+ syscon = clps_readl(SYSCON(port));
+ syscon &= ~SYSCON_UARTEN;
+ clps_writel(syscon, SYSCON(port));
+
+ /*
+ * disable break condition and fifos
+ */
+ ubrlcr = clps_readl(UBRLCR(port));
+ ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
+ clps_writel(ubrlcr, UBRLCR(port));
+}
+
+static void
+clps711xuart_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+ unsigned int ubrlcr;
+ unsigned long flags;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ ubrlcr = UBRLCR_WRDLEN5;
+ break;
+ case CS6:
+ ubrlcr = UBRLCR_WRDLEN6;
+ break;
+ case CS7:
+ ubrlcr = UBRLCR_WRDLEN7;
+ break;
+ default: // CS8
+ ubrlcr = UBRLCR_WRDLEN8;
+ break;
+ }
+ if (cflag & CSTOPB)
+ ubrlcr |= UBRLCR_XSTOP;
+ if (cflag & PARENB) {
+ ubrlcr |= UBRLCR_PRTEN;
+ if (!(cflag & PARODD))
+ ubrlcr |= UBRLCR_EVENPRT;
+ }
+ if (port->fifosize > 1)
+ ubrlcr |= UBRLCR_FIFOEN;
+
+ port->read_status_mask = UARTDR_OVERR;
+ if (iflag & INPCK)
+ port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
+ if (iflag & IGNBRK) {
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns to (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= UARTDR_OVERR;
+ }
+
+ quot -= 1;
+
+ /* first, disable everything */
+ spin_lock_irqsave(&port->lock, flags);
+
+ clps_writel(ubrlcr | quot, UBRLCR(port));
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *clps711xuart_type(struct uart_port *port)
+{
+ return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void clps711xuart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_CLPS711X;
+}
+
+static void clps711xuart_release_port(struct uart_port *port)
+{
+}
+
+static int clps711xuart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static struct uart_ops clps711x_pops = {
+ tx_empty: clps711xuart_tx_empty,
+ set_mctrl: clps711xuart_set_mctrl_null,
+ get_mctrl: clps711xuart_get_mctrl,
+ stop_tx: clps711xuart_stop_tx,
+ start_tx: clps711xuart_start_tx,
+ stop_rx: clps711xuart_stop_rx,
+ enable_ms: clps711xuart_enable_ms,
+ break_ctl: clps711xuart_break_ctl,
+ startup: clps711xuart_startup,
+ shutdown: clps711xuart_shutdown,
+ change_speed: clps711xuart_change_speed,
+ type: clps711xuart_type,
+ config_port: clps711xuart_config_port,
+ release_port: clps711xuart_release_port,
+ request_port: clps711xuart_request_port,
+};
+
+static struct uart_port clps711x_ports[UART_NR] = {
+ {
+ iobase: SYSCON1,
+ irq: IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
+ uartclk: 3686400,
+ fifosize: 16,
+ ops: &clps711x_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ },
+ {
+ iobase: SYSCON2,
+ irq: IRQ_UTXINT2, /* IRQ_URXINT2 */
+ uartclk: 3686400,
+ fifosize: 16,
+ ops: &clps711x_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ }
+};
+
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ *
+ * The console_lock must be held when we get here.
+ *
+ * Note that this is called with interrupts already disabled
+ */
+static void
+clps711xuart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = clps711x_ports + co->index;
+ unsigned int status, syscon;
+ int i;
+
+ /*
+ * Ensure that the port is enabled.
+ */
+ syscon = clps_readl(SYSCON(port));
+ clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ do {
+ status = clps_readl(SYSFLG(port));
+ } while (status & SYSFLG_UTXFF);
+ clps_writel(s[i], UARTDR(port));
+ if (s[i] == '\n') {
+ do {
+ status = clps_readl(SYSFLG(port));
+ } while (status & SYSFLG_UTXFF);
+ clps_writel('\r', UARTDR(port));
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the uart state.
+ */
+ do {
+ status = clps_readl(SYSFLG(port));
+ } while (status & SYSFLG_UBUSY);
+
+ clps_writel(syscon, SYSCON(port));
+}
+
+static kdev_t clps711xuart_console_device(struct console *co)
+{
+ return mk_kdev(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR + co->index);
+}
+
+static void __init
+clps711xuart_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
+ unsigned int ubrlcr, quot;
+
+ ubrlcr = clps_readl(UBRLCR(port));
+
+ *parity = 'n';
+ if (ubrlcr & UBRLCR_PRTEN) {
+ if (ubrlcr & UBRLCR_EVENPRT)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
+ *bits = 7;
+ else
+ *bits = 8;
+
+ quot = ubrlcr & UBRLCR_BAUD_MASK;
+ *baud = port->uartclk / (16 * (quot + 1));
+ }
+}
+
+static int __init clps711xuart_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 38400;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ port = uart_get_console(clps711x_ports, UART_NR, co);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ clps711xuart_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console clps711x_console = {
+ name: SERIAL_CLPS711X_NAME,
+ write: clps711xuart_console_write,
+ device: clps711xuart_console_device,
+ setup: clps711xuart_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void __init clps711xuart_console_init(void)
+{
+ register_console(&clps711x_console);
+}
+
+#define CLPS711X_CONSOLE &clps711x_console
+#else
+#define CLPS711X_CONSOLE NULL
+#endif
+
+static struct uart_driver clps711x_reg = {
+ driver_name: "ttyCL",
+#ifdef CONFIG_DEVFS_FS
+ dev_name: SERIAL_CLPS711X_NAME,
+#else
+ dev_name: SERIAL_CLPS711X_NAME,
+#endif
+
+ major: SERIAL_CLPS711X_MAJOR,
+ minor: SERIAL_CLPS711X_MINOR,
+ nr: UART_NR,
+
+ cons: CLPS711X_CONSOLE,
+};
+
+static int __init clps711xuart_init(void)
+{
+ int ret, i;
+
+ printk(KERN_INFO "Serial: CLPS711x driver $Revision: 1.38 $\n");
+
+ ret = uart_register_driver(&clps711x_reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < UART_NR; i++)
+ uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
+
+ return 0;
+}
+
+static void __exit clps711xuart_exit(void)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++)
+ uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
+
+ uart_unregister_driver(&clps711x_reg);
+}
+
+module_init(clps711xuart_init);
+module_exit(clps711xuart_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("CLPS-711x generic serial driver $Revision: 1.38 $");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
new file mode 100644
index 000000000000..c6d354329e02
--- /dev/null
+++ b/drivers/serial/serial_core.c
@@ -0,0 +1,2467 @@
+/*
+ * linux/drivers/char/serial_core.c
+ *
+ * Driver core for serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright 1999 ARM Limited
+ * Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: serial_core.c,v 1.89 2002/07/20 18:07:32 rmk Exp $
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/pm.h>
+#include <linux/serial_core.h>
+#include <linux/smp_lock.h>
+#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK(x...) printk(x)
+#else
+#define DPRINTK(x...) do { } while (0)
+#endif
+
+#ifndef CONFIG_PM
+#define pm_access(pm) do { } while (0)
+#define pm_unregister(pm) do { } while (0)
+#endif
+
+/*
+ * This is used to lock changes in serial line configuration.
+ */
+static DECLARE_MUTEX(port_sem);
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+static void uart_change_speed(struct uart_info *info, struct termios *old_termios);
+static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
+
+/*
+ * This routine is used by the interrupt handler to schedule processing in
+ * the software interrupt portion of the driver.
+ */
+void uart_event(struct uart_port *port, int event)
+{
+ struct uart_info *info = port->info;
+
+ set_bit(0, &info->event);
+ tasklet_schedule(&info->tlet);
+}
+
+static void uart_stop(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+ struct uart_port *port = info->port;
+
+ port->ops->stop_tx(port, 1);
+}
+
+static void __uart_start(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+ struct uart_port *port = info->port;
+
+ if (!uart_circ_empty(&info->xmit) && info->xmit.buf &&
+ !tty->stopped && !tty->hw_stopped)
+ port->ops->start_tx(port, 1);
+}
+
+static void uart_start(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+ unsigned long flags;
+
+ pm_access(info->state->pm);
+
+ spin_lock_irqsave(&info->port->lock, flags);
+ __uart_start(tty);
+ spin_unlock_irqrestore(&info->port->lock, flags);
+}
+
+static void uart_tasklet_action(unsigned long data)
+{
+ struct uart_info *info = (struct uart_info *)data;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))
+ return;
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+}
+
+static inline void
+uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
+{
+ unsigned long flags;
+ unsigned int old;
+
+ spin_lock_irqsave(&port->lock, flags);
+ old = port->mctrl;
+ port->mctrl = (old & ~clear) | set;
+ if (old != port->mctrl)
+ port->ops->set_mctrl(port, port->mctrl);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+#define uart_set_mctrl(port,set) uart_update_mctrl(port,set,0)
+#define uart_clear_mctrl(port,clear) uart_update_mctrl(port,0,clear)
+
+static inline void uart_update_altspeed(struct uart_info *info)
+{
+ unsigned int flags = info->port->flags & UPF_SPD_MASK;
+
+ if (flags == UPF_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if (flags == UPF_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if (flags == UPF_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if (flags == UPF_SPD_WARP)
+ info->tty->alt_speed = 460800;
+}
+
+/*
+ * Startup the port. This will be called once per open. All calls
+ * will be serialised by the global port semaphore.
+ */
+static int uart_startup(struct uart_info *info, int init_hw)
+{
+ struct uart_port *port = info->port;
+ unsigned long page;
+ int retval = 0;
+
+ if (info->flags & UIF_INITIALIZED)
+ return 0;
+
+ /*
+ * Set the TTY IO error marker - we will only clear this
+ * once we have successfully opened the port. Also set
+ * up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ uart_update_altspeed(info);
+ }
+
+ if (port->type == PORT_UNKNOWN)
+ return 0;
+
+ /*
+ * Initialise and allocate the transmit and temporary
+ * buffer.
+ */
+ if (!info->xmit.buf) {
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ info->xmit.buf = (unsigned char *) page;
+ info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE;
+ init_MUTEX(&info->tmpbuf_sem);
+ uart_circ_clear(&info->xmit);
+ }
+
+ port->mctrl = 0;
+
+ retval = port->ops->startup(port);
+ if (retval == 0) {
+ if (init_hw) {
+ /*
+ * Initialise the hardware port settings.
+ */
+ uart_change_speed(info, NULL);
+
+ /*
+ * Setup the RTS and DTR signals once the
+ * port is open and ready to respond.
+ */
+ if (info->tty->termios->c_cflag & CBAUD)
+ uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+ }
+
+ info->flags |= UIF_INITIALIZED;
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+
+ if (retval && capable(CAP_SYS_ADMIN))
+ retval = 0;
+
+ return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on. Calls to
+ * uart_shutdown are serialised by port_sem.
+ */
+static void uart_shutdown(struct uart_info *info)
+{
+ struct uart_port *port = info->port;
+
+ if (!(info->flags & UIF_INITIALIZED))
+ return;
+
+ /*
+ * Turn off DTR and RTS early.
+ */
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ uart_clear_mctrl(info->port, TIOCM_DTR | TIOCM_RTS);
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free
+ * the irq here so the queue might never be woken up. Note
+ * that we won't end up waiting on delta_msr_wait again since
+ * any outstanding file descriptors should be pointing at
+ * hung_up_tty_fops now.
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ and disable the port.
+ */
+ port->ops->shutdown(port);
+
+ /*
+ * Ensure that the IRQ handler isn't running on another CPU.
+ */
+ synchronize_irq(port->irq);
+
+ /*
+ * Free the transmit buffer page.
+ */
+ if (info->xmit.buf) {
+ free_page((unsigned long)info->xmit.buf);
+ info->xmit.buf = NULL;
+ info->tmpbuf = NULL;
+ }
+
+ /*
+ * kill off our tasklet
+ */
+ tasklet_kill(&info->tlet);
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~UIF_INITIALIZED;
+}
+
+static inline
+unsigned int uart_calculate_quot(struct uart_info *info, unsigned int baud)
+{
+ struct uart_port *port = info->port;
+ unsigned int quot;
+
+ /* Special case: B0 rate */
+ if (baud == 0)
+ baud = 9600;
+
+ /* Old HI/VHI/custom speed handling */
+ if (baud == 38400 &&
+ ((port->flags & UPF_SPD_MASK) == UPF_SPD_CUST))
+ quot = info->state->custom_divisor;
+ else
+ quot = port->uartclk / (16 * baud);
+
+ return quot;
+}
+
+static void
+uart_change_speed(struct uart_info *info, struct termios *old_termios)
+{
+ struct uart_port *port = info->port;
+ unsigned int quot, cflag, bits, try;
+
+ /*
+ * If we have no tty, termios, or the port does not exist,
+ * then we can't set the parameters for this port.
+ */
+ if (!info->tty || !info->tty->termios || port->type == PORT_UNKNOWN)
+ return;
+
+ /*
+ * Set flags based on termios cflag
+ */
+ cflag = info->tty->termios->c_cflag;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ bits = 7;
+ break;
+ case CS6:
+ bits = 8;
+ break;
+ case CS7:
+ bits = 9;
+ break;
+ default:
+ bits = 10;
+ break; // CS8
+ }
+
+ if (cflag & CSTOPB)
+ bits++;
+ if (cflag & PARENB)
+ bits++;
+
+ for (try = 0; try < 3; try ++) {
+ unsigned int baud;
+
+ /* Determine divisor based on baud rate */
+ baud = tty_get_baud_rate(info->tty);
+ quot = uart_calculate_quot(info, baud);
+ if (quot)
+ break;
+
+ /*
+ * Oops, the quotient was zero. Try again with
+ * the old baud rate if possible.
+ */
+ info->tty->termios->c_cflag &= ~CBAUD;
+ if (old_termios) {
+ info->tty->termios->c_cflag |=
+ (old_termios->c_cflag & CBAUD);
+ old_termios = NULL;
+ continue;
+ }
+
+ /*
+ * As a last resort, if the quotient is zero,
+ * default to 9600 bps
+ */
+ info->tty->termios->c_cflag |= B9600;
+ }
+
+ /*
+ * The total number of bits to be transmitted in the fifo.
+ */
+ bits = bits * port->fifosize;
+
+ /*
+ * Figure the timeout to send the above number of bits.
+ * Add .02 seconds of slop
+ */
+ port->timeout = (HZ * bits) / (port->uartclk / (16 * quot)) + HZ/50;
+
+ if (cflag & CRTSCTS)
+ info->flags |= UIF_CTS_FLOW;
+ else
+ info->flags &= ~UIF_CTS_FLOW;
+ if (cflag & CLOCAL)
+ info->flags &= ~UIF_CHECK_CD;
+ else
+ info->flags |= UIF_CHECK_CD;
+
+ port->ops->change_speed(port, cflag, info->tty->termios->c_iflag, quot);
+}
+
+static inline void
+__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
+{
+ unsigned long flags;
+
+ if (!circ->buf)
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (uart_circ_chars_free(circ) != 0) {
+ circ->buf[circ->head] = c;
+ circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static inline int
+__uart_user_write(struct uart_port *port, struct circ_buf *circ,
+ const unsigned char *buf, int count)
+{
+ unsigned long flags;
+ int c, ret = 0;
+
+ if (down_interruptible(&port->info->tmpbuf_sem))
+ return -EINTR;
+
+ while (1) {
+ int c1;
+ c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(port->info->tmpbuf, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ spin_lock_irqsave(&port->lock, flags);
+ c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+ if (c1 < c)
+ c = c1;
+ memcpy(circ->buf + circ->head, port->info->tmpbuf, c);
+ circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+ spin_unlock_irqrestore(&port->lock, flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&port->info->tmpbuf_sem);
+
+ return ret;
+}
+
+static inline int
+__uart_kern_write(struct uart_port *port, struct circ_buf *circ,
+ const unsigned char *buf, int count)
+{
+ unsigned long flags;
+ int c, ret = 0;
+
+ spin_lock_irqsave(&port->lock, flags);
+ while (1) {
+ c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(circ->buf + circ->head, buf, c);
+ circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return ret;
+}
+
+static void uart_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct uart_info *info = tty->driver_data;
+
+ if (tty)
+ __uart_put_char(info->port, &info->xmit, ch);
+}
+
+static void uart_flush_chars(struct tty_struct *tty)
+{
+ uart_start(tty);
+}
+
+static int
+uart_write(struct tty_struct *tty, int from_user, const unsigned char * buf,
+ int count)
+{
+ struct uart_info *info = tty->driver_data;
+ int ret;
+
+ if (!tty || !info->xmit.buf)
+ return 0;
+
+ if (from_user)
+ ret = __uart_user_write(info->port, &info->xmit, buf, count);
+ else
+ ret = __uart_kern_write(info->port, &info->xmit, buf, count);
+
+ uart_start(tty);
+ return ret;
+}
+
+static int uart_write_room(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+
+ return uart_circ_chars_free(&info->xmit);
+}
+
+static int uart_chars_in_buffer(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+
+ return uart_circ_chars_pending(&info->xmit);
+}
+
+static void uart_flush_buffer(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+ unsigned long flags;
+
+ DPRINTK("uart_flush_buffer(%d) called\n",
+ MINOR(tty->device) - tty->driver.minor_start);
+
+ spin_lock_irqsave(&info->port->lock, flags);
+ uart_circ_clear(&info->xmit);
+ spin_unlock_irqrestore(&info->port->lock, flags);
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void uart_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct uart_info *info = tty->driver_data;
+ struct uart_port *port = info->port;
+
+ if (port->ops->send_xchar)
+ port->ops->send_xchar(port, ch);
+ else {
+ port->x_char = ch;
+ if (ch)
+ port->ops->start_tx(port, 0);
+ }
+}
+
+static void uart_throttle(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+
+ if (I_IXOFF(tty))
+ uart_send_xchar(tty, STOP_CHAR(tty));
+
+ if (tty->termios->c_cflag & CRTSCTS)
+ uart_clear_mctrl(info->port, TIOCM_RTS);
+}
+
+static void uart_unthrottle(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+ struct uart_port *port = info->port;
+
+ if (I_IXOFF(tty)) {
+ if (port->x_char)
+ port->x_char = 0;
+ else
+ uart_send_xchar(tty, START_CHAR(tty));
+ }
+
+ if (tty->termios->c_cflag & CRTSCTS)
+ uart_set_mctrl(port, TIOCM_RTS);
+}
+
+static int uart_get_info(struct uart_info *info, struct serial_struct *retinfo)
+{
+ struct uart_state *state = info->state;
+ struct uart_port *port = info->port;
+ struct serial_struct tmp;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = port->type;
+ tmp.line = port->line;
+ tmp.port = port->iobase;
+ if (HIGH_BITS_OFFSET)
+ tmp.port_high = port->iobase >> HIGH_BITS_OFFSET;
+ tmp.irq = port->irq;
+ tmp.flags = port->flags | info->flags;
+ tmp.xmit_fifo_size = port->fifosize;
+ tmp.baud_base = port->uartclk / 16;
+ tmp.close_delay = state->close_delay;
+ tmp.closing_wait = state->closing_wait;
+ tmp.custom_divisor = state->custom_divisor;
+ tmp.hub6 = port->hub6;
+ tmp.io_type = port->iotype;
+ tmp.iomem_reg_shift = port->regshift;
+ tmp.iomem_base = (void *)port->mapbase;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+uart_set_info(struct uart_info *info, struct serial_struct *newinfo)
+{
+ struct serial_struct new_serial;
+ struct uart_state *state = info->state;
+ struct uart_port *port = info->port;
+ unsigned long new_port;
+ unsigned int change_irq, change_port, old_flags;
+ unsigned int old_custom_divisor;
+ int retval = 0;
+
+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+ return -EFAULT;
+
+ new_port = new_serial.port;
+ if (HIGH_BITS_OFFSET)
+ new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+ new_serial.irq = irq_cannonicalize(new_serial.irq);
+
+ /*
+ * This semaphore protects state->count. It is also
+ * very useful to prevent opens. Also, take the
+ * port configuration semaphore to make sure that a
+ * module insertion/removal doesn't change anything
+ * under us.
+ */
+ down(&port_sem);
+
+ change_irq = new_serial.irq != port->irq;
+
+ /*
+ * Since changing the 'type' of the port changes its resource
+ * allocations, we should treat type changes the same as
+ * IO port changes.
+ */
+ change_port = new_port != port->iobase ||
+ (unsigned long)new_serial.iomem_base != port->mapbase ||
+ new_serial.hub6 != port->hub6 ||
+ new_serial.io_type != port->iotype ||
+ new_serial.iomem_reg_shift != port->regshift ||
+ new_serial.type != port->type;
+
+ old_flags = port->flags;
+ old_custom_divisor = state->custom_divisor;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ retval = -EPERM;
+ if (change_irq || change_port ||
+ (new_serial.baud_base != port->uartclk / 16) ||
+ (new_serial.close_delay != state->close_delay) ||
+ (new_serial.closing_wait != state->closing_wait) ||
+ (new_serial.xmit_fifo_size != port->fifosize) ||
+ (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0))
+ goto exit;
+ port->flags = ((port->flags & ~UPF_USR_MASK) |
+ (new_serial.flags & UPF_USR_MASK));
+ state->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ /*
+ * Ask the low level driver to verify the settings.
+ */
+ if (port->ops->verify_port)
+ retval = port->ops->verify_port(port, &new_serial);
+
+ if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+ (new_serial.baud_base < 9600))
+ retval = -EINVAL;
+
+ if (retval)
+ goto exit;
+
+ if (change_port || change_irq) {
+ retval = -EBUSY;
+
+ /*
+ * Make sure that we are the sole user of this port.
+ */
+ if (state->count > 1 || info->blocked_open != 0)
+ goto exit;
+
+ /*
+ * We need to shutdown the serial port at the old
+ * port/type/irq combination.
+ */
+ uart_shutdown(info);
+ }
+
+ if (change_port) {
+ unsigned long old_iobase, old_mapbase;
+ unsigned int old_type, old_iotype, old_hub6, old_shift;
+
+ old_iobase = port->iobase;
+ old_mapbase = port->mapbase;
+ old_type = port->type;
+ old_hub6 = port->hub6;
+ old_iotype = port->iotype;
+ old_shift = port->regshift;
+
+ /*
+ * Free and release old regions
+ */
+ if (old_type != PORT_UNKNOWN)
+ port->ops->release_port(port);
+
+ port->iobase = new_port;
+ port->type = new_serial.type;
+ port->hub6 = new_serial.hub6;
+ port->iotype = new_serial.io_type;
+ port->regshift = new_serial.iomem_reg_shift;
+ port->mapbase = (unsigned long)new_serial.iomem_base;
+
+ /*
+ * Claim and map the new regions
+ */
+ if (port->type != PORT_UNKNOWN)
+ retval = port->ops->request_port(port);
+
+ /*
+ * If we fail to request resources for the
+ * new port, try to restore the old settings.
+ */
+ if (retval && old_type != PORT_UNKNOWN) {
+ port->iobase = old_iobase;
+ port->type = old_type;
+ port->hub6 = old_hub6;
+ port->iotype = old_iotype;
+ port->regshift = old_shift;
+ port->mapbase = old_mapbase;
+ retval = port->ops->request_port(port);
+ /*
+ * If we failed to restore the old settings,
+ * we fail like this.
+ */
+ if (retval)
+ port->type = PORT_UNKNOWN;
+
+ /*
+ * We failed anyway.
+ */
+ retval = -EBUSY;
+ }
+ }
+
+ port->irq = new_serial.irq;
+ port->uartclk = new_serial.baud_base * 16;
+ port->flags = new_serial.flags & UPF_FLAGS;
+ state->custom_divisor = new_serial.custom_divisor;
+ state->close_delay = new_serial.close_delay * HZ / 100;
+ state->closing_wait = new_serial.closing_wait * HZ / 100;
+ port->fifosize = new_serial.xmit_fifo_size;
+ info->tty->low_latency = (port->flags & UPF_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+ retval = 0;
+ if (port->type == PORT_UNKNOWN)
+ goto exit;
+ if (info->flags & UIF_INITIALIZED) {
+ if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
+ old_custom_divisor != state->custom_divisor) {
+ uart_update_altspeed(info);
+ uart_change_speed(info, NULL);
+ }
+ } else
+ retval = uart_startup(info, 1);
+ exit:
+ up(&port_sem);
+ return retval;
+}
+
+
+/*
+ * uart_get_lsr_info - get line status register info
+ */
+static int uart_get_lsr_info(struct uart_info *info, unsigned int *value)
+{
+ struct uart_port *port = info->port;
+ unsigned int result;
+
+ result = port->ops->tx_empty(port);
+
+ /*
+ * If we're about to load something into the transmit
+ * register, we'll pretend the transmitter isn't empty to
+ * avoid a race condition (depending on when the transmit
+ * interrupt happens).
+ */
+ if (info->port->x_char ||
+ ((uart_circ_chars_pending(&info->xmit) > 0) &&
+ !info->tty->stopped && !info->tty->hw_stopped))
+ result &= ~TIOCSER_TEMT;
+
+ return put_user(result, value);
+}
+
+static int uart_get_modem_info(struct uart_port *port, unsigned int *value)
+{
+ unsigned int result = port->mctrl;
+
+ result |= port->ops->get_mctrl(port);
+
+ return put_user(result, value);
+}
+
+static int
+uart_set_modem_info(struct uart_port *port, unsigned int cmd,
+ unsigned int *value)
+{
+ unsigned int arg, set, clear;
+ int ret = 0;
+
+ if (get_user(arg, value))
+ return -EFAULT;
+
+ set = clear = 0;
+ switch (cmd) {
+ case TIOCMBIS:
+ set = arg;
+ break;
+ case TIOCMBIC:
+ clear = arg;
+ break;
+ case TIOCMSET:
+ set = arg;
+ clear = ~arg;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret == 0)
+ uart_update_mctrl(port, set, clear);
+ return ret;
+}
+
+static void uart_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct uart_info *info = tty->driver_data;
+ struct uart_port *port = info->port;
+
+ BUG_ON(!kernel_locked());
+
+ if (port->type != PORT_UNKNOWN)
+ port->ops->break_ctl(port, break_state);
+}
+
+static int uart_do_autoconfig(struct uart_info *info)
+{
+ struct uart_port *port = info->port;
+ int flags, ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ /*
+ * Take the 'count' lock. This prevents count
+ * from incrementing, and hence any extra opens
+ * of the port while we're auto-configging.
+ */
+ if (down_interruptible(&port_sem))
+ return -ERESTARTSYS;
+
+ ret = -EBUSY;
+ if (info->state->count == 1 && info->blocked_open == 0) {
+ uart_shutdown(info);
+
+ /*
+ * If we already have a port type configured,
+ * we must release its resources.
+ */
+ if (port->type != PORT_UNKNOWN)
+ port->ops->release_port(port);
+
+ flags = UART_CONFIG_TYPE;
+ if (port->flags & UPF_AUTO_IRQ)
+ flags |= UART_CONFIG_IRQ;
+
+ /*
+ * This will claim the ports resources if
+ * a port is found.
+ */
+ port->ops->config_port(port, flags);
+
+ ret = uart_startup(info, 1);
+ }
+ up(&port_sem);
+ return ret;
+}
+
+static int
+uart_wait_modem_status(struct uart_info *info, unsigned long arg)
+{
+ struct uart_port *port = info->port;
+ DECLARE_WAITQUEUE(wait, current);
+ struct uart_icount cprev, cnow;
+ int ret;
+
+ /*
+ * note the counters on entry
+ */
+ spin_lock_irq(&port->lock);
+ memcpy(&cprev, &port->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&port->lock);
+
+ /*
+ * Force modem status interrupts on
+ */
+ port->ops->enable_ms(port);
+
+ add_wait_queue(&info->delta_msr_wait, &wait);
+ for (;;) {
+ spin_lock_irq(&port->lock);
+ memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&port->lock);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ ret = 0;
+ break;
+ }
+
+ schedule();
+
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ cprev = cnow;
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->delta_msr_wait, &wait);
+
+ return ret;
+}
+
+/*
+ * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here.
+ */
+static int
+uart_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct uart_info *info = tty->driver_data;
+ struct serial_icounter_struct icount;
+ struct uart_icount cnow;
+ int ret = -ENOIOCTLCMD;
+
+ BUG_ON(!kernel_locked());
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+ (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TIOCMGET:
+ ret = uart_get_modem_info(info->port,
+ (unsigned int *)arg);
+ break;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ ret = uart_set_modem_info(info->port, cmd,
+ (unsigned int *)arg);
+ break;
+
+ case TIOCGSERIAL:
+ ret = uart_get_info(info, (struct serial_struct *)arg);
+ break;
+
+ case TIOCSSERIAL:
+ ret = uart_set_info(info, (struct serial_struct *)arg);
+ break;
+
+ case TIOCSERCONFIG:
+ ret = uart_do_autoconfig(info);
+ break;
+
+ case TIOCSERGETLSR: /* Get line status register */
+ ret = uart_get_lsr_info(info, (unsigned int *)arg);
+ break;
+
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ ret = uart_wait_modem_status(info, arg);
+ break;
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irq(&info->port->lock);
+ memcpy(&cnow, &info->port->icount,
+ sizeof(struct uart_icount));
+ spin_unlock_irq(&info->port->lock);
+
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ ret = copy_to_user((void *)arg, &icount, sizeof(icount))
+ ? -EFAULT : 0;
+ break;
+
+ case TIOCSERGWILD: /* obsolete */
+ case TIOCSERSWILD: /* obsolete */
+ ret = 0;
+ break;
+
+ default: {
+ struct uart_port *port = info->port;
+ if (port->ops->ioctl)
+ ret = port->ops->ioctl(port, cmd, arg);
+ break;
+ }
+ }
+ return ret;
+}
+
+static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct uart_info *info = tty->driver_data;
+ unsigned long flags;
+ unsigned int cflag = tty->termios->c_cflag;
+
+ BUG_ON(!kernel_locked());
+
+ /*
+ * These are the bits that are used to setup various
+ * flags in the low level driver.
+ */
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+ if ((cflag ^ old_termios->c_cflag) == 0 &&
+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ return;
+
+ uart_change_speed(info, old_termios);
+
+ /* Handle transition to B0 status */
+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+ uart_clear_mctrl(info->port, TIOCM_RTS | TIOCM_DTR);
+
+ /* Handle transition away from B0 status */
+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+ unsigned int mask = TIOCM_DTR;
+ if (!(cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags))
+ mask |= TIOCM_RTS;
+ uart_set_mctrl(info->port, mask);
+ }
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
+ spin_lock_irqsave(&info->port->lock, flags);
+ tty->hw_stopped = 0;
+ __uart_start(tty);
+ spin_unlock_irqrestore(&info->port->lock, flags);
+ }
+
+#if 0
+ /*
+ * No need to wake up processes in open wait, since they
+ * sample the CLOCAL flag once, and don't recheck it.
+ * XXX It's not clear whether the current behavior is correct
+ * or not. Hence, this may change.....
+ */
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * In 2.4.5, calls to this will be serialized via the BKL in
+ * linux/drivers/char/tty_io.c:tty_release()
+ * linux/drivers/char/tty_io.c:do_tty_handup()
+ */
+static void uart_close(struct tty_struct *tty, struct file *filp)
+{
+ struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state;
+ struct uart_info *info = tty->driver_data;
+ struct uart_port *port = info->port;
+ struct uart_state *state;
+ unsigned long flags;
+
+ BUG_ON(!kernel_locked());
+
+ if (!info)
+ return;
+
+ state = info->state;
+
+ DPRINTK("uart_close() called\n");
+
+ /*
+ * This is safe, as long as the BKL exists in
+ * do_tty_hangup(), and we're protected by the BKL.
+ */
+ if (tty_hung_up_p(filp))
+ goto done;
+
+ spin_lock_irqsave(&info->port->lock, flags);
+ if ((tty->count == 1) && (state->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. state->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("uart_close: bad serial port count; tty->count is 1, "
+ "state->count is %d\n", state->count);
+ state->count = 1;
+ }
+ if (--state->count < 0) {
+ printk("rs_close: bad serial port count for %s%d: %d\n",
+ tty->driver.name, info->port->line, state->count);
+ state->count = 0;
+ }
+ if (state->count) {
+ spin_unlock_irqrestore(&info->port->lock, flags);
+ goto done;
+ }
+
+ /*
+ * The UIF_CLOSING flag protects us against further opens
+ * of this port.
+ */
+ info->flags |= UIF_CLOSING;
+ spin_unlock_irqrestore(&info->port->lock, flags);
+
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->state->closing_wait != USF_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->state->closing_wait);
+
+ /*
+ * At this point, we stop accepting input. To do this, we
+ * disable the receive line status interrupts.
+ */
+ if (info->flags & UIF_INITIALIZED) {
+ port->ops->stop_rx(port);
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ uart_wait_until_sent(tty, port->timeout);
+ }
+ down(&port_sem);
+ uart_shutdown(info);
+ up(&port_sem);
+ uart_flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->state->close_delay) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(info->state->close_delay);
+ set_current_state(TASK_RUNNING);
+ }
+ } else {
+#ifdef CONFIG_PM
+ /*
+ * Put device into D3 state.
+ */
+ pm_send(info->state->pm, PM_SUSPEND, (void *)3);
+#else
+ if (port->ops->pm)
+ port->ops->pm(port, 3, 0);
+#endif
+ }
+
+ /*
+ * Wake up anyone trying to open this port.
+ */
+ info->flags &= ~(UIF_NORMAL_ACTIVE|UIF_CLOSING);
+ wake_up_interruptible(&info->open_wait);
+
+ done:
+ if (drv->owner)
+ __MOD_DEC_USE_COUNT(drv->owner);
+}
+
+static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct uart_info *info = tty->driver_data;
+ struct uart_port *port = info->port;
+ unsigned long char_time, expire;
+
+ BUG_ON(!kernel_locked());
+
+ if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+ return;
+
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (port->timeout - HZ/50) / port->fifosize;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout && timeout < char_time)
+ char_time = timeout;
+
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than port->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*port->timeout.
+ */
+ if (timeout == 0 || timeout > 2 * port->timeout)
+ timeout = 2 * port->timeout;
+
+ expire = jiffies + timeout;
+
+ DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+ port->line, jiffies, expire);
+
+ /*
+ * Check whether the transmitter is empty every 'char_time'.
+ * 'timeout' / 'expire' give us the maximum amount of time
+ * we wait.
+ */
+ while (!port->ops->tx_empty(port)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(char_time);
+ if (signal_pending(current))
+ break;
+ if (time_after(jiffies, expire))
+ break;
+ }
+ set_current_state(TASK_RUNNING); /* might not be needed */
+}
+
+/*
+ * This is called with the BKL held in
+ * linux/drivers/char/tty_io.c:do_tty_hangup()
+ * We're called from the eventd thread, so we can sleep for
+ * a _short_ time only.
+ */
+static void uart_hangup(struct tty_struct *tty)
+{
+ struct uart_info *info = tty->driver_data;
+ struct uart_state *state = info->state;
+
+ BUG_ON(!kernel_locked());
+
+ uart_flush_buffer(tty);
+ down(&port_sem);
+ if (info->flags & UIF_CLOSING) {
+ up(&port_sem);
+ return;
+ }
+ uart_shutdown(info);
+ info->event = 0;
+ state->count = 0;
+ info->flags &= ~UIF_NORMAL_ACTIVE;
+ info->tty = NULL;
+ up(&port_sem);
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * Copy across the serial console cflag setting into the termios settings
+ * for the initial open of the port. This allows continuity between the
+ * kernel settings, and the settings init adopts when it opens the port
+ * for the first time.
+ */
+static void uart_update_termios(struct uart_info *info)
+{
+ struct tty_struct *tty = info->tty;
+
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+ struct console *c = info->port->cons;
+
+ if (c && c->cflag && c->index == info->port->line) {
+ tty->termios->c_cflag = c->cflag;
+ c->cflag = 0;
+ }
+#endif
+
+ /*
+ * If the device failed to grab its irq resources,
+ * or some other error occurred, don't try to talk
+ * to the port hardware.
+ */
+ if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+ /*
+ * Make termios settings take effect.
+ */
+ uart_change_speed(info, NULL);
+
+ /*
+ * And finally enable the RTS and DTR signals.
+ */
+ if (tty->termios->c_cflag & CBAUD)
+ uart_set_mctrl(info->port, TIOCM_DTR | TIOCM_RTS);
+ }
+}
+
+static int
+uart_block_til_ready(struct file *filp, struct uart_info *info)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct uart_state *state = info->state;
+ struct uart_port *port = info->port;
+
+ info->blocked_open++;
+ state->count--;
+
+ add_wait_queue(&info->open_wait, &wait);
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /*
+ * If we have been hung up, tell userspace/restart open.
+ */
+ if (tty_hung_up_p(filp))
+ break;
+
+ /*
+ * If the device is in the middle of being closed, block
+ * until it's done. We will need to re-initialise the
+ * port. Hmm, is it legal to block a non-blocking open?
+ */
+ if (info->flags & UIF_CLOSING)
+ goto wait;
+
+ /*
+ * If the port has been closed, tell userspace/restart open.
+ */
+ if (!(info->flags & UIF_INITIALIZED))
+ break;
+
+ /*
+ * If non-blocking mode is set, or CLOCAL mode is set,
+ * we don't want to wait for the modem status lines to
+ * indicate that the port is ready.
+ *
+ * Also, if the port is not enabled/configured, we want
+ * to allow the open to succeed here. Note that we will
+ * have set TTY_IO_ERROR for a non-existant port.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (info->tty->termios->c_cflag & CLOCAL) ||
+ (info->tty->flags & (1 << TTY_IO_ERROR))) {
+ break;
+ }
+
+ /*
+ * Set DTR to allow modem to know we're waiting. Do
+ * not set RTS here - we want to make sure we catch
+ * the data from the modem.
+ */
+ if (info->tty->termios->c_cflag & CBAUD)
+ uart_set_mctrl(info->port, TIOCM_DTR);
+
+ /*
+ * and wait for the carrier to indicate that the
+ * modem is ready for us.
+ */
+ if (port->ops->get_mctrl(port) & TIOCM_CAR)
+ break;
+
+ wait:
+ schedule();
+
+ if (signal_pending(current))
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
+
+ state->count++;
+ info->blocked_open--;
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ if (tty_hung_up_p(filp) || !(info->flags & UIF_INITIALIZED))
+ return (port->flags & UPF_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS;
+
+ return 0;
+}
+
+static struct uart_info *uart_get(struct uart_driver *drv, int line)
+{
+ struct uart_state *state = drv->state + line;
+ struct uart_info *info = NULL;
+
+ down(&port_sem);
+ if (!state->port)
+ goto out;
+
+ state->count++;
+ info = state->info;
+
+ if (!info) {
+ info = kmalloc(sizeof(struct uart_info), GFP_KERNEL);
+ if (info) {
+ memset(info, 0, sizeof(struct uart_info));
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+
+ /*
+ * Link the info into the other structures.
+ */
+ info->port = state->port;
+ info->state = state;
+ state->port->info = info;
+
+ tasklet_init(&info->tlet, uart_tasklet_action,
+ (unsigned long)info);
+ state->info = info;
+ } else
+ state->count--;
+ }
+
+ out:
+ up(&port_sem);
+ return info;
+}
+
+/*
+ * In 2.4.5, calls to uart_open are serialised by the BKL in
+ * linux/fs/devices.c:chrdev_open()
+ * Note that if this fails, then uart_close() _will_ be called.
+ *
+ * In time, we want to scrap the "opening nonpresent ports"
+ * behaviour and implement an alternative way for setserial
+ * to set base addresses/ports/types. This will allow us to
+ * get rid of a certain amount of extra tests.
+ */
+static int uart_open(struct tty_struct *tty, struct file *filp)
+{
+ struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state;
+ struct uart_info *info;
+ int retval, line = minor(tty->device) - tty->driver.minor_start;
+
+ BUG_ON(!kernel_locked());
+
+ DPRINTK("uart_open(%d) called\n", line);
+
+ /*
+ * tty->driver.num won't change, so we won't fail here with
+ * tty->driver_data set to something non-NULL (and therefore
+ * we won't get caught by uart_close()).
+ */
+ retval = -ENODEV;
+ if (line >= tty->driver.num)
+ goto fail;
+
+ /*
+ * If we fail to increment the module use count, we can't have
+ * any other users of this tty (since this implies that the module
+ * is about to be unloaded). Therefore, it is safe to set
+ * tty->driver_data to be NULL, so uart_close() doesn't bite us.
+ */
+ if (!try_inc_mod_count(drv->owner)) {
+ tty->driver_data = NULL;
+ goto fail;
+ }
+
+ /*
+ * FIXME: This one isn't fun. We can't guarantee that the tty isn't
+ * already in open, nor can we guarantee the state of tty->driver_data
+ */
+ info = uart_get(drv, line);
+ retval = -ENOMEM;
+ if (!info) {
+ if (tty->driver_data)
+ goto fail;
+ else
+ goto out;
+ }
+
+ /*
+ * Once we set tty->driver_data here, we are guaranteed that
+ * uart_close() will decrement the driver module use count.
+ * Any failures from here onwards should not touch the count.
+ */
+ tty->driver_data = info;
+ info->tty = tty;
+ info->tty->low_latency = (info->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
+
+ /*
+ * If the port is in the middle of closing, bail out now.
+ */
+ if (tty_hung_up_p(filp) || (info->flags & UIF_CLOSING)) {
+ wait_event_interruptible(info->open_wait,
+ !(info->flags & UIF_CLOSING));
+ retval = (info->port->flags & UPF_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS;
+ goto fail;
+ }
+
+ /*
+ * Make sure the device is in D0 state.
+ */
+ if (info->state->count == 1) {
+#ifdef CONFIG_PM
+ pm_send(info->state->pm, PM_RESUME, (void *)0);
+#else
+ struct uart_port *port = info->port;
+ if (port->ops->pm)
+ port->ops->pm(port, 0, 3);
+#endif
+ }
+
+ /*
+ * Start up the serial port. We have this semaphore here to
+ * prevent uart_startup or uart_shutdown being re-entered if
+ * we sleep while requesting an IRQ.
+ */
+ down(&port_sem);
+ retval = uart_startup(info, 0);
+ up(&port_sem);
+ if (retval)
+ goto fail;
+
+ /*
+ * Wait until the port is ready.
+ */
+ retval = uart_block_til_ready(filp, info);
+
+ /*
+ * If this is the first open to succeed, adjust things to suit.
+ */
+ if (retval == 0 && !(info->flags & UIF_NORMAL_ACTIVE)) {
+ info->flags |= UIF_NORMAL_ACTIVE;
+
+ uart_update_termios(info);
+ }
+
+ return retval;
+
+ out:
+ if (drv->owner)
+ __MOD_DEC_USE_COUNT(drv->owner);
+ fail:
+ return retval;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static const char *uart_type(struct uart_port *port)
+{
+ const char *str = NULL;
+
+ if (port->ops->type)
+ str = port->ops->type(port);
+
+ if (!str)
+ str = "unknown";
+
+ return str;
+}
+
+static int uart_line_info(char *buf, struct uart_driver *drv, int i)
+{
+ struct uart_state *state = drv->state + i;
+ struct uart_port *port = state->port;
+ char stat_buf[32];
+ unsigned int status;
+ int ret;
+
+ if (!port)
+ return 0;
+
+ ret = sprintf(buf, "%d: uart:%s port:%08X irq:%d",
+ port->line, uart_type(port),
+ port->iobase, port->irq);
+
+ if (port->type == PORT_UNKNOWN) {
+ strcat(buf, "\n");
+ return ret + 1;
+ }
+
+ status = port->ops->get_mctrl(port);
+
+ ret += sprintf(buf + ret, " tx:%d rx:%d",
+ port->icount.tx, port->icount.rx);
+ if (port->icount.frame)
+ ret += sprintf(buf + ret, " fe:%d",
+ port->icount.frame);
+ if (port->icount.parity)
+ ret += sprintf(buf + ret, " pe:%d",
+ port->icount.parity);
+ if (port->icount.brk)
+ ret += sprintf(buf + ret, " brk:%d",
+ port->icount.brk);
+ if (port->icount.overrun)
+ ret += sprintf(buf + ret, " oe:%d",
+ port->icount.overrun);
+
+#define INFOBIT(bit,str) \
+ if (port->mctrl & (bit)) \
+ strncat(stat_buf, (str), sizeof(stat_buf) - \
+ strlen(stat_buf) - 2)
+#define STATBIT(bit,str) \
+ if (status & (bit)) \
+ strncat(stat_buf, (str), sizeof(stat_buf) - \
+ strlen(stat_buf) - 2)
+
+ stat_buf[0] = '\0';
+ stat_buf[1] = '\0';
+ INFOBIT(TIOCM_RTS, "|RTS");
+ STATBIT(TIOCM_CTS, "|CTS");
+ INFOBIT(TIOCM_DTR, "|DTR");
+ STATBIT(TIOCM_DSR, "|DSR");
+ STATBIT(TIOCM_CAR, "|CD");
+ STATBIT(TIOCM_RNG, "|RI");
+ if (stat_buf[0])
+ stat_buf[0] = ' ';
+ strcat(stat_buf, "\n");
+
+ ret += sprintf(buf + ret, stat_buf);
+ return ret;
+}
+
+static int uart_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct tty_driver *ttydrv = data;
+ struct uart_driver *drv = ttydrv->driver_state;
+ int i, len = 0, l;
+ off_t begin = 0;
+
+ len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+ "", "", "");
+ for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) {
+ l = uart_line_info(page + len, drv, i);
+ len += l;
+ if (len + begin > off + count)
+ goto done;
+ if (len + begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ *eof = 1;
+ done:
+ if (off >= len + begin)
+ return 0;
+ *start = page + (off - begin);
+ return (count < begin + len - off) ? count : (begin + len - off);
+}
+#endif
+
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+/*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+struct uart_port * __init
+uart_get_console(struct uart_port *ports, int nr, struct console *co)
+{
+ int idx = co->index;
+
+ if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
+ ports[idx].membase == NULL))
+ for (idx = 0; idx < nr; idx++)
+ if (ports[idx].iobase != 0 ||
+ ports[idx].membase != NULL)
+ break;
+
+ co->index = idx;
+
+ return ports + idx;
+}
+
+/**
+ * uart_parse_options - Parse serial port baud/parity/bits/flow contro.
+ * @options: pointer to option string
+ * @baud: pointer to an 'int' variable for the baud rate.
+ * @parity: pointer to an 'int' variable for the parity.
+ * @bits: pointer to an 'int' variable for the number of data bits.
+ * @flow: pointer to an 'int' variable for the flow control character.
+ *
+ * uart_parse_options decodes a string containing the serial console
+ * options. The format of the string is <baud><parity><bits><flow>,
+ * eg: 115200n8r
+ */
+void __init
+uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
+{
+ char *s = options;
+
+ *baud = simple_strtoul(s, NULL, 10);
+ while (*s >= '0' && *s <= '9')
+ s++;
+ if (*s)
+ *parity = *s++;
+ if (*s)
+ *bits = *s++ - '0';
+ if (*s)
+ *flow = *s;
+}
+
+struct baud_rates {
+ unsigned int rate;
+ unsigned int cflag;
+};
+
+static struct baud_rates baud_rates[] = {
+ { 921600, B921600 },
+ { 460800, B460800 },
+ { 230400, B230400 },
+ { 115200, B115200 },
+ { 57600, B57600 },
+ { 38400, B38400 },
+ { 19200, B19200 },
+ { 9600, B9600 },
+ { 4800, B4800 },
+ { 2400, B2400 },
+ { 1200, B1200 },
+ { 0, B38400 }
+};
+
+/**
+ * uart_set_options - setup the serial console parameters
+ * @port: pointer to the serial ports uart_port structure
+ * @co: console pointer
+ * @baud: baud rate
+ * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
+ * @bits: number of data bits
+ * @flow: flow control character - 'r' (rts)
+ */
+int __init
+uart_set_options(struct uart_port *port, struct console *co,
+ int baud, int parity, int bits, int flow)
+{
+ unsigned int cflag = CREAD | HUPCL | CLOCAL;
+ unsigned int quot;
+ int i;
+
+ /*
+ * Construct a cflag setting.
+ */
+ for (i = 0; baud_rates[i].rate; i++)
+ if (baud_rates[i].rate <= baud)
+ break;
+
+ cflag |= baud_rates[i].cflag;
+
+ if (bits == 7)
+ cflag |= CS7;
+ else
+ cflag |= CS8;
+
+ switch (parity) {
+ case 'o': case 'O':
+ cflag |= PARODD;
+ /*fall through*/
+ case 'e': case 'E':
+ cflag |= PARENB;
+ break;
+ }
+
+ if (flow == 'r')
+ cflag |= CRTSCTS;
+
+ co->cflag = cflag;
+ quot = (port->uartclk / (16 * baud));
+ port->ops->change_speed(port, cflag, 0, quot);
+
+ return 0;
+}
+
+extern void ambauart_console_init(void);
+extern void anakin_console_init(void);
+extern void clps711xuart_console_init(void);
+extern void rs285_console_init(void);
+extern void sa1100_rs_console_init(void);
+extern void serial8250_console_init(void);
+extern void uart00_console_init(void);
+
+/*
+ * Central "initialise all serial consoles" container. Needs to be killed.
+ */
+void __init uart_console_init(void)
+{
+#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+ ambauart_console_init();
+#endif
+#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE
+ anakin_console_init();
+#endif
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+ clps711xuart_console_init();
+#endif
+#ifdef CONFIG_SERIAL_21285_CONSOLE
+ rs285_console_init();
+#endif
+#ifdef CONFIG_SERIAL_SA1100_CONSOLE
+ sa1100_rs_console_init();
+#endif
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ serial8250_console_init();
+#endif
+#ifdef CONFIG_SERIAL_UART00_CONSOLE
+ uart00_console_init();
+#endif
+}
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+
+#ifdef CONFIG_PM
+/*
+ * Serial port power management.
+ *
+ * This is pretty coarse at the moment - either all on or all off. We
+ * should probably some day do finer power management here some day.
+ *
+ * We don't actually save any state; the serial driver already has the
+ * state held internally to re-setup the port when we come out of D3.
+ */
+static int uart_pm_set_state(struct uart_state *state, int pm_state, int oldstate)
+{
+ struct uart_port *port;
+ struct uart_ops *ops;
+ int running = state->info &&
+ state->info->flags & UIF_INITIALIZED;
+
+ down(&port_sem);
+
+ if (!state->port || state->port->type == PORT_UNKNOWN) {
+ up(&port_sem);
+ return 0;
+ }
+
+ port = state->port;
+ ops = port->ops;
+
+ DPRINTK("pm: %08x: %d -> %d, %srunning\n",
+ port->iobase, dev->state, pm_state, running ? "" : "not ");
+
+ if (pm_state == 0) {
+ if (ops->pm)
+ ops->pm(port, pm_state, oldstate);
+ if (running) {
+ /*
+ * The port lock isn't taken here -
+ * the port isn't initialised.
+ */
+ ops->set_mctrl(port, 0);
+ ops->startup(port);
+ uart_change_speed(state->info, NULL);
+ spin_lock_irq(&port->lock);
+ ops->set_mctrl(port, port->mctrl);
+ ops->start_tx(port, 0);
+ spin_unlock_irq(&port->lock);
+ }
+
+ /*
+ * Re-enable the console device after suspending.
+ */
+ if (port->cons && port->cons->index == port->line)
+ port->cons->flags |= CON_ENABLED;
+ } else if (pm_state == 1) {
+ if (ops->pm)
+ ops->pm(port, pm_state, oldstate);
+ } else {
+ /*
+ * Disable the console device before suspending.
+ */
+ if (port->cons && port->cons->index == port->line)
+ port->cons->flags &= ~CON_ENABLED;
+
+ if (running) {
+ ops->stop_tx(port, 0);
+ spin_lock_irq(&port->lock);
+ ops->set_mctrl(port, 0);
+ spin_unlock_irq(&port->lock);
+ ops->stop_rx(port);
+ ops->shutdown(port);
+ }
+ if (ops->pm)
+ ops->pm(port, pm_state, oldstate);
+ }
+ up(&port_sem);
+
+ return 0;
+}
+
+/*
+ * Wakeup support.
+ */
+static int uart_pm_set_wakeup(struct uart_state *state, int data)
+{
+ int err = 0;
+
+ if (state->port->ops->set_wake)
+ err = state->port->ops->set_wake(state->port, data);
+
+ return err;
+}
+
+static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ struct uart_state *state = dev->data;
+ int err = 0;
+
+ switch (rqst) {
+ case PM_SUSPEND:
+ case PM_RESUME:
+ err = uart_pm_set_state(state, (int)data, dev->state);
+ break;
+
+ case PM_SET_WAKEUP:
+ err = uart_pm_set_wakeup(state, (int)data);
+ break;
+ }
+ return err;
+}
+#endif
+
+static inline void
+uart_report_port(struct uart_driver *drv, struct uart_port *port)
+{
+ printk("%s%d at ", drv->dev_name, port->line);
+ switch (port->iotype) {
+ case UPIO_PORT:
+ printk("I/O 0x%x", port->iobase);
+ break;
+ case UPIO_HUB6:
+ printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+ break;
+ case UPIO_MEM:
+ printk("MMIO 0x%lx", port->mapbase);
+ break;
+ }
+ printk(" (irq = %d) is a %s\n", port->irq, uart_type(port));
+}
+
+static void
+__uart_register_port(struct uart_driver *drv, struct uart_state *state,
+ struct uart_port *port)
+{
+ unsigned int flags;
+
+ state->port = port;
+
+ spin_lock_init(&port->lock);
+ port->type = PORT_UNKNOWN;
+ port->cons = drv->cons;
+ port->info = state->info;
+
+ /*
+ * If there isn't a port here, don't do anything further.
+ */
+ if (!port->iobase && !port->mapbase)
+ return;
+
+ /*
+ * Now do the auto configuration stuff. Note that config_port
+ * is expected to claim the resources and map the port for us.
+ */
+ flags = UART_CONFIG_TYPE;
+ if (port->flags & UPF_AUTO_IRQ)
+ flags |= UART_CONFIG_IRQ;
+ if (port->flags & UPF_BOOT_AUTOCONF)
+ port->ops->config_port(port, flags);
+
+ /*
+ * Register the port whether it's detected or not. This allows
+ * setserial to be used to alter this ports parameters.
+ */
+ tty_register_devfs(drv->tty_driver, 0, drv->minor + port->line);
+
+ if (port->type != PORT_UNKNOWN) {
+ unsigned long flags;
+
+ uart_report_port(drv, port);
+
+ /*
+ * Ensure that the modem control lines are de-activated.
+ * We probably don't need a spinlock around this, but
+ */
+ spin_lock_irqsave(&port->lock, flags);
+ port->ops->set_mctrl(port, 0);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+#ifdef CONFIG_PM
+ /*
+ * Power down all ports by default, except the
+ * console if we have one. We need to drop the
+ * port semaphore here.
+ */
+ if (state->pm && (!drv->cons || port->line != drv->cons->index)) {
+ up(&port_sem);
+ pm_send(state->pm, PM_SUSPEND, (void *)3);
+ down(&port_sem);
+ }
+#endif
+ }
+}
+
+/*
+ * Hangup the port. This must be done outside the port_sem
+ * since uart_hangup() grabs this same semaphore. Grr.
+ */
+static void
+__uart_hangup_port(struct uart_driver *drv, struct uart_state *state)
+{
+ struct uart_info *info = state->info;
+
+ if (info && info->tty)
+ tty_vhangup(info->tty);
+}
+
+/*
+ * This reverses the affects of __uart_register_port.
+ */
+static void
+__uart_unregister_port(struct uart_driver *drv, struct uart_state *state)
+{
+ struct uart_port *port = state->port;
+ struct uart_info *info = state->info;
+
+ state->info = NULL;
+
+ /*
+ * Remove the devices from devfs
+ */
+ tty_unregister_devfs(drv->tty_driver, drv->minor + port->line);
+
+ /*
+ * Free the port IO and memory resources, if any.
+ */
+ if (port->type != PORT_UNKNOWN)
+ port->ops->release_port(port);
+
+ /*
+ * Indicate that there isn't a port here anymore.
+ */
+ port->type = PORT_UNKNOWN;
+
+ /*
+ * Kill the tasklet, and free resources.
+ */
+ if (info) {
+ tasklet_kill(&info->tlet);
+ kfree(info);
+ }
+}
+
+/**
+ * uart_register_driver - register a driver with the uart core layer
+ * @drv: low level driver structure
+ *
+ * Register a uart driver with the core driver. We in turn register
+ * with the tty layer, and initialise the core driver per-port state.
+ *
+ * We have a proc file in /proc/tty/driver which is named after the
+ * normal driver.
+ *
+ * drv->port should be NULL, and the per-port structures should be
+ * registered using uart_add_one_port after this call has succeeded.
+ */
+int uart_register_driver(struct uart_driver *drv)
+{
+ struct tty_driver *normal = NULL;
+ struct termios **termios = NULL;
+ int i, retval;
+
+ BUG_ON(drv->state);
+
+ /*
+ * Maybe we should be using a slab cache for this, especially if
+ * we have a large number of ports to handle. Note that we also
+ * allocate space for an integer for reference counting.
+ */
+ drv->state = kmalloc(sizeof(struct uart_state) * drv->nr +
+ sizeof(int), GFP_KERNEL);
+ retval = -ENOMEM;
+ if (!drv->state)
+ goto out;
+
+ memset(drv->state, 0, sizeof(struct uart_state) * drv->nr +
+ sizeof(int));
+
+ termios = kmalloc(sizeof(struct termios *) * drv->nr * 2 +
+ sizeof(struct tty_struct *) * drv->nr, GFP_KERNEL);
+ if (!termios)
+ goto out;
+
+ memset(termios, 0, sizeof(struct termios *) * drv->nr * 2 +
+ sizeof(struct tty_struct *) * drv->nr);
+
+ normal = kmalloc(sizeof(struct tty_driver), GFP_KERNEL);
+ if (!normal)
+ goto out;
+
+ memset(normal, 0, sizeof(struct tty_driver));
+
+ drv->tty_driver = normal;
+
+ normal->magic = TTY_DRIVER_MAGIC;
+ normal->driver_name = drv->driver_name;
+ normal->name = drv->dev_name;
+ normal->major = drv->major;
+ normal->minor_start = drv->minor;
+ normal->num = drv->nr;
+ normal->type = TTY_DRIVER_TYPE_SERIAL;
+ normal->subtype = SERIAL_TYPE_NORMAL;
+ normal->init_termios = tty_std_termios;
+ normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ normal->refcount = (int *)(drv->state + drv->nr);
+ normal->termios = termios;
+ normal->termios_locked = termios + drv->nr;
+ normal->table = (struct tty_struct **)(termios + drv->nr * 2);
+ normal->driver_state = drv;
+
+ normal->open = uart_open;
+ normal->close = uart_close;
+ normal->write = uart_write;
+ normal->put_char = uart_put_char;
+ normal->flush_chars = uart_flush_chars;
+ normal->write_room = uart_write_room;
+ normal->chars_in_buffer = uart_chars_in_buffer;
+ normal->flush_buffer = uart_flush_buffer;
+ normal->ioctl = uart_ioctl;
+ normal->throttle = uart_throttle;
+ normal->unthrottle = uart_unthrottle;
+ normal->send_xchar = uart_send_xchar;
+ normal->set_termios = uart_set_termios;
+ normal->stop = uart_stop;
+ normal->start = uart_start;
+ normal->hangup = uart_hangup;
+ normal->break_ctl = uart_break_ctl;
+ normal->wait_until_sent = uart_wait_until_sent;
+#ifdef CONFIG_PROC_FS
+ normal->read_proc = uart_read_proc;
+#endif
+
+ /*
+ * Initialise the UART state(s).
+ */
+ for (i = 0; i < drv->nr; i++) {
+ struct uart_state *state = drv->state + i;
+
+ state->close_delay = 5 * HZ / 10;
+ state->closing_wait = 30 * HZ;
+#ifdef CONFIG_PM
+ state->pm = pm_register(PM_SYS_DEV, PM_SYS_COM, uart_pm);
+ if (state->pm)
+ state->pm->data = state;
+#endif
+ }
+
+ retval = tty_register_driver(normal);
+ out:
+ if (retval < 0) {
+#ifdef CONFIG_PM
+ for (i = 0; i < drv->nr; i++)
+ pm_unregister(drv->state[i].pm);
+#endif
+ kfree(normal);
+ kfree(drv->state);
+ kfree(termios);
+ }
+ return retval;
+}
+
+/**
+ * uart_unregister_driver - remove a driver from the uart core layer
+ * @drv: low level driver structure
+ *
+ * Remove all references to a driver from the core driver. The low
+ * level driver must have removed all its ports via the
+ * uart_remove_one_port() if it registered them with uart_add_one_port().
+ * (ie, drv->port == NULL)
+ */
+void uart_unregister_driver(struct uart_driver *drv)
+{
+ int i;
+
+ for (i = 0; i < drv->nr; i++)
+ pm_unregister(drv->state[i].pm);
+
+ tty_unregister_driver(drv->tty_driver);
+
+ kfree(drv->state);
+ kfree(drv->tty_driver->termios);
+ kfree(drv->tty_driver);
+}
+
+/**
+ * uart_add_one_port - attach a driver-defined port structure
+ * @drv: pointer to the uart low level driver structure for this port
+ * @port: uart port structure to use for this port.
+ *
+ * This allows the driver to register its own uart_port structure
+ * with the core driver. The main purpose is to allow the low
+ * level uart drivers to expand uart_port, rather than having yet
+ * more levels of structures.
+ */
+int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
+{
+ struct uart_state *state;
+
+ BUG_ON(in_interrupt());
+
+ if (port->line >= drv->nr)
+ return -EINVAL;
+
+ state = drv->state + port->line;
+
+ down(&port_sem);
+ __uart_register_port(drv, state, port);
+ up(&port_sem);
+
+ return 0;
+}
+
+/**
+ * uart_remove_one_port - detach a driver defined port structure
+ * @drv: pointer to the uart low level driver structure for this port
+ * @port: uart port structure for this port
+ *
+ * This unhooks (and hangs up) the specified port structure from the
+ * core driver. No further calls will be made to the low-level code
+ * for this port.
+ */
+int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
+{
+ struct uart_state *state = drv->state + port->line;
+
+ BUG_ON(in_interrupt());
+
+ if (state->port != port)
+ printk(KERN_ALERT "Removing wrong port: %p != %p\n",
+ state->port, port);
+
+ __uart_hangup_port(drv, state);
+
+ down(&port_sem);
+ __uart_unregister_port(drv, state);
+ state->port = NULL;
+ up(&port_sem);
+
+ return 0;
+}
+
+/*
+ * Are the two ports equivalent?
+ */
+static int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+{
+ if (port1->iotype != port2->iotype)
+ return 0;
+
+ switch (port1->iotype) {
+ case UPIO_PORT:
+ return (port1->iobase == port2->iobase);
+ case UPIO_HUB6:
+ return (port1->iobase == port2->iobase) &&
+ (port1->hub6 == port2->hub6);
+ case UPIO_MEM:
+ return (port1->membase == port2->membase);
+ }
+ return 0;
+}
+
+/*
+ * Try to find an unused uart_state slot for a port.
+ */
+static struct uart_state *
+uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port)
+{
+ int i;
+
+ /*
+ * First, find a port entry which matches. Note: if we do
+ * find a matching entry, and it has a non-zero use count,
+ * then we can't register the port.
+ */
+ for (i = 0; i < drv->nr; i++)
+ if (uart_match_port(drv->state[i].port, port))
+ return &drv->state[i];
+
+ /*
+ * We didn't find a matching entry, so look for the first
+ * free entry. We look for one which hasn't been previously
+ * used (indicated by zero iobase).
+ */
+ for (i = 0; i < drv->nr; i++)
+ if (drv->state[i].port->type == PORT_UNKNOWN &&
+ drv->state[i].port->iobase == 0 &&
+ drv->state[i].count == 0)
+ return &drv->state[i];
+
+ /*
+ * That also failed. Last resort is to find any currently
+ * entry which doesn't have a real port associated with it.
+ */
+ for (i = 0; i < drv->nr; i++)
+ if (drv->state[i].port->type == PORT_UNKNOWN &&
+ drv->state[i].count == 0)
+ return &drv->state[i];
+
+ return NULL;
+}
+
+/**
+ * uart_register_port: register uart settings with a port
+ * @drv: pointer to the uart low level driver structure for this port
+ * @port: uart port structure describing the port
+ *
+ * Register UART settings with the specified low level driver. Detect
+ * the type of the port if UPF_BOOT_AUTOCONF is set, and detect the
+ * IRQ if UPF_AUTO_IRQ is set.
+ *
+ * We try to pick the same port for the same IO base address, so that
+ * when a modem is plugged in, unplugged and plugged back in, it gets
+ * allocated the same port.
+ *
+ * Returns negative error, or positive line number.
+ */
+int uart_register_port(struct uart_driver *drv, struct uart_port *port)
+{
+ struct uart_state *state;
+ int ret;
+
+ down(&port_sem);
+
+ state = uart_find_match_or_unused(drv, port);
+
+ if (state) {
+ /*
+ * Ok, we've found a line that we can use.
+ *
+ * If we find a port that matches this one, and it appears
+ * to be in-use (even if it doesn't have a type) we shouldn't
+ * alter it underneath itself - the port may be open and
+ * trying to do useful work.
+ */
+ if (state->count != 0 ||
+ (state->info && state->info->blocked_open != 0)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ state->port->iobase = port->iobase;
+ state->port->membase = port->membase;
+ state->port->irq = port->irq;
+ state->port->uartclk = port->uartclk;
+ state->port->fifosize = port->fifosize;
+ state->port->regshift = port->regshift;
+ state->port->iotype = port->iotype;
+ state->port->flags = port->flags;
+ state->port->line = drv->state - state;
+
+ __uart_register_port(drv, state, state->port);
+
+ ret = state->port->line;
+ } else
+ ret = -ENOSPC;
+ out:
+ up(&port_sem);
+ return ret;
+}
+
+/**
+ * uart_unregister_port - de-allocate a port
+ * @drv: pointer to the uart low level driver structure for this port
+ * @line: line index previously returned from uart_register_port()
+ *
+ * Hang up the specified line associated with the low level driver,
+ * and mark the port as unused.
+ */
+void uart_unregister_port(struct uart_driver *drv, int line)
+{
+ struct uart_state *state;
+
+ if (line < 0 || line >= drv->nr) {
+ printk(KERN_ERR "Attempt to unregister %s%d\n",
+ drv->dev_name, line);
+ return;
+ }
+
+ state = drv->state + line;
+
+ __uart_hangup_port(drv, state);
+
+ down(&port_sem);
+ __uart_unregister_port(drv, state);
+ up(&port_sem);
+}
+
+EXPORT_SYMBOL(uart_event);
+EXPORT_SYMBOL(uart_register_driver);
+EXPORT_SYMBOL(uart_unregister_driver);
+EXPORT_SYMBOL(uart_register_port);
+EXPORT_SYMBOL(uart_unregister_port);
+
+MODULE_DESCRIPTION("Serial driver core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_sa1100.c b/drivers/serial/serial_sa1100.c
new file mode 100644
index 000000000000..0f578fcdd757
--- /dev/null
+++ b/drivers/serial/serial_sa1100.c
@@ -0,0 +1,899 @@
+/*
+ * linux/drivers/char/serial_sa1100.c
+ *
+ * Driver for SA11x0 serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: serial_sa1100.c,v 1.41 2002/07/21 08:57:55 rmk Exp $
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/mach/serial_sa1100.h>
+
+#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_SA1100_MAJOR 204
+#define MINOR_START 5
+
+#define NR_PORTS 3
+
+#define SA1100_ISR_PASS_LIMIT 256
+
+/*
+ * Convert from ignore_status_mask or read_status_mask to UTSR[01]
+ */
+#define SM_TO_UTSR0(x) ((x) & 0xff)
+#define SM_TO_UTSR1(x) ((x) >> 8)
+#define UTSR0_TO_SM(x) ((x))
+#define UTSR1_TO_SM(x) ((x) << 8)
+
+#define UART_GET_UTCR0(sport) __raw_readl((sport)->port.membase + UTCR0)
+#define UART_GET_UTCR1(sport) __raw_readl((sport)->port.membase + UTCR1)
+#define UART_GET_UTCR2(sport) __raw_readl((sport)->port.membase + UTCR2)
+#define UART_GET_UTCR3(sport) __raw_readl((sport)->port.membase + UTCR3)
+#define UART_GET_UTSR0(sport) __raw_readl((sport)->port.membase + UTSR0)
+#define UART_GET_UTSR1(sport) __raw_readl((sport)->port.membase + UTSR1)
+#define UART_GET_CHAR(sport) __raw_readl((sport)->port.membase + UTDR)
+
+#define UART_PUT_UTCR0(sport,v) __raw_writel((v),(sport)->port.membase + UTCR0)
+#define UART_PUT_UTCR1(sport,v) __raw_writel((v),(sport)->port.membase + UTCR1)
+#define UART_PUT_UTCR2(sport,v) __raw_writel((v),(sport)->port.membase + UTCR2)
+#define UART_PUT_UTCR3(sport,v) __raw_writel((v),(sport)->port.membase + UTCR3)
+#define UART_PUT_UTSR0(sport,v) __raw_writel((v),(sport)->port.membase + UTSR0)
+#define UART_PUT_UTSR1(sport,v) __raw_writel((v),(sport)->port.membase + UTSR1)
+#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR)
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x24
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change. They generally aren't connected to an IRQ
+ * so we have to poll them. We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT (250*HZ/1000)
+
+struct sa1100_port {
+ struct uart_port port;
+ struct timer_list timer;
+ unsigned int old_status;
+};
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void sa1100_mctrl_check(struct sa1100_port *sport)
+{
+ unsigned int status, changed;
+
+ status = sport->port.ops->get_mctrl(&sport->port);
+ changed = status ^ sport->old_status;
+
+ if (changed == 0)
+ return;
+
+ sport->old_status = status;
+
+ if (changed & TIOCM_RI)
+ sport->port.icount.rng++;
+ if (changed & TIOCM_DSR)
+ sport->port.icount.dsr++;
+ if (changed & TIOCM_CAR)
+ uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+ if (changed & TIOCM_CTS)
+ uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+ wake_up_interruptible(&sport->port.info->delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void sa1100_timeout(unsigned long data)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)data;
+ unsigned long flags;
+
+ if (sport->port.info) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ sa1100_mctrl_check(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+ }
+}
+
+static void __sa1100_stop_tx(struct sa1100_port *sport)
+{
+ u32 utcr3;
+
+ utcr3 = UART_GET_UTCR3(sport);
+ UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE);
+ sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS);
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ __sa1100_stop_tx(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+/*
+ * interrupts may not be disabled on entry
+ */
+static void sa1100_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+ unsigned long flags;
+ u32 utcr3;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ utcr3 = UART_GET_UTCR3(sport);
+ sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
+ UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+/*
+ * Interrupts enabled
+ */
+static void sa1100_stop_rx(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+ unsigned long flags;
+ u32 utcr3;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ utcr3 = UART_GET_UTCR3(sport);
+ UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void sa1100_enable_ms(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+
+ mod_timer(&sport->timer, jiffies);
+}
+
+static void
+sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
+{
+ struct tty_struct *tty = sport->port.info->tty;
+ unsigned int status, ch, flg, ignored = 0;
+
+ status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
+ UTSR0_TO_SM(UART_GET_UTSR0(sport));
+ while (status & UTSR1_TO_SM(UTSR1_RNE)) {
+ ch = UART_GET_CHAR(sport);
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ sport->port.icount.rx++;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * note that the error handling code is
+ * out of the main execution path
+ */
+ if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR))
+ goto handle_error;
+
+ if (uart_handle_sysrq_char(&sport->port, ch, regs))
+ goto ignore_char;
+
+ error_return:
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ ignore_char:
+ status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
+ UTSR0_TO_SM(UART_GET_UTSR0(sport));
+ }
+ out:
+ tty_flip_buffer_push(tty);
+ return;
+
+ handle_error:
+ if (status & UTSR1_TO_SM(UTSR1_PRE))
+ sport->port.icount.parity++;
+ else if (status & UTSR1_TO_SM(UTSR1_FRE))
+ sport->port.icount.frame++;
+ if (status & UTSR1_TO_SM(UTSR1_ROR))
+ sport->port.icount.overrun++;
+
+ if (status & sport->port.ignore_status_mask) {
+ if (++ignored > 100)
+ goto out;
+ goto ignore_char;
+ }
+
+ status &= sport->port.read_status_mask;
+
+ if (status & UTSR1_TO_SM(UTSR1_PRE))
+ flg = TTY_PARITY;
+ else if (status & UTSR1_TO_SM(UTSR1_FRE))
+ flg = TTY_FRAME;
+
+ if (status & UTSR1_TO_SM(UTSR1_ROR)) {
+ /*
+ * overrun does *not* affect the character
+ * we read from the FIFO
+ */
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ ch = 0;
+ flg = TTY_OVERRUN;
+ }
+#ifdef SUPPORT_SYSRQ
+ sport->port.sysrq = 0;
+#endif
+ goto error_return;
+}
+
+static void sa1100_tx_chars(struct sa1100_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.info->xmit;
+
+ if (sport->port.x_char) {
+ UART_PUT_CHAR(sport, sport->port.x_char);
+ sport->port.icount.tx++;
+ sport->port.x_char = 0;
+ return;
+ }
+
+ /*
+ * Check the modem control lines before
+ * transmitting anything.
+ */
+ sa1100_mctrl_check(sport);
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+ __sa1100_stop_tx(sport);
+ return;
+ }
+
+ /*
+ * Tried using FIFO (not checking TNF) for fifo fill:
+ * still had the '4 bytes repeated' problem.
+ */
+ while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
+ UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(&sport->port, EVT_WRITE_WAKEUP);
+
+ if (uart_circ_empty(xmit))
+ __sa1100_stop_tx(sport);
+}
+
+static void sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct sa1100_port *sport = dev_id;
+ unsigned int status, pass_counter = 0;
+
+ spin_lock(&sport->port.lock);
+ status = UART_GET_UTSR0(sport);
+ status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
+ do {
+ if (status & (UTSR0_RFS | UTSR0_RID)) {
+ /* Clear the receiver idle bit, if set */
+ if (status & UTSR0_RID)
+ UART_PUT_UTSR0(sport, UTSR0_RID);
+ sa1100_rx_chars(sport, regs);
+ }
+
+ /* Clear the relevent break bits */
+ if (status & (UTSR0_RBB | UTSR0_REB))
+ UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB));
+
+ if (status & UTSR0_RBB)
+ sport->port.icount.brk++;
+
+ if (status & UTSR0_REB)
+ uart_handle_break(&sport->port);
+
+ if (status & UTSR0_TFS)
+ sa1100_tx_chars(sport);
+ if (pass_counter++ > SA1100_ISR_PASS_LIMIT)
+ break;
+ status = UART_GET_UTSR0(sport);
+ status &= SM_TO_UTSR0(sport->port.read_status_mask) |
+ ~UTSR0_TFS;
+ } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
+ spin_unlock(&sport->port.lock);
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int sa1100_tx_empty(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+
+ return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int sa1100_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void sa1100_break_ctl(struct uart_port *port, int break_state)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+ unsigned long flags;
+ unsigned int utcr3;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ utcr3 = UART_GET_UTCR3(sport);
+ if (break_state == -1)
+ utcr3 |= UTCR3_BRK;
+ else
+ utcr3 &= ~UTCR3_BRK;
+ UART_PUT_UTCR3(sport, utcr3);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int sa1100_startup(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+ int retval;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(sport->port.irq, sa1100_int, 0,
+ "serial_sa1100", sport);
+ if (retval)
+ return retval;
+
+ /*
+ * Finally, clear and enable interrupts
+ */
+ UART_PUT_UTSR0(sport, -1);
+ UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE);
+
+ /*
+ * Enable modem status interrupts
+ */
+ sa1100_enable_ms(&sport->port);
+
+ return 0;
+}
+
+static void sa1100_shutdown(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+
+ /*
+ * Stop our timer.
+ */
+ del_timer_sync(&sport->timer);
+
+ /*
+ * Free the interrupt
+ */
+ free_irq(sport->port.irq, sport);
+
+ /*
+ * Disable all interrupts, port and break condition.
+ */
+ UART_PUT_UTCR3(sport, 0);
+}
+
+static void
+sa1100_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+ unsigned long flags;
+ unsigned int utcr0, old_utcr3;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS7:
+ utcr0 = 0;
+ break;
+ default:
+ utcr0 = UTCR0_DSS;
+ break;
+ }
+ if (cflag & CSTOPB)
+ utcr0 |= UTCR0_SBS;
+ if (cflag & PARENB) {
+ utcr0 |= UTCR0_PE;
+ if (!(cflag & PARODD))
+ utcr0 |= UTCR0_OES;
+ }
+
+ sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
+ sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
+ if (iflag & INPCK)
+ sport->port.read_status_mask |=
+ UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
+ if (iflag & (BRKINT | PARMRK))
+ sport->port.read_status_mask |=
+ UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
+
+ /*
+ * Characters to ignore
+ */
+ sport->port.ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ sport->port.ignore_status_mask |=
+ UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
+ if (iflag & IGNBRK) {
+ sport->port.ignore_status_mask |=
+ UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ sport->port.ignore_status_mask |=
+ UTSR1_TO_SM(UTSR1_ROR);
+ }
+
+ del_timer_sync(&sport->timer);
+
+ /* first, disable interrupts and drain transmitter */
+ spin_lock_irqsave(&sport->port.lock, flags);
+ old_utcr3 = UART_GET_UTCR3(sport);
+ UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
+
+ while (UART_GET_UTSR1(sport) & UTSR1_TBY);
+
+ /* then, disable everything */
+ UART_PUT_UTCR3(sport, 0);
+
+ /* set the parity, stop bits and data size */
+ UART_PUT_UTCR0(sport, utcr0);
+
+ /* set the baud rate */
+ quot -= 1;
+ UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8));
+ UART_PUT_UTCR2(sport, (quot & 0xff));
+
+ UART_PUT_UTSR0(sport, -1);
+
+ UART_PUT_UTCR3(sport, old_utcr3);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ if (UART_ENABLE_MS(&sport->port, cflag))
+ sa1100_enable_ms(&sport->port);
+}
+
+static const char *sa1100_type(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+
+ return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void sa1100_release_port(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+
+ release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int sa1100_request_port(struct uart_port *port)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+
+ return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
+ "serial_sa1100") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void sa1100_config_port(struct uart_port *port, int flags)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+
+ if (flags & UART_CONFIG_TYPE &&
+ sa1100_request_port(&sport->port) == 0)
+ sport->port.type = PORT_SA1100;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_SA1100 and PORT_UNKNOWN
+ */
+static int
+sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ struct sa1100_port *sport = (struct sa1100_port *)port;
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
+ ret = -EINVAL;
+ if (sport->port.irq != ser->irq)
+ ret = -EINVAL;
+ if (ser->io_type != SERIAL_IO_MEM)
+ ret = -EINVAL;
+ if (sport->port.uartclk / 16 != ser->baud_base)
+ ret = -EINVAL;
+ if ((void *)sport->port.mapbase != ser->iomem_base)
+ ret = -EINVAL;
+ if (sport->port.iobase != ser->port)
+ ret = -EINVAL;
+ if (ser->hub6 != 0)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops sa1100_pops = {
+ tx_empty: sa1100_tx_empty,
+ set_mctrl: sa1100_set_mctrl,
+ get_mctrl: sa1100_get_mctrl,
+ stop_tx: sa1100_stop_tx,
+ start_tx: sa1100_start_tx,
+ stop_rx: sa1100_stop_rx,
+ enable_ms: sa1100_enable_ms,
+ break_ctl: sa1100_break_ctl,
+ startup: sa1100_startup,
+ shutdown: sa1100_shutdown,
+ change_speed: sa1100_change_speed,
+ type: sa1100_type,
+ release_port: sa1100_release_port,
+ request_port: sa1100_request_port,
+ config_port: sa1100_config_port,
+ verify_port: sa1100_verify_port,
+};
+
+static struct sa1100_port sa1100_ports[NR_PORTS];
+
+/*
+ * Setup the SA1100 serial ports. Note that we don't include the IrDA
+ * port here since we have our own SIR/FIR driver (see drivers/net/irda)
+ *
+ * Note also that we support "console=ttySAx" where "x" is either 0 or 1.
+ * Which serial port this ends up being depends on the machine you're
+ * running this kernel on. I'm not convinced that this is a good idea,
+ * but that's the way it traditionally works.
+ *
+ * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
+ * used here.
+ */
+static void __init sa1100_init_ports(void)
+{
+ static int first = 1;
+ int i;
+
+ if (!first)
+ return;
+ first = 0;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ sa1100_ports[i].port.uartclk = 3686400;
+ sa1100_ports[i].port.ops = &sa1100_pops;
+ sa1100_ports[i].port.fifosize = 8;
+ sa1100_ports[i].port.line = i;
+ sa1100_ports[i].port.iotype = SERIAL_IO_MEM;
+ init_timer(&sa1100_ports[i].timer);
+ sa1100_ports[i].timer.function = sa1100_timeout;
+ sa1100_ports[i].timer.data = (unsigned long)&sa1100_ports[i];
+ }
+
+ /*
+ * make transmit lines outputs, so that when the port
+ * is closed, the output is in the MARK state.
+ */
+ PPDR |= PPC_TXD1 | PPC_TXD3;
+ PPSR |= PPC_TXD1 | PPC_TXD3;
+}
+
+void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns)
+{
+ if (fns->get_mctrl)
+ sa1100_pops.get_mctrl = fns->get_mctrl;
+ if (fns->set_mctrl)
+ sa1100_pops.set_mctrl = fns->set_mctrl;
+
+ sa1100_pops.pm = fns->pm;
+ sa1100_pops.set_wake = fns->set_wake;
+}
+
+void __init sa1100_register_uart(int idx, int port)
+{
+ if (idx >= NR_PORTS) {
+ printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx);
+ return;
+ }
+
+ switch (port) {
+ case 1:
+ sa1100_ports[idx].port.membase = (void *)&Ser1UTCR0;
+ sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
+ sa1100_ports[idx].port.irq = IRQ_Ser1UART;
+ sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
+ break;
+
+ case 2:
+ sa1100_ports[idx].port.membase = (void *)&Ser2UTCR0;
+ sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
+ sa1100_ports[idx].port.irq = IRQ_Ser2ICP;
+ sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
+ break;
+
+ case 3:
+ sa1100_ports[idx].port.membase = (void *)&Ser3UTCR0;
+ sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
+ sa1100_ports[idx].port.irq = IRQ_Ser3UART;
+ sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
+ break;
+
+ default:
+ printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port);
+ }
+}
+
+
+#ifdef CONFIG_SERIAL_SA1100_CONSOLE
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+sa1100_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct sa1100_port *sport = &sa1100_ports[co->index];
+ unsigned int old_utcr3, status, i;
+
+ /*
+ * First, save UTCR3 and then disable interrupts
+ */
+ old_utcr3 = UART_GET_UTCR3(sport);
+ UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) |
+ UTCR3_TXE);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ do {
+ status = UART_GET_UTSR1(sport);
+ } while (!(status & UTSR1_TNF));
+ UART_PUT_CHAR(sport, s[i]);
+ if (s[i] == '\n') {
+ do {
+ status = UART_GET_UTSR1(sport);
+ } while (!(status & UTSR1_TNF));
+ UART_PUT_CHAR(sport, '\r');
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore UTCR3
+ */
+ do {
+ status = UART_GET_UTSR1(sport);
+ } while (status & UTSR1_TBY);
+ UART_PUT_UTCR3(sport, old_utcr3);
+}
+
+static kdev_t sa1100_console_device(struct console *co)
+{
+ return mk_kdev(SERIAL_SA1100_MAJOR, MINOR_START + co->index);
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+sa1100_console_get_options(struct sa1100_port *sport, int *baud,
+ int *parity, int *bits)
+{
+ unsigned int utcr3;
+
+ utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE);
+ if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) {
+ /* ok, the port was enabled */
+ unsigned int utcr0, quot;
+
+ utcr0 = UART_GET_UTCR0(sport);
+
+ *parity = 'n';
+ if (utcr0 & UTCR0_PE) {
+ if (utcr0 & UTCR0_OES)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ if (utcr0 & UTCR0_DSS)
+ *bits = 8;
+ else
+ *bits = 7;
+
+ quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8;
+ quot &= 0xfff;
+ *baud = sport->port.uartclk / (16 * (quot + 1));
+ }
+}
+
+static int __init
+sa1100_console_setup(struct console *co, char *options)
+{
+ struct sa1100_port *sport;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index == -1 || co->index >= NR_PORTS)
+ co->index = 0;
+ sport = &sa1100_ports[co->index];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ sa1100_console_get_options(sport, &baud, &parity, &bits);
+
+ return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct console sa1100_console = {
+ name: "ttySA",
+ write: sa1100_console_write,
+ device: sa1100_console_device,
+ setup: sa1100_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void __init sa1100_rs_console_init(void)
+{
+ sa1100_init_ports();
+ register_console(&sa1100_console);
+}
+
+#define SA1100_CONSOLE &sa1100_console
+#else
+#define SA1100_CONSOLE NULL
+#endif
+
+static struct uart_driver sa1100_reg = {
+ owner: THIS_MODULE,
+ driver_name: "ttySA",
+#ifdef CONFIG_DEVFS_FS
+ dev_name: "ttySA%d",
+#else
+ dev_name: "ttySA",
+#endif
+ major: SERIAL_SA1100_MAJOR,
+ minor: MINOR_START,
+ nr: NR_PORTS,
+ cons: SA1100_CONSOLE,
+};
+
+static int __init sa1100_serial_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: SA11x0 driver $Revision: 1.41 $\n");
+
+ sa1100_init_ports();
+ ret = uart_register_driver(&sa1100_reg);
+ if (ret == 0) {
+ int i;
+
+ for (i = 0; i < NR_PORTS; i++)
+ uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
+ }
+ return ret;
+}
+
+static void __exit sa1100_serial_exit(void)
+{
+ int i;
+
+ for (i = 0; i < NR_PORTS; i++)
+ uart_remove_one_port(&sa1100_reg, &sa1100_ports[i].port);
+
+ uart_unregister_driver(&sa1100_reg);
+}
+
+module_init(sa1100_serial_init);
+module_exit(sa1100_serial_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("Deep Blue Solutions Ltd");
+MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.41 $");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_uart00.c b/drivers/serial/serial_uart00.c
new file mode 100644
index 000000000000..e90c36f6ac97
--- /dev/null
+++ b/drivers/serial/serial_uart00.c
@@ -0,0 +1,778 @@
+/*
+ * linux/drivers/char/serial_uart00.c
+ *
+ * Driver for UART00 serial ports
+ *
+ * Based on drivers/char/serial_amba.c, by ARM Limited &
+ * Deep Blue Solutions Ltd.
+ * Copyright 2001 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: serial_uart00.c,v 1.32 2002/07/20 17:10:04 rmk Exp $
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/pld/pld_hotswap.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/sizes.h>
+
+#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include <asm/arch/excalibur.h>
+#define UART00_TYPE (volatile unsigned int*)
+#include <asm/arch/uart00.h>
+#include <asm/arch/int_ctrl00.h>
+
+#define UART_NR 2
+
+#define SERIAL_UART00_NAME "ttyUA"
+#define SERIAL_UART00_MAJOR 204
+#define SERIAL_UART00_MINOR 16 /* Temporary - will change in future */
+#define SERIAL_UART00_NR UART_NR
+#define UART_PORT_SIZE 0x50
+
+#define UART00_ISR_PASS_LIMIT 256
+
+/*
+ * Access macros for the UART00 UARTs
+ */
+#define UART_GET_INT_STATUS(p) inl(UART_ISR((p)->membase))
+#define UART_PUT_IES(p, c) outl(c,UART_IES((p)->membase))
+#define UART_GET_IES(p) inl(UART_IES((p)->membase))
+#define UART_PUT_IEC(p, c) outl(c,UART_IEC((p)->membase))
+#define UART_GET_IEC(p) inl(UART_IEC((p)->membase))
+#define UART_PUT_CHAR(p, c) outl(c,UART_TD((p)->membase))
+#define UART_GET_CHAR(p) inl(UART_RD((p)->membase))
+#define UART_GET_RSR(p) inl(UART_RSR((p)->membase))
+#define UART_GET_RDS(p) inl(UART_RDS((p)->membase))
+#define UART_GET_MSR(p) inl(UART_MSR((p)->membase))
+#define UART_GET_MCR(p) inl(UART_MCR((p)->membase))
+#define UART_PUT_MCR(p, c) outl(c,UART_MCR((p)->membase))
+#define UART_GET_MC(p) inl(UART_MC((p)->membase))
+#define UART_PUT_MC(p, c) outl(c,UART_MC((p)->membase))
+#define UART_GET_TSR(p) inl(UART_TSR((p)->membase))
+#define UART_GET_DIV_HI(p) inl(UART_DIV_HI((p)->membase))
+#define UART_PUT_DIV_HI(p,c) outl(c,UART_DIV_HI((p)->membase))
+#define UART_GET_DIV_LO(p) inl(UART_DIV_LO((p)->membase))
+#define UART_PUT_DIV_LO(p,c) outl(c,UART_DIV_LO((p)->membase))
+#define UART_RX_DATA(s) ((s) & UART_RSR_RX_LEVEL_MSK)
+#define UART_TX_READY(s) (((s) & UART_TSR_TX_LEVEL_MSK) < 15)
+//#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0)
+
+static void uart00_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+ UART_PUT_IEC(port, UART_IEC_TIE_MSK);
+}
+
+static void uart00_stop_rx(struct uart_port *port)
+{
+ UART_PUT_IEC(port, UART_IEC_RE_MSK);
+}
+
+static void uart00_enable_ms(struct uart_port *port)
+{
+ UART_PUT_IES(port, UART_IES_ME_MSK);
+}
+
+static void
+uart00_rx_chars(struct uart_port *port, struct pt_regs *regs)
+{
+ struct tty_struct *tty = port->info->tty;
+ unsigned int status, ch, rds, flg, ignored = 0;
+
+ status = UART_GET_RSR(port);
+ while (UART_RX_DATA(status)) {
+ /*
+ * We need to read rds before reading the
+ * character from the fifo
+ */
+ rds = UART_GET_RDS(port);
+ ch = UART_GET_CHAR(port);
+ port->icount.rx++;
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK|
+ UART_RDS_PE_MSK |UART_RDS_PE_MSK))
+ goto handle_error;
+ if (uart_handle_sysrq_char(port, ch, regs))
+ goto ignore_char;
+
+ error_return:
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ ignore_char:
+ status = UART_GET_RSR(port);
+ }
+ out:
+ tty_flip_buffer_push(tty);
+ return;
+
+ handle_error:
+ if (rds & UART_RDS_BI_MSK) {
+ status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK);
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ goto ignore_char;
+ } else if (rds & UART_RDS_PE_MSK)
+ port->icount.parity++;
+ else if (rds & UART_RDS_PE_MSK)
+ port->icount.frame++;
+ if (rds & UART_RDS_OE_MSK)
+ port->icount.overrun++;
+
+ if (rds & port->ignore_status_mask) {
+ if (++ignored > 100)
+ goto out;
+ goto ignore_char;
+ }
+ rds &= port->read_status_mask;
+
+ if (rds & UART_RDS_BI_MSK)
+ flg = TTY_BREAK;
+ else if (rds & UART_RDS_PE_MSK)
+ flg = TTY_PARITY;
+ else if (rds & UART_RDS_FE_MSK)
+ flg = TTY_FRAME;
+
+ if (status & UART_RDS_OE_MSK) {
+ /*
+ * CHECK: does overrun affect the current character?
+ * ASSUMPTION: it does not.
+ */
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ ch = 0;
+ flg = TTY_OVERRUN;
+ }
+#ifdef SUPPORT_SYSRQ
+ port->sysrq = 0;
+#endif
+ goto error_return;
+}
+
+static void uart00_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+ int count;
+
+ if (port->x_char) {
+ while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15);
+ UART_PUT_CHAR(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ uart00_stop_tx(port, 0);
+ return;
+ }
+
+ count = port->fifosize >> 1;
+ do {
+ while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15);
+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_event(port, EVT_WRITE_WAKEUP);
+
+ if (uart_circ_empty(xmit))
+ uart00_stop_tx(port, 0);
+}
+
+static void uart00_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+ UART_PUT_IES(port, UART_IES_TIE_MSK);
+ uart00_tx_chars(port);
+}
+
+static void uart00_modem_status(struct uart_port *port)
+{
+ unsigned int status;
+
+ status = UART_GET_MSR(port);
+
+ if (!status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK |
+ UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK))
+ return;
+
+ if (status & UART_MSR_DDCD_MSK)
+ uart_handle_dcd_change(port, status & UART_MSR_DCD_MSK);
+
+ if (status & UART_MSR_DDSR_MSK)
+ port->icount.dsr++;
+
+ if (status & UART_MSR_DCTS_MSK)
+ uart_handle_cts_change(port, status & UART_MSR_CTS_MSK);
+
+ wake_up_interruptible(&port->info->delta_msr_wait);
+}
+
+static void uart00_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = dev_id;
+ unsigned int status, pass_counter = 0;
+
+ status = UART_GET_INT_STATUS(port);
+ do {
+ if (status & UART_ISR_RI_MSK)
+ uart00_rx_chars(port, regs);
+ if (status & UART_ISR_MI_MSK)
+ uart00_modem_status(port);
+ if (status & (UART_ISR_TI_MSK | UART_ISR_TII_MSK))
+ uart00_tx_chars(port);
+ if (pass_counter++ > UART00_ISR_PASS_LIMIT)
+ break;
+
+ status = UART_GET_INT_STATUS(port);
+ } while (status);
+}
+
+static unsigned int uart00_tx_empty(struct uart_port *port)
+{
+ return UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int uart00_get_mctrl(struct uart_port *port)
+{
+ unsigned int result = 0;
+ unsigned int status;
+
+ status = UART_GET_MSR(port);
+ if (status & UART_MSR_DCD_MSK)
+ result |= TIOCM_CAR;
+ if (status & UART_MSR_DSR_MSK)
+ result |= TIOCM_DSR;
+ if (status & UART_MSR_CTS_MSK)
+ result |= TIOCM_CTS;
+ if (status & UART_MSR_RI_MSK)
+ result |= TIOCM_RI;
+
+ return result;
+}
+
+static void uart00_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void uart00_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+ unsigned int mcr;
+
+ spin_lock_irqsave(&port->lock, flags);
+ mcr = UART_GET_MCR(port);
+ if (break_state == -1)
+ mcr |= UART_MCR_BR_MSK;
+ else
+ mcr &= ~UART_MCR_BR_MSK;
+ UART_PUT_MCR(port, mcr);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+uart00_change_speed(struct uart_port *port, unsigned int cflag,
+ unsigned int iflag, unsigned int quot)
+{
+ unsigned int uart_mc, old_ies;
+ unsigned long flags;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ uart_mc = UART_MC_CLS_CHARLEN_5;
+ break;
+ case CS6:
+ uart_mc = UART_MC_CLS_CHARLEN_6;
+ break;
+ case CS7:
+ uart_mc = UART_MC_CLS_CHARLEN_7;
+ break;
+ default: // CS8
+ uart_mc = UART_MC_CLS_CHARLEN_8;
+ break;
+ }
+ if (cflag & CSTOPB)
+ uart_mc|= UART_MC_ST_TWO;
+ if (cflag & PARENB) {
+ uart_mc |= UART_MC_PE_MSK;
+ if (!(cflag & PARODD))
+ uart_mc |= UART_MC_EP_MSK;
+ }
+
+ port->read_status_mask = UART_RDS_OE_MSK;
+ if (iflag & INPCK)
+ port->read_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
+ if (iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= UART_RDS_BI_MSK;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
+ if (iflag & IGNBRK) {
+ port->ignore_status_mask |= UART_RDS_BI_MSK;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns to (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= UART_RDS_OE_MSK;
+ }
+
+ /* first, disable everything */
+ spin_lock_irqsave(&port->lock, flags);
+ old_ies = UART_GET_IES(port);
+
+ if (UART_ENABLE_MS(port, cflag))
+ old_ies |= UART_IES_ME_MSK;
+
+ /* Set baud rate */
+ UART_PUT_DIV_LO(port, (quot & 0xff));
+ UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
+
+ UART_PUT_MC(port, uart_mc);
+ UART_PUT_IES(port, old_ies);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int uart00_startup(struct uart_port *port)
+{
+ int result;
+
+ /*
+ * Allocate the IRQ
+ */
+ result = request_irq(port->irq, uart00_int, 0, "uart00", port);
+ if (result) {
+ printk(KERN_ERR "Request of irq %d failed\n", port->irq);
+ return result;
+ }
+
+ /*
+ * Finally, enable interrupts. Use the TII interrupt to minimise
+ * the number of interrupts generated. If higher performance is
+ * needed, consider using the TI interrupt with a suitable FIFO
+ * threshold
+ */
+ UART_PUT_IES(port, UART_IES_RE_MSK | UART_IES_TIE_MSK);
+
+ return 0;
+}
+
+static void uart00_shutdown(struct uart_port *port)
+{
+ /*
+ * disable all interrupts, disable the port
+ */
+ UART_PUT_IEC(port, 0xff);
+
+ /* disable break condition and fifos */
+ UART_PUT_MCR(port, UART_GET_MCR(port) &~UART_MCR_BR_MSK);
+
+ /*
+ * Free the interrupt
+ */
+ free_irq(port->irq, port);
+}
+
+static const char *uart00_type(struct uart_port *port)
+{
+ return port->type == PORT_UART00 ? "Altera UART00" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void uart00_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, UART_PORT_SIZE);
+
+#ifdef CONFIG_ARCH_CAMELOT
+ if (port->membase != (void*)IO_ADDRESS(EXC_UART00_BASE)) {
+ iounmap(port->membase);
+ }
+#endif
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int uart00_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_uart00")
+ != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void uart00_config_port(struct uart_port *port, int flags)
+{
+
+ /*
+ * Map the io memory if this is a soft uart
+ */
+ if (!port->membase)
+ port->membase = ioremap_nocache(port->mapbase,SZ_4K);
+
+ if (!port->membase)
+ printk(KERN_ERR "serial00: cannot map io memory\n");
+ else
+ port->type = PORT_UART00;
+
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int uart00_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops uart00_pops = {
+ tx_empty: uart00_tx_empty,
+ set_mctrl: uart00_set_mctrl_null,
+ get_mctrl: uart00_get_mctrl,
+ stop_tx: uart00_stop_tx,
+ start_tx: uart00_start_tx,
+ stop_rx: uart00_stop_rx,
+ enable_ms: uart00_enable_ms,
+ break_ctl: uart00_break_ctl,
+ startup: uart00_startup,
+ shutdown: uart00_shutdown,
+ change_speed: uart00_change_speed,
+ type: uart00_type,
+ release_port: uart00_release_port,
+ request_port: uart00_request_port,
+ config_port: uart00_config_port,
+ verify_port: uart00_verify_port,
+};
+
+
+#ifdef CONFIG_ARCH_CAMELOT
+static struct uart_port epxa10db_port = {
+ membase: (void*)IO_ADDRESS(EXC_UART00_BASE),
+ mapbase: EXC_UART00_BASE,
+ iotype: SERIAL_IO_MEM,
+ irq: IRQ_UART,
+ uartclk: EXC_AHB2_CLK_FREQUENCY,
+ fifosize: 16,
+ ops: &uart00_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+};
+#endif
+
+
+#ifdef CONFIG_SERIAL_UART00_CONSOLE
+static void uart00_console_write(struct console *co, const char *s, unsigned count)
+{
+#ifdef CONFIG_ARCH_CAMELOT
+ struct uart_port *port = &epxa10db_port;
+ unsigned int status, old_ies;
+ int i;
+
+ /*
+ * First save the CR then disable the interrupts
+ */
+ old_ies = UART_GET_IES(port);
+ UART_PUT_IEC(port,0xff);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ do {
+ status = UART_GET_TSR(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CHAR(port, s[i]);
+ if (s[i] == '\n') {
+ do {
+ status = UART_GET_TSR(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CHAR(port, '\r');
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the IES
+ */
+ do {
+ status = UART_GET_TSR(port);
+ } while (status & UART_TSR_TX_LEVEL_MSK);
+ UART_PUT_IES(port, old_ies);
+#endif
+}
+
+static kdev_t uart00_console_device(struct console *co)
+{
+ return mk_kdev(SERIAL_UART00_MAJOR, SERIAL_UART00_MINOR + co->index);
+}
+
+static void __init
+uart00_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ unsigned int uart_mc, quot;
+
+ uart_mc = UART_GET_MC(port);
+
+ *parity = 'n';
+ if (uart_mc & UART_MC_PE_MSK) {
+ if (uart_mc & UART_MC_EP_MSK)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ switch (uart_mc & UART_MC_CLS_MSK) {
+ case UART_MC_CLS_CHARLEN_5:
+ *bits = 5;
+ break;
+ case UART_MC_CLS_CHARLEN_6:
+ *bits = 6;
+ break;
+ case UART_MC_CLS_CHARLEN_7:
+ *bits = 7;
+ break;
+ case UART_MC_CLS_CHARLEN_8:
+ *bits = 8;
+ break;
+ }
+ quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
+ *baud = port->uartclk / (16 *quot );
+}
+
+static int __init uart00_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 38400;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+#ifdef CONFIG_ARCH_CAMELOT
+ port = &epxa10db_port; ;
+#else
+ return -ENODEV;
+#endif
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ uart00_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console uart00_console = {
+ name: SERIAL_UART00_NAME,
+ write: uart00_console_write,
+ device: uart00_console_device,
+ setup: uart00_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: 0,
+};
+
+void __init uart00_console_init(void)
+{
+ register_console(&uart00_console);
+}
+
+#define UART00_CONSOLE &uart00_console
+#else
+#define UART00_CONSOLE NULL
+#endif
+
+static struct uart_driver uart00_reg = {
+ owner: NULL,
+ driver_name: SERIAL_UART00_NAME,
+ dev_name: SERIAL_UART00_NAME,
+ major: SERIAL_UART00_MAJOR,
+ minor: SERIAL_UART00_MINOR,
+ nr: UART_NR,
+ cons: UART00_CONSOLE,
+};
+
+struct dev_port_entry{
+ unsigned int base_addr;
+ struct uart_port *port;
+};
+
+static struct dev_port_entry dev_port_map[UART_NR];
+
+#ifdef CONFIG_PLD_HOTSWAP
+/*
+ * Keep a mapping of dev_info addresses -> port lines to use when
+ * removing ports dev==NULL indicates unused entry
+ */
+
+struct uart00_ps_data{
+ unsigned int clk;
+ unsigned int fifosize;
+};
+
+int uart00_add_device(struct pldhs_dev_info* dev_info, void* dev_ps_data)
+{
+ struct uart00_ps_data* dev_ps=dev_ps_data;
+ struct uart_port * port;
+ int i,result;
+
+ i=0;
+ while(dev_port_map[i].port)
+ i++;
+
+ if(i==UART_NR){
+ printk(KERN_WARNING "uart00: Maximum number of ports reached\n");
+ return 0;
+ }
+
+ port=kmalloc(sizeof(struct uart_port),GFP_KERNEL);
+ if(!port)
+ return -ENOMEM;
+
+ printk("clk=%d fifo=%d\n",dev_ps->clk,dev_ps->fifosize);
+ port->membase=0;
+ port->mapbase=dev_info->base_addr;
+ port->iotype=SERIAL_IO_MEM;
+ port->irq=dev_info->irq;
+ port->uartclk=dev_ps->clk;
+ port->fifosize=dev_ps->fifosize;
+ port->ops=&uart00_pops;
+ port->line=i;
+ port->flags=ASYNC_BOOT_AUTOCONF;
+
+ result=uart_add_one_port(&uart00_reg, port);
+ if(result){
+ printk("uart_add_one_port returned %d\n",result);
+ return result;
+ }
+ dev_port_map[i].base_addr=dev_info->base_addr;
+ dev_port_map[i].port=port;
+ printk("uart00: added device at %x as ttyUA%d\n",dev_port_map[i].base_addr,i);
+ return 0;
+
+}
+
+int uart00_remove_devices(void)
+{
+ int i,result;
+
+
+ result=0;
+ for(i=1;i<UART_NR;i++){
+ if(dev_port_map[i].base_addr){
+ result=uart_remove_one_port(&uart00_reg, dev_port_map[i].port);
+ if(result)
+ return result;
+
+ /* port removed sucessfully, so now tidy up */
+ kfree(dev_port_map[i].port);
+ dev_port_map[i].base_addr=0;
+ dev_port_map[i].port=NULL;
+ }
+ }
+ return 0;
+
+}
+
+struct pld_hotswap_ops uart00_pldhs_ops={
+ name: "uart00",
+ add_device: uart00_add_device,
+ remove_devices:uart00_remove_devices,
+};
+
+#endif
+
+static int __init uart00_init(void)
+{
+ int result;
+
+ printk(KERN_INFO "Serial: UART00 driver $Revision: 1.32 $\n");
+
+ printk(KERN_WARNING "serial_uart00:Using temporary major/minor pairs"
+ " - these WILL change in the future\n");
+
+ result = uart_register_driver(&uart00_reg);
+ if (result)
+ return result;
+#ifdef CONFIG_ARCH_CAMELOT
+ result = uart_add_one_port(&uart00_reg,&epxa10db_port);
+#endif
+ if (result)
+ uart_unregister_driver(&uart00_reg);
+
+#ifdef CONFIG_PLD_HOTSWAP
+ pldhs_register_driver(&uart00_pldhs_ops);
+#endif
+ return result;
+}
+
+__initcall(uart00_init);
diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
index 65e4999ba5bf..07c5ea5b7e81 100644
--- a/drivers/usb/class/audio.c
+++ b/drivers/usb/class/audio.c
@@ -2091,11 +2091,11 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign
}
static /*const*/ struct file_operations usb_mixer_fops = {
- owner: THIS_MODULE,
- llseek: no_llseek,
- ioctl: usb_audio_ioctl_mixdev,
- open: usb_audio_open_mixdev,
- release: usb_audio_release_mixdev,
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = usb_audio_ioctl_mixdev,
+ .open = usb_audio_open_mixdev,
+ .release = usb_audio_release_mixdev,
};
/* --------------------------------------------------------------------- */
@@ -2727,15 +2727,15 @@ static int usb_audio_release(struct inode *inode, struct file *file)
}
static /*const*/ struct file_operations usb_audio_fops = {
- owner: THIS_MODULE,
- llseek: no_llseek,
- read: usb_audio_read,
- write: usb_audio_write,
- poll: usb_audio_poll,
- ioctl: usb_audio_ioctl,
- mmap: usb_audio_mmap,
- open: usb_audio_open,
- release: usb_audio_release,
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = usb_audio_read,
+ .write = usb_audio_write,
+ .poll = usb_audio_poll,
+ .ioctl = usb_audio_ioctl,
+ .mmap = usb_audio_mmap,
+ .open = usb_audio_open,
+ .release = usb_audio_release,
};
/* --------------------------------------------------------------------- */
@@ -2753,11 +2753,11 @@ static struct usb_device_id usb_audio_ids [] = {
MODULE_DEVICE_TABLE (usb, usb_audio_ids);
static struct usb_driver usb_audio_driver = {
- name: "audio",
- probe: usb_audio_probe,
- disconnect: usb_audio_disconnect,
- driver_list: LIST_HEAD_INIT(usb_audio_driver.driver_list),
- id_table: usb_audio_ids,
+ .name = "audio",
+ .probe = usb_audio_probe,
+ .disconnect = usb_audio_disconnect,
+ .driver_list = LIST_HEAD_INIT(usb_audio_driver.driver_list),
+ .id_table = usb_audio_ids,
};
static void *find_descriptor(void *descstart, unsigned int desclen, void *after,
diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
index a2ad9ef139c7..8fae68841bbf 100644
--- a/drivers/usb/class/bluetty.c
+++ b/drivers/usb/class/bluetty.c
@@ -234,10 +234,10 @@ static struct usb_device_id usb_bluetooth_ids [] = {
MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
static struct usb_driver usb_bluetooth_driver = {
- name: "bluetty",
- probe: usb_bluetooth_probe,
- disconnect: usb_bluetooth_disconnect,
- id_table: usb_bluetooth_ids,
+ .name = "bluetty",
+ .probe = usb_bluetooth_probe,
+ .disconnect = usb_bluetooth_disconnect,
+ .id_table = usb_bluetooth_ids,
};
static int bluetooth_refcount;
@@ -1284,30 +1284,30 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
static struct tty_driver bluetooth_tty_driver = {
- magic: TTY_DRIVER_MAGIC,
- driver_name: "usb-bluetooth",
- name: "usb/ttub/%d",
- major: BLUETOOTH_TTY_MAJOR,
- minor_start: 0,
- num: BLUETOOTH_TTY_MINORS,
- type: TTY_DRIVER_TYPE_SERIAL,
- subtype: SERIAL_TYPE_NORMAL,
- flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-
- refcount: &bluetooth_refcount,
- table: bluetooth_tty,
- termios: bluetooth_termios,
- termios_locked: bluetooth_termios_locked,
-
- open: bluetooth_open,
- close: bluetooth_close,
- write: bluetooth_write,
- write_room: bluetooth_write_room,
- ioctl: bluetooth_ioctl,
- set_termios: bluetooth_set_termios,
- throttle: bluetooth_throttle,
- unthrottle: bluetooth_unthrottle,
- chars_in_buffer: bluetooth_chars_in_buffer,
+ .magic = TTY_DRIVER_MAGIC,
+ .driver_name = "usb-bluetooth",
+ .name = "usb/ttub/%d",
+ .major = BLUETOOTH_TTY_MAJOR,
+ .minor_start = 0,
+ .num = BLUETOOTH_TTY_MINORS,
+ .type = TTY_DRIVER_TYPE_SERIAL,
+ .subtype = SERIAL_TYPE_NORMAL,
+ .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+ .refcount = &bluetooth_refcount,
+ .table = bluetooth_tty,
+ .termios = bluetooth_termios,
+ .termios_locked = bluetooth_termios_locked,
+
+ .open = bluetooth_open,
+ .close = bluetooth_close,
+ .write = bluetooth_write,
+ .write_room = bluetooth_write_room,
+ .ioctl = bluetooth_ioctl,
+ .set_termios = bluetooth_set_termios,
+ .throttle = bluetooth_throttle,
+ .unthrottle = bluetooth_unthrottle,
+ .chars_in_buffer = bluetooth_chars_in_buffer,
};
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 0e1d275b53b1..8fc07f6fb5d7 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -683,10 +683,10 @@ static struct usb_device_id acm_ids[] = {
MODULE_DEVICE_TABLE (usb, acm_ids);
static struct usb_driver acm_driver = {
- name: "acm",
- probe: acm_probe,
- disconnect: acm_disconnect,
- id_table: acm_ids,
+ .name = "acm",
+ .probe = acm_probe,
+ .disconnect = acm_disconnect,
+ .id_table = acm_ids,
};
/*
@@ -700,32 +700,32 @@ static struct termios *acm_tty_termios[ACM_TTY_MINORS];
static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
static struct tty_driver acm_tty_driver = {
- magic: TTY_DRIVER_MAGIC,
- driver_name: "acm",
- name: "usb/acm/%d",
- major: ACM_TTY_MAJOR,
- minor_start: 0,
- num: ACM_TTY_MINORS,
- type: TTY_DRIVER_TYPE_SERIAL,
- subtype: SERIAL_TYPE_NORMAL,
- flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-
- refcount: &acm_tty_refcount,
-
- table: acm_tty_table,
- termios: acm_tty_termios,
- termios_locked: acm_tty_termios_locked,
-
- open: acm_tty_open,
- close: acm_tty_close,
- write: acm_tty_write,
- write_room: acm_tty_write_room,
- ioctl: acm_tty_ioctl,
- throttle: acm_tty_throttle,
- unthrottle: acm_tty_unthrottle,
- chars_in_buffer: acm_tty_chars_in_buffer,
- break_ctl: acm_tty_break_ctl,
- set_termios: acm_tty_set_termios
+ .magic = TTY_DRIVER_MAGIC,
+ .driver_name = "acm",
+ .name = "usb/acm/%d",
+ .major = ACM_TTY_MAJOR,
+ .minor_start = 0,
+ .num = ACM_TTY_MINORS,
+ .type = TTY_DRIVER_TYPE_SERIAL,
+ .subtype = SERIAL_TYPE_NORMAL,
+ .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+ .refcount = &acm_tty_refcount,
+
+ .table = acm_tty_table,
+ .termios = acm_tty_termios,
+ .termios_locked = acm_tty_termios_locked,
+
+ .open = acm_tty_open,
+ .close = acm_tty_close,
+ .write = acm_tty_write,
+ .write_room = acm_tty_write_room,
+ .ioctl = acm_tty_ioctl,
+ .throttle = acm_tty_throttle,
+ .unthrottle = acm_tty_unthrottle,
+ .chars_in_buffer = acm_tty_chars_in_buffer,
+ .break_ctl = acm_tty_break_ctl,
+ .set_termios = acm_tty_set_termios
};
/*
diff --git a/drivers/usb/class/printer.c b/drivers/usb/class/printer.c
index cd9b52896fa5..b08c164dfd75 100644
--- a/drivers/usb/class/printer.c
+++ b/drivers/usb/class/printer.c
@@ -655,7 +655,10 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
(count - writecount) : USBLP_BUF_SIZE;
if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
- usblp->writeurb->transfer_buffer_length)) return -EFAULT;
+ usblp->writeurb->transfer_buffer_length)) {
+ up(&usblp->sem);
+ return writecount ? writecount : -EFAULT;
+ }
usblp->writeurb->dev = usblp->dev;
usblp->wcomplete = 0;
@@ -783,13 +786,13 @@ static unsigned int usblp_quirks (__u16 vendor, __u16 product)
}
static struct file_operations usblp_fops = {
- owner: THIS_MODULE,
- read: usblp_read,
- write: usblp_write,
- poll: usblp_poll,
- ioctl: usblp_ioctl,
- open: usblp_open,
- release: usblp_release,
+ .owner = THIS_MODULE,
+ .read = usblp_read,
+ .write = usblp_write,
+ .poll = usblp_poll,
+ .ioctl = usblp_ioctl,
+ .open = usblp_open,
+ .release = usblp_release,
};
static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
@@ -1097,11 +1100,11 @@ static struct usb_device_id usblp_ids [] = {
MODULE_DEVICE_TABLE (usb, usblp_ids);
static struct usb_driver usblp_driver = {
- owner: THIS_MODULE,
- name: "usblp",
- probe: usblp_probe,
- disconnect: usblp_disconnect,
- id_table: usblp_ids,
+ .owner = THIS_MODULE,
+ .name = "usblp",
+ .probe = usblp_probe,
+ .disconnect = usblp_disconnect,
+ .id_table = usblp_ids,
};
static int __init usblp_init(void)
diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
index 8aae77591839..cd35694b7d35 100644
--- a/drivers/usb/class/usb-midi.c
+++ b/drivers/usb/class/usb-midi.c
@@ -988,12 +988,12 @@ static int usb_midi_release(struct inode *inode, struct file *file)
}
static struct file_operations usb_midi_fops = {
- llseek: usb_midi_llseek,
- read: usb_midi_read,
- write: usb_midi_write,
- poll: usb_midi_poll,
- open: usb_midi_open,
- release: usb_midi_release,
+ .llseek = usb_midi_llseek,
+ .read = usb_midi_read,
+ .write = usb_midi_write,
+ .poll = usb_midi_poll,
+ .open = usb_midi_open,
+ .release = usb_midi_release,
};
/* ------------------------------------------------------------------------- */
@@ -2095,11 +2095,11 @@ static void usb_midi_disconnect(struct usb_device *dev, void *ptr)
static struct usb_driver usb_midi_driver = {
- name: "midi",
- probe: usb_midi_probe,
- disconnect: usb_midi_disconnect,
- id_table: NULL, /* check all devices */
- driver_list: LIST_HEAD_INIT(usb_midi_driver.driver_list)
+ .name = "midi",
+ .probe = usb_midi_probe,
+ .disconnect = usb_midi_disconnect,
+ .id_table = NULL, /* check all devices */
+ .driver_list = LIST_HEAD_INIT(usb_midi_driver.driver_list)
};
/* ------------------------------------------------------------------------- */
@@ -2168,15 +2168,15 @@ static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream,
static snd_rawmidi_ops_t snd_usbmidi_output =
{
- open: snd_usbmidi_output_open,
- close: snd_usbmidi_output_close,
- trigger: snd_usbmidi_output_trigger,
+ .open = snd_usbmidi_output_open,
+ .close = snd_usbmidi_output_close,
+ .trigger = snd_usbmidi_output_trigger,
};
static snd_rawmidi_ops_t snd_usbmidi_input =
{
- open: snd_usbmidi_input_open,
- close: snd_usbmidi_input_close,
- trigger: snd_usbmidi_input_trigger,
+ .open = snd_usbmidi_input_open,
+ .close = snd_usbmidi_input_close,
+ .trigger = snd_usbmidi_input_trigger,
};
int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
@@ -2211,7 +2211,7 @@ int snd_usbmidi_create( snd_card_t * card,
int err, idx;
snd_region_t *region;
static snd_device_opt_t ops = {
- dev_free: snd_usbmidi_dev_free,
+ .dev_free = snd_usbmidi_dev_free,
};
*rchip = NULL;
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index c15f5f4e60b2..e701a4975071 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -152,8 +152,8 @@ static const struct class_info clas_info[] =
void usbdevfs_conn_disc_event(void)
{
- wake_up(&deviceconndiscwq);
conndiscevcnt++;
+ wake_up(&deviceconndiscwq);
}
static const char *class_decode(const int class)
@@ -239,6 +239,7 @@ static char *usb_dump_interface_descriptor(char *start, char *end, const struct
if (start > end)
return start;
+ lock_kernel(); /* driver might be unloaded */
start += sprintf(start, format_iface,
desc->bInterfaceNumber,
desc->bAlternateSetting,
@@ -248,6 +249,7 @@ static char *usb_dump_interface_descriptor(char *start, char *end, const struct
desc->bInterfaceSubClass,
desc->bInterfaceProtocol,
iface->driver ? iface->driver->name : "(none)");
+ unlock_kernel();
return start;
}
@@ -597,6 +599,13 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
unlock_kernel();
return POLLIN;
}
+
+ /* we may have dropped BKL - need to check for having lost the race */
+ if (file->private_data) {
+ kfree(st);
+ goto lost_race;
+ }
+
/*
* need to prevent the module from being unloaded, since
* proc_unregister does not call the release method and
@@ -606,6 +615,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
file->private_data = st;
mask = POLLIN;
}
+lost_race:
if (file->f_mode & FMODE_READ)
poll_wait(file, &deviceconndiscwq, wait);
if (st->lastev != conndiscevcnt)
@@ -656,9 +666,9 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
}
struct file_operations usbdevfs_devices_fops = {
- llseek: usb_device_lseek,
- read: usb_device_read,
- poll: usb_device_poll,
- open: usb_device_open,
- release: usb_device_release,
+ .llseek = usb_device_lseek,
+ .read = usb_device_read,
+ .poll = usb_device_poll,
+ .open = usb_device_open,
+ .release = usb_device_release,
};
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index b7c95b292a48..e80a3ed170f8 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -324,9 +324,9 @@ static void driver_disconnect(struct usb_device *dev, void *context)
}
struct usb_driver usbdevfs_driver = {
- name: "usbfs",
- probe: driver_probe,
- disconnect: driver_disconnect,
+ .name = "usbfs",
+ .probe = driver_probe,
+ .disconnect = driver_disconnect,
};
static int claimintf(struct dev_state *ps, unsigned int intf)
@@ -361,14 +361,14 @@ static int releaseintf(struct dev_state *ps, unsigned int intf)
if (intf >= 8*sizeof(ps->ifclaimed))
return -EINVAL;
err = -EINVAL;
- lock_kernel();
dev = ps->dev;
+ down(&dev->serialize);
if (dev && test_and_clear_bit(intf, &ps->ifclaimed)) {
iface = &dev->actconfig->interface[intf];
usb_driver_release_interface(&usbdevfs_driver, iface);
err = 0;
}
- unlock_kernel();
+ up(&dev->serialize);
return err;
}
@@ -722,14 +722,11 @@ static int proc_resetdevice(struct dev_state *ps)
if (test_bit(i, &ps->ifclaimed))
continue;
- if (intf->driver) {
- const struct usb_device_id *id;
- down(&intf->driver->serialize);
- intf->driver->disconnect(ps->dev, intf->private_data);
- id = usb_match_id(ps->dev,intf,intf->driver->id_table);
- intf->driver->probe(ps->dev, i, id);
- up(&intf->driver->serialize);
+ lock_kernel();
+ if (intf->driver && ps->dev) {
+ usb_bind_driver(intf->driver,ps->dev, i);
}
+ unlock_kernel();
}
return 0;
@@ -1092,16 +1089,17 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
/* disconnect kernel driver from interface, leaving it unbound. */
case USBDEVFS_DISCONNECT:
+ /* this function is voodoo. without locking it is a maybe thing */
+ lock_kernel();
driver = ifp->driver;
if (driver) {
- down (&driver->serialize);
dbg ("disconnect '%s' from dev %d interface %d",
driver->name, ps->dev->devnum, ctrl.ifno);
- driver->disconnect (ps->dev, ifp->private_data);
+ usb_unbind_driver(ps->dev, ifp);
usb_driver_release_interface (driver, ifp);
- up (&driver->serialize);
} else
retval = -EINVAL;
+ unlock_kernel();
break;
/* let kernel drivers try to (re)bind to the interface */
@@ -1111,18 +1109,28 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
/* talk directly to the interface's driver */
default:
+ lock_kernel(); /* against module unload */
driver = ifp->driver;
- if (driver == 0 || driver->ioctl == 0)
- retval = -ENOSYS;
- else {
- if (ifp->driver->owner)
+ if (driver == 0 || driver->ioctl == 0) {
+ unlock_kernel();
+ retval = -ENOSYS;
+ } else {
+ if (ifp->driver->owner) {
__MOD_INC_USE_COUNT(ifp->driver->owner);
+ unlock_kernel();
+ }
/* ifno might usefully be passed ... */
retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
/* size = min_t(int, size, retval)? */
- if (ifp->driver->owner)
+ if (ifp->driver->owner) {
__MOD_DEC_USE_COUNT(ifp->driver->owner);
+ } else {
+ unlock_kernel();
+ }
}
+
+ if (retval == -ENOIOCTLCMD)
+ retval = -ENOTTY;
}
/* cleanup and return */
@@ -1139,7 +1147,7 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
@@ -1248,10 +1256,10 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
}
struct file_operations usbdevfs_device_file_operations = {
- llseek: usbdev_lseek,
- read: usbdev_read,
- poll: usbdev_poll,
- ioctl: usbdev_ioctl,
- open: usbdev_open,
- release: usbdev_release,
+ .llseek = usbdev_lseek,
+ .read = usbdev_read,
+ .poll = usbdev_poll,
+ .ioctl = usbdev_ioctl,
+ .open = usbdev_open,
+ .release = usbdev_release,
};
diff --git a/drivers/usb/core/drivers.c b/drivers/usb/core/drivers.c
index 3419792c7fb6..22dc21354868 100644
--- a/drivers/usb/core/drivers.c
+++ b/drivers/usb/core/drivers.c
@@ -66,6 +66,7 @@ static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff
start = page;
end = page + (PAGE_SIZE - 100);
pos = *ppos;
+ lock_kernel(); /* else drivers might be unloaded */
for (; tmp != &usb_driver_list; tmp = tmp->next) {
struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
int minor = driver->fops ? driver->minor : -1;
@@ -80,6 +81,7 @@ static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff
break;
}
}
+ unlock_kernel();
if (start == page)
start += sprintf(start, "(none)\n");
len = start - page;
@@ -120,6 +122,6 @@ static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig)
}
struct file_operations usbdevfs_drivers_fops = {
- llseek: usb_driver_lseek,
- read: usb_driver_read,
+ .llseek = usb_driver_lseek,
+ .read = usb_driver_read,
};
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index eba43f1d84e5..803fb19e5ad2 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -44,10 +44,13 @@ static int usb_open(struct inode * inode, struct file * file)
spin_lock (&minor_lock);
c = usb_minors[minor];
- spin_unlock (&minor_lock);
- if (!c || !(new_fops = fops_get(c)))
+ if (!c || !(new_fops = fops_get(c))) {
+ spin_unlock(&minor_lock);
return err;
+ }
+ spin_unlock(&minor_lock);
+
old_fops = file->f_op;
file->f_op = new_fops;
/* Curiouser and curiouser... NULL ->open() as "no device" ? */
@@ -62,8 +65,8 @@ static int usb_open(struct inode * inode, struct file * file)
}
static struct file_operations usb_fops = {
- owner: THIS_MODULE,
- open: usb_open,
+ .owner = THIS_MODULE,
+ .open = usb_open,
};
int usb_major_init(void)
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 15a2c346b4af..05bb930ea5fd 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1240,11 +1240,11 @@ static int hcd_free_dev (struct usb_device *udev)
* bus glue for non-PCI system busses will need to use this.
*/
struct usb_operations usb_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,
+ .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,
};
EXPORT_SYMBOL (usb_hcd_operations);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ad1422fabdfa..f80a98621d26 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1046,8 +1046,6 @@ static void usb_hub_events(void)
static int usb_hub_thread(void *__hub)
{
- lock_kernel();
-
/*
* This thread doesn't need any user-level access,
* so get rid of all our resources
@@ -1067,8 +1065,6 @@ static int usb_hub_thread(void *__hub)
} while (!signal_pending(current));
dbg("usb_hub_thread exiting");
-
- unlock_kernel();
complete_and_exit(&khubd_exited, 0);
}
@@ -1083,11 +1079,11 @@ static struct usb_device_id hub_id_table [] = {
MODULE_DEVICE_TABLE (usb, hub_id_table);
static struct usb_driver hub_driver = {
- name: "hub",
- probe: hub_probe,
- ioctl: hub_ioctl,
- disconnect: hub_disconnect,
- id_table: hub_id_table,
+ .name = "hub",
+ .probe = hub_probe,
+ .ioctl = hub_ioctl,
+ .disconnect = hub_disconnect,
+ .id_table = hub_id_table,
};
/*
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 08d08e3516e8..ffb7e6e13284 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -284,23 +284,23 @@ static int default_open (struct inode *inode, struct file *filp)
}
static struct file_operations default_file_operations = {
- read: default_read_file,
- write: default_write_file,
- open: default_open,
- llseek: default_file_lseek,
+ .read = default_read_file,
+ .write = default_write_file,
+ .open = default_open,
+ .llseek = default_file_lseek,
};
static struct inode_operations usbfs_dir_inode_operations = {
- create: usbfs_create,
- lookup: simple_lookup,
- unlink: usbfs_unlink,
- mkdir: usbfs_mkdir,
- rmdir: usbfs_rmdir,
+ .create = usbfs_create,
+ .lookup = simple_lookup,
+ .unlink = usbfs_unlink,
+ .mkdir = usbfs_mkdir,
+ .rmdir = usbfs_rmdir,
};
static struct super_operations usbfs_ops = {
- statfs: simple_statfs,
- drop_inode: generic_delete_inode,
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
};
static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
@@ -468,17 +468,17 @@ static struct super_block *usb_get_sb(struct file_system_type *fs_type,
}
static struct file_system_type usbdevice_fs_type = {
- owner: THIS_MODULE,
- name: "usbdevfs",
- get_sb: usb_get_sb,
- kill_sb: kill_anon_super,
+ .owner = THIS_MODULE,
+ .name = "usbdevfs",
+ .get_sb = usb_get_sb,
+ .kill_sb = kill_anon_super,
};
static struct file_system_type usb_fs_type = {
- owner: THIS_MODULE,
- name: "usbfs",
- get_sb: usb_get_sb,
- kill_sb: kill_anon_super,
+ .owner = THIS_MODULE,
+ .name = "usbfs",
+ .get_sb = usb_get_sb,
+ .kill_sb = kill_anon_super,
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 55c9e8955d24..ed2e03089e57 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -32,6 +32,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
+#include <linux/smp_lock.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
@@ -117,6 +118,108 @@ void usb_scan_devices(void)
up (&usb_bus_list_lock);
}
+/**
+ * usb_unbind_driver - disconnects a driver from a device
+ * @device: usb device to be disconnected
+ * @intf: interface of the device to be disconnected
+ * Context: BKL held
+ *
+ * Handles module usage count correctly
+ */
+
+void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf)
+{
+ struct usb_driver *driver;
+ void *priv;
+ int m;
+
+
+ driver = intf->driver;
+ priv = intf->private_data;
+
+ if (!driver)
+ return;
+
+ /* as soon as we increase the module use count we drop the BKL
+ before that we must not sleep */
+ if (driver->owner) {
+ m = try_inc_mod_count(driver->owner);
+ if (m == 0) {
+ err("Dieing driver still bound to device.\n");
+ return;
+ }
+ unlock_kernel();
+ }
+ down(&driver->serialize); /* if we sleep here on an umanaged driver
+ the holder of the lock guards against
+ module unload */
+
+ driver->disconnect(device, priv);
+
+ up(&driver->serialize);
+ if (driver->owner) {
+ lock_kernel();
+ __MOD_DEC_USE_COUNT(driver->owner);
+ }
+}
+
+/**
+ * usb_bind_driver - connect a driver to a device's interface
+ * @driver: device driver to be bound to a devices interface
+ * @dev: device to be bound
+ * @ifnum: index number of the interface to be used
+ *
+ * Does a save binding of a driver to a device's interface
+ * Returns a pointer to the drivers private description of the binding
+ */
+
+void *usb_bind_driver(struct usb_driver *driver, struct usb_device *dev, unsigned int ifnum)
+{
+ int i,m;
+ void *private = NULL;
+ const struct usb_device_id *id;
+ struct usb_interface *interface;
+
+ if (driver->owner) {
+ m = try_inc_mod_count(driver->owner);
+ if (m == 0)
+ return NULL; /* this horse is dead - don't ride*/
+ unlock_kernel();
+ }
+
+ interface = &dev->actconfig->interface[ifnum];
+
+ id = driver->id_table;
+ /* new style driver? */
+ if (id) {
+ for (i = 0; i < interface->num_altsetting; i++) {
+ interface->act_altsetting = i;
+ id = usb_match_id(dev, interface, id);
+ if (id) {
+ down(&driver->serialize);
+ private = driver->probe(dev,ifnum,id);
+ up(&driver->serialize);
+ if (private != NULL)
+ break;
+ }
+ }
+
+ /* if driver not bound, leave defaults unchanged */
+ if (private == NULL)
+ interface->act_altsetting = 0;
+ } else { /* "old style" driver */
+ down(&driver->serialize);
+ private = driver->probe(dev, ifnum, NULL);
+ up(&driver->serialize);
+ }
+ if (driver->owner) {
+ lock_kernel();
+ __MOD_DEC_USE_COUNT(driver->owner);
+ }
+
+ return private;
+}
+
/*
* This function is part of a depth-first search down the device tree,
* removing any instances of a device driver.
@@ -136,18 +239,12 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
if (!dev->actconfig)
return;
-
+
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
-
+
if (interface->driver == driver) {
- if (driver->owner)
- __MOD_INC_USE_COUNT(driver->owner);
- down(&driver->serialize);
- driver->disconnect(dev, interface->private_data);
- up(&driver->serialize);
- if (driver->owner)
- __MOD_DEC_USE_COUNT(driver->owner);
+ usb_unbind_driver(dev, interface);
/* if driver->disconnect didn't release the interface */
if (interface->driver)
usb_driver_release_interface(driver, interface);
@@ -163,7 +260,7 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
/**
* usb_deregister - unregister a USB driver
* @driver: USB operations of the driver to unregister
- * Context: !in_interrupt ()
+ * Context: !in_interrupt (), must be called with BKL held
*
* Unlinks the specified driver from the internal USB driver list.
*
@@ -528,9 +625,7 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
struct list_head *tmp;
struct usb_interface *interface;
void *private;
- const struct usb_device_id *id;
struct usb_driver *driver;
- int i;
if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
err("bad find_interface_driver params");
@@ -545,37 +640,12 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
goto out_err;
private = NULL;
+ lock_kernel();
for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) {
driver = list_entry(tmp, struct usb_driver, driver_list);
tmp = tmp->next;
- if (driver->owner)
- __MOD_INC_USE_COUNT(driver->owner);
- id = driver->id_table;
- /* new style driver? */
- if (id) {
- for (i = 0; i < interface->num_altsetting; i++) {
- interface->act_altsetting = i;
- id = usb_match_id(dev, interface, id);
- if (id) {
- down(&driver->serialize);
- private = driver->probe(dev,ifnum,id);
- up(&driver->serialize);
- if (private != NULL)
- break;
- }
- }
-
- /* if driver not bound, leave defaults unchanged */
- if (private == NULL)
- interface->act_altsetting = 0;
- } else { /* "old style" driver */
- down(&driver->serialize);
- private = driver->probe(dev, ifnum, NULL);
- up(&driver->serialize);
- }
- if (driver->owner)
- __MOD_DEC_USE_COUNT(driver->owner);
+ private = usb_bind_driver(driver, dev, ifnum);
/* probe() may have changed the config on us */
interface = dev->actconfig->interface + ifnum;
@@ -583,9 +653,11 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
if (private) {
usb_driver_claim_interface(driver, interface, private);
up(&dev->serialize);
+ unlock_kernel();
return 0;
}
}
+ unlock_kernel();
out_err:
up(&dev->serialize);
@@ -764,9 +836,9 @@ show_config (struct device *dev, char *buf, size_t count, loff_t off)
return sprintf (buf, "%u\n", udev->actconfig->bConfigurationValue);
}
static struct driver_file_entry usb_config_entry = {
- name: "configuration",
- mode: S_IRUGO,
- show: show_config,
+ .name = "configuration",
+ .mode = S_IRUGO,
+ .show = show_config,
};
/* interfaces have one current setting; alternates
@@ -783,9 +855,9 @@ show_altsetting (struct device *dev, char *buf, size_t count, loff_t off)
return sprintf (buf, "%u\n", interface->altsetting->bAlternateSetting);
}
static struct driver_file_entry usb_altsetting_entry = {
- name: "altsetting",
- mode: S_IRUGO,
- show: show_altsetting,
+ .name = "altsetting",
+ .mode = S_IRUGO,
+ .show = show_altsetting,
};
/* product driverfs file */
@@ -804,9 +876,9 @@ static ssize_t show_product (struct device *dev, char *buf, size_t count, loff_t
return len+1;
}
static struct driver_file_entry usb_product_entry = {
- name: "product",
- mode: S_IRUGO,
- show: show_product,
+ .name = "product",
+ .mode = S_IRUGO,
+ .show = show_product,
};
/* manufacturer driverfs file */
@@ -826,9 +898,9 @@ show_manufacturer (struct device *dev, char *buf, size_t count, loff_t off)
return len+1;
}
static struct driver_file_entry usb_manufacturer_entry = {
- name: "manufacturer",
- mode: S_IRUGO,
- show: show_manufacturer,
+ .name = "manufacturer",
+ .mode = S_IRUGO,
+ .show = show_manufacturer,
};
/* serial number driverfs file */
@@ -848,9 +920,9 @@ show_serial (struct device *dev, char *buf, size_t count, loff_t off)
return len+1;
}
static struct driver_file_entry usb_serial_entry = {
- name: "serial",
- mode: S_IRUGO,
- show: show_serial,
+ .name = "serial",
+ .mode = S_IRUGO,
+ .show = show_serial,
};
/*
@@ -1121,27 +1193,22 @@ void usb_disconnect(struct usb_device **pdev)
info("USB disconnect on device %d", dev->devnum);
+ lock_kernel();
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
struct usb_driver *driver = interface->driver;
if (driver) {
- if (driver->owner)
- __MOD_INC_USE_COUNT(driver->owner);
- down(&driver->serialize);
- driver->disconnect(dev, interface->private_data);
- up(&driver->serialize);
+ usb_unbind_driver(dev, interface);
/* if driver->disconnect didn't release the interface */
if (interface->driver)
usb_driver_release_interface(driver, interface);
- /* we don't need the driver any longer */
- if (driver->owner)
- __MOD_DEC_USE_COUNT(driver->owner);
}
/* remove our device node for this interface */
put_device(&interface->dev);
}
}
+ unlock_kernel();
/* Free up all the children.. */
for (i = 0; i < USB_MAXCHILDREN; i++) {
@@ -1416,7 +1483,7 @@ struct list_head *usb_bus_get_list(void)
#endif
struct bus_type usb_bus_type = {
- name: "usb",
+ .name = "usb",
};
/*
@@ -1475,6 +1542,8 @@ EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
+EXPORT_SYMBOL(usb_bind_driver);
+EXPORT_SYMBOL(usb_unbind_driver);
EXPORT_SYMBOL(__usb_get_extra_descriptor);
diff --git a/drivers/usb/host/Config.in b/drivers/usb/host/Config.in
index dbfb819f8d33..0a6f97342a77 100644
--- a/drivers/usb/host/Config.in
+++ b/drivers/usb/host/Config.in
@@ -6,6 +6,5 @@ dep_tristate ' EHCI HCD (USB 2.0) support' CONFIG_USB_EHCI_HCD $CONFIG_USB
dep_tristate ' OHCI HCD support' CONFIG_USB_OHCI_HCD $CONFIG_USB
dep_tristate ' UHCI HCD (most Intel and VIA) support' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB
if [ "$CONFIG_ARM" = "y" ]; then
- dep_tristate ' SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB
dep_tristate ' SL811HS support' CONFIG_USB_SL811HS $CONFIG_USB
fi
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 85b355751fa2..32d1f6086dc1 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -9,8 +9,6 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD_ALT) += uhci-hcd.o
-obj-$(CONFIG_USB_OHCI) += usb-ohci.o usb-ohci-pci.o
-obj-$(CONFIG_USB_OHCI_SA1111) += usb-ohci.o usb-ohci-sa1111.o
obj-$(CONFIG_USB_SL811HS) += hc_sl811.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index fd9bbb044010..74496b06a130 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -702,47 +702,47 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
static const char hcd_name [] = "ehci-hcd";
static const struct hc_driver ehci_driver = {
- description: hcd_name,
+ .description = hcd_name,
/*
* generic hardware linkage
*/
- irq: ehci_irq,
- flags: HCD_MEMORY | HCD_USB2,
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
- start: ehci_start,
+ .start = ehci_start,
#ifdef CONFIG_PM
- suspend: ehci_suspend,
- resume: ehci_resume,
+ .suspend = ehci_suspend,
+ .resume = ehci_resume,
#endif
- stop: ehci_stop,
+ .stop = ehci_stop,
/*
* memory lifecycle (except per-request)
*/
- hcd_alloc: ehci_hcd_alloc,
- hcd_free: ehci_hcd_free,
+ .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,
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .free_config = ehci_free_config,
/*
* scheduling support
*/
- get_frame_number: ehci_get_frame,
+ .get_frame_number = ehci_get_frame,
/*
* root hub support
*/
- hub_status_data: ehci_hub_status_data,
- hub_control: ehci_hub_control,
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
};
/*-------------------------------------------------------------------------*/
@@ -754,15 +754,15 @@ 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,
+ .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,
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
}, { /* end: all zeroes */ }
};
@@ -770,15 +770,15 @@ 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,
+ .name = (char *) hcd_name,
+ .id_table = pci_ids,
- probe: usb_hcd_pci_probe,
- remove: usb_hcd_pci_remove,
+ .probe = usb_hcd_pci_probe,
+ .remove = usb_hcd_pci_remove,
#ifdef CONFIG_PM
- suspend: usb_hcd_pci_suspend,
- resume: usb_hcd_pci_resume,
+ .suspend = usb_hcd_pci_suspend,
+ .resume = usb_hcd_pci_resume,
#endif
};
diff --git a/drivers/usb/host/hc_simple.c b/drivers/usb/host/hc_simple.c
index 3a7218442adb..570267835101 100644
--- a/drivers/usb/host/hc_simple.c
+++ b/drivers/usb/host/hc_simple.c
@@ -343,11 +343,11 @@ static int hci_get_current_frame_number (struct usb_device *usb_dev)
**************************************************************************/
static struct usb_operations hci_device_operations = {
- allocate: hci_alloc_dev,
- deallocate: hci_free_dev,
- get_frame_number: hci_get_current_frame_number,
- submit_urb: hci_submit_urb,
- unlink_urb: hci_unlink_urb,
+ .allocate = hci_alloc_dev,
+ .deallocate = hci_free_dev,
+ .get_frame_number = hci_get_current_frame_number,
+ .submit_urb = hci_submit_urb,
+ .unlink_urb = hci_unlink_urb,
};
/***************************************************************************
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index a56ae64e60cc..2ee09b0a3bcd 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -167,7 +167,7 @@ static int ohci_urb_enqueue (
else if ((urb->transfer_flags & USB_ZERO_PACKET) != 0
&& (urb->transfer_buffer_length
% usb_maxpacket (urb->dev, pipe,
- usb_pipeout (pipe))) != 0)
+ usb_pipeout (pipe))) == 0)
size++;
break;
case PIPE_ISOCHRONOUS: /* number of packets from URB */
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 347dc5d34b0c..a1979e532787 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -284,47 +284,47 @@ dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
/*-------------------------------------------------------------------------*/
static const struct hc_driver ohci_pci_hc_driver = {
- description: hcd_name,
+ .description = hcd_name,
/*
* generic hardware linkage
*/
- irq: ohci_irq,
- flags: HCD_MEMORY | HCD_USB11,
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
/*
* basic lifecycle operations
*/
- start: ohci_pci_start,
+ .start = ohci_pci_start,
#ifdef CONFIG_PM
- suspend: ohci_pci_suspend,
- resume: ohci_pci_resume,
+ .suspend = ohci_pci_suspend,
+ .resume = ohci_pci_resume,
#endif
- stop: ohci_stop,
+ .stop = ohci_stop,
/*
* memory lifecycle (except per-request)
*/
- hcd_alloc: ohci_hcd_alloc,
- hcd_free: ohci_hcd_free,
+ .hcd_alloc = ohci_hcd_alloc,
+ .hcd_free = ohci_hcd_free,
/*
* managing i/o requests and associated device resources
*/
- urb_enqueue: ohci_urb_enqueue,
- urb_dequeue: ohci_urb_dequeue,
- free_config: ohci_free_config,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .free_config = ohci_free_config,
/*
* scheduling support
*/
- get_frame_number: ohci_get_frame,
+ .get_frame_number = ohci_get_frame,
/*
* root hub support
*/
- hub_status_data: ohci_hub_status_data,
- hub_control: ohci_hub_control,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
};
/*-------------------------------------------------------------------------*/
@@ -333,15 +333,15 @@ static const struct hc_driver ohci_pci_hc_driver = {
static const struct pci_device_id __devinitdata pci_ids [] = { {
/* handle any USB OHCI controller */
- class: (PCI_CLASS_SERIAL_USB << 8) | 0x10,
- class_mask: ~0,
- driver_data: (unsigned long) &ohci_pci_hc_driver,
+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0x10,
+ .class_mask = ~0,
+ .driver_data = (unsigned long) &ohci_pci_hc_driver,
/* no matter who makes it */
- vendor: PCI_ANY_ID,
- device: PCI_ANY_ID,
- subvendor: PCI_ANY_ID,
- subdevice: PCI_ANY_ID,
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
}, { /* end: all zeroes */ }
};
@@ -349,15 +349,15 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver ohci_pci_driver = {
- name: (char *) hcd_name,
- id_table: pci_ids,
+ .name = (char *) hcd_name,
+ .id_table = pci_ids,
- probe: usb_hcd_pci_probe,
- remove: usb_hcd_pci_remove,
+ .probe = usb_hcd_pci_probe,
+ .remove = usb_hcd_pci_remove,
#ifdef CONFIG_PM
- suspend: usb_hcd_pci_suspend,
- resume: usb_hcd_pci_resume,
+ .suspend = usb_hcd_pci_suspend,
+ .resume = usb_hcd_pci_resume,
#endif
};
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 95fc8b82af57..05c2127aa57f 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -288,47 +288,47 @@ ohci_sa1111_start (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
static const struct hc_driver ohci_sa1111_hc_driver = {
- description: hcd_name,
+ .description = hcd_name,
/*
* generic hardware linkage
*/
- irq: ohci_irq,
- flags: HCD_USB11,
+ .irq = ohci_irq,
+ .flags = HCD_USB11,
/*
* basic lifecycle operations
*/
- start: ohci_sa1111_start,
+ .start = ohci_sa1111_start,
#ifdef CONFIG_PM
/* suspend: ohci_sa1111_suspend, -- tbd */
/* resume: ohci_sa1111_resume, -- tbd */
#endif
- stop: ohci_stop,
+ .stop = ohci_stop,
/*
* memory lifecycle (except per-request)
*/
- hcd_alloc: ohci_hcd_alloc,
- hcd_free: ohci_hcd_free,
+ .hcd_alloc = ohci_hcd_alloc,
+ .hcd_free = ohci_hcd_free,
/*
* managing i/o requests and associated device resources
*/
- urb_enqueue: ohci_urb_enqueue,
- urb_dequeue: ohci_urb_dequeue,
- free_config: ohci_free_config,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .free_config = ohci_free_config,
/*
* scheduling support
*/
- get_frame_number: ohci_get_frame,
+ .get_frame_number = ohci_get_frame,
/*
* root hub support
*/
- hub_status_data: ohci_hub_status_data,
- hub_control: ohci_hub_control,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 2c27eae0687b..b7817920c542 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -571,11 +571,11 @@ static int uhci_proc_release(struct inode *inode, struct file *file)
}
static struct file_operations uhci_proc_operations = {
- open: uhci_proc_open,
- llseek: uhci_proc_lseek,
- read: uhci_proc_read,
+ .open = uhci_proc_open,
+ .llseek = uhci_proc_lseek,
+ .read = uhci_proc_read,
// write: uhci_proc_write,
- release: uhci_proc_release,
+ .release = uhci_proc_release,
};
#endif
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index b077975c6e22..69cf61862f85 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -2476,45 +2476,45 @@ static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
static const char hcd_name[] = "uhci-hcd";
static const struct hc_driver uhci_driver = {
- description: hcd_name,
+ .description = hcd_name,
/* Generic hardware linkage */
- irq: uhci_irq,
- flags: HCD_USB11,
+ .irq = uhci_irq,
+ .flags = HCD_USB11,
/* Basic lifecycle operations */
- start: uhci_start,
+ .start = uhci_start,
#ifdef CONFIG_PM
- suspend: uhci_suspend,
- resume: uhci_resume,
+ .suspend = uhci_suspend,
+ .resume = uhci_resume,
#endif
- stop: uhci_stop,
+ .stop = uhci_stop,
- hcd_alloc: uhci_hcd_alloc,
- hcd_free: uhci_hcd_free,
+ .hcd_alloc = uhci_hcd_alloc,
+ .hcd_free = uhci_hcd_free,
- urb_enqueue: uhci_urb_enqueue,
- urb_dequeue: uhci_urb_dequeue,
- free_config: NULL,
+ .urb_enqueue = uhci_urb_enqueue,
+ .urb_dequeue = uhci_urb_dequeue,
+ .free_config = NULL,
- get_frame_number: uhci_hcd_get_frame_number,
+ .get_frame_number = uhci_hcd_get_frame_number,
- hub_status_data: uhci_hub_status_data,
- hub_control: uhci_hub_control,
+ .hub_status_data = uhci_hub_status_data,
+ .hub_control = uhci_hub_control,
};
static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
/* handle any USB UHCI controller */
- class: ((PCI_CLASS_SERIAL_USB << 8) | 0x00),
- class_mask: ~0,
- driver_data: (unsigned long) &uhci_driver,
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x00),
+ .class_mask = ~0,
+ .driver_data = (unsigned long) &uhci_driver,
/* no matter who makes it */
- vendor: PCI_ANY_ID,
- device: PCI_ANY_ID,
- subvendor: PCI_ANY_ID,
- subdevice: PCI_ANY_ID,
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
}, { /* end: all zeroes */ }
};
@@ -2522,15 +2522,15 @@ static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
static struct pci_driver uhci_pci_driver = {
- name: (char *)hcd_name,
- id_table: uhci_pci_ids,
+ .name = (char *)hcd_name,
+ .id_table = uhci_pci_ids,
- probe: usb_hcd_pci_probe,
- remove: usb_hcd_pci_remove,
+ .probe = usb_hcd_pci_probe,
+ .remove = usb_hcd_pci_remove,
#ifdef CONFIG_PM
- suspend: usb_hcd_pci_suspend,
- resume: usb_hcd_pci_resume,
+ .suspend = usb_hcd_pci_suspend,
+ .resume = usb_hcd_pci_resume,
#endif /* PM */
};
diff --git a/drivers/usb/host/usb-ohci-pci.c b/drivers/usb/host/usb-ohci-pci.c
deleted file mode 100644
index ad3958c025d9..000000000000
--- a/drivers/usb/host/usb-ohci-pci.c
+++ /dev/null
@@ -1,456 +0,0 @@
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h> /* for in_interrupt() */
-#undef DEBUG
-#include <linux/usb.h>
-
-#include "../core/hcd.h"
-#include "usb-ohci.h"
-
-#ifdef CONFIG_PMAC_PBOOK
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
-#ifndef CONFIG_PM
-#define CONFIG_PM
-#endif
-#endif
-
-int __devinit
-hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,
- ohci_t **ohci, const char *name, const char *slot_name);
-extern void hc_remove_ohci(ohci_t *ohci);
-extern int hc_start (ohci_t * ohci, struct device *parent_dev);
-extern int hc_reset (ohci_t * ohci);
-
-/*-------------------------------------------------------------------------*/
-
-/* Increment the module usage count, start the control thread and
- * return success. */
-
-static struct pci_driver ohci_pci_driver;
-
-static int __devinit
-hc_found_ohci (struct pci_dev *dev, int irq,
- void *mem_base, const struct pci_device_id *id)
-{
- u8 latency, limit;
- ohci_t * ohci;
- int ret;
-
- printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
-
- /* bad pci latencies can contribute to overruns */
- 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);
- latency = limit;
- }
- }
-
- ret = hc_add_ohci(dev, irq, mem_base, id->driver_data,
- &ohci, ohci_pci_driver.name, dev->slot_name);
-
- if (ret == 0) {
- ohci->pci_latency = latency;
-
- if (hc_start (ohci, &ohci->ohci_dev->dev) < 0) {
- err ("can't start usb-%s", ohci->slot_name);
- hc_remove_ohci(ohci);
- return -EBUSY;
- }
-
-#ifdef DEBUG
- ohci_dump (ohci, 1);
-#endif
- }
-
- return ret;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef CONFIG_PM
-
-/* controller died; cleanup debris, then restart */
-/* must not be called from interrupt context */
-
-static void hc_restart (ohci_t *ohci)
-{
- int temp;
- int i;
-
- if (ohci->pci_latency)
- pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
-
- ohci->disabled = 1;
- ohci->sleeping = 0;
- if (ohci->bus->root_hub)
- usb_disconnect (&ohci->bus->root_hub);
-
- /* empty the interrupt branches */
- for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
- for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
-
- /* no EDs to remove */
- ohci->ed_rm_list [0] = NULL;
- ohci->ed_rm_list [1] = NULL;
-
- /* empty control and bulk lists */
- ohci->ed_isotail = NULL;
- ohci->ed_controltail = NULL;
- ohci->ed_bulktail = NULL;
-
- if ((temp = hc_reset (ohci)) < 0 ||
- (temp = hc_start (ohci, &ohci->ohci_dev->dev)) < 0) {
- err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
- } else
- dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
-}
-
-#endif /* CONFIG_PM */
-
-/*-------------------------------------------------------------------------*/
-
-/* configured so that an OHCI device is always provided */
-/* always called with process context; sleeping is OK */
-
-static int __devinit
-ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
- unsigned long mem_resource, mem_len;
- void *mem_base;
- int status;
-
- if (pci_enable_device(dev) < 0)
- return -ENODEV;
-
- if (!dev->irq) {
- err("found OHCI device with no IRQ assigned. check BIOS settings!");
- pci_disable_device (dev);
- return -ENODEV;
- }
-
- /* we read its hardware registers as memory */
- mem_resource = pci_resource_start(dev, 0);
- mem_len = pci_resource_len(dev, 0);
- if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
- dbg ("controller already in use");
- pci_disable_device (dev);
- return -EBUSY;
- }
-
- mem_base = ioremap_nocache (mem_resource, mem_len);
- if (!mem_base) {
- err("Error mapping OHCI memory");
- release_mem_region(mem_resource, mem_len);
- pci_disable_device (dev);
- return -EFAULT;
- }
-
- /* controller writes into our memory */
- pci_set_master (dev);
-
- status = hc_found_ohci (dev, dev->irq, mem_base, id);
- if (status < 0) {
- iounmap (mem_base);
- release_mem_region(mem_resource, mem_len);
- pci_disable_device (dev);
- }
- return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* may be called from interrupt context [interface spec] */
-/* may be called without controller present */
-/* may be called with controller, bus, and devices active */
-
-static void __devexit
-ohci_pci_remove (struct pci_dev *dev)
-{
- ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev);
- void *membase = ohci->regs;
-
- dbg ("remove %s controller usb-%s%s%s",
- hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
- dev->slot_name,
- ohci->disabled ? " (disabled)" : "",
- in_interrupt () ? " in interrupt" : ""
- );
-
- hc_remove_ohci(ohci);
-
- /* unmap the IO address space */
- iounmap (membase);
-
- release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
-}
-
-
-#ifdef CONFIG_PM
-
-/*-------------------------------------------------------------------------*/
-
-static int
-ohci_pci_suspend (struct pci_dev *dev, u32 state)
-{
- ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev);
- unsigned long flags;
- u16 cmd;
-
- if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
- dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
- hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
- return -EIO;
- }
-
- /* act as if usb suspend can always be used */
- info ("USB suspend: usb-%s", dev->slot_name);
- ohci->sleeping = 1;
-
- /* First stop processing */
- spin_lock_irqsave (&usb_ed_lock, flags);
- ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
- writel (ohci->hc_control, &ohci->regs->control);
- writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
- (void) readl (&ohci->regs->intrstatus);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- /* Wait a frame or two */
- mdelay(1);
- if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
- mdelay (1);
-
-#ifdef CONFIG_PMAC_PBOOK
- if (_machine == _MACH_Pmac)
- disable_irq (ohci->irq);
- /* else, 2.4 assumes shared irqs -- don't disable */
-#endif
- /* Enable remote wakeup */
- writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
-
- /* Suspend chip and let things settle down a bit */
- ohci->hc_control = OHCI_USB_SUSPEND;
- writel (ohci->hc_control, &ohci->regs->control);
- (void) readl (&ohci->regs->control);
- mdelay (500); /* No schedule here ! */
- switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
- case OHCI_USB_RESET:
- dbg("Bus in reset phase ???");
- break;
- case OHCI_USB_RESUME:
- dbg("Bus in resume phase ???");
- break;
- case OHCI_USB_OPER:
- dbg("Bus in operational phase ???");
- break;
- case OHCI_USB_SUSPEND:
- dbg("Bus suspended");
- break;
- }
- /* In some rare situations, Apple's OHCI have happily trashed
- * memory during sleep. We disable it's bus master bit during
- * suspend
- */
- pci_read_config_word (dev, PCI_COMMAND, &cmd);
- cmd &= ~PCI_COMMAND_MASTER;
- pci_write_config_word (dev, PCI_COMMAND, cmd);
-#ifdef CONFIG_PMAC_PBOOK
- {
- struct device_node *of_node;
-
- /* Disable USB PAD & cell clock */
- of_node = pci_device_to_OF_node (ohci->ohci_dev);
- if (of_node && _machine == _MACH_Pmac)
- pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
- }
-#endif
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int
-ohci_pci_resume (struct pci_dev *dev)
-{
- ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev);
- int temp;
- unsigned long flags;
-
- /* guard against multiple resumes */
- atomic_inc (&ohci->resume_count);
- if (atomic_read (&ohci->resume_count) != 1) {
- err ("concurrent PCI resumes for usb-%s", dev->slot_name);
- atomic_dec (&ohci->resume_count);
- return 0;
- }
-
-#ifdef CONFIG_PMAC_PBOOK
- {
- struct device_node *of_node;
-
- /* Re-enable USB PAD & cell clock */
- of_node = pci_device_to_OF_node (ohci->ohci_dev);
- if (of_node && _machine == _MACH_Pmac)
- pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
- }
-#endif
-
- /* did we suspend, or were we powered off? */
- ohci->hc_control = readl (&ohci->regs->control);
- temp = ohci->hc_control & OHCI_CTRL_HCFS;
-
-#ifdef DEBUG
- /* the registers may look crazy here */
- ohci_dump_status (ohci);
-#endif
-
- /* Re-enable bus mastering */
- pci_set_master(ohci->ohci_dev);
-
- switch (temp) {
-
- case OHCI_USB_RESET: // lost power
- info ("USB restart: usb-%s", dev->slot_name);
- hc_restart (ohci);
- break;
-
- case OHCI_USB_SUSPEND: // host wakeup
- case OHCI_USB_RESUME: // remote wakeup
- info ("USB continue: usb-%s from %s wakeup", dev->slot_name,
- (temp == OHCI_USB_SUSPEND)
- ? "host" : "remote");
- ohci->hc_control = OHCI_USB_RESUME;
- writel (ohci->hc_control, &ohci->regs->control);
- (void) readl (&ohci->regs->control);
- mdelay (20); /* no schedule here ! */
- /* Some controllers (lucent) need a longer delay here */
- mdelay (15);
- temp = readl (&ohci->regs->control);
- temp = ohci->hc_control & OHCI_CTRL_HCFS;
- if (temp != OHCI_USB_RESUME) {
- err ("controller usb-%s won't resume", dev->slot_name);
- ohci->disabled = 1;
- return -EIO;
- }
-
- /* Some chips likes being resumed first */
- writel (OHCI_USB_OPER, &ohci->regs->control);
- (void) readl (&ohci->regs->control);
- mdelay (3);
-
- /* Then re-enable operations */
- spin_lock_irqsave (&usb_ed_lock, flags);
- ohci->disabled = 0;
- ohci->sleeping = 0;
- ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
- if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
- if (ohci->ed_controltail)
- ohci->hc_control |= OHCI_CTRL_CLE;
- if (ohci->ed_bulktail)
- ohci->hc_control |= OHCI_CTRL_BLE;
- }
- writel (ohci->hc_control, &ohci->regs->control);
- writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
- writel (OHCI_INTR_SF, &ohci->regs->intrenable);
- /* Check for a pending done list */
- writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);
- (void) readl (&ohci->regs->intrdisable);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-#ifdef CONFIG_PMAC_PBOOK
- if (_machine == _MACH_Pmac)
- enable_irq (ohci->irq);
-#endif
- if (ohci->hcca->done_head)
- dl_done_list (ohci, dl_reverse_done_list (ohci));
- writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
- writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
- writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
- break;
-
- default:
- warn ("odd PCI resume for usb-%s", dev->slot_name);
- }
-
- /* controller is operational, extra resumes are harmless */
- atomic_dec (&ohci->resume_count);
-
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
-
- /*
- * AMD-756 [Viper] USB has a serious erratum when used with
- * lowspeed devices like mice.
- */
- vendor: 0x1022,
- device: 0x740c,
- subvendor: PCI_ANY_ID,
- subdevice: PCI_ANY_ID,
-
- driver_data: OHCI_QUIRK_AMD756,
-
-} , {
-
- /* handle any USB OHCI controller */
- class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10),
- class_mask: ~0,
-
- /* 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, ohci_pci_ids);
-
-static struct pci_driver ohci_pci_driver = {
- name: "usb-ohci",
- id_table: &ohci_pci_ids [0],
-
- probe: ohci_pci_probe,
- remove: __devexit_p(ohci_pci_remove),
-
-#ifdef CONFIG_PM
- suspend: ohci_pci_suspend,
- resume: ohci_pci_resume,
-#endif /* PM */
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-static int __init ohci_hcd_init (void)
-{
- return pci_module_init (&ohci_pci_driver);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_cleanup (void)
-{
- pci_unregister_driver (&ohci_pci_driver);
-}
-
-module_init (ohci_hcd_init);
-module_exit (ohci_hcd_cleanup);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/usb-ohci-sa1111.c b/drivers/usb/host/usb-ohci-sa1111.c
deleted file mode 100644
index c6bbd515bc91..000000000000
--- a/drivers/usb/host/usb-ohci-sa1111.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * linux/drivers/usb/usb-ohci-sa1111.c
- *
- * The outline of this code was taken from Brad Parkers <brad@heeltoe.com>
- * original OHCI driver modifications, and reworked into a cleaner form
- * by Russell King <rmk@arm.linux.org.uk>.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/arch/assabet.h>
-#include <asm/arch/badge4.h>
-#include <asm/hardware/sa1111.h>
-
-#include "usb-ohci.h"
-
-int __devinit
-hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,
- ohci_t **ohci, const char *name, const char *slot_name);
-extern void hc_remove_ohci(ohci_t *ohci);
-extern int hc_start (ohci_t * ohci, struct device *parent_dev);
-extern int hc_reset (ohci_t * ohci);
-
-
-static ohci_t *sa1111_ohci;
-
-static void __init sa1111_ohci_configure(void)
-{
- unsigned int usb_rst = 0;
-
- printk(KERN_DEBUG __FILE__
- ": starting SA-1111 OHCI USB Controller\n");
-
-#ifdef CONFIG_SA1100_BADGE4
- if (machine_is_badge4())
- /* power the bus */
- badge4_set_5V(BADGE4_5V_USB, 1);
-#endif
-
- if (machine_is_xp860() ||
- machine_has_neponset() ||
- machine_is_pfs168() ||
- machine_is_badge4())
- usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
-
- /*
- * Configure the power sense and control lines. Place the USB
- * host controller in reset.
- */
- USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
-
- /*
- * Now, carefully enable the USB clock, and take
- * the USB host controller out of reset.
- */
- SKPCR |= SKPCR_UCLKEN;
- udelay(11);
- USB_RESET = usb_rst;
-}
-
-static void __exit sa1111_ohci_unconfigure(void)
-{
- printk(KERN_DEBUG __FILE__
- ": stopping SA-1111 OHCI USB Controller\n");
-
- /*
- * Put the USB host controller into reset.
- */
- USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
-
- /*
- * Stop the USB clock.
- */
- SKPCR &= ~SKPCR_UCLKEN;
-
-#ifdef CONFIG_SA1100_BADGE4
- if (machine_is_badge4())
- badge4_set_5V(BADGE4_5V_USB, 0);
-#endif
-}
-
-
-static int __init sa1111_ohci_init(void)
-{
- int ret;
-
- if (!sa1111)
- return -ENODEV;
-
- /*
- * Request memory resources.
- */
- if (!request_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT, "usb-ohci"))
- return -EBUSY;
-
- sa1111_ohci_configure();
-
- /*
- * Initialise the generic OHCI driver.
- */
- sa1111_ohci = 0;
- ret = hc_add_ohci(SA1111_FAKE_PCIDEV, NIRQHCIM,
- (void *)&USB_OHCI_OP_BASE, 0, &sa1111_ohci,
- "usb-ohci", "sa1111");
-
- if (ret || !sa1111_ohci) {
- sa1111_ohci = 0;
- sa1111_ohci_unconfigure();
- release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
- return -EBUSY;
- }
-
- if (hc_start (sa1111_ohci, &sa1111->dev) < 0) {
- err ("can't start usb-%s", sa1111_ohci->slot_name);
- hc_remove_ohci (sa1111_ohci);
- sa1111_ohci = 0;
- sa1111_ohci_unconfigure();
- release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
- return -EBUSY;
- }
-
- return 0;
-}
-
-static void __exit sa1111_ohci_exit(void)
-{
- printk(KERN_DEBUG __FUNCTION__ ": cleaning up\n");
-
- if (sa1111_ohci) {
- hc_remove_ohci(sa1111_ohci);
- sa1111_ohci = 0;
- }
-
- sa1111_ohci_unconfigure();
- release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
-
- printk(KERN_DEBUG __FUNCTION__ ": exiting\n");
-}
-
-module_init(sa1111_ohci_init);
-module_exit(sa1111_ohci_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/usb-ohci.c b/drivers/usb/host/usb-ohci.c
deleted file mode 100644
index cf64e80bf4a6..000000000000
--- a/drivers/usb/host/usb-ohci.c
+++ /dev/null
@@ -1,2537 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
- *
- * [ Initialisation is based on Linus' ]
- * [ uhci code and gregs ohci fragments ]
- * [ (C) Copyright 1999 Linus Torvalds ]
- * [ (C) Copyright 1999 Gregory P. Smith]
- *
- *
- * History:
- *
- * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
- * load failure (Matthew Frederickson)
- * 2002/01/20 async unlink fixes: return -EINPROGRESS (per spec) and
- * make interrupt unlink-in-completion work (db)
- *
- * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
- * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
- * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
- pci_map_single (db)
- * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
- * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
- *
- * 2000/09/26 fixed races in removing the private portion of the urb
- * 2000/09/07 disable bulk and control lists when unlinking the last
- * endpoint descriptor in order to avoid unrecoverable errors on
- * the Lucent chips. (rwc@sgi)
- * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
- * urb unlink probs, indentation fixes
- * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
- * device unplugs.
- * 2000/06/28 use PCI hotplug framework, for better power management
- * and for Cardbus support (David Brownell)
- * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling
- * when the controller loses power; handle UE; cleanup; ...
- *
- * v5.2 1999/12/07 URB 3rd preview,
- * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
- * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume
- * i386: HUB, Keyboard, Mouse, Printer
- *
- * v4.3 1999/10/27 multiple HCs, bulk_request
- * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
- * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
- * v4.0 1999/08/18
- * v3.0 1999/06/25
- * v2.1 1999/05/09 code clean up
- * v2.0 1999/05/04
- * v1.0 1999/04/27 initial release
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h> /* for in_interrupt() */
-
-#ifdef CONFIG_USB_DEBUG
-# define DEBUG
-#else
-# undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-
-#define OHCI_USE_NPS // force NoPowerSwitching mode
-// #define OHCI_VERBOSE_DEBUG /* not always helpful */
-
-#include "../core/hcd.h"
-#include "usb-ohci.h"
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v5.3"
-#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
-#define DRIVER_DESC "USB OHCI Host Controller Driver"
-
-#define OHCI_UNLINK_TIMEOUT (HZ / 10)
-
-static LIST_HEAD (ohci_hcd_list);
-spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
-
-
-/*-------------------------------------------------------------------------*/
-
-/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
- * The erratum (#4) description is incorrect. AMD's workaround waits
- * till some bits (mostly reserved) are clear; ok for all revs.
- */
-#define read_roothub(hc, register, mask) ({ \
- u32 temp = readl (&hc->regs->roothub.register); \
- if (hc->flags & OHCI_QUIRK_AMD756) \
- while (temp & mask) \
- temp = readl (&hc->regs->roothub.register); \
- temp; })
-
-static u32 roothub_a (struct ohci *hc)
- { return read_roothub (hc, a, 0xfc0fe000); }
-static inline u32 roothub_b (struct ohci *hc)
- { return readl (&hc->regs->roothub.b); }
-static inline u32 roothub_status (struct ohci *hc)
- { return readl (&hc->regs->roothub.status); }
-static u32 roothub_portstatus (struct ohci *hc, int i)
- { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
-
-
-/*-------------------------------------------------------------------------*
- * URB support functions
- *-------------------------------------------------------------------------*/
-
-/* free HCD-private data associated with this URB */
-
-static void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
-{
- int i;
- int last = urb_priv->length - 1;
- int len;
- int dir;
- struct td *td;
-
- if (last >= 0) {
-
- /* ISOC, BULK, INTR data buffer starts at td 0
- * CTRL setup starts at td 0 */
- td = urb_priv->td [0];
-
- len = td->urb->transfer_buffer_length,
- dir = usb_pipeout (td->urb->pipe)
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE;
-
- /* unmap CTRL URB setup */
- if (usb_pipecontrol (td->urb->pipe)) {
- pci_unmap_single (hc->ohci_dev,
- td->data_dma, 8, PCI_DMA_TODEVICE);
-
- /* CTRL data buffer starts at td 1 if len > 0 */
- if (len && last > 0)
- td = urb_priv->td [1];
- }
-
- /* unmap data buffer */
- if (len && td->data_dma)
- pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir);
-
- for (i = 0; i <= last; i++) {
- td = urb_priv->td [i];
- if (td)
- td_free (hc, td);
- }
- }
-
- kfree (urb_priv);
-}
-
-static void urb_rm_priv_locked (struct urb * urb)
-{
- urb_priv_t * urb_priv = urb->hcpriv;
-
- if (urb_priv) {
- urb->hcpriv = NULL;
-
-#ifdef DO_TIMEOUTS
- if (urb->timeout) {
- list_del (&urb->urb_list);
- urb->timeout -= jiffies;
- }
-#endif
-
- /* Release int/iso 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;
- default:
- break;
- }
- }
-
- urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv);
- usb_put_dev (urb->dev);
- urb->dev = NULL;
- usb_put_urb (urb);
- }
-}
-
-static void urb_rm_priv (struct urb * urb)
-{
- unsigned long flags;
-
- spin_lock_irqsave (&usb_ed_lock, flags);
- urb_rm_priv_locked (urb);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-static int sohci_get_current_frame_number (struct usb_device * dev);
-
-/* debug| print the main components of an URB
- * small: 0) header + data packets 1) just header */
-
-static void urb_print (struct urb * urb, char * str, int small)
-{
- unsigned int pipe= urb->pipe;
-
- if (!urb->dev || !urb->dev->bus) {
- dbg("%s URB: no dev", str);
- return;
- }
-
-#ifndef OHCI_VERBOSE_DEBUG
- if (urb->status != 0)
-#endif
- dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)",
- str,
- sohci_get_current_frame_number (urb->dev),
- usb_pipedevice (pipe),
- usb_pipeendpoint (pipe),
- usb_pipeout (pipe)? 'O': 'I',
- usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
- (usb_pipecontrol (pipe)? "CTRL": "BULK"),
- urb->transfer_flags,
- urb->actual_length,
- urb->transfer_buffer_length,
- urb->status, urb->status);
-#ifdef OHCI_VERBOSE_DEBUG
- if (!small) {
- int i, len;
-
- if (usb_pipecontrol (pipe)) {
- printk (KERN_DEBUG __FILE__ ": cmd(8):");
- for (i = 0; i < 8 ; i++)
- printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
- printk ("\n");
- }
- if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
- printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
- urb->actual_length,
- urb->transfer_buffer_length);
- len = usb_pipeout (pipe)?
- urb->transfer_buffer_length: urb->actual_length;
- for (i = 0; i < 16 && i < len; i++)
- printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
- printk ("%s stat:%d\n", i < len? "...": "", urb->status);
- }
- }
-#endif
-}
-
-/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
-void ep_print_int_eds (ohci_t * ohci, char * str) {
- int i, j;
- __u32 * ed_p;
- for (i= 0; i < 32; i++) {
- j = 5;
- ed_p = &(ohci->hcca->int_table [i]);
- if (*ed_p == 0)
- continue;
- printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
- while (*ed_p != 0 && j--) {
- ed_t *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
- printk (" ed: %4x;", ed->hwINFO);
- ed_p = &ed->hwNextED;
- }
- printk ("\n");
- }
-}
-
-
-static void ohci_dump_intr_mask (char *label, __u32 mask)
-{
- dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
- label,
- mask,
- (mask & OHCI_INTR_MIE) ? " MIE" : "",
- (mask & OHCI_INTR_OC) ? " OC" : "",
- (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
- (mask & OHCI_INTR_FNO) ? " FNO" : "",
- (mask & OHCI_INTR_UE) ? " UE" : "",
- (mask & OHCI_INTR_RD) ? " RD" : "",
- (mask & OHCI_INTR_SF) ? " SF" : "",
- (mask & OHCI_INTR_WDH) ? " WDH" : "",
- (mask & OHCI_INTR_SO) ? " SO" : ""
- );
-}
-
-static void maybe_print_eds (char *label, __u32 value)
-{
- if (value)
- dbg ("%s %08x", label, value);
-}
-
-static char *hcfs2string (int state)
-{
- switch (state) {
- case OHCI_USB_RESET: return "reset";
- case OHCI_USB_RESUME: return "resume";
- case OHCI_USB_OPER: return "operational";
- case OHCI_USB_SUSPEND: return "suspend";
- }
- return "?";
-}
-
-// dump control and status registers
-static void ohci_dump_status (ohci_t *controller)
-{
- struct ohci_regs *regs = controller->regs;
- __u32 temp;
-
- temp = readl (&regs->revision) & 0xff;
- if (temp != 0x10)
- dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
-
- temp = readl (&regs->control);
- dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
- (temp & OHCI_CTRL_RWE) ? " RWE" : "",
- (temp & OHCI_CTRL_RWC) ? " RWC" : "",
- (temp & OHCI_CTRL_IR) ? " IR" : "",
- hcfs2string (temp & OHCI_CTRL_HCFS),
- (temp & OHCI_CTRL_BLE) ? " BLE" : "",
- (temp & OHCI_CTRL_CLE) ? " CLE" : "",
- (temp & OHCI_CTRL_IE) ? " IE" : "",
- (temp & OHCI_CTRL_PLE) ? " PLE" : "",
- temp & OHCI_CTRL_CBSR
- );
-
- temp = readl (&regs->cmdstatus);
- dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
- (temp & OHCI_SOC) >> 16,
- (temp & OHCI_OCR) ? " OCR" : "",
- (temp & OHCI_BLF) ? " BLF" : "",
- (temp & OHCI_CLF) ? " CLF" : "",
- (temp & OHCI_HCR) ? " HCR" : ""
- );
-
- ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
- ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
- // intrdisable always same as intrenable
- // ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
-
- maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
-
- maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
- maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
-
- maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
- maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
-
- maybe_print_eds ("donehead", readl (&regs->donehead));
-}
-
-static void ohci_dump_roothub (ohci_t *controller, int verbose)
-{
- __u32 temp, ndp, i;
-
- temp = roothub_a (controller);
- ndp = (temp & RH_A_NDP);
-
- if (verbose) {
- dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
- ((temp & RH_A_POTPGT) >> 24) & 0xff,
- (temp & RH_A_NOCP) ? " NOCP" : "",
- (temp & RH_A_OCPM) ? " OCPM" : "",
- (temp & RH_A_DT) ? " DT" : "",
- (temp & RH_A_NPS) ? " NPS" : "",
- (temp & RH_A_PSM) ? " PSM" : "",
- ndp
- );
- temp = roothub_b (controller);
- dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
- temp,
- (temp & RH_B_PPCM) >> 16,
- (temp & RH_B_DR)
- );
- temp = roothub_status (controller);
- dbg ("roothub.status: %08x%s%s%s%s%s%s",
- temp,
- (temp & RH_HS_CRWE) ? " CRWE" : "",
- (temp & RH_HS_OCIC) ? " OCIC" : "",
- (temp & RH_HS_LPSC) ? " LPSC" : "",
- (temp & RH_HS_DRWE) ? " DRWE" : "",
- (temp & RH_HS_OCI) ? " OCI" : "",
- (temp & RH_HS_LPS) ? " LPS" : ""
- );
- }
-
- for (i = 0; i < ndp; i++) {
- temp = roothub_portstatus (controller, i);
- dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
- i,
- temp,
- (temp & RH_PS_PRSC) ? " PRSC" : "",
- (temp & RH_PS_OCIC) ? " OCIC" : "",
- (temp & RH_PS_PSSC) ? " PSSC" : "",
- (temp & RH_PS_PESC) ? " PESC" : "",
- (temp & RH_PS_CSC) ? " CSC" : "",
-
- (temp & RH_PS_LSDA) ? " LSDA" : "",
- (temp & RH_PS_PPS) ? " PPS" : "",
- (temp & RH_PS_PRS) ? " PRS" : "",
- (temp & RH_PS_POCI) ? " POCI" : "",
- (temp & RH_PS_PSS) ? " PSS" : "",
-
- (temp & RH_PS_PES) ? " PES" : "",
- (temp & RH_PS_CCS) ? " CCS" : ""
- );
- }
-}
-
-static void ohci_dump (ohci_t *controller, int verbose)
-{
- dbg ("OHCI controller usb-%s state", controller->slot_name);
-
- // dumps some of the state we know about
- ohci_dump_status (controller);
- if (verbose)
- ep_print_int_eds (controller, "hcca");
- dbg ("hcca frame #%04x", controller->hcca->frame_no);
- ohci_dump_roothub (controller, 1);
-}
-
-
-#endif
-
-/*-------------------------------------------------------------------------*
- * Interface functions (URB)
- *-------------------------------------------------------------------------*/
-
-/* return a request to the completion handler */
-
-static int sohci_return_urb (struct ohci *hc, struct urb * urb)
-{
- urb_priv_t * urb_priv = urb->hcpriv;
- struct urb * urbt = NULL;
- unsigned long flags;
- int i;
-
- if (!urb_priv)
- return -1; /* urb already unlinked */
-
- /* just to be sure */
- if (!urb->complete) {
- urb_rm_priv (urb);
- return -1;
- }
-
-#ifdef DEBUG
- urb_print (urb, "RET", usb_pipeout (urb->pipe));
-#endif
-
- switch (usb_pipetype (urb->pipe)) {
- case PIPE_INTERRUPT:
- pci_unmap_single (hc->ohci_dev,
- urb_priv->td [0]->data_dma,
- urb->transfer_buffer_length,
- usb_pipeout (urb->pipe)
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE);
- urb->complete (urb);
-
- /* implicitly requeued */
- urb->actual_length = 0;
- urb->status = -EINPROGRESS;
- td_submit_urb (urb);
- break;
-
- case PIPE_ISOCHRONOUS:
- // for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
- if (urbt) { /* send the reply and requeue URB */
- pci_unmap_single (hc->ohci_dev,
- urb_priv->td [0]->data_dma,
- urb->transfer_buffer_length,
- usb_pipeout (urb->pipe)
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE);
- urb->complete (urb);
- spin_lock_irqsave (&usb_ed_lock, flags);
- urb->actual_length = 0;
- urb->status = -EINPROGRESS;
- urb->start_frame = urb_priv->ed->last_iso + 1;
- if (urb_priv->state != URB_DEL) {
- for (i = 0; i < urb->number_of_packets; i++) {
- urb->iso_frame_desc[i].actual_length = 0;
- urb->iso_frame_desc[i].status = -EXDEV;
- }
- td_submit_urb (urb);
- }
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- } else { /* unlink URB, call complete */
- urb_rm_priv (urb);
- urb->complete (urb);
- }
- break;
-
- case PIPE_BULK:
- case PIPE_CONTROL: /* unlink URB, call complete */
- urb_rm_priv (urb);
- urb->complete (urb);
- break;
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* get a transfer request */
-
-static int sohci_submit_urb (struct urb * urb, int mem_flags)
-{
- ohci_t * ohci;
- ed_t * ed;
- urb_priv_t * urb_priv;
- unsigned int pipe = urb->pipe;
- int maxps = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
- int i, size = 0;
- unsigned long flags;
- int bustime = 0;
-
- if (!urb->dev || !urb->dev->bus)
- return -ENODEV;
-
- if (urb->hcpriv) /* urb already in use */
- return -EINVAL;
-
-// if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
-// return -EPIPE;
-
- /* increment the reference count of the urb, as we now also control it */
- urb = usb_get_urb (urb);
-
- usb_get_dev (urb->dev);
- ohci = (ohci_t *) urb->dev->bus->hcpriv;
-
-#ifdef DEBUG
- urb_print (urb, "SUB", usb_pipein (pipe));
-#endif
-
- /* handle a request to the virtual root hub */
- if (usb_pipedevice (pipe) == ohci->rh.devnum)
- return rh_submit_urb (urb);
-
- /* when controller's hung, permit only roothub cleanup attempts
- * such as powering down ports */
- if (ohci->disabled) {
- usb_put_dev (urb->dev);
- usb_put_urb (urb);
- return -ESHUTDOWN;
- }
-
- /* every endpoint has a ed, locate and fill it */
- if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
- usb_put_dev (urb->dev);
- usb_put_urb (urb);
- return -ENOMEM;
- }
-
- /* for the private part of the URB we need the number of TDs (size) */
- switch (usb_pipetype (pipe)) {
- case PIPE_BULK: /* one TD for every 4096 Byte */
- size = (urb->transfer_buffer_length - 1) / 4096 + 1;
-
- /* If the transfer size is multiple of the pipe mtu,
- * we may need an extra TD to create a empty frame
- * Jean II */
- if ((urb->transfer_flags & USB_ZERO_PACKET) &&
- usb_pipeout (pipe) &&
- (urb->transfer_buffer_length != 0) &&
- ((urb->transfer_buffer_length % maxps) == 0))
- size++;
- break;
- case PIPE_ISOCHRONOUS: /* number of packets from URB */
- size = urb->number_of_packets;
- if (size <= 0) {
- usb_put_dev (urb->dev);
- usb_put_urb (urb);
- return -EINVAL;
- }
- for (i = 0; i < urb->number_of_packets; i++) {
- urb->iso_frame_desc[i].actual_length = 0;
- urb->iso_frame_desc[i].status = -EXDEV;
- }
- break;
- case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
- size = (urb->transfer_buffer_length == 0)? 2:
- (urb->transfer_buffer_length - 1) / 4096 + 3;
- break;
- case PIPE_INTERRUPT: /* one TD */
- size = 1;
- break;
- }
-
- /* allocate the private part of the URB */
- urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), mem_flags);
- if (!urb_priv) {
- usb_put_dev (urb->dev);
- usb_put_urb (urb);
- return -ENOMEM;
- }
- memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
-
- /* fill the private part of the URB */
- urb_priv->length = size;
- urb_priv->ed = ed;
-
- /* allocate the TDs (updating hash chains) */
- spin_lock_irqsave (&usb_ed_lock, flags);
- for (i = 0; i < size; i++) {
- urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC);
- if (!urb_priv->td[i]) {
- urb_priv->length = i;
- urb_free_priv (ohci, urb_priv);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- usb_put_dev (urb->dev);
- usb_put_urb (urb);
- return -ENOMEM;
- }
- }
-
- if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
- urb_free_priv (ohci, urb_priv);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- usb_put_dev (urb->dev);
- usb_put_urb (urb);
- return -EINVAL;
- }
-
- /* allocate and claim bandwidth if needed; ISO
- * needs start frame index if it was't provided.
- */
- switch (usb_pipetype (pipe)) {
- case PIPE_ISOCHRONOUS:
- if (urb->transfer_flags & USB_ISO_ASAP) {
- urb->start_frame = ((ed->state == ED_OPER)
- ? (ed->last_iso + 1)
- : (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff;
- }
- /* FALLTHROUGH */
- case PIPE_INTERRUPT:
- if (urb->bandwidth == 0) {
- bustime = usb_check_bandwidth (urb->dev, urb);
- }
- if (bustime < 0) {
- urb_free_priv (ohci, urb_priv);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- usb_put_dev (urb->dev);
- usb_put_urb (urb);
- return bustime;
- }
- usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe));
-#ifdef DO_TIMEOUTS
- urb->timeout = 0;
-#endif
- }
-
- urb->actual_length = 0;
- urb->hcpriv = urb_priv;
- urb->status = -EINPROGRESS;
-
- /* link the ed into a chain if is not already */
- if (ed->state != ED_OPER)
- ep_link (ohci, ed);
-
- /* fill the TDs and link it to the ed */
- td_submit_urb (urb);
-
-#ifdef DO_TIMEOUTS
- /* maybe add to ordered list of timeouts */
- if (urb->timeout) {
- struct list_head *entry;
-
- // FIXME: usb-uhci uses relative timeouts (like this),
- // while uhci uses absolute ones (probably better).
- // Pick one solution and change the affected drivers.
- urb->timeout += jiffies;
-
- list_for_each (entry, &ohci->timeout_list) {
- struct urb *next_urb;
-
- next_urb = list_entry (entry, struct urb, urb_list);
- if (time_after_eq (urb->timeout, next_urb->timeout))
- break;
- }
- list_add (&urb->urb_list, entry);
-
- /* drive timeouts by SF (messy, but works) */
- writel (OHCI_INTR_SF, &ohci->regs->intrenable);
- }
-#endif
-
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* deactivate all TDs and remove the private part of the URB */
-/* interrupt callers must use async unlink mode */
-
-static int sohci_unlink_urb (struct urb * urb)
-{
- unsigned long flags;
- ohci_t * ohci;
-
- if (!urb) /* just to be sure */
- return -EINVAL;
-
- if (!urb->dev || !urb->dev->bus)
- return -ENODEV;
-
- ohci = (ohci_t *) urb->dev->bus->hcpriv;
-
-#ifdef DEBUG
- urb_print (urb, "UNLINK", 1);
-#endif
-
- /* handle a request to the virtual root hub */
- if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
- return rh_unlink_urb (urb);
-
- if (urb->hcpriv && (urb->status == -EINPROGRESS)) {
- if (!ohci->disabled) {
- urb_priv_t * urb_priv;
-
- /* interrupt code may not sleep; it must use
- * async status return to unlink pending urbs.
- */
- if (!(urb->transfer_flags & USB_ASYNC_UNLINK)
- && in_interrupt ()) {
- err ("bug in call from %p; use async!",
- __builtin_return_address(0));
- return -EWOULDBLOCK;
- }
-
- /* flag the urb and its TDs for deletion in some
- * upcoming SF interrupt delete list processing
- */
- spin_lock_irqsave (&usb_ed_lock, flags);
- urb_priv = urb->hcpriv;
-
- if (!urb_priv || (urb_priv->state == URB_DEL)) {
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- return 0;
- }
-
- urb_priv->state = URB_DEL;
- ep_rm_ed (urb->dev, urb_priv->ed);
- urb_priv->ed->state |= ED_URB_DEL;
-
- if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
- DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
- DECLARE_WAITQUEUE (wait, current);
- int timeout = OHCI_UNLINK_TIMEOUT;
-
- add_wait_queue (&unlink_wakeup, &wait);
- urb_priv->wait = &unlink_wakeup;
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- /* wait until all TDs are deleted */
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (timeout && (urb->status == -EINPROGRESS))
- timeout = schedule_timeout (timeout);
- set_current_state(TASK_RUNNING);
- remove_wait_queue (&unlink_wakeup, &wait);
- if (urb->status == -EINPROGRESS) {
- err ("unlink URB timeout");
- return -ETIMEDOUT;
- }
- } else {
- /* usb_put_dev done in dl_del_list() */
- urb->status = -EINPROGRESS;
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- return -EINPROGRESS;
- }
- } else {
- urb_rm_priv (urb);
- if (urb->transfer_flags & USB_ASYNC_UNLINK) {
- urb->status = -ECONNRESET;
- if (urb->complete)
- urb->complete (urb);
- } else
- urb->status = -ENOENT;
- }
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* allocate private data space for a usb device */
-
-static int sohci_alloc_dev (struct usb_device *usb_dev)
-{
- struct ohci_device * dev;
-
- dev = dev_alloc ((struct ohci *) usb_dev->bus->hcpriv, ALLOC_FLAGS);
- if (!dev)
- return -ENOMEM;
-
- usb_dev->hcpriv = dev;
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* may be called from interrupt context */
-/* frees private data space of usb device */
-
-static int sohci_free_dev (struct usb_device * usb_dev)
-{
- unsigned long flags;
- int i, cnt = 0;
- ed_t * ed;
- struct ohci_device * dev = usb_to_ohci (usb_dev);
- ohci_t * ohci = usb_dev->bus->hcpriv;
-
- if (!dev)
- return 0;
-
- if (usb_dev->devnum >= 0) {
-
- /* driver disconnects should have unlinked all urbs
- * (freeing all the TDs, unlinking EDs) but we need
- * to defend against bugs that prevent that.
- */
- spin_lock_irqsave (&usb_ed_lock, flags);
- for(i = 0; i < NUM_EDS; i++) {
- ed = &(dev->ed[i]);
- if (ed->state != ED_NEW) {
- if (ed->state == ED_OPER) {
- /* driver on that interface didn't unlink an urb */
- dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",
- ohci->slot_name, usb_dev->devnum, i);
- ep_unlink (ohci, ed);
- }
- ep_rm_ed (usb_dev, ed);
- ed->state = ED_DEL;
- cnt++;
- }
- }
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- /* if the controller is running, tds for those unlinked
- * urbs get freed by dl_del_list at the next SF interrupt
- */
- if (cnt > 0) {
-
- if (ohci->disabled) {
- /* FIXME: Something like this should kick in,
- * though it's currently an exotic case ...
- * the controller won't ever be touching
- * these lists again!!
- dl_del_list (ohci,
- le16_to_cpu (ohci->hcca->frame_no) & 1);
- */
- warn ("TD leak, %d", cnt);
-
- } else if (!in_interrupt ()) {
- DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup);
- DECLARE_WAITQUEUE (wait, current);
- int timeout = OHCI_UNLINK_TIMEOUT;
-
- /* SF interrupt handler calls dl_del_list */
- add_wait_queue (&freedev_wakeup, &wait);
- dev->wait = &freedev_wakeup;
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (timeout && dev->ed_cnt)
- timeout = schedule_timeout (timeout);
- set_current_state(TASK_RUNNING);
- remove_wait_queue (&freedev_wakeup, &wait);
- if (dev->ed_cnt) {
- err ("free device %d timeout", usb_dev->devnum);
- return -ETIMEDOUT;
- }
- } else {
- /* likely some interface's driver has a refcount bug */
- err ("bus %s devnum %d deletion in interrupt",
- ohci->slot_name, usb_dev->devnum);
- BUG ();
- }
- }
- }
-
- /* free device, and associated EDs */
- dev_free (ohci, dev);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* tell us the current USB frame number */
-
-static int sohci_get_current_frame_number (struct usb_device *usb_dev)
-{
- ohci_t * ohci = usb_dev->bus->hcpriv;
-
- return le16_to_cpu (ohci->hcca->frame_no);
-}
-
-/*-------------------------------------------------------------------------*/
-
-struct usb_operations sohci_device_operations = {
- allocate: sohci_alloc_dev,
- deallocate: sohci_free_dev,
- get_frame_number: sohci_get_current_frame_number,
- submit_urb: sohci_submit_urb,
- unlink_urb: sohci_unlink_urb,
-};
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/
-
-/* search for the right branch to insert an interrupt ed into the int tree
- * do some load ballancing;
- * returns the branch and
- * sets the interval to interval = 2^integer (ld (interval)) */
-
-static int ep_int_ballance (ohci_t * ohci, int interval, int load)
-{
- int i, branch = 0;
-
- /* search for the least loaded interrupt endpoint branch of all 32 branches */
- for (i = 0; i < 32; i++)
- if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i;
-
- branch = branch % interval;
- for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;
-
- return branch;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* 2^int( ld (inter)) */
-
-static int ep_2_n_interval (int inter)
-{
- int i;
- for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++);
- return 1 << i;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* the int tree is a binary tree
- * in order to process it sequentially the indexes of the branches have to be mapped
- * the mapping reverses the bits of a word of num_bits length */
-
-static int ep_rev (int num_bits, int word)
-{
- int i, wout = 0;
-
- for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
- return wout;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* link an ed into one of the HC chains */
-
-static int ep_link (ohci_t * ohci, ed_t * edi)
-{
- int int_branch;
- int i;
- int inter;
- int interval;
- int load;
- __u32 * ed_p;
- volatile ed_t * ed = edi;
-
- ed->state = ED_OPER;
-
- switch (ed->type) {
- case PIPE_CONTROL:
- ed->hwNextED = 0;
- if (ohci->ed_controltail == NULL) {
- writel (ed->dma, &ohci->regs->ed_controlhead);
- } else {
- ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
- }
- ed->ed_prev = ohci->ed_controltail;
- if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1] && !ohci->sleeping) {
- ohci->hc_control |= OHCI_CTRL_CLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- ohci->ed_controltail = edi;
- break;
-
- case PIPE_BULK:
- ed->hwNextED = 0;
- if (ohci->ed_bulktail == NULL) {
- writel (ed->dma, &ohci->regs->ed_bulkhead);
- } else {
- ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
- }
- ed->ed_prev = ohci->ed_bulktail;
- if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1] && !ohci->sleeping) {
- ohci->hc_control |= OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- ohci->ed_bulktail = edi;
- break;
-
- case PIPE_INTERRUPT:
- load = ed->int_load;
- interval = ep_2_n_interval (ed->int_period);
- ed->int_interval = interval;
- int_branch = ep_int_ballance (ohci, interval, load);
- ed->int_branch = int_branch;
-
- for (i = 0; i < ep_rev (6, interval); i += inter) {
- inter = 1;
- for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]);
- (*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval);
- ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED))
- inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
- ed->hwNextED = *ed_p;
- *ed_p = cpu_to_le32 (ed->dma);
- }
-#ifdef DEBUG
- ep_print_int_eds (ohci, "LINK_INT");
-#endif
- break;
-
- case PIPE_ISOCHRONOUS:
- ed->hwNextED = 0;
- ed->int_interval = 1;
- if (ohci->ed_isotail != NULL) {
- ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
- ed->ed_prev = ohci->ed_isotail;
- } else {
- for ( i = 0; i < 32; i += inter) {
- inter = 1;
- for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]);
- *ed_p != 0;
- ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED))
- inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
- *ed_p = cpu_to_le32 (ed->dma);
- }
- ed->ed_prev = NULL;
- }
- ohci->ed_isotail = edi;
-#ifdef DEBUG
- ep_print_int_eds (ohci, "LINK_ISO");
-#endif
- break;
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* scan the periodic table to find and unlink this ED */
-static void periodic_unlink (
- struct ohci *ohci,
- struct ed *ed,
- unsigned index,
- unsigned period
-) {
- for (; index < NUM_INTS; index += period) {
- __u32 *ed_p = &ohci->hcca->int_table [index];
-
- /* ED might have been unlinked through another path */
- while (*ed_p != 0) {
- if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- ed_p = & ((dma_to_ed (ohci,
- le32_to_cpup (ed_p)))->hwNextED);
- }
- }
-}
-
-/* unlink an ed from one of the HC chains.
- * just the link to the ed is unlinked.
- * the link from the ed still points to another operational ed or 0
- * so the HC can eventually finish the processing of the unlinked ed */
-
-static int ep_unlink (ohci_t * ohci, ed_t * ed)
-{
- int i;
-
- ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
-
- switch (ed->type) {
- case PIPE_CONTROL:
- if (ed->ed_prev == NULL) {
- if (!ed->hwNextED) {
- ohci->hc_control &= ~OHCI_CTRL_CLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
- } else {
- ed->ed_prev->hwNextED = ed->hwNextED;
- }
- if (ohci->ed_controltail == ed) {
- ohci->ed_controltail = ed->ed_prev;
- } else {
- (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
- }
- break;
-
- case PIPE_BULK:
- if (ed->ed_prev == NULL) {
- if (!ed->hwNextED) {
- ohci->hc_control &= ~OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
- } else {
- ed->ed_prev->hwNextED = ed->hwNextED;
- }
- if (ohci->ed_bulktail == ed) {
- ohci->ed_bulktail = ed->ed_prev;
- } else {
- (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
- }
- break;
-
- case PIPE_INTERRUPT:
- periodic_unlink (ohci, ed, 0, 1);
- for (i = ed->int_branch; i < 32; i += ed->int_interval)
- ohci->ohci_int_load[i] -= ed->int_load;
-#ifdef DEBUG
- ep_print_int_eds (ohci, "UNLINK_INT");
-#endif
- break;
-
- case PIPE_ISOCHRONOUS:
- if (ohci->ed_isotail == ed)
- ohci->ed_isotail = ed->ed_prev;
- if (ed->hwNextED != 0)
- (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
- ->ed_prev = ed->ed_prev;
-
- if (ed->ed_prev != NULL)
- ed->ed_prev->hwNextED = ed->hwNextED;
- else
- periodic_unlink (ohci, ed, 0, 1);
-#ifdef DEBUG
- ep_print_int_eds (ohci, "UNLINK_ISO");
-#endif
- break;
- }
- ed->state = ED_UNLINK;
- return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
- * but the USB stack is a little bit stateless so we do it at every transaction
- * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
- * in all other cases the state is left unchanged
- * the ed info fields are setted anyway even though most of them should not change */
-
-static ed_t * ep_add_ed (
- struct usb_device * usb_dev,
- unsigned int pipe,
- int interval,
- int load,
- int mem_flags
-)
-{
- ohci_t * ohci = usb_dev->bus->hcpriv;
- td_t * td;
- ed_t * ed_ret;
- volatile ed_t * ed;
- unsigned long flags;
-
-
- spin_lock_irqsave (&usb_ed_lock, flags);
-
- ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) |
- (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
-
- if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
- /* pending delete request */
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- return NULL;
- }
-
- if (ed->state == ED_NEW) {
- ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
- /* dummy td; end of td list for ed */
- td = td_alloc (ohci, SLAB_ATOMIC);
- /* hash the ed for later reverse mapping */
- if (!td || !hash_add_ed (ohci, (ed_t *)ed)) {
- /* out of memory */
- if (td)
- td_free(ohci, td);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- return NULL;
- }
- ed->hwTailP = cpu_to_le32 (td->td_dma);
- ed->hwHeadP = ed->hwTailP;
- ed->state = ED_UNLINK;
- ed->type = usb_pipetype (pipe);
- usb_to_ohci (usb_dev)->ed_cnt++;
- }
-
- ohci->dev[usb_pipedevice (pipe)] = usb_dev;
-
- ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
- | usb_pipeendpoint (pipe) << 7
- | (usb_pipeisoc (pipe)? 0x8000: 0)
- | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
- | (usb_dev->speed == USB_SPEED_LOW) << 13
- | usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
-
- if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
- ed->int_period = interval;
- ed->int_load = load;
- }
-
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- return ed_ret;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* request the removal of an endpoint
- * put the ep on the rm_list and request a stop of the bulk or ctrl list
- * real removal is done at the next start frame (SF) hardware interrupt */
-
-static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
-{
- unsigned int frame;
- ohci_t * ohci = usb_dev->bus->hcpriv;
-
- if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL))
- return;
-
- ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
-
- if (!ohci->disabled) {
- switch (ed->type) {
- case PIPE_CONTROL: /* stop control list */
- ohci->hc_control &= ~OHCI_CTRL_CLE;
- writel (ohci->hc_control, &ohci->regs->control);
- break;
- case PIPE_BULK: /* stop bulk list */
- ohci->hc_control &= ~OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
- break;
- }
- }
-
- frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
- ed->ed_rm_list = ohci->ed_rm_list[frame];
- ohci->ed_rm_list[frame] = ed;
-
- if (!ohci->disabled && !ohci->sleeping) {
- /* enable SOF interrupt */
- writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
- writel (OHCI_INTR_SF, &ohci->regs->intrenable);
- }
-}
-
-/*-------------------------------------------------------------------------*
- * TD handling functions
- *-------------------------------------------------------------------------*/
-
-/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
-
-static void
-td_fill (ohci_t * ohci, unsigned int info,
- dma_addr_t data, int len,
- struct urb * urb, int index)
-{
- volatile td_t * td, * td_pt;
- urb_priv_t * urb_priv = urb->hcpriv;
-
- if (index >= urb_priv->length) {
- err("internal OHCI error: TD index > length");
- return;
- }
-
- /* use this td as the next dummy */
- td_pt = urb_priv->td [index];
- td_pt->hwNextTD = 0;
-
- /* fill the old dummy TD */
- td = urb_priv->td [index] = dma_to_td (ohci,
- le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
-
- td->ed = urb_priv->ed;
- td->next_dl_td = NULL;
- td->index = index;
- td->urb = urb;
- td->data_dma = data;
- if (!len)
- data = 0;
-
- td->hwINFO = cpu_to_le32 (info);
- if ((td->ed->type) == PIPE_ISOCHRONOUS) {
- td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
- td->ed->last_iso = info & 0xffff;
- } else {
- td->hwCBP = cpu_to_le32 (data);
- }
- if (data)
- td->hwBE = cpu_to_le32 (data + len - 1);
- else
- td->hwBE = 0;
- td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
- td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
-
- /* append to queue */
- td->ed->hwTailP = td->hwNextTD;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* prepare all TDs of a transfer */
-
-static void td_submit_urb (struct urb * urb)
-{
- urb_priv_t * urb_priv = urb->hcpriv;
- ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
- dma_addr_t data;
- int data_len = urb->transfer_buffer_length;
- int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
- int cnt = 0;
- __u32 info = 0;
- unsigned int toggle = 0;
-
- /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
- if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
- toggle = TD_T_TOGGLE;
- } else {
- toggle = TD_T_DATA0;
- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
- }
-
- urb_priv->td_cnt = 0;
-
- if (data_len) {
- data = pci_map_single (ohci->ohci_dev,
- urb->transfer_buffer, data_len,
- usb_pipeout (urb->pipe)
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE
- );
- } else
- data = 0;
-
- switch (usb_pipetype (urb->pipe)) {
- case PIPE_BULK:
- info = usb_pipeout (urb->pipe)?
- TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
- while(data_len > 4096) {
- td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
- data += 4096; data_len -= 4096; cnt++;
- }
- info = usb_pipeout (urb->pipe)?
- TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
- td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
- cnt++;
-
- /* If the transfer size is multiple of the pipe mtu,
- * we may need an extra TD to create a empty frame
- * Note : another way to check this condition is
- * to test if(urb_priv->length > cnt) - Jean II */
- if ((urb->transfer_flags & USB_ZERO_PACKET) &&
- usb_pipeout (urb->pipe) &&
- (urb->transfer_buffer_length != 0) &&
- ((urb->transfer_buffer_length % maxps) == 0)) {
- td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
- cnt++;
- }
-
- if (!ohci->sleeping)
- writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
- break;
-
- case PIPE_INTERRUPT:
- info = usb_pipeout (urb->pipe)?
- TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
- td_fill (ohci, info, data, data_len, urb, cnt++);
- break;
-
- case PIPE_CONTROL:
- info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
- td_fill (ohci, info,
- pci_map_single (ohci->ohci_dev,
- urb->setup_packet, 8,
- PCI_DMA_TODEVICE),
- 8, urb, cnt++);
- if (data_len > 0) {
- info = usb_pipeout (urb->pipe)?
- TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
- /* NOTE: mishandles transfers >8K, some >4K */
- td_fill (ohci, info, data, data_len, urb, cnt++);
- }
- info = usb_pipeout (urb->pipe)?
- TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
- td_fill (ohci, info, data, 0, urb, cnt++);
- if (!ohci->sleeping)
- writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
- break;
-
- case PIPE_ISOCHRONOUS:
- for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
- td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff),
- data + urb->iso_frame_desc[cnt].offset,
- urb->iso_frame_desc[cnt].length, urb, cnt);
- }
- break;
- }
- if (urb_priv->length != cnt)
- dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
-}
-
-/*-------------------------------------------------------------------------*
- * Done List handling functions
- *-------------------------------------------------------------------------*/
-
-
-/* calculate the transfer length and update the urb */
-
-static void dl_transfer_length(td_t * td)
-{
- __u32 tdINFO, tdBE, tdCBP;
- __u16 tdPSW;
- struct urb * urb = td->urb;
- urb_priv_t * urb_priv = urb->hcpriv;
- int dlen = 0;
- int cc = 0;
-
- tdINFO = le32_to_cpup (&td->hwINFO);
- tdBE = le32_to_cpup (&td->hwBE);
- tdCBP = le32_to_cpup (&td->hwCBP);
-
-
- if (tdINFO & TD_ISO) {
- tdPSW = le16_to_cpu (td->hwPSW[0]);
- cc = (tdPSW >> 12) & 0xF;
- if (cc < 0xE) {
- if (usb_pipeout(urb->pipe)) {
- dlen = urb->iso_frame_desc[td->index].length;
- } else {
- dlen = tdPSW & 0x3ff;
- }
- urb->actual_length += dlen;
- urb->iso_frame_desc[td->index].actual_length = dlen;
- if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
-
- urb->iso_frame_desc[td->index].status = cc_to_error[cc];
- }
- } else { /* BULK, INT, CONTROL DATA */
- if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL &&
- ((td->index == 0) || (td->index == urb_priv->length - 1)))) {
- if (tdBE != 0) {
- if (td->hwCBP == 0)
- urb->actual_length += tdBE - td->data_dma + 1;
- else
- urb->actual_length += tdCBP - td->data_dma;
- }
- }
- }
-}
-
-/* handle an urb that is being unlinked */
-
-static void dl_del_urb (struct urb * urb)
-{
- wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
-
- urb_rm_priv_locked (urb);
-
- if (urb->transfer_flags & USB_ASYNC_UNLINK) {
- urb->status = -ECONNRESET;
- if (urb->complete)
- urb->complete (urb);
- } else {
- urb->status = -ENOENT;
-
- /* unblock sohci_unlink_urb */
- if (wait_head)
- wake_up (wait_head);
- }
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* replies to the request have to be on a FIFO basis so
- * we reverse the reversed done-list */
-
-td_t * dl_reverse_done_list (ohci_t * ohci)
-{
- __u32 td_list_hc;
- td_t * td_rev = NULL;
- td_t * td_list = NULL;
- urb_priv_t * urb_priv = NULL;
- unsigned long flags;
-
- spin_lock_irqsave (&usb_ed_lock, flags);
-
- td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
- ohci->hcca->done_head = 0;
-
- while (td_list_hc) {
- td_list = dma_to_td (ohci, td_list_hc);
-
- if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
- urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
- dbg(" USB-error/status: %x : %p",
- TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
- if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
- if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
- td_list->ed->hwHeadP =
- (urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
- (td_list->ed->hwHeadP & cpu_to_le32 (0x2));
- urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
- } else
- td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
- }
- }
-
- td_list->next_dl_td = td_rev;
- td_rev = td_list;
- td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;
- }
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- return td_list;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* there are some pending requests to remove
- * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
- * - some URBs/TDs if urb_priv->state == URB_DEL */
-
-static void dl_del_list (ohci_t * ohci, unsigned int frame)
-{
- unsigned long flags;
- ed_t * ed;
- __u32 edINFO;
- __u32 tdINFO;
- td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
- __u32 * td_p;
- int ctrl = 0, bulk = 0;
-
- spin_lock_irqsave (&usb_ed_lock, flags);
-
- for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
-
- tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
- tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
- edINFO = le32_to_cpup (&ed->hwINFO);
- td_p = &ed->hwHeadP;
-
- for (td = tdHeadP; td != tdTailP; td = td_next) {
- struct urb * urb = td->urb;
- urb_priv_t * urb_priv = td->urb->hcpriv;
-
- td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
- if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
- tdINFO = le32_to_cpup (&td->hwINFO);
- if (TD_CC_GET (tdINFO) < 0xE)
- dl_transfer_length (td);
- *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
-
- /* URB is done; clean up */
- if (++(urb_priv->td_cnt) == urb_priv->length)
- dl_del_urb (urb);
- } else {
- td_p = &td->hwNextTD;
- }
- }
-
- if (ed->state & ED_DEL) { /* set by sohci_free_dev */
- struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
- td_free (ohci, tdTailP); /* free dummy td */
- ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
- ed->state = ED_NEW;
- hash_free_ed(ohci, ed);
- /* if all eds are removed wake up sohci_free_dev */
- if (!--dev->ed_cnt) {
- wait_queue_head_t *wait_head = dev->wait;
-
- dev->wait = 0;
- if (wait_head)
- wake_up (wait_head);
- }
- } else {
- ed->state &= ~ED_URB_DEL;
- tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
-
- if (tdHeadP == tdTailP) {
- if (ed->state == ED_OPER)
- ep_unlink(ohci, ed);
- td_free (ohci, tdTailP);
- ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
- ed->state = ED_NEW;
- hash_free_ed(ohci, ed);
- --(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;
- } else
- ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
- }
-
- switch (ed->type) {
- case PIPE_CONTROL:
- ctrl = 1;
- break;
- case PIPE_BULK:
- bulk = 1;
- break;
- }
- }
-
- /* maybe reenable control and bulk lists */
- if (!ohci->disabled) {
- if (ctrl) /* reset control list */
- writel (0, &ohci->regs->ed_controlcurrent);
- if (bulk) /* reset bulk list */
- writel (0, &ohci->regs->ed_bulkcurrent);
- if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
- if (ohci->ed_controltail)
- ohci->hc_control |= OHCI_CTRL_CLE;
- if (ohci->ed_bulktail)
- ohci->hc_control |= OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- }
-
- ohci->ed_rm_list[frame] = NULL;
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-}
-
-
-
-/*-------------------------------------------------------------------------*/
-
-/* td done list */
-
-void dl_done_list (ohci_t * ohci, td_t * td_list)
-{
- td_t * td_list_next = NULL;
- ed_t * ed;
- int cc = 0;
- struct urb * urb;
- urb_priv_t * urb_priv;
- __u32 tdINFO, edHeadP, edTailP;
-
- unsigned long flags;
-
- while (td_list) {
- td_list_next = td_list->next_dl_td;
-
- urb = td_list->urb;
- urb_priv = urb->hcpriv;
- tdINFO = le32_to_cpup (&td_list->hwINFO);
-
- ed = td_list->ed;
-
- dl_transfer_length(td_list);
-
- /* error code of transfer */
- cc = TD_CC_GET (tdINFO);
- if (cc == TD_CC_STALL)
- usb_endpoint_halt(urb->dev,
- usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe));
-
- if (!(urb->transfer_flags & USB_DISABLE_SPD)
- && (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
-
- if (++(urb_priv->td_cnt) == urb_priv->length) {
- if ((ed->state & (ED_OPER | ED_UNLINK))
- && (urb_priv->state != URB_DEL)) {
- urb->status = cc_to_error[cc];
- sohci_return_urb (ohci, urb);
- } else {
- spin_lock_irqsave (&usb_ed_lock, flags);
- dl_del_urb (urb);
- spin_unlock_irqrestore (&usb_ed_lock, flags);
- }
- }
-
- spin_lock_irqsave (&usb_ed_lock, flags);
- if (ed->state != ED_NEW) {
- edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
- edTailP = le32_to_cpup (&ed->hwTailP);
-
- /* unlink eds if they are not busy */
- if ((edHeadP == edTailP) && (ed->state == ED_OPER))
- ep_unlink (ohci, ed);
- }
- spin_unlock_irqrestore (&usb_ed_lock, flags);
-
- td_list = td_list_next;
- }
-}
-
-
-
-
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub
- *-------------------------------------------------------------------------*/
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] =
-{
- 0x12, /* __u8 bLength; */
- 0x01, /* __u8 bDescriptorType; Device */
- 0x10, /* __u16 bcdUSB; v1.1 */
- 0x01,
- 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
- 0x00, /* __u8 bDeviceSubClass; */
- 0x00, /* __u8 bDeviceProtocol; */
- 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
- 0x00, /* __u16 idVendor; */
- 0x00,
- 0x00, /* __u16 idProduct; */
- 0x00,
- 0x00, /* __u16 bcdDevice; */
- 0x00,
- 0x00, /* __u8 iManufacturer; */
- 0x02, /* __u8 iProduct; */
- 0x01, /* __u8 iSerialNumber; */
- 0x01 /* __u8 bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
- 0x09, /* __u8 bLength; */
- 0x02, /* __u8 bDescriptorType; Configuration */
- 0x19, /* __u16 wTotalLength; */
- 0x00,
- 0x01, /* __u8 bNumInterfaces; */
- 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; */
-
- /* 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; */
- 0x00, /* __u8 if_iInterface; */
-
- /* endpoint */
- 0x07, /* __u8 ep_bLength; */
- 0x05, /* __u8 ep_bDescriptorType; Endpoint */
- 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* __u8 ep_bmAttributes; Interrupt */
- 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
- 0x00,
- 0xff /* __u8 ep_bInterval; 255 ms */
-};
-
-/* Hub class-specific descriptor is constructed dynamically */
-
-
-/*-------------------------------------------------------------------------*/
-
-/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */
-
-static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
-{
- int num_ports;
- int i;
- int ret;
- int len;
-
- __u8 data[8];
-
- num_ports = roothub_a (ohci) & RH_A_NDP;
- if (num_ports > MAX_ROOT_PORTS) {
- err ("bogus NDP=%d for OHCI usb-%s", num_ports,
- ohci->slot_name);
- err ("rereads as NDP=%d",
- readl (&ohci->regs->roothub.a) & RH_A_NDP);
- /* retry later; "should not happen" */
- return 0;
- }
- *(__u8 *) data = (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
- ? 1: 0;
- ret = *(__u8 *) data;
-
- for ( i = 0; i < num_ports; i++) {
- *(__u8 *) (data + (i + 1) / 8) |=
- ((roothub_portstatus (ohci, i) &
- (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
- ? 1: 0) << ((i + 1) % 8);
- ret += *(__u8 *) (data + (i + 1) / 8);
- }
- len = i/8 + 1;
-
- if (ret > 0) {
- memcpy(rh_data, data,
- min_t(unsigned int, len,
- min_t(unsigned int, rh_len, sizeof(data))));
- return len;
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-
-static void rh_int_timer_do (unsigned long ptr)
-{
- int len;
-
- struct urb * urb = (struct urb *) ptr;
- ohci_t * ohci = urb->dev->bus->hcpriv;
-
- if (ohci->disabled)
- return;
-
- /* ignore timers firing during PM suspend, etc */
- if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)
- goto out;
-
- if(ohci->rh.send) {
- len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
- if (len > 0) {
- urb->actual_length = len;
-#ifdef DEBUG
- urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
-#endif
- if (urb->complete)
- urb->complete (urb);
- }
- }
- out:
- rh_init_int_timer (urb);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Root Hub INTs are polled by this timer */
-
-static int rh_init_int_timer (struct urb * urb)
-{
- ohci_t * ohci = urb->dev->bus->hcpriv;
-
- ohci->rh.interval = urb->interval;
- init_timer (&ohci->rh.rh_int_timer);
- ohci->rh.rh_int_timer.function = rh_int_timer_do;
- ohci->rh.rh_int_timer.data = (unsigned long) urb;
- ohci->rh.rh_int_timer.expires =
- jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
- add_timer (&ohci->rh.rh_int_timer);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#define OK(x) len = (x); break
-#define WR_RH_STAT(x) writel((x), &ohci->regs->roothub.status)
-#define WR_RH_PORTSTAT(x) writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT roothub_status(ohci)
-#define RD_RH_PORTSTAT roothub_portstatus(ohci,wIndex-1)
-
-/* request to virtual root hub */
-
-static int rh_submit_urb (struct urb * urb)
-{
- struct usb_device * usb_dev = urb->dev;
- ohci_t * ohci = usb_dev->bus->hcpriv;
- unsigned int pipe = urb->pipe;
- struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet;
- void * data = urb->transfer_buffer;
- int leni = urb->transfer_buffer_length;
- int len = 0;
- int status = TD_CC_NOERROR;
-
- __u32 datab[4];
- __u8 * data_buf = (__u8 *) datab;
-
- __u16 bmRType_bReq;
- __u16 wValue;
- __u16 wIndex;
- __u16 wLength;
-
- if (usb_pipeint(pipe)) {
- ohci->rh.urb = urb;
- ohci->rh.send = 1;
- ohci->rh.interval = urb->interval;
- rh_init_int_timer(urb);
- urb->status = cc_to_error [TD_CC_NOERROR];
-
- return 0;
- }
-
- bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
- wValue = le16_to_cpu (cmd->wValue);
- wIndex = le16_to_cpu (cmd->wIndex);
- wLength = le16_to_cpu (cmd->wLength);
-
- switch (bmRType_bReq) {
- /* Request Destination:
- without flags: Device,
- RH_INTERFACE: interface,
- RH_ENDPOINT: endpoint,
- RH_CLASS means HUB here,
- RH_OTHER | RH_CLASS almost ever means HUB_PORT here
- */
-
- case RH_GET_STATUS:
- *(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
- case RH_GET_STATUS | RH_INTERFACE:
- *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
- case RH_GET_STATUS | RH_ENDPOINT:
- *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
- case RH_GET_STATUS | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32 (
- RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
- OK (4);
- case RH_GET_STATUS | RH_OTHER | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
-
- case RH_CLEAR_FEATURE | RH_ENDPOINT:
- switch (wValue) {
- case (RH_ENDPOINT_STALL): OK (0);
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_CLASS:
- switch (wValue) {
- case RH_C_HUB_LOCAL_POWER:
- OK(0);
- case (RH_C_HUB_OVER_CURRENT):
- WR_RH_STAT(RH_HS_OCIC); OK (0);
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_ENABLE):
- WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
- case (RH_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
- case (RH_PORT_POWER):
- WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
- case (RH_C_PORT_CONNECTION):
- WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
- case (RH_C_PORT_ENABLE):
- WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
- case (RH_C_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
- case (RH_C_PORT_OVER_CURRENT):
- WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
- case (RH_C_PORT_RESET):
- WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
- }
- break;
-
- case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
- case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT (RH_PS_PRS);
- OK (0);
- case (RH_PORT_POWER):
- WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
- case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT (RH_PS_PES );
- OK (0);
- }
- break;
-
- case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
-
- case RH_GET_DESCRIPTOR:
- switch ((wValue & 0xff00) >> 8) {
- case (0x01): /* device descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_dev_des),
- wLength));
- data_buf = root_hub_dev_des; OK(len);
- case (0x02): /* configuration descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_config_des),
- wLength));
- data_buf = root_hub_config_des; OK(len);
- case (0x03): /* string descriptors */
- len = usb_root_hub_string (wValue & 0xff,
- (int)(long) ohci->regs, "OHCI",
- data, wLength);
- if (len > 0) {
- data_buf = data;
- OK(min_t(int, leni, len));
- }
- // else fallthrough
- default:
- status = TD_CC_STALL;
- }
- break;
-
- case RH_GET_DESCRIPTOR | RH_CLASS:
- {
- __u32 temp = roothub_a (ohci);
-
- data_buf [0] = 9; // min length;
- data_buf [1] = 0x29;
- data_buf [2] = temp & RH_A_NDP;
- data_buf [3] = 0;
- if (temp & RH_A_PSM) /* per-port power switching? */
- data_buf [3] |= 0x1;
- if (temp & RH_A_NOCP) /* no overcurrent reporting? */
- data_buf [3] |= 0x10;
- else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
- data_buf [3] |= 0x8;
-
- datab [1] = 0;
- data_buf [5] = (temp & RH_A_POTPGT) >> 24;
- temp = roothub_b (ohci);
- data_buf [7] = temp & RH_B_DR;
- if (data_buf [2] < 7) {
- data_buf [8] = 0xff;
- } else {
- data_buf [0] += 2;
- data_buf [8] = (temp & RH_B_DR) >> 8;
- data_buf [10] = data_buf [9] = 0xff;
- }
-
- len = min_t(unsigned int, leni,
- min_t(unsigned int, data_buf [0], wLength));
- OK (len);
- }
-
- case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
-
- case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
-
- default:
- dbg ("unsupported root hub command");
- status = TD_CC_STALL;
- }
-
-#ifdef DEBUG
- // ohci_dump_roothub (ohci, 0);
-#endif
-
- len = min_t(int, len, leni);
- if (data != data_buf)
- memcpy (data, data_buf, len);
- urb->actual_length = len;
- urb->status = cc_to_error [status];
-
-#ifdef DEBUG
- urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
-#endif
-
- urb->hcpriv = NULL;
- usb_put_dev (usb_dev);
- urb->dev = NULL;
- if (urb->complete)
- urb->complete (urb);
- usb_put_urb (urb);
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int rh_unlink_urb (struct urb * urb)
-{
- ohci_t * ohci = urb->dev->bus->hcpriv;
-
- if (ohci->rh.urb == urb) {
- ohci->rh.send = 0;
- del_timer (&ohci->rh.rh_int_timer);
- ohci->rh.urb = NULL;
-
- urb->hcpriv = NULL;
- usb_put_dev (urb->dev);
- urb->dev = NULL;
- if (urb->transfer_flags & USB_ASYNC_UNLINK) {
- urb->status = -ECONNRESET;
- if (urb->complete)
- urb->complete (urb);
- } else
- urb->status = -ENOENT;
- usb_put_urb (urb);
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*
- * HC functions
- *-------------------------------------------------------------------------*/
-
-/* reset the HC and BUS */
-
-int hc_reset (ohci_t * ohci)
-{
- int timeout = 30;
- int smm_timeout = 50; /* 0,5 sec */
-
- if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
- writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
- dbg("USB HC TakeOver from SMM");
- while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
- wait_ms (10);
- if (--smm_timeout == 0) {
- err("USB HC TakeOver failed!");
- return -1;
- }
- }
- }
-
- /* Disable HC interrupts */
- writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
-
- dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;",
- ohci->slot_name,
- readl (&ohci->regs->control));
-
- /* Reset USB (needed by some controllers) */
- writel (0, &ohci->regs->control);
-
- /* HC Reset requires max 10 ms delay */
- writel (OHCI_HCR, &ohci->regs->cmdstatus);
- while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
- if (--timeout == 0) {
- err("USB HC reset timed out!");
- return -1;
- }
- udelay (1);
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Start an OHCI controller, set the BUS operational
- * enable interrupts
- * connect the virtual root hub */
-
-int hc_start (ohci_t * ohci, struct device *parent_dev)
-{
- __u32 mask;
- unsigned int fminterval;
- struct usb_device * usb_dev;
- struct ohci_device * dev;
-
- ohci->disabled = 1;
-
- /* Tell the controller where the control and bulk lists are
- * The lists are empty now. */
-
- writel (0, &ohci->regs->ed_controlhead);
- writel (0, &ohci->regs->ed_bulkhead);
-
- writel (ohci->hcca_dma, &ohci->regs->hcca); /* a reset clears this */
-
- fminterval = 0x2edf;
- writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
- fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
- writel (fminterval, &ohci->regs->fminterval);
- writel (0x628, &ohci->regs->lsthresh);
-
- /* start controller operations */
- ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
- ohci->disabled = 0;
- writel (ohci->hc_control, &ohci->regs->control);
-
- /* Choose the interrupts we care about now, others later on demand */
- mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
- writel (mask, &ohci->regs->intrenable);
- writel (mask, &ohci->regs->intrstatus);
-
-#ifdef OHCI_USE_NPS
- /* required for AMD-756 and some Mac platforms */
- writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
- &ohci->regs->roothub.a);
- writel (RH_HS_LPSC, &ohci->regs->roothub.status);
-#endif /* OHCI_USE_NPS */
-
- // POTPGT delay is bits 24-31, in 2 ms units.
- mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
-
- /* connect the virtual root hub */
- ohci->rh.devnum = 0;
- usb_dev = usb_alloc_dev (NULL, ohci->bus);
- if (!usb_dev) {
- ohci->disabled = 1;
- return -ENOMEM;
- }
-
- dev = usb_to_ohci (usb_dev);
- ohci->bus->root_hub = usb_dev;
- usb_connect (usb_dev);
- if (usb_register_root_hub (usb_dev, parent_dev) != 0) {
- usb_free_dev (usb_dev);
- ohci->disabled = 1;
- return -ENODEV;
- }
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* called only from interrupt handler */
-
-static void check_timeouts (struct ohci *ohci)
-{
- spin_lock (&usb_ed_lock);
- while (!list_empty (&ohci->timeout_list)) {
- struct urb *urb;
-
- urb = list_entry (ohci->timeout_list.next, struct urb, urb_list);
- if (time_after (jiffies, urb->timeout))
- break;
-
- list_del_init (&urb->urb_list);
- if (urb->status != -EINPROGRESS)
- continue;
-
- urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
- spin_unlock (&usb_ed_lock);
-
- // outside the interrupt handler (in a timer...)
- // this reference would race interrupts
- sohci_unlink_urb (urb);
-
- spin_lock (&usb_ed_lock);
- }
- spin_unlock (&usb_ed_lock);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* an interrupt happens */
-
-static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
-{
- ohci_t * ohci = __ohci;
- struct ohci_regs * regs = ohci->regs;
- int ints;
-
- if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
- ints = OHCI_INTR_WDH;
- } else if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0) {
- return;
- }
-
- // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
-
- if (ints & OHCI_INTR_UE) {
- ohci->disabled++;
- err ("OHCI Unrecoverable Error, controller usb-%s disabled",
- ohci->slot_name);
- // e.g. due to PCI Master/Target Abort
-
-#ifdef DEBUG
- ohci_dump (ohci, 1);
-#else
- // FIXME: be optimistic, hope that bug won't repeat often.
- // Make some non-interrupt context restart the controller.
- // Count and limit the retries though; either hardware or
- // software errors can go forever...
-#endif
- hc_reset (ohci);
- }
-
- if (ints & OHCI_INTR_WDH) {
- writel (OHCI_INTR_WDH, &regs->intrdisable);
- dl_done_list (ohci, dl_reverse_done_list (ohci));
- writel (OHCI_INTR_WDH, &regs->intrenable);
- }
-
- if (ints & OHCI_INTR_SO) {
- dbg("USB Schedule overrun");
- writel (OHCI_INTR_SO, &regs->intrenable);
- }
-
- // FIXME: this assumes SOF (1/ms) interrupts don't get lost...
- if (ints & OHCI_INTR_SF) {
- unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
- writel (OHCI_INTR_SF, &regs->intrdisable);
- if (ohci->ed_rm_list[!frame] != NULL) {
- dl_del_list (ohci, !frame);
- }
- if (ohci->ed_rm_list[frame] != NULL)
- writel (OHCI_INTR_SF, &regs->intrenable);
- }
-
- if (!list_empty (&ohci->timeout_list)) {
- check_timeouts (ohci);
-// FIXME: enable SF as needed in a timer;
-// don't make lots of 1ms interrupts
-// On unloaded USB, think 4k ~= 4-5msec
- if (!list_empty (&ohci->timeout_list))
- writel (OHCI_INTR_SF, &regs->intrenable);
- }
-
- writel (ints, &regs->intrstatus);
- writel (OHCI_INTR_MIE, &regs->intrenable);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* allocate OHCI */
-
-static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
-{
- ohci_t * ohci;
-
- ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
- if (!ohci)
- return NULL;
-
- memset (ohci, 0, sizeof (ohci_t));
-
- ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca,
- &ohci->hcca_dma);
- if (!ohci->hcca) {
- kfree (ohci);
- return NULL;
- }
- memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
-
- ohci->disabled = 1;
- ohci->sleeping = 0;
- ohci->irq = -1;
- ohci->regs = mem_base;
-
- ohci->ohci_dev = dev;
-#ifdef CONFIG_PCI
- pci_set_drvdata(dev, ohci);
-#endif
-
- INIT_LIST_HEAD (&ohci->ohci_hcd_list);
- list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
-
- INIT_LIST_HEAD (&ohci->timeout_list);
-
- ohci->bus = usb_alloc_bus (&sohci_device_operations);
- if (!ohci->bus) {
-#ifdef CONFIG_PCI
- pci_set_drvdata (dev, NULL);
-#endif
- pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
- ohci->hcca, ohci->hcca_dma);
- kfree (ohci);
- return NULL;
- }
- ohci->bus->hcpriv = (void *) ohci;
-#ifdef CONFIG_PCI
- ohci->bus->bus_name = dev->slot_name;
-#else
- ohci->bus->bus_name = "ohci-hc";
-#endif
-
- return ohci;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* De-allocate all resources.. */
-
-static void hc_release_ohci (ohci_t * ohci)
-{
- dbg ("USB HC release ohci usb-%s", ohci->slot_name);
-
- /* disconnect all devices */
- if (ohci->bus->root_hub)
- usb_disconnect (&ohci->bus->root_hub);
-
- if (!ohci->disabled)
- hc_reset (ohci);
-
- if (ohci->irq >= 0) {
- free_irq (ohci->irq, ohci);
- ohci->irq = -1;
- }
-#ifdef CONFIG_PCI
- pci_set_drvdata(ohci->ohci_dev, NULL);
-#endif
- if (ohci->bus) {
- if (ohci->bus->busnum)
- usb_deregister_bus (ohci->bus);
- usb_free_bus (ohci->bus);
- }
-
- list_del (&ohci->ohci_hcd_list);
- INIT_LIST_HEAD (&ohci->ohci_hcd_list);
-
- ohci_mem_cleanup (ohci);
-
- pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
- ohci->hcca, ohci->hcca_dma);
- kfree (ohci);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Host bus independent add one OHCI host controller.
- */
-int
-hc_add_ohci(struct pci_dev *dev, int irq, void *mem_base, unsigned long flags,
- ohci_t **ohcip, const char *name, const char *slot_name)
-{
- char buf[8], *bufp = buf;
- ohci_t * ohci;
- int ret;
-
-#ifndef __sparc__
- sprintf(buf, "%d", irq);
-#else
- bufp = __irq_itoa(irq);
-#endif
- printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
- (unsigned long) mem_base, bufp);
-
- ohci = hc_alloc_ohci (dev, mem_base);
- if (!ohci) {
- return -ENOMEM;
- }
- ohci->slot_name = slot_name;
- if ((ret = ohci_mem_init (ohci)) < 0) {
- hc_release_ohci (ohci);
- return ret;
- }
- ohci->flags = flags;
- if (ohci->flags & OHCI_QUIRK_AMD756)
- printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
-
- if (hc_reset (ohci) < 0) {
- hc_release_ohci (ohci);
- return -ENODEV;
- }
-
- /* FIXME this is a second HC reset; why?? */
- writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
- wait_ms (10);
-
- usb_register_bus (ohci->bus);
-
- if (request_irq (irq, hc_interrupt, SA_SHIRQ, name, ohci) != 0) {
- err ("request interrupt %s failed", bufp);
- hc_release_ohci (ohci);
- return -EBUSY;
- }
- ohci->irq = irq;
-
- *ohcip = ohci;
-
- return 0;
-}
-
-/*
- * Host bus independent remove one OHCI host controller.
- */
-void hc_remove_ohci(ohci_t *ohci)
-{
-#ifdef DEBUG
- ohci_dump (ohci, 1);
-#endif
-
- /* don't wake up sleeping controllers, or block in interrupt context */
- if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {
- dbg ("controller being disabled");
- ohci->disabled = 1;
- }
-
- /* on return, USB will always be reset (if present) */
- if (ohci->disabled)
- writel (ohci->hc_control = OHCI_USB_RESET,
- &ohci->regs->control);
-
- hc_release_ohci (ohci);
-}
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(hc_add_ohci);
-EXPORT_SYMBOL(hc_remove_ohci);
-EXPORT_SYMBOL(hc_start);
-EXPORT_SYMBOL(hc_reset);
-EXPORT_SYMBOL(dl_done_list);
-EXPORT_SYMBOL(dl_reverse_done_list);
-EXPORT_SYMBOL(usb_ed_lock);
diff --git a/drivers/usb/host/usb-ohci.h b/drivers/usb/host/usb-ohci.h
deleted file mode 100644
index c04bb49a003f..000000000000
--- a/drivers/usb/host/usb-ohci.h
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
- *
- * usb-ohci.h
- */
-
-
-static int cc_to_error[16] = {
-
-/* mapping of the OHCI CC status to error codes */
- /* No Error */ 0,
- /* CRC Error */ -EILSEQ,
- /* Bit Stuff */ -EPROTO,
- /* Data Togg */ -EILSEQ,
- /* Stall */ -EPIPE,
- /* DevNotResp */ -ETIMEDOUT,
- /* PIDCheck */ -EPROTO,
- /* UnExpPID */ -EPROTO,
- /* DataOver */ -EOVERFLOW,
- /* DataUnder */ -EREMOTEIO,
- /* reservd */ -ETIMEDOUT,
- /* reservd */ -ETIMEDOUT,
- /* BufferOver */ -ECOMM,
- /* BuffUnder */ -ENOSR,
- /* Not Access */ -ETIMEDOUT,
- /* Not Access */ -ETIMEDOUT
-};
-
-#include <linux/config.h>
-
-/* ED States */
-
-#define ED_NEW 0x00
-#define ED_UNLINK 0x01
-#define ED_OPER 0x02
-#define ED_DEL 0x04
-#define ED_URB_DEL 0x08
-
-/* usb_ohci_ed */
-struct ed {
- __u32 hwINFO;
- __u32 hwTailP;
- __u32 hwHeadP;
- __u32 hwNextED;
-
- struct ed * ed_prev;
- __u8 int_period;
- __u8 int_branch;
- __u8 int_load;
- __u8 int_interval;
- __u8 state;
- __u8 type;
- __u16 last_iso;
- struct ed * ed_rm_list;
-
- dma_addr_t dma;
- __u32 unused[3];
-} __attribute((aligned(16)));
-typedef struct ed ed_t;
-
-
-/* TD info field */
-#define TD_CC 0xf0000000
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC 0x0C000000
-#define TD_T 0x03000000
-#define TD_T_DATA0 0x02000000
-#define TD_T_DATA1 0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R 0x00040000
-#define TD_DI 0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP 0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN 0x00100000
-#define TD_DP_OUT 0x00080000
-
-#define TD_ISO 0x00010000
-#define TD_DEL 0x00020000
-
-/* CC Codes */
-#define TD_CC_NOERROR 0x00
-#define TD_CC_CRC 0x01
-#define TD_CC_BITSTUFFING 0x02
-#define TD_CC_DATATOGGLEM 0x03
-#define TD_CC_STALL 0x04
-#define TD_DEVNOTRESP 0x05
-#define TD_PIDCHECKFAIL 0x06
-#define TD_UNEXPECTEDPID 0x07
-#define TD_DATAOVERRUN 0x08
-#define TD_DATAUNDERRUN 0x09
-#define TD_BUFFEROVERRUN 0x0C
-#define TD_BUFFERUNDERRUN 0x0D
-#define TD_NOTACCESSED 0x0F
-
-
-#define MAXPSW 1
-
-struct td {
- __u32 hwINFO;
- __u32 hwCBP; /* Current Buffer Pointer */
- __u32 hwNextTD; /* Next TD Pointer */
- __u32 hwBE; /* Memory Buffer End Pointer */
-
- __u16 hwPSW[MAXPSW];
- __u8 unused;
- __u8 index;
- struct ed * ed;
- struct td * next_dl_td;
- struct urb * urb;
-
- dma_addr_t td_dma;
- dma_addr_t data_dma;
- __u32 unused2[2];
-} __attribute((aligned(32))); /* normally 16, iso needs 32 */
-typedef struct td td_t;
-
-#define OHCI_ED_SKIP (1 << 14)
-
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of. It must be 256-byte aligned.
- */
-
-#define NUM_INTS 32 /* part of the OHCI standard */
-struct ohci_hcca {
- __u32 int_table[NUM_INTS]; /* Interrupt ED table */
- __u16 frame_no; /* current frame number */
- __u16 pad1; /* set to 0 on each frame_no change */
- __u32 done_head; /* info returned for an interrupt */
- u8 reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-
-/*
- * Maximum number of root hub ports.
- */
-#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region. This is Memory Mapped I/O. You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
- /* control and status registers */
- __u32 revision;
- __u32 control;
- __u32 cmdstatus;
- __u32 intrstatus;
- __u32 intrenable;
- __u32 intrdisable;
- /* memory pointers */
- __u32 hcca;
- __u32 ed_periodcurrent;
- __u32 ed_controlhead;
- __u32 ed_controlcurrent;
- __u32 ed_bulkhead;
- __u32 ed_bulkcurrent;
- __u32 donehead;
- /* frame counters */
- __u32 fminterval;
- __u32 fmremaining;
- __u32 fmnumber;
- __u32 periodicstart;
- __u32 lsthresh;
- /* Root hub ports */
- struct ohci_roothub_regs {
- __u32 a;
- __u32 b;
- __u32 status;
- __u32 portstatus[MAX_ROOT_PORTS];
- } roothub;
-} __attribute((aligned(32)));
-
-
-/* OHCI CONTROL AND STATUS REGISTER MASKS */
-
-/*
- * HcControl (control) register masks
- */
-#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
-#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
-#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
-#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
-#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
-#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
-#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
-#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
-#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
-
-/* pre-shifted values for HCFS */
-# define OHCI_USB_RESET (0 << 6)
-# define OHCI_USB_RESUME (1 << 6)
-# define OHCI_USB_OPER (2 << 6)
-# define OHCI_USB_SUSPEND (3 << 6)
-
-/*
- * HcCommandStatus (cmdstatus) register masks
- */
-#define OHCI_HCR (1 << 0) /* host controller reset */
-#define OHCI_CLF (1 << 1) /* control list filled */
-#define OHCI_BLF (1 << 2) /* bulk list filled */
-#define OHCI_OCR (1 << 3) /* ownership change request */
-#define OHCI_SOC (3 << 16) /* scheduling overrun count */
-
-/*
- * masks used with interrupt registers:
- * HcInterruptStatus (intrstatus)
- * HcInterruptEnable (intrenable)
- * HcInterruptDisable (intrdisable)
- */
-#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
-#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
-#define OHCI_INTR_SF (1 << 2) /* start frame */
-#define OHCI_INTR_RD (1 << 3) /* resume detect */
-#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
-#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
-#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
-#define OHCI_INTR_OC (1 << 30) /* ownership change */
-#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
-
-
-
-/* Virtual Root HUB */
-struct virt_root_hub {
- int devnum; /* Address of Root Hub endpoint */
- void * urb;
- void * int_addr;
- int send;
- int interval;
- struct timer_list rh_int_timer;
-};
-
-
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
-
-/* destination of request */
-#define RH_INTERFACE 0x01
-#define RH_ENDPOINT 0x02
-#define RH_OTHER 0x03
-
-#define RH_CLASS 0x20
-#define RH_VENDOR 0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS 0x0080
-#define RH_CLEAR_FEATURE 0x0100
-#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
-#define RH_SET_DESCRIPTOR 0x0700
-#define RH_GET_CONFIGURATION 0x0880
-#define RH_SET_CONFIGURATION 0x0900
-#define RH_GET_STATE 0x0280
-#define RH_GET_INTERFACE 0x0A80
-#define RH_SET_INTERFACE 0x0B00
-#define RH_SYNC_FRAME 0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP 0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION 0x00
-#define RH_PORT_ENABLE 0x01
-#define RH_PORT_SUSPEND 0x02
-#define RH_PORT_OVER_CURRENT 0x03
-#define RH_PORT_RESET 0x04
-#define RH_PORT_POWER 0x08
-#define RH_PORT_LOW_SPEED 0x09
-
-#define RH_C_PORT_CONNECTION 0x10
-#define RH_C_PORT_ENABLE 0x11
-#define RH_C_PORT_SUSPEND 0x12
-#define RH_C_PORT_OVER_CURRENT 0x13
-#define RH_C_PORT_RESET 0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER 0x00
-#define RH_C_HUB_OVER_CURRENT 0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP 0x00
-#define RH_ENDPOINT_STALL 0x01
-
-#define RH_ACK 0x01
-#define RH_REQ_ERR -1
-#define RH_NACK 0x00
-
-
-/* OHCI ROOT HUB REGISTER MASKS */
-
-/* roothub.portstatus [i] bits */
-#define RH_PS_CCS 0x00000001 /* current connect status */
-#define RH_PS_PES 0x00000002 /* port enable status*/
-#define RH_PS_PSS 0x00000004 /* port suspend status */
-#define RH_PS_POCI 0x00000008 /* port over current indicator */
-#define RH_PS_PRS 0x00000010 /* port reset status */
-#define RH_PS_PPS 0x00000100 /* port power status */
-#define RH_PS_LSDA 0x00000200 /* low speed device attached */
-#define RH_PS_CSC 0x00010000 /* connect status change */
-#define RH_PS_PESC 0x00020000 /* port enable status change */
-#define RH_PS_PSSC 0x00040000 /* port suspend status change */
-#define RH_PS_OCIC 0x00080000 /* over current indicator change */
-#define RH_PS_PRSC 0x00100000 /* port reset status change */
-
-/* roothub.status bits */
-#define RH_HS_LPS 0x00000001 /* local power status */
-#define RH_HS_OCI 0x00000002 /* over current indicator */
-#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
-#define RH_HS_LPSC 0x00010000 /* local power status change */
-#define RH_HS_OCIC 0x00020000 /* over current indicator change */
-#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
-
-/* roothub.b masks */
-#define RH_B_DR 0x0000ffff /* device removable flags */
-#define RH_B_PPCM 0xffff0000 /* port power control mask */
-
-/* roothub.a masks */
-#define RH_A_NDP (0xff << 0) /* number of downstream ports */
-#define RH_A_PSM (1 << 8) /* power switching mode */
-#define RH_A_NPS (1 << 9) /* no power switching */
-#define RH_A_DT (1 << 10) /* device type (mbz) */
-#define RH_A_OCPM (1 << 11) /* over current protection mode */
-#define RH_A_NOCP (1 << 12) /* no over current protection */
-#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
-
-/* urb */
-typedef struct
-{
- ed_t * ed;
- __u16 length; // number of tds associated with this request
- __u16 td_cnt; // number of tds already serviced
- int state;
- wait_queue_head_t * wait;
- td_t * td[0]; // list pointer to all corresponding TDs associated with this request
-
-} urb_priv_t;
-#define URB_DEL 1
-
-
-/* Hash struct used for TD/ED hashing */
-struct hash_t {
- void *virt;
- dma_addr_t dma;
- struct hash_t *next; // chaining for collision cases
-};
-
-/* List of TD/ED hash entries */
-struct hash_list_t {
- struct hash_t *head;
- struct hash_t *tail;
-};
-
-#define TD_HASH_SIZE 64 /* power'o'two */
-#define ED_HASH_SIZE 64 /* power'o'two */
-
-#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
-#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
-
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-
-
-typedef struct ohci {
- struct ohci_hcca *hcca; /* hcca */
- dma_addr_t hcca_dma;
-
- int irq;
- int disabled; /* e.g. got a UE, we're hung */
- int sleeping;
- atomic_t resume_count; /* defending against multiple resumes */
- unsigned long flags; /* for HC bugs */
-#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
-
- struct ohci_regs * regs; /* OHCI controller's memory */
- struct list_head ohci_hcd_list; /* list of all ohci_hcd */
-
- struct ohci * next; // chain of ohci device contexts
- struct list_head timeout_list;
- // struct list_head urb_list; // list of all pending urbs
- // spinlock_t urb_list_lock; // lock to keep consistency
-
- int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/
- ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */
- ed_t * ed_bulktail; /* last endpoint of bulk list */
- ed_t * ed_controltail; /* last endpoint of control list */
- ed_t * ed_isotail; /* last endpoint of iso list */
- int intrstatus;
- __u32 hc_control; /* copy of the hc control reg */
- struct usb_bus * bus;
- struct usb_device * dev[128];
- struct virt_root_hub rh;
-
- /* PCI device handle, settings, ... */
- struct pci_dev *ohci_dev;
- const char *slot_name;
- u8 pci_latency;
- struct pci_pool *td_cache;
- struct pci_pool *dev_cache;
- struct hash_list_t td_hash[TD_HASH_SIZE];
- struct hash_list_t ed_hash[ED_HASH_SIZE];
-
-} ohci_t;
-
-#define NUM_EDS 32 /* num of preallocated endpoint descriptors */
-
-struct ohci_device {
- ed_t ed[NUM_EDS];
- dma_addr_t dma;
- int ed_cnt;
- wait_queue_head_t * wait;
-};
-
-// #define ohci_to_usb(ohci) ((ohci)->usb)
-#define usb_to_ohci(usb) ((struct ohci_device *)(usb)->hcpriv)
-
-/* For initializing controller (mask in an HCFS mode too) */
-#define OHCI_CONTROL_INIT \
- (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-
-/* hcd */
-/* endpoint */
-static int ep_link(ohci_t * ohci, ed_t * ed);
-static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
-static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
-/* td */
-static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, struct urb * urb, int index);
-static void td_submit_urb(struct urb * urb);
-/* root hub */
-static int rh_submit_urb(struct urb * urb);
-static int rh_unlink_urb(struct urb * urb);
-static int rh_init_int_timer(struct urb * urb);
-
-/*-------------------------------------------------------------------------*/
-
-#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
-
-#ifdef DEBUG
-# define OHCI_MEM_FLAGS SLAB_POISON
-#else
-# define OHCI_MEM_FLAGS 0
-#endif
-
-
-/* Recover a TD/ED using its collision chain */
-static void *
-dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
-{
- struct hash_t * scan = entry->head;
- while (scan && scan->dma != dma)
- scan = scan->next;
- if (!scan)
- BUG();
- return scan->virt;
-}
-
-static struct ed *
-dma_to_ed (struct ohci * hc, dma_addr_t ed_dma)
-{
- return (struct ed *) dma_to_ed_td(&(hc->ed_hash[ED_HASH_FUNC(ed_dma)]),
- ed_dma);
-}
-
-static struct td *
-dma_to_td (struct ohci * hc, dma_addr_t td_dma)
-{
- return (struct td *) dma_to_ed_td(&(hc->td_hash[TD_HASH_FUNC(td_dma)]),
- td_dma);
-}
-
-/* Add a hash entry for a TD/ED; return true on success */
-static int
-hash_add_ed_td(struct hash_list_t * entry, void * virt, dma_addr_t dma)
-{
- struct hash_t * scan;
-
- scan = (struct hash_t *)kmalloc(sizeof(struct hash_t), ALLOC_FLAGS);
- if (!scan)
- return 0;
-
- if (!entry->tail) {
- entry->head = entry->tail = scan;
- } else {
- entry->tail->next = scan;
- entry->tail = scan;
- }
-
- scan->virt = virt;
- scan->dma = dma;
- scan->next = NULL;
- return 1;
-}
-
-static int
-hash_add_ed (struct ohci * hc, struct ed * ed)
-{
- return hash_add_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]),
- ed, ed->dma);
-}
-
-static int
-hash_add_td (struct ohci * hc, struct td * td)
-{
- return hash_add_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]),
- td, td->td_dma);
-}
-
-
-static void
-hash_free_ed_td (struct hash_list_t * entry, void * virt)
-{
- struct hash_t *scan, *prev;
- scan = prev = entry->head;
-
- // Find and unlink hash entry
- while (scan && scan->virt != virt) {
- prev = scan;
- scan = scan->next;
- }
- if (scan) {
- if (scan == entry->head) {
- if (entry->head == entry->tail)
- entry->head = entry->tail = NULL;
- else
- entry->head = scan->next;
- } else if (scan == entry->tail) {
- entry->tail = prev;
- prev->next = NULL;
- } else
- prev->next = scan->next;
- kfree(scan);
- }
-}
-
-static void
-hash_free_ed (struct ohci * hc, struct ed * ed)
-{
- hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
-}
-
-static void
-hash_free_td (struct ohci * hc, struct td * td)
-{
- hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
-}
-
-
-static int ohci_mem_init (struct ohci *ohci)
-{
- ohci->td_cache = pci_pool_create ("ohci_td", ohci->ohci_dev,
- sizeof (struct td),
- 32 /* byte alignment */,
- 0 /* no page-crossing issues */,
- GFP_KERNEL | OHCI_MEM_FLAGS);
- if (!ohci->td_cache)
- return -ENOMEM;
- ohci->dev_cache = pci_pool_create ("ohci_dev", ohci->ohci_dev,
- sizeof (struct ohci_device),
- 16 /* byte alignment */,
- 0 /* no page-crossing issues */,
- GFP_KERNEL | OHCI_MEM_FLAGS);
- if (!ohci->dev_cache)
- return -ENOMEM;
- return 0;
-}
-
-static void ohci_mem_cleanup (struct ohci *ohci)
-{
- if (ohci->td_cache) {
- pci_pool_destroy (ohci->td_cache);
- ohci->td_cache = 0;
- }
- if (ohci->dev_cache) {
- pci_pool_destroy (ohci->dev_cache);
- ohci->dev_cache = 0;
- }
-}
-
-/* TDs ... */
-static struct td *
-td_alloc (struct ohci *hc, int mem_flags)
-{
- dma_addr_t dma;
- struct td *td;
-
- td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
- if (td) {
- td->td_dma = dma;
-
- /* hash it for later reverse mapping */
- if (!hash_add_td (hc, td)) {
- pci_pool_free (hc->td_cache, td, dma);
- return NULL;
- }
- }
- return td;
-}
-
-static inline void
-td_free (struct ohci *hc, struct td *td)
-{
- hash_free_td (hc, td);
- pci_pool_free (hc->td_cache, td, td->td_dma);
-}
-
-
-/* DEV + EDs ... only the EDs need to be consistent */
-static struct ohci_device *
-dev_alloc (struct ohci *hc, int mem_flags)
-{
- dma_addr_t dma;
- struct ohci_device *dev;
- int i, offset;
-
- dev = pci_pool_alloc (hc->dev_cache, mem_flags, &dma);
- if (dev) {
- memset (dev, 0, sizeof (*dev));
- dev->dma = dma;
- offset = ((char *)&dev->ed) - ((char *)dev);
- for (i = 0; i < NUM_EDS; i++, offset += sizeof dev->ed [0])
- dev->ed [i].dma = dma + offset;
- /* add to hashtable if used */
- }
- return dev;
-}
-
-static inline void
-dev_free (struct ohci *hc, struct ohci_device *dev)
-{
- pci_pool_free (hc->dev_cache, dev, dev->dma);
-}
-
-extern spinlock_t usb_ed_lock;
-extern void dl_done_list (ohci_t * ohci, td_t * td_list);
-extern td_t * dl_reverse_done_list (ohci_t * ohci);
-
-
diff --git a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c
index 58c311db3c4e..5d02c88fcf1b 100644
--- a/drivers/usb/image/hpusbscsi.c
+++ b/drivers/usb/image/hpusbscsi.c
@@ -164,10 +164,10 @@ MODULE_LICENSE("GPL");
static struct usb_driver hpusbscsi_usb_driver = {
- name:"hpusbscsi",
- probe:hpusbscsi_usb_probe,
- disconnect:hpusbscsi_usb_disconnect,
- id_table:hpusbscsi_usb_ids,
+ .name ="hpusbscsi",
+ .probe =hpusbscsi_usb_probe,
+ .disconnect =hpusbscsi_usb_disconnect,
+ .id_table =hpusbscsi_usb_ids,
};
/* module initialisation */
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 6514054a8813..662dba287d3d 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -923,11 +923,11 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t l
/* File Operations of this drivers */
static struct file_operations mdc800_device_ops =
{
- owner: THIS_MODULE,
- read: mdc800_device_read,
- write: mdc800_device_write,
- open: mdc800_device_open,
- release: mdc800_device_release,
+ .owner = THIS_MODULE,
+ .read = mdc800_device_read,
+ .write = mdc800_device_write,
+ .open = mdc800_device_open,
+ .release = mdc800_device_release,
};
@@ -943,11 +943,11 @@ MODULE_DEVICE_TABLE (usb, mdc800_table);
*/
static struct usb_driver mdc800_usb_driver =
{
- owner: THIS_MODULE,
- name: "mdc800",
- probe: mdc800_usb_probe,
- disconnect: mdc800_usb_disconnect,
- id_table: mdc800_table
+ .owner = THIS_MODULE,
+ .name = "mdc800",
+ .probe = mdc800_usb_probe,
+ .disconnect = mdc800_usb_disconnect,
+ .id_table = mdc800_table
};
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 6b2591e7e071..dd454fd08fab 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -161,10 +161,10 @@ static void mts_usb_disconnect(struct usb_device *dev, void *ptr);
static struct usb_device_id mts_usb_ids [];
static struct usb_driver mts_usb_driver = {
- name: "microtekX6",
- probe: mts_usb_probe,
- disconnect: mts_usb_disconnect,
- id_table: mts_usb_ids,
+ .name = "microtekX6",
+ .probe = mts_usb_probe,
+ .disconnect = mts_usb_disconnect,
+ .id_table = mts_usb_ids,
};
@@ -743,22 +743,22 @@ out:
static Scsi_Host_Template mts_scsi_host_template = {
- name: "microtekX6",
- detect: mts_scsi_detect,
- release: mts_scsi_release,
- queuecommand: mts_scsi_queuecommand,
-
- eh_abort_handler: mts_scsi_abort,
- eh_host_reset_handler: mts_scsi_host_reset,
-
- sg_tablesize: SG_ALL,
- can_queue: 1,
- this_id: -1,
- cmd_per_lun: 1,
- present: 0,
- unchecked_isa_dma: FALSE,
- use_clustering: TRUE,
- emulated: TRUE
+ .name = "microtekX6",
+ .detect = mts_scsi_detect,
+ .release = mts_scsi_release,
+ .queuecommand = mts_scsi_queuecommand,
+
+ .eh_abort_handler = mts_scsi_abort,
+ .eh_host_reset_handler =mts_scsi_host_reset,
+
+ .sg_tablesize = SG_ALL,
+ .can_queue = 1,
+ .this_id = -1,
+ .cmd_per_lun = 1,
+ .present = 0,
+ .unchecked_isa_dma = FALSE,
+ .use_clustering = TRUE,
+ .emulated = TRUE
};
diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
index 2bb1de40e3c0..9c9550e5cce7 100644
--- a/drivers/usb/image/scanner.c
+++ b/drivers/usb/image/scanner.c
@@ -811,11 +811,11 @@ ioctl_scanner(struct inode *inode, struct file *file,
static struct
file_operations usb_scanner_fops = {
- read: read_scanner,
- write: write_scanner,
- ioctl: ioctl_scanner,
- open: open_scanner,
- release: close_scanner,
+ .read = read_scanner,
+ .write = write_scanner,
+ .ioctl = ioctl_scanner,
+ .open = open_scanner,
+ .release = close_scanner,
};
static void *
@@ -1116,10 +1116,10 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
static struct
usb_driver scanner_driver = {
- name: "usbscanner",
- probe: probe_scanner,
- disconnect: disconnect_scanner,
- id_table: NULL, /* This would be scanner_device_ids, but we
+ .name = "usbscanner",
+ .probe = probe_scanner,
+ .disconnect = disconnect_scanner,
+ .id_table = NULL, /* This would be scanner_device_ids, but we
need to check every USB device, in case
we match a user defined vendor/product ID. */
};
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index cbed3efbb7c4..764f52074649 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -313,10 +313,10 @@ aiptek_disconnect(struct usb_device *dev, void *ptr)
}
static struct usb_driver aiptek_driver = {
- name:"aiptek",
- probe:aiptek_probe,
- disconnect:aiptek_disconnect,
- id_table:aiptek_ids,
+ .name ="aiptek",
+ .probe =aiptek_probe,
+ .disconnect =aiptek_disconnect,
+ .id_table =aiptek_ids,
};
static int __init
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 068417749db6..19b6ff130baf 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1556,10 +1556,10 @@ static struct usb_device_id hid_usb_ids [] = {
MODULE_DEVICE_TABLE (usb, hid_usb_ids);
static struct usb_driver hid_driver = {
- name: "hid",
- probe: hid_probe,
- disconnect: hid_disconnect,
- id_table: hid_usb_ids,
+ .name = "hid",
+ .probe = hid_probe,
+ .disconnect = hid_disconnect,
+ .id_table = hid_usb_ids,
};
static int __init hid_init(void)
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 563285d58541..93dcc5184758 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -657,14 +657,14 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
static struct file_operations hiddev_fops = {
- owner: THIS_MODULE,
- read: hiddev_read,
- write: hiddev_write,
- poll: hiddev_poll,
- open: hiddev_open,
- release: hiddev_release,
- ioctl: hiddev_ioctl,
- fasync: hiddev_fasync,
+ .owner = THIS_MODULE,
+ .read = hiddev_read,
+ .write = hiddev_write,
+ .poll = hiddev_poll,
+ .open = hiddev_open,
+ .release = hiddev_release,
+ .ioctl = hiddev_ioctl,
+ .fasync = hiddev_fasync,
};
/*
@@ -759,8 +759,8 @@ static void *hiddev_usbd_probe(struct usb_device *dev, unsigned int ifnum,
static /* const */ struct usb_driver hiddev_driver = {
- name: "hiddev",
- probe: hiddev_usbd_probe,
+ .name = "hiddev",
+ .probe = hiddev_usbd_probe,
};
int __init hiddev_init(void)
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
index 378cfa3c0717..9dd719300002 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -334,10 +334,10 @@ static struct usb_device_id powermate_devices [] = {
MODULE_DEVICE_TABLE (usb, powermate_devices);
static struct usb_driver powermate_driver = {
- name: "powermate",
- probe: powermate_probe,
- disconnect: powermate_disconnect,
- id_table: powermate_devices,
+ .name = "powermate",
+ .probe = powermate_probe,
+ .disconnect = powermate_disconnect,
+ .id_table = powermate_devices,
};
int powermate_init(void)
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index 31edd4e7b52b..b9b3e0923cb5 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -287,10 +287,10 @@ static struct usb_device_id usb_kbd_id_table [] = {
MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
static struct usb_driver usb_kbd_driver = {
- name: "keyboard",
- probe: usb_kbd_probe,
- disconnect: usb_kbd_disconnect,
- id_table: usb_kbd_id_table,
+ .name = "keyboard",
+ .probe = usb_kbd_probe,
+ .disconnect = usb_kbd_disconnect,
+ .id_table = usb_kbd_id_table,
};
static int __init usb_kbd_init(void)
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 22673b42d60a..cfec38752242 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -195,10 +195,10 @@ static struct usb_device_id usb_mouse_id_table [] = {
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = {
- name: "usb_mouse",
- probe: usb_mouse_probe,
- disconnect: usb_mouse_disconnect,
- id_table: usb_mouse_id_table,
+ .name = "usb_mouse",
+ .probe = usb_mouse_probe,
+ .disconnect = usb_mouse_disconnect,
+ .id_table = usb_mouse_id_table,
};
static int __init usb_mouse_init(void)
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
index 74bfb073e78d..2d1c8f4ec2d7 100644
--- a/drivers/usb/input/wacom.c
+++ b/drivers/usb/input/wacom.c
@@ -428,10 +428,10 @@ static void wacom_disconnect(struct usb_device *dev, void *ptr)
}
static struct usb_driver wacom_driver = {
- name: "wacom",
- probe: wacom_probe,
- disconnect: wacom_disconnect,
- id_table: wacom_ids,
+ .name = "wacom",
+ .probe = wacom_probe,
+ .disconnect = wacom_disconnect,
+ .id_table = wacom_ids,
};
static int __init wacom_init(void)
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
index ee3ae7fbd648..ace599597455 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/usb/input/xpad.c
@@ -304,10 +304,10 @@ static void xpad_disconnect(struct usb_device *udev, void *ptr)
}
static struct usb_driver xpad_driver = {
- name: "xpad",
- probe: xpad_probe,
- disconnect: xpad_disconnect,
- id_table: xpad_table,
+ .name = "xpad",
+ .probe = xpad_probe,
+ .disconnect = xpad_disconnect,
+ .id_table = xpad_table,
};
static int __init usb_xpad_init(void)
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
index 3658e693484f..50d16e4fd6c7 100644
--- a/drivers/usb/media/dabusb.c
+++ b/drivers/usb/media/dabusb.c
@@ -704,12 +704,12 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
static struct file_operations dabusb_fops =
{
- owner: THIS_MODULE,
- llseek: no_llseek,
- read: dabusb_read,
- ioctl: dabusb_ioctl,
- open: dabusb_open,
- release: dabusb_release,
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = dabusb_read,
+ .ioctl = dabusb_ioctl,
+ .open = dabusb_open,
+ .release = dabusb_release,
};
static int dabusb_find_struct (void)
@@ -806,10 +806,10 @@ MODULE_DEVICE_TABLE (usb, dabusb_ids);
static struct usb_driver dabusb_driver =
{
- name: "dabusb",
- probe: dabusb_probe,
- disconnect: dabusb_disconnect,
- id_table: dabusb_ids,
+ .name = "dabusb",
+ .probe = dabusb_probe,
+ .disconnect = dabusb_disconnect,
+ .id_table = dabusb_ids,
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c
index f4bdcaaa1fd3..ddaef26aa8eb 100644
--- a/drivers/usb/media/dsbr100.c
+++ b/drivers/usb/media/dsbr100.c
@@ -100,19 +100,19 @@ typedef struct
static struct file_operations usb_dsbr100_fops = {
- owner: THIS_MODULE,
- open: usb_dsbr100_open,
- release: usb_dsbr100_close,
- ioctl: usb_dsbr100_ioctl,
- llseek: no_llseek,
+ .owner = THIS_MODULE,
+ .open = usb_dsbr100_open,
+ .release = usb_dsbr100_close,
+ .ioctl = usb_dsbr100_ioctl,
+ .llseek = no_llseek,
};
static struct video_device usb_dsbr100_radio=
{
- owner: THIS_MODULE,
- name: "D-Link DSB R-100 USB radio",
- type: VID_TYPE_TUNER,
- hardware: VID_HARDWARE_AZTECH,
- fops: &usb_dsbr100_fops,
+ .owner = THIS_MODULE,
+ .name = "D-Link DSB R-100 USB radio",
+ .type = VID_TYPE_TUNER,
+ .hardware = VID_HARDWARE_AZTECH,
+ .fops = &usb_dsbr100_fops,
};
static int users = 0;
@@ -125,10 +125,10 @@ static struct usb_device_id usb_dsbr100_table [] = {
MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
static struct usb_driver usb_dsbr100_driver = {
- name: "dsbr100",
- probe: usb_dsbr100_probe,
- disconnect: usb_dsbr100_disconnect,
- id_table: usb_dsbr100_table,
+ .name = "dsbr100",
+ .probe = usb_dsbr100_probe,
+ .disconnect = usb_dsbr100_disconnect,
+ .id_table = usb_dsbr100_table,
};
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
index e5b3f9144fb4..9dff57ad4f38 100644
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -9,7 +9,6 @@
* OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
* Changes by Claudio Matsuoka <claudio@conectiva.com>
* Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * Kernel I2C interface adapted from nt1003 driver
* URB error messages from pwc driver by Nemosoft
* generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
* Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
@@ -61,7 +60,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.60a for Linux 2.5"
+#define DRIVER_VERSION "v1.61 for Linux 2.5"
#define EMAIL "mmcclell@bigfoot.com"
#define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
@@ -72,7 +71,6 @@
#define ENABLE_Y_QUANTABLE 1
#define ENABLE_UV_QUANTABLE 1
-/* If you change this, you must also change the MODULE_PARM definition */
#define OV511_MAX_UNIT_VIDEO 16
/* Pixel count * bytes per YUV420 pixel (1.5) */
@@ -127,7 +125,6 @@ static int framedrop = -1;
static int fastset;
static int force_palette;
-static int tuner = -1;
static int backlight;
static int unit_video[OV511_MAX_UNIT_VIDEO];
static int remove_zeros;
@@ -194,11 +191,9 @@ MODULE_PARM(fastset, "i");
MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
MODULE_PARM(force_palette, "i");
MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-MODULE_PARM(tuner, "i");
-MODULE_PARM_DESC(tuner, "Set tuner type, if not autodetected");
MODULE_PARM(backlight, "i");
MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-MODULE_PARM(unit_video, "0-16i");
+MODULE_PARM(unit_video, "1-" __MODULE_STRING(OV511_MAX_UNIT_VIDEO) "i");
MODULE_PARM_DESC(unit_video,
"Force use of specific minor number(s). 0 is not allowed.");
MODULE_PARM(remove_zeros, "i");
@@ -337,12 +332,14 @@ static struct symbolic_list urb_errlist[] = {
**********************************************************************/
static void ov51x_clear_snapshot(struct usb_ov511 *);
-static int ov51x_check_snapshot(struct usb_ov511 *);
-static inline int sensor_get_picture(struct usb_ov511 *,
+static inline int sensor_get_picture(struct usb_ov511 *,
struct video_picture *);
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
+static int ov51x_check_snapshot(struct usb_ov511 *);
+#endif
/**********************************************************************
* Memory management
@@ -351,7 +348,7 @@ static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
/* Here we want the physical address of the memory.
* This is used when initializing the contents of the area.
*/
-static inline unsigned long
+static inline unsigned long
kvirt_to_pa(unsigned long adr)
{
unsigned long kva, ret;
@@ -384,7 +381,7 @@ rvmalloc(unsigned long size)
return mem;
}
-static void
+static void
rvfree(void *mem, unsigned long size)
{
unsigned long adr;
@@ -412,13 +409,13 @@ static struct proc_dir_entry *ov511_proc_entry = NULL;
extern struct proc_dir_entry *video_proc_entry;
static struct file_operations ov511_control_fops = {
- ioctl: ov51x_control_ioctl,
+ .ioctl = ov51x_control_ioctl,
};
#define YES_NO(x) ((x) ? "yes" : "no")
/* /proc/video/ov511/<minor#>/info */
-static int
+static int
ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
@@ -490,13 +487,13 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof,
* When the camera's button is pressed, the output of this will change from a
* 0 to a 1 (ASCII). It will retain this value until it is read, after which
* it will reset to zero.
- *
+ *
* SECURITY NOTE: Since reading this file can change the state of the snapshot
* status, it is important for applications that open it to keep it locked
* against access by other processes, using flock() or a similar mechanism. No
* locking is provided by this driver.
*/
-static int
+static int
ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
@@ -528,7 +525,7 @@ ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof,
return len;
}
-static void
+static void
create_proc_ov511_cam(struct usb_ov511 *ov)
{
char dirname[10];
@@ -579,11 +576,11 @@ create_proc_ov511_cam(struct usb_ov511 *ov)
unlock_kernel();
}
-static void
+static void
destroy_proc_ov511_cam(struct usb_ov511 *ov)
{
char dirname[10];
-
+
if (!ov || !ov->proc_devdir)
return;
@@ -616,7 +613,7 @@ destroy_proc_ov511_cam(struct usb_ov511 *ov)
ov->proc_devdir = NULL;
}
-static void
+static void
proc_ov511_create(void)
{
/* No current standard here. Alan prefers /proc/video/ as it keeps
@@ -637,7 +634,7 @@ proc_ov511_create(void)
err("Unable to create /proc/video/ov511");
}
-static void
+static void
proc_ov511_destroy(void)
{
PDEBUG(3, "removing /proc/video/ov511");
@@ -656,7 +653,7 @@ proc_ov511_destroy(void)
**********************************************************************/
/* Write an OV51x register */
-static int
+static int
reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
{
int rc;
@@ -669,7 +666,7 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
usb_sndctrlpipe(ov->dev, 0),
(ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, &ov->cbuf[0], 1, HZ);
+ 0, (__u16)reg, &ov->cbuf[0], 1, HZ);
up(&ov->cbuf_lock);
if (rc < 0)
@@ -680,7 +677,7 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
/* Read from an OV51x register */
/* returns: negative is error, pos or zero is data */
-static int
+static int
reg_r(struct usb_ov511 *ov, unsigned char reg)
{
int rc;
@@ -691,13 +688,13 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
(ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, (__u16)reg, &ov->cbuf[0], 1, HZ);
-
- PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
-
- if (rc < 0)
+
+ if (rc < 0) {
err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
- else
- rc = ov->cbuf[0];
+ } else {
+ rc = ov->cbuf[0];
+ PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
+ }
up(&ov->cbuf_lock);
@@ -707,10 +704,10 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
/*
* Writes bits at positions specified by mask to an OV51x reg. Bits that are in
* the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
+ * that are in the same position as 0's in "mask" are preserved, regardless
* of their respective state in "value".
*/
-static int
+static int
reg_w_mask(struct usb_ov511 *ov,
unsigned char reg,
unsigned char value,
@@ -735,7 +732,7 @@ reg_w_mask(struct usb_ov511 *ov,
* Writes multiple (n) byte value to a single register. Only valid with certain
* registers (0x30 and 0xc4 - 0xce).
*/
-static int
+static int
ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
{
int rc;
@@ -760,7 +757,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
return rc;
}
-static int
+static int
ov511_upload_quan_tables(struct usb_ov511 *ov)
{
unsigned char *pYTable = yQuanTable511;
@@ -770,10 +767,8 @@ ov511_upload_quan_tables(struct usb_ov511 *ov)
PDEBUG(4, "Uploading quantization tables");
- for (i = 0; i < OV511_QUANTABLESIZE / 2; i++)
- {
- if (ENABLE_Y_QUANTABLE)
- {
+ for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
+ if (ENABLE_Y_QUANTABLE) {
val0 = *pYTable++;
val1 = *pYTable++;
val0 &= 0x0f;
@@ -784,8 +779,7 @@ ov511_upload_quan_tables(struct usb_ov511 *ov)
return rc;
}
- if (ENABLE_UV_QUANTABLE)
- {
+ if (ENABLE_UV_QUANTABLE) {
val0 = *pUVTable++;
val1 = *pUVTable++;
val0 &= 0x0f;
@@ -803,7 +797,7 @@ ov511_upload_quan_tables(struct usb_ov511 *ov)
}
/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int
+static int
ov518_upload_quan_tables(struct usb_ov511 *ov)
{
unsigned char *pYTable = yQuanTable518;
@@ -813,10 +807,8 @@ ov518_upload_quan_tables(struct usb_ov511 *ov)
PDEBUG(4, "Uploading quantization tables");
- for (i = 0; i < OV518_QUANTABLESIZE / 2; i++)
- {
- if (ENABLE_Y_QUANTABLE)
- {
+ for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
+ if (ENABLE_Y_QUANTABLE) {
val0 = *pYTable++;
val1 = *pYTable++;
val0 &= 0x0f;
@@ -827,8 +819,7 @@ ov518_upload_quan_tables(struct usb_ov511 *ov)
return rc;
}
- if (ENABLE_UV_QUANTABLE)
- {
+ if (ENABLE_UV_QUANTABLE) {
val0 = *pUVTable++;
val1 = *pUVTable++;
val0 &= 0x0f;
@@ -845,16 +836,16 @@ ov518_upload_quan_tables(struct usb_ov511 *ov)
return 0;
}
-static int
+static int
ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
{
int rc;
-
+
/* Setting bit 0 not allowed on 518/518Plus */
if (ov->bclass == BCL_OV518)
reset_type &= 0xfe;
- PDEBUG(4, "Reset: type=0x%X", reset_type);
+ PDEBUG(4, "Reset: type=0x%02X", reset_type);
rc = reg_w(ov, R51x_SYS_RESET, reset_type);
rc = reg_w(ov, R51x_SYS_RESET, 0);
@@ -876,7 +867,7 @@ ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
* This is normally only called from i2c_w(). Note that this function
* always succeeds regardless of whether the sensor is present and working.
*/
-static int
+static int
ov518_i2c_write_internal(struct usb_ov511 *ov,
unsigned char reg,
unsigned char value)
@@ -901,7 +892,7 @@ ov518_i2c_write_internal(struct usb_ov511 *ov,
}
/* NOTE: Do not call this function directly! */
-static int
+static int
ov511_i2c_write_internal(struct usb_ov511 *ov,
unsigned char reg,
unsigned char value)
@@ -917,7 +908,7 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
if (rc < 0) return rc;
/* Write "value" to I2C data port of OV511 */
- rc = reg_w(ov, R51x_I2C_DATA, value);
+ rc = reg_w(ov, R51x_I2C_DATA, value);
if (rc < 0) return rc;
/* Initiate 3-byte write cycle */
@@ -931,7 +922,7 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
if ((rc&2) == 0) /* Ack? */
break;
#if 0
- /* I2C abort */
+ /* I2C abort */
reg_w(ov, R511_I2C_CTL, 0x10);
#endif
if (--retries < 0) {
@@ -948,7 +939,7 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
* This is normally only called from i2c_r(). Note that this function
* always succeeds regardless of whether the sensor is present and working.
*/
-static int
+static int
ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
{
int rc, value;
@@ -974,7 +965,7 @@ ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
/* NOTE: Do not call this function directly!
* returns: negative is error, pos or zero is data */
-static int
+static int
ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
{
int rc, value, retries;
@@ -996,7 +987,7 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
if ((rc&2) == 0) /* Ack? */
break;
- /* I2C abort */
+ /* I2C abort */
reg_w(ov, R511_I2C_CTL, 0x10);
if (--retries < 0) {
@@ -1018,7 +1009,7 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
if ((rc&2) == 0) /* Ack? */
break;
- /* I2C abort */
+ /* I2C abort */
rc = reg_w(ov, R511_I2C_CTL, 0x10);
if (rc < 0) return rc;
@@ -1031,17 +1022,17 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
value = reg_r(ov, R51x_I2C_DATA);
PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
+
/* This is needed to make i2c_w() work */
rc = reg_w(ov, R511_I2C_CTL, 0x05);
if (rc < 0)
return rc;
-
+
return value;
}
/* returns: negative is error, pos or zero is data */
-static int
+static int
i2c_r(struct usb_ov511 *ov, unsigned char reg)
{
int rc;
@@ -1058,7 +1049,7 @@ i2c_r(struct usb_ov511 *ov, unsigned char reg)
return rc;
}
-static int
+static int
i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
{
int rc;
@@ -1076,7 +1067,7 @@ i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
}
/* Do not call this function directly! */
-static int
+static int
ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
unsigned char reg,
unsigned char value,
@@ -1109,10 +1100,10 @@ ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
* the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
+ * that are in the same position as 0's in "mask" are preserved, regardless
* of their respective state in "value".
*/
-static int
+static int
i2c_w_mask(struct usb_ov511 *ov,
unsigned char reg,
unsigned char value,
@@ -1132,7 +1123,7 @@ i2c_w_mask(struct usb_ov511 *ov,
* when calling this. This should not be called from outside the i2c I/O
* functions.
*/
-static inline int
+static inline int
i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
{
int rc;
@@ -1146,8 +1137,10 @@ i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
return 0;
}
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
/* Write to a specific I2C slave ID and register, using the specified mask */
-static int
+static int
i2c_w_slave(struct usb_ov511 *ov,
unsigned char slave,
unsigned char reg,
@@ -1166,7 +1159,7 @@ i2c_w_slave(struct usb_ov511 *ov,
out:
/* Restore primary IDs */
- if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+ if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
err("Couldn't restore primary I2C slave");
up(&ov->i2c_lock);
@@ -1174,7 +1167,7 @@ out:
}
/* Read from a specific I2C slave ID and register */
-static int
+static int
i2c_r_slave(struct usb_ov511 *ov,
unsigned char slave,
unsigned char reg)
@@ -1194,15 +1187,17 @@ i2c_r_slave(struct usb_ov511 *ov,
out:
/* Restore primary IDs */
- if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+ if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
err("Couldn't restore primary I2C slave");
up(&ov->i2c_lock);
return rc;
}
+#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) */
+
/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int
+static int
ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
{
int rc;
@@ -1221,7 +1216,7 @@ out:
return rc;
}
-static int
+static int
write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
{
int rc;
@@ -1242,8 +1237,8 @@ write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
return 0;
}
-#ifdef OV511_DEBUG
-static void
+#ifdef OV511_DEBUG
+static void
dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
{
int i;
@@ -1251,18 +1246,18 @@ dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
for (i = reg1; i <= regn; i++) {
rc = i2c_r(ov, i);
- info("Sensor[0x%X] = 0x%X", i, rc);
+ info("Sensor[0x%02X] = 0x%02X", i, rc);
}
}
-static void
+static void
dump_i2c_regs(struct usb_ov511 *ov)
{
info("I2C REGS");
dump_i2c_range(ov, 0x00, 0x7C);
}
-static void
+static void
dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
{
int i;
@@ -1270,12 +1265,12 @@ dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
for (i = reg1; i <= regn; i++) {
rc = reg_r(ov, i);
- info("OV511[0x%X] = 0x%X", i, rc);
+ info("OV511[0x%02X] = 0x%02X", i, rc);
}
}
/* FIXME: Should there be an OV518 version of this? */
-static void
+static void
ov511_dump_regs(struct usb_ov511 *ov)
{
info("CAMERA INTERFACE REGS");
@@ -1302,29 +1297,15 @@ ov511_dump_regs(struct usb_ov511 *ov)
}
#endif
-/**********************************************************************
- *
- * Kernel I2C Interface (not supported with OV518/OV518+)
- *
- **********************************************************************/
-
-/* For as-yet unimplemented I2C interface */
-static void
-call_i2c_clients(struct usb_ov511 *ov, unsigned int cmd,
- void *arg)
-{
- /* Do nothing */
-}
-
/*****************************************************************************/
/* Temporarily stops OV511 from functioning. Must do this before changing
* registers while the camera is streaming */
-static inline int
+static inline int
ov51x_stop(struct usb_ov511 *ov)
{
PDEBUG(4, "stopping");
- ov->stopped = 1;
+ ov->stopped = 1;
if (ov->bclass == BCL_OV518)
return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
else
@@ -1333,12 +1314,12 @@ ov51x_stop(struct usb_ov511 *ov)
/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
* actually stopped (for performance). */
-static inline int
+static inline int
ov51x_restart(struct usb_ov511 *ov)
{
if (ov->stopped) {
PDEBUG(4, "restarting");
- ov->stopped = 0;
+ ov->stopped = 0;
/* Reinitialize the stream */
if (ov->bclass == BCL_OV518)
@@ -1351,7 +1332,7 @@ ov51x_restart(struct usb_ov511 *ov)
}
/* Resets the hardware snapshot button */
-static void
+static void
ov51x_clear_snapshot(struct usb_ov511 *ov)
{
if (ov->bclass == BCL_OV511) {
@@ -1363,12 +1344,12 @@ ov51x_clear_snapshot(struct usb_ov511 *ov)
} else {
err("clear snap: invalid bridge type");
}
-
}
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
/* Checks the status of the snapshot button. Returns 1 if it was pressed since
* it was last cleared, and zero in all other cases (including errors) */
-static int
+static int
ov51x_check_snapshot(struct usb_ov511 *ov)
{
int ret, status = 0;
@@ -1388,19 +1369,20 @@ ov51x_check_snapshot(struct usb_ov511 *ov)
return status;
}
+#endif
/* This does an initial reset of an OmniVision sensor and ensures that I2C
* is synchronized. Returns <0 for failure.
*/
-static int
+static int
init_ov_sensor(struct usb_ov511 *ov)
{
int i, success;
- /* Reset the sensor */
+ /* Reset the sensor */
if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
- /* Wait for it to initialize */
+ /* Wait for it to initialize */
schedule_timeout (1 + 150 * HZ / 1000);
for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
@@ -1410,9 +1392,9 @@ init_ov_sensor(struct usb_ov511 *ov)
continue;
}
- /* Reset the sensor */
+ /* Reset the sensor */
if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
- /* Wait for it to initialize */
+ /* Wait for it to initialize */
schedule_timeout(1 + 150 * HZ / 1000);
/* Dummy read to sync I2C */
if (i2c_r(ov, 0x00) < 0) return -EIO;
@@ -1420,13 +1402,13 @@ init_ov_sensor(struct usb_ov511 *ov)
if (!success)
return -EIO;
-
+
PDEBUG(1, "I2C synced in %d attempt(s)", i);
return 0;
}
-static int
+static int
ov511_set_packet_size(struct usb_ov511 *ov, int size)
{
int alt, mult;
@@ -1468,7 +1450,7 @@ ov511_set_packet_size(struct usb_ov511 *ov, int size)
if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
return -EIO;
-
+
if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
err("Set packet size: set interface error");
return -EBUSY;
@@ -1488,7 +1470,7 @@ ov511_set_packet_size(struct usb_ov511 *ov, int size)
/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
* optional packet number byte. The actual size *is* stored in ov->packet_size,
* though. */
-static int
+static int
ov518_set_packet_size(struct usb_ov511 *ov, int size)
{
int alt;
@@ -1550,7 +1532,6 @@ ov511_init_compression(struct usb_ov511 *ov)
int rc = 0;
if (!ov->compress_inited) {
-
reg_w(ov, 0x70, phy);
reg_w(ov, 0x71, phuv);
reg_w(ov, 0x72, pvy);
@@ -1568,7 +1549,7 @@ ov511_init_compression(struct usb_ov511 *ov)
}
ov->compress_inited = 1;
-out:
+out:
return rc;
}
@@ -1579,7 +1560,6 @@ ov518_init_compression(struct usb_ov511 *ov)
int rc = 0;
if (!ov->compress_inited) {
-
if (ov518_upload_quan_tables(ov) < 0) {
err("Error uploading quantization tables");
rc = -EIO;
@@ -1588,7 +1568,7 @@ ov518_init_compression(struct usb_ov511 *ov)
}
ov->compress_inited = 1;
-out:
+out:
return rc;
}
@@ -2130,7 +2110,7 @@ sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static inline void
+static inline void
ov51x_led_control(struct usb_ov511 *ov, int enable)
{
PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
@@ -2181,7 +2161,7 @@ sensor_set_light_freq(struct usb_ov511 *ov, int freq)
i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
i2c_w(ov, 0x2b, sixty?0x00:0xac);
i2c_w_mask(ov, 0x76, 0x01, 0x01);
- break;
+ break;
case SEN_OV6620:
case SEN_OV6630:
i2c_w(ov, 0x2b, sixty?0xa8:0x28);
@@ -2269,7 +2249,7 @@ sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
*/
static inline int
sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{
+{
PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
switch (ov->sensor) {
@@ -2281,7 +2261,7 @@ sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
case SEN_OV76BE:
case SEN_OV8600:
i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
- break;
+ break;
case SEN_OV6630:
i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
break;
@@ -2318,7 +2298,7 @@ sensor_set_backlight(struct usb_ov511 *ov, int enable)
i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
- break;
+ break;
case SEN_OV6620:
i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
@@ -2378,7 +2358,7 @@ sensor_set_mirror(struct usb_ov511 *ov, int enable)
/* Returns number of bits per pixel (regardless of where they are located;
* planar or not), or zero for unsupported format.
*/
-static inline int
+static inline int
get_depth(int palette)
{
switch (palette) {
@@ -2390,7 +2370,7 @@ get_depth(int palette)
}
/* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int
+static inline long int
get_frame_length(struct ov511_frame *frame)
{
if (!frame)
@@ -2785,12 +2765,12 @@ ov518_mode_init_regs(struct usb_ov511 *ov,
return -EINVAL;
} else {
hi_res = 0;
- }
+ }
if (ov51x_stop(ov) < 0)
return -EIO;
- /******** Set the mode ********/
+ /******** Set the mode ********/
reg_w(ov, 0x2b, 0);
reg_w(ov, 0x2c, 0);
@@ -2906,10 +2886,10 @@ mode_init_regs(struct usb_ov511 *ov,
rc = -EINVAL;
break;
case SEN_SAA7111A:
-// rc = mode_init_saa_sensor_regs(ov, width, height, mode,
+// rc = mode_init_saa_sensor_regs(ov, width, height, mode,
// sub_flag);
- PDEBUG(1, "SAA status = 0X%x", i2c_r(ov, 0x1f));
+ PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
break;
default:
err("Unknown sensor");
@@ -2952,7 +2932,7 @@ mode_init_regs(struct usb_ov511 *ov,
/* This sets the default image parameters. This is useful for apps that use
* read() and do not set these.
*/
-static int
+static int
ov51x_set_default_params(struct usb_ov511 *ov)
{
int i;
@@ -2988,7 +2968,7 @@ ov51x_set_default_params(struct usb_ov511 *ov)
**********************************************************************/
/* Set analog input port of decoder */
-static int
+static int
decoder_set_input(struct usb_ov511 *ov, int input)
{
PDEBUG(4, "port %d", input);
@@ -3010,7 +2990,7 @@ decoder_set_input(struct usb_ov511 *ov, int input)
}
/* Get ASCII name of video input */
-static int
+static int
decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
{
switch (ov->sensor) {
@@ -3022,7 +3002,6 @@ decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
sprintf(name, "CVBS-%d", input);
else // if (input < 8)
sprintf(name, "S-Video-%d", input - 4);
-
break;
}
default:
@@ -3033,7 +3012,7 @@ decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
}
/* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int
+static int
decoder_set_norm(struct usb_ov511 *ov, int norm)
{
PDEBUG(4, "%d", norm);
@@ -3048,7 +3027,7 @@ decoder_set_norm(struct usb_ov511 *ov, int norm)
reg_e = 0x00; /* NTSC M / PAL BGHI */
} else if (norm == VIDEO_MODE_PAL) {
reg_8 = 0x00; /* 50 Hz */
- reg_e = 0x00; /* NTSC M / PAL BGHI */
+ reg_e = 0x00; /* NTSC M / PAL BGHI */
} else if (norm == VIDEO_MODE_AUTO) {
reg_8 = 0x80; /* Auto field detect */
reg_e = 0x00; /* NTSC M / PAL BGHI */
@@ -3079,7 +3058,7 @@ decoder_set_norm(struct usb_ov511 *ov, int norm)
/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
* image at pOut is specified by w.
*/
-static inline void
+static inline void
make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
{
unsigned char *pOut1 = pOut;
@@ -3092,7 +3071,6 @@ make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
}
pOut += w;
}
-
}
/*
@@ -3214,7 +3192,7 @@ yuv420raw_to_yuv420p(struct ov511_frame *frame,
* accordingly. Returns -ENXIO if decompressor is not available, otherwise
* returns 0 if no other error.
*/
-static int
+static int
request_decompressor(struct usb_ov511 *ov)
{
if (!ov)
@@ -3270,7 +3248,7 @@ request_decompressor(struct usb_ov511 *ov)
/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even
* if ov->decomp_ops is NULL.
*/
-static void
+static void
release_decompressor(struct usb_ov511 *ov)
{
int released = 0; /* Did we actually do anything? */
@@ -3286,14 +3264,14 @@ release_decompressor(struct usb_ov511 *ov)
}
ov->decomp_ops = NULL;
-
+
unlock_kernel();
if (released)
PDEBUG(3, "Decompressor released");
}
-static void
+static void
decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
unsigned char *pIn0, unsigned char *pOut0)
{
@@ -3303,7 +3281,7 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd);
- if (frame->format == VIDEO_PALETTE_GREY
+ if (frame->format == VIDEO_PALETTE_GREY
&& ov->decomp_ops->decomp_400) {
int ret = ov->decomp_ops->decomp_400(
pIn0,
@@ -3313,7 +3291,7 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
frame->rawheight,
frame->bytes_recvd);
PDEBUG(4, "DEBUG: decomp_400 returned %d", ret);
- } else if (frame->format != VIDEO_PALETTE_GREY
+ } else if (frame->format != VIDEO_PALETTE_GREY
&& ov->decomp_ops->decomp_420) {
int ret = ov->decomp_ops->decomp_420(
pIn0,
@@ -3328,6 +3306,12 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
}
}
+/**********************************************************************
+ *
+ * Format conversion
+ *
+ **********************************************************************/
+
/* Fuses even and odd fields together, and doubles width.
* INPUT: an odd field followed by an even field at pIn0, in YUV planar format
* OUTPUT: a normal YUV planar image, with correct aspect ratio
@@ -3432,7 +3416,7 @@ ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
if (frame->compressed)
decompress(ov, frame, frame->rawdata, frame->tempdata);
else
- yuv420raw_to_yuv420p(frame, frame->rawdata,
+ yuv420raw_to_yuv420p(frame, frame->rawdata,
frame->tempdata);
deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
@@ -3452,11 +3436,11 @@ ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
* 3. Convert from YUV planar to destination format, if necessary
* 4. Fix the RGB offset, if necessary
*/
-static void
+static void
ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
{
if (dumppix) {
- memset(frame->data, 0,
+ memset(frame->data, 0,
MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
@@ -3482,7 +3466,7 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
*
**********************************************************************/
-static inline void
+static inline void
ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
{
int num, offset;
@@ -3518,7 +3502,7 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
/* Frame end */
if (in[8] & 0x80) {
- ts = (struct timeval *)(frame->data
+ ts = (struct timeval *)(frame->data
+ MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
do_gettimeofday(ts);
@@ -3656,7 +3640,7 @@ check_middle:
}
}
-static inline void
+static inline void
ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
{
int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
@@ -3796,7 +3780,7 @@ check_middle:
} else {
if (frame->bytes_recvd + copied + 8 <= max_raw)
{
- memcpy(frame->rawdata
+ memcpy(frame->rawdata
+ frame->bytes_recvd + copied,
in + read, 8);
copied += 8;
@@ -3810,7 +3794,7 @@ check_middle:
}
}
-static void
+static void
ov51x_isoc_irq(struct urb *urb)
{
int i;
@@ -3896,7 +3880,7 @@ ov51x_isoc_irq(struct urb *urb)
*
***************************************************************************/
-static int
+static int
ov51x_init_isoc(struct usb_ov511 *ov)
{
struct urb *urb;
@@ -3991,7 +3975,7 @@ ov51x_init_isoc(struct usb_ov511 *ov)
return 0;
}
-static void
+static void
ov51x_unlink_isoc(struct usb_ov511 *ov)
{
int n;
@@ -4006,7 +3990,7 @@ ov51x_unlink_isoc(struct usb_ov511 *ov)
}
}
-static void
+static void
ov51x_stop_isoc(struct usb_ov511 *ov)
{
if (!ov->streaming || !ov->dev)
@@ -4024,7 +4008,7 @@ ov51x_stop_isoc(struct usb_ov511 *ov)
ov51x_unlink_isoc(ov);
}
-static int
+static int
ov51x_new_frame(struct usb_ov511 *ov, int framenum)
{
struct ov511_frame *frame;
@@ -4046,7 +4030,7 @@ ov51x_new_frame(struct usb_ov511 *ov, int framenum)
frame = &ov->frame[framenum];
- PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
+ PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
frame->width, frame->height);
frame->grabstate = FRAME_GRABBING;
@@ -4075,12 +4059,12 @@ ov51x_new_frame(struct usb_ov511 *ov, int framenum)
*
***************************************************************************/
-/*
+/*
* - You must acquire buf_lock before entering this function.
* - Because this code will free any non-null pointer, you must be sure to null
* them if you explicitly free them somewhere else!
*/
-static void
+static void
ov51x_do_dealloc(struct usb_ov511 *ov)
{
int i;
@@ -4124,7 +4108,7 @@ ov51x_do_dealloc(struct usb_ov511 *ov)
PDEBUG(4, "leaving");
}
-static int
+static int
ov51x_alloc(struct usb_ov511 *ov)
{
int i;
@@ -4171,12 +4155,12 @@ ov51x_alloc(struct usb_ov511 *ov)
for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
- ov->frame[i].rawdata = ov->rawfbuf
+ ov->frame[i].rawdata = ov->rawfbuf
+ i * MAX_RAW_DATA_SIZE(w, h);
- ov->frame[i].tempdata = ov->tempfbuf
+ ov->frame[i].tempdata = ov->tempfbuf
+ i * MAX_RAW_DATA_SIZE(w, h);
- ov->frame[i].compbuf =
+ ov->frame[i].compbuf =
(unsigned char *) __get_free_page(GFP_KERNEL);
if (!ov->frame[i].compbuf)
goto error;
@@ -4196,7 +4180,7 @@ error:
return -ENOMEM;
}
-static void
+static void
ov51x_dealloc(struct usb_ov511 *ov, int now)
{
PDEBUG(4, "entered");
@@ -4212,7 +4196,7 @@ ov51x_dealloc(struct usb_ov511 *ov, int now)
*
***************************************************************************/
-static int
+static int
ov51x_v4l1_open(struct inode *inode, struct file *file)
{
struct video_device *vdev = video_devdata(file);
@@ -4224,17 +4208,18 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
down(&ov->lock);
err = -EBUSY;
- if (ov->user)
+ if (ov->user)
goto out;
- err = -ENOMEM;
- if (ov51x_alloc(ov))
+ err = ov51x_alloc(ov);
+ if (err < 0)
goto out;
ov->sub_flag = 0;
/* In case app doesn't set them... */
- if (ov51x_set_default_params(ov) < 0)
+ err = ov51x_set_default_params(ov);
+ if (err < 0)
goto out;
/* Make sure frames are reset */
@@ -4243,7 +4228,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
ov->frame[i].bytes_read = 0;
}
- /* If compression is on, make sure now that a
+ /* If compression is on, make sure now that a
* decompressor can be loaded */
if (ov->compress && !ov->decomp_ops) {
err = request_decompressor(ov);
@@ -4268,14 +4253,14 @@ out:
return err;
}
-static int
+static int
ov51x_v4l1_close(struct inode *inode, struct file *file)
{
struct video_device *vdev = file->private_data;
struct usb_ov511 *ov = vdev->priv;
PDEBUG(4, "ov511_close");
-
+
down(&ov->lock);
ov->user--;
@@ -4303,6 +4288,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
kfree(ov);
ov = NULL;
}
+
file->private_data = NULL;
return 0;
@@ -4318,7 +4304,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
PDEBUG(5, "IOCtl: 0x%X", cmd);
if (!ov->dev)
- return -EIO;
+ return -EIO;
switch (cmd) {
case VIDIOCGCAP:
@@ -4331,10 +4317,8 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
sprintf(b->name, "%s USB Camera",
symbolic(brglist, ov->bridge));
b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- if (ov->has_tuner)
- b->type |= VID_TYPE_TUNER;
b->channels = ov->num_inputs;
- b->audios = ov->has_audio_proc ? 1:0;
+ b->audios = 0;
b->maxwidth = ov->maxwidth;
b->maxheight = ov->maxheight;
b->minwidth = ov->minwidth;
@@ -4354,11 +4338,10 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
}
v->norm = ov->norm;
- v->type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
- v->flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0;
- v->flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
+ v->type = VIDEO_TYPE_CAMERA;
+ v->flags = 0;
// v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
- v->tuners = (ov->has_tuner) ? 1:0;
+ v->tuners = 0;
decoder_get_input_name(ov, v->channel, v->name);
return 0;
@@ -4585,7 +4568,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
return -EINVAL;
}
- if (vm->width > ov->maxwidth
+ if (vm->width > ov->maxwidth
|| vm->height > ov->maxheight) {
err("VIDIOCMCAPTURE: requested dimensions too big");
return -EINVAL;
@@ -4641,7 +4624,6 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
struct ov511_frame *frame;
int rc;
-
if (fnum >= OV511_NUMFRAMES) {
err("VIDIOCSYNC: invalid frame (%d)", fnum);
return -EINVAL;
@@ -4676,7 +4658,7 @@ redo:
return ret;
goto redo;
}
- /* Fall through */
+ /* Fall through */
case FRAME_DONE:
if (ov->snap_enabled && !frame->snapshot) {
int ret;
@@ -4728,92 +4710,6 @@ redo:
return 0;
}
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
-
- PDEBUG(4, "VIDIOCGTUNER");
-
- if (!ov->has_tuner || v->tuner) // Only tuner 0
- return -EINVAL;
-
- strcpy(v->name, "Television");
-
- // FIXME: Need a way to get the real values
- v->rangelow = 0;
- v->rangehigh = ~0;
-
- v->flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC
- | VIDEO_TUNER_SECAM;
- v->mode = 0; /* FIXME: Not sure what this is yet */
- v->signal = 0xFFFF; /* unknown */
-
- call_i2c_clients(ov, cmd, v);
-
- return 0;
- }
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
- int err;
-
- PDEBUG(4, "VIDIOCSTUNER");
-
- /* Only no or one tuner for now */
- if (!ov->has_tuner || v->tuner)
- return -EINVAL;
-
- /* and it only has certain valid modes */
- if (v->mode != VIDEO_MODE_PAL &&
- v->mode != VIDEO_MODE_NTSC &&
- v->mode != VIDEO_MODE_SECAM)
- return -EOPNOTSUPP;
-
- /* Is this right/necessary? */
- err = decoder_set_norm(ov, v->mode);
- if (err)
- return err;
-
- call_i2c_clients(ov, cmd, v);
-
- return 0;
- }
- case VIDIOCGFREQ:
- {
- unsigned long v = *((unsigned long *) arg);
-
- PDEBUG(4, "VIDIOCGFREQ");
-
- if (!ov->has_tuner)
- return -EINVAL;
-
- v = ov->freq;
-#if 0
- /* FIXME: this is necessary for testing */
- v = 46*16;
-#endif
- return 0;
- }
- case VIDIOCSFREQ:
- {
- unsigned long v = *((unsigned long *) arg);
-
- PDEBUG(4, "VIDIOCSFREQ: %lx", v);
-
- if (!ov->has_tuner)
- return -EINVAL;
-
- ov->freq = v;
- call_i2c_clients(ov, cmd, &v);
-
- return 0;
- }
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- {
- /* FIXME: Implement this... */
- return 0;
- }
default:
PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
return -ENOIOCTLCMD;
@@ -4822,7 +4718,7 @@ redo:
return 0;
}
-static int
+static int
ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -4839,7 +4735,7 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
return rc;
}
-static inline int
+static inline int
ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
{
struct video_device *vdev = file->private_data;
@@ -4904,7 +4800,7 @@ restart:
/* Wait while we're grabbing the image */
PDEBUG(4, "Waiting image grabbing");
- rc = wait_event_interruptible(frame->wq,
+ rc = wait_event_interruptible(frame->wq,
(frame->grabstate == FRAME_DONE)
|| (frame->grabstate == FRAME_ERROR));
@@ -4951,7 +4847,7 @@ restart:
get_frame_length(frame));
/* copy bytes to user space; we allow for partials reads */
-// if ((count + frame->bytes_read)
+// if ((count + frame->bytes_read)
// > get_frame_length((struct ov511_frame *)frame))
// count = frame->scanlength - frame->bytes_read;
@@ -5036,25 +4932,25 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
}
static struct file_operations ov511_fops = {
- owner: THIS_MODULE,
- open: ov51x_v4l1_open,
- release: ov51x_v4l1_close,
- read: ov51x_v4l1_read,
- mmap: ov51x_v4l1_mmap,
- ioctl: ov51x_v4l1_ioctl,
- llseek: no_llseek,
+ .owner = THIS_MODULE,
+ .open = ov51x_v4l1_open,
+ .release = ov51x_v4l1_close,
+ .read = ov51x_v4l1_read,
+ .mmap = ov51x_v4l1_mmap,
+ .ioctl = ov51x_v4l1_ioctl,
+ .llseek = no_llseek,
};
static struct video_device vdev_template = {
- owner: THIS_MODULE,
- name: "OV511 USB Camera",
- type: VID_TYPE_CAPTURE,
- hardware: VID_HARDWARE_OV511,
- fops: &ov511_fops,
+ .owner = THIS_MODULE,
+ .name = "OV511 USB Camera",
+ .type = VID_TYPE_CAPTURE,
+ .hardware = VID_HARDWARE_OV511,
+ .fops = &ov511_fops,
};
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-static int
+static int
ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long ularg)
{
@@ -5278,7 +5174,7 @@ ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
* the same register settings as the OV7610, since they are very similar.
*/
-static int
+static int
ov7xx0_configure(struct usb_ov511 *ov)
{
int i, success;
@@ -5429,7 +5325,7 @@ ov7xx0_configure(struct usb_ov511 *ov)
err("this to " EMAIL);
err("This is only a warning. You can attempt to use");
err("your camera anyway");
-// Only issue a warning for now
+// Only issue a warning for now
// return -1;
} else {
PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
@@ -5449,8 +5345,6 @@ ov7xx0_configure(struct usb_ov511 *ov)
/* I don't know what's different about the 76BE yet. */
if (i2c_r(ov, 0x15) & 1) {
info("Sensor is an OV7620AE");
- info("PLEASE REPORT THE EXISTENCE OF THIS SENSOR TO");
- info("THE DRIVER AUTHOR");
} else {
info("Sensor is an OV76BE");
}
@@ -5498,7 +5392,7 @@ ov7xx0_configure(struct usb_ov511 *ov)
}
/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int
+static int
ov6xx0_configure(struct usb_ov511 *ov)
{
int rc;
@@ -5513,7 +5407,7 @@ ov6xx0_configure(struct usb_ov511 *ov)
{ OV511_I2C_BUS, 0x0c, 0x24 },
{ OV511_I2C_BUS, 0x0d, 0x24 },
{ OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
- { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
+ { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
{ OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
{ OV511_I2C_BUS, 0x14, 0x04 },
/* 0x16: 0x06 helps frame stability with moving objects */
@@ -5525,11 +5419,11 @@ ov6xx0_configure(struct usb_ov511 *ov)
{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
{ OV511_I2C_BUS, 0x2d, 0x99 },
- { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Procesing Parameter */
+ { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Procesing Parameter */
{ OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
{ OV511_I2C_BUS, 0x38, 0x8b },
{ OV511_I2C_BUS, 0x39, 0x40 },
-
+
{ OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
{ OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
{ OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
@@ -5609,7 +5503,7 @@ ov6xx0_configure(struct usb_ov511 *ov)
* control the color balance */
// /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
// /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
-// /*U*/ { OV511_I2C_BUS, 0x4c, 0xd0 },
+// /*U*/ { OV511_I2C_BUS, 0x4c, 0xd0 },
/*d2?*/ { OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */
/*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
/*04?*/ { OV511_I2C_BUS, 0x4f, 0x07 },
@@ -5627,7 +5521,7 @@ ov6xx0_configure(struct usb_ov511 *ov)
};
PDEBUG(4, "starting sensor configuration");
-
+
if (init_ov_sensor(ov) < 0) {
err("Failed to read sensor ID. You might not have an OV6xx0,");
err("or it may be not responding. Report this to " EMAIL);
@@ -5642,7 +5536,7 @@ ov6xx0_configure(struct usb_ov511 *ov)
if (rc < 0) {
err("Error detecting sensor type");
return -1;
- }
+ }
if ((rc & 3) == 0)
ov->sensor = SEN_OV6630;
@@ -5676,7 +5570,7 @@ ov6xx0_configure(struct usb_ov511 *ov)
if (write_regvals(ov, aRegvalsNorm6x30))
return -1;
}
-
+
return 0;
}
@@ -5738,7 +5632,7 @@ ks0127_configure(struct usb_ov511 *ov)
}
/* This initializes the SAA7111A video decoder. */
-static int
+static int
saa7111a_configure(struct usb_ov511 *ov)
{
int rc;
@@ -5890,12 +5784,8 @@ ov511_configure(struct usb_ov511 *ov)
err("Also include the output of the detection process.");
}
- if (ov->customid == 6) { /* USB Life TV (NTSC) */
- ov->tuner_type = 8; /* Temic 4036FY5 3X 1981 */
- } else if (ov->customid == 70) { /* USB Life TV (PAL/SECAM) */
- ov->tuner_type = 3; /* Philips FI1216MF */
+ if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */
ov->pal = 1;
- }
if (write_regvals(ov, aRegvalsInit511)) goto error;
@@ -5917,7 +5807,7 @@ ov511_configure(struct usb_ov511 *ov)
ov->packet_numbering = 1;
ov511_set_packet_size(ov, 0);
- ov->snap_enabled = snapshot;
+ ov->snap_enabled = snapshot;
/* Test for 7xx0 */
PDEBUG(3, "Testing for 0V7xx0");
@@ -5994,7 +5884,7 @@ error:
}
/* This initializes the OV518/OV518+ and the sensor */
-static int
+static int
ov518_configure(struct usb_ov511 *ov)
{
/* For 518 and 518+ */
@@ -6190,7 +6080,6 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
ov->lightfreq = lightfreq;
ov->num_inputs = 1; /* Video decoder init functs. change this */
ov->stop_during_set = !fastset;
- ov->tuner_type = tuner;
ov->backlight = backlight;
ov->mirror = mirror;
ov->auto_brt = autobright;
@@ -6221,7 +6110,7 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
ov->bclass = BCL_OV511;
break;
default:
- err("Unknown product ID 0x%x", dev->descriptor.idProduct);
+ err("Unknown product ID 0x%04x", dev->descriptor.idProduct);
goto error_dealloc;
}
@@ -6373,11 +6262,11 @@ ov51x_disconnect(struct usb_device *dev, void *ptr)
}
static struct usb_driver ov511_driver = {
- owner: THIS_MODULE,
- name: "ov511",
- id_table: device_table,
- probe: ov51x_probe,
- disconnect: ov51x_disconnect
+ .owner = THIS_MODULE,
+ .name = "ov511",
+ .id_table = device_table,
+ .probe = ov51x_probe,
+ .disconnect = ov51x_disconnect
};
@@ -6388,7 +6277,7 @@ static struct usb_driver ov511_driver = {
***************************************************************************/
/* Returns 0 for success */
-int
+int
ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518,
int mmx)
{
@@ -6445,7 +6334,7 @@ err_in_use:
return -EBUSY;
}
-void
+void
ov511_deregister_decomp_module(int ov518, int mmx)
{
lock_kernel();
@@ -6461,13 +6350,13 @@ ov511_deregister_decomp_module(int ov518, int mmx)
else
ov511_decomp_ops = NULL;
}
-
+
MOD_DEC_USE_COUNT;
unlock_kernel();
}
-static int __init
+static int __init
usb_ov511_init(void)
{
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
@@ -6482,7 +6371,7 @@ usb_ov511_init(void)
return 0;
}
-static void __exit
+static void __exit
usb_ov511_exit(void)
{
usb_deregister(&ov511_driver);
diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h
index 02a8c2c4139f..20e4011b1794 100644
--- a/drivers/usb/media/ov511.h
+++ b/drivers/usb/media/ov511.h
@@ -551,17 +551,11 @@ struct usb_ov511 {
int num_inputs; /* Number of inputs */
int norm; /* NTSC / PAL / SECAM */
int has_decoder; /* Device has a video decoder */
- int has_tuner; /* Device has a TV tuner */
- int has_audio_proc; /* Device has an audio processor */
- int freq; /* Current tuner frequency */
- int tuner_type; /* Specific tuner model */
int pal; /* Device is designed for PAL resolution */
- /* I2C interface to kernel */
+ /* I2C interface */
struct semaphore i2c_lock; /* Protect I2C controller regs */
unsigned char primary_i2c_slave; /* I2C write id of sensor */
- unsigned char tuner_i2c_slave; /* I2C write id of tuner */
- unsigned char audio_i2c_slave; /* I2C write id of audio processor */
/* Control transaction stuff */
unsigned char *cbuf; /* Buffer for payload */
diff --git a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c
index 7f49d02d7316..72d110a78f05 100644
--- a/drivers/usb/media/pwc-if.c
+++ b/drivers/usb/media/pwc-if.c
@@ -91,10 +91,10 @@ static void usb_pwc_disconnect(struct usb_device *udev, void *ptr);
static struct usb_driver pwc_driver =
{
- name: "Philips webcam", /* name */
- id_table: pwc_device_table,
- probe: usb_pwc_probe, /* probe() */
- disconnect: usb_pwc_disconnect, /* disconnect() */
+ .name = "Philips webcam", /* name */
+ .id_table = pwc_device_table,
+ .probe = usb_pwc_probe, /* probe() */
+ .disconnect = usb_pwc_disconnect, /* disconnect() */
};
#define MAX_DEV_HINTS 10
@@ -130,21 +130,21 @@ static int pwc_video_ioctl(struct inode *inode, struct file *file,
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
static struct file_operations pwc_fops = {
- owner: THIS_MODULE,
- open: pwc_video_open,
- release: pwc_video_close,
- read: pwc_video_read,
- poll: pwc_video_poll,
- mmap: pwc_video_mmap,
- ioctl: pwc_video_ioctl,
- llseek: no_llseek,
+ .owner = THIS_MODULE,
+ .open = pwc_video_open,
+ .release = pwc_video_close,
+ .read = pwc_video_read,
+ .poll = pwc_video_poll,
+ .mmap = pwc_video_mmap,
+ .ioctl = pwc_video_ioctl,
+ .llseek = no_llseek,
};
static struct video_device pwc_template = {
- owner: THIS_MODULE,
- name: "Philips Webcam", /* Filled in later */
- type: VID_TYPE_CAPTURE,
- hardware: VID_HARDWARE_PWC,
- fops: &pwc_fops,
+ .owner = THIS_MODULE,
+ .name = "Philips Webcam", /* Filled in later */
+ .type = VID_TYPE_CAPTURE,
+ .hardware = VID_HARDWARE_PWC,
+ .fops = &pwc_fops,
};
/***************************************************************************/
@@ -1756,40 +1756,40 @@ static void usb_pwc_disconnect(struct usb_device *udev, void *ptr)
pdev = (struct pwc_device *)ptr;
if (pdev == NULL) {
Err("pwc_disconnect() Called without private pointer.\n");
- return;
+ goto out_err;
}
if (pdev->udev == NULL) {
Err("pwc_disconnect() already called for %p\n", pdev);
- return;
+ goto out_err;
}
if (pdev->udev != udev) {
Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
- return;
+ goto out_err;
}
#ifdef PWC_MAGIC
if (pdev->magic != PWC_MAGIC) {
Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
- return;
+ goto out_err;
}
-#endif
-
+#endif
+
pdev->unplugged = 1;
if (pdev->vdev != NULL) {
- video_unregister_device(pdev->vdev);
+ video_unregister_device(pdev->vdev);
if (pdev->vopen) {
Info("Disconnected while device/video is open!\n");
-
+
/* Wake up any processes that might be waiting for
a frame, let them return an error condition
*/
wake_up(&pdev->frameq);
-
+
/* Wait until we get a 'go' from _close(). This used
to have a gigantic race condition, since we kfree()
- stuff here, but we have to wait until close()
- is finished.
+ stuff here, but we have to wait until close()
+ is finished.
*/
-
+
Trace(TRACE_PROBE, "Sleeping on remove_ok.\n");
add_wait_queue(&pdev->remove_ok, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1815,6 +1815,7 @@ static void usb_pwc_disconnect(struct usb_device *udev, void *ptr)
device_hint[hint].pdev = NULL;
pdev->udev = NULL;
+out_err:
unlock_kernel();
kfree(pdev);
}
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
index 9c303e3d3a64..36dd251148bd 100644
--- a/drivers/usb/media/se401.c
+++ b/drivers/usb/media/se401.c
@@ -1283,20 +1283,20 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
}
static struct file_operations se401_fops = {
- owner: THIS_MODULE,
- open: se401_open,
- release: se401_close,
- read: se401_read,
- mmap: se401_mmap,
- ioctl: se401_ioctl,
- llseek: no_llseek,
+ .owner = THIS_MODULE,
+ .open = se401_open,
+ .release = se401_close,
+ .read = se401_read,
+ .mmap = se401_mmap,
+ .ioctl = se401_ioctl,
+ .llseek = no_llseek,
};
static struct video_device se401_template = {
- owner: THIS_MODULE,
- name: "se401 USB camera",
- type: VID_TYPE_CAPTURE,
- hardware: VID_HARDWARE_SE401,
- fops: &se401_fops,
+ .owner = THIS_MODULE,
+ .name = "se401 USB camera",
+ .type = VID_TYPE_CAPTURE,
+ .hardware = VID_HARDWARE_SE401,
+ .fops = &se401_fops,
};
@@ -1523,7 +1523,7 @@ static inline void usb_se401_remove_disconnected (struct usb_se401 *se401)
static struct usb_driver se401_driver = {
name: "se401",
id_table: device_table,
- probe: se401_probe,
+ .probe = se401_probe,
disconnect: se401_disconnect
};
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
index 65ad3a3514e0..ce5134c3dbde 100644
--- a/drivers/usb/media/stv680.c
+++ b/drivers/usb/media/stv680.c
@@ -1432,20 +1432,20 @@ static int stv680_read (struct file *file, char *buf,
} /* stv680_read */
static struct file_operations stv680_fops = {
- owner: THIS_MODULE,
- open: stv_open,
- release: stv_close,
- read: stv680_read,
- mmap: stv680_mmap,
- ioctl: stv680_ioctl,
- llseek: no_llseek,
+ .owner = THIS_MODULE,
+ .open = stv_open,
+ .release = stv_close,
+ .read = stv680_read,
+ .mmap = stv680_mmap,
+ .ioctl = stv680_ioctl,
+ .llseek = no_llseek,
};
static struct video_device stv680_template = {
- owner: THIS_MODULE,
- name: "STV0680 USB camera",
- type: VID_TYPE_CAPTURE,
- hardware: VID_HARDWARE_SE401,
- fops: &stv680_fops,
+ .owner = THIS_MODULE,
+ .name = "STV0680 USB camera",
+ .type = VID_TYPE_CAPTURE,
+ .hardware = VID_HARDWARE_SE401,
+ .fops = &stv680_fops,
};
static void *stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
@@ -1545,10 +1545,10 @@ static void stv680_disconnect (struct usb_device *dev, void *ptr)
}
static struct usb_driver stv680_driver = {
- name: "stv680",
- probe: stv680_probe,
- disconnect: stv680_disconnect,
- id_table: device_table
+ .name = "stv680",
+ .probe = stv680_probe,
+ .disconnect = stv680_disconnect,
+ .id_table = device_table
};
/********************************************************************
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
index f2ad752d6090..17103d7a69a1 100644
--- a/drivers/usb/media/usbvideo.c
+++ b/drivers/usb/media/usbvideo.c
@@ -1054,19 +1054,19 @@ static int usbvideo_find_struct(usbvideo_t *cams)
}
static struct file_operations usbvideo_fops = {
- owner: THIS_MODULE,
- open: usbvideo_v4l_open,
- release: usbvideo_v4l_close,
- read: usbvideo_v4l_read,
- mmap: usbvideo_v4l_mmap,
- ioctl: usbvideo_v4l_ioctl,
- llseek: no_llseek,
+ .owner = THIS_MODULE,
+ .open = usbvideo_v4l_open,
+ .release =usbvideo_v4l_close,
+ .read = usbvideo_v4l_read,
+ .mmap = usbvideo_v4l_mmap,
+ .ioctl = usbvideo_v4l_ioctl,
+ .llseek = no_llseek,
};
static struct video_device usbvideo_template = {
- owner: THIS_MODULE,
- type: VID_TYPE_CAPTURE,
- hardware: VID_HARDWARE_CPIA,
- fops: &usbvideo_fops,
+ .owner = THIS_MODULE,
+ .type = VID_TYPE_CAPTURE,
+ .hardware = VID_HARDWARE_CPIA,
+ .fops = &usbvideo_fops,
};
uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
index 51ed32717520..4426717cb016 100644
--- a/drivers/usb/media/vicam.c
+++ b/drivers/usb/media/vicam.c
@@ -640,20 +640,20 @@ static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma)
/* FIXME - vicam_template - important */
static struct file_operations vicam_fops = {
- owner: THIS_MODULE,
- open: vicam_v4l_open,
- release: vicam_v4l_close,
- read: vicam_v4l_read,
- mmap: vicam_v4l_mmap,
- ioctl: vicam_v4l_ioctl,
- llseek: no_llseek,
+ .owner = THIS_MODULE,
+ .open = vicam_v4l_open,
+ .release = vicam_v4l_close,
+ .read = vicam_v4l_read,
+ .mmap = vicam_v4l_mmap,
+ .ioctl = vicam_v4l_ioctl,
+ .llseek = no_llseek,
};
static struct video_device vicam_template = {
- owner: THIS_MODULE,
- name: "vicam USB camera",
- type: VID_TYPE_CAPTURE,
- hardware: VID_HARDWARE_SE401, /* need to ask for own id */
- fops: &vicam_fops,
+ .owner = THIS_MODULE,
+ .name = "vicam USB camera",
+ .type = VID_TYPE_CAPTURE,
+ .hardware = VID_HARDWARE_SE401, /* need to ask for own id */
+ .fops = &vicam_fops,
};
/******************************************************************************
@@ -876,11 +876,11 @@ static void vicam_disconnect(struct usb_device *udev, void *ptr)
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vicam_driver = {
- owner: THIS_MODULE,
- name: "vicam",
- probe: vicam_probe,
- disconnect: vicam_disconnect,
- id_table: vicam_table,
+ .owner = THIS_MODULE,
+ .name = "vicam",
+ .probe = vicam_probe,
+ .disconnect = vicam_disconnect,
+ .id_table = vicam_table,
};
/******************************************************************************
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 0d55087b038b..aeb5ca4f3086 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -1879,13 +1879,13 @@ static int auerchar_release (struct inode *inode, struct file *file)
/* File operation structure */
static struct file_operations auerswald_fops =
{
- owner: THIS_MODULE,
- llseek: no_llseek,
- read: auerchar_read,
- write: auerchar_write,
- ioctl: auerchar_ioctl,
- open: auerchar_open,
- release: auerchar_release,
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = auerchar_read,
+ .write = auerchar_write,
+ .ioctl = auerchar_ioctl,
+ .open = auerchar_open,
+ .release = auerchar_release,
};
@@ -2138,10 +2138,10 @@ MODULE_DEVICE_TABLE (usb, auerswald_ids);
/* Standard usb driver struct */
static struct usb_driver auerswald_driver = {
- name: "auerswald",
- probe: auerswald_probe,
- disconnect: auerswald_disconnect,
- id_table: auerswald_ids,
+ .name = "auerswald",
+ .probe = auerswald_probe,
+ .disconnect = auerswald_disconnect,
+ .id_table = auerswald_ids,
};
diff --git a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c
index 52b815eb57a3..47195779469f 100644
--- a/drivers/usb/misc/brlvger.c
+++ b/drivers/usb/misc/brlvger.c
@@ -230,23 +230,23 @@ MODULE_DEVICE_TABLE (usb, brlvger_ids);
static struct file_operations brlvger_fops =
{
- owner: THIS_MODULE,
- llseek: brlvger_llseek,
- read: brlvger_read,
- write: brlvger_write,
- ioctl: brlvger_ioctl,
- open: brlvger_open,
- release: brlvger_release,
- poll: brlvger_poll,
+ .owner = THIS_MODULE,
+ .llseek = brlvger_llseek,
+ .read = brlvger_read,
+ .write = brlvger_write,
+ .ioctl = brlvger_ioctl,
+ .open = brlvger_open,
+ .release = brlvger_release,
+ .poll = brlvger_poll,
};
static struct usb_driver brlvger_driver =
{
- owner: THIS_MODULE,
- name: "brlvger",
- probe: brlvger_probe,
- disconnect: brlvger_disconnect,
- id_table: brlvger_ids,
+ .owner = THIS_MODULE,
+ .name = "brlvger",
+ .probe = brlvger_probe,
+ .disconnect = brlvger_disconnect,
+ .id_table = brlvger_ids,
};
static int
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 705f753b8ed2..70388454d8f5 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -443,11 +443,11 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
static struct
file_operations usb_rio_fops = {
- read: read_rio,
- write: write_rio,
- ioctl: ioctl_rio,
- open: open_rio,
- release: close_rio,
+ .read = read_rio,
+ .write = write_rio,
+ .ioctl = ioctl_rio,
+ .open = open_rio,
+ .release = close_rio,
};
static void *probe_rio(struct usb_device *dev, unsigned int ifnum,
@@ -525,10 +525,10 @@ static struct usb_device_id rio_table [] = {
MODULE_DEVICE_TABLE (usb, rio_table);
static struct usb_driver rio_driver = {
- name: "rio500",
- probe: probe_rio,
- disconnect: disconnect_rio,
- id_table: rio_table,
+ .name = "rio500",
+ .probe = probe_rio,
+ .disconnect = disconnect_rio,
+ .id_table = rio_table,
};
int usb_rio_init(void)
diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c
index 00fd9f31353f..e6cb63af2341 100644
--- a/drivers/usb/misc/tiglusb.c
+++ b/drivers/usb/misc/tiglusb.c
@@ -295,13 +295,13 @@ static int tiglusb_ioctl (struct inode *inode, struct file *file,
/* ----- kernel module registering ------------------------------------ */
static struct file_operations tiglusb_fops = {
- owner: THIS_MODULE,
- llseek: no_llseek,
- read: tiglusb_read,
- write: tiglusb_write,
- ioctl: tiglusb_ioctl,
- open: tiglusb_open,
- release: tiglusb_release,
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = tiglusb_read,
+ .write = tiglusb_write,
+ .ioctl = tiglusb_ioctl,
+ .open = tiglusb_open,
+ .release = tiglusb_release,
};
static int tiglusb_find_struct (void)
@@ -407,11 +407,11 @@ static struct usb_device_id tiglusb_ids[] = {
MODULE_DEVICE_TABLE (usb, tiglusb_ids);
static struct usb_driver tiglusb_driver = {
- owner: THIS_MODULE,
- name: "tiglusb",
- probe: tiglusb_probe,
- disconnect: tiglusb_disconnect,
- id_table: tiglusb_ids,
+ .owner = THIS_MODULE,
+ .name = "tiglusb",
+ .probe = tiglusb_probe,
+ .disconnect = tiglusb_disconnect,
+ .id_table = tiglusb_ids,
};
/* --- initialisation code ------------------------------------- */
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index ebf8e985bcec..3940bb1fbe5c 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -646,10 +646,10 @@ MODULE_DEVICE_TABLE (usb, uss720_table);
static struct usb_driver uss720_driver = {
- name: "uss720",
- probe: uss720_probe,
- disconnect: uss720_disconnect,
- id_table: uss720_table,
+ .name = "uss720",
+ .probe = uss720_probe,
+ .disconnect = uss720_disconnect,
+ .id_table = uss720_table,
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
index 0b2336935381..b270dc757afb 100644
--- a/drivers/usb/net/catc.c
+++ b/drivers/usb/net/catc.c
@@ -941,10 +941,10 @@ static struct usb_device_id catc_id_table [] = {
MODULE_DEVICE_TABLE(usb, catc_id_table);
static struct usb_driver catc_driver = {
- name: "catc",
- probe: catc_probe,
- disconnect: catc_disconnect,
- id_table: catc_id_table,
+ .name = "catc",
+ .probe = catc_probe,
+ .disconnect = catc_disconnect,
+ .id_table = catc_id_table,
};
static int __init catc_init(void)
diff --git a/drivers/usb/net/cdc-ether.c b/drivers/usb/net/cdc-ether.c
index 1d3ac4508363..236a0d80cf22 100644
--- a/drivers/usb/net/cdc-ether.c
+++ b/drivers/usb/net/cdc-ether.c
@@ -1325,10 +1325,10 @@ static void CDCEther_disconnect( struct usb_device *usb, void *ptr )
//////////////////////////////////////////////////////////////////////////////
static struct usb_driver CDCEther_driver = {
- name: "CDCEther",
- probe: CDCEther_probe,
- disconnect: CDCEther_disconnect,
- id_table: CDCEther_ids,
+ .name = "CDCEther",
+ .probe = CDCEther_probe,
+ .disconnect = CDCEther_disconnect,
+ .id_table = CDCEther_ids,
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index 096a8b1aded2..738baabda267 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -165,11 +165,11 @@ MODULE_DEVICE_TABLE (usb, usb_klsi_table);
* kaweth_driver
****************************************************************/
static struct usb_driver kaweth_driver = {
- owner: THIS_MODULE,
- name: "kaweth",
- probe: kaweth_probe,
- disconnect: kaweth_disconnect,
- id_table: usb_klsi_table,
+ .owner = THIS_MODULE,
+ .name = "kaweth",
+ .probe = kaweth_probe,
+ .disconnect = kaweth_disconnect,
+ .id_table = usb_klsi_table,
};
typedef __u8 eth_addr_t[6];
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index a7d9c72cdbcc..6728f5cfd6ce 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -1148,10 +1148,10 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
}
static struct usb_driver pegasus_driver = {
- name: driver_name,
- probe: pegasus_probe,
- disconnect: pegasus_disconnect,
- id_table: pegasus_ids,
+ .name = driver_name,
+ .probe = pegasus_probe,
+ .disconnect = pegasus_disconnect,
+ .id_table = pegasus_ids,
};
int __init pegasus_init(void)
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index ffd2737fee5b..89645c118480 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -110,10 +110,10 @@ static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
static struct usb_driver rtl8150_driver = {
- name: "rtl8150",
- probe: rtl8150_probe,
- disconnect: rtl8150_disconnect,
- id_table: rtl8150_table,
+ .name = "rtl8150",
+ .probe = rtl8150_probe,
+ .disconnect = rtl8150_disconnect,
+ .id_table = rtl8150_table,
};
/*
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index b6b9fc8b51e9..c6ac7dd2821e 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -26,12 +26,7 @@
* See the LINUXDEV support.
*
*
- * TODO:
- *
- * This needs to be retested for bulk queuing problems ... earlier versions
- * seemed to find different types of problems in each HCD. Once they're fixed,
- * re-enable queues to get higher bandwidth utilization (without needing
- * to tweak MTU for larger packets).
+ * Status:
*
* - AN2720 ... not widely available, but reportedly works well
*
@@ -45,8 +40,8 @@
* but the Sharp Zaurus uses an incompatible protocol (extra checksums).
* No reason not to merge the Zaurus protocol here too (got patch? :)
*
- * - For Netchip, use keventd to poll via control requests to detect hardware
- * level "carrier detect".
+ * - For Netchip, should use keventd to poll via control requests to detect
+ * hardware level "carrier detect".
*
* - PL-230x ... the initialization protocol doesn't seem to match chip data
* sheets, sometimes it's not needed and sometimes it hangs. Prolific has
@@ -60,9 +55,9 @@
*
* There are reports that bridging gives lower-than-usual throughput.
*
- * Craft smarter hotplug policy scripts ... ones that know how to arrange
+ * Need smarter hotplug policy scripts ... ones that know how to arrange
* bridging with "brctl", and can handle static and dynamic ("pump") setups.
- * Use those "peer connected" events.
+ * Use those eventual "peer connected" events.
*
*
* CHANGELOG:
@@ -122,7 +117,7 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-// #define REALLY_QUEUE
+#define REALLY_QUEUE
#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
# define DEBUG
@@ -139,7 +134,7 @@
#define CONFIG_USB_PL2301
-#define DRIVER_VERSION "07-May-2002"
+#define DRIVER_VERSION "17-Jul-2002"
/*-------------------------------------------------------------------------*/
@@ -301,12 +296,12 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
*-------------------------------------------------------------------------*/
static const struct driver_info an2720_info = {
- description: "AnchorChips/Cypress 2720",
+ .description = "AnchorChips/Cypress 2720",
// no reset available!
// no check_connect available!
- in: 2, out: 2, // direction distinguishes these
- epsize: 64,
+ .in = 2, out: 2, // direction distinguishes these
+ .epsize =64,
};
#endif /* CONFIG_USB_AN2720 */
@@ -324,10 +319,10 @@ static const struct driver_info an2720_info = {
*-------------------------------------------------------------------------*/
static const struct driver_info belkin_info = {
- description: "Belkin, eTEK, or compatible",
+ .description = "Belkin, eTEK, or compatible",
- in: 1, out: 1, // direction distinguishes these
- epsize: 64,
+ .in = 1, out: 1, // direction distinguishes these
+ .epsize =64,
};
#endif /* CONFIG_USB_BELKIN */
@@ -635,17 +630,17 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
}
static const struct driver_info genelink_info = {
- description: "Genesys GeneLink",
- flags: FLAG_FRAMING_GL | FLAG_NO_SETINT,
- reset: genelink_reset,
- rx_fixup: genelink_rx_fixup,
- tx_fixup: genelink_tx_fixup,
+ .description = "Genesys GeneLink",
+ .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT,
+ .reset = genelink_reset,
+ .rx_fixup = genelink_rx_fixup,
+ .tx_fixup = genelink_tx_fixup,
- in: 1, out: 2,
- epsize: 64,
+ .in = 1, out: 2,
+ .epsize =64,
#ifdef GENELINK_ACK
- check_connect: genelink_check_connect,
+ .check_connect =genelink_check_connect,
#endif
};
@@ -676,11 +671,11 @@ static int linuxdev_check_connect (struct usbnet *dev)
}
static const struct driver_info linuxdev_info = {
- description: "Linux Device",
+ .description = "Linux Device",
// no reset defined (yet?)
- check_connect: linuxdev_check_connect,
- in: 2, out: 1,
- epsize: 64,
+ .check_connect =linuxdev_check_connect,
+ .in = 2, out: 1,
+ .epsize =64,
};
#endif /* CONFIG_USB_LINUXDEV */
@@ -1123,15 +1118,15 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
}
static const struct driver_info net1080_info = {
- description: "NetChip TurboCONNECT",
- flags: FLAG_FRAMING_NC,
- reset: net1080_reset,
- check_connect: net1080_check_connect,
- rx_fixup: net1080_rx_fixup,
- tx_fixup: net1080_tx_fixup,
-
- in: 1, out: 1, // direction distinguishes these
- epsize: 64,
+ .description = "NetChip TurboCONNECT",
+ .flags = FLAG_FRAMING_NC,
+ .reset = net1080_reset,
+ .check_connect =net1080_check_connect,
+ .rx_fixup = net1080_rx_fixup,
+ .tx_fixup = net1080_tx_fixup,
+
+ .in = 1, out: 1, // direction distinguishes these
+ .epsize =64,
};
#endif /* CONFIG_USB_NET1080 */
@@ -1192,13 +1187,13 @@ static int pl_reset (struct usbnet *dev)
}
static const struct driver_info prolific_info = {
- description: "Prolific PL-2301/PL-2302",
- flags: FLAG_NO_SETINT,
+ .description = "Prolific PL-2301/PL-2302",
+ .flags = FLAG_NO_SETINT,
/* some PL-2302 versions seem to fail usb_set_interface() */
- reset: pl_reset,
+ .reset = pl_reset,
- in: 3, out: 2,
- epsize: 64,
+ .in = 3, out: 2,
+ .epsize =64,
};
#endif /* CONFIG_USB_PL2301 */
@@ -1815,20 +1810,19 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
}
#endif /* CONFIG_USB_NET1080 */
- netif_stop_queue (net);
switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
case -EPIPE:
+ netif_stop_queue (net);
defer_kevent (dev, EVENT_TX_HALT);
break;
default:
- netif_start_queue (net);
dbg ("%s tx: submit urb err %d", net->name, retval);
break;
case 0:
net->trans_start = jiffies;
__skb_queue_tail (&dev->txq, skb);
- if (dev->txq.qlen < TX_QLEN)
- netif_start_queue (net);
+ if (dev->txq.qlen >= TX_QLEN)
+ netif_stop_queue (net);
}
spin_unlock_irqrestore (&dev->txq.lock, flags);
@@ -2054,32 +2048,32 @@ static const struct usb_device_id products [] = {
#ifdef CONFIG_USB_AN2720
{
USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults
- driver_info: (unsigned long) &an2720_info,
+ .driver_info = (unsigned long) &an2720_info,
},
{
USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET
- driver_info: (unsigned long) &an2720_info,
+ .driver_info = (unsigned long) &an2720_info,
},
#endif
#ifdef CONFIG_USB_BELKIN
{
USB_DEVICE (0x050d, 0x0004), // Belkin
- driver_info: (unsigned long) &belkin_info,
+ .driver_info = (unsigned long) &belkin_info,
}, {
USB_DEVICE (0x056c, 0x8100), // eTEK
- driver_info: (unsigned long) &belkin_info,
+ .driver_info = (unsigned long) &belkin_info,
}, {
USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK)
- driver_info: (unsigned long) &belkin_info,
+ .driver_info = (unsigned long) &belkin_info,
},
#endif
#ifdef CONFIG_USB_GENESYS
{
USB_DEVICE (0x05e3, 0x0502), // GL620USB-A
- driver_info: (unsigned long) &genelink_info,
+ .driver_info = (unsigned long) &genelink_info,
},
#endif
@@ -2091,28 +2085,28 @@ static const struct usb_device_id products [] = {
{
// 1183 = 0x049F, both used as hex values?
USB_DEVICE (0x049F, 0x505A), // Compaq "Itsy"
- driver_info: (unsigned long) &linuxdev_info,
+ .driver_info = (unsigned long) &linuxdev_info,
},
#endif
#ifdef CONFIG_USB_NET1080
{
USB_DEVICE (0x0525, 0x1080), // NetChip ref design
- driver_info: (unsigned long) &net1080_info,
+ .driver_info = (unsigned long) &net1080_info,
},
{
USB_DEVICE (0x06D0, 0x0622), // Laplink Gold
- driver_info: (unsigned long) &net1080_info,
+ .driver_info = (unsigned long) &net1080_info,
},
#endif
#ifdef CONFIG_USB_PL2301
{
USB_DEVICE (0x067b, 0x0000), // PL-2301
- driver_info: (unsigned long) &prolific_info,
+ .driver_info = (unsigned long) &prolific_info,
}, {
USB_DEVICE (0x067b, 0x0001), // PL-2302
- driver_info: (unsigned long) &prolific_info,
+ .driver_info = (unsigned long) &prolific_info,
},
#endif
@@ -2123,10 +2117,10 @@ static const struct usb_device_id products [] = {
MODULE_DEVICE_TABLE (usb, products);
static struct usb_driver usbnet_driver = {
- name: driver_name,
- id_table: products,
- probe: usbnet_probe,
- disconnect: usbnet_disconnect,
+ .name = driver_name,
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 1b95a25f286b..fa8c7f874dd6 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -116,21 +116,21 @@ MODULE_DEVICE_TABLE (usb, id_table_combined);
/* All of the device info needed for the serial converters */
static struct usb_serial_device_type belkin_device = {
- owner: THIS_MODULE,
- name: "Belkin / Peracom / GoHubs USB Serial Adapter",
- id_table: id_table_combined,
- num_interrupt_in: 1,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: belkin_sa_open,
- close: belkin_sa_close,
- read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */
- ioctl: belkin_sa_ioctl,
- set_termios: belkin_sa_set_termios,
- break_ctl: belkin_sa_break_ctl,
- attach: belkin_sa_startup,
- shutdown: belkin_sa_shutdown,
+ .owner = THIS_MODULE,
+ .name = "Belkin / Peracom / GoHubs USB Serial Adapter",
+ .id_table = id_table_combined,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = belkin_sa_open,
+ .close = belkin_sa_close,
+ .read_int_callback = belkin_sa_read_int_callback, /* How we get the status info */
+ .ioctl = belkin_sa_ioctl,
+ .set_termios = belkin_sa_set_termios,
+ .break_ctl = belkin_sa_break_ctl,
+ .attach = belkin_sa_startup,
+ .shutdown = belkin_sa_shutdown,
};
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 9ca8b075f007..7a15cc3564a4 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -74,21 +74,21 @@ static struct usb_device_id id_table [] = {
MODULE_DEVICE_TABLE (usb, id_table);
static struct usb_serial_device_type cyberjack_device = {
- owner: THIS_MODULE,
- name: "Reiner SCT Cyberjack USB card reader",
- id_table: id_table,
- num_interrupt_in: 1,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- attach: cyberjack_startup,
- shutdown: cyberjack_shutdown,
- open: cyberjack_open,
- close: cyberjack_close,
- write: cyberjack_write,
- read_int_callback: cyberjack_read_int_callback,
- read_bulk_callback: cyberjack_read_bulk_callback,
- write_bulk_callback: cyberjack_write_bulk_callback,
+ .owner = THIS_MODULE,
+ .name = "Reiner SCT Cyberjack USB card reader",
+ .id_table = id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .attach = cyberjack_startup,
+ .shutdown = cyberjack_shutdown,
+ .open = cyberjack_open,
+ .close = cyberjack_close,
+ .write = cyberjack_write,
+ .read_int_callback = cyberjack_read_int_callback,
+ .read_bulk_callback = cyberjack_read_bulk_callback,
+ .write_bulk_callback = cyberjack_write_bulk_callback,
};
struct cyberjack_private {
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 4dd615fda3f7..eee56288d2ea 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -498,51 +498,51 @@ MODULE_DEVICE_TABLE (usb, id_table_combined);
/* device info needed for the Digi serial converter */
static struct usb_serial_device_type digi_acceleport_2_device = {
- owner: THIS_MODULE,
- name: "Digi USB",
- id_table: id_table_2,
- num_interrupt_in: 0,
- num_bulk_in: 4,
- num_bulk_out: 4,
- num_ports: 3,
- open: digi_open,
- close: digi_close,
- write: digi_write,
- write_room: digi_write_room,
- write_bulk_callback: digi_write_bulk_callback,
- read_bulk_callback: digi_read_bulk_callback,
- chars_in_buffer: digi_chars_in_buffer,
- throttle: digi_rx_throttle,
- unthrottle: digi_rx_unthrottle,
- ioctl: digi_ioctl,
- set_termios: digi_set_termios,
- break_ctl: digi_break_ctl,
- attach: digi_startup,
- shutdown: digi_shutdown,
+ .owner = THIS_MODULE,
+ .name = "Digi USB",
+ .id_table = id_table_2,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 4,
+ .num_bulk_out = 4,
+ .num_ports = 3,
+ .open = digi_open,
+ .close = digi_close,
+ .write = digi_write,
+ .write_room = digi_write_room,
+ .write_bulk_callback = digi_write_bulk_callback,
+ .read_bulk_callback = digi_read_bulk_callback,
+ .chars_in_buffer = digi_chars_in_buffer,
+ .throttle = digi_rx_throttle,
+ .unthrottle = digi_rx_unthrottle,
+ .ioctl = digi_ioctl,
+ .set_termios = digi_set_termios,
+ .break_ctl = digi_break_ctl,
+ .attach = digi_startup,
+ .shutdown = digi_shutdown,
};
static struct usb_serial_device_type digi_acceleport_4_device = {
- owner: THIS_MODULE,
- name: "Digi USB",
- id_table: id_table_4,
- num_interrupt_in: 0,
- num_bulk_in: 5,
- num_bulk_out: 5,
- num_ports: 4,
- open: digi_open,
- close: digi_close,
- write: digi_write,
- write_room: digi_write_room,
- write_bulk_callback: digi_write_bulk_callback,
- read_bulk_callback: digi_read_bulk_callback,
- chars_in_buffer: digi_chars_in_buffer,
- throttle: digi_rx_throttle,
- unthrottle: digi_rx_unthrottle,
- ioctl: digi_ioctl,
- set_termios: digi_set_termios,
- break_ctl: digi_break_ctl,
- attach: digi_startup,
- shutdown: digi_shutdown,
+ .owner = THIS_MODULE,
+ .name = "Digi USB",
+ .id_table = id_table_4,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 5,
+ .num_bulk_out = 5,
+ .num_ports = 4,
+ .open = digi_open,
+ .close = digi_close,
+ .write = digi_write,
+ .write_room = digi_write_room,
+ .write_bulk_callback = digi_write_bulk_callback,
+ .read_bulk_callback = digi_read_bulk_callback,
+ .chars_in_buffer = digi_chars_in_buffer,
+ .throttle = digi_rx_throttle,
+ .unthrottle = digi_rx_unthrottle,
+ .ioctl = digi_ioctl,
+ .set_termios = digi_set_termios,
+ .break_ctl = digi_break_ctl,
+ .attach = digi_startup,
+ .shutdown = digi_shutdown,
};
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index c6b255a36326..4f66d87f9a10 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -111,26 +111,26 @@ static struct usb_device_id id_table [] = {
MODULE_DEVICE_TABLE (usb, id_table);
static struct usb_serial_device_type empeg_device = {
- owner: THIS_MODULE,
- name: "Empeg",
- id_table: id_table,
- num_interrupt_in: 0,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: empeg_open,
- close: empeg_close,
- throttle: empeg_throttle,
- unthrottle: empeg_unthrottle,
- attach: empeg_startup,
- shutdown: empeg_shutdown,
- ioctl: empeg_ioctl,
- set_termios: empeg_set_termios,
- write: empeg_write,
- write_room: empeg_write_room,
- chars_in_buffer: empeg_chars_in_buffer,
- write_bulk_callback: empeg_write_bulk_callback,
- read_bulk_callback: empeg_read_bulk_callback,
+ .owner = THIS_MODULE,
+ .name = "Empeg",
+ .id_table = id_table,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = empeg_open,
+ .close = empeg_close,
+ .throttle = empeg_throttle,
+ .unthrottle = empeg_unthrottle,
+ .attach = empeg_startup,
+ .shutdown = empeg_shutdown,
+ .ioctl = empeg_ioctl,
+ .set_termios = empeg_set_termios,
+ .write = empeg_write,
+ .write_room = empeg_write_room,
+ .chars_in_buffer = empeg_chars_in_buffer,
+ .write_bulk_callback = empeg_write_bulk_callback,
+ .read_bulk_callback = empeg_read_bulk_callback,
};
#define NUM_URBS 16
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index b833b4577406..fb20bd131723 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -173,45 +173,45 @@ static void ftdi_sio_break_ctl (struct usb_serial_port *port, int break_state )
which share common code */
static struct usb_serial_device_type ftdi_sio_device = {
- owner: THIS_MODULE,
- name: "FTDI SIO",
- id_table: id_table_sio,
- num_interrupt_in: 0,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: ftdi_sio_open,
- close: ftdi_sio_close,
- write: ftdi_sio_write,
- write_room: ftdi_sio_write_room,
- read_bulk_callback: ftdi_sio_read_bulk_callback,
- write_bulk_callback: ftdi_sio_write_bulk_callback,
- ioctl: ftdi_sio_ioctl,
- set_termios: ftdi_sio_set_termios,
- break_ctl: ftdi_sio_break_ctl,
- attach: ftdi_sio_startup,
- shutdown: ftdi_sio_shutdown,
+ .owner = THIS_MODULE,
+ .name = "FTDI SIO",
+ .id_table = id_table_sio,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ftdi_sio_open,
+ .close = ftdi_sio_close,
+ .write = ftdi_sio_write,
+ .write_room = ftdi_sio_write_room,
+ .read_bulk_callback = ftdi_sio_read_bulk_callback,
+ .write_bulk_callback = ftdi_sio_write_bulk_callback,
+ .ioctl = ftdi_sio_ioctl,
+ .set_termios = ftdi_sio_set_termios,
+ .break_ctl = ftdi_sio_break_ctl,
+ .attach = ftdi_sio_startup,
+ .shutdown = ftdi_sio_shutdown,
};
static struct usb_serial_device_type ftdi_8U232AM_device = {
- owner: THIS_MODULE,
- name: "FTDI 8U232AM",
- id_table: id_table_8U232AM,
- num_interrupt_in: 0,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: ftdi_sio_open,
- close: ftdi_sio_close,
- write: ftdi_sio_write,
- write_room: ftdi_sio_write_room,
- read_bulk_callback: ftdi_sio_read_bulk_callback,
- write_bulk_callback: ftdi_sio_write_bulk_callback,
- ioctl: ftdi_sio_ioctl,
- set_termios: ftdi_sio_set_termios,
- break_ctl: ftdi_sio_break_ctl,
- attach: ftdi_8U232AM_startup,
- shutdown: ftdi_sio_shutdown,
+ .owner = THIS_MODULE,
+ .name = "FTDI 8U232AM",
+ .id_table = id_table_8U232AM,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ftdi_sio_open,
+ .close = ftdi_sio_close,
+ .write = ftdi_sio_write,
+ .write_room = ftdi_sio_write_room,
+ .read_bulk_callback = ftdi_sio_read_bulk_callback,
+ .write_bulk_callback = ftdi_sio_write_bulk_callback,
+ .ioctl = ftdi_sio_ioctl,
+ .set_termios = ftdi_sio_set_termios,
+ .break_ctl = ftdi_sio_break_ctl,
+ .attach = ftdi_8U232AM_startup,
+ .shutdown = ftdi_sio_shutdown,
};
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 9323ffefb9d2..aae807c97f65 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -90,22 +90,22 @@ 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: NUM_DONT_CARE,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: ipaq_open,
- close: ipaq_close,
- attach: 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,
+ .owner = THIS_MODULE,
+ .name = "Compaq iPAQ",
+ .id_table = ipaq_id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ipaq_open,
+ .close = ipaq_close,
+ .attach = 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;
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 5fbd5ea1bfa7..f89ebb682280 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -131,20 +131,20 @@ MODULE_DEVICE_TABLE (usb, id_table);
struct usb_serial_device_type ir_device = {
- owner: THIS_MODULE,
- name: "IR Dongle",
- id_table: id_table,
- num_interrupt_in: 1,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- set_termios: ir_set_termios,
- attach: ir_startup,
- open: ir_open,
- close: ir_close,
- write: ir_write,
- write_bulk_callback: ir_write_bulk_callback,
- read_bulk_callback: ir_read_bulk_callback,
+ .owner = THIS_MODULE,
+ .name = "IR Dongle",
+ .id_table = id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .set_termios = ir_set_termios,
+ .attach = ir_startup,
+ .open = ir_open,
+ .close = ir_close,
+ .write = ir_write,
+ .write_bulk_callback = ir_write_bulk_callback,
+ .read_bulk_callback = ir_read_bulk_callback,
};
static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 4804b7d8f0ce..adb378a75ca3 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1103,28 +1103,28 @@ static struct callbacks {
} keyspan_callbacks[] = {
{
/* msg_usa26 callbacks */
- instat_callback: usa26_instat_callback,
- glocont_callback: usa26_glocont_callback,
- indat_callback: usa26_indat_callback,
- outdat_callback: usa2x_outdat_callback,
- inack_callback: usa26_inack_callback,
- outcont_callback: usa26_outcont_callback,
+ .instat_callback = usa26_instat_callback,
+ .glocont_callback = usa26_glocont_callback,
+ .indat_callback = usa26_indat_callback,
+ .outdat_callback = usa2x_outdat_callback,
+ .inack_callback = usa26_inack_callback,
+ .outcont_callback = usa26_outcont_callback,
}, {
/* msg_usa28 callbacks */
- instat_callback: usa28_instat_callback,
- glocont_callback: usa28_glocont_callback,
- indat_callback: usa28_indat_callback,
- outdat_callback: usa2x_outdat_callback,
- inack_callback: usa28_inack_callback,
- outcont_callback: usa28_outcont_callback,
+ .instat_callback = usa28_instat_callback,
+ .glocont_callback = usa28_glocont_callback,
+ .indat_callback = usa28_indat_callback,
+ .outdat_callback = usa2x_outdat_callback,
+ .inack_callback = usa28_inack_callback,
+ .outcont_callback = usa28_outcont_callback,
}, {
/* msg_usa49 callbacks */
- instat_callback: usa49_instat_callback,
- glocont_callback: usa49_glocont_callback,
- indat_callback: usa49_indat_callback,
- outdat_callback: usa2x_outdat_callback,
- inack_callback: usa49_inack_callback,
- outcont_callback: usa49_outcont_callback,
+ .instat_callback = usa49_instat_callback,
+ .glocont_callback = usa49_glocont_callback,
+ .indat_callback = usa49_indat_callback,
+ .outdat_callback = usa2x_outdat_callback,
+ .inack_callback = usa49_inack_callback,
+ .outcont_callback = usa49_outcont_callback,
}
};
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index b0dac088b979..2ee0a07f28fb 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -804,52 +804,52 @@ static void keyspan_pda_shutdown (struct usb_serial *serial)
#ifdef KEYSPAN
static struct usb_serial_device_type keyspan_pda_fake_device = {
- owner: THIS_MODULE,
- name: "Keyspan PDA - (prerenumeration)",
- id_table: id_table_fake,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- attach: keyspan_pda_fake_startup,
+ .owner = THIS_MODULE,
+ .name = "Keyspan PDA - (prerenumeration)",
+ .id_table = id_table_fake,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 1,
+ .attach = keyspan_pda_fake_startup,
};
#endif
#ifdef XIRCOM
static struct usb_serial_device_type xircom_pgs_fake_device = {
- owner: THIS_MODULE,
- name: "Xircom / Entregra PGS - (prerenumeration)",
- id_table: id_table_fake_xircom,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- attach: keyspan_pda_fake_startup,
+ .owner = THIS_MODULE,
+ .name = "Xircom / Entregra PGS - (prerenumeration)",
+ .id_table = id_table_fake_xircom,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 1,
+ .attach = keyspan_pda_fake_startup,
};
#endif
static struct usb_serial_device_type keyspan_pda_device = {
- owner: THIS_MODULE,
- name: "Keyspan PDA",
- id_table: id_table_std,
- num_interrupt_in: 1,
- num_bulk_in: 0,
- num_bulk_out: 1,
- num_ports: 1,
- open: keyspan_pda_open,
- close: keyspan_pda_close,
- write: keyspan_pda_write,
- write_room: keyspan_pda_write_room,
- write_bulk_callback: keyspan_pda_write_bulk_callback,
- read_int_callback: keyspan_pda_rx_interrupt,
- chars_in_buffer: keyspan_pda_chars_in_buffer,
- throttle: keyspan_pda_rx_throttle,
- unthrottle: keyspan_pda_rx_unthrottle,
- ioctl: keyspan_pda_ioctl,
- set_termios: keyspan_pda_set_termios,
- break_ctl: keyspan_pda_break_ctl,
- attach: keyspan_pda_startup,
- shutdown: keyspan_pda_shutdown,
+ .owner = THIS_MODULE,
+ .name = "Keyspan PDA",
+ .id_table = id_table_std,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 0,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = keyspan_pda_open,
+ .close = keyspan_pda_close,
+ .write = keyspan_pda_write,
+ .write_room = keyspan_pda_write_room,
+ .write_bulk_callback = keyspan_pda_write_bulk_callback,
+ .read_int_callback = keyspan_pda_rx_interrupt,
+ .chars_in_buffer = keyspan_pda_chars_in_buffer,
+ .throttle = keyspan_pda_rx_throttle,
+ .unthrottle = keyspan_pda_rx_unthrottle,
+ .ioctl = keyspan_pda_ioctl,
+ .set_termios = keyspan_pda_set_termios,
+ .break_ctl = keyspan_pda_break_ctl,
+ .attach = keyspan_pda_startup,
+ .shutdown = keyspan_pda_shutdown,
};
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 22a965066c3d..58e83e62c6de 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -119,27 +119,27 @@ 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,
+ .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,*/
- attach: klsi_105_startup,
- shutdown: klsi_105_shutdown,
- throttle: klsi_105_throttle,
- unthrottle: klsi_105_unthrottle,
+ .attach = klsi_105_startup,
+ .shutdown = klsi_105_shutdown,
+ .throttle = klsi_105_throttle,
+ .unthrottle = klsi_105_unthrottle,
};
struct klsi_105_port_settings {
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 1cfae6462896..9225f9396f42 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -141,25 +141,25 @@ MODULE_DEVICE_TABLE (usb, id_table_combined);
static struct usb_serial_device_type mct_u232_device = {
- owner: THIS_MODULE,
- name: "Magic Control Technology USB-RS232",
- id_table: id_table_combined,
- num_interrupt_in: 2,
- num_bulk_in: 0,
- num_bulk_out: 1,
- num_ports: 1,
- open: mct_u232_open,
- close: mct_u232_close,
+ .owner = THIS_MODULE,
+ .name = "Magic Control Technology USB-RS232",
+ .id_table = id_table_combined,
+ .num_interrupt_in = 2,
+ .num_bulk_in = 0,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = mct_u232_open,
+ .close = mct_u232_close,
#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
- write: mct_u232_write,
- write_bulk_callback: mct_u232_write_bulk_callback,
+ .write = mct_u232_write,
+ .write_bulk_callback = mct_u232_write_bulk_callback,
#endif
- read_int_callback: mct_u232_read_int_callback,
- ioctl: mct_u232_ioctl,
- set_termios: mct_u232_set_termios,
- break_ctl: mct_u232_break_ctl,
- attach: mct_u232_startup,
- shutdown: mct_u232_shutdown,
+ .read_int_callback = mct_u232_read_int_callback,
+ .ioctl = mct_u232_ioctl,
+ .set_termios = mct_u232_set_termios,
+ .break_ctl = mct_u232_break_ctl,
+ .attach = mct_u232_startup,
+ .shutdown = mct_u232_shutdown,
};
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index fbce2098e4fd..2cea1f883c9f 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -85,20 +85,20 @@ MODULE_DEVICE_TABLE (usb, id_table);
static struct usb_serial_device_type zyxel_omninet_device = {
- owner: THIS_MODULE,
- name: "ZyXEL - omni.net lcd plus usb",
- id_table: id_table,
- num_interrupt_in: 1,
- num_bulk_in: 1,
- num_bulk_out: 2,
- num_ports: 1,
- open: omninet_open,
- close: omninet_close,
- write: omninet_write,
- write_room: omninet_write_room,
- read_bulk_callback: omninet_read_bulk_callback,
- write_bulk_callback: omninet_write_bulk_callback,
- shutdown: omninet_shutdown,
+ .owner = THIS_MODULE,
+ .name = "ZyXEL - omni.net lcd plus usb",
+ .id_table = id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 2,
+ .num_ports = 1,
+ .open = omninet_open,
+ .close = omninet_close,
+ .write = omninet_write,
+ .write_room = omninet_write_room,
+ .read_bulk_callback = omninet_read_bulk_callback,
+ .write_bulk_callback = omninet_write_bulk_callback,
+ .shutdown = omninet_shutdown,
};
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index fb3ffd06ad2d..b4882dba51ec 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -118,24 +118,24 @@ static void pl2303_shutdown (struct usb_serial *serial);
/* All of the device info needed for the PL2303 SIO serial converter */
static struct usb_serial_device_type pl2303_device = {
- owner: THIS_MODULE,
- name: "PL-2303",
- id_table: id_table,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: pl2303_open,
- close: pl2303_close,
- write: pl2303_write,
- ioctl: pl2303_ioctl,
- break_ctl: pl2303_break_ctl,
- set_termios: pl2303_set_termios,
- read_bulk_callback: pl2303_read_bulk_callback,
- read_int_callback: pl2303_read_int_callback,
- write_bulk_callback: pl2303_write_bulk_callback,
- attach: pl2303_startup,
- shutdown: pl2303_shutdown,
+ .owner = THIS_MODULE,
+ .name = "PL-2303",
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = pl2303_open,
+ .close = pl2303_close,
+ .write = pl2303_write,
+ .ioctl = pl2303_ioctl,
+ .break_ctl = pl2303_break_ctl,
+ .set_termios = pl2303_set_termios,
+ .read_bulk_callback = pl2303_read_bulk_callback,
+ .read_int_callback = pl2303_read_int_callback,
+ .write_bulk_callback = pl2303_write_bulk_callback,
+ .attach = pl2303_startup,
+ .shutdown = pl2303_shutdown,
};
struct pl2303_private {
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index bc1fe0713ab9..54da202b1b95 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -399,17 +399,17 @@ static int safe_startup (struct usb_serial *serial)
}
static struct usb_serial_device_type safe_device = {
- owner: THIS_MODULE,
- name: "Safe",
- id_table: id_table,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- write: safe_write,
- write_room: safe_write_room,
- read_bulk_callback: safe_read_bulk_callback,
- attach: safe_startup,
+ .owner = THIS_MODULE,
+ .name = "Safe",
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 1,
+ .write = safe_write,
+ .write_room = safe_write_room,
+ .read_bulk_callback = safe_read_bulk_callback,
+ .attach = safe_startup,
};
static int __init safe_init (void)
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 2e556292db6a..ae7f1f3da7a5 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -366,14 +366,14 @@ static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
/* All of the device info needed for the Generic Serial Converter */
static struct usb_serial_device_type generic_device = {
- owner: THIS_MODULE,
- name: "Generic",
- id_table: generic_device_ids,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- shutdown: generic_shutdown,
+ .owner = THIS_MODULE,
+ .name = "Generic",
+ .id_table = generic_device_ids,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 1,
+ .shutdown = generic_shutdown,
};
#endif
@@ -395,10 +395,10 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
static struct usb_driver usb_serial_driver = {
- name: "serial",
- probe: usb_serial_probe,
- disconnect: usb_serial_disconnect,
- id_table: NULL, /* check all devices */
+ .name = "serial",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = NULL, /* check all devices */
};
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
@@ -447,24 +447,18 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
good_spot = 1;
for (j = 1; j <= num_ports-1; ++j)
- if (serial_table[i+j])
+ if ((serial_table[i+j]) || (i+j >= SERIAL_TTY_MINORS)) {
good_spot = 0;
+ i += j;
+ break;
+ }
if (good_spot == 0)
continue;
- if (!serial) {
- serial = kmalloc(sizeof(*serial), GFP_KERNEL);
- if (!serial) {
- err(__FUNCTION__ " - Out of memory");
- return NULL;
- }
- memset(serial, 0, sizeof(*serial));
- }
serial->magic = USB_SERIAL_MAGIC;
- serial_table[i] = serial;
*minor = i;
dbg(__FUNCTION__ " - minor base = %d", *minor);
- for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
+ for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
return serial;
}
@@ -1207,14 +1201,14 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
return(NULL);
}
+ serial = create_serial (dev, interface, type);
+ if (!serial) {
+ err ("%s - out of memory", __FUNCTION__);
+ return NULL;
+ }
+
/* if this device type has a probe function, call it */
if (type->probe) {
- serial = create_serial (dev, interface, type);
- if (!serial) {
- err ("%s - out of memory", __FUNCTION__);
- return NULL;
- }
-
if (type->owner)
__MOD_INC_USE_COUNT(type->owner);
retval = type->probe (serial);
@@ -1293,6 +1287,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
num_ports = num_bulk_out;
if (num_ports == 0) {
err("Generic device with no bulk out, not allowed.");
+ kfree (serial);
return NULL;
}
}
@@ -1300,14 +1295,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
if (!num_ports) {
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {
- if (!serial) {
- serial = create_serial (dev, interface, type);
- if (!serial) {
- err ("%s - out of memory", __FUNCTION__);
- return NULL;
- }
- }
-
if (type->owner)
__MOD_INC_USE_COUNT(type->owner);
num_ports = type->calc_num_ports (serial);
@@ -1318,22 +1305,17 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
num_ports = type->num_ports;
}
- serial = get_free_serial (serial, num_ports, &minor);
- if (serial == NULL) {
+ if (get_free_serial (serial, num_ports, &minor) == NULL) {
err("No more free serial devices");
+ kfree (serial);
return NULL;
}
- serial->dev = dev;
- serial->type = type;
- serial->interface = interface;
serial->minor = minor;
serial->num_ports = num_ports;
serial->num_bulk_in = num_bulk_in;
serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
- serial->vendor = dev->descriptor.idVendor;
- serial->product = dev->descriptor.idProduct;
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {
@@ -1577,32 +1559,32 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
static struct tty_driver serial_tty_driver = {
- magic: TTY_DRIVER_MAGIC,
- driver_name: "usb-serial",
- name: "usb/tts/%d",
- major: SERIAL_TTY_MAJOR,
- minor_start: 0,
- num: SERIAL_TTY_MINORS,
- type: TTY_DRIVER_TYPE_SERIAL,
- subtype: SERIAL_TYPE_NORMAL,
- flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-
- refcount: &serial_refcount,
- table: serial_tty,
- termios: serial_termios,
- termios_locked: serial_termios_locked,
-
- open: serial_open,
- close: serial_close,
- write: serial_write,
- write_room: serial_write_room,
- ioctl: serial_ioctl,
- set_termios: serial_set_termios,
- throttle: serial_throttle,
- unthrottle: serial_unthrottle,
- break_ctl: serial_break,
- chars_in_buffer: serial_chars_in_buffer,
- read_proc: serial_read_proc,
+ .magic = TTY_DRIVER_MAGIC,
+ .driver_name = "usb-serial",
+ .name = "usb/tts/%d",
+ .major = SERIAL_TTY_MAJOR,
+ .minor_start = 0,
+ .num = SERIAL_TTY_MINORS,
+ .type = TTY_DRIVER_TYPE_SERIAL,
+ .subtype = SERIAL_TYPE_NORMAL,
+ .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+ .refcount = &serial_refcount,
+ .table = serial_tty,
+ .termios = serial_termios,
+ .termios_locked = serial_termios_locked,
+
+ .open = serial_open,
+ .close = serial_close,
+ .write = serial_write,
+ .write_room = serial_write_room,
+ .ioctl = serial_ioctl,
+ .set_termios = serial_set_termios,
+ .throttle = serial_throttle,
+ .unthrottle = serial_unthrottle,
+ .break_ctl = serial_break,
+ .chars_in_buffer = serial_chars_in_buffer,
+ .read_proc = serial_read_proc,
};
@@ -1931,15 +1913,15 @@ static int usb_console_wait_key(struct console *co)
#endif
static struct console usbcons = {
- name: "ttyUSB", /* only [8] */
- write: usb_console_write,
+ .name = "ttyUSB", /* only [8] */
+ .write = usb_console_write,
#if 0
- device: usb_console_device, /* TBD */
- wait_key: usb_console_wait_key, /* TBD */
+ .device = usb_console_device, /* TBD */
+ .wait_key = usb_console_wait_key, /* TBD */
#endif
- setup: usb_console_setup,
- flags: CON_PRINTBUFFER,
- index: -1,
+ .setup = usb_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
};
#endif /* CONFIG_USB_SERIAL_CONSOLE */
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 3eaefb051c5c..146394d96d91 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -218,50 +218,50 @@ MODULE_DEVICE_TABLE (usb, id_table_combined);
/* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */
static struct usb_serial_device_type handspring_device = {
- owner: THIS_MODULE,
- name: "Handspring Visor / Palm 4.0 / Clié 4.x",
- id_table: id_table,
- num_interrupt_in: 0,
- num_bulk_in: 2,
- num_bulk_out: 2,
- num_ports: 2,
- open: visor_open,
- close: visor_close,
- throttle: visor_throttle,
- unthrottle: visor_unthrottle,
- probe: visor_probe,
- calc_num_ports: visor_calc_num_ports,
- shutdown: visor_shutdown,
- ioctl: visor_ioctl,
- set_termios: visor_set_termios,
- write: visor_write,
- write_room: visor_write_room,
- chars_in_buffer: visor_chars_in_buffer,
- write_bulk_callback: visor_write_bulk_callback,
- read_bulk_callback: visor_read_bulk_callback,
+ .owner = THIS_MODULE,
+ .name = "Handspring Visor / Palm 4.0 / Clié 4.x",
+ .id_table = id_table,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 2,
+ .num_bulk_out = 2,
+ .num_ports = 2,
+ .open = visor_open,
+ .close = visor_close,
+ .throttle = visor_throttle,
+ .unthrottle = visor_unthrottle,
+ .probe = visor_probe,
+ .calc_num_ports = visor_calc_num_ports,
+ .shutdown = visor_shutdown,
+ .ioctl = visor_ioctl,
+ .set_termios = visor_set_termios,
+ .write = visor_write,
+ .write_room = visor_write_room,
+ .chars_in_buffer = visor_chars_in_buffer,
+ .write_bulk_callback = visor_write_bulk_callback,
+ .read_bulk_callback = visor_read_bulk_callback,
};
/* device info for the Sony Clie OS version 3.5 */
static struct usb_serial_device_type clie_3_5_device = {
- owner: THIS_MODULE,
- name: "Sony Clié 3.5",
- id_table: clie_id_3_5_table,
- num_interrupt_in: 0,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: visor_open,
- close: visor_close,
- throttle: visor_throttle,
- unthrottle: visor_unthrottle,
- attach: clie_3_5_startup,
- ioctl: visor_ioctl,
- set_termios: visor_set_termios,
- write: visor_write,
- write_room: visor_write_room,
- chars_in_buffer: visor_chars_in_buffer,
- write_bulk_callback: visor_write_bulk_callback,
- read_bulk_callback: visor_read_bulk_callback,
+ .owner = THIS_MODULE,
+ .name = "Sony Clié 3.5",
+ .id_table = clie_id_3_5_table,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = visor_open,
+ .close = visor_close,
+ .throttle = visor_throttle,
+ .unthrottle = visor_unthrottle,
+ .attach = clie_3_5_startup,
+ .ioctl = visor_ioctl,
+ .set_termios = visor_set_termios,
+ .write = visor_write,
+ .write_room = visor_write_room,
+ .chars_in_buffer = visor_chars_in_buffer,
+ .write_bulk_callback = visor_write_bulk_callback,
+ .read_bulk_callback = visor_read_bulk_callback,
};
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 483dfa361700..1e41ef169a87 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -130,32 +130,32 @@ static int whiteheat_attach (struct usb_serial *serial);
static void whiteheat_shutdown (struct usb_serial *serial);
static struct usb_serial_device_type whiteheat_fake_device = {
- owner: THIS_MODULE,
- name: "Connect Tech - WhiteHEAT - (prerenumeration)",
- id_table: id_table_prerenumeration,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- probe: whiteheat_firmware_download,
+ .owner = THIS_MODULE,
+ .name = "Connect Tech - WhiteHEAT - (prerenumeration)",
+ .id_table = id_table_prerenumeration,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 1,
+ .probe = whiteheat_firmware_download,
};
static struct usb_serial_device_type whiteheat_device = {
- owner: THIS_MODULE,
- name: "Connect Tech - WhiteHEAT",
- id_table: id_table_std,
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 4,
- open: whiteheat_open,
- close: whiteheat_close,
- throttle: whiteheat_throttle,
- unthrottle: whiteheat_unthrottle,
- ioctl: whiteheat_ioctl,
- set_termios: whiteheat_set_termios,
- attach: whiteheat_attach,
- shutdown: whiteheat_shutdown,
+ .owner = THIS_MODULE,
+ .name = "Connect Tech - WhiteHEAT",
+ .id_table = id_table_std,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 4,
+ .open = whiteheat_open,
+ .close = whiteheat_close,
+ .throttle = whiteheat_throttle,
+ .unthrottle = whiteheat_unthrottle,
+ .ioctl = whiteheat_ioctl,
+ .set_termios = whiteheat_set_termios,
+ .attach = whiteheat_attach,
+ .shutdown = whiteheat_shutdown,
};
struct whiteheat_private {
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e1fc6507734a..21fb4e6c1835 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -354,29 +354,29 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
*/
Scsi_Host_Template usb_stor_host_template = {
- name: "usb-storage",
- proc_info: proc_info,
- info: host_info,
-
- detect: detect,
- release: release,
- command: command,
- queuecommand: queuecommand,
-
- eh_abort_handler: command_abort,
- eh_device_reset_handler:device_reset,
- eh_bus_reset_handler: bus_reset,
- eh_host_reset_handler: host_reset,
-
- can_queue: 1,
- this_id: -1,
-
- sg_tablesize: SG_ALL,
- cmd_per_lun: 1,
- present: 0,
- unchecked_isa_dma: FALSE,
- use_clustering: TRUE,
- emulated: TRUE
+ .name = "usb-storage",
+ .proc_info = proc_info,
+ .info = host_info,
+
+ .detect = detect,
+ .release = release,
+ .command = command,
+ .queuecommand = queuecommand,
+
+ .eh_abort_handler = command_abort,
+ .eh_device_reset_handler =device_reset,
+ .eh_bus_reset_handler = bus_reset,
+ .eh_host_reset_handler =host_reset,
+
+ .can_queue = 1,
+ .this_id = -1,
+
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .present = 0,
+ .unchecked_isa_dma = FALSE,
+ .use_clustering = TRUE,
+ .emulated = TRUE
};
unsigned char usb_stor_sense_notready[18] = {
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 2e8b68f47517..c0bdea0c4e6e 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -170,12 +170,12 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
vendor_name, product_name, use_protocol, use_transport, \
init_function, Flags) \
{ \
- vendorName: vendor_name, \
- productName: product_name, \
- useProtocol: use_protocol, \
- useTransport: use_transport, \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
initFunction : init_function, \
- flags: Flags, \
+ .flags = Flags, \
}
static struct us_unusual_dev us_unusual_dev_list[] = {
@@ -228,10 +228,10 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
};
struct usb_driver usb_storage_driver = {
- name: "usb-storage",
- probe: storage_probe,
- disconnect: storage_disconnect,
- id_table: storage_usb_ids,
+ .name = "usb-storage",
+ .probe = storage_probe,
+ .disconnect = storage_disconnect,
+ .id_table = storage_usb_ids,
};
/*
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 64fb0078a6cc..f73d6ba9d43b 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -174,22 +174,22 @@ static struct file_operations skel_fops = {
* and decrement it again in the release() function
* yourself.
*/
- owner: THIS_MODULE,
+ .owner = THIS_MODULE,
- read: skel_read,
- write: skel_write,
- ioctl: skel_ioctl,
- open: skel_open,
- release: skel_release,
+ .read = skel_read,
+ .write = skel_write,
+ .ioctl = skel_ioctl,
+ .open = skel_open,
+ .release = skel_release,
};
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver skel_driver = {
- name: "skeleton",
- probe: skel_probe,
- disconnect: skel_disconnect,
- id_table: skel_table,
+ .name = "skeleton",
+ .probe = skel_probe,
+ .disconnect = skel_disconnect,
+ .id_table = skel_table,
};